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 🎉

Differential Revision: https://phabricator.services.mozilla.com/D172183
This commit is contained in:
CanadaHonk 2023-03-13 17:49:57 +00:00 committed by Martin Robinson
parent 2dad1f0fd7
commit 571f8a8dd5
2 changed files with 104 additions and 32 deletions

View file

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

View file

@ -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<O>(&self, other: &Self, op: O) -> Result<Self, ()>
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<O>(&self, other: &Self, op: O) -> Result<Self, ()>
@ -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<CSSFloat> for AbsoluteLength {
}
}
impl Add<AbsoluteLength> 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.
///
/// <https://drafts.csswg.org/css-contain-3/#container-lengths>
@ -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<O>(&self, other: &Self, op: O) -> Result<Self, ()>
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<AbsoluteLength> for AbsoluteLength {
/// A `<length>` without taking `calc` expressions into account
///
/// <https://drafts.csswg.org/css-values/#lengths>
#[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<CSSFloat, ()> {
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<W>(&self, dest: &mut CssWriter<W>) -> 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 {