From 571f8a8dd556d2078506f14bd341e216950366ef Mon Sep 17 00:00:00 2001 From: CanadaHonk Date: Mon, 13 Mar 2023 17:49:57 +0000 Subject: [PATCH] style: Serialize NaN and infinity lengths Lengths using NaN and infinity are now serialized properly with some improvements to computed values as well. Also added a few minor new relevant WPT tests. 35 WPT tests newly pass :tada: Differential Revision: https://phabricator.services.mozilla.com/D172183 --- components/style/values/computed/length.rs | 6 + components/style/values/specified/length.rs | 130 +++++++++++++++----- 2 files changed, 104 insertions(+), 32 deletions(-) diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 4f68e1c4593..e314343702d 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -248,6 +248,12 @@ impl CSSPixelLength { Self::new(crate::values::normalize(self.0)) } + // Returns a finite (normalized and clamped to float min and max) version of this length. + #[inline] + pub fn finite(self) -> Self { + Self::new(crate::values::normalize(self.0).min(f32::MAX).max(f32::MIN)) + } + /// Scale the length by a given amount. #[inline] pub fn scale_by(self, scale: CSSFloat) -> Self { diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 2d0a031953f..b1334ee69b6 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -24,7 +24,8 @@ use cssparser::{Parser, Token}; use std::cmp; use std::ops::{Add, Mul, Sub}; use style_traits::values::specified::AllowedNumericType; -use style_traits::{ParseError, SpecifiedValueInfo, StyleParseErrorKind}; +use std::fmt::{self, Write}; +use style_traits::{ParseError, SpecifiedValueInfo, StyleParseErrorKind, CssWriter, ToCss}; pub use super::image::Image; pub use super::image::{EndingShape as GradientEndingShape, Gradient}; @@ -98,6 +99,18 @@ impl FontRelativeLength { } } + // Return the unit, as a string. + fn unit(&self) -> &'static str { + match *self { + FontRelativeLength::Em(_) => "em", + FontRelativeLength::Ex(_) => "ex", + FontRelativeLength::Ch(_) => "ch", + FontRelativeLength::Cap(_) => "cap", + FontRelativeLength::Ic(_) => "ic", + FontRelativeLength::Rem(_) => "rem" + } + } + fn try_op(&self, other: &Self, op: O) -> Result where O: Fn(f32, f32) -> f32, @@ -133,7 +146,7 @@ impl FontRelativeLength { base_size: FontBaseSize, ) -> computed::Length { let (reference_size, length) = self.reference_font_size_and_length(context, base_size); - (reference_size * length).normalized() + (reference_size * length).finite() } /// Return reference font size. @@ -388,6 +401,36 @@ impl ViewportPercentageLength { self.unpack().2 } + // Return the unit, as a string. + fn unit(&self) -> &'static str { + match *self { + ViewportPercentageLength::Vw(_) => "vw", + ViewportPercentageLength::Lvw(_) => "lvw", + ViewportPercentageLength::Svw(_) => "svw", + ViewportPercentageLength::Dvw(_) => "dvw", + ViewportPercentageLength::Vh(_) => "vh", + ViewportPercentageLength::Svh(_) => "svh", + ViewportPercentageLength::Lvh(_) => "lvh", + ViewportPercentageLength::Dvh(_) => "dvh", + ViewportPercentageLength::Vmin(_) => "vmin", + ViewportPercentageLength::Svmin(_) => "svmin", + ViewportPercentageLength::Lvmin(_) => "lvmin", + ViewportPercentageLength::Dvmin(_) => "dvmin", + ViewportPercentageLength::Vmax(_) => "vmax", + ViewportPercentageLength::Svmax(_) => "svmax", + ViewportPercentageLength::Lvmax(_) => "lvmax", + ViewportPercentageLength::Dvmax(_) => "dvmax", + ViewportPercentageLength::Vb(_) => "vb", + ViewportPercentageLength::Svb(_) => "svb", + ViewportPercentageLength::Lvb(_) => "lvb", + ViewportPercentageLength::Dvb(_) => "dvb", + ViewportPercentageLength::Vi(_) => "vi", + ViewportPercentageLength::Svi(_) => "svi", + ViewportPercentageLength::Lvi(_) => "lvi", + ViewportPercentageLength::Dvi(_) => "dvi", + } + } + fn unpack(&self) -> (ViewportVariant, ViewportUnit, CSSFloat) { match *self { ViewportPercentageLength::Vw(v) => (ViewportVariant::UADefault, ViewportUnit::Vw, v), @@ -496,7 +539,7 @@ impl ViewportPercentageLength { // See bug 989802. We truncate so that adding multiple viewport units // that add up to 100 does not overflow due to rounding differences let trunc_scaled = ((length.0 as f64) * factor as f64 / 100.).trunc(); - Au::from_f64_au(trunc_scaled).into() + Au::from_f64_au(if trunc_scaled.is_nan() { 0.0f64 } else { trunc_scaled }).into() } } @@ -513,7 +556,7 @@ impl CharacterWidth { // TODO(pcwalton): Find these from the font. let average_advance = reference_font_size * 0.5; let max_advance = reference_font_size; - average_advance * (self.0 as CSSFloat - 1.0) + max_advance + (average_advance * (self.0 as CSSFloat - 1.0) + max_advance).finite() } } @@ -557,12 +600,23 @@ impl AbsoluteLength { } } + // Return the unit, as a string. + fn unit(&self) -> &'static str { + match *self { + AbsoluteLength::Px(_) => "px", + AbsoluteLength::In(_) => "in", + AbsoluteLength::Cm(_) => "cm", + AbsoluteLength::Mm(_) => "mm", + AbsoluteLength::Q(_) => "q", + AbsoluteLength::Pt(_) => "pt", + AbsoluteLength::Pc(_) => "pc" + } + } + /// Convert this into a pixel value. #[inline] pub fn to_px(&self) -> CSSFloat { - use std::f32; - - let pixel = match *self { + match *self { AbsoluteLength::Px(value) => value, AbsoluteLength::In(value) => value * PX_PER_IN, AbsoluteLength::Cm(value) => value * PX_PER_CM, @@ -570,8 +624,7 @@ impl AbsoluteLength { AbsoluteLength::Q(value) => value * PX_PER_Q, AbsoluteLength::Pt(value) => value * PX_PER_PT, AbsoluteLength::Pc(value) => value * PX_PER_PC, - }; - pixel.min(f32::MAX).max(f32::MIN) + } } fn try_op(&self, other: &Self, op: O) -> Result @@ -595,7 +648,7 @@ impl ToComputedValue for AbsoluteLength { type ComputedValue = CSSPixelLength; fn to_computed_value(&self, _: &Context) -> Self::ComputedValue { - CSSPixelLength::new(self.to_px()) + CSSPixelLength::new(self.to_px()).finite() } fn from_computed_value(computed: &Self::ComputedValue) -> Self { @@ -626,24 +679,6 @@ impl Mul for AbsoluteLength { } } -impl Add for AbsoluteLength { - type Output = Self; - - #[inline] - fn add(self, rhs: Self) -> Self { - match (self, rhs) { - (AbsoluteLength::Px(x), AbsoluteLength::Px(y)) => AbsoluteLength::Px(x + y), - (AbsoluteLength::In(x), AbsoluteLength::In(y)) => AbsoluteLength::In(x + y), - (AbsoluteLength::Cm(x), AbsoluteLength::Cm(y)) => AbsoluteLength::Cm(x + y), - (AbsoluteLength::Mm(x), AbsoluteLength::Mm(y)) => AbsoluteLength::Mm(x + y), - (AbsoluteLength::Q(x), AbsoluteLength::Q(y)) => AbsoluteLength::Q(x + y), - (AbsoluteLength::Pt(x), AbsoluteLength::Pt(y)) => AbsoluteLength::Pt(x + y), - (AbsoluteLength::Pc(x), AbsoluteLength::Pc(y)) => AbsoluteLength::Pc(x + y), - _ => AbsoluteLength::Px(self.to_px() + rhs.to_px()), - } - } -} - /// A container query length. /// /// @@ -681,6 +716,18 @@ impl ContainerRelativeLength { } } + // Return the unit, as a string. + fn unit(&self) -> &'static str { + match *self { + ContainerRelativeLength::Cqw(_) => "cqw", + ContainerRelativeLength::Cqh(_) => "cqh", + ContainerRelativeLength::Cqi(_) => "cqi", + ContainerRelativeLength::Cqb(_) => "cqb", + ContainerRelativeLength::Cqmin(_) => "cqmin", + ContainerRelativeLength::Cqmax(_) => "cqmax" + } + } + pub(crate) fn try_op(&self, other: &Self, op: O) -> Result where O: Fn(f32, f32) -> f32, @@ -734,7 +781,7 @@ impl ContainerRelativeLength { ), ), }; - CSSPixelLength::new(((container_length.to_f64_px()) * factor as f64 / 100.0) as f32) + CSSPixelLength::new((container_length.to_f64_px() * factor as f64 / 100.0) as f32).finite() } } @@ -768,7 +815,7 @@ impl Sub for AbsoluteLength { /// A `` without taking `calc` expressions into account /// /// -#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)] +#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem)] pub enum NoCalcLength { /// An absolute length /// @@ -793,7 +840,6 @@ pub enum NoCalcLength { /// /// This cannot be specified by the user directly and is only generated by /// `Stylist::synthesize_rules_for_legacy_attributes()`. - #[css(function)] ServoCharacterWidth(CharacterWidth), } @@ -824,6 +870,17 @@ impl NoCalcLength { } } + // Return the unit, as a string. + fn unit(&self) -> &'static str { + match *self { + NoCalcLength::Absolute(v) => v.unit(), + NoCalcLength::FontRelative(v) => v.unit(), + NoCalcLength::ViewportPercentage(v) => v.unit(), + NoCalcLength::ContainerRelative(v) => v.unit(), + NoCalcLength::ServoCharacterWidth(_) => "" + } + } + /// Returns whether the value of this length without unit is less than zero. pub fn is_negative(&self) -> bool { self.unitless_value().is_sign_negative() @@ -1019,7 +1076,7 @@ impl NoCalcLength { #[inline] pub fn to_computed_pixel_length_without_context(&self) -> Result { match *self { - NoCalcLength::Absolute(len) => Ok(len.to_px()), + NoCalcLength::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()), _ => Err(()), } } @@ -1031,6 +1088,15 @@ impl NoCalcLength { } } +impl ToCss for NoCalcLength { + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + crate::values::serialize_specified_dimension(self.unitless_value(), self.unit(), false, dest) + } +} + impl SpecifiedValueInfo for NoCalcLength {} impl PartialOrd for NoCalcLength {