зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1695369 - Simplify StyleColor representation. r=jwatt
There's no need for CurrentColor / Numeric variants when we can represent them with the complex form. Differential Revision: https://phabricator.services.mozilla.com/D106690
This commit is contained in:
Родитель
417b5880d4
Коммит
f482ffa15d
|
@ -50,9 +50,7 @@ template <>
|
||||||
bool StyleColor::MaybeTransparent() const {
|
bool StyleColor::MaybeTransparent() const {
|
||||||
// We know that the color is opaque when it's a numeric color with
|
// We know that the color is opaque when it's a numeric color with
|
||||||
// alpha == 255.
|
// alpha == 255.
|
||||||
// TODO(djg): Should we extend this to check Complex with bgRatio =
|
return ratios != StyleComplexColorRatios::NUMERIC || color.alpha != 255;
|
||||||
// 0, and fgRatio * alpha >= 255?
|
|
||||||
return !IsNumeric() || AsNumeric().alpha != 255;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -62,32 +60,31 @@ nscolor StyleColor::CalcColor(nscolor aColor) const {
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
nscolor StyleColor::CalcColor(const StyleRGBA& aForegroundColor) const {
|
nscolor StyleColor::CalcColor(const StyleRGBA& aForegroundColor) const {
|
||||||
if (IsNumeric()) {
|
if (ratios == StyleComplexColorRatios::NUMERIC) {
|
||||||
return AsNumeric().ToColor();
|
return color.ToColor();
|
||||||
}
|
}
|
||||||
if (IsCurrentColor()) {
|
if (ratios == StyleComplexColorRatios::CURRENT_COLOR) {
|
||||||
return aForegroundColor.ToColor();
|
return aForegroundColor.ToColor();
|
||||||
}
|
}
|
||||||
MOZ_ASSERT(IsComplex());
|
return LinearBlendColors(color, ratios.bg, aForegroundColor, ratios.fg);
|
||||||
const auto& complex = AsComplex();
|
|
||||||
return LinearBlendColors(complex.color, complex.ratios.bg, aForegroundColor,
|
|
||||||
complex.ratios.fg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
nscolor StyleColor::CalcColor(const ComputedStyle& aStyle) const {
|
nscolor StyleColor::CalcColor(const ComputedStyle& aStyle) const {
|
||||||
// Common case that is numeric color, which is pure background, we
|
// Common case that is numeric color, which is pure background, we
|
||||||
// can skip resolving StyleText().
|
// can skip resolving StyleText().
|
||||||
// TODO(djg): Is this optimization worth it?
|
if (ratios == StyleComplexColorRatios::NUMERIC) {
|
||||||
if (IsNumeric()) {
|
return color.ToColor();
|
||||||
return AsNumeric().ToColor();
|
|
||||||
}
|
}
|
||||||
return CalcColor(aStyle.StyleText()->mColor);
|
return CalcColor(aStyle.StyleText()->mColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
nscolor StyleColor::CalcColor(const nsIFrame* aFrame) const {
|
nscolor StyleColor::CalcColor(const nsIFrame* aFrame) const {
|
||||||
return CalcColor(*aFrame->Style());
|
if (ratios == StyleComplexColorRatios::NUMERIC) {
|
||||||
|
return color.ToColor();
|
||||||
|
}
|
||||||
|
return CalcColor(aFrame->StyleText()->mColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -27,7 +27,18 @@ inline StyleRGBA StyleRGBA::Transparent() { return {0, 0, 0, 0}; }
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline StyleColor StyleColor::FromColor(nscolor aColor) {
|
inline StyleColor StyleColor::FromColor(nscolor aColor) {
|
||||||
return StyleColor::Numeric(StyleRGBA::FromColor(aColor));
|
return StyleColor{
|
||||||
|
StyleRGBA::FromColor(aColor),
|
||||||
|
StyleComplexColorRatios::NUMERIC,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline StyleColor StyleColor::CurrentColor() {
|
||||||
|
return StyleColor{
|
||||||
|
StyleRGBA::Transparent(),
|
||||||
|
StyleComplexColorRatios::CURRENT_COLOR,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
|
|
@ -35,17 +35,14 @@ impl RGBA {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
|
pub fn new(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
|
||||||
RGBA {
|
RGBA {
|
||||||
red: red,
|
red,
|
||||||
green: green,
|
green,
|
||||||
blue: blue,
|
blue,
|
||||||
alpha: alpha,
|
alpha,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unlike Animate for computed colors, we don't clamp any component values.
|
|
||||||
///
|
|
||||||
/// FIXME(nox): Why do computed colors even implement Animate?
|
|
||||||
impl Animate for RGBA {
|
impl Animate for RGBA {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||||
|
@ -57,15 +54,11 @@ impl Animate for RGBA {
|
||||||
}
|
}
|
||||||
|
|
||||||
alpha = alpha.min(1.);
|
alpha = alpha.min(1.);
|
||||||
let red =
|
let red = (self.red * self.alpha).animate(&(other.red * other.alpha), procedure)?;
|
||||||
(self.red * self.alpha).animate(&(other.red * other.alpha), procedure)? * 1. / alpha;
|
let green = (self.green * self.alpha).animate(&(other.green * other.alpha), procedure)?;
|
||||||
let green = (self.green * self.alpha).animate(&(other.green * other.alpha), procedure)? *
|
let blue = (self.blue * self.alpha).animate(&(other.blue * other.alpha), procedure)?;
|
||||||
1. /
|
let inv = 1. / alpha;
|
||||||
alpha;
|
Ok(RGBA::new(red * inv, green * inv, blue * inv, alpha))
|
||||||
let blue =
|
|
||||||
(self.blue * self.alpha).animate(&(other.blue * other.alpha), procedure)? * 1. / alpha;
|
|
||||||
|
|
||||||
Ok(RGBA::new(red, green, blue, alpha))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,21 +90,34 @@ pub type Color = GenericColor<RGBA>;
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
fn effective_intermediate_rgba(&self) -> RGBA {
|
fn effective_intermediate_rgba(&self) -> RGBA {
|
||||||
match *self {
|
if self.ratios.bg == 0. {
|
||||||
GenericColor::Numeric(color) => color,
|
return RGBA::transparent();
|
||||||
GenericColor::CurrentColor => RGBA::transparent(),
|
}
|
||||||
GenericColor::Complex { color, ratios } => RGBA {
|
|
||||||
alpha: color.alpha * ratios.bg,
|
if self.ratios.bg == 1. {
|
||||||
..color.clone()
|
return self.color;
|
||||||
},
|
}
|
||||||
|
|
||||||
|
RGBA {
|
||||||
|
alpha: self.color.alpha * self.ratios.bg,
|
||||||
|
..self.color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn effective_ratios(&self) -> ComplexColorRatios {
|
fn scaled_rgba(&self) -> RGBA {
|
||||||
match *self {
|
if self.ratios.bg == 0. {
|
||||||
GenericColor::Numeric(..) => ComplexColorRatios::NUMERIC,
|
return RGBA::transparent();
|
||||||
GenericColor::CurrentColor => ComplexColorRatios::CURRENT_COLOR,
|
}
|
||||||
GenericColor::Complex { ratios, .. } => ratios,
|
|
||||||
|
if self.ratios.bg == 1. {
|
||||||
|
return self.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
RGBA {
|
||||||
|
red: self.color.red * self.ratios.bg,
|
||||||
|
green: self.color.green * self.ratios.bg,
|
||||||
|
blue: self.color.blue * self.ratios.bg,
|
||||||
|
alpha: self.color.alpha * self.ratios.bg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,140 +125,140 @@ 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::*;
|
let self_numeric = self.is_numeric();
|
||||||
|
let other_numeric = other.is_numeric();
|
||||||
|
|
||||||
// Common cases are interpolating between two numeric colors,
|
if self_numeric && other_numeric {
|
||||||
// two currentcolors, and a numeric color and a currentcolor.
|
return Ok(Self::rgba(self.color.animate(&other.color, procedure)?));
|
||||||
let (this_weight, other_weight) = procedure.weights();
|
}
|
||||||
|
|
||||||
Ok(match (*self, *other, procedure) {
|
let self_currentcolor = self.is_currentcolor();
|
||||||
// Any interpolation of currentcolor with currentcolor returns currentcolor.
|
let other_currentcolor = other.is_currentcolor();
|
||||||
(CurrentColor, CurrentColor, Procedure::Interpolate { .. }) => CurrentColor,
|
|
||||||
// Animating two numeric colors.
|
|
||||||
(Numeric(c1), Numeric(c2), _) => Numeric(c1.animate(&c2, procedure)?),
|
|
||||||
// Combinations of numeric color and currentcolor
|
|
||||||
(CurrentColor, Numeric(color), _) => Self::with_ratios(
|
|
||||||
color,
|
|
||||||
ComplexColorRatios {
|
|
||||||
bg: other_weight as f32,
|
|
||||||
fg: this_weight as f32,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(Numeric(color), CurrentColor, _) => Self::with_ratios(
|
|
||||||
color,
|
|
||||||
ComplexColorRatios {
|
|
||||||
bg: this_weight as f32,
|
|
||||||
fg: other_weight as f32,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
// Any other animation of currentcolor with currentcolor.
|
if self_currentcolor && other_currentcolor {
|
||||||
(CurrentColor, CurrentColor, _) => Self::with_ratios(
|
let (self_weight, other_weight) = procedure.weights();
|
||||||
|
return Ok(Self::new(
|
||||||
RGBA::transparent(),
|
RGBA::transparent(),
|
||||||
ComplexColorRatios {
|
ComplexColorRatios {
|
||||||
bg: 0.,
|
bg: 0.,
|
||||||
fg: (this_weight + other_weight) as f32,
|
fg: (self_weight + other_weight) as f32,
|
||||||
},
|
},
|
||||||
),
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// Defer to complex calculations
|
// FIXME(emilio): Without these special cases tests fail, looks fairly
|
||||||
_ => {
|
// sketchy!
|
||||||
// Compute the "scaled" contribution for `color`.
|
if (self_currentcolor && other_numeric) || (self_numeric && other_currentcolor) {
|
||||||
fn scaled_rgba(color: &Color) -> RGBA {
|
let (self_weight, other_weight) = procedure.weights();
|
||||||
match *color {
|
return Ok(if self_numeric {
|
||||||
GenericColor::Numeric(color) => color,
|
Self::new(
|
||||||
GenericColor::CurrentColor => RGBA::transparent(),
|
self.color,
|
||||||
GenericColor::Complex { color, ratios } => RGBA {
|
ComplexColorRatios {
|
||||||
red: color.red * ratios.bg,
|
bg: self_weight as f32,
|
||||||
green: color.green * ratios.bg,
|
fg: other_weight as f32,
|
||||||
blue: color.blue * ratios.bg,
|
},
|
||||||
alpha: color.alpha * ratios.bg,
|
)
|
||||||
},
|
} else {
|
||||||
}
|
Self::new(
|
||||||
}
|
other.color,
|
||||||
|
ComplexColorRatios {
|
||||||
|
bg: other_weight as f32,
|
||||||
|
fg: self_weight as f32,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Each `Color`, represents a complex combination of foreground color and
|
// Compute the "scaled" contribution for `color`.
|
||||||
// background color where fg and bg represent the overall
|
// Each `Color`, represents a complex combination of foreground color and
|
||||||
// contributions. ie:
|
// background color where fg and bg represent the overall
|
||||||
//
|
// contributions. ie:
|
||||||
// color = { bg * mColor, fg * foreground }
|
//
|
||||||
// = { bg_color , fg_color }
|
// color = { bg * mColor, fg * foreground }
|
||||||
// = bg_color + fg_color
|
// = { bg_color , fg_color }
|
||||||
//
|
// = bg_color + fg_color
|
||||||
// where `foreground` is `currentcolor`, and `bg_color`,
|
//
|
||||||
// `fg_color` are the scaled background and foreground
|
// where `foreground` is `currentcolor`, and `bg_color`,
|
||||||
// contributions.
|
// `fg_color` are the scaled background and foreground
|
||||||
//
|
// contributions.
|
||||||
// Each operation, lerp, addition, or accumulate, can be
|
//
|
||||||
// represented as a scaled-addition each complex color. ie:
|
// Each operation, lerp, addition, or accumulate, can be
|
||||||
//
|
// represented as a scaled-addition each complex color. ie:
|
||||||
// p * col1 + q * col2
|
//
|
||||||
//
|
// p * col1 + q * col2
|
||||||
// where p = (1 - a), q = a for lerp(a), p = 1, q = 1 for
|
//
|
||||||
// addition, etc.
|
// where p = (1 - a), q = a for lerp(a), p = 1, q = 1 for
|
||||||
//
|
// addition, etc.
|
||||||
// Therefore:
|
//
|
||||||
//
|
// Therefore:
|
||||||
// col1 op col2
|
//
|
||||||
// = p * col1 + q * col2
|
// col1 op col2
|
||||||
// = p * { bg_color1, fg_color1 } + q * { bg_color2, fg_color2 }
|
// = p * col1 + q * col2
|
||||||
// = p * (bg_color1 + fg_color1) + q * (bg_color2 + fg_color2)
|
// = p * { bg_color1, fg_color1 } + q * { bg_color2, fg_color2 }
|
||||||
// = p * bg_color1 + p * fg_color1 + q * bg_color2 + p * fg_color2
|
// = p * (bg_color1 + fg_color1) + q * (bg_color2 + fg_color2)
|
||||||
// = (p * bg_color1 + q * bg_color2) + (p * fg_color1 + q * fg_color2)
|
// = p * bg_color1 + p * fg_color1 + q * bg_color2 + p * fg_color2
|
||||||
// = (bg_color1 op bg_color2) + (fg_color1 op fg_color2)
|
// = (p * bg_color1 + q * bg_color2) + (p * fg_color1 + q * fg_color2)
|
||||||
//
|
// = (bg_color1 op bg_color2) + (fg_color1 op fg_color2)
|
||||||
// fg_color1 op fg_color2 is equivalent to (fg1 op fg2) * foreground,
|
//
|
||||||
// so the final color is:
|
// fg_color1 op fg_color2 is equivalent to (fg1 op fg2) * foreground,
|
||||||
//
|
// so the final color is:
|
||||||
// = { bg_color, fg_color }
|
//
|
||||||
// = { 1 * (bg_color1 op bg_color2), (fg1 op fg2) * foreground }
|
// = { bg_color, fg_color }
|
||||||
|
// = { 1 * (bg_color1 op bg_color2), (fg1 op fg2) * foreground }
|
||||||
|
//
|
||||||
|
// To perform the operation on two complex colors, we need to
|
||||||
|
// generate the scaled contributions of each background color
|
||||||
|
// component.
|
||||||
|
let bg_color1 = self.scaled_rgba();
|
||||||
|
let bg_color2 = other.scaled_rgba();
|
||||||
|
|
||||||
// To perform the operation on two complex colors, we need to
|
// Perform bg_color1 op bg_color2
|
||||||
// generate the scaled contributions of each background color
|
let bg_color = bg_color1.animate(&bg_color2, procedure)?;
|
||||||
// component.
|
|
||||||
let bg_color1 = scaled_rgba(self);
|
|
||||||
let bg_color2 = scaled_rgba(other);
|
|
||||||
// Perform bg_color1 op bg_color2
|
|
||||||
let bg_color = bg_color1.animate(&bg_color2, procedure)?;
|
|
||||||
|
|
||||||
// Calculate the final foreground color ratios; perform
|
// Calculate the final foreground color ratios; perform
|
||||||
// animation on effective fg ratios.
|
// animation on effective fg ratios.
|
||||||
let ComplexColorRatios { fg: fg1, .. } = self.effective_ratios();
|
let fg = self.ratios.fg.animate(&other.ratios.fg, procedure)?;
|
||||||
let ComplexColorRatios { fg: fg2, .. } = other.effective_ratios();
|
|
||||||
// Perform fg1 op fg2
|
|
||||||
let fg = fg1.animate(&fg2, procedure)?;
|
|
||||||
|
|
||||||
Self::with_ratios(bg_color, ComplexColorRatios { bg: 1., fg })
|
Ok(Self::new(bg_color, ComplexColorRatios { bg: 1., fg }))
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 apply here.
|
||||||
|
let self_numeric = self.is_numeric();
|
||||||
|
let other_numeric = other.is_numeric();
|
||||||
|
|
||||||
// All comments from the Animate impl also applies here.
|
if self_numeric && other_numeric {
|
||||||
Ok(match (*self, *other) {
|
return self.color.compute_squared_distance(&other.color);
|
||||||
(CurrentColor, CurrentColor) => SquaredDistance::from_sqrt(0.),
|
}
|
||||||
(Numeric(c1), Numeric(c2)) => c1.compute_squared_distance(&c2)?,
|
|
||||||
(CurrentColor, Numeric(color)) | (Numeric(color), CurrentColor) => {
|
|
||||||
// `computed_squared_distance` is symmetric.
|
|
||||||
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();
|
|
||||||
let other_ratios = other.effective_ratios();
|
|
||||||
|
|
||||||
self_color.compute_squared_distance(&other_color)? +
|
let self_currentcolor = self.is_currentcolor();
|
||||||
self_ratios.bg.compute_squared_distance(&other_ratios.bg)? +
|
let other_currentcolor = other.is_currentcolor();
|
||||||
self_ratios.fg.compute_squared_distance(&other_ratios.fg)?
|
if self_currentcolor && other_currentcolor {
|
||||||
},
|
return Ok(SquaredDistance::from_sqrt(0.));
|
||||||
})
|
}
|
||||||
|
|
||||||
|
if (self_currentcolor && other_numeric) || (self_numeric && other_currentcolor) {
|
||||||
|
let color = if self_numeric {
|
||||||
|
&self.color
|
||||||
|
} else {
|
||||||
|
&other.color
|
||||||
|
};
|
||||||
|
// `computed_squared_distance` is symmetric.
|
||||||
|
return Ok(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.ratios;
|
||||||
|
let other_ratios = other.ratios;
|
||||||
|
|
||||||
|
Ok(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)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,13 +29,18 @@ impl Color {
|
||||||
/// 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 {
|
// Common cases that the complex color is either pure numeric color or
|
||||||
// Common cases that the complex color is either pure numeric
|
// pure currentcolor.
|
||||||
// color or pure currentcolor.
|
if self.is_numeric() {
|
||||||
GenericColor::Numeric(color) => return color,
|
return self.color;
|
||||||
GenericColor::CurrentColor => return fg_color,
|
}
|
||||||
GenericColor::Complex { color, ratios } => (color, ratios),
|
|
||||||
};
|
if self.is_currentcolor() {
|
||||||
|
return fg_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ratios = &self.ratios;
|
||||||
|
let color = &self.color;
|
||||||
|
|
||||||
// For the more complicated case that the alpha value differs,
|
// For the more complicated case that the alpha value differs,
|
||||||
// we use the following formula to compute the components:
|
// we use the following formula to compute the components:
|
||||||
|
@ -59,13 +64,14 @@ impl Color {
|
||||||
if a <= 0. {
|
if a <= 0. {
|
||||||
return RGBA::transparent();
|
return RGBA::transparent();
|
||||||
}
|
}
|
||||||
let a = f32::min(a, 1.);
|
let a = a.min(1.);
|
||||||
|
|
||||||
let inverse_a = 1. / a;
|
let inv = 1. / a;
|
||||||
let r = (p1 * r1 + p2 * r2) * inverse_a;
|
|
||||||
let g = (p1 * g1 + p2 * g2) * inverse_a;
|
let r = (p1 * r1 + p2 * r2) * inv;
|
||||||
let b = (p1 * b1 + p2 * b2) * inverse_a;
|
let g = (p1 * g1 + p2 * g2) * inv;
|
||||||
return RGBA::from_floats(r, g, b, a);
|
let b = (p1 * b1 + p2 * b2) * inv;
|
||||||
|
RGBA::from_floats(r, g, b, a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,11 +80,13 @@ impl ToCss for Color {
|
||||||
where
|
where
|
||||||
W: fmt::Write,
|
W: fmt::Write,
|
||||||
{
|
{
|
||||||
match *self {
|
if self.is_currentcolor() {
|
||||||
GenericColor::Numeric(color) => color.to_css(dest),
|
return CSSParserColor::CurrentColor.to_css(dest);
|
||||||
GenericColor::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
|
|
||||||
_ => Ok(()),
|
|
||||||
}
|
}
|
||||||
|
if self.is_numeric() {
|
||||||
|
return self.color.to_css(dest);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,11 @@
|
||||||
|
|
||||||
/// Ratios representing the contribution of color and currentcolor to
|
/// Ratios representing the contribution of color and currentcolor to
|
||||||
/// the final color value.
|
/// the final color value.
|
||||||
|
///
|
||||||
|
/// NOTE(emilio): For animated colors, the sum of these two might be more than
|
||||||
|
/// one (because the background color would've been scaled down already). So
|
||||||
|
/// beware that it is not generally safe to assume that if bg is 1 then fg is 0,
|
||||||
|
/// for example.
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ComplexColorRatios {
|
pub struct ComplexColorRatios {
|
||||||
|
@ -22,59 +27,52 @@ impl ComplexColorRatios {
|
||||||
pub const CURRENT_COLOR: ComplexColorRatios = ComplexColorRatios { bg: 0., fg: 1. };
|
pub const CURRENT_COLOR: ComplexColorRatios = ComplexColorRatios { bg: 0., fg: 1. };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This enum represents a combined color from a numeric color and
|
/// This struct represents a combined color from a numeric color and
|
||||||
/// the current foreground color (currentcolor keyword).
|
/// the current foreground color (currentcolor keyword).
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
|
||||||
#[repr(C, u8)]
|
#[repr(C)]
|
||||||
pub enum GenericColor<RGBA> {
|
pub struct GenericColor<RGBA> {
|
||||||
/// Numeric RGBA color.
|
/// The actual numeric color.
|
||||||
Numeric(RGBA),
|
pub color: RGBA,
|
||||||
|
/// The ratios of mixing between numeric and currentcolor.
|
||||||
/// The current foreground color.
|
|
||||||
CurrentColor,
|
|
||||||
|
|
||||||
/// A linear combination of numeric color and currentcolor.
|
|
||||||
/// The formula is: `color * ratios.bg + currentcolor * ratios.fg`.
|
/// The formula is: `color * ratios.bg + currentcolor * ratios.fg`.
|
||||||
Complex {
|
pub ratios: ComplexColorRatios,
|
||||||
/// The actual numeric color.
|
|
||||||
color: RGBA,
|
|
||||||
/// The ratios of mixing between numeric and currentcolor.
|
|
||||||
ratios: ComplexColorRatios,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::GenericColor as Color;
|
pub use self::GenericColor as Color;
|
||||||
|
|
||||||
|
impl Color<cssparser::RGBA> {
|
||||||
|
/// Returns a color value representing currentcolor.
|
||||||
|
pub fn currentcolor() -> Self {
|
||||||
|
Color {
|
||||||
|
color: cssparser::RGBA::transparent(),
|
||||||
|
ratios: ComplexColorRatios::CURRENT_COLOR,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<RGBA> Color<RGBA> {
|
impl<RGBA> Color<RGBA> {
|
||||||
/// Create a color based upon the specified ratios.
|
/// Create a color based upon the specified ratios.
|
||||||
pub fn with_ratios(color: RGBA, ratios: ComplexColorRatios) -> Self {
|
pub fn new(color: RGBA, ratios: ComplexColorRatios) -> Self {
|
||||||
if ratios == ComplexColorRatios::NUMERIC {
|
Self { color, ratios }
|
||||||
Color::Numeric(color)
|
|
||||||
} else if ratios == ComplexColorRatios::CURRENT_COLOR {
|
|
||||||
Color::CurrentColor
|
|
||||||
} else {
|
|
||||||
Color::Complex { color, ratios }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a numeric color representing the given RGBA value.
|
/// Returns a numeric color representing the given RGBA value.
|
||||||
pub fn rgba(color: RGBA) -> Self {
|
pub fn rgba(color: RGBA) -> Self {
|
||||||
Color::Numeric(color)
|
Self {
|
||||||
}
|
color,
|
||||||
|
ratios: ComplexColorRatios::NUMERIC,
|
||||||
/// Returns a complex color value representing currentcolor.
|
}
|
||||||
pub fn currentcolor() -> Self {
|
|
||||||
Color::CurrentColor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether it is a numeric color (no currentcolor component).
|
/// Whether it is a numeric color (no currentcolor component).
|
||||||
pub fn is_numeric(&self) -> bool {
|
pub fn is_numeric(&self) -> bool {
|
||||||
matches!(*self, Color::Numeric(..))
|
self.ratios == ComplexColorRatios::NUMERIC
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether it is a currentcolor value (no numeric color component).
|
/// Whether it is a currentcolor value (no numeric color component).
|
||||||
pub fn is_currentcolor(&self) -> bool {
|
pub fn is_currentcolor(&self) -> bool {
|
||||||
matches!(*self, Color::CurrentColor)
|
self.ratios == ComplexColorRatios::CURRENT_COLOR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ impl ToResolvedValue for computed::Color {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
|
||||||
generics::Color::Numeric(resolved)
|
generics::Color::rgba(resolved)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ impl ToResolvedValue for computed::ColorOrAuto {
|
||||||
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
fn to_resolved_value(self, context: &Context) -> Self::ResolvedValue {
|
||||||
let color = match self {
|
let color = match self {
|
||||||
generics::ColorOrAuto::Color(color) => color,
|
generics::ColorOrAuto::Color(color) => color,
|
||||||
generics::ColorOrAuto::Auto => generics::Color::CurrentColor,
|
generics::ColorOrAuto::Auto => generics::Color::currentcolor(),
|
||||||
};
|
};
|
||||||
color.to_resolved_value(context)
|
color.to_resolved_value(context)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ use super::AllowQuirks;
|
||||||
use crate::gecko_bindings::structs::nscolor;
|
use crate::gecko_bindings::structs::nscolor;
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
use crate::values::computed::{Color as ComputedColor, Context, ToComputedValue};
|
use crate::values::computed::{Color as ComputedColor, Context, ToComputedValue};
|
||||||
use crate::values::generics::color::{Color as GenericColor, ColorOrAuto as GenericColorOrAuto};
|
use crate::values::generics::color::{ColorOrAuto as GenericColorOrAuto};
|
||||||
use crate::values::specified::calc::CalcNode;
|
use crate::values::specified::calc::CalcNode;
|
||||||
use cssparser::{AngleOrNumber, Color as CSSParserColor, Parser, Token, RGBA};
|
use cssparser::{AngleOrNumber, Color as CSSParserColor, Parser, Token, RGBA};
|
||||||
use cssparser::{BasicParseErrorKind, NumberOrPercentage, ParseErrorKind};
|
use cssparser::{BasicParseErrorKind, NumberOrPercentage, ParseErrorKind};
|
||||||
|
@ -585,11 +585,13 @@ impl ToComputedValue for Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_computed_value(computed: &ComputedColor) -> Self {
|
fn from_computed_value(computed: &ComputedColor) -> Self {
|
||||||
match *computed {
|
if computed.is_numeric() {
|
||||||
GenericColor::Numeric(color) => Color::rgba(color),
|
return Color::rgba(computed.color);
|
||||||
GenericColor::CurrentColor => Color::currentcolor(),
|
|
||||||
GenericColor::Complex { .. } => Color::Complex(*computed),
|
|
||||||
}
|
}
|
||||||
|
if computed.is_currentcolor() {
|
||||||
|
return Color::currentcolor();
|
||||||
|
}
|
||||||
|
Color::Complex(*computed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -490,6 +490,7 @@ renaming_overrides_prefixing = true
|
||||||
"""
|
"""
|
||||||
|
|
||||||
"GenericColor" = """
|
"GenericColor" = """
|
||||||
|
static inline StyleGenericColor CurrentColor();
|
||||||
static inline StyleGenericColor FromColor(nscolor);
|
static inline StyleGenericColor FromColor(nscolor);
|
||||||
static inline StyleGenericColor Black();
|
static inline StyleGenericColor Black();
|
||||||
static inline StyleGenericColor White();
|
static inline StyleGenericColor White();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче