diff --git a/servo/components/style/color/convert.rs b/servo/components/style/color/convert.rs index a6274db39aab..18a6e55ff8fe 100644 --- a/servo/components/style/color/convert.rs +++ b/servo/components/style/color/convert.rs @@ -141,17 +141,29 @@ pub fn rgb_to_hwb(from: &ColorComponents) -> ColorComponents { ColorComponents(hue, whiteness * 100.0, blackness * 100.0) } +/// Calculate an epsilon for a specified range. +#[inline] +pub fn epsilon_for_range(min: f32, max: f32) -> f32 { + (max - min) / 1.0e5 +} + /// Convert from the rectangular orthogonal to the cylindrical polar coordinate /// system. This is used to convert (ok)lab to (ok)lch. /// #[inline] -pub fn orthogonal_to_polar(from: &ColorComponents) -> ColorComponents { +pub fn orthogonal_to_polar(from: &ColorComponents, e: f32) -> ColorComponents { let ColorComponents(lightness, a, b) = *from; let chroma = (a * a + b * b).sqrt(); - // Very small chroma values make the hue component powerless. - let hue = if chroma.abs() < 1.0e-6 { + let hue = if a.abs() < e && b.abs() < e { + // For extremely small values of a and b ... the reported hue angle + // swinging about wildly and being essentially random ... this means + // the hue is powerless, and treated as missing when converted into LCH + // or Oklch. + f32::NAN + } else if chroma.abs() < e { + // Very small chroma values make the hue component powerless. f32::NAN } else { normalize_hue(b.atan2(a).to_degrees()) @@ -794,7 +806,7 @@ impl ColorSpaceConversion for Lch { let lab = Lab::from_xyz(&from); // Then convert the Lab to LCH. - orthogonal_to_polar(&lab) + orthogonal_to_polar(&lab, epsilon_for_range(0.0, 100.0)) } fn to_gamma_encoded(from: &ColorComponents) -> ColorComponents { @@ -892,7 +904,7 @@ impl ColorSpaceConversion for Oklch { let lab = Oklab::from_xyz(&from); // Then convert Oklab to OkLCH. - orthogonal_to_polar(&lab) + orthogonal_to_polar(&lab, epsilon_for_range(0.0, 1.0)) } fn to_gamma_encoded(from: &ColorComponents) -> ColorComponents { diff --git a/servo/components/style/color/mod.rs b/servo/components/style/color/mod.rs index 7e427faa8496..da6eeea49251 100644 --- a/servo/components/style/color/mod.rs +++ b/servo/components/style/color/mod.rs @@ -555,7 +555,10 @@ impl AbsoluteColor { (Srgb, Hwb) => convert::rgb_to_hwb(&components), (Hsl, Srgb) => convert::hsl_to_rgb(&components), (Hwb, Srgb) => convert::hwb_to_rgb(&components), - (Lab, Lch) | (Oklab, Oklch) => convert::orthogonal_to_polar(&components), + (Lab, Lch) | (Oklab, Oklch) => convert::orthogonal_to_polar( + &components, + convert::epsilon_for_range(0.0, if color_space == Lch { 100.0 } else { 1.0 }), + ), (Lch, Lab) | (Oklch, Oklab) => convert::polar_to_orthogonal(&components), // All other conversions need to convert to XYZ first. 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 deleted file mode 100644 index 97e04a81815c..000000000000 --- a/testing/web-platform/meta/css/css-color/parsing/color-computed-color-mix-function.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[color-computed-color-mix-function.html] - [Property color value 'color-mix(in lch, white, blue)'] - expected: FAIL - - [Property color value 'color-mix(in lch, white 10%, blue)'] - expected: FAIL