servo: Merge #17177 - Make SVGPaint generic (from Manishearth:generic-paint); r=upsuper
authorManish Goregaokar <manishearth@gmail.com>
Mon, 05 Jun 2017 21:17:57 -0700
changeset 412949 f60d569fdbc0d6def90ef0c6864e97cc07a0ee96
parent 412933 d3b8e8571020ffad87bb140b190799fc6fae06d5
child 412950 97ce14cb28f98838664b6f8576b577ba65df14ee
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersupsuper
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
servo: Merge #17177 - Make SVGPaint generic (from Manishearth:generic-paint); r=upsuper r=xidorn https://bugzilla.mozilla.org/show_bug.cgi?id=1369277 Source-Repo: https://github.com/servo/servo Source-Revision: 6b78a514f8de1975b8e683b5c9b9d7a0bf9f8227
servo/components/style/properties/gecko.mako.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/generics/mod.rs
servo/components/style/values/specified/mod.rs
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -411,17 +411,17 @@ fn color_to_nscolor_zero_currentcolor(co
 % if need_clone:
     <%call expr="impl_color_clone(ident, gecko_ffi_name, complex_color)"></%call>
 % endif
 </%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 values::generics::SVGPaintKind;
         use self::structs::nsStyleSVGPaintType;
         use self::structs::nsStyleSVGFallbackType;
 
         let ref mut paint = ${get_gecko_property(gecko_ffi_name)};
         unsafe {
             bindings::Gecko_nsStyleSVGPaint_Reset(paint);
         }
         let fallback = v.fallback.take();
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -527,91 +527,41 @@ impl IntegerOrAuto {
     pub fn integer_or(&self, auto_value: CSSInteger) -> CSSInteger {
         match *self {
             Either::First(n) => n,
             Either::Second(Auto) => auto_value,
         }
     }
 }
 
-
-/// 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 {
-    /// The paint source
-    pub kind: SVGPaintKind,
-    /// The fallback color
-    pub fallback: Option<CSSColor>,
-}
+/// Computed SVG Paint value
+pub type SVGPaint = ::values::generics::SVGPaint<CSSColor>;
+/// Computed SVG Paint Kind value
+pub type SVGPaintKind = ::values::generics::SVGPaintKind<CSSColor>;
 
 impl Default for SVGPaint {
     fn default() -> Self {
         SVGPaint {
-            kind: SVGPaintKind::None,
+            kind: ::values::generics::SVGPaintKind::None,
             fallback: None,
         }
     }
 }
 
 impl SVGPaint {
     /// Opaque black color
     pub fn black() -> Self {
         let rgba = RGBA::from_floats(0., 0., 0., 1.);
         SVGPaint {
-            kind: SVGPaintKind::Color(CSSColor::RGBA(rgba)),
+            kind: ::values::generics::SVGPaintKind::Color(CSSColor::RGBA(rgba)),
             fallback: None,
         }
     }
 }
 
-/// An SVG paint value without the fallback
-///
-/// Whereas the spec only allows PaintServer
-/// to have a fallback, Gecko lets the context
-/// properties have a fallback as well.
-#[derive(Debug, Clone, PartialEq)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum SVGPaintKind {
-    /// `none`
-    None,
-    /// `<color>`
-    Color(CSSColor),
-    /// `url(...)`
-    PaintServer(SpecifiedUrl),
-    /// `context-fill`
-    ContextFill,
-    /// `context-stroke`
-    ContextStroke,
-}
-
-impl ToCss for SVGPaintKind {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        match *self {
-            SVGPaintKind::None => dest.write_str("none"),
-            SVGPaintKind::ContextStroke => dest.write_str("context-stroke"),
-            SVGPaintKind::ContextFill => dest.write_str("context-fill"),
-            SVGPaintKind::Color(ref color) => color.to_css(dest),
-            SVGPaintKind::PaintServer(ref server) => server.to_css(dest),
-        }
-    }
-}
-
-impl ToCss for SVGPaint {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        self.kind.to_css(dest)?;
-        if let Some(ref fallback) = self.fallback {
-            fallback.to_css(dest)?;
-        }
-        Ok(())
-    }
-}
-
 /// <length> | <percentage> | <number>
 pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>;
 
 #[derive(Clone, PartialEq, Eq, Copy, Debug)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[allow(missing_docs)]
 /// A computed cliprect for clip and image-region
 pub struct ClipRect {
--- a/servo/components/style/values/generics/mod.rs
+++ b/servo/components/style/values/generics/mod.rs
@@ -6,16 +6,17 @@
 //! for both specified and computed values.
 
 use counter_style::{Symbols, parse_counter_style_name};
 use cssparser::Parser;
 use parser::{Parse, ParserContext};
 use std::fmt;
 use style_traits::{OneOrMoreCommaSeparated, ToCss};
 use super::CustomIdent;
+use values::specified::url::SpecifiedUrl;
 
 pub mod background;
 pub mod basic_shape;
 pub mod border;
 pub mod grid;
 pub mod image;
 pub mod position;
 pub mod rect;
@@ -263,8 +264,138 @@ impl Parse for FontSettingTagFloat {
 }
 
 impl ToCss for FontSettingTagFloat {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
         dest.write_str(" ")?;
         self.0.to_css(dest)
     }
 }
+
+
+/// 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<ColorType> {
+    /// The paint source
+    pub kind: SVGPaintKind<ColorType>,
+    /// The fallback color
+    pub fallback: Option<ColorType>,
+}
+
+/// An SVG paint value without the fallback
+///
+/// Whereas the spec only allows PaintServer
+/// to have a fallback, Gecko lets the context
+/// properties have a fallback as well.
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+pub enum SVGPaintKind<ColorType> {
+    /// `none`
+    None,
+    /// `<color>`
+    Color(ColorType),
+    /// `url(...)`
+    PaintServer(SpecifiedUrl),
+    /// `context-fill`
+    ContextFill,
+    /// `context-stroke`
+    ContextStroke,
+}
+
+impl<ColorType> SVGPaintKind<ColorType> {
+    /// Convert to a value with a different kind of color
+    pub fn convert<F, OtherColor>(&self, f: F) -> SVGPaintKind<OtherColor>
+        where F: Fn(&ColorType) -> OtherColor {
+            match *self {
+                SVGPaintKind::None => SVGPaintKind::None,
+                SVGPaintKind::ContextStroke => SVGPaintKind::ContextStroke,
+                SVGPaintKind::ContextFill => SVGPaintKind::ContextFill,
+                SVGPaintKind::Color(ref color) => {
+                    SVGPaintKind::Color(f(color))
+                }
+                SVGPaintKind::PaintServer(ref server) => {
+                    SVGPaintKind::PaintServer(server.clone())
+                }
+            }
+    }
+}
+
+impl<ColorType> SVGPaint<ColorType> {
+    /// Convert to a value with a different kind of color
+    pub fn convert<F, OtherColor>(&self, f: F) -> SVGPaint<OtherColor>
+        where F: Fn(&ColorType) -> OtherColor {
+        SVGPaint {
+            kind: self.kind.convert(&f),
+            fallback: self.fallback.as_ref().map(|color| f(color))
+        }
+    }
+}
+
+impl<ColorType> SVGPaintKind<ColorType> {
+    /// Parse a keyword value only
+    fn parse_ident(input: &mut Parser) -> Result<Self, ()> {
+        Ok(match_ignore_ascii_case! { &input.expect_ident()?,
+            "none" => SVGPaintKind::None,
+            "context-fill" => SVGPaintKind::ContextFill,
+            "context-stroke" => SVGPaintKind::ContextStroke,
+            _ => return Err(())
+        })
+    }
+}
+
+impl<ColorType: Parse> Parse for SVGPaint<ColorType> {
+    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+        if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
+            let fallback = input.try(|i| ColorType::parse(context, i));
+            Ok(SVGPaint {
+                kind: SVGPaintKind::PaintServer(url),
+                fallback: fallback.ok(),
+            })
+        } else if let Ok(kind) = input.try(SVGPaintKind::parse_ident) {
+            if let SVGPaintKind::None = kind {
+                Ok(SVGPaint {
+                    kind: kind,
+                    fallback: None,
+                })
+            } else {
+                let fallback = input.try(|i| ColorType::parse(context, i));
+                Ok(SVGPaint {
+                    kind: kind,
+                    fallback: fallback.ok(),
+                })
+            }
+        } else if let Ok(color) = input.try(|i| ColorType::parse(context, i)) {
+            Ok(SVGPaint {
+                kind: SVGPaintKind::Color(color),
+                fallback: None,
+            })
+        } else {
+            Err(())
+        }
+    }
+}
+
+impl<ColorType: ToCss> ToCss for SVGPaintKind<ColorType> {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        match *self {
+            SVGPaintKind::None => dest.write_str("none"),
+            SVGPaintKind::ContextStroke => dest.write_str("context-stroke"),
+            SVGPaintKind::ContextFill => dest.write_str("context-fill"),
+            SVGPaintKind::Color(ref color) => color.to_css(dest),
+            SVGPaintKind::PaintServer(ref server) => server.to_css(dest),
+        }
+    }
+}
+
+impl<ColorType: ToCss> ToCss for SVGPaint<ColorType> {
+    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+        self.kind.to_css(dest)?;
+        if let Some(ref fallback) = self.fallback {
+            fallback.to_css(dest)?;
+        }
+        Ok(())
+    }
+}
+
+
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -928,113 +928,21 @@ impl Shadow {
             color: color,
             inset: inset,
         })
     }
 }
 
 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 {
-    /// The paint source
-    pub kind: SVGPaintKind,
-    /// The fallback color
-    pub fallback: Option<CSSColor>,
-}
-
-/// An SVG paint value without the fallback
-///
-/// Whereas the spec only allows PaintServer
-/// to have a fallback, Gecko lets the context
-/// properties have a fallback as well.
-#[derive(Debug, Clone, PartialEq)]
-#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
-pub enum SVGPaintKind {
-    /// `none`
-    None,
-    /// `<color>`
-    Color(CSSColor),
-    /// `url(...)`
-    PaintServer(SpecifiedUrl),
-    /// `context-fill`
-    ContextFill,
-    /// `context-stroke`
-    ContextStroke,
-}
-
-impl SVGPaintKind {
-    fn parse_ident(input: &mut Parser) -> Result<Self, ()> {
-        Ok(match_ignore_ascii_case! { &input.expect_ident()?,
-            "none" => SVGPaintKind::None,
-            "context-fill" => SVGPaintKind::ContextFill,
-            "context-stroke" => SVGPaintKind::ContextStroke,
-            _ => return Err(())
-        })
-    }
-}
+/// Specified SVG Paint value
+pub type SVGPaint = ::values::generics::SVGPaint<CSSColor>;
 
-impl Parse for SVGPaint {
-    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
-        if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
-            let fallback = input.try(|i| CSSColor::parse(context, i));
-            Ok(SVGPaint {
-                kind: SVGPaintKind::PaintServer(url),
-                fallback: fallback.ok(),
-            })
-        } else if let Ok(kind) = input.try(SVGPaintKind::parse_ident) {
-            if kind == SVGPaintKind::None {
-                Ok(SVGPaint {
-                    kind: kind,
-                    fallback: None,
-                })
-            } else {
-                let fallback = input.try(|i| CSSColor::parse(context, i));
-                Ok(SVGPaint {
-                    kind: kind,
-                    fallback: fallback.ok(),
-                })
-            }
-        } else if let Ok(color) = input.try(|i| CSSColor::parse(context, i)) {
-            Ok(SVGPaint {
-                kind: SVGPaintKind::Color(color),
-                fallback: None,
-            })
-        } else {
-            Err(())
-        }
-    }
-}
-
-impl ToCss for SVGPaintKind {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        match *self {
-            SVGPaintKind::None => dest.write_str("none"),
-            SVGPaintKind::ContextStroke => dest.write_str("context-stroke"),
-            SVGPaintKind::ContextFill => dest.write_str("context-fill"),
-            SVGPaintKind::Color(ref color) => color.to_css(dest),
-            SVGPaintKind::PaintServer(ref server) => server.to_css(dest),
-        }
-    }
-}
-
-impl ToCss for SVGPaint {
-    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
-        self.kind.to_css(dest)?;
-        if let Some(ref fallback) = self.fallback {
-            fallback.to_css(dest)?;
-        }
-        Ok(())
-    }
-}
-
+/// Specified SVG Paint Kind value
+pub type SVGPaintKind = ::values::generics::SVGPaintKind<CSSColor>;
 
 impl ToComputedValue for SVGPaint {
     type ComputedValue = super::computed::SVGPaint;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
         super::computed::SVGPaint {
             kind: self.kind.to_computed_value(context),
@@ -1051,46 +959,27 @@ impl ToComputedValue for SVGPaint {
     }
 }
 
 impl ToComputedValue for SVGPaintKind {
     type ComputedValue = super::computed::SVGPaintKind;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
-        match *self {
-            SVGPaintKind::None => super::computed::SVGPaintKind::None,
-            SVGPaintKind::ContextStroke => super::computed::SVGPaintKind::ContextStroke,
-            SVGPaintKind::ContextFill => super::computed::SVGPaintKind::ContextFill,
-            SVGPaintKind::Color(ref color) => {
-                let color = match color.parsed {
-                    Color::CurrentColor => cssparser::Color::RGBA(context.style().get_color().clone_color()),
-                    _ => color.to_computed_value(context),
-                };
-                super::computed::SVGPaintKind::Color(color)
+        self.convert(|color| {
+            match color.parsed {
+                Color::CurrentColor => cssparser::Color::RGBA(context.style().get_color().clone_color()),
+                _ => color.to_computed_value(context),
             }
-            SVGPaintKind::PaintServer(ref server) => {
-                super::computed::SVGPaintKind::PaintServer(server.to_computed_value(context))
-            }
-        }
+        })
     }
 
     #[inline]
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
-        match *computed {
-            super::computed::SVGPaintKind::None => SVGPaintKind::None,
-            super::computed::SVGPaintKind::ContextStroke => SVGPaintKind::ContextStroke,
-            super::computed::SVGPaintKind::ContextFill => SVGPaintKind::ContextFill,
-            super::computed::SVGPaintKind::Color(ref color) => {
-                SVGPaintKind::Color(ToComputedValue::from_computed_value(color))
-            }
-            super::computed::SVGPaintKind::PaintServer(ref server) => {
-                SVGPaintKind::PaintServer(ToComputedValue::from_computed_value(server))
-            }
-        }
+        computed.convert(ToComputedValue::from_computed_value)
     }
 }
 
 /// <length> | <percentage> | <number>
 pub type LengthOrPercentageOrNumber = Either<Number, LengthOrPercentage>;
 
 impl LengthOrPercentageOrNumber {
     /// parse a <length-percentage> | <number> enforcing that the contents aren't negative