Skip to content

Commit

Permalink
[CSS Math Functions] Correct mod() evaluation
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=259690
rdar://113213059

Reviewed by Simon Fraser.

According to https://drafts.csswg.org/css-values/#round-func :

Their behavior diverges if the A value and the B step are on opposite sides of zero: mod() (short
for “modulus”) continues to choose the integer multiple of B that puts the value between zero and
B, as above (guaranteeing that the result will either be zero or share the sign of B, not A), while
rem() (short for "remainder") chooses the integer multiple of B that puts the value between zero
and -B, avoiding changing the sign of the value.

* LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-computed-expected.txt:
* Source/WebCore/platform/calc/CalcOperator.h:
(WebCore::evaluateCalcExpression):

Canonical link: https://commits.webkit.org/266485@main
  • Loading branch information
nt1m committed Aug 1, 2023
1 parent 48aceba commit 440d1ba
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ PASS calc(mod(18,5) * 2 + mod(17,5)) should be used-value-equivalent to 8
PASS calc(rem(mod(18,5),5)) should be used-value-equivalent to 3
PASS calc(rem(mod(18,5),mod(17,5))) should be used-value-equivalent to 1
PASS calc(mod(-140,-90)) should be used-value-equivalent to -50
FAIL calc(mod(rem(1,18)* -1,5)) should be used-value-equivalent to 4 assert_equals: calc(mod(rem(1,18)* -1,5)) and 4 serialize to the same thing in used values. expected "matrix(4, 0, 0, 4, 0, 0)" but got "matrix(-1, 0, 0, -1, 0, 0)"
PASS calc(mod(rem(1,18)* -1,5)) should be used-value-equivalent to 4

This comment has been minimized.

Copy link
@darinadler

darinadler Aug 2, 2023

Member

I’m a bit surprised that there are two code changes, but only one test case affected.

This comment has been minimized.

Copy link
@nt1m

nt1m Aug 2, 2023

Author Member
PASS round(10px,6px) should be used-value-equivalent to 12px
PASS round(10cm,6cm) should be used-value-equivalent to 12cm
PASS round(10mm,6mm) should be used-value-equivalent to 12mm
Expand Down
15 changes: 11 additions & 4 deletions Source/WebCore/platform/calc/CalcOperator.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,18 @@ double evaluateCalcExpression(CalcOperator calcOperator, const Vector<T>& childr
return std::numeric_limits<double>::quiet_NaN();
auto left = evaluate(children[0]);
auto right = evaluate(children[1]);
if (!right)
// In mod(A, B) only, if B is infinite and A has opposite sign to B
// (including an oppositely-signed zero), the result is NaN.
// https://drafts.csswg.org/css-values/#round-infinities
if (std::isinf(right) && std::signbit(left) != std::signbit(right))
return std::numeric_limits<double>::quiet_NaN();
if ((left < 0) == (right < 0))
return std::fmod(left, right);
return std::remainder(left, right);
auto result = std::fmod(left, right);
// If the result is on opposite side of zero from B,
// put it between 0 and B.
// https://drafts.csswg.org/css-values/#round-func
if (std::signbit(result) != std::signbit(right))
result += right;
return result;
}
case CalcOperator::Rem: {
if (children.size() != 2)
Expand Down

0 comments on commit 440d1ba

Please sign in to comment.