commit 3d27100ba4127a113fa2ec8c1d3091dfaec60845
parent fc50bf838085b780fcef5bb39e13d0ac7475d8a0
Author: Tiaan Louw <tlouw@mozilla.com>
Date: Mon, 1 Dec 2025 15:26:51 +0000
Bug 2002148 - Handle oklab as the default interpolation method for color-mix r=layout-reviewers,firefox-style-system-reviewers,emilio
The oklab color space is now handled as default, so color-mix now
handles parsing and serialization accordingly.
See: https://github.com/web-platform-tests/interop/issues/1166
Differential Revision: https://phabricator.services.mozilla.com/D273982
Diffstat:
8 files changed, 35 insertions(+), 259 deletions(-)
diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js
@@ -5322,6 +5322,7 @@ var gCSSProperties = {
"-moz-hyperlinktext",
"-moz-visitedhyperlinktext",
/* color-mix */
+ "color-mix(red, blue)",
"color-mix(in srgb, red, blue)",
"color-mix(in srgb, highlight, rgba(0, 0, 0, .5))",
"color-mix(in srgb, color-mix(in srgb, red 10%, blue), green)",
@@ -5360,7 +5361,6 @@ var gCSSProperties = {
"hsl(0 0% 0% /)",
"hsl(0, 0%, 0% /)",
/* color-mix */
- "color-mix(red, blue)",
"color-mix(red blue)",
"color-mix(in srgb, red blue)",
"color-mix(in srgb, red 10% blue)",
diff --git a/servo/components/style/color/mix.rs b/servo/components/style/color/mix.rs
@@ -81,20 +81,31 @@ impl ColorInterpolationMethod {
}
}
+ /// Return true if the this is the default method.
+ pub fn is_default(&self) -> bool {
+ self.space == ColorSpace::Oklab
+ }
+
/// Decides the best method for interpolating between the given colors.
/// https://drafts.csswg.org/css-color-4/#interpolation-space
pub fn best_interpolation_between(left: &AbsoluteColor, right: &AbsoluteColor) -> Self {
- // The preferred color space to use for interpolating colors is Oklab.
- // However, if either of the colors are in legacy rgb(), hsl() or hwb(),
- // then interpolation is done in sRGB.
+ // The default color space to use for interpolation is Oklab. However,
+ // if either of the colors are in legacy rgb(), hsl() or hwb(), then
+ // interpolation is done in sRGB.
if !left.is_legacy_syntax() || !right.is_legacy_syntax() {
- Self::oklab()
+ Self::default()
} else {
Self::srgb()
}
}
}
+impl Default for ColorInterpolationMethod {
+ fn default() -> Self {
+ Self::oklab()
+ }
+}
+
impl Parse for ColorInterpolationMethod {
fn parse<'i, 't>(
_: &ParserContext,
diff --git a/servo/components/style/values/generics/color.rs b/servo/components/style/values/generics/color.rs
@@ -91,8 +91,15 @@ impl<Color: ToCss, Percentage: ToCss + ToPercentage> ToCss for ColorMix<Color, P
}
dest.write_str("color-mix(")?;
- self.interpolation.to_css(dest)?;
- dest.write_str(", ")?;
+
+ // If the color interpolation method is oklab (which is now the default),
+ // it can be omitted.
+ // See: https://github.com/web-platform-tests/interop/issues/1166
+ if !self.interpolation.is_default() {
+ self.interpolation.to_css(dest)?;
+ dest.write_str(", ")?;
+ }
+
self.left.to_css(dest)?;
if !can_omit(&self.left_percentage, &self.right_percentage, true) {
dest.write_char(' ')?;
diff --git a/servo/components/style/values/specified/color.rs b/servo/components/style/values/specified/color.rs
@@ -33,8 +33,15 @@ impl ColorMix {
input.expect_function_matching("color-mix")?;
input.parse_nested_block(|input| {
- let interpolation = ColorInterpolationMethod::parse(context, input)?;
- input.expect_comma()?;
+ // If the color interpolation method is omitted, default to "in oklab".
+ // See: https://github.com/web-platform-tests/interop/issues/1166
+ let interpolation = input
+ .try_parse(|input| -> Result<_, ParseError<'i>> {
+ let interpolation = ColorInterpolationMethod::parse(context, input)?;
+ input.expect_comma()?;
+ Ok(interpolation)
+ })
+ .unwrap_or_default();
let try_parse_percentage = |input: &mut Parser| -> Option<Percentage> {
input
diff --git a/servo/components/style/values/specified/image.rs b/servo/components/style/values/specified/image.rs
@@ -103,7 +103,7 @@ fn default_color_interpolation_method<T>(
});
if has_modern_syntax_item {
- ColorInterpolationMethod::oklab()
+ ColorInterpolationMethod::default()
} else {
ColorInterpolationMethod::srgb()
}
diff --git a/testing/web-platform/meta/css/css-color/parsing/color-computed-color-mix-function.html.ini b/testing/web-platform/meta/css/css-color/parsing/color-computed-color-mix-function.html.ini
@@ -1,120 +1,3 @@
[color-computed-color-mix-function.html]
[Property color value 'color-mix(in srgb, red calc(50% + (sign(100em - 1px) * 10%)), blue)']
expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3), oklab(0.5 0.6 0.7))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3) 25%, oklab(0.5 0.6 0.7))']
- expected: FAIL
-
- [Property color value 'color-mix(25% oklab(0.1 0.2 0.3), oklab(0.5 0.6 0.7))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3), 25% oklab(0.5 0.6 0.7))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3), oklab(0.5 0.6 0.7) 25%)']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3) 25%, oklab(0.5 0.6 0.7) 75%)']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3) 30%, oklab(0.5 0.6 0.7) 90%)']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3) 12.5%, oklab(0.5 0.6 0.7) 37.5%)']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3) 0%, oklab(0.5 0.6 0.7))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / .4), oklab(0.5 0.6 0.7 / .8))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / .4) 25%, oklab(0.5 0.6 0.7 / .8))']
- expected: FAIL
-
- [Property color value 'color-mix(25% oklab(0.1 0.2 0.3 / .4), oklab(0.5 0.6 0.7 / .8))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / .4), 25% oklab(0.5 0.6 0.7 / .8))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / .4), oklab(0.5 0.6 0.7 / .8) 25%)']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / .4) 25%, oklab(0.5 0.6 0.7 / .8) 75%)']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / .4) 30%, oklab(0.5 0.6 0.7 / .8) 90%)']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / .4) 12.5%, oklab(0.5 0.6 0.7 / .8) 37.5%)']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / .4) 0%, oklab(0.5 0.6 0.7 / .8))']
- expected: FAIL
-
- [Property color value 'color-mix(transparent, oklab(0.3 0.4 0.5))']
- expected: FAIL
-
- [Property color value 'color-mix(transparent 10%, oklab(0.3 0.4 0.5))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / 0), oklab(0.3 0.4 0.5))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / 0) 10%, oklab(0.3 0.4 0.5))']
- expected: FAIL
-
- [Property color value 'color-mix(white, blue)']
- expected: FAIL
-
- [Property color value 'color-mix(white 10%, blue)']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(none none none), oklab(none none none))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(none none none), oklab(0.5 0.6 0.7))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3), oklab(none none none))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 none), oklab(0.5 0.6 0.7))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3), oklab(0.5 0.6 none))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(none 0.2 0.3), oklab(0.5 none 0.7))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / none), oklab(0.5 0.6 0.7))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / none), oklab(0.5 0.6 0.7 / 0.5))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / none), oklab(0.5 0.6 0.7 / none))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / 25%) 0%, oklab(0.5 none none / none))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / 25%) 0%, oklab(none 0.5 none / none))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / 25%) 0%, oklab(none none 0.5 / none))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / 25%) 0%, oklab(0.5 0.5 none / none))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / 25%) 0%, oklab(none none none / 0.5))']
- expected: FAIL
-
- [Property color value 'color-mix(oklab(0.1 0.2 0.3 / 25%) 0%, oklab(0.5 none none / 0.5))']
- expected: FAIL
diff --git a/testing/web-platform/meta/css/css-color/parsing/color-valid-color-mix-function.html.ini b/testing/web-platform/meta/css/css-color/parsing/color-valid-color-mix-function.html.ini
@@ -1,132 +1,3 @@
[color-valid-color-mix-function.html]
[e.style['color'\] = "color-mix(in hsl, red calc(50% * sign(100em - 1px)), blue)" should set the property value]
expected: FAIL
-
- [e.style['color'\] = "color-mix(hsl(120deg 10% 20%), hsl(30deg 30% 40%))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(hwb(120deg 10% 20%), hwb(30deg 30% 40%))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(lch(10 20 30), lch(50 60 70))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(oklch(0.1 20 30), oklch(0.5 60 70))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(lab(10 20 30), lab(50 60 70))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3), oklab(0.5 0.6 0.7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3) 25%, oklab(0.5 0.6 0.7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, 25% oklab(0.1 0.2 0.3), oklab(0.5 0.6 0.7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3), 25% oklab(0.5 0.6 0.7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3), oklab(0.5 0.6 0.7) 25%)" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3) 25%, oklab(0.5 0.6 0.7) 75%)" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3) 30%, oklab(0.5 0.6 0.7) 90%)" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3) 12.5%, oklab(0.5 0.6 0.7) 37.5%)" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3) 0%, oklab(0.5 0.6 0.7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3 / .4), oklab(0.5 0.6 0.7 / .8))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3 / .4) 25%, oklab(0.5 0.6 0.7 / .8))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, 25% oklab(0.1 0.2 0.3 / .4), oklab(0.5 0.6 0.7 / .8))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3 / .4), 25% oklab(0.5 0.6 0.7 / .8))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3 / .4), oklab(0.5 0.6 0.7 / .8) 25%)" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3 / .4) 25%, oklab(0.5 0.6 0.7 / .8) 75%)" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3 / .4) 30%, oklab(0.5 0.6 0.7 / .8) 90%)" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3 / .4) 12.5%, oklab(0.5 0.6 0.7 / .8) 37.5%)" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3 / .4) 0%, oklab(0.5 0.6 0.7 / .8))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(none none none), oklab(none none none))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(none none none), oklab(0.5 0.6 0.7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3), oklab(none none none))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 none), oklab(0.5 0.6 0.7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3), oklab(0.5 0.6 none))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(none 0.2 0.3), oklab(0.5 none 0.7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3 / none), oklab(0.5 0.6 0.7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3 / none), oklab(0.5 0.6 0.7 / 0.5))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(in oklab, oklab(0.1 0.2 0.3 / none), oklab(0.5 0.6 0.7 / none))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(oklab(0.1 0.2 0.3), oklab(0.5 0.6 0.7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(color(srgb .1 .2 .3), color(srgb .5 .6 .7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(color(srgb-linear .1 .2 .3), color(srgb-linear .5 .6 .7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(color(display-p3 .1 .2 .3), color(display-p3 .5 .6 .7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(color(a98-rgb .1 .2 .3), color(a98-rgb .5 .6 .7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(color(prophoto-rgb .1 .2 .3), color(prophoto-rgb .5 .6 .7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(color(rec2020 .1 .2 .3), color(rec2020 .5 .6 .7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(color(xyz .1 .2 .3), color(xyz .5 .6 .7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(color(xyz-d50 .1 .2 .3), color(xyz-d50 .5 .6 .7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(color(xyz-d65 .1 .2 .3), color(xyz-d65 .5 .6 .7))" should set the property value]
- expected: FAIL
-
- [e.style['color'\] = "color-mix(color(display-p3-linear .1 .2 .3), color(display-p3-linear .5 .6 .7))" should set the property value]
- expected: FAIL
diff --git a/testing/web-platform/meta/css/css-color/parsing/color-valid-relative-color.html.ini b/testing/web-platform/meta/css/css-color/parsing/color-valid-relative-color.html.ini
@@ -1,6 +1,3 @@
[color-valid-relative-color.html]
[e.style['color'\] = "oklch(from red calc(1 / l) c h)" should set the property value]
expected: [FAIL, PASS]
-
- [e.style['color'\] = "oklab(from color-mix(in oklab, oklab(0.25 0.2 0.5), oklab(0.25 0.2 0.5)) l a b / alpha)" should set the property value]
- expected: FAIL