Bug 1465307 - P3: Extract {animated,computed}::Color common parts. r?xidorn draft
authorDan Glastonbury <dan.glastonbury@gmail.com>
Tue, 05 Jun 2018 11:49:51 +1000
changeset 804569 71ef5aa85d98ddbb52cdd2d85576d2c667379610
parent 804565 976435661b40d6520d327e3940aec5112d9f64ba
child 804570 31610a71b94bec2a0119cbcf21d0c95781ec6312
push id112412
push userbmo:dglastonbury@mozilla.com
push dateWed, 06 Jun 2018 09:37:37 +0000
reviewersxidorn
bugs1465307
milestone62.0a1
Bug 1465307 - P3: Extract {animated,computed}::Color common parts. r?xidorn Extract the common parts of `animated::Color` and `computed::Color` out into `generics::color::Color<T>` that is generic over the type of RGBA color. MozReview-Commit-ID: EymSr7aqnAP
servo/components/style/gecko_bindings/sugar/style_complex_color.rs
servo/components/style/values/animated/color.rs
servo/components/style/values/computed/color.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/generics/color.rs
servo/components/style/values/generics/mod.rs
servo/components/style/values/specified/color.rs
--- a/servo/components/style/gecko_bindings/sugar/style_complex_color.rs
+++ b/servo/components/style/gecko_bindings/sugar/style_complex_color.rs
@@ -4,18 +4,18 @@
 
 //! Rust helpers to interact with Gecko's StyleComplexColor.
 
 use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
 use gecko_bindings::structs::StyleComplexColor;
 use gecko_bindings::structs::StyleComplexColor_Tag as Tag;
 use values::{Auto, Either};
 use values::computed::{Color as ComputedColor, RGBAColor as ComputedRGBA};
-use values::computed::ComplexColorRatios;
 use values::computed::ui::ColorOrAuto;
+use values::generics::color::{Color as GenericColor, ComplexColorRatios};
 
 impl StyleComplexColor {
     /// Create a `StyleComplexColor` value that represents `currentColor`.
     pub fn current_color() -> Self {
         StyleComplexColor {
             mColor: 0,
             mBgRatio: 0.,
             mFgRatio: 1.,
@@ -43,19 +43,19 @@ impl From<ComputedRGBA> for StyleComplex
             mTag: Tag::eNumeric,
         }
     }
 }
 
 impl From<ComputedColor> for StyleComplexColor {
     fn from(other: ComputedColor) -> Self {
         match other {
-            ComputedColor::Numeric(color) => color.into(),
-            ComputedColor::Foreground => Self::current_color(),
-            ComputedColor::Complex(color, ratios) => {
+            GenericColor::Numeric(color) => color.into(),
+            GenericColor::Foreground => Self::current_color(),
+            GenericColor::Complex(color, ratios) => {
                 debug_assert!(ratios != ComplexColorRatios::NUMERIC);
                 debug_assert!(ratios != ComplexColorRatios::FOREGROUND);
                 StyleComplexColor {
                     mColor: convert_rgba_to_nscolor(&color).into(),
                     mBgRatio: ratios.bg,
                     mFgRatio: ratios.fg,
                     mTag: Tag::eComplex,
                 }
@@ -64,26 +64,26 @@ impl From<ComputedColor> for StyleComple
     }
 }
 
 impl From<StyleComplexColor> for ComputedColor {
     fn from(other: StyleComplexColor) -> Self {
         match other.mTag {
             Tag::eNumeric => {
                 debug_assert!(other.mBgRatio == 1. && other.mFgRatio == 0.);
-                ComputedColor::Numeric(convert_nscolor_to_rgba(other.mColor))
+                GenericColor::Numeric(convert_nscolor_to_rgba(other.mColor))
             }
             Tag::eForeground => {
                 debug_assert!(other.mBgRatio == 0. && other.mFgRatio == 1.);
-                ComputedColor::Foreground
+                GenericColor::Foreground
             }
             Tag::eComplex => {
                 debug_assert!(other.mBgRatio != 1. || other.mFgRatio != 0.);
                 debug_assert!(other.mBgRatio != 0. || other.mFgRatio != 1.);
-                ComputedColor::Complex(
+                GenericColor::Complex(
                     convert_nscolor_to_rgba(other.mColor),
                     ComplexColorRatios {
                         bg: other.mBgRatio,
                         fg: other.mFgRatio,
                     },
                 )
             }
             Tag::eAuto => unreachable!("Unsupport StyleComplexColor with tag eAuto"),
--- a/servo/components/style/values/animated/color.rs
+++ b/servo/components/style/values/animated/color.rs
@@ -1,17 +1,17 @@
 /* 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/. */
 
 //! Animated types for CSS colors.
 
 use values::animated::{Animate, Procedure, ToAnimatedZero};
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
-use values::computed::ComplexColorRatios;
+use values::generics::color::{Color as GenericColor, ComplexColorRatios};
 
 /// An animated RGBA color.
 ///
 /// Unlike in computed values, each component value may exceed the
 /// range `[0.0, 1.0]`.
 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
 #[derive(Clone, Copy, Debug, PartialEq, ToAnimatedZero)]
 pub struct RGBA {
@@ -98,88 +98,71 @@ impl Animate for ComplexColorRatios {
         let bg = self.bg.animate(&other.bg, procedure)?;
         let fg = self.fg.animate(&other.fg, procedure)?;
 
         Ok(ComplexColorRatios { bg, fg })
     }
 }
 
 #[allow(missing_docs)]
-#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum Color {
-    Numeric(RGBA),
-    Foreground,
-    Complex(RGBA, ComplexColorRatios),
-}
+pub type Color = GenericColor<RGBA>;
 
 impl Color {
-    fn currentcolor() -> Self {
-        Color::Foreground
-    }
-
-    /// Returns a transparent intermediate color.
-    pub fn transparent() -> Self {
-        Color::Numeric(RGBA::transparent())
-    }
-
     fn effective_intermediate_rgba(&self) -> RGBA {
         match *self {
-            Color::Numeric(color) => color,
-            Color::Foreground => RGBA::transparent(),
-            Color::Complex(color, ratios) => RGBA {
+            GenericColor::Numeric(color) => color,
+            GenericColor::Foreground => RGBA::transparent(),
+            GenericColor::Complex(color, ratios) => RGBA {
                 alpha: color.alpha * ratios.bg,
                 ..color.clone()
             },
         }
     }
 
     fn effective_ratios(&self) -> ComplexColorRatios {
         match *self {
-            Color::Numeric(..) => ComplexColorRatios::NUMERIC,
-            Color::Foreground => ComplexColorRatios::FOREGROUND,
-            Color::Complex(.., ratios) => ratios,
+            GenericColor::Numeric(..) => ComplexColorRatios::NUMERIC,
+            GenericColor::Foreground => ComplexColorRatios::FOREGROUND,
+            GenericColor::Complex(.., ratios) => ratios,
         }
     }
 }
 
 impl Animate for Color {
     #[inline]
     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
+        use self::GenericColor::*;
+
         // Common cases are interpolating between two numeric colors,
         // two currentcolors, and a numeric color and a currentcolor.
         let (this_weight, other_weight) = procedure.weights();
 
         Ok(match (*self, *other, procedure) {
             // Any interpolation of currentColor with currentColor returns currentColor.
-            (Color::Foreground, Color::Foreground, Procedure::Interpolate { .. }) => {
-                Color::currentcolor()
-            }
+            (Foreground, Foreground, Procedure::Interpolate { .. }) => Color::currentcolor(),
             // Animating two numeric colors.
-            (Color::Numeric(c1), Color::Numeric(c2), _) => {
-                Color::Numeric(c1.animate(&c2, procedure)?)
-            }
+            (Numeric(c1), Numeric(c2), _) => Numeric(c1.animate(&c2, procedure)?),
             // Combinations of numeric color and currentColor
-            (Color::Foreground, Color::Numeric(color), _) => Color::Complex(
+            (Foreground, Numeric(color), _) => Self::with_ratios(
                 color,
                 ComplexColorRatios {
                     bg: other_weight as f32,
                     fg: this_weight as f32,
                 },
             ),
-            (Color::Numeric(color), Color::Foreground, _) => Color::Complex(
+            (Numeric(color), Foreground, _) => Self::with_ratios(
                 color,
                 ComplexColorRatios {
                     bg: this_weight as f32,
                     fg: other_weight as f32,
                 },
             ),
 
-            // Any other animation of currentColor with currentColor is complex.
-            (Color::Foreground, Color::Foreground, _) => Color::Complex(
+            // Any other animation of currentColor with currentColor.
+            (Foreground, Foreground, _) => Self::with_ratios(
                 RGBA::transparent(),
                 ComplexColorRatios {
                     bg: 0.,
                     fg: (this_weight + other_weight) as f32,
                 },
             ),
 
             // Defer to complex calculations
@@ -192,37 +175,32 @@ impl Animate for Color {
                 // Then we compute the final background ratio, and derive
                 // the final alpha value from the effective alpha value.
                 let self_ratios = self.effective_ratios();
                 let other_ratios = other.effective_ratios();
                 let ratios = self_ratios.animate(&other_ratios, procedure)?;
                 let alpha = color.alpha / ratios.bg;
                 let color = RGBA { alpha, ..color };
 
-                if ratios == ComplexColorRatios::NUMERIC {
-                    Color::Numeric(color)
-                } else if ratios == ComplexColorRatios::FOREGROUND {
-                    Color::Foreground
-                } else {
-                    Color::Complex(color, ratios)
-                }
+                Self::with_ratios(color, ratios)
             }
         })
     }
 }
 
 impl ComputeSquaredDistance for Color {
     #[inline]
     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+        use self::GenericColor::*;
+
         // All comments from the Animate impl also applies here.
         Ok(match (*self, *other) {
-            (Color::Foreground, Color::Foreground) => SquaredDistance::from_sqrt(0.),
-            (Color::Numeric(c1), Color::Numeric(c2)) => c1.compute_squared_distance(&c2)?,
-            (Color::Foreground, Color::Numeric(color))
-            | (Color::Numeric(color), Color::Foreground) => {
+            (Foreground, Foreground) => SquaredDistance::from_sqrt(0.),
+            (Numeric(c1), Numeric(c2)) => c1.compute_squared_distance(&c2)?,
+            (Foreground, Numeric(color)) | (Numeric(color), Foreground) => {
                 // `computed_squared_distance` is symmetic.
                 color.compute_squared_distance(&RGBA::transparent())?
                     + SquaredDistance::from_sqrt(1.)
             }
             (_, _) => {
                 let self_color = self.effective_intermediate_rgba();
                 let other_color = other.effective_intermediate_rgba();
                 let self_ratios = self.effective_ratios();
--- a/servo/components/style/values/computed/color.rs
+++ b/servo/components/style/values/computed/color.rs
@@ -3,91 +3,44 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Computed color values.
 
 use cssparser::{Color as CSSParserColor, RGBA};
 use std::fmt;
 use style_traits::{CssWriter, ToCss};
 use values::animated::ToAnimatedValue;
-use values::animated::color::{Color as AnimatedColor, RGBA as AnimatedRGBA};
-
-/// Ratios representing the contribution of color and currentcolor to
-/// the final color value.
-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
-pub struct ComplexColorRatios {
-    /// Numeric color contribution.
-    pub bg: f32,
-    /// Foreground color, aka currentcolor, contribution.
-    pub fg: f32,
-}
-
-impl ComplexColorRatios {
-    /// Ratios representing pure numeric color.
-    pub const NUMERIC: ComplexColorRatios = ComplexColorRatios { bg: 1., fg: 0. };
-    /// Ratios representing pure foreground color.
-    pub const FOREGROUND: ComplexColorRatios = ComplexColorRatios { bg: 0., fg: 1. };
-}
-
-/// This enum represents a combined color from a numeric color and
-/// the current foreground color (currentColor keyword).
-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
-pub enum Color {
-    ///  Numeric RGBA color.
-    Numeric(RGBA),
-
-    /// The current foreground color.
-    Foreground,
-
-    /// A linear combination of numeric color and currentColor.
-    /// The formula is: `color * bg_ratio + currentColor * fg_ratio`.
-    Complex(RGBA, ComplexColorRatios),
-}
+use values::animated::color::RGBA as AnimatedRGBA;
+use values::generics::color::Color as GenericColor;
 
 /// Computed value type for the specified RGBAColor.
 pub type RGBAColor = RGBA;
 
 /// The computed value of the `color` property.
 pub type ColorPropertyValue = RGBA;
 
+/// This enum represents a combined color from a numeric color and
+/// the current foreground color (currentcolor keyword).
+pub type Color = GenericColor<RGBAColor>;
+
 impl Color {
-    /// Returns a numeric color representing the given RGBA value.
-    pub fn rgba(color: RGBA) -> Color {
-        Color::Numeric(color)
-    }
-
     /// Returns a complex color value representing transparent.
     pub fn transparent() -> Color {
         Color::rgba(RGBA::transparent())
     }
 
-    /// Returns a complex color value representing currentcolor.
-    pub fn currentcolor() -> Color {
-        Color::Foreground
-    }
-
-    /// Whether it is a numeric color (no currentcolor component).
-    pub fn is_numeric(&self) -> bool {
-        matches!(*self, Color::Numeric { .. })
-    }
-
-    /// Whether it is a currentcolor value (no numeric color component).
-    pub fn is_currentcolor(&self) -> bool {
-        matches!(*self, Color::Foreground)
-    }
-
     /// Combine this complex color with the given foreground color into
     /// a numeric RGBA color. It currently uses linear blending.
     pub fn to_rgba(&self, fg_color: RGBA) -> RGBA {
         let (color, ratios) = match *self {
             // Common cases that the complex color is either pure numeric
             // color or pure currentcolor.
-            Color::Numeric(color) => return color,
-            Color::Foreground => return fg_color,
-            Color::Complex(color, ratios) => (color, ratios),
+            GenericColor::Numeric(color) => return color,
+            GenericColor::Foreground => return fg_color,
+            GenericColor::Complex(color, ratios) => (color, ratios),
         };
 
         // For the more complicated case that the alpha value differs,
         // we use the following formula to compute the components:
         // alpha = self_alpha * bg_ratio + fg_alpha * fg_ratio
         // color = (self_color * self_alpha * bg_ratio +
         //          fg_color * fg_alpha * fg_ratio) / alpha
 
@@ -112,61 +65,29 @@ impl Color {
         let inverse_a = 1. / a;
         let r = (p1 * r1 + p2 * r2) * inverse_a;
         let g = (p1 * g1 + p2 * g2) * inverse_a;
         let b = (p1 * b1 + p2 * b2) * inverse_a;
         return RGBA::from_floats(r, g, b, a);
     }
 }
 
-impl From<RGBA> for Color {
-    fn from(color: RGBA) -> Color {
-        Color::Numeric(color)
-    }
-}
-
 impl ToCss for Color {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: fmt::Write,
     {
         match *self {
-            Color::Numeric(color) => color.to_css(dest),
-            Color::Foreground => CSSParserColor::CurrentColor.to_css(dest),
+            GenericColor::Numeric(color) => color.to_css(dest),
+            GenericColor::Foreground => CSSParserColor::CurrentColor.to_css(dest),
             _ => Ok(()),
         }
     }
 }
 
-impl ToAnimatedValue for Color {
-    type AnimatedValue = AnimatedColor;
-
-    #[inline]
-    fn to_animated_value(self) -> Self::AnimatedValue {
-        match self {
-            Color::Numeric(color) => AnimatedColor::Numeric(color.to_animated_value()),
-            Color::Foreground => AnimatedColor::Foreground,
-            Color::Complex(color, ratios) => {
-                AnimatedColor::Complex(color.to_animated_value(), ratios)
-            }
-        }
-    }
-
-    #[inline]
-    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
-        match animated {
-            AnimatedColor::Numeric(color) => Color::Numeric(RGBA::from_animated_value(color)),
-            AnimatedColor::Foreground => Color::Foreground,
-            AnimatedColor::Complex(color, ratios) => {
-                Color::Complex(RGBA::from_animated_value(color), ratios)
-            }
-        }
-    }
-}
-
 impl ToAnimatedValue for RGBA {
     type AnimatedValue = AnimatedRGBA;
 
     #[inline]
     fn to_animated_value(self) -> Self::AnimatedValue {
         AnimatedRGBA::new(
             self.red_f32(),
             self.green_f32(),
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -41,17 +41,17 @@ pub use self::border::{BorderImageRepeat
 pub use self::border::{BorderCornerRadius, BorderRadius, BorderSpacing};
 pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis, FontVariantAlternates, FontWeight};
 pub use self::font::{FontFamily, FontLanguageOverride, FontStyle, FontVariantEastAsian, FontVariationSettings};
 pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric};
 pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
 pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display};
 pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective};
 pub use self::box_::{ScrollSnapType, TouchAction, VerticalAlign, WillChange};
-pub use self::color::{Color, ColorPropertyValue, ComplexColorRatios, RGBAColor};
+pub use self::color::{Color, ColorPropertyValue, RGBAColor};
 pub use self::column::ColumnCount;
 pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset};
 pub use self::effects::{BoxShadow, Filter, SimpleShadow};
 pub use self::flex::FlexBasis;
 pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect};
 pub use self::inherited_box::{ImageOrientation, Orientation};
 #[cfg(feature = "gecko")]
 pub use self::gecko::ScrollSnapPoint;
new file mode 100644
--- /dev/null
+++ b/servo/components/style/values/generics/color.rs
@@ -0,0 +1,76 @@
+/* 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 color properties.
+
+/// Ratios representing the contribution of color and currentcolor to
+/// the final color value.
+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue)]
+pub struct ComplexColorRatios {
+    /// Numeric color contribution.
+    pub bg: f32,
+    /// Foreground color, aka currentcolor, contribution.
+    pub fg: f32,
+}
+
+impl ComplexColorRatios {
+    /// Ratios representing a `Numeric` color.
+    pub const NUMERIC: ComplexColorRatios = ComplexColorRatios { bg: 1., fg: 0. };
+    /// Ratios representing the `Foreground` color.
+    pub const FOREGROUND: ComplexColorRatios = ComplexColorRatios { bg: 0., fg: 1. };
+}
+
+/// This enum represents a combined color from a numeric color and
+/// the current foreground color (currentcolor keyword).
+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue)]
+pub enum Color<RGBA> {
+    ///  Numeric RGBA color.
+    Numeric(RGBA),
+
+    /// The current foreground color.
+    Foreground,
+
+    /// A linear combination of numeric color and currentcolor.
+    /// The formula is: `color * ratios.bg + currentcolor * ratios.fg`.
+    Complex(RGBA, ComplexColorRatios),
+}
+
+impl<RGBA> Color<RGBA> {
+    /// Create a color based upon the specified ratios.
+    pub fn with_ratios(color: RGBA, ratios: ComplexColorRatios) -> Self {
+        if ratios == ComplexColorRatios::NUMERIC {
+            Color::Numeric(color)
+        } else if ratios == ComplexColorRatios::FOREGROUND {
+            Color::Foreground
+        } else {
+            Color::Complex(color, ratios)
+        }
+    }
+
+    /// Returns a numeric color representing the given RGBA value.
+    pub fn rgba(color: RGBA) -> Self {
+        Color::Numeric(color)
+    }
+
+    /// Returns a complex color value representing currentcolor.
+    pub fn currentcolor() -> Self {
+        Color::Foreground
+    }
+
+    /// Whether it is a numeric color (no currentcolor component).
+    pub fn is_numeric(&self) -> bool {
+        matches!(*self, Color::Numeric(..))
+    }
+
+    /// Whether it is a currentcolor value (no numeric color component).
+    pub fn is_currentcolor(&self) -> bool {
+        matches!(*self, Color::Foreground)
+    }
+}
+
+impl<RGBA> From<RGBA> for Color<RGBA> {
+    fn from(color: RGBA) -> Self {
+        Self::rgba(color)
+    }
+}
--- a/servo/components/style/values/generics/mod.rs
+++ b/servo/components/style/values/generics/mod.rs
@@ -12,16 +12,17 @@ use style_traits::{KeywordsCollectFn, Pa
 use style_traits::{SpecifiedValueInfo, StyleParseErrorKind};
 use super::CustomIdent;
 
 pub mod background;
 pub mod basic_shape;
 pub mod border;
 #[path = "box.rs"]
 pub mod box_;
+pub mod color;
 pub mod column;
 pub mod counters;
 pub mod effects;
 pub mod flex;
 pub mod font;
 #[cfg(feature = "gecko")]
 pub mod gecko;
 pub mod grid;
--- a/servo/components/style/values/specified/color.rs
+++ b/servo/components/style/values/specified/color.rs
@@ -13,16 +13,17 @@ use parser::{Parse, ParserContext};
 #[cfg(feature = "gecko")]
 use properties::longhands::system_colors::SystemColor;
 use std::fmt::{self, Write};
 use std::io::Write as IoWrite;
 use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError, StyleParseErrorKind};
 use style_traits::{SpecifiedValueInfo, ToCss, ValueParseErrorKind};
 use super::AllowQuirks;
 use values::computed::{Color as ComputedColor, Context, ToComputedValue};
+use values::generics::color::Color as GenericColor;
 use values::specified::calc::CalcNode;
 
 /// Specified color value
 #[derive(Clone, Debug, MallocSizeOf, PartialEq)]
 pub enum Color {
     /// The 'currentColor' keyword
     CurrentColor,
     /// A specific RGBA color
@@ -379,19 +380,19 @@ impl ToComputedValue for Color {
                 }
             }
         }
         result
     }
 
     fn from_computed_value(computed: &ComputedColor) -> Self {
         match *computed {
-            ComputedColor::Numeric(color) => Color::rgba(color),
-            ComputedColor::Foreground => Color::currentcolor(),
-            ComputedColor::Complex(..) => Color::Complex(*computed),
+            GenericColor::Numeric(color) => Color::rgba(color),
+            GenericColor::Foreground => Color::currentcolor(),
+            GenericColor::Complex(..) => Color::Complex(*computed),
         }
     }
 }
 
 /// Specified color value, but resolved to just RGBA for computed value
 /// with value from color property at the same context.
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
 pub struct RGBAColor(pub Color);