From 7a214831f00ce557b8bccfd8f4e88299a9eef94b Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 23 May 2017 02:40:12 +0200 Subject: [PATCH 1/3] =?UTF-8?q?Introduce=20style::values::generics::rect?= =?UTF-8?q?=20=E2=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This defines a single type Rect which allows us to abstract over CSS values made of four sides top, right, bottom and left. --- components/style/properties/gecko.mako.rs | 3 +- .../style/properties/longhand/border.mako.rs | 110 ++---------------- components/style/values/computed/length.rs | 8 ++ components/style/values/computed/mod.rs | 2 + components/style/values/computed/rect.rs | 11 ++ components/style/values/generics/mod.rs | 1 + components/style/values/generics/rect.rs | 110 ++++++++++++++++++ components/style/values/specified/length.rs | 6 + components/style/values/specified/mod.rs | 2 + components/style/values/specified/rect.rs | 21 ++++ 10 files changed, 169 insertions(+), 105 deletions(-) create mode 100644 components/style/values/computed/rect.rs create mode 100644 components/style/values/generics/rect.rs create mode 100644 components/style/values/specified/rect.rs diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index fa7d5c67271..d2416781330 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 } diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index 8c775b682c0..82169a9a943 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); - - impl ToCss for computed_value::T { - fn to_css(&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(&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 { - 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.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"> 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; /// Either a computed `` or a `` value. pub type LengthOrNumber = Either; +impl LengthOrNumber { + /// Returns `0`. + #[inline] + pub fn zero() -> Self { + Either::Second(0.) + } +} + /// Either a computed `` or the `normal` keyword. pub type LengthOrNormal = Either; diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 7251b315796..97d3ca76114 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -25,6 +25,7 @@ use super::specified; pub use app_units::Au; pub use cssparser::Color as CSSColor; 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}; @@ -40,6 +41,7 @@ pub mod basic_shape; 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 `` values. +pub type LengthOrNumberRect = Rect; diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 65fca55feb6..de5e043c52e 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -19,6 +19,7 @@ pub mod basic_shape; 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 { + /// Top + pub top: T, + /// Right. + pub right: T, + /// Bottom. + pub bottom: T, + /// Left. + pub left: T, +} + +impl Rect { + /// Returns a new `Rect` value. + pub fn new(top: T, right: T, bottom: T, left: T) -> Self { + Rect { + top: top, + right: right, + bottom: bottom, + left: left, + } + } +} + +impl Rect + where T: Clone +{ + /// Parses a new `Rect` value with the given parse function. + pub fn parse_with( + context: &ParserContext, + input: &mut Parser, + parse: Parse) + -> Result + where Parse: Fn(&ParserContext, &mut Parser) -> Result + { + let top = parse(context, input)?; + let right = if let Ok(right) = input.try(|i| parse(context, i)) { right } else { + // + 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 { + // + return Ok(Self::new(top.clone(), right.clone(), top, right)); + }; + let left = if let Ok(left) = input.try(|i| parse(context, i)) { left } else { + // + return Ok(Self::new(top, right.clone(), bottom, right)); + }; + // + Ok(Self::new(top, right, bottom, left)) + } +} + +impl From for Rect + where T: Clone +{ + #[inline] + fn from(value: T) -> Self { + Self::new(value.clone(), value.clone(), value.clone(), value) + } +} + +impl Parse for Rect + where T: Clone + Parse +{ + #[inline] + fn parse(context: &ParserContext, input: &mut Parser) -> Result { + Self::parse_with(context, input, T::parse) + } +} + +impl ToCss for Rect + where T: PartialEq + ToCss +{ + fn to_css(&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/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..87a46823d5f 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -30,6 +30,7 @@ use values::specified::calc::CalcNode; #[cfg(feature = "gecko")] pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems}; +pub use self::rect::LengthOrNumberRect; pub use self::color::Color; pub use super::generics::grid::GridLine; pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient}; @@ -50,6 +51,7 @@ 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 `` values. +pub type LengthOrNumberRect = Rect; + +impl LengthOrNumberRect { + /// Parses a `LengthOrNumberRect`, rejecting negative values. + #[inline] + pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result { + Rect::parse_with(context, input, LengthOrNumber::parse_non_negative) + } +} From c8eb277ca580bdf0f1ba169349d741b7e5ea1e11 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 23 May 2017 10:10:35 +0200 Subject: [PATCH 2/3] Use generics for the border-image-width property --- components/style/properties/gecko.mako.rs | 10 +- .../style/properties/longhand/border.mako.rs | 190 +----------------- components/style/values/computed/border.rs | 24 +++ components/style/values/computed/mod.rs | 2 + components/style/values/generics/border.rs | 34 ++++ components/style/values/generics/mod.rs | 1 + components/style/values/specified/border.rs | 41 ++++ components/style/values/specified/mod.rs | 2 + 8 files changed, 115 insertions(+), 189 deletions(-) create mode 100644 components/style/values/computed/border.rs create mode 100644 components/style/values/generics/border.rs create mode 100644 components/style/values/specified/border.rs diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index d2416781330..b1a68d5e3e6 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -993,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)) }, } diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index 82169a9a943..9edab419b8d 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -284,190 +284,12 @@ ${helpers.predefined_type("border-image-outset", "LengthOrNumberRect", } -<%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); - - impl ToCss for computed_value::T { - fn to_css(&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(&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(&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(&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 { - 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 { - 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.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)} <%helpers:longhand name="border-image-slice" boxed="True" animation_value_type="none" spec="https://drafts.csswg.org/css-backgrounds/#border-image-slice"> diff --git a/components/style/values/computed/border.rs b/components/style/values/computed/border.rs new file mode 100644 index 00000000000..180b66ef8a9 --- /dev/null +++ b/components/style/values/computed/border.rs @@ -0,0 +1,24 @@ +/* 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; +use values::computed::length::LengthOrPercentage; +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; + +/// A computed value for a single side of a `border-image-width` property. +pub type BorderImageWidthSide = GenericBorderImageWidthSide; + +impl BorderImageWidthSide { + /// Returns `1`. + #[inline] + pub fn one() -> Self { + GenericBorderImageWidthSide::Number(1.) + } +} diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 97d3ca76114..b1ba6ed9702 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -24,6 +24,7 @@ use super::specified; pub use app_units::Au; pub use cssparser::Color as CSSColor; +pub use self::border::{BorderImageWidth, BorderImageWidthSide}; pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect}; pub use self::rect::LengthOrNumberRect; pub use super::{Auto, Either, None_}; @@ -38,6 +39,7 @@ 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; diff --git a/components/style/values/generics/border.rs b/components/style/values/generics/border.rs new file mode 100644 index 00000000000..cd725fa232d --- /dev/null +++ b/components/style/values/generics/border.rs @@ -0,0 +1,34 @@ +/* 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; + +/// 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 { + /// `` + Length(LengthOrPercentage), + /// `` + Number(Number), + /// `auto` + Auto, +} + +impl ToCss for BorderImageWidthSide + where L: ToCss, N: ToCss, +{ + fn to_css(&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"), + } + } +} diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index de5e043c52e..1efc617b0b0 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -16,6 +16,7 @@ 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; diff --git a/components/style/values/specified/border.rs b/components/style/values/specified/border.rs new file mode 100644 index 00000000000..cf3c1f6832b --- /dev/null +++ b/components/style/values/specified/border.rs @@ -0,0 +1,41 @@ +/* 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::BorderImageWidthSide as GenericBorderImageWidthSide; +use values::generics::rect::Rect; +use values::specified::Number; +use values::specified::length::LengthOrPercentage; + +/// A specified value for the `border-image-width` property. +pub type BorderImageWidth = Rect; + +/// A specified value for a single side of a `border-image-width` property. +pub type BorderImageWidthSide = GenericBorderImageWidthSide; + +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 { + 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)) + } +} diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 87a46823d5f..57b8ad311e1 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -31,6 +31,7 @@ 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::{BorderImageWidth, BorderImageWidthSide}; pub use self::color::Color; pub use super::generics::grid::GridLine; pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient}; @@ -45,6 +46,7 @@ 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; From 078d4ed40c7c3858f84200f9354351e99ca18d2e Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Tue, 23 May 2017 10:56:03 +0200 Subject: [PATCH 3/3] Use generics for border-image-slice property --- components/layout/display_list_builder.rs | 11 +- components/style/properties/gecko.mako.rs | 6 +- .../style/properties/longhand/border.mako.rs | 150 +----------------- components/style/values/computed/border.rs | 6 +- components/style/values/computed/mod.rs | 2 +- components/style/values/generics/border.rs | 37 +++++ components/style/values/specified/border.rs | 20 ++- components/style/values/specified/mod.rs | 2 +- 8 files changed, 77 insertions(+), 157 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 b1a68d5e3e6..81a91df7dd8 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1020,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 9edab419b8d..bd6c6549f6d 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -291,147 +291,9 @@ ${helpers.predefined_type("border-image-width", "BorderImageWidth", animation_value_type="none", boxed=True)} -<%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, - pub fill: bool, - } - - impl ToCss for computed_value::T { - fn to_css(&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(&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 { - 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(); - } - - if !values.is_empty() { - Ok(SpecifiedValue { - corners: values, - fill: fill - }) - } else { - Err(()) - } - } - +${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 index 180b66ef8a9..e247f9a9cf4 100644 --- a/components/style/values/computed/border.rs +++ b/components/style/values/computed/border.rs @@ -4,8 +4,9 @@ //! Computed types for CSS values related to borders. -use values::computed::Number; +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; @@ -15,6 +16,9 @@ pub type BorderImageWidth = Rect; /// A computed value for a single side of a `border-image-width` property. pub type BorderImageWidthSide = GenericBorderImageWidthSide; +/// A computed value for the `border-image-slice` property. +pub type BorderImageSlice = GenericBorderImageSlice; + impl BorderImageWidthSide { /// Returns `1`. #[inline] diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index b1ba6ed9702..10b5014483b 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -24,7 +24,7 @@ use super::specified; pub use app_units::Au; pub use cssparser::Color as CSSColor; -pub use self::border::{BorderImageWidth, BorderImageWidthSide}; +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_}; diff --git a/components/style/values/generics/border.rs b/components/style/values/generics/border.rs index cd725fa232d..70e5812b401 100644 --- a/components/style/values/generics/border.rs +++ b/components/style/values/generics/border.rs @@ -6,6 +6,7 @@ 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))] @@ -19,6 +20,16 @@ pub enum BorderImageWidthSide { 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 { + /// The offsets. + pub offsets: Rect, + /// Whether to fill the middle part. + pub fill: bool, +} + impl ToCss for BorderImageWidthSide where L: ToCss, N: ToCss, { @@ -32,3 +43,29 @@ impl ToCss for BorderImageWidthSide } } } + +impl From for BorderImageSlice + where N: Clone, +{ + #[inline] + fn from(value: N) -> Self { + Self { + offsets: value.into(), + fill: false, + } + } +} + +impl ToCss for BorderImageSlice + where N: PartialEq + ToCss, +{ + fn to_css(&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/specified/border.rs b/components/style/values/specified/border.rs index cf3c1f6832b..c4b95c86865 100644 --- a/components/style/values/specified/border.rs +++ b/components/style/values/specified/border.rs @@ -6,9 +6,10 @@ 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; +use values::specified::{Number, NumberOrPercentage}; use values::specified::length::LengthOrPercentage; /// A specified value for the `border-image-width` property. @@ -17,6 +18,9 @@ pub type BorderImageWidth = Rect; /// A specified value for a single side of a `border-image-width` property. pub type BorderImageWidthSide = GenericBorderImageWidthSide; +/// A specified value for the `border-image-slice` property. +pub type BorderImageSlice = GenericBorderImageSlice; + impl BorderImageWidthSide { /// Returns `1`. #[inline] @@ -39,3 +43,17 @@ impl Parse for BorderImageWidthSide { Ok(GenericBorderImageWidthSide::Number(num)) } } + +impl Parse for BorderImageSlice { + fn parse(context: &ParserContext, input: &mut Parser) -> Result { + 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/mod.rs b/components/style/values/specified/mod.rs index 57b8ad311e1..ec0ac648d87 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -31,7 +31,7 @@ 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::{BorderImageWidth, BorderImageWidthSide}; +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};