diff options
-rw-r--r-- | components/layout/display_list_builder.rs | 11 | ||||
-rw-r--r-- | components/style/properties/gecko.mako.rs | 19 | ||||
-rw-r--r-- | components/style/properties/longhand/border.mako.rs | 450 | ||||
-rw-r--r-- | components/style/values/computed/border.rs | 28 | ||||
-rw-r--r-- | components/style/values/computed/length.rs | 8 | ||||
-rw-r--r-- | components/style/values/computed/mod.rs | 4 | ||||
-rw-r--r-- | components/style/values/computed/rect.rs | 11 | ||||
-rw-r--r-- | components/style/values/generics/border.rs | 71 | ||||
-rw-r--r-- | components/style/values/generics/mod.rs | 2 | ||||
-rw-r--r-- | components/style/values/generics/rect.rs | 110 | ||||
-rw-r--r-- | components/style/values/specified/border.rs | 59 | ||||
-rw-r--r-- | components/style/values/specified/length.rs | 6 | ||||
-rw-r--r-- | components/style/values/specified/mod.rs | 4 | ||||
-rw-r--r-- | components/style/values/specified/rect.rs | 21 |
14 files changed, 357 insertions, 447 deletions
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 63ec70b7096..13829e8830d 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -1429,8 +1429,7 @@ impl FragmentDisplayListBuilding for Fragment { url.clone(), UsePlaceholder::No); if let Some(webrender_image) = webrender_image { - // The corners array is guaranteed to be len=4 by the css parser. - let corners = &border_style_struct.border_image_slice.corners; + let corners = &border_style_struct.border_image_slice.offsets; state.add_display_item(DisplayItem::Border(box BorderDisplayItem { base: base, @@ -1438,10 +1437,10 @@ impl FragmentDisplayListBuilding for Fragment { details: BorderDetails::Image(ImageBorder { image: webrender_image, fill: border_style_struct.border_image_slice.fill, - slice: SideOffsets2D::new(corners[0].resolve(webrender_image.height), - corners[1].resolve(webrender_image.width), - corners[2].resolve(webrender_image.height), - corners[3].resolve(webrender_image.width)), + slice: SideOffsets2D::new(corners.top.resolve(webrender_image.height), + corners.right.resolve(webrender_image.width), + corners.bottom.resolve(webrender_image.height), + corners.left.resolve(webrender_image.width)), // TODO(gw): Support border-image-outset outset: SideOffsets2D::zero(), repeat_horizontal: convert_repeat_mode(border_style_struct.border_image_repeat.0), diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 28ab764c463..bd390fc4273 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -959,8 +959,7 @@ fn static_assert() { pub fn set_border_image_outset(&mut self, v: longhands::border_image_outset::computed_value::T) { % for side in SIDES: - v.${side.index}.to_gecko_style_coord(&mut self.gecko.mBorderImageOutset - .data_at_mut(${side.index})); + v.${side.ident}.to_gecko_style_coord(&mut self.gecko.mBorderImageOutset.data_at_mut(${side.index})); % endfor } @@ -994,17 +993,17 @@ fn static_assert() { } pub fn set_border_image_width(&mut self, v: longhands::border_image_width::computed_value::T) { - use properties::longhands::border_image_width::computed_value::SingleComputedValue; + use values::generics::border::BorderImageWidthSide; % for side in SIDES: - match v.${side.index} { - SingleComputedValue::Auto => { + match v.${side.ident} { + BorderImageWidthSide::Auto => { self.gecko.mBorderImageWidth.data_at_mut(${side.index}).set_value(CoordDataValue::Auto) }, - SingleComputedValue::LengthOrPercentage(l) => { + BorderImageWidthSide::Length(l) => { l.to_gecko_style_coord(&mut self.gecko.mBorderImageWidth.data_at_mut(${side.index})) }, - SingleComputedValue::Number(n) => { + BorderImageWidthSide::Number(n) => { self.gecko.mBorderImageWidth.data_at_mut(${side.index}).set_value(CoordDataValue::Factor(n)) }, } @@ -1021,9 +1020,9 @@ fn static_assert() { pub fn set_border_image_slice(&mut self, v: longhands::border_image_slice::computed_value::T) { use gecko_bindings::structs::{NS_STYLE_BORDER_IMAGE_SLICE_NOFILL, NS_STYLE_BORDER_IMAGE_SLICE_FILL}; - for (i, corner) in v.corners.iter().enumerate() { - corner.to_gecko_style_coord(&mut self.gecko.mBorderImageSlice.data_at_mut(i)); - } + % for side in SIDES: + v.offsets.${side.ident}.to_gecko_style_coord(&mut self.gecko.mBorderImageSlice.data_at_mut(${side.index})); + % endfor let fill = if v.fill { NS_STYLE_BORDER_IMAGE_SLICE_FILL diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index 8c775b682c0..bd6c6549f6d 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -200,109 +200,13 @@ ${helpers.predefined_type("border-image-source", "ImageLayer", has_uncacheable_values=False, boxed="True")} -<%helpers:longhand name="border-image-outset" animation_value_type="none" - spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset"> - use std::fmt; - use style_traits::ToCss; - use values::specified::{LengthOrNumber, Number}; - - pub mod computed_value { - use values::computed::LengthOrNumber; - #[derive(Debug, Clone, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct T(pub LengthOrNumber, pub LengthOrNumber, - pub LengthOrNumber, pub LengthOrNumber); - } - - #[derive(Clone, Debug, HasViewportPercentage, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct SpecifiedValue(pub Vec<LengthOrNumber>); - - impl ToCss for computed_value::T { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.0.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.1.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.2.to_css(dest)); - try!(dest.write_str(" ")); - self.3.to_css(dest) - } - } - impl ToCss for SpecifiedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.0[0].to_css(dest)); - for value in self.0.iter().skip(1) { - try!(dest.write_str(" ")); - try!(value.to_css(dest)); - } - Ok(()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(Either::Second(0.0), Either::Second(0.0), - Either::Second(0.0), Either::Second(0.0)) - } - - #[inline] - pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue(vec![Either::Second(Number::new(0.0))]) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Context) -> computed_value::T { - let length = self.0.len(); - match length { - 4 => computed_value::T(self.0[0].to_computed_value(context), - self.0[1].to_computed_value(context), - self.0[2].to_computed_value(context), - self.0[3].to_computed_value(context)), - 3 => computed_value::T(self.0[0].to_computed_value(context), - self.0[1].to_computed_value(context), - self.0[2].to_computed_value(context), - self.0[1].to_computed_value(context)), - 2 => computed_value::T(self.0[0].to_computed_value(context), - self.0[1].to_computed_value(context), - self.0[0].to_computed_value(context), - self.0[1].to_computed_value(context)), - 1 => computed_value::T(self.0[0].to_computed_value(context), - self.0[0].to_computed_value(context), - self.0[0].to_computed_value(context), - self.0[0].to_computed_value(context)), - _ => unreachable!(), - } - } - #[inline] - fn from_computed_value(computed: &computed_value::T) -> Self { - SpecifiedValue(vec![ToComputedValue::from_computed_value(&computed.0), - ToComputedValue::from_computed_value(&computed.1), - ToComputedValue::from_computed_value(&computed.2), - ToComputedValue::from_computed_value(&computed.3)]) - } - } - - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - let mut values = vec![]; - for _ in 0..4 { - let value = input.try(|input| LengthOrNumber::parse_non_negative(context, input)); - match value { - Ok(val) => values.push(val), - Err(_) => break, - } - } - - if values.len() > 0 { - Ok(SpecifiedValue(values)) - } else { - Err(()) - } - } -</%helpers:longhand> +${helpers.predefined_type("border-image-outset", "LengthOrNumberRect", + parse_method="parse_non_negative", + initial_value="computed::LengthOrNumber::zero().into()", + initial_specified_value="specified::LengthOrNumber::zero().into()", + spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset", + animation_value_type="none", + boxed=True)} <%helpers:longhand name="border-image-repeat" animation_value_type="none" spec="https://drafts.csswg.org/css-backgrounds/#border-image-repeat"> @@ -380,332 +284,16 @@ ${helpers.predefined_type("border-image-source", "ImageLayer", } </%helpers:longhand> -<%helpers:longhand name="border-image-width" animation_value_type="none" - spec="https://drafts.csswg.org/css-backgrounds/#border-image-width"> - use std::fmt; - use style_traits::ToCss; - use values::specified::{LengthOrPercentage, Number}; - - pub mod computed_value { - use values::computed::{LengthOrPercentage, Number}; - #[derive(Debug, Clone, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct T(pub SingleComputedValue, pub SingleComputedValue, - pub SingleComputedValue, pub SingleComputedValue); - - #[derive(Debug, Clone, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum SingleComputedValue { - LengthOrPercentage(LengthOrPercentage), - Number(Number), - Auto, - } - } - - #[derive(Clone, Debug, HasViewportPercentage, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct SpecifiedValue(pub Vec<SingleSpecifiedValue>); - - impl ToCss for computed_value::T { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.0.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.1.to_css(dest)); - try!(dest.write_str(" ")); - try!(self.2.to_css(dest)); - try!(dest.write_str(" ")); - self.3.to_css(dest) - } - } - impl ToCss for SpecifiedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.0[0].to_css(dest)); - for value in self.0.iter().skip(1) { - try!(dest.write_str(" ")); - try!(value.to_css(dest)); - } - Ok(()) - } - } - - #[derive(Clone, Debug, HasViewportPercentage, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub enum SingleSpecifiedValue { - LengthOrPercentage(LengthOrPercentage), - Number(Number), - Auto, - } - - impl ToCss for computed_value::SingleComputedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - computed_value::SingleComputedValue::LengthOrPercentage(ref len) => len.to_css(dest), - computed_value::SingleComputedValue::Number(number) => number.to_css(dest), - computed_value::SingleComputedValue::Auto => dest.write_str("auto"), - } - } - } - impl ToCss for SingleSpecifiedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - match *self { - SingleSpecifiedValue::LengthOrPercentage(ref len) => len.to_css(dest), - SingleSpecifiedValue::Number(number) => number.to_css(dest), - SingleSpecifiedValue::Auto => dest.write_str("auto"), - } - } - } - - impl ToComputedValue for SingleSpecifiedValue { - type ComputedValue = computed_value::SingleComputedValue; - - #[inline] - fn to_computed_value(&self, context: &Context) -> computed_value::SingleComputedValue { - match *self { - SingleSpecifiedValue::LengthOrPercentage(ref len) => { - computed_value::SingleComputedValue::LengthOrPercentage( - len.to_computed_value(context)) - }, - SingleSpecifiedValue::Number(number) => - computed_value::SingleComputedValue::Number(number.to_computed_value(context)), - SingleSpecifiedValue::Auto => computed_value::SingleComputedValue::Auto, - } - } - #[inline] - fn from_computed_value(computed: &computed_value::SingleComputedValue) -> Self { - match *computed { - computed_value::SingleComputedValue::LengthOrPercentage(len) => { - SingleSpecifiedValue::LengthOrPercentage( - ToComputedValue::from_computed_value(&len)) - }, - computed_value::SingleComputedValue::Number(number) => - SingleSpecifiedValue::Number(ToComputedValue::from_computed_value(&number)), - computed_value::SingleComputedValue::Auto => SingleSpecifiedValue::Auto, - } - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T(computed_value::SingleComputedValue::Number(1.0), - computed_value::SingleComputedValue::Number(1.0), - computed_value::SingleComputedValue::Number(1.0), - computed_value::SingleComputedValue::Number(1.0)) - } - - #[inline] - pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue(vec![SingleSpecifiedValue::Number(Number::new(1.0))]) - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Context) -> computed_value::T { - let length = self.0.len(); - match length { - 4 => computed_value::T(self.0[0].to_computed_value(context), - self.0[1].to_computed_value(context), - self.0[2].to_computed_value(context), - self.0[3].to_computed_value(context)), - 3 => computed_value::T(self.0[0].to_computed_value(context), - self.0[1].to_computed_value(context), - self.0[2].to_computed_value(context), - self.0[1].to_computed_value(context)), - 2 => computed_value::T(self.0[0].to_computed_value(context), - self.0[1].to_computed_value(context), - self.0[0].to_computed_value(context), - self.0[1].to_computed_value(context)), - 1 => computed_value::T(self.0[0].to_computed_value(context), - self.0[0].to_computed_value(context), - self.0[0].to_computed_value(context), - self.0[0].to_computed_value(context)), - _ => unreachable!(), - } - } - #[inline] - fn from_computed_value(computed: &computed_value::T) -> Self { - SpecifiedValue(vec![ToComputedValue::from_computed_value(&computed.0), - ToComputedValue::from_computed_value(&computed.1), - ToComputedValue::from_computed_value(&computed.2), - ToComputedValue::from_computed_value(&computed.3)]) - } - } - - impl Parse for SingleSpecifiedValue { - fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { - if input.try(|input| input.expect_ident_matching("auto")).is_ok() { - return Ok(SingleSpecifiedValue::Auto); - } - - if let Ok(len) = input.try(|input| LengthOrPercentage::parse_non_negative(context, input)) { - return Ok(SingleSpecifiedValue::LengthOrPercentage(len)); - } - - let num = try!(Number::parse_non_negative(context, input)); - Ok(SingleSpecifiedValue::Number(num)) - } - } - - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - let mut values = vec![]; - for _ in 0..4 { - let value = input.try(|input| SingleSpecifiedValue::parse(context, input)); - match value { - Ok(val) => values.push(val), - Err(_) => break, - } - } - - if values.len() > 0 { - Ok(SpecifiedValue(values)) - } else { - Err(()) - } - } -</%helpers:longhand> - -<%helpers:longhand name="border-image-slice" boxed="True" animation_value_type="none" - spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice"> - use std::fmt; - use style_traits::ToCss; - use values::computed::NumberOrPercentage as ComputedNumberOrPercentage; - use values::specified::{NumberOrPercentage, Percentage}; - - no_viewport_percentage!(SpecifiedValue); - - pub mod computed_value { - use values::computed::NumberOrPercentage; - #[derive(Debug, Clone, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct T { - pub corners: [NumberOrPercentage; 4], - pub fill: bool, - } - } - - #[derive(Debug, Clone, PartialEq)] - #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - pub struct SpecifiedValue { - pub corners: Vec<NumberOrPercentage>, - pub fill: bool, - } - - impl ToCss for computed_value::T { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.corners[0].to_css(dest)); - try!(dest.write_str(" ")); - try!(self.corners[1].to_css(dest)); - try!(dest.write_str(" ")); - try!(self.corners[2].to_css(dest)); - try!(dest.write_str(" ")); - try!(self.corners[3].to_css(dest)); - - if self.fill { - try!(dest.write_str(" fill")); - } - Ok(()) - } - } - impl ToCss for SpecifiedValue { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.corners[0].to_css(dest)); - for value in self.corners.iter().skip(1) { - try!(dest.write_str(" ")); - try!(value.to_css(dest)); - } - - if self.fill { - try!(dest.write_str(" fill")); - } - Ok(()) - } - } - - #[inline] - pub fn get_initial_value() -> computed_value::T { - computed_value::T { - corners: [ComputedNumberOrPercentage::Percentage(Percentage(1.0)), - ComputedNumberOrPercentage::Percentage(Percentage(1.0)), - ComputedNumberOrPercentage::Percentage(Percentage(1.0)), - ComputedNumberOrPercentage::Percentage(Percentage(1.0))], - fill: false, - } - } - - #[inline] - pub fn get_initial_specified_value() -> SpecifiedValue { - SpecifiedValue { - corners: vec![NumberOrPercentage::Percentage(Percentage(1.0))], - fill: false, - } - } - - impl ToComputedValue for SpecifiedValue { - type ComputedValue = computed_value::T; - - #[inline] - fn to_computed_value(&self, context: &Context) -> computed_value::T { - let length = self.corners.len(); - let corners = match length { - 4 => [self.corners[0].to_computed_value(context), - self.corners[1].to_computed_value(context), - self.corners[2].to_computed_value(context), - self.corners[3].to_computed_value(context)], - 3 => [self.corners[0].to_computed_value(context), - self.corners[1].to_computed_value(context), - self.corners[2].to_computed_value(context), - self.corners[1].to_computed_value(context)], - 2 => [self.corners[0].to_computed_value(context), - self.corners[1].to_computed_value(context), - self.corners[0].to_computed_value(context), - self.corners[1].to_computed_value(context)], - 1 => [self.corners[0].to_computed_value(context), - self.corners[0].to_computed_value(context), - self.corners[0].to_computed_value(context), - self.corners[0].to_computed_value(context)], - _ => unreachable!(), - }; - computed_value::T { - corners: corners, - fill: self.fill, - } - } - #[inline] - fn from_computed_value(computed: &computed_value::T) -> Self { - SpecifiedValue { - corners: vec![ToComputedValue::from_computed_value(&computed.corners[0]), - ToComputedValue::from_computed_value(&computed.corners[1]), - ToComputedValue::from_computed_value(&computed.corners[2]), - ToComputedValue::from_computed_value(&computed.corners[3])], - fill: computed.fill, - } - } - } - - pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { - let mut fill = input.try(|input| input.expect_ident_matching("fill")).is_ok(); - - let mut values = vec![]; - for _ in 0..4 { - let value = input.try(|input| NumberOrPercentage::parse_non_negative(context, input)); - match value { - Ok(val) => values.push(val), - Err(_) => break, - } - } - - if !fill { - fill = input.try(|input| input.expect_ident_matching("fill")).is_ok(); - } +${helpers.predefined_type("border-image-width", "BorderImageWidth", + initial_value="computed::BorderImageWidthSide::one().into()", + initial_specified_value="specified::BorderImageWidthSide::one().into()", + spec="https://drafts.csswg.org/css-backgrounds/#border-image-width", + animation_value_type="none", + boxed=True)} - if !values.is_empty() { - Ok(SpecifiedValue { - corners: values, - fill: fill - }) - } else { - Err(()) - } - } -</%helpers:longhand> +${helpers.predefined_type("border-image-slice", "BorderImageSlice", + initial_value="computed::NumberOrPercentage::Percentage(computed::Percentage(1.)).into()", + initial_specified_value="specified::NumberOrPercentage::Percentage(specified::Percentage(1.)).into()", + spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice", + animation_value_type="none", + boxed=True)} diff --git a/components/style/values/computed/border.rs b/components/style/values/computed/border.rs new file mode 100644 index 00000000000..e247f9a9cf4 --- /dev/null +++ b/components/style/values/computed/border.rs @@ -0,0 +1,28 @@ +/* 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/. */ + +//! Computed types for CSS values related to borders. + +use values::computed::{Number, NumberOrPercentage}; +use values::computed::length::LengthOrPercentage; +use values::generics::border::BorderImageSlice as GenericBorderImageSlice; +use values::generics::border::BorderImageWidthSide as GenericBorderImageWidthSide; +use values::generics::rect::Rect; + +/// A computed value for the `border-image-width` property. +pub type BorderImageWidth = Rect<BorderImageWidthSide>; + +/// A computed value for a single side of a `border-image-width` property. +pub type BorderImageWidthSide = GenericBorderImageWidthSide<LengthOrPercentage, Number>; + +/// A computed value for the `border-image-slice` property. +pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>; + +impl BorderImageWidthSide { + /// Returns `1`. + #[inline] + pub fn one() -> Self { + GenericBorderImageWidthSide::Number(1.) + } +} diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index e2dac197652..1ed038941a7 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -603,6 +603,14 @@ pub type LengthOrAuto = Either<Length, Auto>; /// Either a computed `<length>` or a `<number>` value. pub type LengthOrNumber = Either<Length, Number>; +impl LengthOrNumber { + /// Returns `0`. + #[inline] + pub fn zero() -> Self { + Either::Second(0.) + } +} + /// Either a computed `<length>` or the `normal` keyword. pub type LengthOrNormal = Either<Length, Normal>; diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 7251b315796..10b5014483b 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -24,7 +24,9 @@ use super::specified; pub use app_units::Au; pub use cssparser::Color as CSSColor; +pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageWidthSide}; pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect}; +pub use self::rect::LengthOrNumberRect; pub use super::{Auto, Either, None_}; #[cfg(feature = "gecko")] pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems}; @@ -37,9 +39,11 @@ pub use self::length::{MaxLength, MozLength}; pub use self::position::Position; pub mod basic_shape; +pub mod border; pub mod image; pub mod length; pub mod position; +pub mod rect; /// A `Context` is all the data a specified value could ever need to compute /// itself and be transformed to a computed value. diff --git a/components/style/values/computed/rect.rs b/components/style/values/computed/rect.rs new file mode 100644 index 00000000000..46fcdc65583 --- /dev/null +++ b/components/style/values/computed/rect.rs @@ -0,0 +1,11 @@ +/* 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/. */ + +//! Computed types for CSS borders. + +use values::computed::length::LengthOrNumber; +use values::generics::rect::Rect; + +/// A specified rectangle made of four `<length-or-number>` values. +pub type LengthOrNumberRect = Rect<LengthOrNumber>; diff --git a/components/style/values/generics/border.rs b/components/style/values/generics/border.rs new file mode 100644 index 00000000000..70e5812b401 --- /dev/null +++ b/components/style/values/generics/border.rs @@ -0,0 +1,71 @@ +/* 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/. */ + +//! Generic types for CSS values related to borders. + +use std::fmt; +use style_traits::ToCss; +use values::generics::rect::Rect; + +/// A generic value for a single side of a `border-image-width` property. +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] +pub enum BorderImageWidthSide<LengthOrPercentage, Number> { + /// `<length-or-percentage>` + Length(LengthOrPercentage), + /// `<number>` + Number(Number), + /// `auto` + Auto, +} + +/// A generic value for the `border-image-slice` property. +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct BorderImageSlice<NumberOrPercentage> { + /// The offsets. + pub offsets: Rect<NumberOrPercentage>, + /// Whether to fill the middle part. + pub fill: bool, +} + +impl<L, N> ToCss for BorderImageWidthSide<L, N> + where L: ToCss, N: ToCss, +{ + fn to_css<W>(&self, dest: &mut W) -> fmt::Result + where W: fmt::Write + { + match *self { + BorderImageWidthSide::Length(ref length) => length.to_css(dest), + BorderImageWidthSide::Number(ref number) => number.to_css(dest), + BorderImageWidthSide::Auto => dest.write_str("auto"), + } + } +} + +impl<N> From<N> for BorderImageSlice<N> + where N: Clone, +{ + #[inline] + fn from(value: N) -> Self { + Self { + offsets: value.into(), + fill: false, + } + } +} + +impl<N> ToCss for BorderImageSlice<N> + where N: PartialEq + ToCss, +{ + fn to_css<W>(&self, dest: &mut W) -> fmt::Result + where W: fmt::Write + { + self.offsets.to_css(dest)?; + if self.fill { + dest.write_str(" fill")?; + } + Ok(()) + } +} diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 65fca55feb6..1efc617b0b0 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -16,9 +16,11 @@ use super::CustomIdent; pub use self::basic_shape::serialize_radius_values; pub mod basic_shape; +pub mod border; pub mod grid; pub mod image; pub mod position; +pub mod rect; #[derive(Clone, Debug, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] diff --git a/components/style/values/generics/rect.rs b/components/style/values/generics/rect.rs new file mode 100644 index 00000000000..767ce2223e4 --- /dev/null +++ b/components/style/values/generics/rect.rs @@ -0,0 +1,110 @@ +/* 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/. */ + +//! Generic types for CSS values that are composed of four sides. + +use cssparser::Parser; +use parser::{Parse, ParserContext}; +use std::fmt; +use style_traits::ToCss; + +/// A CSS value made of four sides: top, right, bottom, and left. +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub struct Rect<T> { + /// Top + pub top: T, + /// Right. + pub right: T, + /// Bottom. + pub bottom: T, + /// Left. + pub left: T, +} + +impl<T> Rect<T> { + /// Returns a new `Rect<T>` value. + pub fn new(top: T, right: T, bottom: T, left: T) -> Self { + Rect { + top: top, + right: right, + bottom: bottom, + left: left, + } + } +} + +impl<T> Rect<T> + where T: Clone +{ + /// Parses a new `Rect<T>` value with the given parse function. + pub fn parse_with<Parse>( + context: &ParserContext, + input: &mut Parser, + parse: Parse) + -> Result<Self, ()> + where Parse: Fn(&ParserContext, &mut Parser) -> Result<T, ()> + { + let top = parse(context, input)?; + let right = if let Ok(right) = input.try(|i| parse(context, i)) { right } else { + // <top> + return Ok(Self::new(top.clone(), top.clone(), top.clone(), top)); + }; + let bottom = if let Ok(bottom) = input.try(|i| parse(context, i)) { bottom } else { + // <top> <right> + return Ok(Self::new(top.clone(), right.clone(), top, right)); + }; + let left = if let Ok(left) = input.try(|i| parse(context, i)) { left } else { + // <top> <right> <bottom> + return Ok(Self::new(top, right.clone(), bottom, right)); + }; + // <top> <right> <bottom> <left> + Ok(Self::new(top, right, bottom, left)) + } +} + +impl<T> From<T> for Rect<T> + where T: Clone +{ + #[inline] + fn from(value: T) -> Self { + Self::new(value.clone(), value.clone(), value.clone(), value) + } +} + +impl<T> Parse for Rect<T> + where T: Clone + Parse +{ + #[inline] + fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + Self::parse_with(context, input, T::parse) + } +} + +impl<T> ToCss for Rect<T> + where T: PartialEq + ToCss +{ + fn to_css<W>(&self, dest: &mut W) -> fmt::Result + where W: fmt::Write, + { + self.top.to_css(dest)?; + let same_vertical = self.top == self.bottom; + let same_horizontal = self.right == self.left; + if same_vertical && same_horizontal && self.top == self.right { + return Ok(()); + } + dest.write_str(" ")?; + self.right.to_css(dest)?; + if same_vertical && same_horizontal { + return Ok(()); + } + dest.write_str(" ")?; + self.bottom.to_css(dest)?; + if same_horizontal { + return Ok(()); + } + dest.write_str(" ")?; + self.left.to_css(dest) + } +} diff --git a/components/style/values/specified/border.rs b/components/style/values/specified/border.rs new file mode 100644 index 00000000000..c4b95c86865 --- /dev/null +++ b/components/style/values/specified/border.rs @@ -0,0 +1,59 @@ +/* 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/. */ + +//! Specified types for CSS values related to borders. + +use cssparser::Parser; +use parser::{Parse, ParserContext}; +use values::generics::border::BorderImageSlice as GenericBorderImageSlice; +use values::generics::border::BorderImageWidthSide as GenericBorderImageWidthSide; +use values::generics::rect::Rect; +use values::specified::{Number, NumberOrPercentage}; +use values::specified::length::LengthOrPercentage; + +/// A specified value for the `border-image-width` property. +pub type BorderImageWidth = Rect<BorderImageWidthSide>; + +/// A specified value for a single side of a `border-image-width` property. +pub type BorderImageWidthSide = GenericBorderImageWidthSide<LengthOrPercentage, Number>; + +/// A specified value for the `border-image-slice` property. +pub type BorderImageSlice = GenericBorderImageSlice<NumberOrPercentage>; + +impl BorderImageWidthSide { + /// Returns `1`. + #[inline] + pub fn one() -> Self { + GenericBorderImageWidthSide::Number(Number::new(1.)) + } +} + +impl Parse for BorderImageWidthSide { + fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + if input.try(|i| i.expect_ident_matching("auto")).is_ok() { + return Ok(GenericBorderImageWidthSide::Auto); + } + + if let Ok(len) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { + return Ok(GenericBorderImageWidthSide::Length(len)); + } + + let num = Number::parse_non_negative(context, input)?; + Ok(GenericBorderImageWidthSide::Number(num)) + } +} + +impl Parse for BorderImageSlice { + fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + let mut fill = input.try(|i| i.expect_ident_matching("fill")).is_ok(); + let offsets = Rect::parse_with(context, input, NumberOrPercentage::parse_non_negative)?; + if !fill { + fill = input.try(|i| i.expect_ident_matching("fill")).is_ok(); + } + Ok(GenericBorderImageSlice { + offsets: offsets, + fill: fill, + }) + } +} diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index e37aad81f0e..ef4083544ae 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -1180,6 +1180,12 @@ impl LengthOrNumber { Length::parse_non_negative(context, input).map(Either::First) } + + /// Returns `0`. + #[inline] + pub fn zero() -> Self { + Either::Second(Number::new(0.)) + } } /// A value suitable for a `min-width` or `min-height` property. diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 8d75e0c4a07..ec0ac648d87 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -30,6 +30,8 @@ use values::specified::calc::CalcNode; #[cfg(feature = "gecko")] pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems}; +pub use self::rect::LengthOrNumberRect; +pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageWidthSide}; pub use self::color::Color; pub use super::generics::grid::GridLine; pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient}; @@ -44,12 +46,14 @@ pub use self::position::{Position, PositionComponent}; #[cfg(feature = "gecko")] pub mod align; pub mod basic_shape; +pub mod border; pub mod calc; pub mod color; pub mod grid; pub mod image; pub mod length; pub mod position; +pub mod rect; /// Common handling for the specified value CSS url() values. pub mod url { diff --git a/components/style/values/specified/rect.rs b/components/style/values/specified/rect.rs new file mode 100644 index 00000000000..11c03e57f7b --- /dev/null +++ b/components/style/values/specified/rect.rs @@ -0,0 +1,21 @@ +/* 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/. */ + +//! Computed types for CSS borders. + +use cssparser::Parser; +use parser::ParserContext; +use values::generics::rect::Rect; +use values::specified::length::LengthOrNumber; + +/// A specified rectangle made of four `<length-or-number>` values. +pub type LengthOrNumberRect = Rect<LengthOrNumber>; + +impl LengthOrNumberRect { + /// Parses a `LengthOrNumberRect`, rejecting negative values. + #[inline] + pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { + Rect::parse_with(context, input, LengthOrNumber::parse_non_negative) + } +} |