Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[CSS Math Functions] Correctly serialize asin/acos/atan/atan2 root nodes
https://bugs.webkit.org/show_bug.cgi?id=259019 rdar://111960627 Reviewed by Darin Adler. From the spec https://drafts.csswg.org/css-values-4/#calc-simplification: > If root is an operator node that’s not one of the calc-operator nodes, and all of its calculation children are numeric values with enough information to compute the operation root represents, return the result of running root’s operation using its children, expressed in the result’s canonical unit. We now always try to resolve the top-level asin/acos/atan/atan2, e.g. acos(0) now gives calc(0deg) instead of acos(0). This is consistent with calc(acos(0)) being serialized as calc(0deg). * LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize.html: * Source/WebCore/css/calc/CSSCalcOperationNode.h: Canonical link: https://commits.webkit.org/265885@main
- Loading branch information
Showing
3 changed files
with
113 additions
and
48 deletions.
There are no files selected for viewing
68 changes: 61 additions & 7 deletions
68
...mported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize-expected.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,66 @@ | ||
|
||
FAIL 'rotate(acos(0))' as a specified value should serialize as 'rotate(calc(90deg))'. assert_equals: 'rotate(acos(0))' and 'rotate(calc(90deg))' should serialize the same in specified values. expected "rotate(calc(90deg))" but got "rotate(acos(0))" | ||
PASS 'rotate(acos(0))' as a computed value should serialize as 'matrix(0, 1, -1, 0, 0, 0)'. | ||
FAIL 'rotate(asin(1))' as a specified value should serialize as 'rotate(calc(90deg))'. assert_equals: 'rotate(asin(1))' and 'rotate(calc(90deg))' should serialize the same in specified values. expected "rotate(calc(90deg))" but got "rotate(asin(1))" | ||
PASS 'rotate(asin(1))' as a computed value should serialize as 'matrix(0, 1, -1, 0, 0, 0)'. | ||
PASS 'rotate(acos(1))' as a specified value should serialize as 'rotate(calc(0deg))'. | ||
PASS 'rotate(calc(acos(1)))' as a specified value should serialize as 'rotate(calc(0deg))'. | ||
PASS 'rotate(acos(-1))' as a specified value should serialize as 'rotate(calc(180deg))'. | ||
PASS 'rotate(calc(acos(-1)))' as a specified value should serialize as 'rotate(calc(180deg))'. | ||
PASS 'rotate(acos(-1.5))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(calc(acos(-1.5)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(acos(1.5))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(calc(acos(1.5)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(acos(2))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(calc(acos(2)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(acos(0.5))' as a specified value should serialize as 'rotate(calc(60deg))'. | ||
PASS 'rotate(calc(acos(0.5)))' as a specified value should serialize as 'rotate(calc(60deg))'. | ||
PASS 'rotate(acos(1 - 0.5))' as a specified value should serialize as 'rotate(calc(60deg))'. | ||
PASS 'rotate(calc(acos(1 - 0.5)))' as a specified value should serialize as 'rotate(calc(60deg))'. | ||
PASS 'rotate(acos(0))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(calc(acos(0)))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(asin(1))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(calc(asin(1)))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(asin(-1))' as a specified value should serialize as 'rotate(calc(-90deg))'. | ||
PASS 'rotate(calc(asin(-1)))' as a specified value should serialize as 'rotate(calc(-90deg))'. | ||
PASS 'rotate(asin(-1.5))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(calc(asin(-1.5)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(asin(1.5))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(calc(asin(1.5)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(asin(2))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(calc(asin(2)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(asin(0.5))' as a specified value should serialize as 'rotate(calc(30deg))'. | ||
PASS 'rotate(calc(asin(0.5)))' as a specified value should serialize as 'rotate(calc(30deg))'. | ||
PASS 'rotate(asin(1 - 0.5))' as a specified value should serialize as 'rotate(calc(30deg))'. | ||
PASS 'rotate(calc(asin(1 - 0.5)))' as a specified value should serialize as 'rotate(calc(30deg))'. | ||
PASS 'rotate(asin(0))' as a specified value should serialize as 'rotate(calc(0deg))'. | ||
PASS 'rotate(calc(asin(0)))' as a specified value should serialize as 'rotate(calc(0deg))'. | ||
PASS 'rotate(acos(pi - pi))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(calc(acos(pi - pi)))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(calc(acos(pi - pi)))' as a computed value should serialize as 'matrix(0, 1, -1, 0, 0, 0)'. | ||
PASS 'rotate(asin(pi - pi + 1))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(calc(asin(pi - pi + 1)))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(calc(asin(pi - pi + 1)))' as a computed value should serialize as 'matrix(0, 1, -1, 0, 0, 0)'. | ||
PASS 'rotate(atan(1))' as a specified value should serialize as 'rotate(calc(45deg))'. | ||
PASS 'rotate(calc(atan(1)))' as a specified value should serialize as 'rotate(calc(45deg))'. | ||
FAIL 'rotate(atan(0.5))' as a specified value should serialize as 'rotate(calc(26.5651deg))'. assert_equals: 'rotate(atan(0.5))' and 'rotate(calc(26.5651deg))' should serialize the same in specified values. expected "rotate(calc(26.5651deg))" but got "rotate(calc(26.565051deg))" | ||
FAIL 'rotate(calc(atan(0.5)))' as a specified value should serialize as 'rotate(calc(26.5651deg))'. assert_equals: 'rotate(calc(atan(0.5)))' and 'rotate(calc(26.5651deg))' should serialize the same in specified values. expected "rotate(calc(26.5651deg))" but got "rotate(calc(26.565051deg))" | ||
PASS 'rotate(atan(0.577350269))' as a specified value should serialize as 'rotate(calc(30deg))'. | ||
PASS 'rotate(calc(atan(0.577350269)))' as a specified value should serialize as 'rotate(calc(30deg))'. | ||
PASS 'rotate(atan(0))' as a specified value should serialize as 'rotate(calc(0deg))'. | ||
PASS 'rotate(calc(atan(0)))' as a specified value should serialize as 'rotate(calc(0deg))'. | ||
PASS 'rotate(atan(infinity))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(calc(atan(infinity)))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(calc(atan(infinity)))' as a computed value should serialize as 'matrix(0, 1, -1, 0, 0, 0)'. | ||
PASS 'rotate(atan2(37.320508075, 10))' as a specified value should serialize as 'rotate(calc(75deg))'. | ||
PASS 'rotate(calc(atan2(37.320508075, 10)))' as a specified value should serialize as 'rotate(calc(75deg))'. | ||
PASS 'rotate(atan2(1s, 1000ms))' as a specified value should serialize as 'rotate(calc(45deg))'. | ||
PASS 'rotate(calc(atan2(1s, 1000ms)))' as a specified value should serialize as 'rotate(calc(45deg))'. | ||
PASS 'rotate(atan2(infinity, infinity))' as a specified value should serialize as 'rotate(calc(45deg))'. | ||
PASS 'rotate(calc(atan2(infinity, infinity)))' as a specified value should serialize as 'rotate(calc(45deg))'. | ||
PASS 'rotate(atan2(-infinity, -infinity))' as a specified value should serialize as 'rotate(calc(-135deg))'. | ||
PASS 'rotate(calc(atan2(-infinity, -infinity)))' as a specified value should serialize as 'rotate(calc(-135deg))'. | ||
PASS 'rotate(atan2(infinity, 10))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(calc(atan2(infinity, 10)))' as a specified value should serialize as 'rotate(calc(90deg))'. | ||
PASS 'rotate(atan2(10, infinity))' as a specified value should serialize as 'rotate(calc(0deg))'. | ||
PASS 'rotate(calc(atan2(10, infinity)))' as a specified value should serialize as 'rotate(calc(0deg))'. | ||
PASS 'rotate(atan2(NaN, 10))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(calc(atan2(NaN, 10)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(atan2(10, NaN))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(calc(atan2(10, NaN)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(atan2(NaN, NaN))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
PASS 'rotate(calc(atan2(NaN, NaN)))' as a specified value should serialize as 'rotate(calc(NaN * 1deg))'. | ||
|
89 changes: 50 additions & 39 deletions
89
...tTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,62 @@ | ||
<!DOCTYPE html> | ||
<link rel="help" href="https://drafts.csswg.org/css-values-4/#comp-func"> | ||
<link rel="help" href="https://drafts.csswg.org/css-values-4/#trig-funcs"> | ||
<link rel="help" href="https://drafts.csswg.org/css-values-4/#angles"> | ||
<link rel="help" href="https://drafts.csswg.org/css-values-4/#calc-serialize"> | ||
<link rel="author" title="Apple Inc"> | ||
<link rel="author" title="Seokho Song" href="seokho@chromium.org"> | ||
<script src="/resources/testharness.js"></script> | ||
<script src="/resources/testharnessreport.js"></script> | ||
<script src="../support/serialize-testcommon.js"></script> | ||
<div id=target></div> | ||
<script> | ||
function test_serialization(t,s,c,u, {prop="transform"}={}) { | ||
t = `rotate(${t})`; | ||
test_specified_serialization(prop, t, `rotate(${s})`); | ||
test_computed_serialization(prop, t, c); | ||
if(u) test_used_serialization(prop, t, u); | ||
} | ||
|
||
// Browsers aren't perfectly interoperable about how a 90deg rotation is serialized, | ||
// but that's not the focus of this test, | ||
// so just capture *whatever* the browser does and expect that. | ||
const rotateMatrix = (()=>{ | ||
const el = document.querySelector("#target"); | ||
el.style.transform = "rotate(90deg)"; | ||
const ret = getComputedStyle(el).transform; | ||
el.removeAttribute('style'); | ||
return ret; | ||
})(); | ||
|
||
test_serialization( | ||
'acos(0)', | ||
'calc(90deg)', | ||
rotateMatrix); | ||
test_serialization( | ||
'asin(1)', | ||
'calc(90deg)', | ||
rotateMatrix); | ||
function test_serialization(specified, expected, {prop="transform"}={}) { | ||
|
||
test_serialization( | ||
'calc(acos(pi - pi))', | ||
'calc(90deg)', | ||
rotateMatrix); | ||
test_serialization( | ||
'calc(asin(pi - pi + 1))', | ||
'calc(90deg)', | ||
rotateMatrix); | ||
// We only test the specified serialization, | ||
// and not the computed or used serialization, | ||
// since we'd need to do that by retrieving the rotation matrix, | ||
// and that isn't perfectly interoperable in corner cases. | ||
// Plus the point of this test is to check the trig functions themselves. | ||
test_specified_serialization(prop, `rotate(${specified})`, `rotate(${expected})`) | ||
} | ||
//TEST CASE | EXPECTED | ||
var test_map = { | ||
"acos(1)" :"calc(0deg)", | ||
"acos(-1)" :"calc(180deg)", | ||
"acos(-1.5)" :"calc(NaN * 1deg)", | ||
"acos(1.5)" :"calc(NaN * 1deg)", | ||
"acos(2)" :"calc(NaN * 1deg)", | ||
"acos(0.5)" :"calc(60deg)", | ||
"acos(1 - 0.5)" :"calc(60deg)", | ||
"acos(0)" :"calc(90deg)", | ||
"asin(1)" :"calc(90deg)", | ||
"asin(-1)" :"calc(-90deg)", | ||
"asin(-1.5)" :"calc(NaN * 1deg)", | ||
"asin(1.5)" :"calc(NaN * 1deg)", | ||
"asin(2)" :"calc(NaN * 1deg)", | ||
"asin(0.5)" :"calc(30deg)", | ||
"asin(1 - 0.5)" :"calc(30deg)", | ||
"asin(0)" :"calc(0deg)", | ||
"acos(pi - pi)" :"calc(90deg)", | ||
"asin(pi - pi + 1)" :"calc(90deg)", | ||
"atan(1)" :"calc(45deg)", | ||
"atan(0.5)" :"calc(26.5651deg)", | ||
"atan(0.577350269)" :"calc(30deg)", | ||
"atan(0)" :"calc(0deg)", | ||
"atan(infinity)" :"calc(90deg)", | ||
"atan2(37.320508075, 10)" :"calc(75deg)", | ||
"atan2(1s, 1000ms)" :"calc(45deg)", | ||
"atan2(infinity, infinity)" :"calc(45deg)", | ||
"atan2(-infinity, -infinity)" :"calc(-135deg)", | ||
"atan2(infinity, 10)" :"calc(90deg)", | ||
"atan2(10, infinity)" :"calc(0deg)", | ||
"atan2(NaN, 10)" :"calc(NaN * 1deg)", | ||
"atan2(10, NaN)" :"calc(NaN * 1deg)", | ||
"atan2(NaN, NaN)" :"calc(NaN * 1deg)", | ||
}; | ||
|
||
test_serialization( | ||
'calc(atan(infinity))', | ||
'calc(90deg)', | ||
rotateMatrix); | ||
</script> | ||
for (var exp in test_map) { | ||
test_serialization(exp, test_map[exp]); | ||
test_serialization(`calc(${exp})`, test_map[exp]); | ||
} | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters