mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
style: Extend StyleComplexColor to support additive blending.
Refactored StyleComplexColor to support "complex" blending between background (numeric) color and foreground color (currentColor). Made explicit the distinction between numeric, currentColor and a complex blend in Gecko and Stylo. This is to support SMIL animation, for example, of the form: <animate from="rgb(10,20,30)" by="currentColor" ... /> Bug: 1465307 Reviewed-by: hiro,xidorn MozReview-Commit-ID: IUAK8P07gtm
This commit is contained in:
parent
3816143a1d
commit
255fe05d40
5 changed files with 248 additions and 204 deletions
|
@ -5,28 +5,21 @@
|
|||
//! Rust helpers to interact with Gecko's StyleComplexColor.
|
||||
|
||||
use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
|
||||
use gecko_bindings::structs::{nscolor, StyleComplexColor};
|
||||
use gecko_bindings::structs::StyleComplexColor;
|
||||
use gecko_bindings::structs::StyleComplexColor_Tag as Tag;
|
||||
use values::{Auto, Either};
|
||||
use values::computed::Color as ComputedColor;
|
||||
use values::computed::{Color as ComputedColor, RGBAColor as ComputedRGBA};
|
||||
use values::computed::ComplexColorRatios;
|
||||
use values::computed::ui::ColorOrAuto;
|
||||
|
||||
impl From<nscolor> for StyleComplexColor {
|
||||
fn from(other: nscolor) -> Self {
|
||||
StyleComplexColor {
|
||||
mColor: other,
|
||||
mForegroundRatio: 0,
|
||||
mIsAuto: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StyleComplexColor {
|
||||
/// Create a `StyleComplexColor` value that represents `currentColor`.
|
||||
pub fn current_color() -> Self {
|
||||
StyleComplexColor {
|
||||
mColor: 0,
|
||||
mForegroundRatio: 255,
|
||||
mIsAuto: false,
|
||||
mBgRatio: 0.,
|
||||
mFgRatio: 1.,
|
||||
mTag: Tag::eForeground,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,28 +27,66 @@ impl StyleComplexColor {
|
|||
pub fn auto() -> Self {
|
||||
StyleComplexColor {
|
||||
mColor: 0,
|
||||
mForegroundRatio: 255,
|
||||
mIsAuto: true,
|
||||
mBgRatio: 0.,
|
||||
mFgRatio: 1.,
|
||||
mTag: Tag::eAuto,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ComputedRGBA> for StyleComplexColor {
|
||||
fn from(other: ComputedRGBA) -> Self {
|
||||
StyleComplexColor {
|
||||
mColor: convert_rgba_to_nscolor(&other),
|
||||
mBgRatio: 1.,
|
||||
mFgRatio: 0.,
|
||||
mTag: Tag::eNumeric,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ComputedColor> for StyleComplexColor {
|
||||
fn from(other: ComputedColor) -> Self {
|
||||
StyleComplexColor {
|
||||
mColor: convert_rgba_to_nscolor(&other.color).into(),
|
||||
mForegroundRatio: other.foreground_ratio,
|
||||
mIsAuto: false,
|
||||
match other {
|
||||
ComputedColor::Numeric(color) => color.into(),
|
||||
ComputedColor::Foreground => Self::current_color(),
|
||||
ComputedColor::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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StyleComplexColor> for ComputedColor {
|
||||
fn from(other: StyleComplexColor) -> Self {
|
||||
debug_assert!(!other.mIsAuto);
|
||||
ComputedColor {
|
||||
color: convert_nscolor_to_rgba(other.mColor),
|
||||
foreground_ratio: other.mForegroundRatio,
|
||||
match other.mTag {
|
||||
Tag::eNumeric => {
|
||||
debug_assert!(other.mBgRatio == 1. && other.mFgRatio == 0.);
|
||||
ComputedColor::Numeric(convert_nscolor_to_rgba(other.mColor))
|
||||
}
|
||||
Tag::eForeground => {
|
||||
debug_assert!(other.mBgRatio == 0. && other.mFgRatio == 1.);
|
||||
ComputedColor::Foreground
|
||||
}
|
||||
Tag::eComplex => {
|
||||
debug_assert!(other.mBgRatio != 1. || other.mFgRatio != 0.);
|
||||
debug_assert!(other.mBgRatio != 0. || other.mFgRatio != 1.);
|
||||
ComputedColor::Complex(
|
||||
convert_nscolor_to_rgba(other.mColor),
|
||||
ComplexColorRatios {
|
||||
bg: other.mBgRatio,
|
||||
fg: other.mFgRatio,
|
||||
},
|
||||
)
|
||||
}
|
||||
Tag::eAuto => unreachable!("Unsupport StyleComplexColor with tag eAuto"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +102,7 @@ impl From<ColorOrAuto> for StyleComplexColor {
|
|||
|
||||
impl From<StyleComplexColor> for ColorOrAuto {
|
||||
fn from(other: StyleComplexColor) -> Self {
|
||||
if !other.mIsAuto {
|
||||
if other.mTag != Tag::eAuto {
|
||||
Either::First(other.into())
|
||||
} else {
|
||||
Either::Second(Auto)
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
use values::animated::{Animate, Procedure, ToAnimatedZero};
|
||||
use values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||
use values::computed::ComplexColorRatios;
|
||||
|
||||
/// An animated RGBA color.
|
||||
///
|
||||
|
@ -91,42 +92,51 @@ impl ComputeSquaredDistance for RGBA {
|
|||
}
|
||||
}
|
||||
|
||||
impl Animate for ComplexColorRatios {
|
||||
#[inline]
|
||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||
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 struct Color {
|
||||
pub color: RGBA,
|
||||
pub foreground_ratio: f32,
|
||||
pub enum Color {
|
||||
Numeric(RGBA),
|
||||
Foreground,
|
||||
Complex(RGBA, ComplexColorRatios),
|
||||
}
|
||||
|
||||
impl Color {
|
||||
fn currentcolor() -> Self {
|
||||
Color {
|
||||
color: RGBA::transparent(),
|
||||
foreground_ratio: 1.,
|
||||
}
|
||||
Color::Foreground
|
||||
}
|
||||
|
||||
/// Returns a transparent intermediate color.
|
||||
pub fn transparent() -> Self {
|
||||
Color {
|
||||
color: RGBA::transparent(),
|
||||
foreground_ratio: 0.,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_currentcolor(&self) -> bool {
|
||||
self.foreground_ratio >= 1.
|
||||
}
|
||||
|
||||
fn is_numeric(&self) -> bool {
|
||||
self.foreground_ratio <= 0.
|
||||
Color::Numeric(RGBA::transparent())
|
||||
}
|
||||
|
||||
fn effective_intermediate_rgba(&self) -> RGBA {
|
||||
RGBA {
|
||||
alpha: self.color.alpha * (1. - self.foreground_ratio),
|
||||
..self.color
|
||||
match *self {
|
||||
Color::Numeric(color) => color,
|
||||
Color::Foreground => RGBA::transparent(),
|
||||
Color::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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -136,50 +146,66 @@ impl Animate for Color {
|
|||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||
// Common cases are interpolating between two numeric colors,
|
||||
// two currentcolors, and a numeric color and a currentcolor.
|
||||
//
|
||||
// Note: this algorithm assumes self_portion + other_portion
|
||||
// equals to one, so it may be broken for additive operation.
|
||||
// To properly support additive color interpolation, we would
|
||||
// need two ratio fields in computed color types.
|
||||
let (this_weight, other_weight) = procedure.weights();
|
||||
if self.foreground_ratio == other.foreground_ratio {
|
||||
if self.is_currentcolor() {
|
||||
Ok(Color::currentcolor())
|
||||
} else {
|
||||
Ok(Color {
|
||||
color: self.color.animate(&other.color, procedure)?,
|
||||
foreground_ratio: self.foreground_ratio,
|
||||
})
|
||||
|
||||
Ok(match (*self, *other, procedure) {
|
||||
// Any interpolation of currentColor with currentColor returns currentColor.
|
||||
(Color::Foreground, Color::Foreground, Procedure::Interpolate { .. }) => {
|
||||
Color::currentcolor()
|
||||
}
|
||||
} else if self.is_currentcolor() && other.is_numeric() {
|
||||
Ok(Color {
|
||||
color: other.color,
|
||||
foreground_ratio: this_weight as f32,
|
||||
})
|
||||
} else if self.is_numeric() && other.is_currentcolor() {
|
||||
Ok(Color {
|
||||
color: self.color,
|
||||
foreground_ratio: other_weight as f32,
|
||||
})
|
||||
} else {
|
||||
// For interpolating between two complex colors, we need to
|
||||
// generate colors with effective alpha value.
|
||||
let self_color = self.effective_intermediate_rgba();
|
||||
let other_color = other.effective_intermediate_rgba();
|
||||
let color = self_color.animate(&other_color, procedure)?;
|
||||
// Then we compute the final foreground ratio, and derive
|
||||
// the final alpha value from the effective alpha value.
|
||||
let foreground_ratio = self.foreground_ratio
|
||||
.animate(&other.foreground_ratio, procedure)?;
|
||||
let alpha = color.alpha / (1. - foreground_ratio);
|
||||
Ok(Color {
|
||||
color: RGBA {
|
||||
alpha: alpha,
|
||||
..color
|
||||
// Animating two numeric colors.
|
||||
(Color::Numeric(c1), Color::Numeric(c2), _) => {
|
||||
Color::Numeric(c1.animate(&c2, procedure)?)
|
||||
}
|
||||
// Combinations of numeric color and currentColor
|
||||
(Color::Foreground, Color::Numeric(color), _) => Color::Complex(
|
||||
color,
|
||||
ComplexColorRatios {
|
||||
bg: other_weight as f32,
|
||||
fg: this_weight as f32,
|
||||
},
|
||||
foreground_ratio: foreground_ratio,
|
||||
})
|
||||
}
|
||||
),
|
||||
(Color::Numeric(color), Color::Foreground, _) => Color::Complex(
|
||||
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(
|
||||
RGBA::transparent(),
|
||||
ComplexColorRatios {
|
||||
bg: 0.,
|
||||
fg: (this_weight + other_weight) as f32,
|
||||
},
|
||||
),
|
||||
|
||||
// Defer to complex calculations
|
||||
_ => {
|
||||
// For interpolating between two complex colors, we need to
|
||||
// generate colors with effective alpha value.
|
||||
let self_color = self.effective_intermediate_rgba();
|
||||
let other_color = other.effective_intermediate_rgba();
|
||||
let color = self_color.animate(&other_color, procedure)?;
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,27 +213,26 @@ impl ComputeSquaredDistance for Color {
|
|||
#[inline]
|
||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||
// All comments from the Animate impl also applies here.
|
||||
if self.foreground_ratio == other.foreground_ratio {
|
||||
if self.is_currentcolor() {
|
||||
Ok(SquaredDistance::from_sqrt(0.))
|
||||
} else {
|
||||
self.color.compute_squared_distance(&other.color)
|
||||
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) => {
|
||||
// `computed_squared_distance` is symmetic.
|
||||
color.compute_squared_distance(&RGBA::transparent())?
|
||||
+ SquaredDistance::from_sqrt(1.)
|
||||
}
|
||||
} else if self.is_currentcolor() && other.is_numeric() {
|
||||
Ok(
|
||||
RGBA::transparent().compute_squared_distance(&other.color)? +
|
||||
SquaredDistance::from_sqrt(1.),
|
||||
)
|
||||
} else if self.is_numeric() && other.is_currentcolor() {
|
||||
Ok(self.color.compute_squared_distance(&RGBA::transparent())? +
|
||||
SquaredDistance::from_sqrt(1.))
|
||||
} else {
|
||||
let self_color = self.effective_intermediate_rgba();
|
||||
let other_color = other.effective_intermediate_rgba();
|
||||
Ok(self_color.compute_squared_distance(&other_color)? +
|
||||
self.foreground_ratio
|
||||
.compute_squared_distance(&other.foreground_ratio)?)
|
||||
}
|
||||
(_, _) => {
|
||||
let self_color = self.effective_intermediate_rgba();
|
||||
let other_color = other.effective_intermediate_rgba();
|
||||
let self_ratios = self.effective_ratios();
|
||||
let other_ratios = other.effective_ratios();
|
||||
|
||||
self_color.compute_squared_distance(&other_color)?
|
||||
+ self_ratios.bg.compute_squared_distance(&other_ratios.bg)?
|
||||
+ self_ratios.fg.compute_squared_distance(&other_ratios.fg)?
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,17 +10,36 @@ use style_traits::{CssWriter, ToCss};
|
|||
use values::animated::ToAnimatedValue;
|
||||
use values::animated::color::{Color as AnimatedColor, RGBA as AnimatedRGBA};
|
||||
|
||||
/// This struct represents a combined color from a numeric color and
|
||||
/// the current foreground color (currentcolor keyword).
|
||||
/// Conceptually, the formula is "color * (1 - p) + currentcolor * p"
|
||||
/// where p is foreground_ratio.
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf)]
|
||||
pub struct Color {
|
||||
/// RGBA color.
|
||||
pub color: RGBA,
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// The ratio of currentcolor in complex color.
|
||||
pub foreground_ratio: u8,
|
||||
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.
|
||||
|
@ -31,11 +50,8 @@ pub type ColorPropertyValue = RGBA;
|
|||
|
||||
impl Color {
|
||||
/// Returns a numeric color representing the given RGBA value.
|
||||
pub fn rgba(rgba: RGBA) -> Color {
|
||||
Color {
|
||||
color: rgba,
|
||||
foreground_ratio: 0,
|
||||
}
|
||||
pub fn rgba(color: RGBA) -> Color {
|
||||
Color::Numeric(color)
|
||||
}
|
||||
|
||||
/// Returns a complex color value representing transparent.
|
||||
|
@ -45,73 +61,53 @@ impl Color {
|
|||
|
||||
/// Returns a complex color value representing currentcolor.
|
||||
pub fn currentcolor() -> Color {
|
||||
Color {
|
||||
color: RGBA::transparent(),
|
||||
foreground_ratio: u8::max_value(),
|
||||
}
|
||||
Color::Foreground
|
||||
}
|
||||
|
||||
/// Whether it is a numeric color (no currentcolor component).
|
||||
pub fn is_numeric(&self) -> bool {
|
||||
self.foreground_ratio == 0
|
||||
matches!(*self, Color::Numeric { .. })
|
||||
}
|
||||
|
||||
/// Whether it is a currentcolor value (no numeric color component).
|
||||
pub fn is_currentcolor(&self) -> bool {
|
||||
self.foreground_ratio == u8::max_value()
|
||||
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 {
|
||||
// Common cases that the complex color is either pure numeric
|
||||
// color or pure currentcolor.
|
||||
if self.is_numeric() {
|
||||
return self.color;
|
||||
}
|
||||
if self.is_currentcolor() {
|
||||
return fg_color.clone();
|
||||
}
|
||||
|
||||
fn blend_color_component(bg: u8, fg: u8, fg_alpha: u8) -> u8 {
|
||||
let bg_ratio = (u8::max_value() - fg_alpha) as u32;
|
||||
let fg_ratio = fg_alpha as u32;
|
||||
let color = bg as u32 * bg_ratio + fg as u32 * fg_ratio;
|
||||
// Rounding divide the number by 255
|
||||
((color + 127) / 255) as u8
|
||||
}
|
||||
|
||||
// Common case that alpha channel is equal (usually both are opaque).
|
||||
let fg_ratio = self.foreground_ratio;
|
||||
if self.color.alpha == fg_color.alpha {
|
||||
let r = blend_color_component(self.color.red, fg_color.red, fg_ratio);
|
||||
let g = blend_color_component(self.color.green, fg_color.green, fg_ratio);
|
||||
let b = blend_color_component(self.color.blue, fg_color.blue, fg_ratio);
|
||||
return RGBA::new(r, g, b, fg_color.alpha);
|
||||
}
|
||||
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),
|
||||
};
|
||||
|
||||
// For the more complicated case that the alpha value differs,
|
||||
// we use the following formula to compute the components:
|
||||
// alpha = self_alpha * (1 - fg_ratio) + fg_alpha * fg_ratio
|
||||
// color = (self_color * self_alpha * (1 - fg_ratio) +
|
||||
// alpha = self_alpha * bg_ratio + fg_alpha * fg_ratio
|
||||
// color = (self_color * self_alpha * bg_ratio +
|
||||
// fg_color * fg_alpha * fg_ratio) / alpha
|
||||
|
||||
let p1 = (1. / 255.) * (255 - fg_ratio) as f32;
|
||||
let a1 = self.color.alpha_f32();
|
||||
let r1 = a1 * self.color.red_f32();
|
||||
let g1 = a1 * self.color.green_f32();
|
||||
let b1 = a1 * self.color.blue_f32();
|
||||
let p1 = ratios.bg;
|
||||
let a1 = color.alpha_f32();
|
||||
let r1 = a1 * color.red_f32();
|
||||
let g1 = a1 * color.green_f32();
|
||||
let b1 = a1 * color.blue_f32();
|
||||
|
||||
let p2 = 1. - p1;
|
||||
let p2 = ratios.fg;
|
||||
let a2 = fg_color.alpha_f32();
|
||||
let r2 = a2 * fg_color.red_f32();
|
||||
let g2 = a2 * fg_color.green_f32();
|
||||
let b2 = a2 * fg_color.blue_f32();
|
||||
|
||||
let a = p1 * a1 + p2 * a2;
|
||||
if a == 0.0 {
|
||||
if a <= 0. {
|
||||
return RGBA::transparent();
|
||||
}
|
||||
let a = f32::min(a, 1.);
|
||||
|
||||
let inverse_a = 1. / a;
|
||||
let r = (p1 * r1 + p2 * r2) * inverse_a;
|
||||
|
@ -121,19 +117,9 @@ impl Color {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Color {
|
||||
fn eq(&self, other: &Color) -> bool {
|
||||
self.foreground_ratio == other.foreground_ratio &&
|
||||
(self.is_currentcolor() || self.color == other.color)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RGBA> for Color {
|
||||
fn from(color: RGBA) -> Color {
|
||||
Color {
|
||||
color: color,
|
||||
foreground_ratio: 0,
|
||||
}
|
||||
Color::Numeric(color)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,12 +128,10 @@ impl ToCss for Color {
|
|||
where
|
||||
W: fmt::Write,
|
||||
{
|
||||
if self.is_numeric() {
|
||||
self.color.to_css(dest)
|
||||
} else if self.is_currentcolor() {
|
||||
CSSParserColor::CurrentColor.to_css(dest)
|
||||
} else {
|
||||
Ok(())
|
||||
match *self {
|
||||
Color::Numeric(color) => color.to_css(dest),
|
||||
Color::Foreground => CSSParserColor::CurrentColor.to_css(dest),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,17 +141,23 @@ impl ToAnimatedValue for Color {
|
|||
|
||||
#[inline]
|
||||
fn to_animated_value(self) -> Self::AnimatedValue {
|
||||
AnimatedColor {
|
||||
color: self.color.to_animated_value(),
|
||||
foreground_ratio: self.foreground_ratio as f32 * (1. / 255.),
|
||||
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 {
|
||||
Color {
|
||||
color: RGBA::from_animated_value(animated.color),
|
||||
foreground_ratio: (animated.foreground_ratio * 255.).round() as u8,
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier,
|
|||
pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display, TransitionProperty};
|
||||
pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective};
|
||||
pub use self::box_::{ScrollSnapType, TouchAction, VerticalAlign, WillChange};
|
||||
pub use self::color::{Color, ColorPropertyValue, RGBAColor};
|
||||
pub use self::color::{Color, ColorPropertyValue, ComplexColorRatios, RGBAColor};
|
||||
pub use self::column::ColumnCount;
|
||||
pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset};
|
||||
pub use self::effects::{BoxShadow, Filter, SimpleShadow};
|
||||
|
|
|
@ -88,11 +88,11 @@ impl<'a, 'b: 'a, 'i: 'a> ::cssparser::ColorComponentParser<'i> for ColorComponen
|
|||
};
|
||||
|
||||
Ok(AngleOrNumber::Angle { degrees })
|
||||
},
|
||||
}
|
||||
Token::Number { value, .. } => Ok(AngleOrNumber::Number { value }),
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
input.parse_nested_block(|i| CalcNode::parse_angle_or_number(self.0, i))
|
||||
},
|
||||
}
|
||||
t => return Err(location.new_unexpected_token_error(t)),
|
||||
}
|
||||
}
|
||||
|
@ -119,10 +119,10 @@ impl<'a, 'b: 'a, 'i: 'a> ::cssparser::ColorComponentParser<'i> for ColorComponen
|
|||
Token::Number { value, .. } => Ok(NumberOrPercentage::Number { value }),
|
||||
Token::Percentage { unit_value, .. } => {
|
||||
Ok(NumberOrPercentage::Percentage { unit_value })
|
||||
},
|
||||
}
|
||||
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||
input.parse_nested_block(|i| CalcNode::parse_number_or_percentage(self.0, i))
|
||||
},
|
||||
}
|
||||
t => return Err(location.new_unexpected_token_error(t)),
|
||||
}
|
||||
}
|
||||
|
@ -168,10 +168,10 @@ impl Parse for Color {
|
|||
Err(e.location.new_custom_error(StyleParseErrorKind::ValueError(
|
||||
ValueParseErrorKind::InvalidColor(t),
|
||||
)))
|
||||
},
|
||||
}
|
||||
_ => Err(e),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -275,10 +275,10 @@ impl Color {
|
|||
}
|
||||
return parse_hash_color(ident.as_bytes())
|
||||
.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
},
|
||||
}
|
||||
ref t => {
|
||||
return Err(location.new_unexpected_token_error(t.clone()));
|
||||
},
|
||||
}
|
||||
};
|
||||
if value < 0 {
|
||||
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
|
@ -358,11 +358,11 @@ impl Color {
|
|||
Keyword::MozVisitedhyperlinktext => pres_context.mVisitedLinkColor,
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
#[cfg(feature = "gecko")]
|
||||
Color::InheritFromBodyQuirk => {
|
||||
_context.map(|context| ComputedColor::rgba(context.device().body_text_color()))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -372,7 +372,7 @@ impl ToComputedValue for Color {
|
|||
|
||||
fn to_computed_value(&self, context: &Context) -> ComputedColor {
|
||||
let result = self.to_computed_color(Some(context)).unwrap();
|
||||
if result.foreground_ratio != 0 {
|
||||
if !result.is_numeric() {
|
||||
if let Some(longhand) = context.for_non_inherited_property {
|
||||
if longhand.stores_complex_colors_lossily() {
|
||||
context.rule_cache_conditions.borrow_mut().set_uncacheable();
|
||||
|
@ -383,12 +383,10 @@ impl ToComputedValue for Color {
|
|||
}
|
||||
|
||||
fn from_computed_value(computed: &ComputedColor) -> Self {
|
||||
if computed.is_numeric() {
|
||||
Color::rgba(computed.color)
|
||||
} else if computed.is_currentcolor() {
|
||||
Color::currentcolor()
|
||||
} else {
|
||||
Color::Complex(*computed)
|
||||
match *computed {
|
||||
ComputedColor::Numeric(color) => Color::rgba(color),
|
||||
ComputedColor::Foreground => Color::currentcolor(),
|
||||
ComputedColor::Complex(..) => Color::Complex(*computed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue