mirror of
https://github.com/servo/servo.git
synced 2025-07-23 23:33:43 +01:00
style: Allow 'none' keyword in color components
Make use of the new changes in the cssparser that allows 'none' keywords in color components where allowed. We store the none values as 0.0 (as per the spec) and mark the components with the flags. This way we don't have to check anything on the components before doing calculations. As this is the last part intended to be released for the new [color-4] changes, I've also enabled the changes on nightly. Differential Revision: https://phabricator.services.mozilla.com/D170208
This commit is contained in:
parent
3756e3b027
commit
fb4501c5b4
3 changed files with 264 additions and 72 deletions
|
@ -68,6 +68,7 @@ fn hue_to_rgb(t1: f32, t2: f32, hue: f32) -> f32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert from HSL notation to RGB notation.
|
/// Convert from HSL notation to RGB notation.
|
||||||
|
/// https://drafts.csswg.org/css-color-4/#hsl-to-rgb
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn hsl_to_rgb(from: &ColorComponents) -> ColorComponents {
|
pub fn hsl_to_rgb(from: &ColorComponents) -> ColorComponents {
|
||||||
let ColorComponents(hue, saturation, lightness) = *from;
|
let ColorComponents(hue, saturation, lightness) = *from;
|
||||||
|
@ -87,26 +88,26 @@ pub fn hsl_to_rgb(from: &ColorComponents) -> ColorComponents {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert from RGB notation to HSL notation.
|
/// Convert from RGB notation to HSL notation.
|
||||||
/// https://drafts.csswg.org/css-color/#rgb-to-hsl
|
/// https://drafts.csswg.org/css-color-4/#rgb-to-hsl
|
||||||
pub fn rgb_to_hsl(from: &ColorComponents) -> ColorComponents {
|
pub fn rgb_to_hsl(from: &ColorComponents) -> ColorComponents {
|
||||||
let ColorComponents(red, green, blue) = *from;
|
let ColorComponents(red, green, blue) = *from;
|
||||||
|
|
||||||
let (hue, min, max) = rgb_to_hue_min_max(red, green, blue);
|
let (hue, min, max) = rgb_to_hue_min_max(red, green, blue);
|
||||||
|
|
||||||
let light = (min + max) / 2.0;
|
let lightness = (min + max) / 2.0;
|
||||||
let delta = max - min;
|
let delta = max - min;
|
||||||
|
|
||||||
let sat = if delta != 0.0 {
|
let saturation = if delta != 0.0 {
|
||||||
if light == 0.0 || light == 1.0 {
|
if lightness == 0.0 || lightness == 1.0 {
|
||||||
0.0
|
0.0
|
||||||
} else {
|
} else {
|
||||||
(max - light) / light.min(1.0 - light)
|
(max - lightness) / lightness.min(1.0 - lightness)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
};
|
};
|
||||||
|
|
||||||
ColorComponents(hue, sat, light)
|
ColorComponents(hue, saturation, lightness)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert from HWB notation to RGB notation.
|
/// Convert from HWB notation to RGB notation.
|
||||||
|
@ -138,6 +139,30 @@ pub fn rgb_to_hwb(from: &ColorComponents) -> ColorComponents {
|
||||||
ColorComponents(hue, whiteness, blackness)
|
ColorComponents(hue, whiteness, blackness)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert from Lab to Lch. This calculation works for both Lab and Olab.
|
||||||
|
/// <https://drafts.csswg.org/css-color-4/#color-conversion-code>
|
||||||
|
#[inline]
|
||||||
|
pub fn lab_to_lch(from: &ColorComponents) -> ColorComponents {
|
||||||
|
let ColorComponents(lightness, a, b) = *from;
|
||||||
|
|
||||||
|
let hue = normalize_hue(b.atan2(a) * 180.0 / PI);
|
||||||
|
let chroma = (a.powf(2.0) + b.powf(2.0)).sqrt();
|
||||||
|
|
||||||
|
ColorComponents(lightness, chroma, hue)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert from Lch to Lab. This calculation works for both Lch and Oklch.
|
||||||
|
/// <https://drafts.csswg.org/css-color-4/#color-conversion-code>
|
||||||
|
#[inline]
|
||||||
|
pub fn lch_to_lab(from: &ColorComponents) -> ColorComponents {
|
||||||
|
let ColorComponents(lightness, chroma, hue) = *from;
|
||||||
|
|
||||||
|
let a = chroma * (hue * PI / 180.0).cos();
|
||||||
|
let b = chroma * (hue * PI / 180.0).sin();
|
||||||
|
|
||||||
|
ColorComponents(lightness, a, b)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn transform(from: &ColorComponents, mat: &Transform) -> ColorComponents {
|
fn transform(from: &ColorComponents, mat: &Transform) -> ColorComponents {
|
||||||
let result = mat.transform_vector3d(Vector::new(from.0, from.1, from.2));
|
let result = mat.transform_vector3d(Vector::new(from.0, from.1, from.2));
|
||||||
|
@ -305,6 +330,56 @@ impl ColorSpaceConversion for Srgb {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Color specified with hue, saturation and lightness components.
|
||||||
|
pub struct Hsl;
|
||||||
|
|
||||||
|
impl ColorSpaceConversion for Hsl {
|
||||||
|
const WHITE_POINT: WhitePoint = Srgb::WHITE_POINT;
|
||||||
|
|
||||||
|
fn to_linear_light(from: &ColorComponents) -> ColorComponents {
|
||||||
|
Srgb::to_linear_light(&hsl_to_rgb(from))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_xyz(from: &ColorComponents) -> ColorComponents {
|
||||||
|
Srgb::to_xyz(from)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_xyz(from: &ColorComponents) -> ColorComponents {
|
||||||
|
Srgb::from_xyz(from)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_gamma_encoded(from: &ColorComponents) -> ColorComponents {
|
||||||
|
rgb_to_hsl(&Srgb::to_gamma_encoded(from))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Color specified with hue, whiteness and blackness components.
|
||||||
|
pub struct Hwb;
|
||||||
|
|
||||||
|
impl ColorSpaceConversion for Hwb {
|
||||||
|
const WHITE_POINT: WhitePoint = Srgb::WHITE_POINT;
|
||||||
|
|
||||||
|
fn to_linear_light(from: &ColorComponents) -> ColorComponents {
|
||||||
|
Srgb::to_linear_light(&hwb_to_rgb(from))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_xyz(from: &ColorComponents) -> ColorComponents {
|
||||||
|
Srgb::to_xyz(from)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_xyz(from: &ColorComponents) -> ColorComponents {
|
||||||
|
Srgb::from_xyz(from)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_gamma_encoded(from: &ColorComponents) -> ColorComponents {
|
||||||
|
rgb_to_hwb(&Srgb::to_gamma_encoded(from))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The same as sRGB color space, except the transfer function is linear light.
|
/// The same as sRGB color space, except the transfer function is linear light.
|
||||||
/// https://drafts.csswg.org/csswg-drafts/css-color-4/#predefined-sRGB-linear
|
/// https://drafts.csswg.org/csswg-drafts/css-color-4/#predefined-sRGB-linear
|
||||||
pub struct SrgbLinear;
|
pub struct SrgbLinear;
|
||||||
|
|
|
@ -26,11 +26,6 @@ impl ColorComponents {
|
||||||
/// A color space representation in the CSS specification.
|
/// A color space representation in the CSS specification.
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-color-4/#typedef-color-space
|
/// https://drafts.csswg.org/css-color-4/#typedef-color-space
|
||||||
///
|
|
||||||
/// NOTE: Right now HSL and HWB colors can not be constructed by the user. They
|
|
||||||
/// are converted to RGB in the parser. The parser should return the
|
|
||||||
/// HSL/HWB values as is to avoid unnescessary conversions to/from RGB.
|
|
||||||
/// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1817035
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
Copy,
|
Copy,
|
||||||
|
@ -138,7 +133,15 @@ bitflags! {
|
||||||
pub struct SerializationFlags : u8 {
|
pub struct SerializationFlags : u8 {
|
||||||
/// If set, serializes sRGB colors into `color(srgb ...)` instead of
|
/// If set, serializes sRGB colors into `color(srgb ...)` instead of
|
||||||
/// `rgba(...)`.
|
/// `rgba(...)`.
|
||||||
const AS_COLOR_FUNCTION = 0x01;
|
const AS_COLOR_FUNCTION = 1 << 0;
|
||||||
|
/// Whether the 1st color component is `none`.
|
||||||
|
const C1_IS_NONE = 1 << 1;
|
||||||
|
/// Whether the 2nd color component is `none`.
|
||||||
|
const C2_IS_NONE = 1 << 2;
|
||||||
|
/// Whether the 3rd color component is `none`.
|
||||||
|
const C3_IS_NONE = 1 << 3;
|
||||||
|
/// Whether the alpha component is `none`.
|
||||||
|
const ALPHA_IS_NONE = 1 << 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,20 +262,69 @@ impl AbsoluteColor {
|
||||||
return self.clone();
|
return self.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have simplified conversions that do not need to convert to XYZ
|
||||||
|
// first. This improves performance, because it skips 2 matrix
|
||||||
|
// multiplications and reduces float rounding errors.
|
||||||
|
match (self.color_space, color_space) {
|
||||||
|
(Srgb, Hsl) => {
|
||||||
|
return Self::new(
|
||||||
|
color_space,
|
||||||
|
convert::rgb_to_hsl(&self.components),
|
||||||
|
self.alpha,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
(Srgb, Hwb) => {
|
||||||
|
return Self::new(
|
||||||
|
color_space,
|
||||||
|
convert::rgb_to_hwb(&self.components),
|
||||||
|
self.alpha,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
(Hsl, Srgb) => {
|
||||||
|
return Self::new(
|
||||||
|
color_space,
|
||||||
|
convert::hsl_to_rgb(&self.components),
|
||||||
|
self.alpha,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
(Hwb, Srgb) => {
|
||||||
|
return Self::new(
|
||||||
|
color_space,
|
||||||
|
convert::hwb_to_rgb(&self.components),
|
||||||
|
self.alpha,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
(Lab, Lch) | (Oklab, Oklch) => {
|
||||||
|
return Self::new(
|
||||||
|
color_space,
|
||||||
|
convert::lab_to_lch(&self.components),
|
||||||
|
self.alpha,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
(Lch, Lab) | (Oklch, Oklab) => {
|
||||||
|
return Self::new(
|
||||||
|
color_space,
|
||||||
|
convert::lch_to_lab(&self.components),
|
||||||
|
self.alpha,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
let (xyz, white_point) = match self.color_space {
|
let (xyz, white_point) = match self.color_space {
|
||||||
Hsl => {
|
|
||||||
let rgb = convert::hsl_to_rgb(&self.components);
|
|
||||||
convert::to_xyz::<convert::Srgb>(&rgb)
|
|
||||||
},
|
|
||||||
Hwb => {
|
|
||||||
let rgb = convert::hwb_to_rgb(&self.components);
|
|
||||||
convert::to_xyz::<convert::Srgb>(&rgb)
|
|
||||||
},
|
|
||||||
Lab => convert::to_xyz::<convert::Lab>(&self.components),
|
Lab => convert::to_xyz::<convert::Lab>(&self.components),
|
||||||
Lch => convert::to_xyz::<convert::Lch>(&self.components),
|
Lch => convert::to_xyz::<convert::Lch>(&self.components),
|
||||||
Oklab => convert::to_xyz::<convert::Oklab>(&self.components),
|
Oklab => convert::to_xyz::<convert::Oklab>(&self.components),
|
||||||
Oklch => convert::to_xyz::<convert::Oklch>(&self.components),
|
Oklch => convert::to_xyz::<convert::Oklch>(&self.components),
|
||||||
Srgb => convert::to_xyz::<convert::Srgb>(&self.components),
|
Srgb => convert::to_xyz::<convert::Srgb>(&self.components),
|
||||||
|
Hsl => convert::to_xyz::<convert::Hsl>(&self.components),
|
||||||
|
Hwb => convert::to_xyz::<convert::Hwb>(&self.components),
|
||||||
SrgbLinear => convert::to_xyz::<convert::SrgbLinear>(&self.components),
|
SrgbLinear => convert::to_xyz::<convert::SrgbLinear>(&self.components),
|
||||||
DisplayP3 => convert::to_xyz::<convert::DisplayP3>(&self.components),
|
DisplayP3 => convert::to_xyz::<convert::DisplayP3>(&self.components),
|
||||||
A98Rgb => convert::to_xyz::<convert::A98Rgb>(&self.components),
|
A98Rgb => convert::to_xyz::<convert::A98Rgb>(&self.components),
|
||||||
|
@ -283,19 +335,13 @@ impl AbsoluteColor {
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = match color_space {
|
let result = match color_space {
|
||||||
Hsl => {
|
|
||||||
let rgb = convert::from_xyz::<convert::Srgb>(&xyz, white_point);
|
|
||||||
convert::rgb_to_hsl(&rgb)
|
|
||||||
},
|
|
||||||
Hwb => {
|
|
||||||
let rgb = convert::from_xyz::<convert::Srgb>(&xyz, white_point);
|
|
||||||
convert::rgb_to_hwb(&rgb)
|
|
||||||
},
|
|
||||||
Lab => convert::from_xyz::<convert::Lab>(&xyz, white_point),
|
Lab => convert::from_xyz::<convert::Lab>(&xyz, white_point),
|
||||||
Lch => convert::from_xyz::<convert::Lch>(&xyz, white_point),
|
Lch => convert::from_xyz::<convert::Lch>(&xyz, white_point),
|
||||||
Oklab => convert::from_xyz::<convert::Oklab>(&xyz, white_point),
|
Oklab => convert::from_xyz::<convert::Oklab>(&xyz, white_point),
|
||||||
Oklch => convert::from_xyz::<convert::Oklch>(&xyz, white_point),
|
Oklch => convert::from_xyz::<convert::Oklch>(&xyz, white_point),
|
||||||
Srgb => convert::from_xyz::<convert::Srgb>(&xyz, white_point),
|
Srgb => convert::from_xyz::<convert::Srgb>(&xyz, white_point),
|
||||||
|
Hsl => convert::from_xyz::<convert::Hsl>(&xyz, white_point),
|
||||||
|
Hwb => convert::from_xyz::<convert::Hwb>(&xyz, white_point),
|
||||||
SrgbLinear => convert::from_xyz::<convert::SrgbLinear>(&xyz, white_point),
|
SrgbLinear => convert::from_xyz::<convert::SrgbLinear>(&xyz, white_point),
|
||||||
DisplayP3 => convert::from_xyz::<convert::DisplayP3>(&xyz, white_point),
|
DisplayP3 => convert::from_xyz::<convert::DisplayP3>(&xyz, white_point),
|
||||||
A98Rgb => convert::from_xyz::<convert::A98Rgb>(&xyz, white_point),
|
A98Rgb => convert::from_xyz::<convert::A98Rgb>(&xyz, white_point),
|
||||||
|
@ -329,6 +375,21 @@ impl ToCss for AbsoluteColor {
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
|
macro_rules! value_or_none {
|
||||||
|
($v:expr,$flag:tt) => {{
|
||||||
|
if self.flags.contains(SerializationFlags::$flag) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some($v)
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
let maybe_c1 = value_or_none!(self.components.0, C1_IS_NONE);
|
||||||
|
let maybe_c2 = value_or_none!(self.components.1, C2_IS_NONE);
|
||||||
|
let maybe_c3 = value_or_none!(self.components.2, C3_IS_NONE);
|
||||||
|
let maybe_alpha = value_or_none!(self.alpha, ALPHA_IS_NONE);
|
||||||
|
|
||||||
match self.color_space {
|
match self.color_space {
|
||||||
ColorSpace::Hsl => {
|
ColorSpace::Hsl => {
|
||||||
let rgb = convert::hsl_to_rgb(&self.components);
|
let rgb = convert::hsl_to_rgb(&self.components);
|
||||||
|
@ -342,30 +403,28 @@ impl ToCss for AbsoluteColor {
|
||||||
},
|
},
|
||||||
|
|
||||||
ColorSpace::Srgb if !self.flags.contains(SerializationFlags::AS_COLOR_FUNCTION) => {
|
ColorSpace::Srgb if !self.flags.contains(SerializationFlags::AS_COLOR_FUNCTION) => {
|
||||||
|
// Althought we are passing Option<_> in here, the to_css fn
|
||||||
|
// knows that the "none" keyword is not supported in the
|
||||||
|
// rgb/rgba legacy syntax.
|
||||||
cssparser::ToCss::to_css(
|
cssparser::ToCss::to_css(
|
||||||
&cssparser::RGBA::from_floats(
|
&cssparser::RGBA::from_floats(maybe_c1, maybe_c2, maybe_c3, maybe_alpha),
|
||||||
self.components.0,
|
|
||||||
self.components.1,
|
|
||||||
self.components.2,
|
|
||||||
self.alpha(),
|
|
||||||
),
|
|
||||||
dest,
|
dest,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
ColorSpace::Lab => cssparser::ToCss::to_css(
|
ColorSpace::Lab => cssparser::ToCss::to_css(
|
||||||
unsafe { color_components_as!(self, cssparser::Lab) },
|
&cssparser::Lab::new(maybe_c1, maybe_c2, maybe_c3, maybe_alpha),
|
||||||
dest,
|
dest,
|
||||||
),
|
),
|
||||||
ColorSpace::Lch => cssparser::ToCss::to_css(
|
ColorSpace::Lch => cssparser::ToCss::to_css(
|
||||||
unsafe { color_components_as!(self, cssparser::Lch) },
|
&cssparser::Lch::new(maybe_c1, maybe_c2, maybe_c3, maybe_alpha),
|
||||||
dest,
|
dest,
|
||||||
),
|
),
|
||||||
ColorSpace::Oklab => cssparser::ToCss::to_css(
|
ColorSpace::Oklab => cssparser::ToCss::to_css(
|
||||||
unsafe { color_components_as!(self, cssparser::Oklab) },
|
&cssparser::Oklab::new(maybe_c1, maybe_c2, maybe_c3, maybe_alpha),
|
||||||
dest,
|
dest,
|
||||||
),
|
),
|
||||||
ColorSpace::Oklch => cssparser::ToCss::to_css(
|
ColorSpace::Oklch => cssparser::ToCss::to_css(
|
||||||
unsafe { color_components_as!(self, cssparser::Oklch) },
|
&cssparser::Oklch::new(maybe_c1, maybe_c2, maybe_c3, maybe_alpha),
|
||||||
dest,
|
dest,
|
||||||
),
|
),
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -393,10 +452,10 @@ impl ToCss for AbsoluteColor {
|
||||||
|
|
||||||
let color_function = cssparser::ColorFunction {
|
let color_function = cssparser::ColorFunction {
|
||||||
color_space,
|
color_space,
|
||||||
c1: self.components.0,
|
c1: maybe_c1,
|
||||||
c2: self.components.1,
|
c2: maybe_c2,
|
||||||
c3: self.components.2,
|
c3: maybe_c3,
|
||||||
alpha: self.alpha,
|
alpha: maybe_alpha,
|
||||||
};
|
};
|
||||||
let color = cssparser::Color::ColorFunction(color_function);
|
let color = cssparser::Color::ColorFunction(color_function);
|
||||||
cssparser::ToCss::to_css(&color, dest)
|
cssparser::ToCss::to_css(&color, dest)
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::values::generics::color::{GenericCaretColor, GenericColorMix, Generic
|
||||||
use crate::values::specified::calc::CalcNode;
|
use crate::values::specified::calc::CalcNode;
|
||||||
use crate::values::specified::Percentage;
|
use crate::values::specified::Percentage;
|
||||||
use crate::values::CustomIdent;
|
use crate::values::CustomIdent;
|
||||||
use cssparser::{AngleOrNumber, Color as CSSParserColor, Parser, Token, RGBA};
|
use cssparser::{AngleOrNumber, Color as CSSParserColor, Parser, Token};
|
||||||
use cssparser::{BasicParseErrorKind, NumberOrPercentage, ParseErrorKind};
|
use cssparser::{BasicParseErrorKind, NumberOrPercentage, ParseErrorKind};
|
||||||
use itoa;
|
use itoa;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
@ -409,9 +409,35 @@ impl SystemColor {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new_absolute(color_space: ColorSpace, c1: f32, c2: f32, c3: f32, alpha: f32) -> Color {
|
fn new_absolute(
|
||||||
|
color_space: ColorSpace,
|
||||||
|
c1: Option<f32>,
|
||||||
|
c2: Option<f32>,
|
||||||
|
c3: Option<f32>,
|
||||||
|
alpha: Option<f32>,
|
||||||
|
) -> Color {
|
||||||
|
let mut flags = SerializationFlags::empty();
|
||||||
|
|
||||||
|
macro_rules! c {
|
||||||
|
($v:expr,$flag:tt) => {{
|
||||||
|
if let Some(value) = $v {
|
||||||
|
value
|
||||||
|
} else {
|
||||||
|
flags |= SerializationFlags::$flag;
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
let c1 = c!(c1, C1_IS_NONE);
|
||||||
|
let c2 = c!(c2, C2_IS_NONE);
|
||||||
|
let c3 = c!(c3, C3_IS_NONE);
|
||||||
|
let alpha = c!(alpha, ALPHA_IS_NONE);
|
||||||
|
|
||||||
|
let mut color = AbsoluteColor::new(color_space, ColorComponents(c1, c2, c3), alpha);
|
||||||
|
color.flags |= flags;
|
||||||
Color::Absolute(Box::new(Absolute {
|
Color::Absolute(Box::new(Absolute {
|
||||||
color: AbsoluteColor::new(color_space, ColorComponents(c1, c2, c3), alpha),
|
color,
|
||||||
authored: None,
|
authored: None,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -421,38 +447,76 @@ impl cssparser::FromParsedColor for Color {
|
||||||
Color::CurrentColor
|
Color::CurrentColor
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_rgba(red: u8, green: u8, blue: u8, alpha: f32) -> Self {
|
fn from_rgba(red: Option<u8>, green: Option<u8>, blue: Option<u8>, alpha: Option<f32>) -> Self {
|
||||||
new_absolute(
|
new_absolute(
|
||||||
ColorSpace::Srgb,
|
ColorSpace::Srgb,
|
||||||
red as f32 / 255.0,
|
red.map(|r| r as f32 / 255.0),
|
||||||
green as f32 / 255.0,
|
green.map(|g| g as f32 / 255.0),
|
||||||
blue as f32 / 255.0,
|
blue.map(|b| b as f32 / 255.0),
|
||||||
alpha,
|
alpha,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_lab(lightness: f32, a: f32, b: f32, alpha: f32) -> Self {
|
fn from_hsl(
|
||||||
|
hue: Option<f32>,
|
||||||
|
saturation: Option<f32>,
|
||||||
|
lightness: Option<f32>,
|
||||||
|
alpha: Option<f32>,
|
||||||
|
) -> Self {
|
||||||
|
new_absolute(ColorSpace::Hsl, hue, saturation, lightness, alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_hwb(
|
||||||
|
hue: Option<f32>,
|
||||||
|
whiteness: Option<f32>,
|
||||||
|
blackness: Option<f32>,
|
||||||
|
alpha: Option<f32>,
|
||||||
|
) -> Self {
|
||||||
|
new_absolute(ColorSpace::Hwb, hue, whiteness, blackness, alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_lab(
|
||||||
|
lightness: Option<f32>,
|
||||||
|
a: Option<f32>,
|
||||||
|
b: Option<f32>,
|
||||||
|
alpha: Option<f32>,
|
||||||
|
) -> Self {
|
||||||
new_absolute(ColorSpace::Lab, lightness, a, b, alpha)
|
new_absolute(ColorSpace::Lab, lightness, a, b, alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_lch(lightness: f32, chroma: f32, hue: f32, alpha: f32) -> Self {
|
fn from_lch(
|
||||||
|
lightness: Option<f32>,
|
||||||
|
chroma: Option<f32>,
|
||||||
|
hue: Option<f32>,
|
||||||
|
alpha: Option<f32>,
|
||||||
|
) -> Self {
|
||||||
new_absolute(ColorSpace::Lch, lightness, chroma, hue, alpha)
|
new_absolute(ColorSpace::Lch, lightness, chroma, hue, alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_oklab(lightness: f32, a: f32, b: f32, alpha: f32) -> Self {
|
fn from_oklab(
|
||||||
|
lightness: Option<f32>,
|
||||||
|
a: Option<f32>,
|
||||||
|
b: Option<f32>,
|
||||||
|
alpha: Option<f32>,
|
||||||
|
) -> Self {
|
||||||
new_absolute(ColorSpace::Oklab, lightness, a, b, alpha)
|
new_absolute(ColorSpace::Oklab, lightness, a, b, alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_oklch(lightness: f32, chroma: f32, hue: f32, alpha: f32) -> Self {
|
fn from_oklch(
|
||||||
|
lightness: Option<f32>,
|
||||||
|
chroma: Option<f32>,
|
||||||
|
hue: Option<f32>,
|
||||||
|
alpha: Option<f32>,
|
||||||
|
) -> Self {
|
||||||
new_absolute(ColorSpace::Oklch, lightness, chroma, hue, alpha)
|
new_absolute(ColorSpace::Oklch, lightness, chroma, hue, alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_color_function(
|
fn from_color_function(
|
||||||
color_space: cssparser::PredefinedColorSpace,
|
color_space: cssparser::PredefinedColorSpace,
|
||||||
c1: f32,
|
c1: Option<f32>,
|
||||||
c2: f32,
|
c2: Option<f32>,
|
||||||
c3: f32,
|
c3: Option<f32>,
|
||||||
alpha: f32,
|
alpha: Option<f32>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut result = new_absolute(color_space.into(), c1, c2, c3, alpha);
|
let mut result = new_absolute(color_space.into(), c1, c2, c3, alpha);
|
||||||
if let Color::Absolute(ref mut absolute) = result {
|
if let Color::Absolute(ref mut absolute) = result {
|
||||||
|
@ -569,14 +633,17 @@ impl Color {
|
||||||
Ok(mut color) => {
|
Ok(mut color) => {
|
||||||
if let Color::Absolute(ref mut absolute) = color {
|
if let Color::Absolute(ref mut absolute) = color {
|
||||||
let enabled = {
|
let enabled = {
|
||||||
let is_srgb = matches!(absolute.color.color_space, ColorSpace::Srgb);
|
let is_legacy_color = matches!(
|
||||||
|
absolute.color.color_space,
|
||||||
|
ColorSpace::Srgb | ColorSpace::Hsl
|
||||||
|
);
|
||||||
let is_color_function = absolute
|
let is_color_function = absolute
|
||||||
.color
|
.color
|
||||||
.flags
|
.flags
|
||||||
.contains(SerializationFlags::AS_COLOR_FUNCTION);
|
.contains(SerializationFlags::AS_COLOR_FUNCTION);
|
||||||
let pref_enabled = allow_more_color_4();
|
let pref_enabled = allow_more_color_4();
|
||||||
|
|
||||||
(is_srgb && !is_color_function) || pref_enabled
|
(is_legacy_color && !is_color_function) || pref_enabled
|
||||||
};
|
};
|
||||||
if !enabled {
|
if !enabled {
|
||||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
|
@ -731,23 +798,14 @@ impl Color {
|
||||||
if !allow_quirks.allowed(context.quirks_mode) {
|
if !allow_quirks.allowed(context.quirks_mode) {
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
Color::parse_quirky_color(input)
|
Color::parse_quirky_color(input).map_err(|_| e)
|
||||||
.map(|rgba| {
|
|
||||||
Color::from_absolute_color(AbsoluteColor::srgb(
|
|
||||||
rgba.red as f32 / 255.0,
|
|
||||||
rgba.green as f32 / 255.0,
|
|
||||||
rgba.blue as f32 / 255.0,
|
|
||||||
rgba.alpha, // alpha value is already a float and in range [0..1]
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.map_err(|_| e)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a <quirky-color> value.
|
/// Parse a <quirky-color> value.
|
||||||
///
|
///
|
||||||
/// <https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk>
|
/// <https://quirks.spec.whatwg.org/#the-hashless-hex-color-quirk>
|
||||||
fn parse_quirky_color<'i, 't>(input: &mut Parser<'i, 't>) -> Result<RGBA, ParseError<'i>> {
|
fn parse_quirky_color<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
let (value, unit) = match *input.next()? {
|
let (value, unit) = match *input.next()? {
|
||||||
Token::Number {
|
Token::Number {
|
||||||
|
@ -763,7 +821,7 @@ impl Color {
|
||||||
if ident.len() != 3 && ident.len() != 6 {
|
if ident.len() != 3 && ident.len() != 6 {
|
||||||
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
}
|
}
|
||||||
return RGBA::parse_hash(ident.as_bytes()).map_err(|()| {
|
return cssparser::parse_hash_color(ident.as_bytes()).map_err(|()| {
|
||||||
location.new_custom_error(StyleParseErrorKind::UnspecifiedError)
|
location.new_custom_error(StyleParseErrorKind::UnspecifiedError)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -808,7 +866,7 @@ impl Color {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
debug_assert_eq!(written, 6);
|
debug_assert_eq!(written, 6);
|
||||||
RGBA::parse_hash(&serialization)
|
cssparser::parse_hash_color(&serialization)
|
||||||
.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue