Title: [283013] trunk
Revision
283013
Author
[email protected]
Date
2021-09-23 15:01:16 -0700 (Thu, 23 Sep 2021)

Log Message

Implement atan, acos, asin, atan2 calc functions
https://bugs.webkit.org/show_bug.cgi?id=229775

Patch by Nikos Mouchtaris <[email protected]> on 2021-09-23
Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

* 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:

Source/WebCore:

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:

Modified Paths

Added Paths

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);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to