Bug 1920496 - Store ColorFunction inside a computed color r=layout-reviewers,emilio
Differential Revision: https://phabricator.services.mozilla.com/D223136
This commit is contained in:
@@ -70,6 +70,15 @@ namespace mozilla {
|
||||
|
||||
class ComputedStyle;
|
||||
|
||||
template <typename T>
|
||||
struct StyleColorFunction {};
|
||||
|
||||
template <typename T>
|
||||
inline bool operator==(const StyleColorFunction<T>& left,
|
||||
const StyleColorFunction<T>& right) {
|
||||
return &left == &right;
|
||||
}
|
||||
|
||||
using Matrix4x4Components = float[16];
|
||||
using StyleMatrix4x4Components = Matrix4x4Components;
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ StyleAbsoluteColor StyleColor::ResolveColor(
|
||||
return aForegroundColor;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsColorMix(), "should be the only type left at this point.");
|
||||
return Servo_ResolveColor(this, &aForegroundColor);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,15 +12,17 @@ use super::{
|
||||
parsing::{NumberOrAngle, NumberOrPercentage},
|
||||
AbsoluteColor, ColorFlags, ColorSpace,
|
||||
};
|
||||
use crate::values::{normalize, specified::color::Color as SpecifiedColor};
|
||||
use crate::values::{
|
||||
computed::color::Color as ComputedColor, normalize, specified::color::Color as SpecifiedColor,
|
||||
};
|
||||
use cssparser::color::{clamp_floor_256_f32, OPAQUE};
|
||||
|
||||
/// Represents a specified color function.
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
|
||||
pub enum ColorFunction {
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
|
||||
pub enum ColorFunction<Color> {
|
||||
/// <https://drafts.csswg.org/css-color-4/#rgb-functions>
|
||||
Rgb(
|
||||
Option<SpecifiedColor>, // origin
|
||||
Option<Color>, // origin
|
||||
ColorComponent<NumberOrPercentage>, // red
|
||||
ColorComponent<NumberOrPercentage>, // green
|
||||
ColorComponent<NumberOrPercentage>, // blue
|
||||
@@ -28,7 +30,7 @@ pub enum ColorFunction {
|
||||
),
|
||||
/// <https://drafts.csswg.org/css-color-4/#the-hsl-notation>
|
||||
Hsl(
|
||||
Option<SpecifiedColor>, // origin
|
||||
Option<Color>, // origin
|
||||
ColorComponent<NumberOrAngle>, // hue
|
||||
ColorComponent<NumberOrPercentage>, // saturation
|
||||
ColorComponent<NumberOrPercentage>, // lightness
|
||||
@@ -36,7 +38,7 @@ pub enum ColorFunction {
|
||||
),
|
||||
/// <https://drafts.csswg.org/css-color-4/#the-hwb-notation>
|
||||
Hwb(
|
||||
Option<SpecifiedColor>, // origin
|
||||
Option<Color>, // origin
|
||||
ColorComponent<NumberOrAngle>, // hue
|
||||
ColorComponent<NumberOrPercentage>, // whiteness
|
||||
ColorComponent<NumberOrPercentage>, // blackness
|
||||
@@ -44,7 +46,7 @@ pub enum ColorFunction {
|
||||
),
|
||||
/// <https://drafts.csswg.org/css-color-4/#specifying-lab-lch>
|
||||
Lab(
|
||||
Option<SpecifiedColor>, // origin
|
||||
Option<Color>, // origin
|
||||
ColorComponent<NumberOrPercentage>, // lightness
|
||||
ColorComponent<NumberOrPercentage>, // a
|
||||
ColorComponent<NumberOrPercentage>, // b
|
||||
@@ -52,7 +54,7 @@ pub enum ColorFunction {
|
||||
),
|
||||
/// <https://drafts.csswg.org/css-color-4/#specifying-lab-lch>
|
||||
Lch(
|
||||
Option<SpecifiedColor>, // origin
|
||||
Option<Color>, // origin
|
||||
ColorComponent<NumberOrPercentage>, // lightness
|
||||
ColorComponent<NumberOrPercentage>, // chroma
|
||||
ColorComponent<NumberOrAngle>, // hue
|
||||
@@ -60,7 +62,7 @@ pub enum ColorFunction {
|
||||
),
|
||||
/// <https://drafts.csswg.org/css-color-4/#specifying-oklab-oklch>
|
||||
Oklab(
|
||||
Option<SpecifiedColor>, // origin
|
||||
Option<Color>, // origin
|
||||
ColorComponent<NumberOrPercentage>, // lightness
|
||||
ColorComponent<NumberOrPercentage>, // a
|
||||
ColorComponent<NumberOrPercentage>, // b
|
||||
@@ -68,7 +70,7 @@ pub enum ColorFunction {
|
||||
),
|
||||
/// <https://drafts.csswg.org/css-color-4/#specifying-oklab-oklch>
|
||||
Oklch(
|
||||
Option<SpecifiedColor>, // origin
|
||||
Option<Color>, // origin
|
||||
ColorComponent<NumberOrPercentage>, // lightness
|
||||
ColorComponent<NumberOrPercentage>, // chroma
|
||||
ColorComponent<NumberOrAngle>, // hue
|
||||
@@ -76,7 +78,7 @@ pub enum ColorFunction {
|
||||
),
|
||||
/// <https://drafts.csswg.org/css-color-4/#color-function>
|
||||
Color(
|
||||
Option<SpecifiedColor>, // origin
|
||||
Option<Color>, // origin
|
||||
ColorComponent<NumberOrPercentage>, // red / x
|
||||
ColorComponent<NumberOrPercentage>, // green / y
|
||||
ColorComponent<NumberOrPercentage>, // blue / z
|
||||
@@ -85,24 +87,8 @@ pub enum ColorFunction {
|
||||
),
|
||||
}
|
||||
|
||||
impl ColorFunction {
|
||||
/// Return true if the color funciton has an origin color specified.
|
||||
pub fn has_origin_color(&self) -> bool {
|
||||
match self {
|
||||
Self::Rgb(origin_color, ..) |
|
||||
Self::Hsl(origin_color, ..) |
|
||||
Self::Hwb(origin_color, ..) |
|
||||
Self::Lab(origin_color, ..) |
|
||||
Self::Lch(origin_color, ..) |
|
||||
Self::Oklab(origin_color, ..) |
|
||||
Self::Oklch(origin_color, ..) |
|
||||
Self::Color(origin_color, ..) => origin_color.is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to resolve the color function to an [`AbsoluteColor`] that does not
|
||||
/// contain any variables (currentcolor, color components, etc.).
|
||||
pub fn resolve_to_absolute(&self) -> Result<AbsoluteColor, ()> {
|
||||
impl ColorFunction<AbsoluteColor> {
|
||||
fn resolve_to_absolute(&self) -> Result<AbsoluteColor, ()> {
|
||||
macro_rules! alpha {
|
||||
($alpha:expr, $origin_color:expr) => {{
|
||||
$alpha
|
||||
@@ -111,17 +97,6 @@ impl ColorFunction {
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! resolved_origin_color {
|
||||
($origin_color:expr,$color_space:expr) => {{
|
||||
match $origin_color {
|
||||
Some(color) => color
|
||||
.resolve_to_absolute()
|
||||
.map(|color| color.to_color_space($color_space)),
|
||||
None => None,
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
Ok(match self {
|
||||
ColorFunction::Rgb(origin_color, r, g, b, alpha) => {
|
||||
#[inline]
|
||||
@@ -137,17 +112,19 @@ impl ColorFunction {
|
||||
))
|
||||
}
|
||||
|
||||
// Ensure that the origin color is in the rgb(..) format and not in
|
||||
// the color(srgb ..) format.
|
||||
let origin_color = resolved_origin_color!(origin_color, ColorSpace::Srgb)
|
||||
.map(|origin| origin.into_srgb_legacy());
|
||||
let origin_color =
|
||||
origin_color.map(|o| o.to_color_space(ColorSpace::Srgb).into_srgb_legacy());
|
||||
|
||||
AbsoluteColor::srgb_legacy(
|
||||
resolve(r, origin_color.as_ref())?,
|
||||
resolve(g, origin_color.as_ref())?,
|
||||
resolve(b, origin_color.as_ref())?,
|
||||
alpha!(alpha, origin_color.as_ref()).unwrap_or(0.0),
|
||||
)
|
||||
let r = resolve(r, origin_color.as_ref())?;
|
||||
let g = resolve(g, origin_color.as_ref())?;
|
||||
let b = resolve(b, origin_color.as_ref())?;
|
||||
let alpha = alpha!(alpha, origin_color.as_ref()).unwrap_or(0.0);
|
||||
|
||||
if origin_color.is_some() {
|
||||
AbsoluteColor::new(ColorSpace::Srgb, r, g, b, alpha)
|
||||
} else {
|
||||
AbsoluteColor::srgb_legacy(r, g, b, alpha)
|
||||
}
|
||||
},
|
||||
ColorFunction::Hsl(origin_color, h, s, l, alpha) => {
|
||||
// Percent reference range for S and L: 0% = 0.0, 100% = 100.0
|
||||
@@ -161,7 +138,7 @@ impl ColorFunction {
|
||||
// color to be out of gamut and not clamp.
|
||||
let use_rgb_sytax = origin_color.is_none();
|
||||
|
||||
let origin_color = resolved_origin_color!(origin_color, ColorSpace::Hsl);
|
||||
let origin_color = origin_color.map(|o| o.to_color_space(ColorSpace::Hsl));
|
||||
|
||||
let mut result = AbsoluteColor::new(
|
||||
ColorSpace::Hsl,
|
||||
@@ -202,7 +179,7 @@ impl ColorFunction {
|
||||
const WHITENESS_RANGE: f32 = 100.0;
|
||||
const BLACKNESS_RANGE: f32 = 100.0;
|
||||
|
||||
let origin_color = resolved_origin_color!(origin_color, ColorSpace::Hwb);
|
||||
let origin_color = origin_color.map(|o| o.to_color_space(ColorSpace::Hwb));
|
||||
|
||||
let mut result = AbsoluteColor::new(
|
||||
ColorSpace::Hwb,
|
||||
@@ -237,7 +214,7 @@ impl ColorFunction {
|
||||
const LIGHTNESS_RANGE: f32 = 100.0;
|
||||
const A_B_RANGE: f32 = 125.0;
|
||||
|
||||
let origin_color = resolved_origin_color!(origin_color, ColorSpace::Lab);
|
||||
let origin_color = origin_color.map(|o| o.to_color_space(ColorSpace::Lab));
|
||||
|
||||
AbsoluteColor::new(
|
||||
ColorSpace::Lab,
|
||||
@@ -256,7 +233,7 @@ impl ColorFunction {
|
||||
const LIGHTNESS_RANGE: f32 = 100.0;
|
||||
const CHROMA_RANGE: f32 = 150.0;
|
||||
|
||||
let origin_color = resolved_origin_color!(origin_color, ColorSpace::Lch);
|
||||
let origin_color = origin_color.map(|o| o.to_color_space(ColorSpace::Lch));
|
||||
|
||||
AbsoluteColor::new(
|
||||
ColorSpace::Lch,
|
||||
@@ -275,7 +252,7 @@ impl ColorFunction {
|
||||
const LIGHTNESS_RANGE: f32 = 1.0;
|
||||
const A_B_RANGE: f32 = 0.4;
|
||||
|
||||
let origin_color = resolved_origin_color!(origin_color, ColorSpace::Oklab);
|
||||
let origin_color = origin_color.map(|o| o.to_color_space(ColorSpace::Oklab));
|
||||
|
||||
AbsoluteColor::new(
|
||||
ColorSpace::Oklab,
|
||||
@@ -294,7 +271,7 @@ impl ColorFunction {
|
||||
const LIGHTNESS_RANGE: f32 = 1.0;
|
||||
const CHROMA_RANGE: f32 = 0.4;
|
||||
|
||||
let origin_color = resolved_origin_color!(origin_color, ColorSpace::Oklch);
|
||||
let origin_color = origin_color.map(|o| o.to_color_space(ColorSpace::Oklch));
|
||||
|
||||
AbsoluteColor::new(
|
||||
ColorSpace::Oklch,
|
||||
@@ -308,7 +285,7 @@ impl ColorFunction {
|
||||
)
|
||||
},
|
||||
ColorFunction::Color(origin_color, r, g, b, alpha, color_space) => {
|
||||
let origin_color = resolved_origin_color!(origin_color, *color_space);
|
||||
let origin_color = origin_color.map(|o| o.to_color_space(*color_space));
|
||||
AbsoluteColor::new(
|
||||
(*color_space).into(),
|
||||
r.resolve(origin_color.as_ref())?.map(|c| c.to_number(1.0)),
|
||||
@@ -321,7 +298,83 @@ impl ColorFunction {
|
||||
}
|
||||
}
|
||||
|
||||
impl style_traits::ToCss for ColorFunction {
|
||||
impl ColorFunction<SpecifiedColor> {
|
||||
/// Return true if the color funciton has an origin color specified.
|
||||
pub fn has_origin_color(&self) -> bool {
|
||||
match self {
|
||||
Self::Rgb(origin_color, ..) |
|
||||
Self::Hsl(origin_color, ..) |
|
||||
Self::Hwb(origin_color, ..) |
|
||||
Self::Lab(origin_color, ..) |
|
||||
Self::Lch(origin_color, ..) |
|
||||
Self::Oklab(origin_color, ..) |
|
||||
Self::Oklch(origin_color, ..) |
|
||||
Self::Color(origin_color, ..) => origin_color.is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to resolve the color function to an [`AbsoluteColor`] that does not
|
||||
/// contain any variables (currentcolor, color components, etc.).
|
||||
pub fn resolve_to_absolute(&self) -> Result<AbsoluteColor, ()> {
|
||||
// Map the color function to one with an absolute origin color.
|
||||
let resolvable = self.map_origin_color(|o| o.resolve_to_absolute());
|
||||
resolvable.resolve_to_absolute()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Color> ColorFunction<Color> {
|
||||
/// Map the origin color to another type. Return None from `f` if the conversion fails.
|
||||
pub fn map_origin_color<U>(&self, f: impl FnOnce(&Color) -> Option<U>) -> ColorFunction<U> {
|
||||
macro_rules! map {
|
||||
($f:ident, $o:expr, $c0:expr, $c1:expr, $c2:expr, $alpha:expr) => {{
|
||||
ColorFunction::$f(
|
||||
$o.as_ref().and_then(f),
|
||||
$c0.clone(),
|
||||
$c1.clone(),
|
||||
$c2.clone(),
|
||||
$alpha.clone(),
|
||||
)
|
||||
}};
|
||||
}
|
||||
match self {
|
||||
ColorFunction::Rgb(o, c0, c1, c2, alpha) => map!(Rgb, o, c0, c1, c2, alpha),
|
||||
ColorFunction::Hsl(o, c0, c1, c2, alpha) => map!(Hsl, o, c0, c1, c2, alpha),
|
||||
ColorFunction::Hwb(o, c0, c1, c2, alpha) => map!(Hwb, o, c0, c1, c2, alpha),
|
||||
ColorFunction::Lab(o, c0, c1, c2, alpha) => map!(Lab, o, c0, c1, c2, alpha),
|
||||
ColorFunction::Lch(o, c0, c1, c2, alpha) => map!(Lch, o, c0, c1, c2, alpha),
|
||||
ColorFunction::Oklab(o, c0, c1, c2, alpha) => map!(Oklab, o, c0, c1, c2, alpha),
|
||||
ColorFunction::Oklch(o, c0, c1, c2, alpha) => map!(Oklch, o, c0, c1, c2, alpha),
|
||||
ColorFunction::Color(o, c0, c1, c2, alpha, color_space) => ColorFunction::Color(
|
||||
o.as_ref().and_then(f),
|
||||
c0.clone(),
|
||||
c1.clone(),
|
||||
c2.clone(),
|
||||
alpha.clone(),
|
||||
color_space.clone(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorFunction<ComputedColor> {
|
||||
/// Resolve a computed color function to an absolute computed color.
|
||||
pub fn resolve_to_absolute(&self, current_color: &AbsoluteColor) -> AbsoluteColor {
|
||||
// Map the color function to one with an absolute origin color.
|
||||
let resolvable = self.map_origin_color(|o| Some(o.resolve_to_absolute(current_color)));
|
||||
match resolvable.resolve_to_absolute() {
|
||||
Ok(color) => color,
|
||||
Err(..) => {
|
||||
debug_assert!(
|
||||
false,
|
||||
"the color could not be resolved even with a currentcolor specified?"
|
||||
);
|
||||
AbsoluteColor::TRANSPARENT_BLACK
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: style_traits::ToCss> style_traits::ToCss for ColorFunction<C> {
|
||||
fn to_css<W>(&self, dest: &mut style_traits::CssWriter<W>) -> std::fmt::Result
|
||||
where
|
||||
W: std::fmt::Write,
|
||||
|
||||
@@ -13,6 +13,7 @@ use super::{
|
||||
use crate::{
|
||||
parser::ParserContext,
|
||||
values::{
|
||||
animated::ToAnimatedValue,
|
||||
generics::calc::CalcUnits,
|
||||
specified::calc::{CalcNode as SpecifiedCalcNode, Leaf as SpecifiedLeaf},
|
||||
},
|
||||
@@ -209,3 +210,15 @@ impl<ValueType: ToCss> ToCss for ColorComponent<ValueType> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<ValueType> ToAnimatedValue for ColorComponent<ValueType> {
|
||||
type AnimatedValue = Self;
|
||||
|
||||
fn to_animated_value(self, _context: &crate::values::animated::Context) -> Self::AnimatedValue {
|
||||
self
|
||||
}
|
||||
|
||||
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
|
||||
animated
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,10 @@
|
||||
|
||||
//! Color support functions.
|
||||
|
||||
/// cbindgen:ignore
|
||||
mod color_function;
|
||||
|
||||
/// cbindgen:ignore
|
||||
pub mod convert;
|
||||
|
||||
mod color_function;
|
||||
pub mod component;
|
||||
pub mod mix;
|
||||
pub mod parsing;
|
||||
|
||||
@@ -169,7 +169,7 @@ fn parse_color_function<'i, 't>(
|
||||
context: &ParserContext,
|
||||
name: CowRcStr<'i>,
|
||||
arguments: &mut Parser<'i, 't>,
|
||||
) -> Result<ColorFunction, ParseError<'i>> {
|
||||
) -> Result<ColorFunction<SpecifiedColor>, ParseError<'i>> {
|
||||
let origin_color = parse_origin_color(context, arguments)?;
|
||||
|
||||
let color = match_ignore_ascii_case! { &name,
|
||||
@@ -215,7 +215,7 @@ fn parse_rgb<'i, 't>(
|
||||
context: &ParserContext,
|
||||
arguments: &mut Parser<'i, 't>,
|
||||
origin_color: Option<SpecifiedColor>,
|
||||
) -> Result<ColorFunction, ParseError<'i>> {
|
||||
) -> Result<ColorFunction<SpecifiedColor>, ParseError<'i>> {
|
||||
let maybe_red = parse_number_or_percentage(context, arguments, true, RGB_CHANNEL_KEYWORDS)?;
|
||||
|
||||
// If the first component is not "none" and is followed by a comma, then we
|
||||
@@ -259,7 +259,7 @@ fn parse_hsl<'i, 't>(
|
||||
context: &ParserContext,
|
||||
arguments: &mut Parser<'i, 't>,
|
||||
origin_color: Option<SpecifiedColor>,
|
||||
) -> Result<ColorFunction, ParseError<'i>> {
|
||||
) -> Result<ColorFunction<SpecifiedColor>, ParseError<'i>> {
|
||||
let hue = parse_number_or_angle(context, arguments, true, HSL_CHANNEL_KEYWORDS)?;
|
||||
|
||||
// If the hue is not "none" and is followed by a comma, then we are parsing
|
||||
@@ -299,7 +299,7 @@ fn parse_hwb<'i, 't>(
|
||||
context: &ParserContext,
|
||||
arguments: &mut Parser<'i, 't>,
|
||||
origin_color: Option<SpecifiedColor>,
|
||||
) -> Result<ColorFunction, ParseError<'i>> {
|
||||
) -> Result<ColorFunction<SpecifiedColor>, ParseError<'i>> {
|
||||
let hue = parse_number_or_angle(context, arguments, true, HWB_CHANNEL_KEYWORDS)?;
|
||||
let whiteness = parse_number_or_percentage(context, arguments, true, HWB_CHANNEL_KEYWORDS)?;
|
||||
let blackness = parse_number_or_percentage(context, arguments, true, HWB_CHANNEL_KEYWORDS)?;
|
||||
@@ -328,8 +328,8 @@ fn parse_lab_like<'i, 't>(
|
||||
context: &ParserContext,
|
||||
arguments: &mut Parser<'i, 't>,
|
||||
origin_color: Option<SpecifiedColor>,
|
||||
into_color: IntoLabFn<ColorFunction>,
|
||||
) -> Result<ColorFunction, ParseError<'i>> {
|
||||
into_color: IntoLabFn<ColorFunction<SpecifiedColor>>,
|
||||
) -> Result<ColorFunction<SpecifiedColor>, ParseError<'i>> {
|
||||
let lightness = parse_number_or_percentage(context, arguments, true, LAB_CHANNEL_KEYWORDS)?;
|
||||
let a = parse_number_or_percentage(context, arguments, true, LAB_CHANNEL_KEYWORDS)?;
|
||||
let b = parse_number_or_percentage(context, arguments, true, LAB_CHANNEL_KEYWORDS)?;
|
||||
@@ -352,8 +352,8 @@ fn parse_lch_like<'i, 't>(
|
||||
context: &ParserContext,
|
||||
arguments: &mut Parser<'i, 't>,
|
||||
origin_color: Option<SpecifiedColor>,
|
||||
into_color: IntoLchFn<ColorFunction>,
|
||||
) -> Result<ColorFunction, ParseError<'i>> {
|
||||
into_color: IntoLchFn<ColorFunction<SpecifiedColor>>,
|
||||
) -> Result<ColorFunction<SpecifiedColor>, ParseError<'i>> {
|
||||
let lightness = parse_number_or_percentage(context, arguments, true, LCH_CHANNEL_KEYWORDS)?;
|
||||
let chroma = parse_number_or_percentage(context, arguments, true, LCH_CHANNEL_KEYWORDS)?;
|
||||
let hue = parse_number_or_angle(context, arguments, true, LCH_CHANNEL_KEYWORDS)?;
|
||||
@@ -369,7 +369,7 @@ fn parse_color_with_color_space<'i, 't>(
|
||||
context: &ParserContext,
|
||||
arguments: &mut Parser<'i, 't>,
|
||||
origin_color: Option<SpecifiedColor>,
|
||||
) -> Result<ColorFunction, ParseError<'i>> {
|
||||
) -> Result<ColorFunction<SpecifiedColor>, ParseError<'i>> {
|
||||
let color_space = PredefinedColorSpace::parse(arguments)?;
|
||||
|
||||
let allowed_channel_keywords = match color_space {
|
||||
@@ -398,8 +398,8 @@ fn parse_color_with_color_space<'i, 't>(
|
||||
))
|
||||
}
|
||||
|
||||
/// Eithee.
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem)]
|
||||
/// Either a percentage or a number.
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
|
||||
pub enum NumberOrPercentage {
|
||||
/// `<number>`.
|
||||
Number(f32),
|
||||
@@ -448,7 +448,7 @@ impl ColorComponentType for NumberOrPercentage {
|
||||
}
|
||||
|
||||
/// Either an angle or a number.
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem)]
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
|
||||
pub enum NumberOrAngle {
|
||||
/// `<number>`.
|
||||
Number(f32),
|
||||
|
||||
@@ -31,6 +31,7 @@ impl ToCss for Color {
|
||||
{
|
||||
match *self {
|
||||
Self::Absolute(ref c) => c.to_css(dest),
|
||||
Self::ColorFunction(ref color_function) => color_function.to_css(dest),
|
||||
Self::CurrentColor => dest.write_str("currentcolor"),
|
||||
Self::ColorMix(ref m) => m.to_css(dest),
|
||||
}
|
||||
@@ -64,6 +65,9 @@ impl Color {
|
||||
|
||||
match *self {
|
||||
Self::Absolute(c) => c,
|
||||
Self::ColorFunction(ref color_function) => {
|
||||
color_function.resolve_to_absolute(current_color)
|
||||
},
|
||||
Self::CurrentColor => *current_color,
|
||||
Self::ColorMix(ref mix) => {
|
||||
let left = mix.left.resolve_to_absolute(current_color);
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
//! Generic types for color properties.
|
||||
|
||||
use crate::color::mix::ColorInterpolationMethod;
|
||||
use crate::color::AbsoluteColor;
|
||||
use crate::color::{mix::ColorInterpolationMethod, AbsoluteColor, ColorFunction};
|
||||
use crate::values::specified::percentage::ToPercentage;
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ToCss};
|
||||
@@ -17,6 +16,8 @@ use style_traits::{CssWriter, ToCss};
|
||||
pub enum GenericColor<Percentage> {
|
||||
/// The actual numeric color.
|
||||
Absolute(AbsoluteColor),
|
||||
/// A unresolvable color.
|
||||
ColorFunction(Box<ColorFunction<Self>>),
|
||||
/// The `CurrentColor` keyword.
|
||||
CurrentColor,
|
||||
/// The color-mix() function.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
use super::AllowQuirks;
|
||||
use crate::color::mix::ColorInterpolationMethod;
|
||||
use crate::color::{parsing, AbsoluteColor, ColorFlags, ColorFunction, ColorSpace};
|
||||
use crate::color::{parsing, AbsoluteColor, ColorFunction, ColorSpace};
|
||||
use crate::media_queries::Device;
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::values::computed::{Color as ComputedColor, Context, ToComputedValue};
|
||||
@@ -117,7 +117,7 @@ pub enum Color {
|
||||
Absolute(Box<Absolute>),
|
||||
/// A color function that could not be resolved to a [Color::Absolute] color at parse time.
|
||||
/// Right now this is only the case for relative colors with `currentColor` as the origin.
|
||||
ColorFunction(Box<ColorFunction>),
|
||||
ColorFunction(Box<ColorFunction<Self>>),
|
||||
/// A system color.
|
||||
#[cfg(feature = "gecko")]
|
||||
System(SystemColor),
|
||||
@@ -786,29 +786,17 @@ impl Color {
|
||||
ComputedColor::Absolute(color)
|
||||
},
|
||||
Color::ColorFunction(ref color_function) => {
|
||||
let has_origin_color = color_function.has_origin_color();
|
||||
debug_assert!(color_function.has_origin_color(),
|
||||
"no need for a ColorFunction if it doesn't contain an unresolvable origin color");
|
||||
|
||||
let Ok(mut absolute) = color_function.resolve_to_absolute() else {
|
||||
// TODO(tlouw): The specified color must contain `currentColor` or some other
|
||||
// unresolvable origin color, so here we have to store the whole
|
||||
// [ColorFunction] in the computed color.
|
||||
return Some(ComputedColor::Absolute(AbsoluteColor::BLACK));
|
||||
};
|
||||
|
||||
// A special case when the color was a rgb(..) function and had an origin color,
|
||||
// the result must be in the color(srgb ..) syntax, to avoid clipped channels
|
||||
// into gamut limits.
|
||||
let mut absolute = match absolute.color_space {
|
||||
_ if has_origin_color && absolute.is_legacy_syntax() => {
|
||||
absolute.flags.remove(ColorFlags::IS_LEGACY_SRGB);
|
||||
absolute
|
||||
},
|
||||
_ => absolute,
|
||||
};
|
||||
|
||||
adjust_absolute_color!(absolute);
|
||||
|
||||
ComputedColor::Absolute(absolute)
|
||||
// Try to eagerly resolve the color function before making it a computed color.
|
||||
if let Ok(absolute) = color_function.resolve_to_absolute() {
|
||||
ComputedColor::Absolute(absolute)
|
||||
} else {
|
||||
let color_function = color_function
|
||||
.map_origin_color(|origin_color| origin_color.to_computed_color(context));
|
||||
ComputedColor::ColorFunction(Box::new(color_function))
|
||||
}
|
||||
},
|
||||
Color::LightDark(ref ld) => ld.compute(context?),
|
||||
Color::ColorMix(ref mix) => {
|
||||
@@ -852,6 +840,11 @@ impl ToComputedValue for Color {
|
||||
fn from_computed_value(computed: &ComputedColor) -> Self {
|
||||
match *computed {
|
||||
ComputedColor::Absolute(ref color) => Self::from_absolute_color(color.clone()),
|
||||
ComputedColor::ColorFunction(ref color_function) => {
|
||||
let color_function =
|
||||
color_function.map_origin_color(|o| Some(Self::from_computed_value(o)));
|
||||
Self::ColorFunction(Box::new(color_function))
|
||||
},
|
||||
ComputedColor::CurrentColor => Color::CurrentColor,
|
||||
ComputedColor::ColorMix(ref mix) => {
|
||||
Color::ColorMix(Box::new(ToComputedValue::from_computed_value(&**mix)))
|
||||
|
||||
@@ -84,6 +84,7 @@ exclude = [
|
||||
"NS_LogDtor",
|
||||
"SelectorList",
|
||||
"AuthorStyles",
|
||||
"ColorFunction",
|
||||
]
|
||||
include = [
|
||||
"AnchorName",
|
||||
@@ -328,7 +329,14 @@ include = [
|
||||
"AnchorSizeFunction",
|
||||
"Margin",
|
||||
]
|
||||
item_types = ["enums", "structs", "unions", "typedefs", "functions", "constants"]
|
||||
item_types = [
|
||||
"enums",
|
||||
"structs",
|
||||
"unions",
|
||||
"typedefs",
|
||||
"functions",
|
||||
"constants",
|
||||
]
|
||||
renaming_overrides_prefixing = true
|
||||
|
||||
# Prevent some renaming for Gecko types that cbindgen doesn't otherwise understand.
|
||||
|
||||
Reference in New Issue
Block a user