Bug 1899011 - In Lab/Oklab, very small a and b values makes the color achromatic r=layout-reviewers,emilio

Using an dynamic epsilon to check for small a and b values.

Differential Revision: https://phabricator.services.mozilla.com/D211665
This commit is contained in:
Tiaan Louw 2024-05-29 14:26:39 +00:00
parent 0c79149d0a
commit 7ace11cfe2
3 changed files with 21 additions and 12 deletions

View file

@ -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.
/// <https://drafts.csswg.org/css-color-4/#lab-to-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 {

View file

@ -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.

View file

@ -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