From 2580c1dc6ea3fbec337a31a38ab1a3abf6d2a90c Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 29 Jul 2016 18:40:22 +0530 Subject: [PATCH] Add InsetRect, move BorderRadius to basic_shape.rs --- .../style/properties/properties.mako.rs | 2 +- .../style/properties/shorthand/border.mako.rs | 48 +--- .../style/values/computed/basic_shape.rs | 88 +++++++ components/style/values/computed/mod.rs | 2 + .../style/values/specified/basic_shape.rs | 217 ++++++++++++++++++ components/style/values/specified/mod.rs | 2 + 6 files changed, 316 insertions(+), 43 deletions(-) create mode 100644 components/style/values/computed/basic_shape.rs create mode 100644 components/style/values/specified/basic_shape.rs diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 83ad6b73d82..ffc56c1cb48 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -77,7 +77,7 @@ pub mod shorthands { use parser::ParserContext; use values::specified; - fn parse_four_sides(input: &mut Parser, parse_one: F) -> Result<(T, T, T, T), ()> + pub fn parse_four_sides(input: &mut Parser, parse_one: F) -> Result<(T, T, T, T), ()> where F: Fn(&mut Parser) -> Result, F: Copy, T: Clone { // zero or more than four values is invalid. // one value sets them all diff --git a/components/style/properties/shorthand/border.mako.rs b/components/style/properties/shorthand/border.mako.rs index f884708e76c..106fed7f678 100644 --- a/components/style/properties/shorthand/border.mako.rs +++ b/components/style/properties/shorthand/border.mako.rs @@ -99,51 +99,15 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser) )}"> use app_units::Au; use values::specified::{Length, LengthOrPercentage}; - use values::specified::BorderRadiusSize; + use values::specified::basic_shape::BorderRadius; let _ignored = context; - fn parse_one_set_of_border_values(mut input: &mut Parser) - -> Result<[LengthOrPercentage; 4], ()> { - let mut count = 0; - let mut values = [LengthOrPercentage::Length(Length::Absolute(Au(0))); 4]; - while count < 4 { - if let Ok(value) = input.try(LengthOrPercentage::parse) { - values[count] = value; - count += 1; - } else { - break - } - } - - match count { - 1 => Ok([values[0], values[0], values[0], values[0]]), - 2 => Ok([values[0], values[1], values[0], values[1]]), - 3 => Ok([values[0], values[1], values[2], values[1]]), - 4 => Ok([values[0], values[1], values[2], values[3]]), - _ => Err(()), - } - } - - fn parse_one_set_of_border_radii(mut input: &mut Parser) - -> Result<[BorderRadiusSize; 4], ()> { - let widths = try!(parse_one_set_of_border_values(input)); - let mut heights = widths.clone(); - let mut radii_values = [BorderRadiusSize::zero(); 4]; - if input.try(|input| input.expect_delim('/')).is_ok() { - heights = try!(parse_one_set_of_border_values(input)); - } - for i in 0..radii_values.len() { - radii_values[i] = BorderRadiusSize::new(widths[i], heights[i]); - } - Ok(radii_values) - } - - let radii = try!(parse_one_set_of_border_radii(input)); + let radii = try!(BorderRadius::parse(input)); Ok(Longhands { - border_top_left_radius: Some(radii[0]), - border_top_right_radius: Some(radii[1]), - border_bottom_right_radius: Some(radii[2]), - border_bottom_left_radius: Some(radii[3]), + border_top_left_radius: Some(radii.top_left), + border_top_right_radius: Some(radii.top_right), + border_bottom_right_radius: Some(radii.bottom_right), + border_bottom_left_radius: Some(radii.bottom_left), }) diff --git a/components/style/values/computed/basic_shape.rs b/components/style/values/computed/basic_shape.rs new file mode 100644 index 00000000000..2f85667851b --- /dev/null +++ b/components/style/values/computed/basic_shape.rs @@ -0,0 +1,88 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! CSS handling for the computed value of +//! [`basic-shape`][basic-shape]s +//! +//! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape + +use values::computed::{Length, LengthOrPercentage}; +use values::computed::BorderRadiusSize; +use std::fmt; +use cssparser::{self, Parser, ToCss, Token}; + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum BasicShape { + Inset(InsetRect), + // Circle(Circle), + // Ellipse(Ellipse), + // Polygon(Polygon), +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct InsetRect { + pub top: LengthOrPercentage, + pub right: LengthOrPercentage, + pub bottom: LengthOrPercentage, + pub left: LengthOrPercentage, + pub round: Option, +} + +impl ToCss for InsetRect { + // XXXManishearth again, we should try to reduce the number of values printed here + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(dest.write_str("inset(")); + try!(self.top.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.right.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.bottom.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.left.to_css(dest)); + if let Some(ref radius) = self.round { + try!(dest.write_str(" round ")); + try!(radius.to_css(dest)); + } + dest.write_str(")") + } +} + +/// https://drafts.csswg.org/css-backgrounds-3/#border-radius +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct BorderRadius { + pub top_left: BorderRadiusSize, + pub top_right: BorderRadiusSize, + pub bottom_left: BorderRadiusSize, + pub bottom_right: BorderRadiusSize, +} + +impl ToCss for BorderRadius { + // XXXManishearth: We should be producing minimal output: + // if height=width for all, we should not be printing the part after + // the slash. For any set of four values, + // we should try to reduce them to one or two. This probably should be + // a helper function somewhere, for all the parse_four_sides-like + // values + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.top_left.0.width.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.top_right.0.width.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.bottom_left.0.width.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.bottom_right.0.width.to_css(dest)); + try!(dest.write_str(" / ")); + try!(self.top_left.0.height.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.top_right.0.height.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.bottom_left.0.height.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.bottom_right.0.height.to_css(dest)); + dest.write_str(" ") + } +} diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index cefe1c7d6ac..129d480332d 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -13,6 +13,8 @@ use url::Url; pub use cssparser::Color as CSSColor; pub use super::specified::{Angle, BorderStyle, Time, UrlExtraData}; +pub mod basic_shape; + pub struct Context<'a> { pub is_root_element: bool, pub viewport_size: Size2D, diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs new file mode 100644 index 00000000000..cf263adde77 --- /dev/null +++ b/components/style/values/specified/basic_shape.rs @@ -0,0 +1,217 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! CSS handling for the specified value of +//! [`basic-shape`][basic-shape]s +//! +//! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape + +use std::fmt; +use app_units::Au; +use euclid::size::Size2D; +use cssparser::{self, Parser, ToCss, Token}; +use parser::{ParserContext, ParserContextExtraData}; +use url::Url; +use properties::shorthands::parse_four_sides; +use values::specified::{Length, LengthOrPercentage}; +use values::specified::BorderRadiusSize; +use values::computed::{Context, ToComputedValue}; +use values::computed::basic_shape as computed_basic_shape; + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum BasicShape { + Inset(InsetRect), + // Circle(Circle), + // Ellipse(Ellipse), + // Polygon(Polygon), +} + +impl BasicShape { + pub fn parse(input: &mut Parser) -> Result { + if let Ok(result) = input.try(InsetRect::parse) { + Ok(BasicShape::Inset(result)) + } else { + Err(()) + } + } +} + +impl ToCss for BasicShape { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + BasicShape::Inset(rect) => rect.to_css(dest), + } + } +} + +impl ToComputedValue for BasicShape { + type ComputedValue = computed_basic_shape::BasicShape; + + #[inline] + fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue { + match *self { + BasicShape::Inset(rect) => computed_basic_shape::BasicShape::Inset(rect.to_computed_value(cx)), + } + } +} + +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct InsetRect { + pub top: LengthOrPercentage, + pub right: LengthOrPercentage, + pub bottom: LengthOrPercentage, + pub left: LengthOrPercentage, + pub round: Option, +} + +impl InsetRect { + pub fn parse(input: &mut Parser) -> Result { + match_ignore_ascii_case! { try!(input.expect_function()), + "inset" => { + Ok(try!(input.parse_nested_block(InsetRect::parse_function))) + }, + _ => Err(()) + } + } + pub fn parse_function(input: &mut Parser) -> Result { + let (t,r,b,l) = try!(parse_four_sides(input, LengthOrPercentage::parse)); + let mut rect = InsetRect { + top: t, + right: r, + bottom: b, + left: l, + round: None, + }; + if let Ok(_) = input.expect_ident_matching("round") { + rect.round = Some(try!(BorderRadius::parse(input))); + } + Ok(rect) + } +} + +impl ToCss for InsetRect { + // XXXManishearth again, we should try to reduce the number of values printed here + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(dest.write_str("inset(")); + try!(self.top.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.right.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.bottom.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.left.to_css(dest)); + if let Some(ref radius) = self.round { + try!(dest.write_str(" round ")); + try!(radius.to_css(dest)); + } + dest.write_str(")") + } +} + +impl ToComputedValue for InsetRect { + type ComputedValue = computed_basic_shape::InsetRect; + + #[inline] + fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue { + computed_basic_shape::InsetRect { + top: self.top.to_computed_value(cx), + right: self.right.to_computed_value(cx), + bottom: self.bottom.to_computed_value(cx), + left: self.left.to_computed_value(cx), + round: self.round.map(|r| r.to_computed_value(cx)), + } + } +} + +/// https://drafts.csswg.org/css-backgrounds-3/#border-radius +#[derive(Clone, PartialEq, Copy, Debug)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct BorderRadius { + pub top_left: BorderRadiusSize, + pub top_right: BorderRadiusSize, + pub bottom_left: BorderRadiusSize, + pub bottom_right: BorderRadiusSize, +} + +impl ToCss for BorderRadius { + // XXXManishearth: We should be producing minimal output: + // if height=width for all, we should not be printing the part after + // the slash. For any set of four values, + // we should try to reduce them to one or two. This probably should be + // a helper function somewhere, for all the parse_four_sides-like + // values + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + try!(self.top_left.0.width.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.top_right.0.width.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.bottom_left.0.width.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.bottom_right.0.width.to_css(dest)); + try!(dest.write_str(" / ")); + try!(self.top_left.0.height.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.top_right.0.height.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.bottom_left.0.height.to_css(dest)); + try!(dest.write_str(" ")); + try!(self.bottom_right.0.height.to_css(dest)); + dest.write_str(" ") + } +} + +impl BorderRadius { + pub fn parse(input: &mut Parser) -> Result { + let widths = try!(parse_one_set_of_border_values(input)); + let mut heights = widths.clone(); + if input.try(|input| input.expect_delim('/')).is_ok() { + heights = try!(parse_one_set_of_border_values(input)); + } + Ok(BorderRadius { + top_left: BorderRadiusSize::new(widths[1], heights[1]), + top_right: BorderRadiusSize::new(widths[2], heights[2]), + bottom_left: BorderRadiusSize::new(widths[3], heights[3]), + bottom_right: BorderRadiusSize::new(widths[4], heights[4]), + }) + } +} + +fn parse_one_set_of_border_values(mut input: &mut Parser) + -> Result<[LengthOrPercentage; 4], ()> { + let mut count = 0; + let mut values = [LengthOrPercentage::Length(Length::Absolute(Au(0))); 4]; + while count < 4 { + if let Ok(value) = input.try(LengthOrPercentage::parse) { + values[count] = value; + count += 1; + } else { + break + } + } + + match count { + 1 => Ok([values[0], values[0], values[0], values[0]]), + 2 => Ok([values[0], values[1], values[0], values[1]]), + 3 => Ok([values[0], values[1], values[2], values[1]]), + 4 => Ok([values[0], values[1], values[2], values[3]]), + _ => Err(()), + } +} + + +impl ToComputedValue for BorderRadius { + type ComputedValue = computed_basic_shape::BorderRadius; + + #[inline] + fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue { + computed_basic_shape::BorderRadius { + top_left: self.top_left.to_computed_value(cx), + top_right: self.top_right.to_computed_value(cx), + bottom_left: self.bottom_left.to_computed_value(cx), + bottom_right: self.bottom_right.to_computed_value(cx), + } + } +} diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 93b270bc117..20b2f2778ab 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -18,6 +18,8 @@ use super::computed::{Context, ToComputedValue}; use super::{CSSFloat, FONT_MEDIUM_PX, HasViewportPercentage, LocalToCss, NoViewportPercentage}; use url::Url; +pub mod basic_shape; + impl NoViewportPercentage for i32 {} // For PropertyDeclaration::Order #[derive(Clone, PartialEq, Debug)]