From 07c0456cfd5a2be826d49be3accffe12ac692971 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 21 May 2017 01:04:00 +0200 Subject: [PATCH] Derive ToComputedValue For now, only impls for types like in style::values::generics can be derived. This also needed a few ToComputedValueAsSpecified impls that I would like to replace by some #[to_computed_value(clone)] attribute, but I think it is ok to keep it like this for now. --- components/style/values/computed/mod.rs | 77 ++++++ .../style/values/generics/basic_shape.rs | 139 +--------- components/style/values/generics/image.rs | 256 +----------------- components/style/values/generics/mod.rs | 23 +- components/style/values/generics/position.rs | 25 +- components/style_derive/lib.rs | 7 + components/style_derive/to_computed_value.rs | 142 ++++++++++ 7 files changed, 247 insertions(+), 422 deletions(-) create mode 100644 components/style_derive/to_computed_value.rs diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 8c537eb3694..94042158c48 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -4,6 +4,7 @@ //! Computed values. +use Atom; use context::QuirksMode; use euclid::size::Size2D; use font_metrics::FontMetricsProvider; @@ -154,6 +155,79 @@ pub trait ToComputedValue { fn from_computed_value(computed: &Self::ComputedValue) -> Self; } +impl ToComputedValue for (A, B) + where A: ToComputedValue, B: ToComputedValue, +{ + type ComputedValue = ( + ::ComputedValue, + ::ComputedValue, + ); + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + (self.0.to_computed_value(context), self.1.to_computed_value(context)) + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + (A::from_computed_value(&computed.0), B::from_computed_value(&computed.1)) + } +} + +impl ToComputedValue for Option + where T: ToComputedValue +{ + type ComputedValue = Option<::ComputedValue>; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + self.as_ref().map(|item| item.to_computed_value(context)) + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + computed.as_ref().map(T::from_computed_value) + } +} + +impl ToComputedValue for Size2D + where T: ToComputedValue +{ + type ComputedValue = Size2D<::ComputedValue>; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + Size2D::new( + self.width.to_computed_value(context), + self.height.to_computed_value(context), + ) + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + Size2D::new( + T::from_computed_value(&computed.width), + T::from_computed_value(&computed.height), + ) + } +} + +impl ToComputedValue for Vec + where T: ToComputedValue +{ + type ComputedValue = Vec<::ComputedValue>; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + self.iter().map(|item| item.to_computed_value(context)).collect() + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + computed.iter().map(T::from_computed_value).collect() + } +} + /// A marker trait to represent that the specified value is also the computed /// value. pub trait ComputedValueAsSpecified {} @@ -174,6 +248,9 @@ impl ToComputedValue for T } } +impl ComputedValueAsSpecified for Atom {} +impl ComputedValueAsSpecified for bool {} + /// A computed `` value. #[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, PartialOrd)] #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))] diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index f75c038b59a..31f434414f5 100644 --- a/components/style/values/generics/basic_shape.rs +++ b/components/style/values/generics/basic_shape.rs @@ -12,14 +12,14 @@ use properties::shorthands::serialize_four_sides; use std::ascii::AsciiExt; use std::fmt; use style_traits::{HasViewportPercentage, ToCss}; -use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue}; +use values::computed::ComputedValueAsSpecified; use values::generics::BorderRadiusSize; use values::specified::url::SpecifiedUrl; /// A generic type used for `border-radius`, `outline-radius` and `inset()` values. /// /// https://drafts.csswg.org/css-backgrounds-3/#border-radius -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, Debug, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct BorderRadius { /// The top left radius. @@ -59,32 +59,8 @@ impl ToCss for BorderRadius { } } -impl ToComputedValue for BorderRadius { - type ComputedValue = BorderRadius; - - #[inline] - fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue { - BorderRadius { - top_left: self.top_left.to_computed_value(cx), - top_right: self.top_right.to_computed_value(cx), - bottom_right: self.bottom_right.to_computed_value(cx), - bottom_left: self.bottom_left.to_computed_value(cx), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - BorderRadius { - top_left: ToComputedValue::from_computed_value(&computed.top_left), - top_right: ToComputedValue::from_computed_value(&computed.top_right), - bottom_right: ToComputedValue::from_computed_value(&computed.bottom_right), - bottom_left: ToComputedValue::from_computed_value(&computed.bottom_left), - } - } -} - /// https://drafts.csswg.org/css-shapes/#typedef-shape-radius -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, Debug, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] pub enum ShapeRadius { @@ -109,28 +85,6 @@ impl ToCss for ShapeRadius { } } -impl ToComputedValue for ShapeRadius { - type ComputedValue = ShapeRadius; - - #[inline] - fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue { - match *self { - ShapeRadius::Length(ref lop) => ShapeRadius::Length(lop.to_computed_value(cx)), - ShapeRadius::ClosestSide => ShapeRadius::ClosestSide, - ShapeRadius::FarthestSide => ShapeRadius::FarthestSide, - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - ShapeRadius::Length(ref lop) => ShapeRadius::Length(ToComputedValue::from_computed_value(lop)), - ShapeRadius::ClosestSide => ShapeRadius::ClosestSide, - ShapeRadius::FarthestSide => ShapeRadius::FarthestSide, - } - } -} - // https://drafts.csswg.org/css-shapes/#typedef-fill-rule // NOTE: Basic shapes spec says that these are the only two values, however // https://www.w3.org/TR/SVG/painting.html#FillRuleProperty @@ -147,7 +101,7 @@ impl Default for FillRule { fn default() -> Self { FillRule::NonZero } } -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, Debug, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] /// A generic type for representing the `polygon()` function /// @@ -211,32 +165,7 @@ impl ToCss for Polygon { } } -impl ToComputedValue for Polygon { - type ComputedValue = Polygon; - - #[inline] - fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue { - Polygon { - fill: self.fill.to_computed_value(cx), - coordinates: self.coordinates.iter().map(|c| { - (c.0.to_computed_value(cx), c.1.to_computed_value(cx)) - }).collect(), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - Polygon { - fill: ToComputedValue::from_computed_value(&computed.fill), - coordinates: computed.coordinates.iter().map(|c| { - (ToComputedValue::from_computed_value(&c.0), - ToComputedValue::from_computed_value(&c.1)) - }).collect(), - } - } -} - -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, Debug, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] /// https://drafts.csswg.org/css-shapes/#funcdef-inset #[allow(missing_docs)] @@ -268,37 +197,11 @@ impl ToCss for InsetRect { } } -impl ToComputedValue for InsetRect { - type ComputedValue = InsetRect; - - #[inline] - fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue { - 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.as_ref().map(|r| r.to_computed_value(cx)), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - InsetRect { - top: ToComputedValue::from_computed_value(&computed.top), - right: ToComputedValue::from_computed_value(&computed.right), - bottom: ToComputedValue::from_computed_value(&computed.bottom), - left: ToComputedValue::from_computed_value(&computed.left), - round: computed.round.as_ref().map(|r| ToComputedValue::from_computed_value(r)), - } - } -} - /// A shape source, for some reference box /// /// `clip-path` uses ShapeSource, /// `shape-outside` uses ShapeSource -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, Debug, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] pub enum ShapeSource { @@ -364,33 +267,3 @@ impl Parse for ShapeSource { ref_box.map(|v| ShapeSource::Box(v)).ok_or(()) } } - -impl ToComputedValue for ShapeSource { - type ComputedValue = ShapeSource; - - #[inline] - fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue { - match *self { - ShapeSource::Url(ref url) => ShapeSource::Url(url.to_computed_value(cx)), - ShapeSource::Shape(ref shape, ref ref_box) => { - ShapeSource::Shape(shape.to_computed_value(cx), - ref_box.as_ref().map(|ref val| val.to_computed_value(cx))) - }, - ShapeSource::Box(ref ref_box) => ShapeSource::Box(ref_box.to_computed_value(cx)), - ShapeSource::None => ShapeSource::None, - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - ShapeSource::Url(ref url) => ShapeSource::Url(SpecifiedUrl::from_computed_value(url)), - ShapeSource::Shape(ref shape, ref ref_box) => { - ShapeSource::Shape(ToComputedValue::from_computed_value(shape), - ref_box.as_ref().map(|val| ToComputedValue::from_computed_value(val))) - }, - ShapeSource::Box(ref ref_box) => ShapeSource::Box(ToComputedValue::from_computed_value(ref_box)), - ShapeSource::None => ShapeSource::None, - } - } -} diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs index 034bc0c2859..9aa49428dce 100644 --- a/components/style/values/generics/image.rs +++ b/components/style/values/generics/image.rs @@ -10,13 +10,13 @@ use Atom; use cssparser::serialize_identifier; use std::fmt; use style_traits::{HasViewportPercentage, ToCss}; -use values::computed::{Context, ToComputedValue}; +use values::computed::ComputedValueAsSpecified; use values::specified::url::SpecifiedUrl; /// An [image]. /// /// [image]: https://drafts.csswg.org/css-images/#image-values -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum Image { /// A `` image. @@ -31,7 +31,7 @@ pub enum Image { /// A CSS gradient. /// https://drafts.csswg.org/css-images/#gradients -#[derive(Clone, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct Gradient { /// Gradients can be linear or radial. @@ -44,7 +44,7 @@ pub struct Gradient pub compat_mode: CompatMode, } -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] /// Whether we used the modern notation or the compatibility `-webkit` prefix. pub enum CompatMode { @@ -55,7 +55,7 @@ pub enum CompatMode { } /// A gradient kind. -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum GradientKind { /// A linear gradient. @@ -65,7 +65,7 @@ pub enum GradientKind { } /// A radial gradient's ending shape. -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum EndingShape { /// A circular gradient. @@ -75,7 +75,7 @@ pub enum EndingShape { } /// A circle shape. -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum Circle { /// A circle radius. @@ -85,7 +85,7 @@ pub enum Circle { } /// An ellipse shape. -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum Ellipse { /// An ellipse pair of radii. @@ -104,10 +104,11 @@ define_css_keyword_enum!(ShapeExtent: "cover" => Cover ); no_viewport_percentage!(ShapeExtent); +impl ComputedValueAsSpecified for ShapeExtent {} /// A gradient item. /// https://drafts.csswg.org/css-images-4/#color-stop-syntax -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub enum GradientItem { /// A color stop. @@ -118,7 +119,7 @@ pub enum GradientItem { /// A color stop. /// https://drafts.csswg.org/css-images/#typedef-color-stop-list -#[derive(Clone, Copy, HasViewportPercentage, PartialEq)] +#[derive(Clone, Copy, HasViewportPercentage, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct ColorStop { /// The color of this stop. @@ -130,7 +131,7 @@ pub struct ColorStop { /// Values for `moz-image-rect`. /// /// `-moz-image-rect(, top, right, bottom, left);` -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, Debug, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] pub struct ImageRect { @@ -186,47 +187,6 @@ impl HasViewportPercentage for Image } } -impl ToComputedValue for Image - where G: ToComputedValue, R: ToComputedValue, -{ - type ComputedValue = Image<::ComputedValue, - ::ComputedValue>; - - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - match *self { - Image::Url(ref url) => { - Image::Url(url.clone()) - }, - Image::Gradient(ref gradient) => { - Image::Gradient(gradient.to_computed_value(context)) - }, - Image::Rect(ref rect) => { - Image::Rect(rect.to_computed_value(context)) - }, - Image::Element(ref selector) => { - Image::Element(selector.clone()) - } - } - } - - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - Image::Url(ref url) => { - Image::Url(url.clone()) - }, - Image::Gradient(ref gradient) => { - Image::Gradient(ToComputedValue::from_computed_value(gradient)) - }, - Image::Rect(ref rect) => { - Image::Rect(ToComputedValue::from_computed_value(rect)) - }, - Image::Element(ref selector) => { - Image::Element(selector.clone()) - }, - } - } -} - impl ToCss for Gradient where D: LineDirection, L: ToCss, LoP: ToCss, P: ToCss, C: ToCss, { @@ -281,38 +241,6 @@ impl ToCss for Gradient } } -impl ToComputedValue for Gradient - where D: ToComputedValue, - L: ToComputedValue, - LoP: ToComputedValue, - P: ToComputedValue, - C: ToComputedValue, -{ - type ComputedValue = Gradient<::ComputedValue, - ::ComputedValue, - ::ComputedValue, -

::ComputedValue, - ::ComputedValue>; - - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - Gradient { - kind: self.kind.to_computed_value(context), - items: self.items.iter().map(|s| s.to_computed_value(context)).collect(), - repeating: self.repeating, - compat_mode: self.compat_mode, - } - } - - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - Gradient { - kind: ToComputedValue::from_computed_value(&computed.kind), - items: computed.items.iter().map(ToComputedValue::from_computed_value).collect(), - repeating: computed.repeating, - compat_mode: computed.compat_mode, - } - } -} - impl GradientKind { fn label(&self) -> &str { match *self { @@ -322,43 +250,6 @@ impl GradientKind { } } -impl ToComputedValue for GradientKind - where D: ToComputedValue, - L: ToComputedValue, - LoP: ToComputedValue, - P: ToComputedValue, -{ - type ComputedValue = GradientKind<::ComputedValue, - ::ComputedValue, - ::ComputedValue, -

::ComputedValue>; - - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - match *self { - GradientKind::Linear(ref direction) => { - GradientKind::Linear(direction.to_computed_value(context)) - }, - GradientKind::Radial(ref shape, ref position) => { - GradientKind::Radial(shape.to_computed_value(context), position.to_computed_value(context)) - }, - } - } - - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - GradientKind::Linear(ref direction) => { - GradientKind::Linear(ToComputedValue::from_computed_value(direction)) - }, - GradientKind::Radial(ref shape, ref position) => { - GradientKind::Radial( - ToComputedValue::from_computed_value(shape), - ToComputedValue::from_computed_value(position), - ) - } - } - } -} - /// The direction of a linear gradient. pub trait LineDirection { /// Whether this direction points towards, and thus can be omitted. @@ -397,53 +288,6 @@ impl ToCss for EndingShape } } -impl ToComputedValue for EndingShape - where L: ToComputedValue, LoP: ToComputedValue, -{ - type ComputedValue = EndingShape<::ComputedValue, - ::ComputedValue>; - - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - match *self { - EndingShape::Circle(Circle::Radius(ref length)) => { - EndingShape::Circle(Circle::Radius(length.to_computed_value(context))) - }, - EndingShape::Circle(Circle::Extent(extent)) => { - EndingShape::Circle(Circle::Extent(extent)) - }, - EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => { - EndingShape::Ellipse(Ellipse::Radii( - x.to_computed_value(context), - y.to_computed_value(context), - )) - }, - EndingShape::Ellipse(Ellipse::Extent(extent)) => { - EndingShape::Ellipse(Ellipse::Extent(extent)) - }, - } - } - - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - EndingShape::Circle(Circle::Radius(ref length)) => { - EndingShape::Circle(Circle::Radius(ToComputedValue::from_computed_value(length))) - }, - EndingShape::Circle(Circle::Extent(extent)) => { - EndingShape::Circle(Circle::Extent(extent)) - }, - EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => { - EndingShape::Ellipse(Ellipse::Radii( - ToComputedValue::from_computed_value(x), - ToComputedValue::from_computed_value(y), - )) - }, - EndingShape::Ellipse(Ellipse::Extent(extent)) => { - EndingShape::Ellipse(Ellipse::Extent(extent)) - }, - } - } -} - impl ToCss for GradientItem where C: ToCss, L: ToCss, { @@ -455,35 +299,6 @@ impl ToCss for GradientItem } } -impl ToComputedValue for GradientItem - where C: ToComputedValue, L: ToComputedValue, -{ - type ComputedValue = GradientItem<::ComputedValue, - ::ComputedValue>; - - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - match *self { - GradientItem::ColorStop(ref stop) => { - GradientItem::ColorStop(stop.to_computed_value(context)) - }, - GradientItem::InterpolationHint(ref hint) => { - GradientItem::InterpolationHint(hint.to_computed_value(context)) - }, - } - } - - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - GradientItem::ColorStop(ref stop) => { - GradientItem::ColorStop(ToComputedValue::from_computed_value(stop)) - }, - GradientItem::InterpolationHint(ref hint) => { - GradientItem::InterpolationHint(ToComputedValue::from_computed_value(hint)) - }, - } - } -} - impl fmt::Debug for ColorStop where C: fmt::Debug, L: fmt::Debug, { @@ -509,27 +324,6 @@ impl ToCss for ColorStop } } -impl ToComputedValue for ColorStop - where C: ToComputedValue, L: ToComputedValue, -{ - type ComputedValue = ColorStop<::ComputedValue, - ::ComputedValue>; - - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - ColorStop { - color: self.color.to_computed_value(context), - position: self.position.as_ref().map(|p| p.to_computed_value(context)), - } - } - - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - ColorStop { - color: ToComputedValue::from_computed_value(&computed.color), - position: computed.position.as_ref().map(ToComputedValue::from_computed_value), - } - } -} - impl ToCss for ImageRect where C: ToCss, { @@ -547,29 +341,3 @@ impl ToCss for ImageRect dest.write_str(")") } } - -impl ToComputedValue for ImageRect - where C: ToComputedValue, -{ - type ComputedValue = ImageRect<::ComputedValue>; - - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - ImageRect { - url: self.url.to_computed_value(context), - top: self.top.to_computed_value(context), - right: self.right.to_computed_value(context), - bottom: self.bottom.to_computed_value(context), - left: self.left.to_computed_value(context), - } - } - - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - ImageRect { - url: ToComputedValue::from_computed_value(&computed.url), - top: ToComputedValue::from_computed_value(&computed.top), - right: ToComputedValue::from_computed_value(&computed.right), - bottom: ToComputedValue::from_computed_value(&computed.bottom), - left: ToComputedValue::from_computed_value(&computed.left), - } - } -} diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 58445ef39df..983246b9885 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -12,7 +12,6 @@ use parser::{Parse, ParserContext}; use std::fmt; use style_traits::{HasViewportPercentage, ToCss}; use super::CustomIdent; -use super::computed::{Context, ToComputedValue}; pub use self::basic_shape::serialize_radius_values; @@ -20,9 +19,9 @@ pub mod basic_shape; pub mod image; pub mod position; -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, Debug, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -/// A type for representing CSS `widthh` and `height` values. +/// A type for representing CSS `width` and `height` values. pub struct BorderRadiusSize(pub Size2D); impl HasViewportPercentage for BorderRadiusSize { @@ -61,24 +60,6 @@ impl ToCss for BorderRadiusSize { } } -impl ToComputedValue for BorderRadiusSize { - type ComputedValue = BorderRadiusSize; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - let w = self.0.width.to_computed_value(context); - let h = self.0.height.to_computed_value(context); - BorderRadiusSize(Size2D::new(w, h)) - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - let w = ToComputedValue::from_computed_value(&computed.0.width); - let h = ToComputedValue::from_computed_value(&computed.0.height); - BorderRadiusSize(Size2D::new(w, h)) - } -} - /// https://drafts.csswg.org/css-counter-styles/#typedef-counter-style /// /// Since wherever is used, 'none' is a valid value as diff --git a/components/style/values/generics/position.rs b/components/style/values/generics/position.rs index 7e13919d30c..4ce5b63ab30 100644 --- a/components/style/values/generics/position.rs +++ b/components/style/values/generics/position.rs @@ -5,9 +5,7 @@ //! Generic types for CSS handling of specified and computed values of //! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position) -use values::computed::{Context, ToComputedValue}; - -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] /// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position). pub struct Position { @@ -26,24 +24,3 @@ impl Position { } } } - -impl ToComputedValue for Position { - type ComputedValue = Position<::ComputedValue, - ::ComputedValue>; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - Position { - horizontal: self.horizontal.to_computed_value(context), - vertical: self.vertical.to_computed_value(context), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - Self { - horizontal: ToComputedValue::from_computed_value(&computed.horizontal), - vertical: ToComputedValue::from_computed_value(&computed.vertical), - } - } -} diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs index fd47a962ce9..7f4743dccd7 100644 --- a/components/style_derive/lib.rs +++ b/components/style_derive/lib.rs @@ -10,9 +10,16 @@ extern crate synstructure; use proc_macro::TokenStream; mod has_viewport_percentage; +mod to_computed_value; #[proc_macro_derive(HasViewportPercentage)] pub fn derive_has_viewport_percentage(stream: TokenStream) -> TokenStream { let input = syn::parse_derive_input(&stream.to_string()).unwrap(); has_viewport_percentage::derive(input).to_string().parse().unwrap() } + +#[proc_macro_derive(ToComputedValue)] +pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream { + let input = syn::parse_derive_input(&stream.to_string()).unwrap(); + to_computed_value::derive(input).to_string().parse().unwrap() +} diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs new file mode 100644 index 00000000000..d7c4801dbf8 --- /dev/null +++ b/components/style_derive/to_computed_value.rs @@ -0,0 +1,142 @@ +/* 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/. */ + +use quote; +use syn; +use synstructure; + +pub fn derive(input: syn::DeriveInput) -> quote::Tokens { + let name = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let mut where_clause = where_clause.clone(); + for param in &input.generics.ty_params { + where_clause.predicates.push(where_predicate(syn::Ty::Path(None, param.ident.clone().into()), None)); + } + + let computed_value_type = syn::Path::from(syn::PathSegment { + ident: name.clone(), + parameters: syn::PathParameters::AngleBracketed(syn::AngleBracketedParameterData { + lifetimes: input.generics.lifetimes.iter().map(|l| { + l.lifetime.clone() + }).collect(), + types: input.generics.ty_params.iter().map(|ty| { + syn::Ty::Path( + Some(syn::QSelf { + ty: Box::new(syn::Ty::Path(None, ty.ident.clone().into())), + position: 3, + }), + syn::Path { + global: true, + segments: vec![ + "values".into(), + "computed".into(), + "ToComputedValue".into(), + "ComputedValue".into(), + ], + }, + ) + }).collect(), + .. Default::default() + }), + }); + + let to_body = match_body(&input, |field| { + quote!(::values::computed::ToComputedValue::to_computed_value(#field, context)) + }); + let from_body = match_body(&input, |field| { + quote!(::values::computed::ToComputedValue::from_computed_value(#field)) + }); + + quote! { + impl #impl_generics ::values::computed::ToComputedValue for #name #ty_generics #where_clause { + type ComputedValue = #computed_value_type; + + #[allow(unused_variables)] + #[inline] + fn to_computed_value(&self, context: &::values::computed::Context) -> Self::ComputedValue { + match *self { + #to_body + } + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + match *computed { + #from_body + } + } + } + } +} + +fn match_body(input: &syn::DeriveInput, f: F) -> quote::Tokens + where F: Fn(&synstructure::BindingInfo) -> quote::Tokens, +{ + let by_ref = synstructure::BindStyle::Ref.into(); + let by_value = synstructure::BindStyle::Move.into(); + + synstructure::each_variant(&input, &by_ref, |fields, variant| { + let name = if let syn::Body::Enum(_) = input.body { + format!("{}::{}", input.ident, variant.ident).into() + } else { + variant.ident.clone() + }; + let (computed_value, computed_fields) = synstructure::match_pattern(&name, &variant.data, &by_value); + let fields_pairs = fields.iter().zip(computed_fields.iter()); + let mut computations = quote!(); + computations.append_all(fields_pairs.map(|(field, computed_field)| { + let expr = f(field); + quote!(let #computed_field = #expr;) + })); + Some(quote!( + #computations + #computed_value + )) + }) +} + +/// `#ty: ::values::computed::ToComputedValue` +fn where_predicate(ty: syn::Ty, computed_value: Option) -> syn::WherePredicate { + syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate { + bound_lifetimes: vec![], + bounded_ty: ty, + bounds: vec![syn::TyParamBound::Trait( + syn::PolyTraitRef { + bound_lifetimes: vec![], + trait_ref: trait_ref(computed_value), + }, + syn::TraitBoundModifier::None + )], + }) +} + +/// `::values::computed::ToComputedValue` +fn trait_ref(computed_value: Option) -> syn::Path { + syn::Path { + global: true, + segments: vec![ + "values".into(), + "computed".into(), + syn::PathSegment { + ident: "ToComputedValue".into(), + parameters: syn::PathParameters::AngleBracketed( + syn::AngleBracketedParameterData { + bindings: trait_bindings(computed_value), + .. Default::default() + } + ), + } + ], + } +} + +/// `ComputedValue = #computed_value,` +fn trait_bindings(computed_value: Option) -> Vec { + computed_value.into_iter().map(|ty| { + syn::TypeBinding { + ident: "ComputedValue".into(), + ty: ty, + } + }).collect() +}