Bug 1359787 - Implement {specified|computed}::LayerImage. draft
authorcku <cku@mozilla.com>
Thu, 27 Apr 2017 14:50:54 +0800
changeset 571655 fe33bdc520e41b2ec14c6b9a5293df534cd8e3ca
parent 571618 a748acbebbde373a88868dc02910fb2bc5e6a023
child 626842 05d3eed5c5c9e038542d3de52184f0d872089dda
push id56878
push userbmo:cku@mozilla.com
push dateWed, 03 May 2017 03:37:20 +0000
bugs1359787
milestone55.0a1
Bug 1359787 - Implement {specified|computed}::LayerImage. Since the way of parsing and serialization {specified|computed} value of backgound-image, mask-image and border-image-source is the exactly the same, create a new struct {specified|computed}::LayerImage to handling value parsing and serialization, so that we can reuse the code among three properties. MozReview-Commit-ID: 38e99H4k7mW
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/background.mako.rs
servo/components/style/properties/longhand/border.mako.rs
servo/components/style/properties/longhand/svg.mako.rs
servo/components/style/values/computed/image.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/specified/image.rs
servo/components/style/values/specified/mod.rs
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -916,23 +916,23 @@ fn static_assert() {
     % for corner in CORNERS:
     <% impl_corner_style_coord("border_%s_radius" % corner.ident,
                                "mBorderRadius",
                                corner.x_index,
                                corner.y_index,
                                need_clone=True) %>
     % endfor
 
-    pub fn set_border_image_source(&mut self, v: longhands::border_image_source::computed_value::T) {
+    pub fn set_border_image_source(&mut self, image: longhands::border_image_source::computed_value::T) {
         unsafe {
             // Prevent leaking of the last elements we did set
             Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource);
         }
 
-        if let Some(image) = v.0 {
+        if let Some(image) = image.0 {
             self.gecko.mBorderImageSource.set(image, &mut false)
         }
     }
 
     pub fn copy_border_image_source_from(&mut self, other: &Self) {
         unsafe {
             Gecko_CopyImageValueFrom(&mut self.gecko.mBorderImageSource,
                                      &other.gecko.mBorderImageSource);
@@ -2740,28 +2740,19 @@ fn static_assert() {
             Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, images.0.len(),
                                           LayerType::${shorthand.title()});
         }
 
         self.gecko.${image_layers_field}.mImageCount = images.0.len() as u32;
 
         for (image, geckoimage) in images.0.into_iter().zip(self.gecko.${image_layers_field}
                                                                 .mLayers.iter_mut()) {
-            % if shorthand == "background":
-                if let Some(image) = image.0 {
-                    geckoimage.mImage.set(image, cacheable)
-                }
-            % else:
-                use properties::longhands::mask_image::single_value::computed_value::T;
-                match image {
-                    T::Image(image) => geckoimage.mImage.set(image, cacheable),
-                    _ => ()
-                }
-            % endif
-
+            if let Some(image) = image.0 {
+                geckoimage.mImage.set(image, cacheable)
+            }
         }
     }
 
     <%
         fill_fields = "mRepeat mClip mOrigin mPositionX mPositionY mImage mSize"
         if shorthand == "background":
             fill_fields += " mAttachment mBlendMode"
         else:
--- a/servo/components/style/properties/longhand/background.mako.rs
+++ b/servo/components/style/properties/longhand/background.mako.rs
@@ -7,92 +7,23 @@
 <% data.new_style_struct("Background", inherited=False) %>
 
 ${helpers.predefined_type("background-color", "CSSColor",
     "::cssparser::Color::RGBA(::cssparser::RGBA::transparent())",
     initial_specified_value="SpecifiedValue::transparent()",
     spec="https://drafts.csswg.org/css-backgrounds/#background-color",
     animation_value_type="IntermediateColor", complex_color=True)}
 
-<%helpers:vector_longhand name="background-image" animation_value_type="none"
-                          spec="https://drafts.csswg.org/css-backgrounds/#the-background-image"
-                          has_uncacheable_values="${product == 'gecko'}">
-    use std::fmt;
-    use style_traits::ToCss;
-    use values::HasViewportPercentage;
-    use values::specified::Image;
-
-    pub mod computed_value {
-        use values::computed;
-        #[derive(Debug, Clone, PartialEq)]
-        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-        pub struct T(pub Option<computed::Image>);
-    }
-
-    impl ToCss for computed_value::T {
-        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-            match self.0 {
-                None => dest.write_str("none"),
-                Some(ref image) => image.to_css(dest),
-            }
-        }
-    }
-
-    no_viewport_percentage!(SpecifiedValue);
-
-    #[derive(Debug, Clone, PartialEq)]
-    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-    pub struct SpecifiedValue(pub Option<Image>);
-
-    impl ToCss for SpecifiedValue {
-        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-            match *self {
-                SpecifiedValue(Some(ref image)) => image.to_css(dest),
-                SpecifiedValue(None) => dest.write_str("none"),
-            }
-        }
-    }
-
-    #[inline]
-    pub fn get_initial_value() -> computed_value::T {
-        computed_value::T(None)
-    }
-    #[inline]
-    pub fn get_initial_specified_value() -> SpecifiedValue {
-        SpecifiedValue(None)
-    }
-    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
-        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
-            Ok(SpecifiedValue(None))
-        } else {
-            Ok(SpecifiedValue(Some(try!(Image::parse(context, input)))))
-        }
-    }
-    impl ToComputedValue for SpecifiedValue {
-        type ComputedValue = computed_value::T;
-
-        #[inline]
-        fn to_computed_value(&self, context: &Context) -> computed_value::T {
-            match *self {
-                SpecifiedValue(None) => computed_value::T(None),
-                SpecifiedValue(Some(ref image)) =>
-                    computed_value::T(Some(image.to_computed_value(context))),
-            }
-        }
-
-        #[inline]
-        fn from_computed_value(computed: &computed_value::T) -> Self {
-            match *computed {
-                computed_value::T(None) => SpecifiedValue(None),
-                computed_value::T(Some(ref image)) =>
-                    SpecifiedValue(Some(ToComputedValue::from_computed_value(image))),
-            }
-        }
-    }
-</%helpers:vector_longhand>
+${helpers.predefined_type("background-image", "LayerImage",
+    initial_value="computed_value::T(None)",
+    initial_specified_value="SpecifiedValue(None)",
+    spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
+    vector="True",
+    animation_value_type="none",
+    has_uncacheable_values="${product == 'gecko'}")}
 
 <%helpers:predefined_type name="background-position-x" type="position::HorizontalPosition"
                           initial_value="computed::position::HorizontalPosition::zero()"
                           initial_specified_value="specified::position::HorizontalPosition::left()"
                           spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x"
                           animation_value_type="ComputedValue" vector="True" delegate_animate="True">
     #[inline]
     /// Get the initial value for horizontal position.
--- a/servo/components/style/properties/longhand/border.mako.rs
+++ b/servo/components/style/properties/longhand/border.mako.rs
@@ -185,91 +185,24 @@
 ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
                          gecko_ffi_name="mFloatEdge",
                          gecko_enum_prefix="StyleFloatEdge",
                          gecko_inexhaustive=True,
                          products="gecko",
                          spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
                          animation_value_type="none")}
 
-<%helpers:longhand name="border-image-source" animation_value_type="none" boxed="True"
-                   spec="https://drafts.csswg.org/css-backgrounds/#border-image-source">
-    use std::fmt;
-    use style_traits::ToCss;
-    use values::HasViewportPercentage;
-    use values::specified::Image;
-
-    no_viewport_percentage!(SpecifiedValue);
-
-    pub mod computed_value {
-        use values::computed;
-        #[derive(Debug, Clone, PartialEq)]
-        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-        pub struct T(pub Option<computed::Image>);
-    }
-
-    #[derive(Debug, Clone, PartialEq)]
-    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-    pub struct SpecifiedValue(pub Option<Image>);
-
-    impl ToCss for computed_value::T {
-        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-            match self.0 {
-                Some(ref image) => image.to_css(dest),
-                None => dest.write_str("none"),
-            }
-        }
-    }
-    impl ToCss for SpecifiedValue {
-        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-            match self.0 {
-                Some(ref image) => image.to_css(dest),
-                None => dest.write_str("none"),
-            }
-        }
-    }
-
-    #[inline]
-    pub fn get_initial_value() -> computed_value::T {
-        computed_value::T(None)
-    }
-
-    #[inline]
-    pub fn get_initial_specified_value() -> SpecifiedValue {
-        SpecifiedValue(None)
-    }
-
-    impl ToComputedValue for SpecifiedValue {
-        type ComputedValue = computed_value::T;
-
-        #[inline]
-        fn to_computed_value(&self, context: &Context) -> computed_value::T {
-            match self.0 {
-                Some(ref image) => computed_value::T(Some(image.to_computed_value(context))),
-                None => computed_value::T(None),
-            }
-        }
-        #[inline]
-        fn from_computed_value(computed: &computed_value::T) -> Self {
-            match computed.0 {
-                Some(ref image) =>
-                    SpecifiedValue(Some(ToComputedValue::from_computed_value(image))),
-                None => SpecifiedValue(None),
-            }
-        }
-    }
-
-    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
-        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
-            return Ok(SpecifiedValue(None));
-        }
-
-        Ok(SpecifiedValue(Some(try!(Image::parse(context, input)))))
-    }
-</%helpers:longhand>
+${helpers.predefined_type("border-image-source", "LayerImage",
+    initial_value="computed_value::T(None)",
+    initial_specified_value="SpecifiedValue(None)",
+    spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
+    vector=False,
+    animation_value_type="none",
+    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::HasViewportPercentage;
     use values::specified::{LengthOrNumber, Number};
 
--- a/servo/components/style/properties/longhand/svg.mako.rs
+++ b/servo/components/style/properties/longhand/svg.mako.rs
@@ -186,102 +186,18 @@
 ${helpers.single_keyword("mask-composite",
                          "add subtract intersect exclude",
                          vector=True,
                          products="gecko",
                          extra_prefixes="webkit",
                          animation_value_type="none",
                          spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")}
 
-<%helpers:vector_longhand name="mask-image" products="gecko" animation_value_type="none" extra_prefixes="webkit"
-                          has_uncacheable_values="${product == 'gecko'}"
-                          flags="CREATES_STACKING_CONTEXT",
-                          spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image">
-    use std::fmt;
-    use style_traits::ToCss;
-    use std::sync::Arc;
-    use values::specified::Image;
-    use values::specified::url::SpecifiedUrl;
-    use values::HasViewportPercentage;
-
-    pub mod computed_value {
-        use std::fmt;
-        use style_traits::ToCss;
-        use values::computed;
-        use values::specified::url::SpecifiedUrl;
-        #[derive(Debug, Clone, PartialEq)]
-        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-        pub enum T {
-            Image(computed::Image),
-            None
-        }
-
-        impl ToCss for T {
-            fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-                match *self {
-                    T::None => dest.write_str("none"),
-                    T::Image(ref image) => image.to_css(dest),
-                }
-            }
-        }
-    }
-
-    no_viewport_percentage!(SpecifiedValue);
-
-    #[derive(Debug, Clone, PartialEq)]
-    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-    pub enum SpecifiedValue {
-        Image(Image),
-        None
-    }
-
-    impl ToCss for SpecifiedValue {
-        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-            match *self {
-                SpecifiedValue::Image(ref image) => image.to_css(dest),
-                SpecifiedValue::None => dest.write_str("none"),
-            }
-        }
-    }
-
-    #[inline]
-    pub fn get_initial_value() -> computed_value::T {
-        computed_value::T::None
-    }
-    #[inline]
-    pub fn get_initial_specified_value() -> SpecifiedValue {
-        SpecifiedValue::None
-    }
-    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
-        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
-            Ok(SpecifiedValue::None)
-        } else {
-            let image = try!(Image::parse(context, input));
-            match image {
-                Image::Url(url_value) => {
-                    Ok(SpecifiedValue::Image(Image::Url(url_value)))
-                }
-                image => Ok(SpecifiedValue::Image(image))
-            }
-        }
-    }
-    impl ToComputedValue for SpecifiedValue {
-        type ComputedValue = computed_value::T;
-
-        #[inline]
-        fn to_computed_value(&self, context: &Context) -> computed_value::T {
-            match *self {
-                SpecifiedValue::None => computed_value::T::None,
-                SpecifiedValue::Image(ref image) =>
-                    computed_value::T::Image(image.to_computed_value(context)),
-            }
-        }
-
-        #[inline]
-        fn from_computed_value(computed: &computed_value::T) -> Self {
-            match *computed {
-                computed_value::T::None => SpecifiedValue::None,
-                computed_value::T::Image(ref image) =>
-                    SpecifiedValue::Image(ToComputedValue::from_computed_value(image)),
-            }
-        }
-    }
-</%helpers:vector_longhand>
+${helpers.predefined_type("mask-image", "LayerImage",
+    initial_value="computed_value::T(None)",
+    initial_specified_value="SpecifiedValue(None)",
+    spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image",
+    vector=True,
+    products="gecko",
+    extra_prefixes="webkit",
+    animation_value_type="none",
+    flags="CREATES_STACKING_CONTEXT",
+    has_uncacheable_values="${product == 'gecko'}")}
\ No newline at end of file
--- a/servo/components/style/values/computed/image.rs
+++ b/servo/components/style/values/computed/image.rs
@@ -672,8 +672,22 @@ impl AngleOrCorner {
                 try!(horizontal.to_css(dest));
                 try!(dest.write_str(" "));
                 try!(vertical.to_css(dest));
                 Ok(())
             }
         }
     }
 }
+
+/// Computed values for none | <image> | <mask-source>.
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub struct LayerImage(pub Option<Image>);
+
+impl ToCss for LayerImage {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        match self.0 {
+            None => dest.write_str("none"),
+            Some(ref image) => image.to_css(dest),
+        }
+    }
+}
\ No newline at end of file
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -17,17 +17,17 @@ use std::fmt;
 use style_traits::ToCss;
 use super::{CSSFloat, CSSInteger, RGBA};
 use super::generics::BorderRadiusSize as GenericBorderRadiusSize;
 use super::specified;
 use super::specified::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
 
 pub use app_units::Au;
 pub use cssparser::Color as CSSColor;
-pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientItem};
+pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientItem, LayerImage};
 pub use self::image::{GradientKind, Image, ImageRect, LengthOrKeyword, LengthOrPercentageOrKeyword};
 pub use super::{Auto, Either, None_};
 #[cfg(feature = "gecko")]
 pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
 pub use super::specified::{BorderStyle, GridLine, Percentage, UrlOrNone};
 pub use super::specified::url::SpecifiedUrl;
 pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
 pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone};
--- a/servo/components/style/values/specified/image.rs
+++ b/servo/components/style/values/specified/image.rs
@@ -661,8 +661,58 @@ define_css_keyword_enum!(SizeKeyword: "c
 impl SizeKeyword {
     fn parse_modern(input: &mut Parser) -> Result<Self, ()> {
         match try!(SizeKeyword::parse(input)) {
             SizeKeyword::Contain | SizeKeyword::Cover => Err(()),
             keyword => Ok(keyword),
         }
     }
 }
+
+/// Specified values for none | <image> | <mask-source>.
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[allow(missing_docs)]
+pub struct LayerImage(pub Option<Image>);
+use values::HasViewportPercentage;
+no_viewport_percentage!(LayerImage);
+
+impl ToCss for LayerImage {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        match *self {
+            LayerImage(Some(ref image)) => image.to_css(dest),
+            LayerImage(None) => dest.write_str("none"),
+        }
+    }
+}
+
+use super::computed::{ToComputedValue, Context};
+impl ToComputedValue for LayerImage {
+    type ComputedValue = super::computed::LayerImage;
+
+    #[inline]
+    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+        match *self {
+            LayerImage(None) => super::computed::LayerImage(None),
+            LayerImage(Some(ref image)) =>
+                super::computed::LayerImage(Some(image.to_computed_value(context))),
+        }
+    }
+
+    #[inline]
+    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+        match *computed {
+            super::computed::LayerImage(None) => LayerImage(None),
+            super::computed::LayerImage(Some(ref image)) =>
+                LayerImage(Some(ToComputedValue::from_computed_value(image))),
+        }
+    }
+}
+
+impl Parse for LayerImage {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
+            Ok(LayerImage(None))
+        } else {
+            Ok(LayerImage(Some(try!(Image::parse(context, input)))))
+        }
+    }
+}
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -24,17 +24,17 @@ use super::computed::{self, Context};
 use super::computed::{Shadow as ComputedShadow, ToComputedValue};
 use super::generics::BorderRadiusSize as GenericBorderRadiusSize;
 
 #[cfg(feature = "gecko")]
 pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
 pub use self::color::Color;
 pub use self::grid::{GridLine, TrackKeyword};
 pub use self::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
-pub use self::image::{GradientItem, GradientKind, HorizontalDirection, Image, ImageRect};
+pub use self::image::{GradientItem, GradientKind, HorizontalDirection, Image, ImageRect, LayerImage};
 pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword, SizeKeyword, VerticalDirection};
 pub use self::length::AbsoluteLength;
 pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
 pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
 pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength, CalcUnit};
 pub use self::length::{MaxLength, MinLength};
 pub use self::position::{HorizontalPosition, Position, VerticalPosition};