From a8fef9d4f2bc971dab40f610e5ad5286aac31140 Mon Sep 17 00:00:00 2001 From: CanadaHonk Date: Tue, 7 Mar 2023 00:02:55 +0000 Subject: [PATCH] style: Serialize NaN and infinity angles as per spec `NaN`, `infinity`, and `-infinity` angles should be specially serialized. Also fixed a few relevant WPT tests which did not follow spec. (see https://github.com/web-platform-tests/wpt/pull/38825) Adjusted WPT test expectations, 40 newly pass :tada: Differential Revision: https://phabricator.services.mozilla.com/D171658 --- components/style/values/mod.rs | 33 +++++++++++++++++ components/style/values/specified/angle.rs | 42 ++++++++++++++-------- components/style/values/specified/calc.rs | 7 +++- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/components/style/values/mod.rs b/components/style/values/mod.rs index ac43ea62694..24fc08d4159 100644 --- a/components/style/values/mod.rs +++ b/components/style/values/mod.rs @@ -92,6 +92,39 @@ where serialize_name(&ident, dest) } +fn nan_inf_enabled() -> bool { + static_prefs::pref!("layout.css.nan-inf.enabled") +} + +/// Serialize a specified dimension with unit, calc, and NaN/infinity handling (if enabled) +pub fn serialize_specified_dimension(v: f32, unit: &str, was_calc: bool, dest: &mut CssWriter) -> fmt::Result +where + W: Write, +{ + if was_calc { + dest.write_str("calc(")?; + } + + if !v.is_finite() && nan_inf_enabled() { + if v.is_nan() { + dest.write_str("NaN * 1")?; + } else if v == f32::INFINITY { + dest.write_str("infinity * 1")?; + } else if v == f32::NEG_INFINITY { + dest.write_str("-infinity * 1")?; + } + } else { + v.to_css(dest)?; + } + + dest.write_str(unit)?; + + if was_calc { + dest.write_char(')')?; + } + Ok(()) +} + /// A CSS string stored as an `Atom`. #[repr(transparent)] #[derive( diff --git a/components/style/values/specified/angle.rs b/components/style/values/specified/angle.rs index 0c8c030a9ca..7f6c1a9dca4 100644 --- a/components/style/values/specified/angle.rs +++ b/components/style/values/specified/angle.rs @@ -39,12 +39,7 @@ impl Zero for AngleDimension { } fn is_zero(&self) -> bool { - match *self { - AngleDimension::Deg(ref f) | - AngleDimension::Grad(ref f) | - AngleDimension::Rad(ref f) | - AngleDimension::Turn(ref f) => *f == 0., - } + self.unitless_value() == 0.0 } } @@ -63,6 +58,24 @@ impl AngleDimension { AngleDimension::Grad(gradians) => gradians * DEG_PER_GRAD, } } + + fn unitless_value(&self) -> CSSFloat { + match *self { + AngleDimension::Deg(v) | + AngleDimension::Rad(v) | + AngleDimension::Turn(v) | + AngleDimension::Grad(v) => v, + } + } + + fn unit(&self) -> &'static str { + match *self { + AngleDimension::Deg(_) => "deg", + AngleDimension::Rad(_) => "rad", + AngleDimension::Turn(_) => "turn", + AngleDimension::Grad(_) => "grad" + } + } } /// A specified Angle value, which is just the angle dimension, plus whether it @@ -92,14 +105,7 @@ impl ToCss for Angle { where W: Write, { - if self.was_calc { - dest.write_str("calc(")?; - } - self.value.to_css(dest)?; - if self.was_calc { - dest.write_char(')')?; - } - Ok(()) + crate::values::serialize_specified_dimension(self.value.unitless_value(), self.value.unit(), self.was_calc, dest) } } @@ -108,7 +114,7 @@ impl ToComputedValue for Angle { #[inline] fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue { - ComputedAngle::from_degrees(self.degrees()) + ComputedAngle::from_degrees(crate::values::normalize(self.degrees())) } #[inline] @@ -170,6 +176,12 @@ impl Angle { was_calc: true, } } + + /// Returns the unit of the angle. + #[inline] + pub fn unit(&self) -> &'static str { + self.value.unit() + } } /// Whether to allow parsing an unitless zero as a valid angle. diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs index 7fae98cc88d..200a6db1d0a 100644 --- a/components/style/values/specified/calc.rs +++ b/components/style/values/specified/calc.rs @@ -836,7 +836,12 @@ impl CalcNode { Leaf::Angle(ref angle) => Ok(angle.degrees()), _ => Err(()), })?; - Ok(Angle::from_calc(crate::values::normalize(degrees))) + let result = Angle::from_calc(if nan_inf_enabled() { + degrees + } else { + crate::values::normalize(degrees) + }); + Ok(result) } /// Tries to simplify this expression into a `` value.