mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
style: Serialize NaN and infinity numbers
Added NaN/inf serialization of <number> and changed calc() code to not remove NaN/infinity in code using it. This change is unfortunately imperfect as some things using <number> still refuse to serialize NaN/infinity for some reason (scale()?), but this bug/patch is just for <number> so leaving that out of scope for this. Also added new WPT test file for number NaN/inf serialization based on existing serialization tests (all pass already!). 5 other WPT subtests now newly pass. Differential Revision: https://phabricator.services.mozilla.com/D178587
This commit is contained in:
parent
dcb61c095f
commit
a10df24ffb
3 changed files with 37 additions and 23 deletions
|
@ -99,6 +99,14 @@ fn nan_inf_enabled() -> bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serialize a number with calc, and NaN/infinity handling (if enabled)
|
||||||
|
pub fn serialize_number<W>(v: f32, was_calc: bool, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
|
where
|
||||||
|
W: Write,
|
||||||
|
{
|
||||||
|
serialize_specified_dimension(v, "", was_calc, dest)
|
||||||
|
}
|
||||||
|
|
||||||
/// Serialize a specified dimension with unit, calc, and NaN/infinity handling (if enabled)
|
/// Serialize a specified dimension with unit, calc, and NaN/infinity handling (if enabled)
|
||||||
pub fn serialize_specified_dimension<W>(
|
pub fn serialize_specified_dimension<W>(
|
||||||
v: f32,
|
v: f32,
|
||||||
|
@ -120,11 +128,15 @@ where
|
||||||
// requires an expression like calc(infinity * 1px)."
|
// requires an expression like calc(infinity * 1px)."
|
||||||
|
|
||||||
if v.is_nan() {
|
if v.is_nan() {
|
||||||
dest.write_str("NaN * 1")?;
|
dest.write_str("NaN")?;
|
||||||
} else if v == f32::INFINITY {
|
} else if v == f32::INFINITY {
|
||||||
dest.write_str("infinity * 1")?;
|
dest.write_str("infinity")?;
|
||||||
} else if v == f32::NEG_INFINITY {
|
} else if v == f32::NEG_INFINITY {
|
||||||
dest.write_str("-infinity * 1")?;
|
dest.write_str("-infinity")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !unit.is_empty() {
|
||||||
|
dest.write_str(" * 1")?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
v.to_css(dest)?;
|
v.to_css(dest)?;
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::values::generics::calc::{MinMaxOp, ModRemOp, RoundingStrategy, SortKe
|
||||||
use crate::values::specified::length::{AbsoluteLength, FontRelativeLength, NoCalcLength};
|
use crate::values::specified::length::{AbsoluteLength, FontRelativeLength, NoCalcLength};
|
||||||
use crate::values::specified::length::{ContainerRelativeLength, ViewportPercentageLength};
|
use crate::values::specified::length::{ContainerRelativeLength, ViewportPercentageLength};
|
||||||
use crate::values::specified::{self, Angle, Resolution, Time};
|
use crate::values::specified::{self, Angle, Resolution, Time};
|
||||||
use crate::values::{CSSFloat, CSSInteger};
|
use crate::values::{serialize_number, serialize_percentage, CSSFloat, CSSInteger};
|
||||||
use cssparser::{AngleOrNumber, CowRcStr, NumberOrPercentage, Parser, Token};
|
use cssparser::{AngleOrNumber, CowRcStr, NumberOrPercentage, Parser, Token};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
@ -131,9 +131,9 @@ impl ToCss for Leaf {
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
Self::Length(ref l) => l.to_css(dest),
|
Self::Length(ref l) => l.to_css(dest),
|
||||||
Self::Number(ref n) => n.to_css(dest),
|
Self::Number(n) => serialize_number(n, /* was_calc = */ false, dest),
|
||||||
Self::Resolution(ref r) => r.to_css(dest),
|
Self::Resolution(ref r) => r.to_css(dest),
|
||||||
Self::Percentage(p) => crate::values::serialize_percentage(p, dest),
|
Self::Percentage(p) => serialize_percentage(p, dest),
|
||||||
Self::Angle(ref a) => a.to_css(dest),
|
Self::Angle(ref a) => a.to_css(dest),
|
||||||
Self::Time(ref t) => t.to_css(dest),
|
Self::Time(ref t) => t.to_css(dest),
|
||||||
}
|
}
|
||||||
|
@ -887,10 +887,16 @@ impl CalcNode {
|
||||||
|
|
||||||
/// Tries to simplify this expression into a `<number>` value.
|
/// Tries to simplify this expression into a `<number>` value.
|
||||||
fn to_number(&self) -> Result<CSSFloat, ()> {
|
fn to_number(&self) -> Result<CSSFloat, ()> {
|
||||||
self.resolve(|leaf| match *leaf {
|
let number = self.resolve(|leaf| match *leaf {
|
||||||
Leaf::Number(n) => Ok(n),
|
Leaf::Number(n) => Ok(n),
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
})
|
})?;
|
||||||
|
let result = if nan_inf_enabled() {
|
||||||
|
number
|
||||||
|
} else {
|
||||||
|
crate::values::normalize(number)
|
||||||
|
};
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to simplify this expression into a `<percentage>` value.
|
/// Tries to simplify this expression into a `<percentage>` value.
|
||||||
|
@ -992,7 +998,6 @@ impl CalcNode {
|
||||||
) -> Result<CSSFloat, ParseError<'i>> {
|
) -> Result<CSSFloat, ParseError<'i>> {
|
||||||
Self::parse(context, input, function, CalcUnits::empty())?
|
Self::parse(context, input, function, CalcUnits::empty())?
|
||||||
.to_number()
|
.to_number()
|
||||||
.map(crate::values::normalize)
|
|
||||||
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ use super::generics::{self, GreaterThanOrEqualToOne, NonNegative};
|
||||||
use super::{CSSFloat, CSSInteger};
|
use super::{CSSFloat, CSSInteger};
|
||||||
use crate::context::QuirksMode;
|
use crate::context::QuirksMode;
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
use crate::values::serialize_atom_identifier;
|
|
||||||
use crate::values::specified::calc::CalcNode;
|
use crate::values::specified::calc::CalcNode;
|
||||||
|
use crate::values::{serialize_atom_identifier, serialize_number};
|
||||||
use crate::{Atom, Namespace, One, Prefix, Zero};
|
use crate::{Atom, Namespace, One, Prefix, Zero};
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::{Parser, Token};
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
@ -196,15 +196,15 @@ fn parse_number_with_clamping_mode<'i, 't>(
|
||||||
match *input.next()? {
|
match *input.next()? {
|
||||||
Token::Number { value, .. } if clamping_mode.is_ok(context.parsing_mode, value) => {
|
Token::Number { value, .. } if clamping_mode.is_ok(context.parsing_mode, value) => {
|
||||||
Ok(Number {
|
Ok(Number {
|
||||||
value: value.min(f32::MAX).max(f32::MIN),
|
value,
|
||||||
calc_clamping_mode: None,
|
calc_clamping_mode: None,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
Token::Function(ref name) => {
|
Token::Function(ref name) => {
|
||||||
let function = CalcNode::math_function(context, name, location)?;
|
let function = CalcNode::math_function(context, name, location)?;
|
||||||
let result = CalcNode::parse_number(context, input, function)?;
|
let value = CalcNode::parse_number(context, input, function)?;
|
||||||
Ok(Number {
|
Ok(Number {
|
||||||
value: result.min(f32::MAX).max(f32::MIN),
|
value,
|
||||||
calc_clamping_mode: Some(clamping_mode),
|
calc_clamping_mode: Some(clamping_mode),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -264,8 +264,12 @@ impl Number {
|
||||||
/// Returns the numeric value, clamped if needed.
|
/// Returns the numeric value, clamped if needed.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self) -> f32 {
|
pub fn get(&self) -> f32 {
|
||||||
self.calc_clamping_mode
|
crate::values::normalize(
|
||||||
.map_or(self.value, |mode| mode.clamp(self.value))
|
self.calc_clamping_mode
|
||||||
|
.map_or(self.value, |mode| mode.clamp(self.value)),
|
||||||
|
)
|
||||||
|
.min(f32::MAX)
|
||||||
|
.max(f32::MIN)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
@ -316,14 +320,7 @@ impl ToCss for Number {
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
if self.calc_clamping_mode.is_some() {
|
serialize_number(self.value, self.calc_clamping_mode.is_some(), dest)
|
||||||
dest.write_str("calc(")?;
|
|
||||||
}
|
|
||||||
self.value.to_css(dest)?;
|
|
||||||
if self.calc_clamping_mode.is_some() {
|
|
||||||
dest.write_char(')')?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue