Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (283012 => 283013)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2021-09-23 21:57:21 UTC (rev 283012)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2021-09-23 22:01:16 UTC (rev 283013)
@@ -1,3 +1,18 @@
+2021-09-23 Nikos Mouchtaris <[email protected]>
+
+ Implement atan, acos, asin, atan2 calc functions
+ https://bugs.webkit.org/show_bug.cgi?id=229775
+
+ Reviewed by Simon Fraser.
+
+ * web-platform-tests/css/css-values/acos-asin-atan-atan2-computed-expected.txt: Added.
+ * web-platform-tests/css/css-values/acos-asin-atan-atan2-computed.html: Added.
+ * web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid-expected.txt: Added.
+ * web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid.html: Added.
+ * web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize-expected.txt: Added.
+ * web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize.html: Added.
+ * web-platform-tests/css/support/numeric-testcommon.js:
+
2021-09-22 Myles C. Maxfield <[email protected]>
[Cocoa] Hook up palettes to CoreText
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-computed-expected.txt (0 => 283013)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-computed-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-computed-expected.txt 2021-09-23 22:01:16 UTC (rev 283013)
@@ -0,0 +1,43 @@
+
+PASS acos(1) should be used-value-equivalent to 0deg
+PASS atan(0) should be used-value-equivalent to 0deg
+PASS asin(0) should be used-value-equivalent to 0deg
+PASS atan2(0,0) should be used-value-equivalent to 0deg
+PASS calc(asin(sin(pi/2))) should be used-value-equivalent to 90deg
+PASS calc(acos(cos(pi - 3.14159265358979323846))) should be used-value-equivalent to 0deg
+PASS calc(atan(e - 2.7182818284590452354) ) should be used-value-equivalent to 0deg
+PASS calc(asin(sin(30deg + 1.0471967rad ) )) should be used-value-equivalent to 90deg
+PASS calc(acos(cos(30deg - 0.523599rad ) )) should be used-value-equivalent to 0deg
+PASS calc(asin(sin(3.14159 / 2 + 1 - 1) )) should be used-value-equivalent to 90deg
+PASS calc(asin(sin(100grad) )) should be used-value-equivalent to 90deg
+PASS calc(acos(cos(0 / 2 + 1 - 1) )) should be used-value-equivalent to 0deg
+PASS calc(atan(tan(30deg + 0.261799rad ) )) should be used-value-equivalent to 45deg
+PASS calc(atan(tan(0.7853975rad ) )) should be used-value-equivalent to 45deg
+PASS calc(atan(tan(3.14159 / 4 + 1 - 1) )) should be used-value-equivalent to 45deg
+PASS calc(asin(sin(0.25turn)) ) should be used-value-equivalent to 90deg
+PASS calc(atan2(0,1)) should be used-value-equivalent to 0deg
+PASS calc(atan2(0,-1)) should be used-value-equivalent to -180deg
+PASS calc(atan2(1,-1)) should be used-value-equivalent to 135deg
+PASS calc(atan2(-1,1)) should be used-value-equivalent to -45deg
+PASS calc(cos(sin(acos(cos(pi))))) should be used-value-equivalent to 1
+PASS calc(sin(atan(tan(pi/2)))) should be used-value-equivalent to 1
+PASS atan2(1px, -1px) should be used-value-equivalent to 135deg
+PASS atan2(1cm, -1cm) should be used-value-equivalent to 135deg
+PASS atan2(1mm, -1mm) should be used-value-equivalent to 135deg
+PASS atan2(1Q, -1Q) should be used-value-equivalent to 135deg
+PASS atan2(1in, -1in) should be used-value-equivalent to 135deg
+PASS atan2(1pc, -1pc) should be used-value-equivalent to 135deg
+PASS atan2(1pt, -1pt) should be used-value-equivalent to 135deg
+PASS atan2(1em, -1em) should be used-value-equivalent to 135deg
+PASS atan2(1ex, -1ex) should be used-value-equivalent to 135deg
+PASS atan2(1ch, -1ch) should be used-value-equivalent to 135deg
+PASS atan2(1rem, -1rem) should be used-value-equivalent to 135deg
+PASS atan2(1vh, -1vh) should be used-value-equivalent to 135deg
+PASS atan2(1vw, -1vw) should be used-value-equivalent to 135deg
+PASS atan2(1deg, -1deg) should be used-value-equivalent to 135deg
+PASS atan2(1grad, -1grad) should be used-value-equivalent to 135deg
+PASS atan2(1turn, -1turn) should be used-value-equivalent to 135deg
+PASS atan2(1rad, -1rad) should be used-value-equivalent to 135deg
+PASS atan2(1s, -1s) should be used-value-equivalent to 135deg
+PASS atan2(1ms, -1ms) should be used-value-equivalent to 135deg
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-computed.html (0 => 283013)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-computed.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-computed.html 2021-09-23 22:01:16 UTC (rev 283013)
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<link rel="help" href=""
+<link rel="help" href=""
+<link rel="help" href=""
+<link rel="author" title="Apple Inc">
+<script src=""
+<script src=""
+<script src=""
+<div id="target"></div>
+<script>
+function test_angle_equals(value, expected) {
+ test_math_used(`rotate(${value})`, `rotate(${expected})`,
+ {prop:'transform', base:'none',
+ msg: `${value} should be used-value-equivalent to ${expected}`});
+}
+// Simple tests
+test_angle_equals('acos(1)', '0deg');
+test_angle_equals('atan(0)', '0deg');
+test_angle_equals('asin(0)', '0deg');
+test_angle_equals('atan2(0,0)', '0deg');
+
+// Test pi
+test_math_used('calc(asin(sin(pi/2)))', '90deg', {type:'angle', approx:0.1});
+test_math_used('calc(acos(cos(pi - 3.14159265358979323846)))', '0deg', {type:'angle', approx:0.1});
+
+// Test e
+test_math_used('calc(atan(e - 2.7182818284590452354) )', '0deg', {type:'angle', approx:0.1});
+
+// General calculations
+test_math_used('calc(asin(sin(30deg + 1.0471967rad ) ))', '90deg', {type:'angle', approx:0.1});
+test_math_used('calc(acos(cos(30deg - 0.523599rad ) ))', '0deg'), {type:'angle', approx:0.1};
+test_math_used('calc(asin(sin(3.14159 / 2 + 1 - 1) ))', '90deg', {type:'angle', approx:0.1});
+test_math_used('calc(asin(sin(100grad) ))', '90deg', {type:'angle', approx:0.1});
+test_math_used('calc(acos(cos(0 / 2 + 1 - 1) ))', '0deg', {type:'angle', approx:0.1});
+test_math_used('calc(atan(tan(30deg + 0.261799rad ) ))', '45deg', {type:'angle', approx:0.1});
+test_math_used('calc(atan(tan(0.7853975rad ) ))', '45deg', {type:'angle', approx:0.1});
+test_math_used('calc(atan(tan(3.14159 / 4 + 1 - 1) ))', '45deg', {type:'angle', approx:0.1});
+test_math_used('calc(asin(sin(0.25turn)) )', '90deg', {type:'angle', approx:0.1});
+test_math_used('calc(atan2(0,1))', '0deg', {type:'angle', approx:0.1});
+test_math_used('calc(atan2(0,-1))', '-180deg', {type:'angle', approx:0.1});
+test_math_used('calc(atan2(1,-1))', '135deg', {type:'angle', approx:0.1});
+test_math_used('calc(atan2(-1,1))', '-45deg', {type:'angle', approx:0.1});
+
+// Test nesting
+test_math_used('calc(cos(sin(acos(cos(pi)))))', '1', {type:'number', approx:0.1});
+test_math_used('calc(sin(atan(tan(pi/2))))', '1', {type:'number', approx:0.1});
+
+// Test types for atan2
+test_math_used('atan2(1px, -1px)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1cm, -1cm)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1mm, -1mm)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1Q, -1Q)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1in, -1in)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1pc, -1pc)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1pt, -1pt)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1em, -1em)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1ex, -1ex)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1ch, -1ch)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1rem, -1rem)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1vh, -1vh)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1vw, -1vw)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1deg, -1deg)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1grad, -1grad)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1turn, -1turn)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1rad, -1rad)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1s, -1s)', '135deg', {type:'angle', approx:0.1});
+test_math_used('atan2(1ms, -1ms)', '135deg', {type:'angle', approx:0.1});
+
+</script>
\ No newline at end of file
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid-expected.txt (0 => 283013)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid-expected.txt 2021-09-23 22:01:16 UTC (rev 283013)
@@ -0,0 +1,62 @@
+
+PASS e.style['transform'] = "rotate(asin())" should not set the property value
+PASS e.style['transform'] = "rotate(asin( ))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(,))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(1dag))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(1deg, ))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(, 1deg))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(1deg + ))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(1deg - ))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(1deg * ))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(1deg / ))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(1deg 2deg))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(1deg, , 2deg))" should not set the property value
+PASS e.style['transform'] = "rotate(acos())" should not set the property value
+PASS e.style['transform'] = "rotate(acos( ))" should not set the property value
+PASS e.style['transform'] = "rotate(acos(,))" should not set the property value
+PASS e.style['transform'] = "rotate(acos(1dag))" should not set the property value
+PASS e.style['transform'] = "rotate(acos(1deg, ))" should not set the property value
+PASS e.style['transform'] = "rotate(acos(, 1deg))" should not set the property value
+PASS e.style['transform'] = "rotate(acos(1deg + ))" should not set the property value
+PASS e.style['transform'] = "rotate(acos(1deg - ))" should not set the property value
+PASS e.style['transform'] = "rotate(acos(1deg * ))" should not set the property value
+PASS e.style['transform'] = "rotate(acos(1deg / ))" should not set the property value
+PASS e.style['transform'] = "rotate(acos(1deg 2deg))" should not set the property value
+PASS e.style['transform'] = "rotate(acos(1deg, , 2deg))" should not set the property value
+PASS e.style['transform'] = "rotate(atan())" should not set the property value
+PASS e.style['transform'] = "rotate(atan( ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(,))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(1dag))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(1deg, ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(, 1deg))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(1deg + ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(1deg - ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(1deg * ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(1deg / ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(1deg 2deg))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(1deg, , 2deg))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(90px))" should not set the property value
+PASS e.style['transform'] = "rotate(asin(30deg + 1.0471967rad, 0))" should not set the property value
+PASS e.style['transform'] = "rotate(acos( 0 ,))" should not set the property value
+PASS e.style['transform'] = "rotate(acos( () 30deg - 0.523599rad ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(45deg ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan(30deg, + 0.261799rad))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2())" should not set the property value
+PASS e.style['transform'] = "rotate(atan2( ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(,))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(1dag))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(1deg, ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(, 1deg))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(1deg + ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(1deg - ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(1deg * ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(1deg / ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(1deg 2deg))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(1deg, , 2deg))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(90px))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(30deg + 1.0471967rad, 0))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2( 0 ,))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2( () 30deg - 0.523599rad ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(45deg ))" should not set the property value
+PASS e.style['transform'] = "rotate(atan2(30deg, + 0.261799rad))" should not set the property value
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid.html (0 => 283013)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid.html 2021-09-23 22:01:16 UTC (rev 283013)
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<link rel="help" href=""
+<link rel="help" href=""
+<link rel="help" href=""
+<link rel="author" title="Apple Inc">
+<script src=""
+<script src=""
+<script src=""
+<script>
+function test_invalid_angle(value) {
+ test_invalid_value('transform', `rotate(${value})`);
+}
+
+// Syntax checking
+test_invalid_angle('asin()');
+test_invalid_angle('asin( )');
+test_invalid_angle('asin(,)');
+test_invalid_angle('asin(1dag)');
+test_invalid_angle('asin(1deg, )');
+test_invalid_angle('asin(, 1deg)');
+test_invalid_angle('asin(1deg + )');
+test_invalid_angle('asin(1deg - )');
+test_invalid_angle('asin(1deg * )');
+test_invalid_angle('asin(1deg / )');
+test_invalid_angle('asin(1deg 2deg)');
+test_invalid_angle('asin(1deg, , 2deg)');
+test_invalid_angle('acos()');
+test_invalid_angle('acos( )');
+test_invalid_angle('acos(,)');
+test_invalid_angle('acos(1dag)');
+test_invalid_angle('acos(1deg, )');
+test_invalid_angle('acos(, 1deg)');
+test_invalid_angle('acos(1deg + )');
+test_invalid_angle('acos(1deg - )');
+test_invalid_angle('acos(1deg * )');
+test_invalid_angle('acos(1deg / )');
+test_invalid_angle('acos(1deg 2deg)');
+test_invalid_angle('acos(1deg, , 2deg)');
+test_invalid_angle('atan()');
+test_invalid_angle('atan( )');
+test_invalid_angle('atan(,)');
+test_invalid_angle('atan(1dag)');
+test_invalid_angle('atan(1deg, )');
+test_invalid_angle('atan(, 1deg)');
+test_invalid_angle('atan(1deg + )');
+test_invalid_angle('atan(1deg - )');
+test_invalid_angle('atan(1deg * )');
+test_invalid_angle('atan(1deg / )');
+test_invalid_angle('atan(1deg 2deg)');
+test_invalid_angle('atan(1deg, , 2deg)');
+test_invalid_angle('asin(90px)');
+test_invalid_angle('asin(30deg + 1.0471967rad, 0)');
+test_invalid_angle('acos( 0 ,)');
+test_invalid_angle('acos( () 30deg - 0.523599rad )');
+test_invalid_angle('atan(45deg )');
+test_invalid_angle('atan(30deg, + 0.261799rad)');
+test_invalid_angle('atan2()');
+test_invalid_angle('atan2( )');
+test_invalid_angle('atan2(,)');
+test_invalid_angle('atan2(1dag)');
+test_invalid_angle('atan2(1deg, )');
+test_invalid_angle('atan2(, 1deg)');
+test_invalid_angle('atan2(1deg + )');
+test_invalid_angle('atan2(1deg - )');
+test_invalid_angle('atan2(1deg * )');
+test_invalid_angle('atan2(1deg / )');
+test_invalid_angle('atan2(1deg 2deg)');
+test_invalid_angle('atan2(1deg, , 2deg)');
+test_invalid_angle('atan2(90px)');
+test_invalid_angle('atan2(30deg + 1.0471967rad, 0)');
+test_invalid_angle('atan2( 0 ,)');
+test_invalid_angle('atan2( () 30deg - 0.523599rad )');
+test_invalid_angle('atan2(45deg )');
+test_invalid_angle('atan2(30deg, + 0.261799rad)');
+</script>
\ No newline at end of file
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize-expected.txt (0 => 283013)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize-expected.txt 2021-09-23 22:01:16 UTC (rev 283013)
@@ -0,0 +1,10 @@
+
+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(6.123233995736766e-17, 1, -1, 6.123233995736766e-17, 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(6.123233995736766e-17, 1, -1, 6.123233995736766e-17, 0, 0)'.
+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(6.123233995736766e-17, 1, -1, 6.123233995736766e-17, 0, 0)'.
+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(6.123233995736766e-17, 1, -1, 6.123233995736766e-17, 0, 0)'.
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize.html (0 => 283013)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize.html 2021-09-23 22:01:16 UTC (rev 283013)
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<link rel="help" href=""
+<link rel="help" href=""
+<link rel="help" href=""
+<link rel="author" title="Apple Inc">
+<script src=""
+<script src=""
+<script src=""
+<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);
+
+test_serialization(
+ 'calc(acos(pi - pi))',
+ 'calc(90deg)',
+ rotateMatrix);
+test_serialization(
+ 'calc(asin(pi - pi + 1))',
+ 'calc(90deg)',
+ rotateMatrix);
+</script>
\ No newline at end of file
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/support/numeric-testcommon.js (283012 => 283013)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/support/numeric-testcommon.js 2021-09-23 21:57:21 UTC (rev 283012)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/support/numeric-testcommon.js 2021-09-23 22:01:16 UTC (rev 283013)
@@ -184,7 +184,7 @@
testEl.style[prop] = e;
const expectedValue = getComputedStyle(testEl)[prop];
assert_not_equals(expectedValue, '', `${expectedString} isn't valid in '${prop}'; got the default value instead.`)
- if(approx && type == "number"){
+ if(approx && (type == "number" || type == "angle")){
let parsedUsed = usedValue.split('(')[1].split(')')[0].split(',').map(parseFloat);
let parsedExpected = expectedValue.split('(')[1].split(')')[0].split(',').map(parseFloat);
assert_array_approx_equals(parsedUsed, parsedExpected, approx, `${testString} and ${expectedString} ${approx} serialize to the same thing in ${stage} values.`);
Modified: trunk/Source/WebCore/ChangeLog (283012 => 283013)
--- trunk/Source/WebCore/ChangeLog 2021-09-23 21:57:21 UTC (rev 283012)
+++ trunk/Source/WebCore/ChangeLog 2021-09-23 22:01:16 UTC (rev 283013)
@@ -1,3 +1,44 @@
+2021-09-23 Nikos Mouchtaris <[email protected]>
+
+ Implement atan, acos, asin, atan2 calc functions
+ https://bugs.webkit.org/show_bug.cgi?id=229775
+
+ Reviewed by Simon Fraser.
+
+ Added support for calc functions asin, acos, atan, atan2. Involved adding function CSS
+ keywords and handling for parsing these functions and their arguments as well as computing
+ the result based on the arguments. Spec for these functions:
+ https://drafts.csswg.org/css-values-4/#trig-funcs.
+
+ Tests: imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-computed.html
+ imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-invalid.html
+ imported/w3c/web-platform-tests/css/css-values/acos-asin-atan-atan2-serialize.html
+
+ * css/CSSValueKeywords.in:
+ * css/calc/CSSCalcExpressionNodeParser.cpp:
+ (WebCore::CSSCalcExpressionNodeParser::parseCalcFunction):
+ * css/calc/CSSCalcOperationNode.cpp:
+ (WebCore::determineCategory):
+ (WebCore::functionFromOperator):
+ (WebCore::CSSCalcOperationNode::createInverseTrig):
+ (WebCore::CSSCalcOperationNode::createAtan2):
+ (WebCore::CSSCalcOperationNode::combineChildren):
+ (WebCore::CSSCalcOperationNode::simplifyNode):
+ (WebCore::CSSCalcOperationNode::primitiveType const):
+ (WebCore::CSSCalcOperationNode::doubleValue const):
+ (WebCore::functionPrefixForOperator):
+ (WebCore::CSSCalcOperationNode::evaluateOperator):
+ * css/calc/CSSCalcOperationNode.h:
+ * css/calc/CSSCalcValue.cpp:
+ (WebCore::createCSS):
+ (WebCore::CSSCalcValue::isCalcFunction):
+ * platform/calc/CalcExpressionOperation.cpp:
+ (WebCore::CalcExpressionOperation::evaluate const):
+ Return converted to degrees based on spec: https://drafts.csswg.org/css-values-4/#trig-funcs.
+ * platform/calc/CalcOperator.cpp:
+ (WebCore::operator<<):
+ * platform/calc/CalcOperator.h:
+
2021-09-23 Tim Horton <[email protected]>
Move more linked-on-or-after checks to WebCore::linkedOnOrAfter()
Modified: trunk/Source/WebCore/css/CSSValueKeywords.in (283012 => 283013)
--- trunk/Source/WebCore/css/CSSValueKeywords.in 2021-09-23 21:57:21 UTC (rev 283012)
+++ trunk/Source/WebCore/css/CSSValueKeywords.in 2021-09-23 22:01:16 UTC (rev 283013)
@@ -1353,6 +1353,10 @@
pi
exp
log
+asin
+acos
+atan
+atan2
from-image
Modified: trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.cpp (283012 => 283013)
--- trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.cpp 2021-09-23 21:57:21 UTC (rev 283012)
+++ trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.cpp 2021-09-23 22:01:16 UTC (rev 283013)
@@ -137,10 +137,17 @@
case CSSValueSin:
case CSSValueCos:
case CSSValueTan:
+
+ case CSSValueAcos:
+ case CSSValueAsin:
+ case CSSValueAtan:
case CSSValueCalc:
maxArgumentCount = 1;
break;
- // TODO: clamp, sin, cos, tan, asin, acos, atan, atan2, pow, sqrt, hypot.
+ case CSSValueAtan2:
+ maxArgumentCount = 2;
+ break;
+ // TODO: pow, sqrt, hypot.
default:
break;
}
@@ -198,7 +205,19 @@
case CSSValueExp:
result = CSSCalcOperationNode::createExp(WTFMove(nodes));
break;
- // TODO: clamp, sin, cos, tan, asin, acos, atan, atan2, pow, sqrt, hypot
+ case CSSValueAcos:
+ result = CSSCalcOperationNode::createInverseTrig(CalcOperator::Acos, WTFMove(nodes));
+ break;
+ case CSSValueAsin:
+ result = CSSCalcOperationNode::createInverseTrig(CalcOperator::Asin, WTFMove(nodes));
+ break;
+ case CSSValueAtan:
+ result = CSSCalcOperationNode::createInverseTrig(CalcOperator::Atan, WTFMove(nodes));
+ break;
+ case CSSValueAtan2:
+ result = CSSCalcOperationNode::createAtan2(WTFMove(nodes));
+ break;
+ // TODO: pow, sqrt, hypot
default:
break;
}
Modified: trunk/Source/WebCore/css/calc/CSSCalcOperationNode.cpp (283012 => 283013)
--- trunk/Source/WebCore/css/calc/CSSCalcOperationNode.cpp 2021-09-23 21:57:21 UTC (rev 283012)
+++ trunk/Source/WebCore/css/calc/CSSCalcOperationNode.cpp 2021-09-23 22:01:16 UTC (rev 283013)
@@ -81,6 +81,10 @@
case CalcOperator::Clamp:
case CalcOperator::Log:
case CalcOperator::Exp:
+ case CalcOperator::Asin:
+ case CalcOperator::Acos:
+ case CalcOperator::Atan:
+ case CalcOperator::Atan2:
ASSERT_NOT_REACHED();
return CalculationCategory::Other;
}
@@ -154,6 +158,10 @@
case CalcOperator::Clamp:
case CalcOperator::Log:
case CalcOperator::Exp:
+ case CalcOperator::Asin:
+ case CalcOperator::Acos:
+ case CalcOperator::Atan:
+ case CalcOperator::Atan2:
// The type of a min(), max(), or clamp() _expression_ is the result of adding the types of its comma-separated calculations
return CalculationCategory::Other;
}
@@ -275,6 +283,14 @@
return CSSValueExp;
case CalcOperator::Log:
return CSSValueLog;
+ case CalcOperator::Asin:
+ return CSSValueAsin;
+ case CalcOperator::Acos:
+ return CSSValueAcos;
+ case CalcOperator::Atan:
+ return CSSValueAtan;
+ case CalcOperator::Atan2:
+ return CSSValueAtan2;
}
return CSSValueCalc;
}
@@ -313,6 +329,34 @@
return adoptRef(new CSSCalcOperationNode(newCategory, CalcOperator::Add, WTFMove(values)));
}
+RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::createInverseTrig(CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& values)
+{
+ if (values.size() != 1)
+ return nullptr;
+
+ auto childCategory = values[0]->category();
+ if (childCategory != CalculationCategory::Number) {
+ LOG_WITH_STREAM(Calc, stream << "Failed to create trig node because unable to determine category from " << prettyPrintNodes(values));
+ return nullptr;
+ }
+
+ return adoptRef(new CSSCalcOperationNode(CalculationCategory::Angle, op, WTFMove(values)));
+}
+
+RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::createAtan2(Vector<Ref<CSSCalcExpressionNode>>&& values)
+{
+ if (values.size() != 2)
+ return nullptr;
+
+ auto child1Category = values[0]->category();
+ auto child2Category = values[1]->category();
+ if (child1Category != child2Category) {
+ LOG_WITH_STREAM(Calc, stream << "Failed to create atan2 node because unable to determine category from " << prettyPrintNodes(values));
+ return nullptr;
+ }
+ return adoptRef(new CSSCalcOperationNode(CalculationCategory::Angle, CalcOperator::Atan2, WTFMove(values)));
+}
+
RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::createProduct(Vector<Ref<CSSCalcExpressionNode>>&& values)
{
if (values.isEmpty())
@@ -484,10 +528,16 @@
if (isExpNode()) {
double resolvedValue = doubleValue(m_children[0]->primitiveType());
auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, CSSUnitType::CSS_NUMBER));
-
m_children.clear();
m_children.append(WTFMove(newChild));
}
+
+ if (m_children.size() == 1 && isInverseTrigNode()) {
+ double resolvedValue = doubleValue(m_children[0]->primitiveType());
+ auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, CSSUnitType::CSS_DEG));
+ m_children.clear();
+ m_children.append(WTFMove(newChild));
+ }
return;
}
@@ -621,6 +671,13 @@
m_children.clear();
m_children.append(WTFMove(newChild));
}
+
+ if (calcOperator() == CalcOperator::Atan2) {
+ double resolvedValue = doubleValue(m_children[0]->primitiveType());
+ auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, CSSUnitType::CSS_DEG));
+ m_children.clear();
+ m_children.append(WTFMove(newChild));
+ }
}
// https://drafts.csswg.org/css-values-4/#simplify-a-calculation-tree
@@ -679,7 +736,7 @@
if (is<CSSCalcOperationNode>(rootNode)) {
auto& calcOperationNode = downcast<CSSCalcOperationNode>(rootNode.get());
// Simplify operations with only one child node (other than root and operations that only need one node).
- if (calcOperationNode.children().size() == 1 && depth && !calcOperationNode.isTrigNode() && !calcOperationNode.isExpNode())
+ if (calcOperationNode.children().size() == 1 && depth && !calcOperationNode.isTrigNode() && !calcOperationNode.isExpNode() && !calcOperationNode.isInverseTrigNode())
return WTFMove(calcOperationNode.children()[0]);
if (calcOperationNode.isCalcSumNode()) {
@@ -701,6 +758,12 @@
if (calcOperationNode.isExpNode() && depth)
calcOperationNode.combineChildren();
+ if (calcOperationNode.isInverseTrigNode() && depth)
+ calcOperationNode.combineChildren();
+
+ if (calcOperationNode.isAtan2Node() && depth)
+ calcOperationNode.combineChildren();
+
// If only one child remains, return the child (except at the root).
auto shouldCombineParentWithOnlyChild = [](const CSSCalcOperationNode& parent, int depth)
{
@@ -788,7 +851,7 @@
case CalculationCategory::Angle:
case CalculationCategory::Time:
case CalculationCategory::Frequency:
- if (m_children.size() == 1)
+ if (m_children.size() == 1 && !isInverseTrigNode())
return m_children.first()->primitiveType();
return canonicalUnitTypeForCalculationCategory(unitCategory);
@@ -834,6 +897,10 @@
childType = CSSUnitType::CSS_NUMBER;
if (isTrigNode() && unitType != CSSUnitType::CSS_NUMBER)
childType = CSSUnitType::CSS_RAD;
+ if (isInverseTrigNode())
+ childType = CSSUnitType::CSS_NUMBER;
+ if (isAtan2Node())
+ childType = child->primitiveType();
return child->doubleValue(childType);
}));
}
@@ -894,6 +961,10 @@
case CalcOperator::Clamp: return "clamp(";
case CalcOperator::Exp: return "exp(";
case CalcOperator::Log: return "log(";
+ case CalcOperator::Asin: return "asin(";
+ case CalcOperator::Acos: return "acos(";
+ case CalcOperator::Atan: return "atan(";
+ case CalcOperator::Atan2: return "atan2(";
}
return "";
@@ -1122,7 +1193,27 @@
return std::numeric_limits<double>::quiet_NaN();
return std::exp(children[0]);
}
+ case CalcOperator::Asin: {
+ if (children.size() != 1)
+ return std::numeric_limits<double>::quiet_NaN();
+ return rad2deg(std::asin(children[0]));
}
+ case CalcOperator::Acos: {
+ if (children.size() != 1)
+ return std::numeric_limits<double>::quiet_NaN();
+ return rad2deg(std::acos(children[0]));
+ }
+ case CalcOperator::Atan: {
+ if (children.size() != 1)
+ return std::numeric_limits<double>::quiet_NaN();
+ return rad2deg(std::atan(children[0]));
+ }
+ case CalcOperator::Atan2: {
+ if (children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ return rad2deg(atan2(children[0], children[1]));
+ }
+ }
ASSERT_NOT_REACHED();
return 0;
}
Modified: trunk/Source/WebCore/css/calc/CSSCalcOperationNode.h (283012 => 283013)
--- trunk/Source/WebCore/css/calc/CSSCalcOperationNode.h 2021-09-23 21:57:21 UTC (rev 283012)
+++ trunk/Source/WebCore/css/calc/CSSCalcOperationNode.h 2021-09-23 22:01:16 UTC (rev 283013)
@@ -40,6 +40,8 @@
static RefPtr<CSSCalcOperationNode> createTrig(CalcOperator, Vector<Ref<CSSCalcExpressionNode>>&& values);
static RefPtr<CSSCalcOperationNode> createLog(Vector<Ref<CSSCalcExpressionNode>>&& values);
static RefPtr<CSSCalcOperationNode> createExp(Vector<Ref<CSSCalcExpressionNode>>&& values);
+ static RefPtr<CSSCalcOperationNode> createInverseTrig(CalcOperator, Vector<Ref<CSSCalcExpressionNode>>&& values);
+ static RefPtr<CSSCalcOperationNode> createAtan2(Vector<Ref<CSSCalcExpressionNode>>&& values);
static Ref<CSSCalcExpressionNode> simplify(Ref<CSSCalcExpressionNode>&&);
@@ -51,6 +53,8 @@
bool isMinOrMaxNode() const { return m_operator == CalcOperator::Min || m_operator == CalcOperator::Max; }
bool isTrigNode() const { return m_operator == CalcOperator::Sin || m_operator == CalcOperator::Cos || m_operator == CalcOperator::Tan; }
bool isExpNode() const { return m_operator == CalcOperator::Exp || m_operator == CalcOperator::Log; }
+ bool isInverseTrigNode() const { return m_operator == CalcOperator::Asin || m_operator == CalcOperator::Acos || m_operator == CalcOperator::Atan; }
+ bool isAtan2Node() const { return m_operator == CalcOperator::Atan2; }
bool shouldSortChildren() const { return isCalcSumNode() || isCalcProductNode(); }
void hoistChildrenWithOperator(CalcOperator);
Modified: trunk/Source/WebCore/css/calc/CSSCalcValue.cpp (283012 => 283013)
--- trunk/Source/WebCore/css/calc/CSSCalcValue.cpp 2021-09-23 21:57:21 UTC (rev 283012)
+++ trunk/Source/WebCore/css/calc/CSSCalcValue.cpp 2021-09-23 22:01:16 UTC (rev 283013)
@@ -192,7 +192,21 @@
return nullptr;
return CSSCalcOperationNode::createExp(WTFMove(children));
}
+ case CalcOperator::Asin:
+ case CalcOperator::Acos:
+ case CalcOperator::Atan: {
+ auto children = createCSS(operationChildren, style);
+ if (children.size() != 1)
+ return nullptr;
+ return CSSCalcOperationNode::createInverseTrig(op, WTFMove(children));
}
+ case CalcOperator::Atan2: {
+ auto children = createCSS(operationChildren, style);
+ if (children.size() != 2)
+ return nullptr;
+ return CSSCalcOperationNode::createAtan2(WTFMove(children));
+ }
+ }
return nullptr;
}
case CalcExpressionNodeType::BlendLength: {
@@ -308,6 +322,10 @@
case CSSValueTan:
case CSSValueExp:
case CSSValueLog:
+ case CSSValueAsin:
+ case CSSValueAcos:
+ case CSSValueAtan:
+ case CSSValueAtan2:
return true;
default:
return false;
Modified: trunk/Source/WebCore/platform/calc/CalcExpressionOperation.cpp (283012 => 283013)
--- trunk/Source/WebCore/platform/calc/CalcExpressionOperation.cpp 2021-09-23 21:57:21 UTC (rev 283012)
+++ trunk/Source/WebCore/platform/calc/CalcExpressionOperation.cpp 2021-09-23 22:01:16 UTC (rev 283013)
@@ -114,7 +114,27 @@
return std::numeric_limits<float>::quiet_NaN();
return std::exp(m_children[0]->evaluate(maxValue));
}
+ case CalcOperator::Asin: {
+ if (m_children.size() != 1)
+ return std::numeric_limits<float>::quiet_NaN();
+ return rad2deg(std::asin(m_children[0]->evaluate(maxValue)));
}
+ case CalcOperator::Acos: {
+ if (m_children.size() != 1)
+ return std::numeric_limits<float>::quiet_NaN();
+ return rad2deg(std::acos(m_children[0]->evaluate(maxValue)));
+ }
+ case CalcOperator::Atan: {
+ if (m_children.size() != 1)
+ return std::numeric_limits<float>::quiet_NaN();
+ return rad2deg(std::atan(m_children[0]->evaluate(maxValue)));
+ }
+ case CalcOperator::Atan2: {
+ if (m_children.size() != 2)
+ return std::numeric_limits<float>::quiet_NaN();
+ return rad2deg(atan2(m_children[0]->evaluate(maxValue), m_children[1]->evaluate(maxValue)));
+ }
+ }
ASSERT_NOT_REACHED();
return std::numeric_limits<float>::quiet_NaN();
}
Modified: trunk/Source/WebCore/platform/calc/CalcOperator.cpp (283012 => 283013)
--- trunk/Source/WebCore/platform/calc/CalcOperator.cpp 2021-09-23 21:57:21 UTC (rev 283012)
+++ trunk/Source/WebCore/platform/calc/CalcOperator.cpp 2021-09-23 22:01:16 UTC (rev 283013)
@@ -45,6 +45,10 @@
case CalcOperator::Tan: ts << "tan"; break;
case CalcOperator::Exp: ts << "exp"; break;
case CalcOperator::Log: ts << "log"; break;
+ case CalcOperator::Asin: ts << "asin"; break;
+ case CalcOperator::Acos: ts << "acos"; break;
+ case CalcOperator::Atan: ts << "atan"; break;
+ case CalcOperator::Atan2: ts << "atan2"; break;
}
return ts;
}
Modified: trunk/Source/WebCore/platform/calc/CalcOperator.h (283012 => 283013)
--- trunk/Source/WebCore/platform/calc/CalcOperator.h 2021-09-23 21:57:21 UTC (rev 283012)
+++ trunk/Source/WebCore/platform/calc/CalcOperator.h 2021-09-23 22:01:16 UTC (rev 283013)
@@ -43,6 +43,10 @@
Tan,
Exp,
Log,
+ Asin,
+ Acos,
+ Atan,
+ Atan2,
};
TextStream& operator<<(TextStream&, CalcOperator);