Bug 1338764 - Implement context-{fill|stroke}-opacity property values. draft
authorcku <cku@mozilla.com>
Thu, 20 Apr 2017 17:46:44 +0800
changeset 566448 874421d503f3e1009a879d4aa60f29d75fb97911
parent 566378 dd530a59750adcaa0d48fa4f69b0cdb52715852a
child 625316 6ca19fc416ff26e377cb87ab2b8664d5cbe6f7fd
push id55217
push userbmo:cku@mozilla.com
push dateFri, 21 Apr 2017 15:27:36 +0000
bugs1338764
milestone55.0a1
Bug 1338764 - Implement context-{fill|stroke}-opacity property values. MozReview-Commit-ID: In1hM9gcW93
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
servo/components/style/build_gecko.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/inherited_svg.mako.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/specified/mod.rs
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1405,16 +1405,50 @@ Gecko_CopyFiltersFrom(nsStyleEffects* aS
 
 void
 Gecko_nsStyleFilter_SetURLValue(nsStyleFilter* aEffects, ServoBundledURI aURI)
 {
   RefPtr<css::URLValue> url = aURI.IntoCssUrl();
   aEffects->SetURL(url.get());
 }
 
+void Gecko_nsStyleSVG_ResetFillOpacity(nsStyleSVG *dest)
+{
+  dest->SetFillOpacitySource(eStyleSVGOpacitySource_Normal);
+  dest->mFillOpacity = 1.0;
+}
+
+void Gecko_nsStyleSVG_ResetStrokeOpacity(nsStyleSVG *dest)
+{
+  dest->SetStrokeOpacitySource(eStyleSVGOpacitySource_Normal);
+  dest->mStrokeOpacity = 1.0;
+}
+
+void Gecko_nsStyleSVG_SetFillOpacitySource(nsStyleSVG *dest, const nsStyleSVGOpacitySource aOpacity)
+{
+  dest->SetFillOpacitySource(aOpacity);
+}
+
+void Gecko_nsStyleSVG_SetStrokeOpacitySource(nsStyleSVG *dest, const nsStyleSVGOpacitySource aOpacity)
+{
+  dest->SetStrokeOpacitySource(aOpacity);
+}
+
+void Gecko_nsStyleSV_CopyFillOpacityFrom(nsStyleSVG* dest, const nsStyleSVG* src)
+{
+  dest->SetFillOpacitySource(src->FillOpacitySource());
+  dest->mFillOpacity = src->mFillOpacity;
+}
+
+void Gecko_nsStyleSV_CopyStrokeOpacityFrom(nsStyleSVG* dest, const nsStyleSVG* src)
+{
+  dest->SetStrokeOpacitySource(src->StrokeOpacitySource());
+  dest->mStrokeOpacity = src->mStrokeOpacity;
+}
+
 void
 Gecko_nsStyleSVGPaint_CopyFrom(nsStyleSVGPaint* aDest, const nsStyleSVGPaint* aSrc)
 {
   *aDest = *aSrc;
 }
 
 void
 Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* aPaint, ServoBundledURI aURI)
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -357,16 +357,23 @@ void Gecko_CopyShapeSourceFrom(mozilla::
 void Gecko_DestroyShapeSource(mozilla::StyleShapeSource* shape);
 mozilla::StyleBasicShape* Gecko_NewBasicShape(mozilla::StyleBasicShapeType type);
 void Gecko_StyleShapeSource_SetURLValue(mozilla::StyleShapeSource* shape, ServoBundledURI uri);
 
 void Gecko_ResetFilters(nsStyleEffects* effects, size_t new_len);
 void Gecko_CopyFiltersFrom(nsStyleEffects* aSrc, nsStyleEffects* aDest);
 void Gecko_nsStyleFilter_SetURLValue(nsStyleFilter* effects, ServoBundledURI uri);
 
+void Gecko_nsStyleSVG_ResetFillOpacity(nsStyleSVG *dest);
+void Gecko_nsStyleSVG_ResetStrokeOpacity(nsStyleSVG *dest);
+void Gecko_nsStyleSVG_SetFillOpacitySource(nsStyleSVG *dest, const nsStyleSVGOpacitySource aOpacity);
+void Gecko_nsStyleSVG_SetStrokeOpacitySource(nsStyleSVG *dest, const nsStyleSVGOpacitySource aOpacity);
+void Gecko_nsStyleSV_CopyFillOpacityFrom(nsStyleSVG* dest, const nsStyleSVG* src);
+void Gecko_nsStyleSV_CopyStrokeOpacityFrom(nsStyleSVG* dest, const nsStyleSVG* src);
+
 void Gecko_nsStyleSVGPaint_CopyFrom(nsStyleSVGPaint* dest, const nsStyleSVGPaint* src);
 void Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* paint, ServoBundledURI uri);
 void Gecko_nsStyleSVGPaint_Reset(nsStyleSVGPaint* paint);
 
 void Gecko_nsStyleSVG_SetDashArrayLength(nsStyleSVG* svg, uint32_t len);
 void Gecko_nsStyleSVG_CopyDashArray(nsStyleSVG* dst, const nsStyleSVG* src);
 
 mozilla::css::URLValue* Gecko_NewURLValue(ServoBundledURI uri);
--- a/servo/components/style/build_gecko.rs
+++ b/servo/components/style/build_gecko.rs
@@ -428,16 +428,17 @@ mod bindings {
             "nsStyleImage",
             "nsStyleImageLayers",
             "nsStyleList",
             "nsStyleMargin",
             "nsStyleOutline",
             "nsStylePadding",
             "nsStylePosition",
             "nsStyleSVG",
+            "nsStyleSVGOpacitySource",
             "nsStyleSVGPaint",
             "nsStyleSVGReset",
             "nsStyleTable",
             "nsStyleTableBorder",
             "nsStyleText",
             "nsStyleTextReset",
             "nsStyleUIReset",
             "nsStyleUnion",
@@ -696,16 +697,17 @@ mod bindings {
             "nsStyleImageRequest",
             "nsStyleList",
             "nsStyleMargin",
             "nsStyleOutline",
             "nsStylePadding",
             "nsStylePosition",
             "nsStyleQuoteValues",
             "nsStyleSVG",
+            "nsStyleSVGOpacitySource",
             "nsStyleSVGPaint",
             "nsStyleSVGReset",
             "nsStyleTable",
             "nsStyleTableBorder",
             "nsStyleText",
             "nsStyleTextReset",
             "nsStyleUIReset",
             "nsStyleUnion",
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -411,16 +411,52 @@ fn color_to_nscolor_zero_currentcolor(co
 <%def name="impl_color(ident, gecko_ffi_name, need_clone=False, complex_color=True)">
 <%call expr="impl_color_setter(ident, gecko_ffi_name, complex_color)"></%call>
 <%call expr="impl_color_copy(ident, gecko_ffi_name, complex_color)"></%call>
 % if need_clone:
     <%call expr="impl_color_clone(ident, gecko_ffi_name, complex_color)"></%call>
 % endif
 </%def>
 
+<%def name="impl_svg_opacity(ident, gecko_ffi_name, need_clone=False)">
+    <%
+        fill_or_stroke = "FillOpacity" if ident == "fill_opacity" else "StrokeOpacity"
+    %>
+    #[allow(non_snake_case)]
+    pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
+        use values::computed::SVGOpacity;
+        use self::structs::nsStyleSVGOpacitySource;
+        unsafe {
+            bindings::Gecko_nsStyleSVG_Reset${fill_or_stroke}(& mut self.gecko);
+        }
+
+        match v {
+            SVGOpacity::Opacity(opacity) => {
+                let ref mut result = ${get_gecko_property(gecko_ffi_name)};
+                *result = opacity
+            },
+            SVGOpacity::ContextFillOpacity =>
+                unsafe {
+                    bindings::Gecko_nsStyleSVG_Set${fill_or_stroke}Source(& mut self.gecko, nsStyleSVGOpacitySource::eStyleSVGOpacitySource_ContextFillOpacity);
+                },
+            SVGOpacity::ContextStrokeOpacity =>
+                unsafe {
+                    bindings::Gecko_nsStyleSVG_Set${fill_or_stroke}Source(& mut self.gecko, nsStyleSVGOpacitySource::eStyleSVGOpacitySource_ContextStrokeOpacity);
+                },
+        }
+    }
+
+    #[allow(non_snake_case)]
+    pub fn copy_${ident}_from(&mut self, other: &Self) {
+        unsafe{
+            bindings::Gecko_nsStyleSV_Copy${fill_or_stroke}From(& mut self.gecko, &other.gecko);
+        }
+    }
+</%def>
+
 <%def name="impl_svg_paint(ident, gecko_ffi_name, need_clone=False, complex_color=True)">
     #[allow(non_snake_case)]
     pub fn set_${ident}(&mut self, mut v: longhands::${ident}::computed_value::T) {
         use values::computed::SVGPaintKind;
         use self::structs::nsStyleSVGPaintType;
 
         let ref mut paint = ${get_gecko_property(gecko_ffi_name)};
         unsafe {
@@ -681,16 +717,17 @@ impl Debug for ${style_struct.gecko_stru
         "LengthOrPercentageOrNone": impl_style_coord,
         "LengthOrNone": impl_style_coord,
         "LengthOrNormal": impl_style_coord,
         "MaxLength": impl_style_coord,
         "MinLength": impl_style_coord,
         "Number": impl_simple,
         "Integer": impl_simple,
         "Opacity": impl_simple,
+        "SVGOpacity": impl_svg_opacity,
         "CSSColor": impl_color,
         "SVGPaint": impl_svg_paint,
         "UrlOrNone": impl_css_url,
     }
 
     def longhand_method(longhand):
         args = dict(ident=longhand.ident, gecko_ffi_name=longhand.gecko_ffi_name,
                     need_clone=longhand.need_clone)
--- a/servo/components/style/properties/longhand/inherited_svg.mako.rs
+++ b/servo/components/style/properties/longhand/inherited_svg.mako.rs
@@ -36,17 +36,17 @@
 ${helpers.predefined_type(
     "fill", "SVGPaint",
     "::values::computed::SVGPaint::black()",
     products="gecko",
     animation_type="none",
     boxed=True,
     spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint")}
 
-${helpers.predefined_type("fill-opacity", "Opacity", "1.0",
+${helpers.predefined_type("fill-opacity", "SVGOpacity", "Default::default()",
                           products="gecko", animation_type="none",
                           spec="https://www.w3.org/TR/SVG11/painting.html#FillOpacityProperty")}
 
 ${helpers.single_keyword("fill-rule", "nonzero evenodd",
                          gecko_enum_prefix="StyleFillRule",
                          gecko_inexhaustive=True,
                          products="gecko", animation_type="none",
                          spec="https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty")}
@@ -81,17 +81,17 @@
                          products="gecko", animation_type="none",
                          spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty")}
 
 ${helpers.predefined_type("stroke-miterlimit", "Number", "4.0",
                           "parse_at_least_one", products="gecko",
                           animation_type="none",
                           spec="https://www.w3.org/TR/SVG11/painting.html#StrokeMiterlimitProperty")}
 
-${helpers.predefined_type("stroke-opacity", "Opacity", "1.0",
+${helpers.predefined_type("stroke-opacity", "SVGOpacity", "Default::default()",
                           products="gecko", animation_type="none",
                           spec="https://www.w3.org/TR/SVG11/painting.html#StrokeOpacityProperty")}
 
 ${helpers.predefined_type("stroke-dasharray",
                           "LengthOrPercentageOrNumber",
                           "Either::Second(0.0)",
                           "parse_non_negative",
                           vector="True",
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -388,16 +388,44 @@ impl ToCss for NumberOrPercentage {
             NumberOrPercentage::Number(number) => number.to_css(dest),
         }
     }
 }
 
 /// A type used for opacity.
 pub type Opacity = CSSFloat;
 
+/// An SVG opacity value.
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum SVGOpacity {
+    /// Float from 0 to 1
+    Opacity(Opacity),
+    /// `context-fill-opacity`
+    ContextFillOpacity,
+    /// `context-stroke-opacity`
+    ContextStrokeOpacity,
+}
+
+impl Default for SVGOpacity {
+    fn default() -> Self {
+        SVGOpacity::Opacity(1.0)
+    }
+}
+
+impl ToCss for SVGOpacity {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        match *self {
+            SVGOpacity::ContextFillOpacity => dest.write_str("context-stroke-opacity"),
+            SVGOpacity::ContextStrokeOpacity => dest.write_str("context-stroke-opacity"),
+            SVGOpacity::Opacity(opacity) => opacity.to_css(dest),
+        }
+    }
+}
+
 /// A `<integer>` value.
 pub type Integer = CSSInteger;
 
 /// <integer> | auto
 pub type IntegerOrAuto = Either<CSSInteger, Auto>;
 
 impl IntegerOrAuto {
     /// Returns the integer value if it is an integer, otherwise return
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -803,16 +803,22 @@ impl ToCss for NumberOrPercentage {
 
 #[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
 pub struct Opacity(Number);
 
 no_viewport_percentage!(Opacity);
 
+impl Default for Opacity {
+    fn default() -> Self {
+        Opacity(Number{value:1.0, calc_clamping_mode: None,})
+    }
+}
+
 impl Parse for Opacity {
     fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
         parse_number(context, input).map(Opacity)
     }
 }
 
 impl ToComputedValue for Opacity {
     type ComputedValue = CSSFloat;
@@ -1048,16 +1054,91 @@ impl Shadow {
             blur_radius: lengths[2].take(),
             spread_radius: lengths[3].take(),
             color: color,
             inset: inset,
         })
     }
 }
 
+no_viewport_percentage!(SVGOpacity);
+
+/// An SVG opacity value.
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum SVGOpacity {
+    /// Float from 0 to 1
+    Opacity(Opacity),
+    /// `context-fill-opacity`
+    ContextFillOpacity,
+    /// `context-stroke-opacity`
+    ContextStrokeOpacity,
+}
+
+impl Default for SVGOpacity {
+    fn default() -> Self {
+        SVGOpacity::Opacity(Opacity::default())
+    }
+}
+
+impl ToCss for SVGOpacity {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        match *self {
+            SVGOpacity::ContextFillOpacity => dest.write_str("context-stroke-opacity"),
+            SVGOpacity::ContextStrokeOpacity => dest.write_str("context-stroke-opacity"),
+            SVGOpacity::Opacity(opacity) => opacity.to_css(dest),
+        }
+    }
+}
+
+impl SVGOpacity {
+    fn parse_ident(input: &mut Parser) -> Result<Self, ()> {
+        Ok(match_ignore_ascii_case! { &input.expect_ident()?,
+            "context-fill-opacity" => SVGOpacity::ContextFillOpacity,
+            "context-stroke-opacity" => SVGOpacity::ContextStrokeOpacity,
+            _ => return Err(())
+        })
+    }
+}
+
+impl Parse for SVGOpacity {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        if let Ok(opacity) = Opacity::parse(context, input) {
+            // Question: why we need return here?
+            return Ok(SVGOpacity::Opacity(opacity));
+        } else if let Ok(opacity) = input.try(SVGOpacity::parse_ident) {
+            return Ok(opacity);
+        }
+
+        Err(())
+    }
+}
+
+impl ToComputedValue for SVGOpacity {
+    type ComputedValue = super::computed::SVGOpacity;
+
+    #[inline]
+    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+        match *self {
+            SVGOpacity::Opacity(opacity) => super::computed::SVGOpacity::Opacity(opacity.to_computed_value(context)),
+            SVGOpacity::ContextFillOpacity => super::computed::SVGOpacity::ContextFillOpacity,
+            SVGOpacity::ContextStrokeOpacity => super::computed::SVGOpacity::ContextStrokeOpacity,
+        }
+    }
+
+    #[inline]
+    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+        match *computed {
+            super::computed::SVGOpacity::Opacity(opacity) => SVGOpacity::Opacity(Opacity(Number{value:opacity, calc_clamping_mode: None}))
+            super::computed::SVGOpacity::ContextFillOpacity => SVGOpacity::ContextFillOpacity,
+            super::computed::SVGOpacity::ContextStrokeOpacity => SVGOpacity::ContextStrokeOpacity,
+        }
+    }
+}
+
 no_viewport_percentage!(SVGPaint);
 
 /// An SVG paint value
 ///
 /// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
 #[derive(Debug, Clone, PartialEq)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub struct SVGPaint {