mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
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:
parent
2dad1f0fd7
commit
571f8a8dd5
2 changed files with 104 additions and 32 deletions
|
@ -248,6 +248,12 @@ impl CSSPixelLength {
|
||||||
Self::new(crate::values::normalize(self.0))
|
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.
|
/// Scale the length by a given amount.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scale_by(self, scale: CSSFloat) -> Self {
|
pub fn scale_by(self, scale: CSSFloat) -> Self {
|
||||||
|
|
|
@ -24,7 +24,8 @@ use cssparser::{Parser, Token};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::ops::{Add, Mul, Sub};
|
use std::ops::{Add, Mul, Sub};
|
||||||
use style_traits::values::specified::AllowedNumericType;
|
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::Image;
|
||||||
pub use super::image::{EndingShape as GradientEndingShape, Gradient};
|
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, ()>
|
fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
|
||||||
where
|
where
|
||||||
O: Fn(f32, f32) -> f32,
|
O: Fn(f32, f32) -> f32,
|
||||||
|
@ -133,7 +146,7 @@ impl FontRelativeLength {
|
||||||
base_size: FontBaseSize,
|
base_size: FontBaseSize,
|
||||||
) -> computed::Length {
|
) -> computed::Length {
|
||||||
let (reference_size, length) = self.reference_font_size_and_length(context, base_size);
|
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.
|
/// Return reference font size.
|
||||||
|
@ -388,6 +401,36 @@ impl ViewportPercentageLength {
|
||||||
self.unpack().2
|
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) {
|
fn unpack(&self) -> (ViewportVariant, ViewportUnit, CSSFloat) {
|
||||||
match *self {
|
match *self {
|
||||||
ViewportPercentageLength::Vw(v) => (ViewportVariant::UADefault, ViewportUnit::Vw, v),
|
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
|
// See bug 989802. We truncate so that adding multiple viewport units
|
||||||
// that add up to 100 does not overflow due to rounding differences
|
// that add up to 100 does not overflow due to rounding differences
|
||||||
let trunc_scaled = ((length.0 as f64) * factor as f64 / 100.).trunc();
|
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.
|
// TODO(pcwalton): Find these from the font.
|
||||||
let average_advance = reference_font_size * 0.5;
|
let average_advance = reference_font_size * 0.5;
|
||||||
let max_advance = reference_font_size;
|
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.
|
/// Convert this into a pixel value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_px(&self) -> CSSFloat {
|
pub fn to_px(&self) -> CSSFloat {
|
||||||
use std::f32;
|
match *self {
|
||||||
|
|
||||||
let pixel = match *self {
|
|
||||||
AbsoluteLength::Px(value) => value,
|
AbsoluteLength::Px(value) => value,
|
||||||
AbsoluteLength::In(value) => value * PX_PER_IN,
|
AbsoluteLength::In(value) => value * PX_PER_IN,
|
||||||
AbsoluteLength::Cm(value) => value * PX_PER_CM,
|
AbsoluteLength::Cm(value) => value * PX_PER_CM,
|
||||||
|
@ -570,8 +624,7 @@ impl AbsoluteLength {
|
||||||
AbsoluteLength::Q(value) => value * PX_PER_Q,
|
AbsoluteLength::Q(value) => value * PX_PER_Q,
|
||||||
AbsoluteLength::Pt(value) => value * PX_PER_PT,
|
AbsoluteLength::Pt(value) => value * PX_PER_PT,
|
||||||
AbsoluteLength::Pc(value) => value * PX_PER_PC,
|
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, ()>
|
fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
|
||||||
|
@ -595,7 +648,7 @@ impl ToComputedValue for AbsoluteLength {
|
||||||
type ComputedValue = CSSPixelLength;
|
type ComputedValue = CSSPixelLength;
|
||||||
|
|
||||||
fn to_computed_value(&self, _: &Context) -> Self::ComputedValue {
|
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 {
|
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.
|
/// A container query length.
|
||||||
///
|
///
|
||||||
/// <https://drafts.csswg.org/css-contain-3/#container-lengths>
|
/// <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, ()>
|
pub(crate) fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
|
||||||
where
|
where
|
||||||
O: Fn(f32, f32) -> f32,
|
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
|
/// A `<length>` without taking `calc` expressions into account
|
||||||
///
|
///
|
||||||
/// <https://drafts.csswg.org/css-values/#lengths>
|
/// <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 {
|
pub enum NoCalcLength {
|
||||||
/// An absolute length
|
/// An absolute length
|
||||||
///
|
///
|
||||||
|
@ -793,7 +840,6 @@ pub enum NoCalcLength {
|
||||||
///
|
///
|
||||||
/// This cannot be specified by the user directly and is only generated by
|
/// This cannot be specified by the user directly and is only generated by
|
||||||
/// `Stylist::synthesize_rules_for_legacy_attributes()`.
|
/// `Stylist::synthesize_rules_for_legacy_attributes()`.
|
||||||
#[css(function)]
|
|
||||||
ServoCharacterWidth(CharacterWidth),
|
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.
|
/// Returns whether the value of this length without unit is less than zero.
|
||||||
pub fn is_negative(&self) -> bool {
|
pub fn is_negative(&self) -> bool {
|
||||||
self.unitless_value().is_sign_negative()
|
self.unitless_value().is_sign_negative()
|
||||||
|
@ -1019,7 +1076,7 @@ impl NoCalcLength {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> {
|
pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> {
|
||||||
match *self {
|
match *self {
|
||||||
NoCalcLength::Absolute(len) => Ok(len.to_px()),
|
NoCalcLength::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()),
|
||||||
_ => Err(()),
|
_ => 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 SpecifiedValueInfo for NoCalcLength {}
|
||||||
|
|
||||||
impl PartialOrd for NoCalcLength {
|
impl PartialOrd for NoCalcLength {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue