Bug Description
The polar_premultiply macro's unpremultiply method divides by self.alpha without checking for zero, causing division by zero when interpolating colors with alpha=0 in polar color spaces (HSL, HWB, LCH, OKLCH).
This produces NaN values that leak into the output as none keyword in the serialized CSS for color spaces like oklch and lch that are not converted to RGBA.
The rectangular_premultiply macro correctly guards against this with self.alpha != 0.0, but polar_premultiply is missing this check.
Reproduction
/* Input */
.foo { color: color-mix(in oklch, oklch(0.5 0.2 120 / 0), oklch(0.7 0.1 240 / 0)); }
/* Actual (buggy) output */
.foo{color:oklch(none none 180/0)}
/* Expected output */
.foo{color:oklch(0% 0 180/0)}
Similarly for LCH:
/* Input */
.foo { color: color-mix(in lch, lch(50 30 120 / 0), lch(70 10 240 / 0)); }
/* Actual (buggy) output */
.foo{color:lch(none none 180/0)}
/* Expected output */
.foo{color:lch(0% 0 180/0)}
Root Cause
In src/values/color.rs, the polar_premultiply macro:
fn unpremultiply(&mut self, alpha_multiplier: f32) {
self.h %= 360.0;
if !self.alpha.is_nan() { // Missing: && self.alpha != 0.0
self.$a /= self.alpha; // Division by zero when alpha=0 -> NaN
self.$b /= self.alpha;
self.alpha *= alpha_multiplier;
}
}
Compare with rectangular_premultiply which correctly checks:
if !self.alpha.is_nan() && self.alpha != 0.0 {
Fix
Add && self.alpha != 0.0 to the polar_premultiply unpremultiply guard, matching the rectangular_premultiply behavior.
Affected Color Spaces
- HSL (via
color-mix(in hsl, ...))
- HWB (via
color-mix(in hwb, ...))
- LCH (via
color-mix(in lch, ...))
- OKLCH (via
color-mix(in oklch, ...))
Bug Description
The
polar_premultiplymacro'sunpremultiplymethod divides byself.alphawithout checking for zero, causing division by zero when interpolating colors with alpha=0 in polar color spaces (HSL, HWB, LCH, OKLCH).This produces
NaNvalues that leak into the output asnonekeyword in the serialized CSS for color spaces likeoklchandlchthat are not converted to RGBA.The
rectangular_premultiplymacro correctly guards against this withself.alpha != 0.0, butpolar_premultiplyis missing this check.Reproduction
Similarly for LCH:
Root Cause
In
src/values/color.rs, thepolar_premultiplymacro:Compare with
rectangular_premultiplywhich correctly checks:Fix
Add
&& self.alpha != 0.0to thepolar_premultiplyunpremultiply guard, matching therectangular_premultiplybehavior.Affected Color Spaces
color-mix(in hsl, ...))color-mix(in hwb, ...))color-mix(in lch, ...))color-mix(in oklch, ...))