LibWeb: Handle NaN and Infinite values in CSS round function

Gains us 10 WPT tests
This commit is contained in:
Callum Law 2025-06-27 02:35:07 +12:00 committed by Sam Atkins
commit 4ba54a7a1c
Notes: github-actions[bot] 2025-08-08 10:45:07 +00:00
3 changed files with 59 additions and 10 deletions

View file

@ -2362,6 +2362,55 @@ Optional<CalculatedStyleValue::CalculationResult> RoundCalculationNode::run_oper
auto a = maybe_a->value();
auto b = maybe_b->value();
// https://drafts.csswg.org/css-values-4/#round-infinities
// In round(A, B), if B is 0, the result is NaN. If A and B are both infinite, the result is NaN.
if (b == 0 || (isinf(a) && isinf(b)))
return CalculatedStyleValue::CalculationResult { AK::NaN<double>, consistent_type };
// If A is infinite but B is finite, the result is the same infinity.
if (isinf(a) && isfinite(b))
return CalculatedStyleValue::CalculationResult { a, consistent_type };
// If A is finite but B is infinite, the result depends on the <rounding-strategy> and the sign of A:
if (isfinite(a) && isinf(b)) {
FloatExtractor<double> const extractor { .d = a };
switch (m_strategy) {
// nearest, to-zero:
case RoundingStrategy::Nearest:
case RoundingStrategy::ToZero: {
// If A is positive or 0⁺, return 0⁺. Otherwise, return 0⁻.
return CalculatedStyleValue::CalculationResult { !extractor.sign ? 0.0 : -0.0, consistent_type };
}
// up:
case RoundingStrategy::Up: {
double result;
if (a > 0) {
// If A is positive(not zero), return +∞.
result = AK::Infinity<double>;
} else {
// If A is 0⁺, return 0⁺. Otherwise, return 0⁻.
result = !extractor.sign ? 0.0 : -0.0;
}
return CalculatedStyleValue::CalculationResult { result, consistent_type };
}
// down:
case RoundingStrategy::Down: {
double result;
if (a < 0) {
// If A is negative (not zero), return −∞.
result = -AK::Infinity<double>;
} else {
// If A is 0⁻, return 0⁻. Otherwise, return 0⁺.
result = extractor.sign ? -0.0 : 0.0;
}
return CalculatedStyleValue::CalculationResult { result, consistent_type };
}
}
}
// If A is exactly equal to an integer multiple of B, round() resolves to A exactly (preserving whether A is 0⁻ or
// 0⁺, if relevant).
if (fmod(a, b) == 0)

View file

@ -2,8 +2,8 @@ Harness status: OK
Found 229 tests
211 Pass
18 Fail
215 Pass
14 Fail
Pass round(10,10) should be used-value-equivalent to 10
Pass mod(1,1) should be used-value-equivalent to 0
Pass rem(1,1) should be used-value-equivalent to 0
@ -217,18 +217,18 @@ Pass round(to-zero, 0, -Infinity) should be used-value-equivalent to 0
Pass round(to-zero, 4, -Infinity) should be used-value-equivalent to 0
Pass round(to-zero, -0, -Infinity) should be used-value-equivalent to calc(-0)
Pass round(to-zero, -4, -Infinity) should be used-value-equivalent to calc(-0)
Fail round(up, 1, Infinity) should be used-value-equivalent to calc(Infinity)
Pass round(up, 1, Infinity) should be used-value-equivalent to calc(Infinity)
Pass round(up, 0, Infinity) should be used-value-equivalent to 0
Pass round(up, -1, Infinity) should be used-value-equivalent to calc(-0)
Fail round(up, 1, -Infinity) should be used-value-equivalent to calc(Infinity)
Pass round(up, 1, -Infinity) should be used-value-equivalent to calc(Infinity)
Pass round(up, 0, -Infinity) should be used-value-equivalent to 0
Pass round(up, -1, -Infinity) should be used-value-equivalent to calc(-0)
Pass round(down, 1, Infinity) should be used-value-equivalent to calc(-0)
Pass round(down, 0, Infinity) should be used-value-equivalent to 0
Fail round(down, -1, Infinity) should be used-value-equivalent to calc(-Infinity)
Pass round(down, -1, Infinity) should be used-value-equivalent to calc(-Infinity)
Pass round(down, 1, -Infinity) should be used-value-equivalent to calc(-0)
Pass round(down, 0, -Infinity) should be used-value-equivalent to 0
Fail round(down, -1, -Infinity) should be used-value-equivalent to calc(-Infinity)
Pass round(down, -1, -Infinity) should be used-value-equivalent to calc(-Infinity)
Pass mod(-0, Infinity) should be used-value-equivalent to calc(NaN)
Pass mod(0, -Infinity) should be used-value-equivalent to calc(NaN)
Pass mod(-4, Infinity) should be used-value-equivalent to calc(NaN)

View file

@ -2,8 +2,8 @@ Harness status: OK
Found 162 tests
154 Pass
8 Fail
156 Pass
6 Fail
Pass sign(calc(-0)) should be used-value-equivalent to 0
Pass clamp(-1, 1 / sign(calc(-0)), 1) should be used-value-equivalent to -1
Pass sign(calc( 0)) should be used-value-equivalent to 0
@ -79,7 +79,7 @@ Pass clamp(-1, 1 / sign(round(nearest, -0, infinity)), 1) should be used-value-e
Pass sign(round(nearest, 0, infinity)) should be used-value-equivalent to 0
Pass clamp(-1, 1 / sign(round(nearest, 0, infinity)), 1) should be used-value-equivalent to 1
Pass sign(round(nearest, 1, infinity)) should be used-value-equivalent to 0
Fail clamp(-1, 1 / sign(round(nearest, 1, infinity)), 1) should be used-value-equivalent to 1
Pass clamp(-1, 1 / sign(round(nearest, 1, infinity)), 1) should be used-value-equivalent to 1
Pass sign(round(up, -1, infinity)) should be used-value-equivalent to 0
Pass clamp(-1, 1 / sign(round(up, -1, infinity)), 1) should be used-value-equivalent to -1
Pass sign(round(up, -0, infinity)) should be used-value-equivalent to 0
@ -91,7 +91,7 @@ Pass clamp(-1, 1 / sign(round(down, -0, infinity)), 1) should be used-value-equi
Pass sign(round(down, 0, infinity)) should be used-value-equivalent to 0
Pass clamp(-1, 1 / sign(round(down, 0, infinity)), 1) should be used-value-equivalent to 1
Pass sign(round(down, 1, infinity)) should be used-value-equivalent to 0
Fail clamp(-1, 1 / sign(round(down, 1, infinity)), 1) should be used-value-equivalent to 1
Pass clamp(-1, 1 / sign(round(down, 1, infinity)), 1) should be used-value-equivalent to 1
Pass sign(mod(-1, -1)) should be used-value-equivalent to 0
Fail clamp(-1, 1 / sign(mod(-1, -1)), 1) should be used-value-equivalent to -1
Pass sign(mod(-1, 1)) should be used-value-equivalent to 0