From 0f359a70e2141bc0fa1b5899cd5579d0bd238d87 Mon Sep 17 00:00:00 2001 From: Connor Pearson Date: Sat, 5 Nov 2022 21:25:16 +0000 Subject: [PATCH] Bug 1764850 Implement CSS round() function. r=emilio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Emilio Cobos Álvarez Differential Revision: https://phabricator.services.mozilla.com/D156742 --- layout/style/nsStyleStruct.cpp | 52 +++ modules/libpref/init/StaticPrefList.yaml | 7 + .../style/values/computed/length.rs | 11 +- .../values/computed/length_percentage.rs | 28 +- .../style/values/computed/percentage.rs | 24 ++ .../components/style/values/generics/calc.rs | 369 +++++++++++++++++- .../components/style/values/specified/calc.rs | 101 ++++- .../style/values/specified/length.rs | 234 ++++++----- .../css/css-values/round-function.html.ini | 185 --------- .../round-mod-rem-computed.html.ini | 107 ----- .../round-mod-rem-serialize.html.ini | 11 - .../tests/css/css-values/round-function.html | 14 +- .../css-values/round-mod-rem-computed.html | 26 +- 13 files changed, 732 insertions(+), 437 deletions(-) delete mode 100644 testing/web-platform/meta/css/css-values/round-function.html.ini diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index f1e313aa8bb1..2fbbbe159dea 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -3538,6 +3538,12 @@ void StyleCalcNode::ScaleLengthsBy(float aScale) { ScaleNode(*clamp.max); break; } + case Tag::Round: { + const auto& round = AsRound(); + ScaleNode(*round.value); + ScaleNode(*round.step); + break; + } case Tag::MinMax: { for (auto& child : AsMinMax()._0.AsSpan()) { ScaleNode(child); @@ -3580,6 +3586,52 @@ ResultT StyleCalcNode::ResolveInternal(ResultT aPercentageBasis, auto max = clamp.max->ResolveInternal(aPercentageBasis, aConverter); return std::max(min, std::min(center, max)); } + case Tag::Round: { + const auto& round = AsRound(); + + // Make sure to do the math in CSS pixels, so that floor() and ceil() + // below round to an integer number of CSS pixels, not app units. + CSSCoord step, value; + if constexpr (std::is_same_v) { + step = round.step->ResolveInternal(aPercentageBasis, aConverter); + value = round.value->ResolveInternal(aPercentageBasis, aConverter); + } else { + step = CSSPixel::FromAppUnits( + round.step->ResolveInternal(aPercentageBasis, aConverter)); + value = CSSPixel::FromAppUnits( + round.value->ResolveInternal(aPercentageBasis, aConverter)); + } + + const float div = value / step; + const CSSCoord lowerBound = std::floor(div) * step; + const CSSCoord upperBound = std::ceil(div) * step; + const CSSCoord result = [&] { + switch (round.strategy) { + case StyleRoundingStrategy::Nearest: + // In case of a tie, use the upper bound + if (value - lowerBound < upperBound - value) { + return lowerBound; + } + return upperBound; + case StyleRoundingStrategy::Up: + return upperBound; + case StyleRoundingStrategy::Down: + return lowerBound; + case StyleRoundingStrategy::ToZero: + // In case of a tie, use the upper bound + return std::abs(lowerBound) < std::abs(upperBound) ? lowerBound + : upperBound; + } + MOZ_ASSERT_UNREACHABLE("Unknown rounding strategy"); + return CSSCoord(0); + }(); + + if constexpr (std::is_same_v) { + return result; + } else { + return CSSPixel::ToAppUnits(result); + } + } case Tag::MinMax: { auto children = AsMinMax()._0.AsSpan(); StyleMinMaxOp op = AsMinMax()._1; diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index fa211f062173..64b9bea055d6 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -7940,6 +7940,13 @@ mirror: always rust: true +# Whether the round() function is enabled in calc(). +- name: layout.css.round.enabled + type: RelaxedAtomicBool + value: @IS_NIGHTLY_BUILD@ + mirror: always + rust: true + # Whether infinity / nan constants are enabled in calc(). - name: layout.css.nan-inf.enabled type: RelaxedAtomicBool diff --git a/servo/components/style/values/computed/length.rs b/servo/components/style/values/computed/length.rs index 12e8bbdf416e..526691bdef8e 100644 --- a/servo/components/style/values/computed/length.rs +++ b/servo/components/style/values/computed/length.rs @@ -17,7 +17,7 @@ use crate::values::{specified, CSSFloat}; use crate::Zero; use app_units::Au; use std::fmt::{self, Write}; -use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub}; +use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Rem, Sub}; use style_traits::{CSSPixel, CssWriter, ToCss}; pub use super::image::Image; @@ -402,6 +402,15 @@ impl Neg for CSSPixelLength { } } +impl Rem for CSSPixelLength { + type Output = Self; + + #[inline] + fn rem(self, other: Self) -> Self { + CSSPixelLength::new(self.0 % other.0) + } +} + impl Sub for CSSPixelLength { type Output = Self; diff --git a/servo/components/style/values/computed/length_percentage.rs b/servo/components/style/values/computed/length_percentage.rs index 21e0a4b0cfb4..0afa1014d92f 100644 --- a/servo/components/style/values/computed/length_percentage.rs +++ b/servo/components/style/values/computed/length_percentage.rs @@ -624,10 +624,10 @@ impl PartialOrd for CalcLengthPercentageLeaf { } impl calc::CalcNodeLeaf for CalcLengthPercentageLeaf { - fn is_negative(&self) -> bool { + fn unitless_value(&self) -> f32 { match *self { - Self::Length(ref l) => l.px() < 0., - Self::Percentage(ref p) => p.0 < 0., + Self::Length(ref l) => l.px(), + Self::Percentage(ref p) => p.0, } } @@ -657,6 +657,28 @@ impl calc::CalcNodeLeaf for CalcLengthPercentageLeaf { Ok(()) } + fn try_op(&self, other: &Self, op: O) -> Result + where + O: Fn(f32, f32) -> f32, + { + match (self, other) { + ( + &CalcLengthPercentageLeaf::Length(ref one), + &CalcLengthPercentageLeaf::Length(ref other), + ) => Ok(CalcLengthPercentageLeaf::Length(Length::new(op( + one.px(), + other.px(), + )))), + ( + &CalcLengthPercentageLeaf::Percentage(one), + &CalcLengthPercentageLeaf::Percentage(other), + ) => Ok(CalcLengthPercentageLeaf::Percentage(Percentage(op( + one.0, other.0, + )))), + _ => Err(()), + } + } + fn mul_by(&mut self, scalar: f32) { match *self { Self::Length(ref mut l) => *l = *l * scalar, diff --git a/servo/components/style/values/computed/percentage.rs b/servo/components/style/values/computed/percentage.rs index 4e9732ade2cf..30ef5ab0f0d4 100644 --- a/servo/components/style/values/computed/percentage.rs +++ b/servo/components/style/values/computed/percentage.rs @@ -77,6 +77,30 @@ impl std::ops::AddAssign for Percentage { } } +impl std::ops::Add for Percentage { + type Output = Self; + + fn add(self, other: Self) -> Self { + Percentage(self.0 + other.0) + } +} + +impl std::ops::Sub for Percentage { + type Output = Self; + + fn sub(self, other: Self) -> Self { + Percentage(self.0 - other.0) + } +} + +impl std::ops::Rem for Percentage { + type Output = Self; + + fn rem(self, other: Self) -> Self { + Percentage(self.0 % other.0) + } +} + impl ToCss for Percentage { fn to_css(&self, dest: &mut CssWriter) -> fmt::Result where diff --git a/servo/components/style/values/generics/calc.rs b/servo/components/style/values/generics/calc.rs index 301ffb5cd62d..91941a6b71bb 100644 --- a/servo/components/style/values/generics/calc.rs +++ b/servo/components/style/values/generics/calc.rs @@ -6,10 +6,10 @@ //! //! [calc]: https://drafts.csswg.org/css-values/#calc-notation -use crate::Zero; +use num_traits::{Float, Zero}; use smallvec::SmallVec; use std::fmt::{self, Write}; -use std::ops::Add; +use std::ops::{Add, Div, Mul, Rem, Sub}; use std::{cmp, mem}; use style_traits::{CssWriter, ToCss}; @@ -34,6 +34,35 @@ pub enum MinMaxOp { Max, } +/// The strategy used in `round()` +#[derive( + Clone, + Copy, + Debug, + Deserialize, + MallocSizeOf, + PartialEq, + Serialize, + ToAnimatedZero, + ToResolvedValue, + ToShmem, +)] +#[repr(u8)] +pub enum RoundingStrategy { + /// `round(nearest, a, b)` + /// round a to the nearest multiple of b + Nearest, + /// `round(up, a, b)` + /// round a up to the nearest multiple of b + Up, + /// `round(down, a, b)` + /// round a down to the nearest multiple of b + Down, + /// `round(to-zero, a, b)` + /// round a to the nearest multiple of b that is towards zero + ToZero, +} + /// This determines the order in which we serialize members of a calc() sum. /// /// See https://drafts.csswg.org/css-values-4/#sort-a-calculations-children @@ -124,18 +153,52 @@ pub enum GenericCalcNode { /// The maximum value. max: Box>, }, + /// A `round()` function. + Round { + /// The rounding strategy. + strategy: RoundingStrategy, + /// The value to round. + value: Box>, + /// The step value. + step: Box>, + }, } pub use self::GenericCalcNode as CalcNode; /// A trait that represents all the stuff a valid leaf of a calc expression. pub trait CalcNodeLeaf: Clone + Sized + PartialOrd + PartialEq + ToCss { + /// Returns the unitless value of this leaf. + fn unitless_value(&self) -> f32; + /// Whether this value is known-negative. - fn is_negative(&self) -> bool; + fn is_negative(&self) -> bool { + self.unitless_value().is_sign_negative() + } + + /// Whether this value is infinite. + fn is_infinite(&self) -> bool { + self.unitless_value().is_infinite() + } + + /// Whether this value is zero. + fn is_zero(&self) -> bool { + self.unitless_value().is_zero() + } + + /// Whether this value is NaN. + fn is_nan(&self) -> bool { + self.unitless_value().is_nan() + } /// Tries to merge one sum to another, that is, perform `x` + `y`. fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()>; + /// Tries a generic arithmetic operation. + fn try_op(&self, other: &Self, op: O) -> Result + where + O: Fn(f32, f32) -> f32; + /// Multiplies the leaf by a given scalar number. fn mul_by(&mut self, scalar: f32); @@ -182,6 +245,19 @@ impl CalcNode { } } + /// Tries to apply a generic arithmentic operator + fn try_op(&self, other: &Self, op: O) -> Result + where + O: Fn(f32, f32) -> f32, + { + match (self, other) { + (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => { + Ok(CalcNode::Leaf(one.try_op(other, op)?)) + }, + _ => Err(()), + } + } + /// Convert this `CalcNode` into a `CalcNode` with a different leaf kind. pub fn map_leaves(&self, mut map: F) -> CalcNode where @@ -225,6 +301,19 @@ impl CalcNode { let max = Box::new(max.map_leaves_internal(map)); CalcNode::Clamp { min, center, max } }, + Self::Round { + strategy, + ref value, + ref step, + } => { + let value = Box::new(value.map_leaves_internal(map)); + let step = Box::new(step.map_leaves_internal(map)); + CalcNode::Round { + strategy, + value, + step, + } + }, } } @@ -235,14 +324,30 @@ impl CalcNode { mut leaf_to_output_fn: impl FnMut(&L) -> Result, ) -> Result where - O: PartialOrd + PartialEq + Add + Zero, + O: PartialOrd + + PartialEq + + Add + + Mul + + Div + + Sub + + Zero + + Float + + Copy, { self.resolve_internal(&mut leaf_to_output_fn) } fn resolve_internal(&self, leaf_to_output_fn: &mut F) -> Result where - O: PartialOrd + PartialEq + Add + Zero, + O: PartialOrd + + PartialEq + + Add + + Mul + + Div + + Sub + + Zero + + Float + + Copy, F: FnMut(&L) -> Result, { Ok(match *self { @@ -286,6 +391,84 @@ impl CalcNode { } result }, + Self::Round { + strategy, + ref value, + ref step, + } => { + let value = value.resolve_internal(leaf_to_output_fn)?; + let step = step.resolve_internal(leaf_to_output_fn)?; + + // TODO(emilio): Seems like at least a few of these + // special-cases could be removed if we do the math in a + // particular order. + if step.is_zero() { + return Ok(::nan()); + } + + if value.is_infinite() && step.is_infinite() { + return Ok(::nan()); + } + + if value.is_infinite() { + return Ok(value); + } + + if step.is_infinite() { + match strategy { + RoundingStrategy::Nearest | RoundingStrategy::ToZero => { + return if value.is_sign_negative() { + Ok(::neg_zero()) + } else { + Ok(::zero()) + } + }, + RoundingStrategy::Up => { + return if !value.is_sign_negative() && !value.is_zero() { + Ok(::infinity()) + } else if !value.is_sign_negative() && value.is_zero() { + Ok(value) + } else { + Ok(::neg_zero()) + } + }, + RoundingStrategy::Down => { + return if value.is_sign_negative() && !value.is_zero() { + Ok(::neg_infinity()) + } else if value.is_sign_negative() && value.is_zero() { + Ok(value) + } else { + Ok(::zero()) + } + }, + } + } + + let div = value / step; + let lower_bound = div.floor() * step; + let upper_bound = div.ceil() * step; + + match strategy { + RoundingStrategy::Nearest => { + // In case of a tie, use the upper bound + if value - lower_bound < upper_bound - value { + lower_bound + } else { + upper_bound + } + }, + RoundingStrategy::Up => upper_bound, + RoundingStrategy::Down => lower_bound, + RoundingStrategy::ToZero => { + // In case of a tie, use the upper bound + if lower_bound.abs() < upper_bound.abs() { + lower_bound + } else { + upper_bound + } + }, + } + }, }) } @@ -296,6 +479,20 @@ impl CalcNode { } } + fn is_zero_leaf(&self) -> bool { + match *self { + Self::Leaf(ref l) => l.is_zero(), + _ => false, + } + } + + fn is_infinite_leaf(&self) -> bool { + match *self { + Self::Leaf(ref l) => l.is_infinite(), + _ => false, + } + } + /// Multiplies the node by a scalar. pub fn mul_by(&mut self, scalar: f32) { match *self { @@ -334,6 +531,14 @@ impl CalcNode { mem::swap(min, max); } }, + Self::Round { + ref mut value, + ref mut step, + .. + } => { + value.mul_by(scalar); + step.mul_by(scalar); + }, } } @@ -357,6 +562,14 @@ impl CalcNode { center.visit_depth_first_internal(f); max.visit_depth_first_internal(f); }, + Self::Round { + ref mut value, + ref mut step, + .. + } => { + value.visit_depth_first_internal(f); + step.visit_depth_first_internal(f); + }, Self::Sum(ref mut children) | Self::MinMax(ref mut children, _) => { for child in &mut **children { child.visit_depth_first_internal(f); @@ -432,6 +645,133 @@ impl CalcNode { // Otherwise we're the center node. return replace_self_with!(&mut **center); }, + Self::Round { + strategy, + ref mut value, + ref mut step, + } => { + if step.is_zero_leaf() { + value.mul_by(f32::NAN); + return replace_self_with!(&mut **value); + } + + if value.is_infinite_leaf() && step.is_infinite_leaf() { + value.mul_by(f32::NAN); + return replace_self_with!(&mut **value); + } + + if value.is_infinite_leaf() { + return replace_self_with!(&mut **value); + } + + if step.is_infinite_leaf() { + match strategy { + RoundingStrategy::Nearest | RoundingStrategy::ToZero => { + value.mul_by(0.); + return replace_self_with!(&mut **value); + }, + RoundingStrategy::Up => { + if !value.is_negative_leaf() && !value.is_zero_leaf() { + value.mul_by(f32::INFINITY); + return replace_self_with!(&mut **value); + } else if !value.is_negative_leaf() && value.is_zero_leaf() { + return replace_self_with!(&mut **value); + } else { + value.mul_by(0.); + return replace_self_with!(&mut **value); + } + }, + RoundingStrategy::Down => { + if value.is_negative_leaf() && !value.is_zero_leaf() { + value.mul_by(f32::INFINITY); + return replace_self_with!(&mut **value); + } else if value.is_negative_leaf() && value.is_zero_leaf() { + return replace_self_with!(&mut **value); + } else { + value.mul_by(0.); + return replace_self_with!(&mut **value); + } + }, + } + } + + if step.is_negative_leaf() { + step.negate(); + } + + let remainder = match value.try_op(step, Rem::rem) { + Ok(res) => res, + Err(..) => return, + }; + + let (mut lower_bound, mut upper_bound) = if value.is_negative_leaf() { + let upper_bound = match value.try_op(&remainder, Sub::sub) { + Ok(res) => res, + Err(..) => return, + }; + + let lower_bound = match upper_bound.try_op(&step, Sub::sub) { + Ok(res) => res, + Err(..) => return, + }; + + (lower_bound, upper_bound) + } else { + let lower_bound = match value.try_op(&remainder, Sub::sub) { + Ok(res) => res, + Err(..) => return, + }; + + let upper_bound = match lower_bound.try_op(&step, Add::add) { + Ok(res) => res, + Err(..) => return, + }; + + (lower_bound, upper_bound) + }; + + match strategy { + RoundingStrategy::Nearest => { + let lower_diff = match value.try_op(&lower_bound, Sub::sub) { + Ok(res) => res, + Err(..) => return, + }; + + let upper_diff = match upper_bound.try_op(value, Sub::sub) { + Ok(res) => res, + Err(..) => return, + }; + + // In case of a tie, use the upper bound + if lower_diff < upper_diff { + return replace_self_with!(&mut lower_bound); + } else { + return replace_self_with!(&mut upper_bound); + } + }, + RoundingStrategy::Up => return replace_self_with!(&mut upper_bound), + RoundingStrategy::Down => return replace_self_with!(&mut lower_bound), + RoundingStrategy::ToZero => { + let mut lower_diff = lower_bound.clone(); + let mut upper_diff = upper_bound.clone(); + + if lower_diff.is_negative_leaf() { + lower_diff.negate(); + } + + if upper_diff.is_negative_leaf() { + upper_diff.negate(); + } + + // In case of a tie, use the upper bound + if lower_diff < upper_diff { + return replace_self_with!(&mut lower_bound); + } else { + return replace_self_with!(&mut upper_bound); + } + }, + }; + }, Self::MinMax(ref mut children, op) => { let winning_order = match op { MinMaxOp::Min => cmp::Ordering::Less, @@ -537,6 +877,16 @@ impl CalcNode { dest.write_str("clamp(")?; true }, + Self::Round { strategy, .. } => { + match strategy { + RoundingStrategy::Nearest => dest.write_str("round("), + RoundingStrategy::Up => dest.write_str("round(up, "), + RoundingStrategy::Down => dest.write_str("round(down, "), + RoundingStrategy::ToZero => dest.write_str("round(to-zero, "), + }?; + + true + }, _ => { if is_outermost { dest.write_str("calc(")?; @@ -586,6 +936,15 @@ impl CalcNode { dest.write_str(", ")?; max.to_css_impl(dest, false)?; }, + Self::Round { + ref value, + ref step, + .. + } => { + value.to_css_impl(dest, false)?; + dest.write_str(", ")?; + step.to_css_impl(dest, false)?; + }, Self::Leaf(ref l) => l.to_css(dest)?, } diff --git a/servo/components/style/values/specified/calc.rs b/servo/components/style/values/specified/calc.rs index 52c6b23b6a5c..b6ab4a82f9b9 100644 --- a/servo/components/style/values/specified/calc.rs +++ b/servo/components/style/values/specified/calc.rs @@ -8,7 +8,7 @@ use crate::parser::ParserContext; use crate::values::generics::calc as generic; -use crate::values::generics::calc::{MinMaxOp, SortKey}; +use crate::values::generics::calc::{MinMaxOp, RoundingStrategy, SortKey}; use crate::values::specified::length::{AbsoluteLength, FontRelativeLength, NoCalcLength}; use crate::values::specified::length::{ContainerRelativeLength, ViewportPercentageLength}; use crate::values::specified::{self, Angle, Time}; @@ -39,6 +39,8 @@ pub enum MathFunction { Max, /// `clamp()`: https://drafts.csswg.org/css-values-4/#funcdef-clamp Clamp, + /// `round()`: https://drafts.csswg.org/css-values-4/#funcdef-round + Round, /// `sin()`: https://drafts.csswg.org/css-values-4/#funcdef-sin Sin, /// `cos()`: https://drafts.csswg.org/css-values-4/#funcdef-cos @@ -179,12 +181,12 @@ impl PartialOrd for Leaf { } impl generic::CalcNodeLeaf for Leaf { - fn is_negative(&self) -> bool { + fn unitless_value(&self) -> f32 { match *self { - Self::Length(ref l) => l.is_negative(), - Self::Percentage(n) | Self::Number(n) => n < 0., - Self::Angle(ref a) => a.degrees() < 0., - Self::Time(ref t) => t.seconds() < 0., + Self::Length(ref l) => l.unitless_value(), + Self::Percentage(n) | Self::Number(n) => n, + Self::Angle(ref a) => a.degrees(), + Self::Time(ref t) => t.seconds(), } } @@ -294,7 +296,7 @@ impl generic::CalcNodeLeaf for Leaf { *one = specified::Time::from_calc(one.seconds() + other.seconds()); }, (&mut Length(ref mut one), &Length(ref other)) => { - *one = one.try_sum(other)?; + *one = one.try_op(other, std::ops::Add::add)?; }, _ => { match *other { @@ -308,6 +310,49 @@ impl generic::CalcNodeLeaf for Leaf { Ok(()) } + + fn try_op(&self, other: &Self, op: O) -> Result + where + O: Fn(f32, f32) -> f32, + { + use self::Leaf::*; + + if std::mem::discriminant(self) != std::mem::discriminant(other) { + return Err(()); + } + + match (self, other) { + (&Number(one), &Number(other)) => { + return Ok(Leaf::Number(op(one, other))); + }, + (&Percentage(one), &Percentage(other)) => { + return Ok(Leaf::Percentage(op(one, other))); + }, + (&Angle(ref one), &Angle(ref other)) => { + return Ok(Leaf::Angle(specified::Angle::from_calc(op( + one.degrees(), + other.degrees(), + )))); + }, + (&Time(ref one), &Time(ref other)) => { + return Ok(Leaf::Time(specified::Time::from_calc(op( + one.seconds(), + other.seconds(), + )))); + }, + (&Length(ref one), &Length(ref other)) => { + return Ok(Leaf::Length(one.try_op(other, op)?)); + }, + _ => { + match *other { + Number(..) | Percentage(..) | Angle(..) | Time(..) | Length(..) => {}, + } + unsafe { + debug_unreachable!(); + } + }, + } + } } /// A calc node representation for specified values. @@ -402,6 +447,36 @@ impl CalcNode { max: Box::new(max), }) }, + MathFunction::Round => { + let strategy = input.try_parse(parse_rounding_strategy); + + // = nearest | up | down | to-zero + // https://drafts.csswg.org/css-values-4/#calc-syntax + fn parse_rounding_strategy<'i, 't>( + input: &mut Parser<'i, 't>, + ) -> Result> { + Ok(try_match_ident_ignore_ascii_case! { input, + "nearest" => RoundingStrategy::Nearest, + "up" => RoundingStrategy::Up, + "down" => RoundingStrategy::Down, + "to-zero" => RoundingStrategy::ToZero, + }) + } + + if strategy.is_ok() { + input.expect_comma()?; + } + + let value = Self::parse_argument(context, input, allowed_units)?; + input.expect_comma()?; + let step = Self::parse_argument(context, input, allowed_units)?; + + Ok(Self::Round { + strategy: strategy.unwrap_or(RoundingStrategy::Nearest), + value: Box::new(value), + step: Box::new(step), + }) + }, MathFunction::Min | MathFunction::Max => { // TODO(emilio): The common case for parse_comma_separated // is just one element, but for min / max is two, really... @@ -688,9 +763,15 @@ impl CalcNode { }, }; - if matches!(function, Sin | Cos | Tan | Asin | Acos | Atan | Atan2) && - !static_prefs::pref!("layout.css.trig.enabled") - { + let enabled = if matches!(function, Sin | Cos | Tan | Asin | Acos | Atan | Atan2) { + trig_enabled() + } else if matches!(function, Round) { + static_prefs::pref!("layout.css.round.enabled") + } else { + true + }; + + if !enabled { return Err(location.new_unexpected_token_error(Token::Function(name.clone()))); } diff --git a/servo/components/style/values/specified/length.rs b/servo/components/style/values/specified/length.rs index ff36ebc4a55f..f0ac2e46b7ed 100644 --- a/servo/components/style/values/specified/length.rs +++ b/servo/components/style/values/specified/length.rs @@ -22,7 +22,7 @@ use crate::{Zero, ZeroNoPercent}; use app_units::Au; use cssparser::{Parser, Token}; use std::cmp; -use std::ops::{Add, Mul}; +use std::ops::{Add, Mul, Rem, Sub}; use style_traits::values::specified::AllowedNumericType; use style_traits::{ParseError, SpecifiedValueInfo, StyleParseErrorKind}; @@ -88,11 +88,6 @@ impl FontBaseSize { } impl FontRelativeLength { - /// Return true if this is a zero value. - fn is_zero(&self) -> bool { - self.unitless_value() == 0. - } - /// Return the unitless, raw value. fn unitless_value(&self) -> CSSFloat { match *self { @@ -105,11 +100,10 @@ impl FontRelativeLength { } } - fn is_negative(&self) -> bool { - self.unitless_value() < 0. - } - - fn try_sum(&self, other: &Self) -> Result { + fn try_op(&self, other: &Self, op: O) -> Result + where + O: Fn(f32, f32) -> f32, + { use self::FontRelativeLength::*; if std::mem::discriminant(self) != std::mem::discriminant(other) { @@ -117,19 +111,19 @@ impl FontRelativeLength { } Ok(match (self, other) { - (&Em(one), &Em(other)) => Em(one + other), - (&Ex(one), &Ex(other)) => Ex(one + other), - (&Ch(one), &Ch(other)) => Ch(one + other), - (&Cap(one), &Cap(other)) => Cap(one + other), - (&Ic(one), &Ic(other)) => Ic(one + other), - (&Rem(one), &Rem(other)) => Rem(one + other), + (&Em(one), &Em(other)) => Em(op(one, other)), + (&Ex(one), &Ex(other)) => Ex(op(one, other)), + (&Ch(one), &Ch(other)) => Ch(op(one, other)), + (&Cap(one), &Cap(other)) => Cap(op(one, other)), + (&Ic(one), &Ic(other)) => Ic(op(one, other)), + (&Rem(one), &Rem(other)) => Rem(op(one, other)), // See https://github.com/rust-lang/rust/issues/68867. rustc isn't // able to figure it own on its own so we help. _ => unsafe { match *self { Em(..) | Ex(..) | Ch(..) | Cap(..) | Ic(..) | Rem(..) => {}, } - debug_unreachable!("Forgot to handle unit in try_sum()") + debug_unreachable!("Forgot to handle unit in try_op()") }, }) } @@ -384,15 +378,6 @@ pub enum ViewportPercentageLength { } impl ViewportPercentageLength { - /// Return true if this is a zero value. - fn is_zero(&self) -> bool { - self.unitless_value() == 0. - } - - fn is_negative(&self) -> bool { - self.unitless_value() < 0. - } - /// Return the unitless, raw value. fn unitless_value(&self) -> CSSFloat { self.unpack().2 @@ -431,7 +416,10 @@ impl ViewportPercentageLength { } } - fn try_sum(&self, other: &Self) -> Result { + fn try_op(&self, other: &Self, op: O) -> Result + where + O: Fn(f32, f32) -> f32, + { use self::ViewportPercentageLength::*; if std::mem::discriminant(self) != std::mem::discriminant(other) { @@ -439,30 +427,30 @@ impl ViewportPercentageLength { } Ok(match (self, other) { - (&Vw(one), &Vw(other)) => Vw(one + other), - (&Svw(one), &Svw(other)) => Svw(one + other), - (&Lvw(one), &Lvw(other)) => Lvw(one + other), - (&Dvw(one), &Dvw(other)) => Dvw(one + other), - (&Vh(one), &Vh(other)) => Vh(one + other), - (&Svh(one), &Svh(other)) => Svh(one + other), - (&Lvh(one), &Lvh(other)) => Lvh(one + other), - (&Dvh(one), &Dvh(other)) => Dvh(one + other), - (&Vmin(one), &Vmin(other)) => Vmin(one + other), - (&Svmin(one), &Svmin(other)) => Svmin(one + other), - (&Lvmin(one), &Lvmin(other)) => Lvmin(one + other), - (&Dvmin(one), &Dvmin(other)) => Dvmin(one + other), - (&Vmax(one), &Vmax(other)) => Vmax(one + other), - (&Svmax(one), &Svmax(other)) => Svmax(one + other), - (&Lvmax(one), &Lvmax(other)) => Lvmax(one + other), - (&Dvmax(one), &Dvmax(other)) => Dvmax(one + other), - (&Vb(one), &Vb(other)) => Vb(one + other), - (&Svb(one), &Svb(other)) => Svb(one + other), - (&Lvb(one), &Lvb(other)) => Lvb(one + other), - (&Dvb(one), &Dvb(other)) => Dvb(one + other), - (&Vi(one), &Vi(other)) => Vi(one + other), - (&Svi(one), &Svi(other)) => Svi(one + other), - (&Lvi(one), &Lvi(other)) => Lvi(one + other), - (&Dvi(one), &Dvi(other)) => Dvi(one + other), + (&Vw(one), &Vw(other)) => Vw(op(one, other)), + (&Svw(one), &Svw(other)) => Svw(op(one, other)), + (&Lvw(one), &Lvw(other)) => Lvw(op(one, other)), + (&Dvw(one), &Dvw(other)) => Dvw(op(one, other)), + (&Vh(one), &Vh(other)) => Vh(op(one, other)), + (&Svh(one), &Svh(other)) => Svh(op(one, other)), + (&Lvh(one), &Lvh(other)) => Lvh(op(one, other)), + (&Dvh(one), &Dvh(other)) => Dvh(op(one, other)), + (&Vmin(one), &Vmin(other)) => Vmin(op(one, other)), + (&Svmin(one), &Svmin(other)) => Svmin(op(one, other)), + (&Lvmin(one), &Lvmin(other)) => Lvmin(op(one, other)), + (&Dvmin(one), &Dvmin(other)) => Dvmin(op(one, other)), + (&Vmax(one), &Vmax(other)) => Vmax(op(one, other)), + (&Svmax(one), &Svmax(other)) => Svmax(op(one, other)), + (&Lvmax(one), &Lvmax(other)) => Lvmax(op(one, other)), + (&Dvmax(one), &Dvmax(other)) => Dvmax(op(one, other)), + (&Vb(one), &Vb(other)) => Vb(op(one, other)), + (&Svb(one), &Svb(other)) => Svb(op(one, other)), + (&Lvb(one), &Lvb(other)) => Lvb(op(one, other)), + (&Dvb(one), &Dvb(other)) => Dvb(op(one, other)), + (&Vi(one), &Vi(other)) => Vi(op(one, other)), + (&Svi(one), &Svi(other)) => Svi(op(one, other)), + (&Lvi(one), &Lvi(other)) => Lvi(op(one, other)), + (&Dvi(one), &Dvi(other)) => Dvi(op(one, other)), // See https://github.com/rust-lang/rust/issues/68867. rustc isn't // able to figure it own on its own so we help. _ => unsafe { @@ -472,7 +460,7 @@ impl ViewportPercentageLength { Svmax(..) | Lvmax(..) | Dvmax(..) | Vb(..) | Svb(..) | Lvb(..) | Dvb(..) | Vi(..) | Svi(..) | Lvi(..) | Dvi(..) => {}, } - debug_unreachable!("Forgot to handle unit in try_sum()") + debug_unreachable!("Forgot to handle unit in try_op()") }, }) } @@ -564,14 +552,6 @@ impl AbsoluteLength { } } - fn is_zero(&self) -> bool { - self.unitless_value() == 0. - } - - fn is_negative(&self) -> bool { - self.unitless_value() < 0. - } - /// Convert this into a pixel value. #[inline] pub fn to_px(&self) -> CSSFloat { @@ -588,6 +568,22 @@ impl AbsoluteLength { }; pixel.min(f32::MAX).max(f32::MIN) } + + fn try_op(&self, other: &Self, op: O) -> Result + where + O: Fn(f32, f32) -> f32, + { + Ok(match (self, other) { + (AbsoluteLength::Px(x), AbsoluteLength::Px(y)) => AbsoluteLength::Px(op(*x, *y)), + (AbsoluteLength::In(x), AbsoluteLength::In(y)) => AbsoluteLength::In(op(*x, *y)), + (AbsoluteLength::Cm(x), AbsoluteLength::Cm(y)) => AbsoluteLength::Cm(op(*x, *y)), + (AbsoluteLength::Mm(x), AbsoluteLength::Mm(y)) => AbsoluteLength::Mm(op(*x, *y)), + (AbsoluteLength::Q(x), AbsoluteLength::Q(y)) => AbsoluteLength::Q(op(*x, *y)), + (AbsoluteLength::Pt(x), AbsoluteLength::Pt(y)) => AbsoluteLength::Pt(op(*x, *y)), + (AbsoluteLength::Pc(x), AbsoluteLength::Pc(y)) => AbsoluteLength::Pc(op(*x, *y)), + _ => AbsoluteLength::Px(op(self.to_px(), other.to_px())), + }) + } } impl ToComputedValue for AbsoluteLength { @@ -680,15 +676,10 @@ impl ContainerRelativeLength { } } - fn is_zero(&self) -> bool { - self.unitless_value() == 0. - } - - fn is_negative(&self) -> bool { - self.unitless_value() < 0. - } - - fn try_sum(&self, other: &Self) -> Result { + pub(crate) fn try_op(&self, other: &Self, op: O) -> Result + where + O: Fn(f32, f32) -> f32, + { use self::ContainerRelativeLength::*; if std::mem::discriminant(self) != std::mem::discriminant(other) { @@ -696,12 +687,12 @@ impl ContainerRelativeLength { } Ok(match (self, other) { - (&Cqw(one), &Cqw(other)) => Cqw(one + other), - (&Cqh(one), &Cqh(other)) => Cqh(one + other), - (&Cqi(one), &Cqi(other)) => Cqi(one + other), - (&Cqb(one), &Cqb(other)) => Cqb(one + other), - (&Cqmin(one), &Cqmin(other)) => Cqmin(one + other), - (&Cqmax(one), &Cqmax(other)) => Cqmax(one + other), + (&Cqw(one), &Cqw(other)) => Cqw(op(one, other)), + (&Cqh(one), &Cqh(other)) => Cqh(op(one, other)), + (&Cqi(one), &Cqi(other)) => Cqi(op(one, other)), + (&Cqb(one), &Cqb(other)) => Cqb(op(one, other)), + (&Cqmin(one), &Cqmin(other)) => Cqmin(op(one, other)), + (&Cqmax(one), &Cqmax(other)) => Cqmax(op(one, other)), // See https://github.com/rust-lang/rust/issues/68867, then // https://github.com/rust-lang/rust/pull/95161. rustc isn't @@ -710,7 +701,7 @@ impl ContainerRelativeLength { match *self { Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {}, } - debug_unreachable!("Forgot to handle unit in try_sum()") + debug_unreachable!("Forgot to handle unit in try_op()") }, }) } @@ -751,6 +742,42 @@ fn are_container_queries_enabled() -> bool { false } +impl Sub for AbsoluteLength { + type Output = Self; + + #[inline] + fn sub(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()), + } + } +} + +impl Rem for AbsoluteLength { + type Output = Self; + + #[inline] + fn rem(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 `` without taking `calc` expressions into account /// /// @@ -812,13 +839,22 @@ impl NoCalcLength { /// Returns whether the value of this length without unit is less than zero. pub fn is_negative(&self) -> bool { - match *self { - NoCalcLength::Absolute(v) => v.is_negative(), - NoCalcLength::FontRelative(v) => v.is_negative(), - NoCalcLength::ViewportPercentage(v) => v.is_negative(), - NoCalcLength::ContainerRelative(v) => v.is_negative(), - NoCalcLength::ServoCharacterWidth(c) => c.0 < 0, - } + self.unitless_value().is_sign_negative() + } + + /// Returns whether the value of this length without unit is equal to zero. + pub fn is_zero(&self) -> bool { + self.unitless_value() == 0.0 + } + + /// Returns whether the value of this length without unit is infinite. + pub fn is_infinite(&self) -> bool { + self.unitless_value().is_infinite() + } + + /// Returns whether the value of this length without unit is NaN. + pub fn is_nan(&self) -> bool { + self.unitless_value().is_nan() } /// Whether text-only zoom should be applied to this length. @@ -953,8 +989,10 @@ impl NoCalcLength { }) } - /// Try to sume two lengths if compatible into the left hand side. - pub(crate) fn try_sum(&self, other: &Self) -> Result { + pub(crate) fn try_op(&self, other: &Self, op: O) -> Result + where + O: Fn(f32, f32) -> f32, + { use self::NoCalcLength::*; if std::mem::discriminant(self) != std::mem::discriminant(other) { @@ -962,16 +1000,18 @@ impl NoCalcLength { } Ok(match (self, other) { - (&Absolute(ref one), &Absolute(ref other)) => Absolute(*one + *other), - (&FontRelative(ref one), &FontRelative(ref other)) => FontRelative(one.try_sum(other)?), + (&Absolute(ref one), &Absolute(ref other)) => Absolute(one.try_op(other, op)?), + (&FontRelative(ref one), &FontRelative(ref other)) => { + FontRelative(one.try_op(other, op)?) + }, (&ViewportPercentage(ref one), &ViewportPercentage(ref other)) => { - ViewportPercentage(one.try_sum(other)?) + ViewportPercentage(one.try_op(other, op)?) }, (&ContainerRelative(ref one), &ContainerRelative(ref other)) => { - ContainerRelative(one.try_sum(other)?) + ContainerRelative(one.try_op(other, op)?) }, (&ServoCharacterWidth(ref one), &ServoCharacterWidth(ref other)) => { - ServoCharacterWidth(CharacterWidth(one.0 + other.0)) + ServoCharacterWidth(CharacterWidth(op(one.0 as f32, other.0 as f32) as i32)) }, // See https://github.com/rust-lang/rust/issues/68867. rustc isn't // able to figure it own on its own so we help. @@ -983,7 +1023,7 @@ impl NoCalcLength { ContainerRelative(..) | ServoCharacterWidth(..) => {}, } - debug_unreachable!("Forgot to handle unit in try_sum()") + debug_unreachable!("Forgot to handle unit in try_op()") }, }) } @@ -1046,13 +1086,7 @@ impl Zero for NoCalcLength { } fn is_zero(&self) -> bool { - match *self { - NoCalcLength::Absolute(v) => v.is_zero(), - NoCalcLength::FontRelative(v) => v.is_zero(), - NoCalcLength::ViewportPercentage(v) => v.is_zero(), - NoCalcLength::ContainerRelative(v) => v.is_zero(), - NoCalcLength::ServoCharacterWidth(v) => v.0 == 0, - } + NoCalcLength::is_zero(self) } } @@ -1171,7 +1205,7 @@ impl PartialOrd for ContainerRelativeLength { match *self { Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {}, } - debug_unreachable!("Forgot to handle unit in try_sum()") + debug_unreachable!("Forgot to handle unit in partial_cmp()") }, } } diff --git a/testing/web-platform/meta/css/css-values/round-function.html.ini b/testing/web-platform/meta/css/css-values/round-function.html.ini deleted file mode 100644 index 2f8c5c898302..000000000000 --- a/testing/web-platform/meta/css/css-values/round-function.html.ini +++ /dev/null @@ -1,185 +0,0 @@ -[round-function.html] - expected: - if (os == "android") and fission: [OK, TIMEOUT] - [round(15px, -10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(nearest, 15px, 10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(nearest, 13px, 10px) should be used-value-equivalent to 10px] - expected: FAIL - - [round(down, 18px, 10px) should be used-value-equivalent to 10px] - expected: FAIL - - [round(-18px, 10px) should be used-value-equivalent to -20px] - expected: FAIL - - [round(up, 18px, 10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(15px, 10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(down, 13px, 10px) should be used-value-equivalent to 10px] - expected: FAIL - - [round(23px, 10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(13px, 10px) should be used-value-equivalent to 10px] - expected: FAIL - - [round(down, -13px, 10px) should be used-value-equivalent to -20px] - expected: FAIL - - [round(13px, -10px) should be used-value-equivalent to 10px] - expected: FAIL - - [round(to-zero, 23px, 10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(down, 15px, 10px) should be used-value-equivalent to 10px] - expected: FAIL - - [round(up, -13px, 10px) should be used-value-equivalent to -10px] - expected: FAIL - - [round(to-zero, 13px, 10px) should be used-value-equivalent to 10px] - expected: FAIL - - [round(down, -18px, 10px) should be used-value-equivalent to -20px] - expected: FAIL - - [round(up, -18px, 10px) should be used-value-equivalent to -10px] - expected: FAIL - - [round(to-zero, -13px, 10px) should be used-value-equivalent to -10px] - expected: FAIL - - [round(18px, -10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(18px, 10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(up, 15px, 10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(23px, -10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(nearest, 23px, 10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(up, 13px, 10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(nearest, -18px, 10px) should be used-value-equivalent to -20px] - expected: FAIL - - [round(down, 23px, 10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(-13px, 10px) should be used-value-equivalent to -10px] - expected: FAIL - - [round(nearest, 18px, 10px) should be used-value-equivalent to 20px] - expected: FAIL - - [round(to-zero, 18px, 10px) should be used-value-equivalent to 10px] - expected: FAIL - - [round(-13px, -10px) should be used-value-equivalent to -10px] - expected: FAIL - - [round(to-zero, 15px, 10px) should be used-value-equivalent to 10px] - expected: FAIL - - [round(nearest, -13px, 10px) should be used-value-equivalent to -10px] - expected: FAIL - - [round(-18px, -10px) should be used-value-equivalent to -20px] - expected: FAIL - - [round(up, 23px, 10px) should be used-value-equivalent to 30px] - expected: FAIL - - [round(to-zero, -18px, 10px) should be used-value-equivalent to -10px] - expected: FAIL - - [round(infinity, 5) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [round(infinity, -5) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [round(-infinity, 5) should be used-value-equivalent to calc(-infinity)] - expected: FAIL - - [round(-infinity, -5) should be used-value-equivalent to calc(-infinity)] - expected: FAIL - - [calc(1 / round(5, infinity)) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [calc(1 / round(5, -infinity)) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [calc(1 / round(-5, infinity)) should be used-value-equivalent to calc(-infinity)] - expected: FAIL - - [calc(1 / round(-5, -infinity)) should be used-value-equivalent to calc(-infinity)] - expected: FAIL - - [calc(1 / round(to-zero, 5, infinity)) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [calc(1 / round(to-zero, 5, -infinity)) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [calc(1 / round(to-zero, -5, infinity)) should be used-value-equivalent to calc(-infinity)] - expected: FAIL - - [calc(1 / round(to-zero, -5, -infinity)) should be used-value-equivalent to calc(-infinity)] - expected: FAIL - - [round(up, 1, infinity) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [calc(1 / round(up, 0, infinity)) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [calc(1 / round(up, -1 * 0, infinity) should be used-value-equivalent to calc(-infinity)] - expected: FAIL - - [calc(1 / round(up, -1, infinity) should be used-value-equivalent to calc(-infinity)] - expected: FAIL - - [round(down, -1, infinity) should be used-value-equivalent to calc(-infinity)] - expected: FAIL - - [calc(1 / round(down, -1 * 0, infinity)) should be used-value-equivalent to calc(-infinity)] - expected: FAIL - - [calc(1 / round(down, 0, infinity)) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [calc(1 / round(down, 1, infinity)) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [round(-infinity, infinity) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [round(infinity, -infinity) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [round(5, 0) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [round(infinity, infinity) should be used-value-equivalent to calc(infinity)] - expected: FAIL - - [round(-infinity, -infinity) should be used-value-equivalent to calc(infinity)] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-values/round-mod-rem-computed.html.ini b/testing/web-platform/meta/css/css-values/round-mod-rem-computed.html.ini index b96ae3ac3fc1..e479fc8d5140 100644 --- a/testing/web-platform/meta/css/css-values/round-mod-rem-computed.html.ini +++ b/testing/web-platform/meta/css/css-values/round-mod-rem-computed.html.ini @@ -1,36 +1,10 @@ [round-mod-rem-computed.html] - expected: - if (os == "android") and fission: [OK, TIMEOUT] - [round(10,10) should be used-value-equivalent to 10] - expected: FAIL - [mod(1,1) should be used-value-equivalent to 0] expected: FAIL [rem(1,1) should be used-value-equivalent to 0] expected: FAIL - [calc(round(100,10)) should be used-value-equivalent to 100] - expected: FAIL - - [calc(round(up, 101,10)) should be used-value-equivalent to 110] - expected: FAIL - - [calc(round(down, 106,10)) should be used-value-equivalent to 100] - expected: FAIL - - [calc(round(to-zero,105, 10)) should be used-value-equivalent to 100] - expected: FAIL - - [calc(round(to-zero,-105, 10)) should be used-value-equivalent to 100] - expected: FAIL - - [calc(round(-100,10)) should be used-value-equivalent to -100] - expected: FAIL - - [calc(round(up, -103,10)) should be used-value-equivalent to -100] - expected: FAIL - [mod(18,5) should be used-value-equivalent to 3] expected: FAIL @@ -52,24 +26,6 @@ [rem(140,-90) should be used-value-equivalent to 50] expected: FAIL - [calc(round(round(100,10), 10)) should be used-value-equivalent to 100] - expected: FAIL - - [calc(round(up, round(100,10) + 1,10)) should be used-value-equivalent to 110] - expected: FAIL - - [calc(round(down, round(100,10) + 2 * 3,10)) should be used-value-equivalent to 100] - expected: FAIL - - [calc(round(to-zero,round(100,10) * 2 - 95, 10)) should be used-value-equivalent to 100] - expected: FAIL - - [calc(round(round(100,10)* -1,10)) should be used-value-equivalent to -100] - expected: FAIL - - [calc(round(up, -103 + -103 / -103 - 1,10)) should be used-value-equivalent to -100] - expected: FAIL - [calc(mod(18,5) * 2 + mod(17,5)) should be used-value-equivalent to 8] expected: FAIL @@ -85,63 +41,6 @@ [calc(mod(rem(1,18)* -1,5)) should be used-value-equivalent to -1] expected: FAIL - [round(10px,6px) should be used-value-equivalent to 12px] - expected: FAIL - - [round(10cm,6cm) should be used-value-equivalent to 12cm] - expected: FAIL - - [round(10mm,6mm) should be used-value-equivalent to 12mm] - expected: FAIL - - [round(10Q, 6Q) should be used-value-equivalent to 12Q] - expected: FAIL - - [round(10in,6in) should be used-value-equivalent to 12in] - expected: FAIL - - [round(10pc,6pc) should be used-value-equivalent to 12pc] - expected: FAIL - - [round(10pt,6pt) should be used-value-equivalent to 12pt] - expected: FAIL - - [round(10em,6em) should be used-value-equivalent to 12em] - expected: FAIL - - [round(10ex,6ex) should be used-value-equivalent to 12ex] - expected: FAIL - - [round(10ch,6ch) should be used-value-equivalent to 12ch] - expected: FAIL - - [round(10rem,6rem) should be used-value-equivalent to 12rem] - expected: FAIL - - [round(10vh,6vh) should be used-value-equivalent to 12vh] - expected: FAIL - - [round(10vw,6vw) should be used-value-equivalent to 12vw] - expected: FAIL - - [round(10vmin,6vmin) should be used-value-equivalent to 12vmin] - expected: FAIL - - [round(10vmax,6vmax) should be used-value-equivalent to 12vmax] - expected: FAIL - - [round(10deg,6deg) should be used-value-equivalent to 12deg] - expected: FAIL - - [round(10grad,6grad) should be used-value-equivalent to 12grad] - expected: FAIL - - [round(10rad,6rad) should be used-value-equivalent to 12rad] - expected: FAIL - - [round(10turn,6turn) should be used-value-equivalent to 12turn] - expected: FAIL - [mod(10px,6px) should be used-value-equivalent to 4px] expected: FAIL @@ -250,12 +149,6 @@ [rem(10turn,6turn) should be used-value-equivalent to 4turn] expected: FAIL - [round(10s,6s) should be used-value-equivalent to 12s] - expected: FAIL - - [round(10ms,6ms) should be used-value-equivalent to 12ms] - expected: FAIL - [mod(10s,6s) should be used-value-equivalent to 4s] expected: FAIL diff --git a/testing/web-platform/meta/css/css-values/round-mod-rem-serialize.html.ini b/testing/web-platform/meta/css/css-values/round-mod-rem-serialize.html.ini index e54ea4fc37e1..c9e2bfd42598 100644 --- a/testing/web-platform/meta/css/css-values/round-mod-rem-serialize.html.ini +++ b/testing/web-platform/meta/css/css-values/round-mod-rem-serialize.html.ini @@ -1,15 +1,4 @@ [round-mod-rem-serialize.html] - expected: - if (os == "android") and fission: [OK, TIMEOUT] - ['round(1.1,1)' as a specified value should serialize as 'calc(1)'.] - expected: FAIL - - ['scale(round(1.1,1))' as a specified value should serialize as 'scale(calc(1))'.] - expected: FAIL - - ['scale(round(1.1,1))' as a computed value should serialize as 'matrix(1, 0, 0, 1, 0, 0)'.] - expected: FAIL - ['mod(1,1)' as a specified value should serialize as 'calc(0)'.] expected: FAIL diff --git a/testing/web-platform/tests/css/css-values/round-function.html b/testing/web-platform/tests/css/css-values/round-function.html index dd4cfbea8d34..bc8734b011a6 100644 --- a/testing/web-platform/tests/css/css-values/round-function.html +++ b/testing/web-platform/tests/css/css-values/round-function.html @@ -61,12 +61,12 @@ test_math_used("round(-18px, -10px)", "-20px"); // Extreme cases: // 0 step is NaN -test_plus_infinity("round(5, 0)"); +test_nan("round(5, 0)"); // both infinite is NaN -test_plus_infinity("round(infinity, infinity)"); -test_plus_infinity("round(infinity, -infinity)"); -test_plus_infinity("round(-infinity, infinity)"); -test_plus_infinity("round(-infinity, -infinity)"); +test_nan("round(infinity, infinity)"); +test_nan("round(infinity, -infinity)"); +test_nan("round(-infinity, infinity)"); +test_nan("round(-infinity, -infinity)"); // infinite value with finite step is the same infinity test_plus_infinity("round(infinity, 5)"); @@ -87,8 +87,8 @@ test_minus_zero("round(to-zero, -5, -infinity)"); // 'up': pos goes to +inf, 0+ goes to 0+, else 0- test_plus_infinity("round(up, 1, infinity)"); test_plus_zero("round(up, 0, infinity)"); -test_minus_zero("round(up, -1 * 0, infinity"); -test_minus_zero("round(up, -1, infinity"); +test_minus_zero("round(up, -1 * 0, infinity)"); +test_minus_zero("round(up, -1, infinity)"); // 'down': neg goes to -inf, -0 goes to -0, else 0+ test_minus_infinity("round(down, -1, infinity)"); test_minus_zero("round(down, -1 * 0, infinity)"); diff --git a/testing/web-platform/tests/css/css-values/round-mod-rem-computed.html b/testing/web-platform/tests/css/css-values/round-mod-rem-computed.html index a98e4a433225..581b838744f1 100644 --- a/testing/web-platform/tests/css/css-values/round-mod-rem-computed.html +++ b/testing/web-platform/tests/css/css-values/round-mod-rem-computed.html @@ -6,7 +6,9 @@ -
+
+
+
\ No newline at end of file