Backed out changeset 218b12b92ccb (bug 1352757) for causing failures on test_transitions_per_property.html.

This commit is contained in:
Cosmin Sabou 2023-01-19 19:34:50 +02:00
parent edd09f1f0f
commit c5cbcf0a2e
69 changed files with 930 additions and 1384 deletions

View File

@ -20,11 +20,6 @@ git = "https://github.com/chris-zen/coremidi.git"
rev = "fc68464b5445caf111e41f643a2e69ccce0b4f83"
replace-with = "vendored-sources"
[source."https://github.com/servo/rust-cssparser"]
git = "https://github.com/servo/rust-cssparser"
replace-with = "vendored-sources"
rev = "722b30d2f1634714befab967ecae627813fa4cf0"
[source."https://github.com/gfx-rs/naga"]
git = "https://github.com/gfx-rs/naga"
rev = "e7fc8e6"

8
Cargo.lock generated
View File

@ -1101,8 +1101,9 @@ dependencies = [
[[package]]
name = "cssparser"
version = "0.30.0"
source = "git+https://github.com/servo/rust-cssparser?rev=722b30d2f1634714befab967ecae627813fa4cf0#722b30d2f1634714befab967ecae627813fa4cf0"
version = "0.29.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa"
dependencies = [
"cssparser-macros",
"dtoa-short",
@ -1118,7 +1119,8 @@ dependencies = [
[[package]]
name = "cssparser-macros"
version = "0.6.0"
source = "git+https://github.com/servo/rust-cssparser?rev=722b30d2f1634714befab967ecae627813fa4cf0#722b30d2f1634714befab967ecae627813fa4cf0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e"
dependencies = [
"quote",
"syn",

View File

@ -161,8 +161,6 @@ minidump-writer = { git = "https://github.com/rust-minidump/minidump-writer.git"
# warp 0.3.3 + https://github.com/seanmonstar/warp/pull/1007
warp = { git = "https://github.com/glandium/warp", rev = "4af45fae95bc98b0eba1ef0db17e1dac471bb23d" }
cssparser = { git = "https://github.com/servo/rust-cssparser", rev = "722b30d2f1634714befab967ecae627813fa4cf0" }
# application-services overrides to make updating them all simpler.
interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "51b984ecb21ba00694c3eee33364123a064a7cbb" }
sql-support = { git = "https://github.com/mozilla/application-services", rev = "51b984ecb21ba00694c3eee33364123a064a7cbb" }

View File

@ -16,8 +16,8 @@ namespace mozilla {
template <>
bool StyleColor::MaybeTransparent() const {
// We know that the color is opaque when it's a numeric color with
// alpha == 1.0.
return !IsNumeric() || AsNumeric().alpha != 1.0f;
// alpha == 255.
return !IsNumeric() || AsNumeric().alpha != 255;
}
template <>

View File

@ -11,17 +11,16 @@
#include "nsColor.h"
#include "mozilla/ServoStyleConsts.h"
#include "nsStyleUtil.h"
namespace mozilla {
inline StyleRGBA StyleRGBA::FromColor(nscolor aColor) {
return {NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor),
NS_GET_A(aColor) / 255.0f};
NS_GET_A(aColor)};
}
inline nscolor StyleRGBA::ToColor() const {
return NS_RGBA(red, green, blue, nsStyleUtil::FloatToColorComponent(alpha));
return NS_RGBA(red, green, blue, alpha);
}
inline StyleRGBA StyleRGBA::Transparent() { return {0, 0, 0, 0}; }

View File

@ -8736,13 +8736,6 @@
value: true
mirror: always
# Enable experimental enhanced color CSS color spaces. (lab(), lch(), oklab(), oklch(), color())
- name: layout.css.more_color_4.enabled
type: RelaxedAtomicBool
value: false
mirror: always
rust: true
# The margin used for detecting relevancy for `content-visibility: auto`.
- name: layout.css.content-visibility-relevant-content-margin
type: float

View File

@ -31,7 +31,7 @@ accountable-refcell = { version = "0.2.0", optional = true }
app_units = "0.7"
content-security-policy = { version = "0.4.0", features = ["serde"], optional = true }
crossbeam-channel = { version = "0.4", optional = true }
cssparser = "0.30"
cssparser = "0.29"
dom = { path = "../../../dom/base/rust" }
euclid = "0.22"
hyper = { version = "0.12", optional = true }

View File

@ -20,7 +20,7 @@ bench = []
[dependencies]
bitflags = "1.0"
matches = "0.1"
cssparser = "0.30"
cssparser = "0.29"
derive_more = { version = "0.99", default-features = false, features = ["add", "add_assign"] }
fxhash = "0.2"
log = "0.4"

View File

@ -32,7 +32,7 @@ arrayvec = "0.7"
atomic_refcell = "0.1"
bitflags = "1.0"
byteorder = "1.0"
cssparser = "0.30"
cssparser = "0.29"
derive_more = { version = "0.99", default-features = false, features = ["add", "add_assign", "deref", "from"] }
dom = { path = "../../../dom/base/rust" }
new_debug_unreachable = "1.0"

View File

@ -18,18 +18,20 @@ use std::cmp::max;
/// Convert a given RGBA value to `nscolor`.
pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 {
u32::from_le_bytes([
rgba.red,
rgba.green,
rgba.blue,
(rgba.alpha * 255.0).round() as u8,
])
((rgba.alpha as u32) << 24) |
((rgba.blue as u32) << 16) |
((rgba.green as u32) << 8) |
(rgba.red as u32)
}
/// Convert a given `nscolor` to a Servo RGBA value.
pub fn convert_nscolor_to_rgba(color: u32) -> RGBA {
let [r, g, b, a] = color.to_le_bytes();
RGBA::new(r, g, b, a as f32 / 255.0)
RGBA::new(
(color & 0xff) as u8,
(color >> 8 & 0xff) as u8,
(color >> 16 & 0xff) as u8,
(color >> 24 & 0xff) as u8,
)
}
/// Round `width` down to the nearest device pixel, but any non-zero value that

View File

@ -434,11 +434,9 @@ fn tweak_when_ignoring_colors(
return;
}
fn alpha_channel(color: &Color, context: &computed::Context) -> f32 {
fn alpha_channel(color: &Color, context: &computed::Context) -> u8 {
// We assume here currentColor is opaque.
let color = color
.to_computed_value(context)
.into_rgba(RGBA::new(0, 0, 0, 1.0));
let color = color.to_computed_value(context).into_rgba(RGBA::new(0, 0, 0, 255));
color.alpha
}
@ -461,7 +459,7 @@ fn tweak_when_ignoring_colors(
// otherwise, this is needed to preserve semi-transparent
// backgrounds.
let alpha = alpha_channel(color, context);
if alpha == 0.0 {
if alpha == 0 {
return;
}
let mut color = context.builder.device.default_background_color();
@ -477,7 +475,7 @@ fn tweak_when_ignoring_colors(
// If the inherited color would be transparent, but we would
// override this with a non-transparent color, then override it with
// the default color. Otherwise just let it inherit through.
if context.builder.get_parent_inherited_text().clone_color().alpha == 0.0 {
if context.builder.get_parent_inherited_text().clone_color().alpha == 0 {
let color = context.builder.device.default_color();
declarations_to_apply_unless_overriden.push(PropertyDeclaration::Color(
specified::ColorPropertyValue(color.into()),

View File

@ -9,7 +9,7 @@
${helpers.predefined_type(
"color",
"ColorPropertyValue",
"::cssparser::RGBA::new(0, 0, 0, 1.0)",
"::cssparser::RGBA::new(0, 0, 0, 255)",
engines="gecko servo-2013 servo-2020",
animation_value_type="AnimatedRGBA",
ignored_when_colors_disabled="True",

View File

@ -78,6 +78,7 @@ ${helpers.predefined_type(
engines="gecko",
spec="https://drafts.csswg.org/css-ui/#caret-color",
animation_value_type="CaretColor",
boxed=True,
ignored_when_colors_disabled=True,
)}
@ -89,6 +90,7 @@ ${helpers.predefined_type(
spec="https://drafts.csswg.org/css-ui-4/#widget-accent",
gecko_pref="layout.css.accent-color.enabled",
animation_value_type="ColorOrAuto",
boxed=True,
ignored_when_colors_disabled=True,
has_effect_on_gecko_scrollbars=False,
)}

View File

@ -44,8 +44,8 @@ impl Parse for FontPaletteOverrideColor {
let location = input.current_source_location();
let color = SpecifiedColor::parse(context, input)?;
// Only absolute colors are accepted here.
if let SpecifiedColor::Absolute { .. } = color {
Ok(FontPaletteOverrideColor { index, color })
if let SpecifiedColor::Numeric { parsed: _, authored: _ } = color {
Ok(FontPaletteOverrideColor{ index, color })
} else {
Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
@ -179,10 +179,11 @@ impl FontPaletteValuesRule {
}
}
for c in &self.override_colors {
if let SpecifiedColor::Absolute(ref absolute) = c.color {
let rgba = absolute.color.to_rgba();
if let SpecifiedColor::Numeric { parsed, authored: _ } = &c.color {
unsafe {
Gecko_SetFontPaletteOverride(palette_values, c.index.0.value(), rgba);
Gecko_SetFontPaletteOverride(palette_values,
c.index.0.value(),
*parsed);
}
}
}

View File

@ -168,13 +168,6 @@ impl Color {
rgba.alpha *= alpha_multiplier;
}
// FIXME: In rare cases we end up with 0.999995 in the alpha channel,
// so we reduce the precision to avoid serializing to
// rgba(?, ?, ?, 1). This is not ideal, so we should look into
// ways to avoid it. Maybe pre-multiply all color components and
// then divide after calculations?
rgba.alpha = (rgba.alpha * 1000.0).round() / 1000.0;
rgba
}
}
@ -431,56 +424,29 @@ struct XYZD50A {
impl_lerp!(XYZD50A, None);
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct LABA {
pub lightness: f32,
pub a: f32,
pub b: f32,
pub alpha: f32,
struct LABA {
lightness: f32,
a: f32,
b: f32,
alpha: f32,
}
impl_lerp!(LABA, None);
/// An animated LCHA colour.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct LCHA {
pub lightness: f32,
pub chroma: f32,
pub hue: f32,
pub alpha: f32,
struct LCHA {
lightness: f32,
chroma: f32,
hue: f32,
alpha: f32,
}
impl_lerp!(LCHA, Some(2));
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct OKLABA {
pub lightness: f32,
pub a: f32,
pub b: f32,
pub alpha: f32,
}
impl_lerp!(OKLABA, None);
/// An animated OKLCHA colour.
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct OKLCHA {
pub lightness: f32,
pub chroma: f32,
pub hue: f32,
pub alpha: f32,
}
impl_lerp!(OKLCHA, Some(2));
/// An animated hwb() color.
#[derive(Clone, Copy, Debug)]
#[repr(C)]
@ -638,7 +604,6 @@ impl From<XYZD65A> for XYZD50A {
-0.05019222954313557, -0.01707382502938514, 0.7518742899580008, 0.,
0., 0., 0., 1.,
);
let d50 = BRADFORD.transform_vector3d(Vector3D::new(d65.x, d65.y, d65.z));
Self {
x: d50.x,
@ -782,22 +747,6 @@ impl From<LABA> for LCHA {
}
}
impl From<OKLABA> for OKLCHA {
/// Convert an OKLAB color to OKLCH as specified in [1].
///
/// [1]: https://drafts.csswg.org/css-color/#color-conversion-code
fn from(oklaba: OKLABA) -> Self {
let hue = oklaba.b.atan2(oklaba.a) * DEG_PER_RAD;
let chroma = (oklaba.a * oklaba.a + oklaba.b * oklaba.b).sqrt();
OKLCHA {
lightness: oklaba.lightness,
chroma,
hue,
alpha: oklaba.alpha,
}
}
}
impl From<LCHA> for LABA {
/// Convert a LCH color to LAB as specified in [1].
///
@ -815,23 +764,6 @@ impl From<LCHA> for LABA {
}
}
impl From<OKLCHA> for OKLABA {
/// Convert a OKLCH color to OKLAB as specified in [1].
///
/// [1]: https://drafts.csswg.org/css-color/#color-conversion-code
fn from(oklcha: OKLCHA) -> Self {
let hue_radians = oklcha.hue * RAD_PER_DEG;
let a = oklcha.chroma * hue_radians.cos();
let b = oklcha.chroma * hue_radians.sin();
OKLABA {
lightness: oklcha.lightness,
a,
b,
alpha: oklcha.alpha,
}
}
}
impl From<LABA> for XYZD50A {
/// Convert a CIELAB color to XYZ as specified in [1] and [2].
///
@ -872,78 +804,6 @@ impl From<LABA> for XYZD50A {
}
}
impl From<XYZD65A> for OKLABA {
fn from(xyza: XYZD65A) -> Self {
// https://drafts.csswg.org/css-color-4/#color-conversion-code
#[cfg_attr(rustfmt, rustfmt_skip)]
const XYZ_TO_LMS: Transform3D<f32> = Transform3D::new(
0.8190224432164319, 0.0329836671980271, 0.048177199566046255, 0.,
0.3619062562801221, 0.9292868468965546, 0.26423952494422764, 0.,
-0.12887378261216414, 0.03614466816999844, 0.6335478258136937, 0.,
0., 0., 0., 1.,
);
#[cfg_attr(rustfmt, rustfmt_skip)]
const LMS_TO_OKLAB: Transform3D<f32> = Transform3D::new(
0.2104542553, 1.9779984951, 0.0259040371, 0.,
0.7936177850, -2.4285922050, 0.7827717662, 0.,
-0.0040720468, 0.4505937099, -0.8086757660, 0.,
0., 0., 0., 1.,
);
let lms = XYZ_TO_LMS.transform_vector3d(Vector3D::new(xyza.x, xyza.y, xyza.z));
let lab = LMS_TO_OKLAB.transform_vector3d(Vector3D::new(
lms.x.cbrt(),
lms.y.cbrt(),
lms.z.cbrt(),
));
Self {
lightness: lab.x,
a: lab.y,
b: lab.z,
alpha: xyza.alpha,
}
}
}
impl From<OKLABA> for XYZD65A {
fn from(oklaba: OKLABA) -> Self {
// https://drafts.csswg.org/css-color-4/#color-conversion-code
// Given OKLab, convert to XYZ relative to D65
#[cfg_attr(rustfmt, rustfmt_skip)]
const LMS_TO_XYZ: Transform3D<f32> = Transform3D::new(
1.2268798733741557, -0.04057576262431372, -0.07637294974672142, 0.,
-0.5578149965554813, 1.1122868293970594, -0.4214933239627914, 0.,
0.28139105017721583, -0.07171106666151701, 1.5869240244272418, 0.,
0., 0., 0., 1.,
);
#[cfg_attr(rustfmt, rustfmt_skip)]
const OKLAB_TO_LMS: Transform3D<f32> = Transform3D::new(
0.99999999845051981432, 1.0000000088817607767, 1.0000000546724109177, 0.,
0.39633779217376785678, -0.1055613423236563494, -0.089484182094965759684, 0.,
0.21580375806075880339, -0.063854174771705903402, -1.2914855378640917399, 0.,
0., 0., 0., 1.,
);
let lms =
OKLAB_TO_LMS.transform_vector3d(Vector3D::new(oklaba.lightness, oklaba.a, oklaba.b));
let xyz = LMS_TO_XYZ.transform_vector3d(Vector3D::new(
lms.x.powf(3.0),
lms.y.powf(3.0),
lms.z.powf(3.0),
));
Self {
x: xyz.x,
y: xyz.y,
z: xyz.z,
alpha: oklaba.alpha,
}
}
}
impl From<XYZD50A> for RGBA {
fn from(d50: XYZD50A) -> Self {
Self::from(XYZD65A::from(d50))
@ -968,18 +828,6 @@ impl From<LABA> for RGBA {
}
}
impl From<OKLABA> for RGBA {
fn from(oklaba: OKLABA) -> Self {
Self::from(XYZD65A::from(oklaba))
}
}
impl From<RGBA> for OKLABA {
fn from(rgba: RGBA) -> Self {
Self::from(XYZD65A::from(rgba))
}
}
impl From<RGBA> for LCHA {
fn from(rgba: RGBA) -> Self {
Self::from(LABA::from(rgba))
@ -991,15 +839,3 @@ impl From<LCHA> for RGBA {
Self::from(LABA::from(lcha))
}
}
impl From<OKLCHA> for RGBA {
fn from(oklcha: OKLCHA) -> Self {
Self::from(OKLABA::from(oklcha))
}
}
impl From<RGBA> for OKLCHA {
fn from(rgba: RGBA) -> Self {
Self::from(OKLABA::from(rgba))
}
}

View File

@ -30,7 +30,7 @@ impl ToCss for Color {
{
match *self {
Self::Numeric(ref c) => c.to_css(dest),
Self::CurrentColor => cssparser::ToCss::to_css(&CSSParserColor::CurrentColor, dest),
Self::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
Self::ColorMix(ref m) => m.to_css(dest),
}
}
@ -44,12 +44,12 @@ impl Color {
/// Returns opaque black.
pub fn black() -> Color {
Color::rgba(RGBA::new(0, 0, 0, 1.0))
Color::rgba(RGBA::new(0, 0, 0, 255))
}
/// Returns opaque white.
pub fn white() -> Color {
Color::rgba(RGBA::new(255, 255, 255, 1.0))
Color::rgba(RGBA::new(255, 255, 255, 255))
}
/// Combine this complex color with the given foreground color into

View File

@ -90,291 +90,18 @@ impl ColorMix {
}
}
/// A color space representation in the CSS specification.
///
/// https://w3c.github.io/csswg-drafts/css-color-4/#color-type
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem)]
#[repr(u8)]
pub enum ColorSpace {
/// A color specified in the Lab color format, e.g.
/// "lab(29.2345% 39.3825 20.0664)".
/// https://w3c.github.io/csswg-drafts/css-color-4/#lab-colors
Lab,
/// A color specified in the Lch color format, e.g.
/// "lch(29.2345% 44.2 27)".
/// https://w3c.github.io/csswg-drafts/css-color-4/#lch-colors
Lch,
/// A color specified in the Oklab color format, e.g.
/// "oklab(40.101% 0.1147 0.0453)".
/// https://w3c.github.io/csswg-drafts/css-color-4/#lab-colors
Oklab,
/// A color specified in the Oklch color format, e.g.
/// "oklch(40.101% 0.12332 21.555)".
/// https://w3c.github.io/csswg-drafts/css-color-4/#lch-colors
Oklch,
/// A color specified with the color(..) function and the "srgb" color
/// space, e.g. "color(srgb 0.691 0.139 0.259)".
Srgb,
/// A color specified with the color(..) function and the "srgb-linear"
/// color space, e.g. "color(srgb-linear 0.435 0.017 0.055)".
SrgbLinear,
/// A color specified with the color(..) function and the "display-p3"
/// color space, e.g. "color(display-p3 0.84 0.19 0.72)".
DisplayP3,
/// A color specified with the color(..) function and the "a98-rgb" color
/// space, e.g. "color(a98-rgb 0.44091 0.49971 0.37408)".
A98Rgb,
/// A color specified with the color(..) function and the "prophoto-rgb"
/// color space, e.g. "color(prophoto-rgb 0.36589 0.41717 0.31333)".
ProphotoRgb,
/// A color specified with the color(..) function and the "rec2020" color
/// space, e.g. "color(rec2020 0.42210 0.47580 0.35605)".
Rec2020,
/// A color specified with the color(..) function and the "xyz-d50" color
/// space, e.g. "color(xyz-d50 0.2005 0.14089 0.4472)".
XyzD50,
/// A color specified with the color(..) function and the "xyz-d65" or "xyz"
/// color space, e.g. "color(xyz-d65 0.21661 0.14602 0.59452)".
XyzD65,
}
bitflags! {
#[derive(Default, MallocSizeOf, ToShmem)]
#[repr(C)]
struct SerializationFlags : u8 {
const AS_COLOR_FUNCTION = 0x01;
}
}
/// The 3 components that make up a color. (Does not include the alpha component)
#[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
struct ColorComponents(f32, f32, f32);
/// An absolutely specified color, using either rgb(), rgba(), lab(), lch(),
/// oklab(), oklch() or color().
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
#[repr(C)]
pub struct AbsoluteColor {
components: ColorComponents,
alpha: f32,
color_space: ColorSpace,
flags: SerializationFlags,
}
macro_rules! color_components_as {
($c:expr, $t:ty) => {{
// This macro is not an inline function, because we can't use the
// generic type ($t) in a constant expression as per:
// https://github.com/rust-lang/rust/issues/76560
const_assert_eq!(std::mem::size_of::<$t>(), std::mem::size_of::<[f32; 4]>());
const_assert_eq!(std::mem::align_of::<$t>(), std::mem::align_of::<[f32; 4]>());
const_assert!(std::mem::size_of::<AbsoluteColor>() >= std::mem::size_of::<$t>());
const_assert_eq!(
std::mem::align_of::<AbsoluteColor>(),
std::mem::align_of::<$t>()
);
std::mem::transmute::<&ColorComponents, &$t>(&$c.components)
}};
}
impl AbsoluteColor {
/// Create a new [AbsoluteColor] with the given [ColorSpace] and components.
pub fn new(color_space: ColorSpace, c1: f32, c2: f32, c3: f32, alpha: f32) -> Self {
Self {
components: ColorComponents(c1, c2, c3),
alpha,
color_space,
flags: SerializationFlags::empty(),
}
}
/// Convenience function to create a color in the sRGB color space.
pub fn from_rgba(rgba: RGBA) -> Self {
let red = rgba.red as f32 / 255.0;
let green = rgba.green as f32 / 255.0;
let blue = rgba.blue as f32 / 255.0;
Self::new(ColorSpace::Srgb, red, green, blue, rgba.alpha)
}
/// Return the alpha component.
#[inline]
pub fn alpha(&self) -> f32 {
self.alpha
}
/// Convert the color to sRGB color space and return it in the RGBA struct.
pub fn to_rgba(&self) -> RGBA {
let rgba = self.to_color_space(ColorSpace::Srgb);
let red = (rgba.components.0 * 255.0).round() as u8;
let green = (rgba.components.1 * 255.0).round() as u8;
let blue = (rgba.components.2 * 255.0).round() as u8;
RGBA::new(red, green, blue, rgba.alpha)
}
/// Convert this color to the specified color space.
pub fn to_color_space(&self, color_space: ColorSpace) -> Self {
use crate::values::animated::color::{AnimatedRGBA, LABA, LCHA, OKLABA, OKLCHA};
use ColorSpace::*;
if self.color_space == color_space {
return self.clone();
}
match (self.color_space, color_space) {
(Lab, Srgb) => {
let laba = unsafe { color_components_as!(self, LABA) };
let rgba = AnimatedRGBA::from(*laba);
Self::new(Srgb, rgba.red, rgba.green, rgba.blue, rgba.alpha)
},
(Oklab, Srgb) => {
let oklaba: &OKLABA = unsafe { color_components_as!(self, OKLABA) };
let rgba = AnimatedRGBA::from(*oklaba);
Self::new(Srgb, rgba.red, rgba.green, rgba.blue, rgba.alpha)
},
(Lch, Srgb) => {
let lcha: &LCHA = unsafe { color_components_as!(self, LCHA) };
let rgba = AnimatedRGBA::from(*lcha);
Self::new(Srgb, rgba.red, rgba.green, rgba.blue, rgba.alpha)
},
(Oklch, Srgb) => {
let oklcha: &OKLCHA = unsafe { color_components_as!(self, OKLCHA) };
let rgba = AnimatedRGBA::from(*oklcha);
Self::new(Srgb, rgba.red, rgba.green, rgba.blue, rgba.alpha)
},
_ => {
// Conversion to other color spaces is not implemented yet.
log::warn!(
"Can not convert from {:?} to {:?}!",
self.color_space,
color_space
);
Self::from_rgba(RGBA::new(0, 0, 0, 1.0))
},
}
}
}
impl From<cssparser::AbsoluteColor> for AbsoluteColor {
fn from(f: cssparser::AbsoluteColor) -> Self {
match f {
cssparser::AbsoluteColor::Rgba(rgba) => Self::from_rgba(rgba),
cssparser::AbsoluteColor::Lab(lab) => {
Self::new(ColorSpace::Lab, lab.lightness, lab.a, lab.b, lab.alpha)
},
cssparser::AbsoluteColor::Lch(lch) => Self::new(
ColorSpace::Lch,
lch.lightness,
lch.chroma,
lch.hue,
lch.alpha,
),
cssparser::AbsoluteColor::Oklab(oklab) => Self::new(
ColorSpace::Oklab,
oklab.lightness,
oklab.a,
oklab.b,
oklab.alpha,
),
cssparser::AbsoluteColor::Oklch(oklch) => Self::new(
ColorSpace::Oklch,
oklch.lightness,
oklch.chroma,
oklch.hue,
oklch.alpha,
),
}
}
}
impl ToCss for AbsoluteColor {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
match self.color_space {
ColorSpace::Srgb if !self.flags.contains(SerializationFlags::AS_COLOR_FUNCTION) => {
cssparser::ToCss::to_css(
&cssparser::RGBA::from_floats(
self.components.0,
self.components.1,
self.components.2,
self.alpha(),
),
dest,
)
},
ColorSpace::Lab => cssparser::ToCss::to_css(
unsafe { color_components_as!(self, cssparser::Lab) },
dest,
),
ColorSpace::Lch => cssparser::ToCss::to_css(
unsafe { color_components_as!(self, cssparser::Lch) },
dest,
),
ColorSpace::Oklab => cssparser::ToCss::to_css(
unsafe { color_components_as!(self, cssparser::Oklab) },
dest,
),
ColorSpace::Oklch => cssparser::ToCss::to_css(
unsafe { color_components_as!(self, cssparser::Oklch) },
dest,
),
// Other color spaces are not implemented yet. See:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1128204
ColorSpace::Srgb |
ColorSpace::SrgbLinear |
ColorSpace::DisplayP3 |
ColorSpace::A98Rgb |
ColorSpace::ProphotoRgb |
ColorSpace::Rec2020 |
ColorSpace::XyzD50 |
ColorSpace::XyzD65 => todo!(),
}
}
}
/// Container holding an absolute color and the text specified by an author.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
pub struct Absolute {
/// The specified color.
pub color: AbsoluteColor,
/// Authored representation.
pub authored: Option<Box<str>>,
}
impl ToCss for Absolute {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if let Some(ref authored) = self.authored {
dest.write_str(authored)
} else {
self.color.to_css(dest)
}
}
}
/// Specified color value
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToShmem)]
pub enum Color {
/// The 'currentColor' keyword
CurrentColor,
/// An absolute color.
/// https://w3c.github.io/csswg-drafts/css-color-4/#typedef-absolute-color-function
Absolute(Box<Absolute>),
/// A specific RGBA color
Numeric {
/// Parsed RGBA color
parsed: RGBA,
/// Authored representation
authored: Option<Box<str>>,
},
/// A system color.
#[cfg(feature = "gecko")]
System(SystemColor),
@ -742,24 +469,16 @@ impl Color {
let authored = input.expect_ident_cloned().ok();
input.reset(&start);
authored
},
}
};
let compontent_parser = ColorComponentParser(&*context);
match input.try_parse(|i| CSSParserColor::parse_with(&compontent_parser, i)) {
Ok(value) => Ok(match value {
CSSParserColor::CurrentColor => Color::CurrentColor,
CSSParserColor::Absolute(absolute) => {
let enabled = matches!(absolute, cssparser::AbsoluteColor::Rgba(_)) ||
static_prefs::pref!("layout.css.more_color_4.enabled");
if !enabled {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Color::Absolute(Box::new(Absolute {
color: absolute.into(),
authored: authored.map(|s| s.to_ascii_lowercase().into_boxed_str()),
}))
CSSParserColor::RGBA(rgba) => Color::Numeric {
parsed: rgba,
authored: authored.map(|s| s.to_ascii_lowercase().into_boxed_str()),
},
}),
Err(e) => {
@ -770,8 +489,7 @@ impl Color {
}
}
if let Ok(mix) = input.try_parse(|i| ColorMix::parse(context, i, preserve_authored))
{
if let Ok(mix) = input.try_parse(|i| ColorMix::parse(context, i, preserve_authored)) {
return Ok(Color::ColorMix(Box::new(mix)));
}
@ -789,9 +507,7 @@ impl Color {
/// Returns whether a given color is valid for authors.
pub fn is_valid(context: &ParserContext, input: &mut Parser) -> bool {
input
.parse_entirely(|input| Self::parse_internal(context, input, PreserveAuthored::No))
.is_ok()
input.parse_entirely(|input| Self::parse_internal(context, input, PreserveAuthored::No)).is_ok()
}
/// Tries to parse a color and compute it with a given device.
@ -802,8 +518,9 @@ impl Color {
) -> Option<ComputedColor> {
use crate::error_reporting::ContextualParseError;
let start = input.position();
let result = input
.parse_entirely(|input| Self::parse_internal(context, input, PreserveAuthored::No));
let result = input.parse_entirely(|input| {
Self::parse_internal(context, input, PreserveAuthored::No)
});
let specified = match result {
Ok(s) => s,
@ -820,11 +537,14 @@ impl Color {
// default and not available on OffscreenCanvas anyways...
if let ParseErrorKind::Custom(StyleParseErrorKind::ValueError(..)) = e.kind {
let location = e.location.clone();
let error = ContextualParseError::UnsupportedValue(input.slice_from(start), e);
let error = ContextualParseError::UnsupportedValue(
input.slice_from(start),
e,
);
context.log_css_error(location, error);
}
return None;
},
}
};
match device {
@ -844,8 +564,14 @@ impl ToCss for Color {
W: Write,
{
match *self {
Color::CurrentColor => cssparser::ToCss::to_css(&CSSParserColor::CurrentColor, dest),
Color::Absolute(ref absolute) => absolute.to_css(dest),
Color::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
Color::Numeric {
authored: Some(ref authored),
..
} => dest.write_str(authored),
Color::Numeric {
parsed: ref rgba, ..
} => rgba.to_css(dest),
Color::ColorMix(ref mix) => mix.to_css(dest),
#[cfg(feature = "gecko")]
Color::System(system) => system.to_css(dest),
@ -855,13 +581,25 @@ impl ToCss for Color {
}
}
/// A wrapper of cssparser::Color::parse_hash.
///
/// That function should never return CurrentColor, so it makes no sense to
/// handle a cssparser::Color here. This should really be done in cssparser
/// directly rather than here.
fn parse_hash_color(value: &[u8]) -> Result<RGBA, ()> {
CSSParserColor::parse_hash(value).map(|color| match color {
CSSParserColor::RGBA(rgba) => rgba,
CSSParserColor::CurrentColor => unreachable!("parse_hash should never return currentcolor"),
})
}
impl Color {
/// Returns whether this color is allowed in forced-colors mode.
pub fn honored_in_forced_colors_mode(&self, allow_transparent: bool) -> bool {
match *self {
Color::InheritFromBodyQuirk => false,
Color::CurrentColor | Color::System(..) => true,
Color::Absolute(ref absolute) => allow_transparent && absolute.color.alpha() == 0.0,
Color::Numeric { ref parsed, .. } => allow_transparent && parsed.alpha == 0,
Color::ColorMix(ref mix) => {
mix.left.honored_in_forced_colors_mode(allow_transparent) &&
mix.right.honored_in_forced_colors_mode(allow_transparent)
@ -882,13 +620,13 @@ impl Color {
Color::rgba(RGBA::transparent())
}
/// Returns an absolute RGBA color value.
/// Returns a numeric RGBA color value.
#[inline]
pub fn rgba(rgba: RGBA) -> Self {
Color::Absolute(Box::new(Absolute {
color: AbsoluteColor::from_rgba(rgba),
Color::Numeric {
parsed: rgba,
authored: None,
}))
}
}
/// Parse a color, with quirks.
@ -928,7 +666,7 @@ impl Color {
if ident.len() != 3 && ident.len() != 6 {
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
return RGBA::parse_hash(ident.as_bytes()).map_err(|()| {
return parse_hash_color(ident.as_bytes()).map_err(|()| {
location.new_custom_error(StyleParseErrorKind::UnspecifiedError)
});
},
@ -973,7 +711,7 @@ impl Color {
.unwrap();
}
debug_assert_eq!(written, 6);
RGBA::parse_hash(&serialization)
parse_hash_color(&serialization)
.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
}
@ -986,7 +724,7 @@ impl Color {
pub fn to_computed_color(&self, context: Option<&Context>) -> Option<ComputedColor> {
Some(match *self {
Color::CurrentColor => ComputedColor::CurrentColor,
Color::Absolute(ref absolute) => ComputedColor::Numeric(absolute.color.to_rgba()),
Color::Numeric { ref parsed, .. } => ComputedColor::Numeric(*parsed),
Color::ColorMix(ref mix) => {
use crate::values::computed::percentage::Percentage;

View File

@ -16,7 +16,7 @@ gecko = []
[dependencies]
app_units = "0.7"
bitflags = "1.0"
cssparser = "0.30"
cssparser = "0.29"
euclid = "0.22"
lazy_static = "1"
malloc_size_of = { path = "../malloc_size_of" }

View File

@ -499,8 +499,9 @@ impl_to_css_for_predefined_type!(i8);
impl_to_css_for_predefined_type!(i32);
impl_to_css_for_predefined_type!(u16);
impl_to_css_for_predefined_type!(u32);
impl_to_css_for_predefined_type!(::cssparser::RGBA);
impl_to_css_for_predefined_type!(::cssparser::Token<'a>);
impl_to_css_for_predefined_type!(::cssparser::RGBA);
impl_to_css_for_predefined_type!(::cssparser::Color);
impl_to_css_for_predefined_type!(::cssparser::UnicodeRange);
/// Define an enum type with unit variants that each correspond to a CSS keyword.

View File

@ -14,7 +14,7 @@ servo = ["cssparser/serde", "string_cache"]
gecko = []
[dependencies]
cssparser = "0.30"
cssparser = "0.29"
servo_arc = { path = "../servo_arc" }
smallbitvec = "2.1.1"
smallvec = "1.0"

View File

@ -15,7 +15,7 @@ gecko_refcount_logging = ["style/gecko_refcount_logging", "servo_arc/gecko_refco
[dependencies]
atomic_refcell = "0.1"
bincode = "1.0"
cssparser = "0.30"
cssparser = "0.29"
cstr = "0.2"
dom = { path = "../../../dom/base/rust" }
gecko-profiler = { path = "../../../tools/profiler/rust-api" }

View File

@ -12,7 +12,7 @@ doctest = false
[dependencies]
byteorder = "1.0"
app_units = "0.7"
cssparser = "0.30"
cssparser = "0.29"
euclid = "0.22"
html5ever = "0.22"
parking_lot = "0.10"

View File

@ -355,12 +355,6 @@ Trivial crate with a single proc macro to compute the max length of the inputs
to a match expression.
"""
[[audits.cssparser-macros]]
who = "Tiaan Louw <tlouw@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.6.0 -> 0.6.0@git:722b30d2f1634714befab967ecae627813fa4cf0"
notes = "We are pulling this package from a non crates.io source until the changes are published. No changes were made to the code."
[[audits.cstr]]
who = "Emilio Cobos Álvarez <emilio@crisal.io>"
criteria = "safe-to-deploy"

View File

@ -35,10 +35,6 @@ notes = "This is a crate Henri wrote which is also published. We should probably
audit-as-crates-io = true
notes = "This is a pinned version of the upstream code, presumably to get a fix that hadn't been released yet. We should consider switching to the latest official release."
[policy.cssparser-macros]
audit-as-crates-io = true
notes = "Using non-crates.io revision because the color-4 changes has not been published yet."
[policy.geckodriver]
audit-as-crates-io = false
criteria = "safe-to-run"

View File

@ -1 +1 @@
prefs: [dom.animations-api.compositing.enabled:true,layout.css.cascade-layers.enabled:true, layout.css.more_color_4.enabled:true]
prefs: [dom.animations-api.compositing.enabled:true,layout.css.cascade-layers.enabled:true]

View File

@ -1,14 +1,3 @@
[background-color-interpolation.html]
expected:
if swgl and (os == "linux"): [OK, ERROR]
[CSS Transitions: property <background-color> from [currentcolor\] to [rgba(0, 255, 0, 0.75)\] at (0.75) should be [rgba(0, 208, 47, 0.69)\]]
expected: FAIL
[CSS Transitions with transition: all: property <background-color> from [currentcolor\] to [rgba(0, 255, 0, 0.75)\] at (0.75) should be [rgba(0, 208, 47, 0.69)\]]
expected: FAIL
[CSS Animations: property <background-color> from [currentcolor\] to [rgba(0, 255, 0, 0.75)\] at (0.75) should be [rgba(0, 208, 47, 0.69)\]]
expected: FAIL
[Web Animations: property <background-color> from [currentcolor\] to [rgba(0, 255, 0, 0.75)\] at (0.75) should be [rgba(0, 208, 47, 0.69)\]]
expected: FAIL
if swgl and (os == "linux"): ["OK", "ERROR"]

View File

@ -0,0 +1,2 @@
[lab-001.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[lab-002.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[lab-003.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[lab-004.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[lab-005.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[lab-006.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[lab-007.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[lch-001.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[lch-002.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[lch-003.html]
expected: FAIL

View File

@ -0,0 +1,3 @@
[lch-004.html]
expected:
FAIL

View File

@ -0,0 +1,2 @@
[lch-006.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[lch-007.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklab-001.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklab-002.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklab-003.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklab-004.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklab-005.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklab-006.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklab-007.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklch-001.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklch-002.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklch-003.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklch-004.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklch-005.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklch-006.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[oklch-007.html]
expected: FAIL

View File

@ -59,9 +59,15 @@
[Property color value 'color-mix(in hsl, lch(0 116 334) 100%, rgb(0, 0, 0) 0%)']
expected: FAIL
[Property color value 'color-mix(in hsl, oklab(100 0.365 -0.16) 100%, rgb(0, 0, 0) 0%)']
expected: FAIL
[Property color value 'color-mix(in hsl, oklab(0 0.365 -0.16) 100%, rgb(0, 0, 0) 0%)']
expected: FAIL
[Property color value 'color-mix(in hsl, oklch(100 0.399 336.3) 100%, rgb(0, 0, 0) 0%)']
expected: FAIL
[Property color value 'color-mix(in hsl, oklch(0 0.399 336.3) 100%, rgb(0, 0, 0) 0%)']
expected: FAIL
@ -125,9 +131,15 @@
[Property color value 'color-mix(in hwb, lch(0 116 334) 100%, rgb(0, 0, 0) 0%)']
expected: FAIL
[Property color value 'color-mix(in hwb, oklab(100 0.365 -0.16) 100%, rgb(0, 0, 0) 0%)']
expected: FAIL
[Property color value 'color-mix(in hwb, oklab(0 0.365 -0.16) 100%, rgb(0, 0, 0) 0%)']
expected: FAIL
[Property color value 'color-mix(in hwb, oklch(100 0.399 336.3) 100%, rgb(0, 0, 0) 0%)']
expected: FAIL
[Property color value 'color-mix(in hwb, oklch(0 0.399 336.3) 100%, rgb(0, 0, 0) 0%)']
expected: FAIL

View File

@ -145,6 +145,15 @@
[e.style['color'\] = "color-mix(in hwb, oklch(0 0.399 336.3) 100%, rgb(0, 0, 0) 0%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg), lch(50 60 70deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg) 25%, lch(50 60 70deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, 25% lch(10 20 30deg), lch(50 60 70deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg), 25% lch(50 60 70deg))" should set the property value]
expected: FAIL
@ -154,6 +163,24 @@
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg) 25%, lch(50 60 70deg) 75%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg) 30%, lch(50 60 70deg) 90%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg) 12.5%, lch(50 60 70deg) 37.5%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg) 0%, lch(50 60 70deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg / .4), lch(50 60 70deg / .8))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg / .4) 25%, lch(50 60 70deg / .8))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, 25% lch(10 20 30deg / .4), lch(50 60 70deg / .8))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg / .4), 25% lch(50 60 70deg / .8))" should set the property value]
expected: FAIL
@ -163,6 +190,105 @@
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg / .4) 25%, lch(50 60 70deg / .8) 75%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg / .4) 30%, lch(50 60 70deg / .8) 90%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg / .4) 12.5%, lch(50 60 70deg / .8) 37.5%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(10 20 30deg / .4) 0%, lch(50 60 70deg / .8))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(100 0 40deg), lch(100 0 60deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(100 0 60deg), lch(100 0 40deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(100 0 50deg), lch(100 0 330deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(100 0 330deg), lch(100 0 50deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(100 0 20deg), lch(100 0 320deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(100 0 320deg), lch(100 0 20deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch shorter hue, lch(100 0 40deg), lch(100 0 60deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch shorter hue, lch(100 0 60deg), lch(100 0 40deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch shorter hue, lch(100 0 50deg), lch(100 0 330deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch shorter hue, lch(100 0 330deg), lch(100 0 50deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch shorter hue, lch(100 0 20deg), lch(100 0 320deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch shorter hue, lch(100 0 320deg), lch(100 0 20deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch longer hue, lch(100 0 40deg), lch(100 0 60deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch longer hue, lch(100 0 60deg), lch(100 0 40deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch longer hue, lch(100 0 50deg), lch(100 0 330deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch longer hue, lch(100 0 330deg), lch(100 0 50deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch longer hue, lch(100 0 20deg), lch(100 0 320deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch longer hue, lch(100 0 320deg), lch(100 0 20deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch increasing hue, lch(100 0 40deg), lch(100 0 60deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch increasing hue, lch(100 0 60deg), lch(100 0 40deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch increasing hue, lch(100 0 50deg), lch(100 0 330deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch increasing hue, lch(100 0 330deg), lch(100 0 50deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch increasing hue, lch(100 0 20deg), lch(100 0 320deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch increasing hue, lch(100 0 320deg), lch(100 0 20deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch decreasing hue, lch(100 0 40deg), lch(100 0 60deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch decreasing hue, lch(100 0 60deg), lch(100 0 40deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch decreasing hue, lch(100 0 50deg), lch(100 0 330deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch decreasing hue, lch(100 0 330deg), lch(100 0 50deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch decreasing hue, lch(100 0 20deg), lch(100 0 320deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch decreasing hue, lch(100 0 320deg), lch(100 0 20deg))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lch, lch(none none none), lch(none none none))" should set the property value]
expected: FAIL
@ -361,6 +487,15 @@
[e.style['color'\] = "color-mix(in oklch, oklch(10 20 30deg / none), oklch(50 60 70deg / none))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30), lab(50 60 70))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30) 25%, lab(50 60 70))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, 25% lab(10 20 30), lab(50 60 70))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30), 25% lab(50 60 70))" should set the property value]
expected: FAIL
@ -370,6 +505,24 @@
[e.style['color'\] = "color-mix(in lab, lab(10 20 30) 25%, lab(50 60 70) 75%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30) 30%, lab(50 60 70) 90%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30) 12.5%, lab(50 60 70) 37.5%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30) 0%, lab(50 60 70))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30 / .4), lab(50 60 70 / .8))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30 / .4) 25%, lab(50 60 70 / .8))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, 25% lab(10 20 30 / .4), lab(50 60 70 / .8))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30 / .4), 25% lab(50 60 70 / .8))" should set the property value]
expected: FAIL
@ -379,6 +532,15 @@
[e.style['color'\] = "color-mix(in lab, lab(10 20 30 / .4) 25%, lab(50 60 70 / .8) 75%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30 / .4) 30%, lab(50 60 70 / .8) 90%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30 / .4) 12.5%, lab(50 60 70 / .8) 37.5%)" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(10 20 30 / .4) 0%, lab(50 60 70 / .8))" should set the property value]
expected: FAIL
[e.style['color'\] = "color-mix(in lab, lab(none none none), lab(none none none))" should set the property value]
expected: FAIL

View File

@ -1,6 +1,54 @@
[color-valid-lab.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[e.style['color'\] = "lab(0 0 0)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(0 0 0 / 1)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(0 0 0 / 0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(20 0 10/0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(20 0 10/50%)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(400 0 10/50%)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(50 -160 160)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(50 -200 200)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(0 0 0 / -10%)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(0 0 0 / 110%)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(0 0 0 / 300%)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(-40 0 0)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(50 -20 0)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(50 0 -20)" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(calc(50 * 3) calc(0.5 - 1) calc(1.5) / calc(-0.5 + 1))" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(calc(-50 * 3) calc(0.5 + 1) calc(-1.5) / calc(-0.5 * 2))" should set the property value]
expected: FAIL
[e.style['color'\] = "lab(none none none / none)" should set the property value]
expected: FAIL
@ -16,6 +64,54 @@
[e.style['color'\] = "lab(0 0 0 / none)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(0 0 0)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(0 0 0 / 1)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(0 0 0 / 0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(20 0 10/0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(20 0 10/50%)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(400 0 10/50%)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(50 -160 160)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(50 -200 200)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(0 0 0 / -10%)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(0 0 0 / 110%)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(0 0 0 / 300%)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(-40 0 0)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(50 -20 0)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(50 0 -20)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(calc(50 * 3) calc(0.5 - 1) calc(1.5) / calc(-0.5 + 1))" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(calc(-50 * 3) calc(0.5 + 1) calc(-1.5) / calc(-0.5 * 2))" should set the property value]
expected: FAIL
[e.style['color'\] = "oklab(none none none / none)" should set the property value]
expected: FAIL
@ -31,6 +127,66 @@
[e.style['color'\] = "oklab(0 0 0 / none)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(0 0 0deg)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(0 0 0deg / 1)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(0 0 0deg / 0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(100 230 0deg / 0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(20 50 20deg/0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(20 50 20deg/50%)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(10 20 20deg / -10%)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(10 20 20deg / 110%)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(10 20 1.28rad)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(10 20 380deg)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(10 20 -340deg)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(10 20 740deg)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(10 20 -700deg)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(-40 0 0)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(20 -20 0)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(0 0 0 / 0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(10 20 20 / 110%)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(10 20 -700)" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(calc(50 * 3) calc(0.5 - 1) calc(20deg * 2) / calc(-0.5 + 1))" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(calc(-50 * 3) calc(0.5 + 1) calc(-20deg * 2) / calc(-0.5 * 2))" should set the property value]
expected: FAIL
[e.style['color'\] = "lch(none none none / none)" should set the property value]
expected: FAIL
@ -46,6 +202,66 @@
[e.style['color'\] = "lch(0 0 0 / none)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(0 0 0deg)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(0 0 0deg / 1)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(0 0 0deg / 0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(100 230 0deg / 0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(20 50 20deg/0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(20 50 20deg/50%)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(10 20 20deg / -10%)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(10 20 20deg / 110%)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(10 20 1.28rad)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(10 20 380deg)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(10 20 -340deg)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(10 20 740deg)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(10 20 -700deg)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(-40 0 0)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(20 -20 0)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(0 0 0 / 0.5)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(10 20 20 / 110%)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(10 20 -700)" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(calc(50 * 3) calc(0.5 - 1) calc(20deg * 2) / calc(-0.5 + 1))" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(calc(-50 * 3) calc(0.5 + 1) calc(-20deg * 2) / calc(-0.5 * 2))" should set the property value]
expected: FAIL
[e.style['color'\] = "oklch(none none none / none)" should set the property value]
expected: FAIL

View File

@ -1 +1 @@
{"files":{"Cargo.toml":"7394bcf36879adf2eac7c491ada5713e69014482f0d8d3f696fbbf5084801002","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","lib.rs":"ece2f6d1a33f80180bd69075578a5b95036f45d5effe25ad828d53c62e640524"},"package":null}
{"files":{"Cargo.toml":"0da70f27e2b97898b01ce464320726e76a2a1d2079355b4517ace23cca95eec6","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","lib.rs":"ece2f6d1a33f80180bd69075578a5b95036f45d5effe25ad828d53c62e640524"},"package":"dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e"}

View File

@ -1,17 +1,31 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
edition = "2018"
name = "cssparser-macros"
version = "0.6.0"
authors = ["Simon Sapin <simon.sapin@exyr.org>"]
description = "Procedural macros for cssparser"
documentation = "https://docs.rs/cssparser-macros/"
repository = "https://github.com/servo/rust-cssparser"
license = "MPL-2.0"
edition = "2018"
repository = "https://github.com/servo/rust-cssparser"
[lib]
path = "lib.rs"
proc-macro = true
[dependencies.quote]
version = "1"
[dependencies]
quote = "1"
syn = {version = "1", features = ["full", "extra-traits"]}
[dependencies.syn]
version = "1"
features = ["full", "extra-traits"]

View File

@ -1 +1 @@
{"files":{".github/workflows/main.yml":"d66f2aac0764ebb09540737931fe2b9311e7033a2bf9a116c072cae6bec5e187","Cargo.toml":"24d32e0afdd92b7a8e7392f6239ca254439b05c3a5d05bcfac414f37fcdb5c6e","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README.md":"53a6805edd80f642473514cb93f1f4197e17a911d66a2dfcefc3dc5e82bac206","build.rs":"b30f35bfbd713943822a19ce6ebe5c99017f603cb001ed37354020549aec71fc","build/match_byte.rs":"f57faf0597cb7b3e32999c5fb1215a43a5603121588c67d5031f720362171e1c","docs/.nojekyll":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","docs/404.html":"025861f76f8d1f6d67c20ab624c6e418f4f824385e2dd8ad8732c4ea563c6a2e","docs/index.html":"025861f76f8d1f6d67c20ab624c6e418f4f824385e2dd8ad8732c4ea563c6a2e","src/color.rs":"e4aa5da550c922a9c4a401452fea30889ba400633839cdc7500a37482d9945a4","src/cow_rc_str.rs":"89b5dff5cf80eef3fcff0c11799e54a978d02d8b8963a621fbb999d35e7c03a3","src/from_bytes.rs":"b1cf15c4e975523fef46b575598737a39f3c63e5ce0b2bfd6ec627c69c6ea54a","src/lib.rs":"0a1c0aed2a9aec427ff5acf2436720111f8b0067e53a16048f2cf5f35b308a1a","src/macros.rs":"9788d5dfa8fa426801fab2d787b616346a0e229e8d63e76a263cf3dd5009208c","src/nth.rs":"ae2f8b0f2c9e8b1ffb3cb842ca78c0060829a7d2e0762d1eb427f40188686ba1","src/parser.rs":"f9985187ede4361a29b3bf22d248903343d58e5cf369a9b5e046961356a4faf9","src/rules_and_declarations.rs":"d826f82f8c179fc13756b92336556e3ee40a273314ef774f95af71e687745f2a","src/serializer.rs":"8a1fcea21b485c848a7c7dff4ccfe6997dd72d40c8d3d41f50afb0eb582cb20f","src/size_of_tests.rs":"da0cbcaa304f7800e9122e2bce0a11d42a70b9012e646a723cb23ee74a6b858c","src/tests.rs":"bc6f6c3fb15c8159220bf0665250b0355a73450fad893dd35d8c71fdb902a937","src/tokenizer.rs":"76360e46c0efceff82b6336b3522c95bdb8ef96379a617e7eed12eec9bad7ab7","src/unicode_range.rs":"20d96f06fbb73921e308cc340c9fe065e27f19843005689fb259007a6a372bcc"},"package":null}
{"files":{"Cargo.toml":"2b3b153e6b0758f499f087d1fdf3f041dad6939b0b1ed9b848ba8c16058fa970","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README.md":"a533b45a9c43083c6a6000a9c99a1acfed123d6430b232352ae02f1144a09f12","build.rs":"a9619dbf086f20d3cbfee2b05c1a761f683acb30191d7286d24ad53617e9043b","build/match_byte.rs":"f57faf0597cb7b3e32999c5fb1215a43a5603121588c67d5031f720362171e1c","docs/404.html":"025861f76f8d1f6d67c20ab624c6e418f4f824385e2dd8ad8732c4ea563c6a2e","docs/index.html":"025861f76f8d1f6d67c20ab624c6e418f4f824385e2dd8ad8732c4ea563c6a2e","src/color.rs":"3ad1c1fee10137552585776f9e3fdcbd92d5d845a8bf0461e5fe9a0d58333d0b","src/cow_rc_str.rs":"89b5dff5cf80eef3fcff0c11799e54a978d02d8b8963a621fbb999d35e7c03a3","src/from_bytes.rs":"b1cf15c4e975523fef46b575598737a39f3c63e5ce0b2bfd6ec627c69c6ea54a","src/lib.rs":"88a1a1b4d8451f1374fccc2041c83607cf93560ac2c22fa7530ad65e4d581f8a","src/macros.rs":"9788d5dfa8fa426801fab2d787b616346a0e229e8d63e76a263cf3dd5009208c","src/nth.rs":"ae2f8b0f2c9e8b1ffb3cb842ca78c0060829a7d2e0762d1eb427f40188686ba1","src/parser.rs":"60b5adb9e7b8661a18a795e73c858f716ebc18252c0f63c0eff38f2564c790c9","src/rules_and_declarations.rs":"d826f82f8c179fc13756b92336556e3ee40a273314ef774f95af71e687745f2a","src/serializer.rs":"8a1fcea21b485c848a7c7dff4ccfe6997dd72d40c8d3d41f50afb0eb582cb20f","src/size_of_tests.rs":"acd10556e060e4149e9f565f36058ca26bf3b3296d512d45127845fa12b94539","src/tests.rs":"3a421dbc64ad62eeb6f4f00c7fb8244bc45b2be260e364eb1d53fc9300d6d033","src/tokenizer.rs":"76360e46c0efceff82b6336b3522c95bdb8ef96379a617e7eed12eec9bad7ab7","src/unicode_range.rs":"20d96f06fbb73921e308cc340c9fe065e27f19843005689fb259007a6a372bcc"},"package":"f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa"}

View File

@ -1,67 +0,0 @@
name: CI
on:
push:
branches: [auto]
pull_request:
workflow_dispatch:
jobs:
linux-ci:
name: Linux
runs-on: ubuntu-latest
strategy:
matrix:
toolchain:
- nightly
- beta
- stable
- 1.56.0
features:
-
- --features dummy_match_byte
include:
- toolchain: nightly
features: --features bench
- toolchain: nightly
features: --features bench,dummy_match_byte
steps:
- uses: actions/checkout@v2
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.toolchain }}
override: true
- name: Downgrade phf to a version compatible with the MSRV
run: cargo update --package phf --precise 0.10.1
if: matrix.toolchain == '1.40.0'
- name: Cargo build
run: cargo build ${{ matrix.features }}
- name: Cargo doc
run: cargo doc ${{ matrix.features }}
- name: Cargo test
run: cargo test ${{ matrix.features }}
- name: macros build
run: cargo build
working-directory: macros
build_result:
name: homu build finished
runs-on: ubuntu-latest
needs:
- "linux-ci"
steps:
- name: Mark the job as successful
run: exit 0
if: success()
- name: Mark the job as unsuccessful
run: exit 1
if: "!success()"

View File

@ -1,42 +1,81 @@
[package]
name = "cssparser"
version = "0.30.0"
authors = [ "Simon Sapin <simon.sapin@exyr.org>" ]
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
name = "cssparser"
version = "0.29.6"
authors = ["Simon Sapin <simon.sapin@exyr.org>"]
build = "build.rs"
exclude = [
"src/css-parsing-tests/**",
"src/big-data-url.css",
]
description = "Rust implementation of CSS Syntax Level 3"
documentation = "https://docs.rs/cssparser/"
repository = "https://github.com/servo/rust-cssparser"
readme = "README.md"
keywords = ["css", "syntax", "parser"]
keywords = [
"css",
"syntax",
"parser",
]
license = "MPL-2.0"
build = "build.rs"
edition = "2018"
rust-version = "1.56"
repository = "https://github.com/servo/rust-cssparser"
exclude = ["src/css-parsing-tests/**", "src/big-data-url.css"]
[dependencies.cssparser-macros]
version = "0.6"
[dev-dependencies]
serde_json = "1.0"
difference = "2.0"
encoding_rs = "0.8"
[dependencies.dtoa-short]
version = "0.3"
[dependencies]
cssparser-macros = {path = "./macros", version = "0.6"}
dtoa-short = "0.3"
itoa = "1.0"
matches = "0.1"
phf = {version = ">=0.8,<=0.11", features = ["macros"]}
serde = {version = "1.0", optional = true}
smallvec = "1.0"
[dependencies.itoa]
version = "1.0"
[build-dependencies]
syn = { version = "1", features = ["extra-traits", "fold", "full"] }
quote = "1"
proc-macro2 = "1"
[dependencies.matches]
version = "0.1"
[dependencies.phf]
version = ">=0.8,<=0.10"
features = ["macros"]
[dependencies.serde]
version = "1.0"
optional = true
[dependencies.smallvec]
version = "1.0"
[dev-dependencies.difference]
version = "2.0"
[dev-dependencies.encoding_rs]
version = "0.8"
[dev-dependencies.serde_json]
version = "1.0"
[build-dependencies.proc-macro2]
version = "1"
[build-dependencies.quote]
version = "1"
[build-dependencies.syn]
version = "1"
features = [
"extra-traits",
"fold",
"full",
]
[features]
bench = []
dummy_match_byte = []
[workspace]
members = [".", "./macros", "./procedural-masquerade"]

View File

@ -1,7 +1,7 @@
rust-cssparser
==============
[![Build Status](https://github.com/servo/rust-cssparser/actions/workflows/main.yml/badge.svg)](https://github.com/servo/rust-cssparser/actions)
[![Build Status](https://travis-ci.com/servo/rust-cssparser.svg)](https://travis-ci.com/servo/rust-cssparser)
[Documentation](https://docs.rs/cssparser/)
@ -53,5 +53,5 @@ Parsing CSS involves a series of steps:
It does however provide some helper functions to parse [CSS colors](src/color.rs)
and [An+B](src/nth.rs) (the argument to `:nth-child()` and related selectors.
See [Servos `style` crate](https://github.com/servo/servo/tree/master/components/style)
See [Servos `style` crate](https://github.com/mozilla/servo/tree/master/components/style)
for an example of a parser based on rust-cssparser.

View File

@ -37,5 +37,10 @@ mod codegen {
}
fn main() {
if std::mem::size_of::<Option<bool>>() == 1 {
// https://github.com/rust-lang/rust/pull/45225
println!("cargo:rustc-cfg=rustc_has_pr45225")
}
codegen::main();
}

View File

@ -10,27 +10,6 @@ use super::{BasicParseError, ParseError, Parser, ToCss, Token};
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
const OPAQUE: f32 = 1.0;
/// https://w3c.github.io/csswg-drafts/css-color-4/#serializing-alpha-values
#[inline]
fn serialize_alpha(dest: &mut impl fmt::Write, alpha: f32, legacy_syntax: bool) -> fmt::Result {
// If the alpha component is full opaque, don't emit the alpha value in CSS.
if alpha == OPAQUE {
return Ok(());
}
dest.write_str(if legacy_syntax { ", " } else { " / " })?;
// Try first with two decimal places, then with three.
let mut rounded_alpha = (alpha * 100.).round() / 100.;
if clamp_unit_f32(rounded_alpha) != clamp_unit_f32(alpha) {
rounded_alpha = (alpha * 1000.).round() / 1000.;
}
rounded_alpha.to_css(dest)
}
/// A color with red, green, blue, and alpha components, in a byte each.
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
@ -42,7 +21,7 @@ pub struct RGBA {
/// The blue component.
pub blue: u8,
/// The alpha component.
pub alpha: f32,
pub alpha: u8,
}
impl RGBA {
@ -55,24 +34,24 @@ impl RGBA {
clamp_unit_f32(red),
clamp_unit_f32(green),
clamp_unit_f32(blue),
alpha.max(0.0).min(1.0),
clamp_unit_f32(alpha),
)
}
/// Returns a transparent color.
#[inline]
pub fn transparent() -> Self {
Self::new(0, 0, 0, 0.0)
Self::new(0, 0, 0, 0)
}
/// Same thing, but with `u8` values instead of floats in the 0 to 1 range.
#[inline]
pub const fn new(red: u8, green: u8, blue: u8, alpha: f32) -> Self {
Self {
red,
green,
blue,
alpha,
pub fn new(red: u8, green: u8, blue: u8, alpha: u8) -> Self {
RGBA {
red: red,
green: green,
blue: blue,
alpha: alpha,
}
}
@ -97,39 +76,7 @@ impl RGBA {
/// Returns the alpha channel in a floating point number form, from 0 to 1.
#[inline]
pub fn alpha_f32(&self) -> f32 {
self.alpha
}
/// Parse a color hash, without the leading '#' character.
#[inline]
pub fn parse_hash(value: &[u8]) -> Result<Self, ()> {
Ok(match value.len() {
8 => Self::new(
from_hex(value[0])? * 16 + from_hex(value[1])?,
from_hex(value[2])? * 16 + from_hex(value[3])?,
from_hex(value[4])? * 16 + from_hex(value[5])?,
(from_hex(value[6])? * 16 + from_hex(value[7])?) as f32 / 255.0,
),
6 => Self::new(
from_hex(value[0])? * 16 + from_hex(value[1])?,
from_hex(value[2])? * 16 + from_hex(value[3])?,
from_hex(value[4])? * 16 + from_hex(value[5])?,
OPAQUE,
),
4 => Self::new(
from_hex(value[0])? * 17,
from_hex(value[1])? * 17,
from_hex(value[2])? * 17,
(from_hex(value[3])? * 17) as f32 / 255.0,
),
3 => Self::new(
from_hex(value[0])? * 17,
from_hex(value[1])? * 17,
from_hex(value[2])? * 17,
OPAQUE,
),
_ => return Err(()),
})
self.alpha as f32 / 255.0
}
}
@ -159,265 +106,36 @@ impl ToCss for RGBA {
where
W: fmt::Write,
{
let has_alpha = self.alpha != OPAQUE;
let serialize_alpha = self.alpha != 255;
dest.write_str(if has_alpha { "rgba(" } else { "rgb(" })?;
dest.write_str(if serialize_alpha { "rgba(" } else { "rgb(" })?;
self.red.to_css(dest)?;
dest.write_str(", ")?;
self.green.to_css(dest)?;
dest.write_str(", ")?;
self.blue.to_css(dest)?;
if serialize_alpha {
dest.write_str(", ")?;
serialize_alpha(dest, self.alpha, true)?;
// Try first with two decimal places, then with three.
let mut rounded_alpha = (self.alpha_f32() * 100.).round() / 100.;
if clamp_unit_f32(rounded_alpha) != self.alpha {
rounded_alpha = (self.alpha_f32() * 1000.).round() / 1000.;
}
rounded_alpha.to_css(dest)?;
}
dest.write_char(')')
}
}
// NOTE: LAB and OKLAB is not declared inside the [impl_lab_like] macro,
// because it causes cbindgen to ignore them.
/// Color specified by lightness, a- and b-axis components.
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
pub struct Lab {
/// The lightness component.
pub lightness: f32,
/// The a-axis component.
pub a: f32,
/// The b-axis component.
pub b: f32,
/// The alpha component.
pub alpha: f32,
}
/// Color specified by lightness, a- and b-axis components.
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
pub struct Oklab {
/// The lightness component.
pub lightness: f32,
/// The a-axis component.
pub a: f32,
/// The b-axis component.
pub b: f32,
/// The alpha component.
pub alpha: f32,
}
macro_rules! impl_lab_like {
($cls:ident, $fname:literal) => {
impl $cls {
/// Construct a new Lab color format with lightness, a, b and alpha components.
pub fn new(lightness: f32, a: f32, b: f32, alpha: f32) -> Self {
Self {
lightness,
a,
b,
alpha,
}
}
}
#[cfg(feature = "serde")]
impl Serialize for $cls {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
(self.lightness, self.a, self.b, self.alpha).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for $cls {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let (lightness, a, b, alpha) = Deserialize::deserialize(deserializer)?;
Ok(Self::new(lightness, a, b, alpha))
}
}
impl ToCss for $cls {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
dest.write_str($fname)?;
dest.write_str("(")?;
self.lightness.to_css(dest)?;
dest.write_char(' ')?;
self.a.to_css(dest)?;
dest.write_char(' ')?;
self.b.to_css(dest)?;
serialize_alpha(dest, self.alpha, false)?;
dest.write_char(')')
}
}
};
}
impl_lab_like!(Lab, "lab");
impl_lab_like!(Oklab, "oklab");
// NOTE: LCH and OKLCH is not declared inside the [impl_lch_like] macro,
// because it causes cbindgen to ignore them.
/// Color specified by lightness, chroma and hue components.
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
pub struct Lch {
/// The lightness component.
pub lightness: f32,
/// The chroma component.
pub chroma: f32,
/// The hue component.
pub hue: f32,
/// The alpha component.
pub alpha: f32,
}
/// Color specified by lightness, chroma and hue components.
#[derive(Clone, Copy, PartialEq, Debug)]
#[repr(C)]
pub struct Oklch {
/// The lightness component.
pub lightness: f32,
/// The chroma component.
pub chroma: f32,
/// The hue component.
pub hue: f32,
/// The alpha component.
pub alpha: f32,
}
macro_rules! impl_lch_like {
($cls:ident, $fname:literal) => {
impl $cls {
/// Construct a new color with lightness, chroma and hue components.
pub fn new(lightness: f32, chroma: f32, hue: f32, alpha: f32) -> Self {
Self {
lightness,
chroma,
hue,
alpha,
}
}
}
#[cfg(feature = "serde")]
impl Serialize for $cls {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
(self.lightness, self.chroma, self.hue, self.alpha).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for $cls {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let (lightness, chroma, hue, alpha) = Deserialize::deserialize(deserializer)?;
Ok(Self::new(lightness, chroma, hue, alpha))
}
}
impl ToCss for $cls {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
dest.write_str($fname)?;
dest.write_str("(")?;
self.lightness.to_css(dest)?;
dest.write_char(' ')?;
self.chroma.to_css(dest)?;
dest.write_char(' ')?;
self.hue.to_css(dest)?;
serialize_alpha(dest, self.alpha, false)?;
dest.write_char(')')
}
}
};
}
impl_lch_like!(Lch, "lch");
impl_lch_like!(Oklch, "oklch");
/// An absolutely specified color.
/// https://w3c.github.io/csswg-drafts/css-color-4/#typedef-absolute-color-base
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum AbsoluteColor {
/// Specify sRGB colors directly by their red/green/blue/alpha chanels.
Rgba(RGBA),
/// Specifies a CIELAB color by CIE Lightness and its a- and b-axis hue
/// coordinates (red/green-ness, and yellow/blue-ness) using the CIE LAB
/// rectangular coordinate model.
Lab(Lab),
/// Specifies a CIELAB color by CIE Lightness, Chroma, and hue using the
/// CIE LCH cylindrical coordinate model.
Lch(Lch),
/// Specifies an Oklab color by Oklab Lightness and its a- and b-axis hue
/// coordinates (red/green-ness, and yellow/blue-ness) using the Oklab
/// rectangular coordinate model.
Oklab(Oklab),
/// Specifies an Oklab color by Oklab Lightness, Chroma, and hue using
/// the OKLCH cylindrical coordinate model.
Oklch(Oklch),
}
impl AbsoluteColor {
/// Return the alpha component of any of the schemes within.
pub fn alpha(&self) -> f32 {
match self {
Self::Rgba(c) => c.alpha,
Self::Lab(c) => c.alpha,
Self::Lch(c) => c.alpha,
Self::Oklab(c) => c.alpha,
Self::Oklch(c) => c.alpha,
}
}
}
impl ToCss for AbsoluteColor {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
where
W: fmt::Write,
{
match self {
Self::Rgba(rgba) => rgba.to_css(dest),
Self::Lab(lab) => lab.to_css(dest),
Self::Lch(lch) => lch.to_css(dest),
Self::Oklab(lab) => lab.to_css(dest),
Self::Oklch(lch) => lch.to_css(dest),
}
}
}
#[inline]
pub(crate) const fn rgb(red: u8, green: u8, blue: u8) -> Color {
rgba(red, green, blue, OPAQUE)
}
#[inline]
pub(crate) const fn rgba(red: u8, green: u8, blue: u8, alpha: f32) -> Color {
Color::Absolute(AbsoluteColor::Rgba(RGBA::new(red, green, blue, alpha)))
}
/// A <color> value.
/// https://w3c.github.io/csswg-drafts/css-color-4/#color-type
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Color {
/// The 'currentcolor' keyword.
/// The 'currentcolor' keyword
CurrentColor,
/// An absolutely specified color.
Absolute(AbsoluteColor),
/// Everything else gets converted to RGBA during parsing
RGBA(RGBA),
}
impl ToCss for Color {
@ -427,7 +145,7 @@ impl ToCss for Color {
{
match *self {
Color::CurrentColor => dest.write_str("currentcolor"),
Color::Absolute(absolute) => absolute.to_css(dest),
Color::RGBA(ref rgba) => rgba.to_css(dest),
}
}
}
@ -565,8 +283,9 @@ impl Color {
let location = input.current_source_location();
let token = input.next()?;
match *token {
Token::Hash(ref value) | Token::IDHash(ref value) => RGBA::parse_hash(value.as_bytes())
.map(|rgba| Color::Absolute(AbsoluteColor::Rgba(rgba))),
Token::Hash(ref value) | Token::IDHash(ref value) => {
Color::parse_hash(value.as_bytes())
}
Token::Ident(ref value) => parse_color_keyword(&*value),
Token::Function(ref name) => {
let name = name.clone();
@ -584,6 +303,46 @@ impl Color {
let component_parser = DefaultComponentParser;
Self::parse_with(&component_parser, input).map_err(ParseError::basic)
}
/// Parse a color hash, without the leading '#' character.
#[inline]
pub fn parse_hash(value: &[u8]) -> Result<Self, ()> {
match value.len() {
8 => Ok(rgba(
from_hex(value[0])? * 16 + from_hex(value[1])?,
from_hex(value[2])? * 16 + from_hex(value[3])?,
from_hex(value[4])? * 16 + from_hex(value[5])?,
from_hex(value[6])? * 16 + from_hex(value[7])?,
)),
6 => Ok(rgb(
from_hex(value[0])? * 16 + from_hex(value[1])?,
from_hex(value[2])? * 16 + from_hex(value[3])?,
from_hex(value[4])? * 16 + from_hex(value[5])?,
)),
4 => Ok(rgba(
from_hex(value[0])? * 17,
from_hex(value[1])? * 17,
from_hex(value[2])? * 17,
from_hex(value[3])? * 17,
)),
3 => Ok(rgb(
from_hex(value[0])? * 17,
from_hex(value[1])? * 17,
from_hex(value[2])? * 17,
)),
_ => Err(()),
}
}
}
#[inline]
fn rgb(red: u8, green: u8, blue: u8) -> Color {
rgba(red, green, blue, 255)
}
#[inline]
fn rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Color {
Color::RGBA(RGBA::new(red, green, blue, alpha))
}
/// Return the named color with the given name.
@ -593,159 +352,169 @@ impl Color {
/// (For example, the value of an `Ident` token is fine.)
#[inline]
pub fn parse_color_keyword(ident: &str) -> Result<Color, ()> {
macro_rules! rgb {
($red: expr, $green: expr, $blue: expr) => {
Color::RGBA(RGBA {
red: $red,
green: $green,
blue: $blue,
alpha: 255,
})
};
}
ascii_case_insensitive_phf_map! {
keyword -> Color = {
"black" => rgb(0, 0, 0),
"silver" => rgb(192, 192, 192),
"gray" => rgb(128, 128, 128),
"white" => rgb(255, 255, 255),
"maroon" => rgb(128, 0, 0),
"red" => rgb(255, 0, 0),
"purple" => rgb(128, 0, 128),
"fuchsia" => rgb(255, 0, 255),
"green" => rgb(0, 128, 0),
"lime" => rgb(0, 255, 0),
"olive" => rgb(128, 128, 0),
"yellow" => rgb(255, 255, 0),
"navy" => rgb(0, 0, 128),
"blue" => rgb(0, 0, 255),
"teal" => rgb(0, 128, 128),
"aqua" => rgb(0, 255, 255),
"black" => rgb!(0, 0, 0),
"silver" => rgb!(192, 192, 192),
"gray" => rgb!(128, 128, 128),
"white" => rgb!(255, 255, 255),
"maroon" => rgb!(128, 0, 0),
"red" => rgb!(255, 0, 0),
"purple" => rgb!(128, 0, 128),
"fuchsia" => rgb!(255, 0, 255),
"green" => rgb!(0, 128, 0),
"lime" => rgb!(0, 255, 0),
"olive" => rgb!(128, 128, 0),
"yellow" => rgb!(255, 255, 0),
"navy" => rgb!(0, 0, 128),
"blue" => rgb!(0, 0, 255),
"teal" => rgb!(0, 128, 128),
"aqua" => rgb!(0, 255, 255),
"aliceblue" => rgb(240, 248, 255),
"antiquewhite" => rgb(250, 235, 215),
"aquamarine" => rgb(127, 255, 212),
"azure" => rgb(240, 255, 255),
"beige" => rgb(245, 245, 220),
"bisque" => rgb(255, 228, 196),
"blanchedalmond" => rgb(255, 235, 205),
"blueviolet" => rgb(138, 43, 226),
"brown" => rgb(165, 42, 42),
"burlywood" => rgb(222, 184, 135),
"cadetblue" => rgb(95, 158, 160),
"chartreuse" => rgb(127, 255, 0),
"chocolate" => rgb(210, 105, 30),
"coral" => rgb(255, 127, 80),
"cornflowerblue" => rgb(100, 149, 237),
"cornsilk" => rgb(255, 248, 220),
"crimson" => rgb(220, 20, 60),
"cyan" => rgb(0, 255, 255),
"darkblue" => rgb(0, 0, 139),
"darkcyan" => rgb(0, 139, 139),
"darkgoldenrod" => rgb(184, 134, 11),
"darkgray" => rgb(169, 169, 169),
"darkgreen" => rgb(0, 100, 0),
"darkgrey" => rgb(169, 169, 169),
"darkkhaki" => rgb(189, 183, 107),
"darkmagenta" => rgb(139, 0, 139),
"darkolivegreen" => rgb(85, 107, 47),
"darkorange" => rgb(255, 140, 0),
"darkorchid" => rgb(153, 50, 204),
"darkred" => rgb(139, 0, 0),
"darksalmon" => rgb(233, 150, 122),
"darkseagreen" => rgb(143, 188, 143),
"darkslateblue" => rgb(72, 61, 139),
"darkslategray" => rgb(47, 79, 79),
"darkslategrey" => rgb(47, 79, 79),
"darkturquoise" => rgb(0, 206, 209),
"darkviolet" => rgb(148, 0, 211),
"deeppink" => rgb(255, 20, 147),
"deepskyblue" => rgb(0, 191, 255),
"dimgray" => rgb(105, 105, 105),
"dimgrey" => rgb(105, 105, 105),
"dodgerblue" => rgb(30, 144, 255),
"firebrick" => rgb(178, 34, 34),
"floralwhite" => rgb(255, 250, 240),
"forestgreen" => rgb(34, 139, 34),
"gainsboro" => rgb(220, 220, 220),
"ghostwhite" => rgb(248, 248, 255),
"gold" => rgb(255, 215, 0),
"goldenrod" => rgb(218, 165, 32),
"greenyellow" => rgb(173, 255, 47),
"grey" => rgb(128, 128, 128),
"honeydew" => rgb(240, 255, 240),
"hotpink" => rgb(255, 105, 180),
"indianred" => rgb(205, 92, 92),
"indigo" => rgb(75, 0, 130),
"ivory" => rgb(255, 255, 240),
"khaki" => rgb(240, 230, 140),
"lavender" => rgb(230, 230, 250),
"lavenderblush" => rgb(255, 240, 245),
"lawngreen" => rgb(124, 252, 0),
"lemonchiffon" => rgb(255, 250, 205),
"lightblue" => rgb(173, 216, 230),
"lightcoral" => rgb(240, 128, 128),
"lightcyan" => rgb(224, 255, 255),
"lightgoldenrodyellow" => rgb(250, 250, 210),
"lightgray" => rgb(211, 211, 211),
"lightgreen" => rgb(144, 238, 144),
"lightgrey" => rgb(211, 211, 211),
"lightpink" => rgb(255, 182, 193),
"lightsalmon" => rgb(255, 160, 122),
"lightseagreen" => rgb(32, 178, 170),
"lightskyblue" => rgb(135, 206, 250),
"lightslategray" => rgb(119, 136, 153),
"lightslategrey" => rgb(119, 136, 153),
"lightsteelblue" => rgb(176, 196, 222),
"lightyellow" => rgb(255, 255, 224),
"limegreen" => rgb(50, 205, 50),
"linen" => rgb(250, 240, 230),
"magenta" => rgb(255, 0, 255),
"mediumaquamarine" => rgb(102, 205, 170),
"mediumblue" => rgb(0, 0, 205),
"mediumorchid" => rgb(186, 85, 211),
"mediumpurple" => rgb(147, 112, 219),
"mediumseagreen" => rgb(60, 179, 113),
"mediumslateblue" => rgb(123, 104, 238),
"mediumspringgreen" => rgb(0, 250, 154),
"mediumturquoise" => rgb(72, 209, 204),
"mediumvioletred" => rgb(199, 21, 133),
"midnightblue" => rgb(25, 25, 112),
"mintcream" => rgb(245, 255, 250),
"mistyrose" => rgb(255, 228, 225),
"moccasin" => rgb(255, 228, 181),
"navajowhite" => rgb(255, 222, 173),
"oldlace" => rgb(253, 245, 230),
"olivedrab" => rgb(107, 142, 35),
"orange" => rgb(255, 165, 0),
"orangered" => rgb(255, 69, 0),
"orchid" => rgb(218, 112, 214),
"palegoldenrod" => rgb(238, 232, 170),
"palegreen" => rgb(152, 251, 152),
"paleturquoise" => rgb(175, 238, 238),
"palevioletred" => rgb(219, 112, 147),
"papayawhip" => rgb(255, 239, 213),
"peachpuff" => rgb(255, 218, 185),
"peru" => rgb(205, 133, 63),
"pink" => rgb(255, 192, 203),
"plum" => rgb(221, 160, 221),
"powderblue" => rgb(176, 224, 230),
"rebeccapurple" => rgb(102, 51, 153),
"rosybrown" => rgb(188, 143, 143),
"royalblue" => rgb(65, 105, 225),
"saddlebrown" => rgb(139, 69, 19),
"salmon" => rgb(250, 128, 114),
"sandybrown" => rgb(244, 164, 96),
"seagreen" => rgb(46, 139, 87),
"seashell" => rgb(255, 245, 238),
"sienna" => rgb(160, 82, 45),
"skyblue" => rgb(135, 206, 235),
"slateblue" => rgb(106, 90, 205),
"slategray" => rgb(112, 128, 144),
"slategrey" => rgb(112, 128, 144),
"snow" => rgb(255, 250, 250),
"springgreen" => rgb(0, 255, 127),
"steelblue" => rgb(70, 130, 180),
"tan" => rgb(210, 180, 140),
"thistle" => rgb(216, 191, 216),
"tomato" => rgb(255, 99, 71),
"turquoise" => rgb(64, 224, 208),
"violet" => rgb(238, 130, 238),
"wheat" => rgb(245, 222, 179),
"whitesmoke" => rgb(245, 245, 245),
"yellowgreen" => rgb(154, 205, 50),
"aliceblue" => rgb!(240, 248, 255),
"antiquewhite" => rgb!(250, 235, 215),
"aquamarine" => rgb!(127, 255, 212),
"azure" => rgb!(240, 255, 255),
"beige" => rgb!(245, 245, 220),
"bisque" => rgb!(255, 228, 196),
"blanchedalmond" => rgb!(255, 235, 205),
"blueviolet" => rgb!(138, 43, 226),
"brown" => rgb!(165, 42, 42),
"burlywood" => rgb!(222, 184, 135),
"cadetblue" => rgb!(95, 158, 160),
"chartreuse" => rgb!(127, 255, 0),
"chocolate" => rgb!(210, 105, 30),
"coral" => rgb!(255, 127, 80),
"cornflowerblue" => rgb!(100, 149, 237),
"cornsilk" => rgb!(255, 248, 220),
"crimson" => rgb!(220, 20, 60),
"cyan" => rgb!(0, 255, 255),
"darkblue" => rgb!(0, 0, 139),
"darkcyan" => rgb!(0, 139, 139),
"darkgoldenrod" => rgb!(184, 134, 11),
"darkgray" => rgb!(169, 169, 169),
"darkgreen" => rgb!(0, 100, 0),
"darkgrey" => rgb!(169, 169, 169),
"darkkhaki" => rgb!(189, 183, 107),
"darkmagenta" => rgb!(139, 0, 139),
"darkolivegreen" => rgb!(85, 107, 47),
"darkorange" => rgb!(255, 140, 0),
"darkorchid" => rgb!(153, 50, 204),
"darkred" => rgb!(139, 0, 0),
"darksalmon" => rgb!(233, 150, 122),
"darkseagreen" => rgb!(143, 188, 143),
"darkslateblue" => rgb!(72, 61, 139),
"darkslategray" => rgb!(47, 79, 79),
"darkslategrey" => rgb!(47, 79, 79),
"darkturquoise" => rgb!(0, 206, 209),
"darkviolet" => rgb!(148, 0, 211),
"deeppink" => rgb!(255, 20, 147),
"deepskyblue" => rgb!(0, 191, 255),
"dimgray" => rgb!(105, 105, 105),
"dimgrey" => rgb!(105, 105, 105),
"dodgerblue" => rgb!(30, 144, 255),
"firebrick" => rgb!(178, 34, 34),
"floralwhite" => rgb!(255, 250, 240),
"forestgreen" => rgb!(34, 139, 34),
"gainsboro" => rgb!(220, 220, 220),
"ghostwhite" => rgb!(248, 248, 255),
"gold" => rgb!(255, 215, 0),
"goldenrod" => rgb!(218, 165, 32),
"greenyellow" => rgb!(173, 255, 47),
"grey" => rgb!(128, 128, 128),
"honeydew" => rgb!(240, 255, 240),
"hotpink" => rgb!(255, 105, 180),
"indianred" => rgb!(205, 92, 92),
"indigo" => rgb!(75, 0, 130),
"ivory" => rgb!(255, 255, 240),
"khaki" => rgb!(240, 230, 140),
"lavender" => rgb!(230, 230, 250),
"lavenderblush" => rgb!(255, 240, 245),
"lawngreen" => rgb!(124, 252, 0),
"lemonchiffon" => rgb!(255, 250, 205),
"lightblue" => rgb!(173, 216, 230),
"lightcoral" => rgb!(240, 128, 128),
"lightcyan" => rgb!(224, 255, 255),
"lightgoldenrodyellow" => rgb!(250, 250, 210),
"lightgray" => rgb!(211, 211, 211),
"lightgreen" => rgb!(144, 238, 144),
"lightgrey" => rgb!(211, 211, 211),
"lightpink" => rgb!(255, 182, 193),
"lightsalmon" => rgb!(255, 160, 122),
"lightseagreen" => rgb!(32, 178, 170),
"lightskyblue" => rgb!(135, 206, 250),
"lightslategray" => rgb!(119, 136, 153),
"lightslategrey" => rgb!(119, 136, 153),
"lightsteelblue" => rgb!(176, 196, 222),
"lightyellow" => rgb!(255, 255, 224),
"limegreen" => rgb!(50, 205, 50),
"linen" => rgb!(250, 240, 230),
"magenta" => rgb!(255, 0, 255),
"mediumaquamarine" => rgb!(102, 205, 170),
"mediumblue" => rgb!(0, 0, 205),
"mediumorchid" => rgb!(186, 85, 211),
"mediumpurple" => rgb!(147, 112, 219),
"mediumseagreen" => rgb!(60, 179, 113),
"mediumslateblue" => rgb!(123, 104, 238),
"mediumspringgreen" => rgb!(0, 250, 154),
"mediumturquoise" => rgb!(72, 209, 204),
"mediumvioletred" => rgb!(199, 21, 133),
"midnightblue" => rgb!(25, 25, 112),
"mintcream" => rgb!(245, 255, 250),
"mistyrose" => rgb!(255, 228, 225),
"moccasin" => rgb!(255, 228, 181),
"navajowhite" => rgb!(255, 222, 173),
"oldlace" => rgb!(253, 245, 230),
"olivedrab" => rgb!(107, 142, 35),
"orange" => rgb!(255, 165, 0),
"orangered" => rgb!(255, 69, 0),
"orchid" => rgb!(218, 112, 214),
"palegoldenrod" => rgb!(238, 232, 170),
"palegreen" => rgb!(152, 251, 152),
"paleturquoise" => rgb!(175, 238, 238),
"palevioletred" => rgb!(219, 112, 147),
"papayawhip" => rgb!(255, 239, 213),
"peachpuff" => rgb!(255, 218, 185),
"peru" => rgb!(205, 133, 63),
"pink" => rgb!(255, 192, 203),
"plum" => rgb!(221, 160, 221),
"powderblue" => rgb!(176, 224, 230),
"rebeccapurple" => rgb!(102, 51, 153),
"rosybrown" => rgb!(188, 143, 143),
"royalblue" => rgb!(65, 105, 225),
"saddlebrown" => rgb!(139, 69, 19),
"salmon" => rgb!(250, 128, 114),
"sandybrown" => rgb!(244, 164, 96),
"seagreen" => rgb!(46, 139, 87),
"seashell" => rgb!(255, 245, 238),
"sienna" => rgb!(160, 82, 45),
"skyblue" => rgb!(135, 206, 235),
"slateblue" => rgb!(106, 90, 205),
"slategray" => rgb!(112, 128, 144),
"slategrey" => rgb!(112, 128, 144),
"snow" => rgb!(255, 250, 250),
"springgreen" => rgb!(0, 255, 127),
"steelblue" => rgb!(70, 130, 180),
"tan" => rgb!(210, 180, 140),
"thistle" => rgb!(216, 191, 216),
"tomato" => rgb!(255, 99, 71),
"turquoise" => rgb!(64, 224, 208),
"violet" => rgb!(238, 130, 238),
"wheat" => rgb!(245, 222, 179),
"whitesmoke" => rgb!(245, 245, 245),
"yellowgreen" => rgb!(154, 205, 50),
"transparent" => rgba(0, 0, 0, 0.0),
"transparent" => Color::RGBA(RGBA { red: 0, green: 0, blue: 0, alpha: 0 }),
"currentcolor" => Color::CurrentColor,
}
}
@ -793,77 +562,37 @@ fn parse_color_function<'i, 't, ComponentParser>(
where
ComponentParser: ColorComponentParser<'i>,
{
// FIXME: Should the parser clamp values? or should specified/computed
// value processing handle clamping?
let color = match_ignore_ascii_case! { name,
"rgb" | "rgba" => parse_rgb(component_parser, arguments),
"hsl" | "hsla" => parse_hsl_hwb(component_parser, arguments, hsl_to_rgb, /* allow_comma = */ true),
"hwb" => parse_hsl_hwb(component_parser, arguments, hwb_to_rgb, /* allow_comma = */ false),
// for L: 0% = 0.0, 100% = 100.0
// for a and b: -100% = -125, 100% = 125
"lab" => parse_lab_like(component_parser, arguments, 100.0, 125.0, |l, a, b, alpha| {
Color::Absolute(AbsoluteColor::Lab(Lab::new(l.max(0.), a , b , alpha)))
}),
// for L: 0% = 0.0, 100% = 100.0
// for C: 0% = 0, 100% = 150
"lch" => parse_lch_like(component_parser, arguments, 100.0, 150.0, |l, c, h, alpha| {
Color::Absolute(AbsoluteColor::Lch(Lch::new(l.max(0.), c.max(0.), h, alpha)))
}),
// for L: 0% = 0.0, 100% = 1.0
// for a and b: -100% = -0.4, 100% = 0.4
"oklab" => parse_lab_like(component_parser, arguments, 1.0, 0.4, |l, a, b, alpha| {
Color::Absolute(AbsoluteColor::Oklab(Oklab::new(l.max(0.), a, b, alpha)))
}),
// for L: 0% = 0.0, 100% = 1.0
// for C: 0% = 0.0 100% = 0.4
"oklch" => parse_lch_like(component_parser, arguments, 1.0, 0.4, |l, c, h, alpha| {
Color::Absolute(AbsoluteColor::Oklch(Oklch::new(l.max(0.), c.max(0.), h, alpha)))
}),
let (red, green, blue, uses_commas) = match_ignore_ascii_case! { name,
"rgb" | "rgba" => parse_rgb_components_rgb(component_parser, arguments)?,
"hsl" | "hsla" => parse_hsl_hwb(component_parser, arguments, hsl_to_rgb, /* allow_comma = */ true)?,
"hwb" => parse_hsl_hwb(component_parser, arguments, hwb_to_rgb, /* allow_comma = */ false)?,
_ => return Err(arguments.new_unexpected_token_error(Token::Ident(name.to_owned().into()))),
}?;
};
arguments.expect_exhausted()?;
Ok(color)
}
#[inline]
fn parse_alpha<'i, 't, ComponentParser>(
component_parser: &ComponentParser,
arguments: &mut Parser<'i, 't>,
uses_commas: bool,
) -> Result<f32, ParseError<'i, ComponentParser::Error>>
where
ComponentParser: ColorComponentParser<'i>,
{
Ok(if !arguments.is_exhausted() {
let alpha = if !arguments.is_exhausted() {
if uses_commas {
arguments.expect_comma()?;
} else {
arguments.expect_delim('/')?;
};
component_parser
.parse_number_or_percentage(arguments)?
.unit_value()
.clamp(0.0, OPAQUE)
clamp_unit_f32(
component_parser
.parse_number_or_percentage(arguments)?
.unit_value(),
)
} else {
OPAQUE
})
255
};
arguments.expect_exhausted()?;
Ok(rgba(red, green, blue, alpha))
}
#[inline]
fn parse_rgb_components_rgb<'i, 't, ComponentParser>(
component_parser: &ComponentParser,
arguments: &mut Parser<'i, 't>,
) -> Result<(u8, u8, u8, f32), ParseError<'i, ComponentParser::Error>>
) -> Result<(u8, u8, u8, bool), ParseError<'i, ComponentParser::Error>>
where
ComponentParser: ColorComponentParser<'i>,
{
@ -892,21 +621,7 @@ where
blue = clamp_unit_f32(component_parser.parse_percentage(arguments)?);
}
let alpha = parse_alpha(component_parser, arguments, uses_commas)?;
Ok((red, green, blue, alpha))
}
#[inline]
fn parse_rgb<'i, 't, ComponentParser>(
component_parser: &ComponentParser,
arguments: &mut Parser<'i, 't>,
) -> Result<Color, ParseError<'i, ComponentParser::Error>>
where
ComponentParser: ColorComponentParser<'i>,
{
let (red, green, blue, alpha) = parse_rgb_components_rgb(component_parser, arguments)?;
Ok(rgba(red, green, blue, alpha))
Ok((red, green, blue, uses_commas))
}
/// Parses hsl and hbw syntax, which happens to be identical.
@ -919,7 +634,7 @@ fn parse_hsl_hwb<'i, 't, ComponentParser>(
arguments: &mut Parser<'i, 't>,
to_rgb: impl FnOnce(f32, f32, f32) -> (f32, f32, f32),
allow_comma: bool,
) -> Result<Color, ParseError<'i, ComponentParser::Error>>
) -> Result<(u8, u8, u8, bool), ParseError<'i, ComponentParser::Error>>
where
ComponentParser: ColorComponentParser<'i>,
{
@ -934,26 +649,19 @@ where
// Saturation and lightness are clamped to 0% ... 100%
let uses_commas = allow_comma && arguments.try_parse(|i| i.expect_comma()).is_ok();
let first_percentage = component_parser
.parse_percentage(arguments)?
.clamp(0.0, 1.0);
let first_percentage = component_parser.parse_percentage(arguments)?.max(0.).min(1.);
if uses_commas {
arguments.expect_comma()?;
}
let second_percentage = component_parser
.parse_percentage(arguments)?
.clamp(0.0, 1.0);
let second_percentage = component_parser.parse_percentage(arguments)?.max(0.).min(1.);
let (red, green, blue) = to_rgb(hue, first_percentage, second_percentage);
let red = clamp_unit_f32(red);
let green = clamp_unit_f32(green);
let blue = clamp_unit_f32(blue);
let alpha = parse_alpha(component_parser, arguments, uses_commas)?;
Ok(rgba(red, green, blue, alpha))
Ok((red, green, blue, uses_commas))
}
/// https://drafts.csswg.org/css-color-4/#hwb-to-rgb
@ -1005,67 +713,3 @@ pub fn hsl_to_rgb(hue: f32, saturation: f32, lightness: f32) -> (f32, f32, f32)
let blue = hue_to_rgb(m1, m2, hue_times_3 - 1.);
(red, green, blue)
}
#[inline]
fn parse_lab_like<'i, 't, ComponentParser>(
component_parser: &ComponentParser,
arguments: &mut Parser<'i, 't>,
lightness_range: f32,
a_b_range: f32,
into_color: fn(l: f32, a: f32, b: f32, alpha: f32) -> Color,
) -> Result<Color, ParseError<'i, ComponentParser::Error>>
where
ComponentParser: ColorComponentParser<'i>,
{
let lightness = match component_parser.parse_number_or_percentage(arguments)? {
NumberOrPercentage::Number { value } => value,
NumberOrPercentage::Percentage { unit_value } => unit_value * lightness_range,
};
macro_rules! parse_a_b {
() => {{
match component_parser.parse_number_or_percentage(arguments)? {
NumberOrPercentage::Number { value } => value,
NumberOrPercentage::Percentage { unit_value } => unit_value * a_b_range,
}
}};
}
let a = parse_a_b!();
let b = parse_a_b!();
let alpha = parse_alpha(component_parser, arguments, false)?;
Ok(into_color(lightness, a, b, alpha))
}
#[inline]
fn parse_lch_like<'i, 't, ComponentParser>(
component_parser: &ComponentParser,
arguments: &mut Parser<'i, 't>,
lightness_range: f32,
chroma_range: f32,
into_color: fn(l: f32, c: f32, h: f32, alpha: f32) -> Color,
) -> Result<Color, ParseError<'i, ComponentParser::Error>>
where
ComponentParser: ColorComponentParser<'i>,
{
// for L: 0% = 0.0, 100% = 100.0
let lightness = match component_parser.parse_number_or_percentage(arguments)? {
NumberOrPercentage::Number { value } => value,
NumberOrPercentage::Percentage { unit_value } => unit_value * lightness_range,
};
// for C: 0% = 0, 100% = 150
let chroma = match component_parser.parse_number_or_percentage(arguments)? {
NumberOrPercentage::Number { value } => value,
NumberOrPercentage::Percentage { unit_value } => unit_value * chroma_range,
};
let hue_degrees = component_parser.parse_angle_or_number(arguments)?.degrees();
let hue = hue_degrees - 360. * (hue_degrees / 360.).floor();
let alpha = parse_alpha(component_parser, arguments, false)?;
Ok(into_color(lightness, chroma, hue, alpha))
}

View File

@ -68,8 +68,8 @@ fn parse_border_spacing(_context: &ParserContext, input: &mut Parser)
#![recursion_limit = "200"] // For color::parse_color_keyword
pub use crate::color::{
hsl_to_rgb, hwb_to_rgb, parse_color_keyword, AbsoluteColor, AngleOrNumber, Color,
ColorComponentParser, Lab, Lch, NumberOrPercentage, Oklab, Oklch, RGBA,
hsl_to_rgb, hwb_to_rgb, parse_color_keyword, AngleOrNumber, Color, ColorComponentParser,
NumberOrPercentage, RGBA,
};
pub use crate::cow_rc_str::CowRcStr;
pub use crate::from_bytes::{stylesheet_encoding, EncodingSupport};

View File

@ -639,49 +639,17 @@ impl<'i: 't, 't> Parser<'i, 't> {
/// Parse a list of comma-separated values, all with the same syntax.
///
/// The given closure is called repeatedly with a "delimited" parser
/// (see the `Parser::parse_until_before` method) so that it can over
/// consume the input past a comma at this block/function nesting level.
/// (see the `Parser::parse_until_before` method)
/// so that it can over consume the input past a comma at this block/function nesting level.
///
/// Successful results are accumulated in a vector.
///
/// This method returns `Err(())` the first time that a closure call does,
/// or if a closure call leaves some input before the next comma or the end
/// of the input.
/// or if a closure call leaves some input before the next comma or the end of the input.
#[inline]
pub fn parse_comma_separated<F, T, E>(
&mut self,
parse_one: F,
) -> Result<Vec<T>, ParseError<'i, E>>
where
F: for<'tt> FnMut(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>>,
{
self.parse_comma_separated_internal(parse_one, /* ignore_errors = */ false)
}
/// Like `parse_comma_separated`, but ignores errors on unknown components,
/// rather than erroring out in the whole list.
///
/// Caller must deal with the fact that the resulting list might be empty,
/// if there's no valid component on the list.
#[inline]
pub fn parse_comma_separated_ignoring_errors<F, T, E: 'i>(
&mut self,
parse_one: F,
) -> Vec<T>
where
F: for<'tt> FnMut(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>>,
{
match self.parse_comma_separated_internal(parse_one, /* ignore_errors = */ true) {
Ok(values) => values,
Err(..) => unreachable!(),
}
}
#[inline]
fn parse_comma_separated_internal<F, T, E>(
&mut self,
mut parse_one: F,
ignore_errors: bool,
) -> Result<Vec<T>, ParseError<'i, E>>
where
F: for<'tt> FnMut(&mut Parser<'i, 'tt>) -> Result<T, ParseError<'i, E>>,
@ -693,11 +661,7 @@ impl<'i: 't, 't> Parser<'i, 't> {
let mut values = Vec::with_capacity(1);
loop {
self.skip_whitespace(); // Unnecessary for correctness, but may help try() in parse_one rewind less.
match self.parse_until_before(Delimiter::Comma, &mut parse_one) {
Ok(v) => values.push(v),
Err(e) if !ignore_errors => return Err(e),
Err(_) => {},
}
values.push(self.parse_until_before(Delimiter::Comma, &mut parse_one)?);
match self.next() {
Err(_) => return Ok(values),
Ok(&Token::Comma) => continue,

View File

@ -4,49 +4,56 @@
use crate::cow_rc_str::CowRcStr;
use crate::tokenizer::Token;
use std::borrow::Cow;
macro_rules! size_of_test {
($testname: ident, $t: ty, $expected_min_size: expr, $expected_max_size: expr) => {
($testname: ident, $t: ty, $expected_size: expr) => {
#[test]
fn $testname() {
let new = ::std::mem::size_of::<$t>();
if new < $expected_min_size {
let old = $expected_size;
if new < old {
panic!(
"Your changes have decreased the stack size of {} from {} to {}. \
Good work! Please update the expected size in {}.",
stringify!($t),
$expected_min_size,
old,
new,
file!()
)
} else if new > $expected_max_size {
} else if new > old {
panic!(
"Your changes have increased the stack size of {} from {} to {}. \
Please consider choosing a design which avoids this increase. \
If you feel that the increase is necessary, update the size in {}.",
stringify!($t),
$expected_max_size,
old,
new,
file!()
)
}
}
};
($testname: ident, $t: ty, $expected_size: expr) => {
size_of_test!($testname, $t, $expected_size, $expected_size);
};
}
// Some of these assume 64-bit
size_of_test!(token, Token, 32);
size_of_test!(std_cow_str, std::borrow::Cow<'static, str>, 24, 32);
size_of_test!(std_cow_str, Cow<'static, str>, 32);
size_of_test!(cow_rc_str, CowRcStr, 16);
size_of_test!(tokenizer, crate::tokenizer::Tokenizer, 72);
size_of_test!(parser_input, crate::parser::ParserInput, 136);
size_of_test!(
parser_input,
crate::parser::ParserInput,
if cfg!(rustc_has_pr45225) { 136 } else { 144 }
);
size_of_test!(parser, crate::parser::Parser, 16);
size_of_test!(source_position, crate::SourcePosition, 8);
size_of_test!(parser_state, crate::ParserState, 24);
size_of_test!(basic_parse_error, crate::BasicParseError, 40, 48);
size_of_test!(parse_error_lower_bound, crate::ParseError<()>, 40, 48);
size_of_test!(basic_parse_error, crate::BasicParseError, 48);
size_of_test!(
parse_error_lower_bound,
crate::ParseError<()>,
if cfg!(rustc_has_pr45225) { 48 } else { 56 }
);

View File

@ -13,9 +13,8 @@ use serde_json::{self, json, Map, Value};
use self::test::Bencher;
use super::{
color::{rgb, rgba},
parse_important, parse_nth, parse_one_declaration, parse_one_rule, stylesheet_encoding,
AbsoluteColor, AtRuleParser, BasicParseError, BasicParseErrorKind, Color, CowRcStr,
AtRuleParser, BasicParseError, BasicParseErrorKind, Color, CowRcStr,
DeclarationListParser, DeclarationParser, Delimiter, EncodingSupport, ParseError,
ParseErrorKind, Parser, ParserInput, ParserState, QualifiedRuleParser, RuleListParser,
SourceLocation, ToCss, Token, TokenSerializationType, UnicodeRange, RGBA,
@ -366,18 +365,14 @@ fn run_color_tests<F: Fn(Result<Color, ()>) -> Value>(json_data: &str, to_json:
#[test]
fn color3() {
run_color_tests(include_str!("css-parsing-tests/color3.json"), |c| {
c.ok()
.map(|v| v.to_css_string().to_json())
.unwrap_or(Value::Null)
c.ok().map(|v| v.to_json()).unwrap_or(Value::Null)
})
}
#[test]
fn color3_hsl() {
run_color_tests(include_str!("css-parsing-tests/color3_hsl.json"), |c| {
c.ok()
.map(|v| v.to_css_string().to_json())
.unwrap_or(Value::Null)
c.ok().map(|v| v.to_json()).unwrap_or(Value::Null)
})
}
@ -386,35 +381,17 @@ fn color3_hsl() {
fn color3_keywords() {
run_color_tests(
include_str!("css-parsing-tests/color3_keywords.json"),
|c| {
c.ok()
.map(|v| v.to_css_string().to_json())
.unwrap_or(Value::Null)
},
|c| c.ok().map(|v| v.to_json()).unwrap_or(Value::Null),
)
}
#[test]
fn color4_hwb() {
run_color_tests(include_str!("css-parsing-tests/color4_hwb.json"), |c| {
c.ok()
.map(|v| v.to_css_string().to_json())
.unwrap_or(Value::Null)
c.ok().map(|v| v.to_json()).unwrap_or(Value::Null)
})
}
#[test]
fn color4_lab_lch_oklab_oklch() {
run_color_tests(
include_str!("css-parsing-tests/color4_lab_lch_oklab_oklch.json"),
|c| {
c.ok()
.map(|v| v.to_css_string().to_json())
.unwrap_or(Value::Null)
},
)
}
#[test]
fn nth() {
run_json_tests(include_str!("css-parsing-tests/An+B.json"), |input| {
@ -429,20 +406,6 @@ fn nth() {
});
}
#[test]
fn parse_comma_separated_ignoring_errors() {
let input = "red, green something, yellow, whatever, blue";
let mut input = ParserInput::new(input);
let mut input = Parser::new(&mut input);
let result = input.parse_comma_separated_ignoring_errors(|input| {
Color::parse(input).map_err(Into::<ParseError<()>>::into)
});
assert_eq!(result.len(), 3);
assert_eq!(result[0].to_css_string(), "rgb(255, 0, 0)");
assert_eq!(result[1].to_css_string(), "rgb(255, 255, 0)");
assert_eq!(result[2].to_css_string(), "rgb(0, 0, 255)");
}
#[test]
fn unicode_range() {
run_json_tests(include_str!("css-parsing-tests/urange.json"), |input| {
@ -564,19 +527,19 @@ fn serialize_current_color() {
#[test]
fn serialize_rgb_full_alpha() {
let c = rgb(255, 230, 204);
let c = Color::RGBA(RGBA::new(255, 230, 204, 255));
assert_eq!(c.to_css_string(), "rgb(255, 230, 204)");
}
#[test]
fn serialize_rgba() {
let c = rgba(26, 51, 77, 0.125);
let c = Color::RGBA(RGBA::new(26, 51, 77, 32));
assert_eq!(c.to_css_string(), "rgba(26, 51, 77, 0.125)");
}
#[test]
fn serialize_rgba_two_digit_float_if_roundtrips() {
let c = Color::Absolute(AbsoluteColor::Rgba(RGBA::from_floats(0., 0., 0., 0.5)));
let c = Color::RGBA(RGBA::from_floats(0., 0., 0., 0.5));
assert_eq!(c.to_css_string(), "rgba(0, 0, 0, 0.5)");
}
@ -868,16 +831,8 @@ where
impl ToJson for Color {
fn to_json(&self) -> Value {
match *self {
Color::RGBA(ref rgba) => json!([rgba.red, rgba.green, rgba.blue, rgba.alpha]),
Color::CurrentColor => "currentcolor".to_json(),
Color::Absolute(absolute) => match absolute {
AbsoluteColor::Rgba(ref rgba) => {
json!([rgba.red, rgba.green, rgba.blue, rgba.alpha])
}
AbsoluteColor::Lab(ref c) => json!([c.lightness, c.a, c.b, c.alpha]),
AbsoluteColor::Lch(ref c) => json!([c.lightness, c.chroma, c.hue, c.alpha]),
AbsoluteColor::Oklab(ref c) => json!([c.lightness, c.a, c.b, c.alpha]),
AbsoluteColor::Oklch(ref c) => json!([c.lightness, c.chroma, c.hue, c.alpha]),
},
}
}
}
@ -996,11 +951,7 @@ impl<'i> AtRuleParser<'i> for JsonParser {
}
}
fn rule_without_block(
&mut self,
mut prelude: Vec<Value>,
_: &ParserState,
) -> Result<Value, ()> {
fn rule_without_block(&mut self, mut prelude: Vec<Value>, _: &ParserState) -> Result<Value, ()> {
prelude.push(Value::Null);
Ok(Value::Array(prelude))
}