style: Extract {animated,computed}::Color common parts.

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.

Bug: 1465307
Reviewed-by: xidorn
MozReview-Commit-ID: EymSr7aqnAP
This commit is contained in:
Dan Glastonbury 2018-06-05 11:49:51 +10:00 committed by Emilio Cobos Álvarez
parent 314b14d46e
commit 5f74a15f38
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
7 changed files with 122 additions and 146 deletions

View file

@ -9,8 +9,8 @@ use gecko_bindings::structs::StyleComplexColor;
use gecko_bindings::structs::StyleComplexColor_Tag as Tag; use gecko_bindings::structs::StyleComplexColor_Tag as Tag;
use values::{Auto, Either}; use values::{Auto, Either};
use values::computed::{Color as ComputedColor, RGBAColor as ComputedRGBA}; use values::computed::{Color as ComputedColor, RGBAColor as ComputedRGBA};
use values::computed::ComplexColorRatios;
use values::computed::ui::ColorOrAuto; use values::computed::ui::ColorOrAuto;
use values::generics::color::{Color as GenericColor, ComplexColorRatios};
impl StyleComplexColor { impl StyleComplexColor {
/// Create a `StyleComplexColor` value that represents `currentColor`. /// Create a `StyleComplexColor` value that represents `currentColor`.
@ -48,9 +48,9 @@ impl From<ComputedRGBA> for StyleComplexColor {
impl From<ComputedColor> for StyleComplexColor { impl From<ComputedColor> for StyleComplexColor {
fn from(other: ComputedColor) -> Self { fn from(other: ComputedColor) -> Self {
match other { match other {
ComputedColor::Numeric(color) => color.into(), GenericColor::Numeric(color) => color.into(),
ComputedColor::Foreground => Self::current_color(), GenericColor::Foreground => Self::current_color(),
ComputedColor::Complex(color, ratios) => { GenericColor::Complex(color, ratios) => {
debug_assert!(ratios != ComplexColorRatios::NUMERIC); debug_assert!(ratios != ComplexColorRatios::NUMERIC);
debug_assert!(ratios != ComplexColorRatios::FOREGROUND); debug_assert!(ratios != ComplexColorRatios::FOREGROUND);
StyleComplexColor { StyleComplexColor {
@ -69,16 +69,16 @@ impl From<StyleComplexColor> for ComputedColor {
match other.mTag { match other.mTag {
Tag::eNumeric => { Tag::eNumeric => {
debug_assert!(other.mBgRatio == 1. && other.mFgRatio == 0.); 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 => { Tag::eForeground => {
debug_assert!(other.mBgRatio == 0. && other.mFgRatio == 1.); debug_assert!(other.mBgRatio == 0. && other.mFgRatio == 1.);
ComputedColor::Foreground GenericColor::Foreground
} }
Tag::eComplex => { Tag::eComplex => {
debug_assert!(other.mBgRatio != 1. || other.mFgRatio != 0.); debug_assert!(other.mBgRatio != 1. || other.mFgRatio != 0.);
debug_assert!(other.mBgRatio != 0. || other.mFgRatio != 1.); debug_assert!(other.mBgRatio != 0. || other.mFgRatio != 1.);
ComputedColor::Complex( GenericColor::Complex(
convert_nscolor_to_rgba(other.mColor), convert_nscolor_to_rgba(other.mColor),
ComplexColorRatios { ComplexColorRatios {
bg: other.mBgRatio, bg: other.mBgRatio,

View file

@ -6,7 +6,7 @@
use values::animated::{Animate, Procedure, ToAnimatedZero}; use values::animated::{Animate, Procedure, ToAnimatedZero};
use values::distance::{ComputeSquaredDistance, SquaredDistance}; use values::distance::{ComputeSquaredDistance, SquaredDistance};
use values::computed::ComplexColorRatios; use values::generics::color::{Color as GenericColor, ComplexColorRatios};
/// An animated RGBA color. /// An animated RGBA color.
/// ///
@ -102,30 +102,15 @@ impl Animate for ComplexColorRatios {
} }
} }
#[allow(missing_docs)] /// An animated value for `<color>`.
#[cfg_attr(feature = "servo", derive(MallocSizeOf))] pub type Color = GenericColor<RGBA>;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Color {
Numeric(RGBA),
Foreground,
Complex(RGBA, ComplexColorRatios),
}
impl Color { 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 { fn effective_intermediate_rgba(&self) -> RGBA {
match *self { match *self {
Color::Numeric(color) => color, GenericColor::Numeric(color) => color,
Color::Foreground => RGBA::transparent(), GenericColor::Foreground => RGBA::transparent(),
Color::Complex(color, ratios) => RGBA { GenericColor::Complex(color, ratios) => RGBA {
alpha: color.alpha * ratios.bg, alpha: color.alpha * ratios.bg,
..color.clone() ..color.clone()
}, },
@ -134,9 +119,9 @@ impl Color {
fn effective_ratios(&self) -> ComplexColorRatios { fn effective_ratios(&self) -> ComplexColorRatios {
match *self { match *self {
Color::Numeric(..) => ComplexColorRatios::NUMERIC, GenericColor::Numeric(..) => ComplexColorRatios::NUMERIC,
Color::Foreground => ComplexColorRatios::FOREGROUND, GenericColor::Foreground => ComplexColorRatios::FOREGROUND,
Color::Complex(.., ratios) => ratios, GenericColor::Complex(.., ratios) => ratios,
} }
} }
} }
@ -144,28 +129,26 @@ impl Color {
impl Animate for Color { impl Animate for Color {
#[inline] #[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> { fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
use self::GenericColor::*;
// Common cases are interpolating between two numeric colors, // Common cases are interpolating between two numeric colors,
// two currentcolors, and a numeric color and a currentcolor. // two currentcolors, and a numeric color and a currentcolor.
let (this_weight, other_weight) = procedure.weights(); let (this_weight, other_weight) = procedure.weights();
Ok(match (*self, *other, procedure) { Ok(match (*self, *other, procedure) {
// Any interpolation of currentColor with currentColor returns currentColor. // Any interpolation of currentColor with currentColor returns currentColor.
(Color::Foreground, Color::Foreground, Procedure::Interpolate { .. }) => { (Foreground, Foreground, Procedure::Interpolate { .. }) => Color::currentcolor(),
Color::currentcolor()
}
// Animating two numeric colors. // Animating two numeric colors.
(Color::Numeric(c1), Color::Numeric(c2), _) => { (Numeric(c1), Numeric(c2), _) => Numeric(c1.animate(&c2, procedure)?),
Color::Numeric(c1.animate(&c2, procedure)?)
}
// Combinations of numeric color and currentColor // Combinations of numeric color and currentColor
(Color::Foreground, Color::Numeric(color), _) => Color::Complex( (Foreground, Numeric(color), _) => Self::with_ratios(
color, color,
ComplexColorRatios { ComplexColorRatios {
bg: other_weight as f32, bg: other_weight as f32,
fg: this_weight as f32, fg: this_weight as f32,
}, },
), ),
(Color::Numeric(color), Color::Foreground, _) => Color::Complex( (Numeric(color), Foreground, _) => Self::with_ratios(
color, color,
ComplexColorRatios { ComplexColorRatios {
bg: this_weight as f32, bg: this_weight as f32,
@ -173,8 +156,8 @@ impl Animate for Color {
}, },
), ),
// Any other animation of currentColor with currentColor is complex. // Any other animation of currentColor with currentColor.
(Color::Foreground, Color::Foreground, _) => Color::Complex( (Foreground, Foreground, _) => Self::with_ratios(
RGBA::transparent(), RGBA::transparent(),
ComplexColorRatios { ComplexColorRatios {
bg: 0., bg: 0.,
@ -197,13 +180,7 @@ impl Animate for Color {
let alpha = color.alpha / ratios.bg; let alpha = color.alpha / ratios.bg;
let color = RGBA { alpha, ..color }; let color = RGBA { alpha, ..color };
if ratios == ComplexColorRatios::NUMERIC { Self::with_ratios(color, ratios)
Color::Numeric(color)
} else if ratios == ComplexColorRatios::FOREGROUND {
Color::Foreground
} else {
Color::Complex(color, ratios)
}
} }
}) })
} }
@ -212,12 +189,13 @@ impl Animate for Color {
impl ComputeSquaredDistance for Color { impl ComputeSquaredDistance for Color {
#[inline] #[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
use self::GenericColor::*;
// All comments from the Animate impl also applies here. // All comments from the Animate impl also applies here.
Ok(match (*self, *other) { Ok(match (*self, *other) {
(Color::Foreground, Color::Foreground) => SquaredDistance::from_sqrt(0.), (Foreground, Foreground) => SquaredDistance::from_sqrt(0.),
(Color::Numeric(c1), Color::Numeric(c2)) => c1.compute_squared_distance(&c2)?, (Numeric(c1), Numeric(c2)) => c1.compute_squared_distance(&c2)?,
(Color::Foreground, Color::Numeric(color)) (Foreground, Numeric(color)) | (Numeric(color), Foreground) => {
| (Color::Numeric(color), Color::Foreground) => {
// `computed_squared_distance` is symmetic. // `computed_squared_distance` is symmetic.
color.compute_squared_distance(&RGBA::transparent())? color.compute_squared_distance(&RGBA::transparent())?
+ SquaredDistance::from_sqrt(1.) + SquaredDistance::from_sqrt(1.)

View file

@ -8,39 +8,8 @@ use cssparser::{Color as CSSParserColor, RGBA};
use std::fmt; use std::fmt;
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
use values::animated::ToAnimatedValue; use values::animated::ToAnimatedValue;
use values::animated::color::{Color as AnimatedColor, RGBA as AnimatedRGBA}; use values::animated::color::RGBA as AnimatedRGBA;
use values::generics::color::Color as GenericColor;
/// 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),
}
/// Computed value type for the specified RGBAColor. /// Computed value type for the specified RGBAColor.
pub type RGBAColor = RGBA; pub type RGBAColor = RGBA;
@ -48,41 +17,24 @@ pub type RGBAColor = RGBA;
/// The computed value of the `color` property. /// The computed value of the `color` property.
pub type ColorPropertyValue = RGBA; pub type ColorPropertyValue = RGBA;
impl Color { /// A computed value for `<color>`.
/// Returns a numeric color representing the given RGBA value. pub type Color = GenericColor<RGBAColor>;
pub fn rgba(color: RGBA) -> Color {
Color::Numeric(color)
}
impl Color {
/// Returns a complex color value representing transparent. /// Returns a complex color value representing transparent.
pub fn transparent() -> Color { pub fn transparent() -> Color {
Color::rgba(RGBA::transparent()) 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 /// Combine this complex color with the given foreground color into
/// a numeric RGBA color. It currently uses linear blending. /// a numeric RGBA color. It currently uses linear blending.
pub fn to_rgba(&self, fg_color: RGBA) -> RGBA { pub fn to_rgba(&self, fg_color: RGBA) -> RGBA {
let (color, ratios) = match *self { let (color, ratios) = match *self {
// Common cases that the complex color is either pure numeric // Common cases that the complex color is either pure numeric
// color or pure currentcolor. // color or pure currentcolor.
Color::Numeric(color) => return color, GenericColor::Numeric(color) => return color,
Color::Foreground => return fg_color, GenericColor::Foreground => return fg_color,
Color::Complex(color, ratios) => (color, ratios), GenericColor::Complex(color, ratios) => (color, ratios),
}; };
// For the more complicated case that the alpha value differs, // For the more complicated case that the alpha value differs,
@ -117,51 +69,19 @@ impl Color {
} }
} }
impl From<RGBA> for Color {
fn from(color: RGBA) -> Color {
Color::Numeric(color)
}
}
impl ToCss for Color { impl ToCss for Color {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where where
W: fmt::Write, W: fmt::Write,
{ {
match *self { match *self {
Color::Numeric(color) => color.to_css(dest), GenericColor::Numeric(color) => color.to_css(dest),
Color::Foreground => CSSParserColor::CurrentColor.to_css(dest), GenericColor::Foreground => CSSParserColor::CurrentColor.to_css(dest),
_ => Ok(()), _ => 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 { impl ToAnimatedValue for RGBA {
type AnimatedValue = AnimatedRGBA; type AnimatedValue = AnimatedRGBA;

View file

@ -45,7 +45,7 @@ pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier,
pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display, TransitionProperty}; pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display, TransitionProperty};
pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective}; pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective};
pub use self::box_::{ScrollSnapType, TouchAction, VerticalAlign, WillChange}; 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::column::ColumnCount;
pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset}; pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset};
pub use self::effects::{BoxShadow, Filter, SimpleShadow}; pub use self::effects::{BoxShadow, Filter, SimpleShadow};

View file

@ -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)
}
}

View file

@ -17,6 +17,7 @@ pub mod basic_shape;
pub mod border; pub mod border;
#[path = "box.rs"] #[path = "box.rs"]
pub mod box_; pub mod box_;
pub mod color;
pub mod column; pub mod column;
pub mod counters; pub mod counters;
pub mod effects; pub mod effects;

View file

@ -18,6 +18,7 @@ use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError, StyleParse
use style_traits::{SpecifiedValueInfo, ToCss, ValueParseErrorKind}; use style_traits::{SpecifiedValueInfo, ToCss, ValueParseErrorKind};
use super::AllowQuirks; use super::AllowQuirks;
use values::computed::{Color as ComputedColor, Context, ToComputedValue}; use values::computed::{Color as ComputedColor, Context, ToComputedValue};
use values::generics::color::Color as GenericColor;
use values::specified::calc::CalcNode; use values::specified::calc::CalcNode;
/// Specified color value /// Specified color value
@ -384,9 +385,9 @@ impl ToComputedValue for Color {
fn from_computed_value(computed: &ComputedColor) -> Self { fn from_computed_value(computed: &ComputedColor) -> Self {
match *computed { match *computed {
ComputedColor::Numeric(color) => Color::rgba(color), GenericColor::Numeric(color) => Color::rgba(color),
ComputedColor::Foreground => Color::currentcolor(), GenericColor::Foreground => Color::currentcolor(),
ComputedColor::Complex(..) => Color::Complex(*computed), GenericColor::Complex(..) => Color::Complex(*computed),
} }
} }
} }