Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (283072 => 283073)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2021-09-25 05:03:08 UTC (rev 283073)
@@ -1,5 +1,21 @@
2021-09-24 Nikos Mouchtaris <nmouchta...@apple.com>
+ Implement round,mod,rem functions for calc
+ https://bugs.webkit.org/show_bug.cgi?id=230073
+
+ Reviewed by Simon Fraser.
+
+ * web-platform-tests/css/css-values/round-function-expected.txt:
+ * web-platform-tests/css/css-values/round-mod-rem-computed-expected.txt: Added.
+ * web-platform-tests/css/css-values/round-mod-rem-computed.html: Added.
+ * web-platform-tests/css/css-values/round-mod-rem-invalid-expected.txt: Added.
+ * web-platform-tests/css/css-values/round-mod-rem-invalid.html: Added.
+ * web-platform-tests/css/css-values/round-mod-rem-serialize-expected.txt: Added.
+ * web-platform-tests/css/css-values/round-mod-rem-serialize.html: Added.
+ * web-platform-tests/css/support/numeric-testcommon.js:
+
+2021-09-24 Nikos Mouchtaris <nmouchta...@apple.com>
+
Implement abs,sign calc functions
https://bugs.webkit.org/show_bug.cgi?id=229786
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-function-expected.txt (283072 => 283073)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-function-expected.txt 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-function-expected.txt 2021-09-25 05:03:08 UTC (rev 283073)
@@ -1,40 +1,40 @@
-FAIL round(23px, 10px) should be used-value-equivalent to 20px assert_equals: round(23px, 10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(18px, 10px) should be used-value-equivalent to 20px assert_equals: round(18px, 10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(15px, 10px) should be used-value-equivalent to 20px assert_equals: round(15px, 10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(13px, 10px) should be used-value-equivalent to 10px assert_equals: round(13px, 10px) and 10px serialize to the same thing in used values. expected "10px" but got "0px"
-FAIL round(-13px, 10px) should be used-value-equivalent to -10px assert_equals: round(-13px, 10px) and -10px serialize to the same thing in used values. expected "-10px" but got "0px"
-FAIL round(-18px, 10px) should be used-value-equivalent to -20px assert_equals: round(-18px, 10px) and -20px serialize to the same thing in used values. expected "-20px" but got "0px"
-FAIL round(nearest, 23px, 10px) should be used-value-equivalent to 20px assert_equals: round(nearest, 23px, 10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(nearest, 18px, 10px) should be used-value-equivalent to 20px assert_equals: round(nearest, 18px, 10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(nearest, 15px, 10px) should be used-value-equivalent to 20px assert_equals: round(nearest, 15px, 10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(nearest, 13px, 10px) should be used-value-equivalent to 10px assert_equals: round(nearest, 13px, 10px) and 10px serialize to the same thing in used values. expected "10px" but got "0px"
-FAIL round(nearest, -13px, 10px) should be used-value-equivalent to -10px assert_equals: round(nearest, -13px, 10px) and -10px serialize to the same thing in used values. expected "-10px" but got "0px"
-FAIL round(nearest, -18px, 10px) should be used-value-equivalent to -20px assert_equals: round(nearest, -18px, 10px) and -20px serialize to the same thing in used values. expected "-20px" but got "0px"
-FAIL round(down, 23px, 10px) should be used-value-equivalent to 20px assert_equals: round(down, 23px, 10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(down, 18px, 10px) should be used-value-equivalent to 10px assert_equals: round(down, 18px, 10px) and 10px serialize to the same thing in used values. expected "10px" but got "0px"
-FAIL round(down, 15px, 10px) should be used-value-equivalent to 10px assert_equals: round(down, 15px, 10px) and 10px serialize to the same thing in used values. expected "10px" but got "0px"
-FAIL round(down, 13px, 10px) should be used-value-equivalent to 10px assert_equals: round(down, 13px, 10px) and 10px serialize to the same thing in used values. expected "10px" but got "0px"
-FAIL round(down, -13px, 10px) should be used-value-equivalent to -20px assert_equals: round(down, -13px, 10px) and -20px serialize to the same thing in used values. expected "-20px" but got "0px"
-FAIL round(down, -18px, 10px) should be used-value-equivalent to -20px assert_equals: round(down, -18px, 10px) and -20px serialize to the same thing in used values. expected "-20px" but got "0px"
-FAIL round(up, 23px, 10px) should be used-value-equivalent to 30px assert_equals: round(up, 23px, 10px) and 30px serialize to the same thing in used values. expected "30px" but got "0px"
-FAIL round(up, 18px, 10px) should be used-value-equivalent to 20px assert_equals: round(up, 18px, 10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(up, 15px, 10px) should be used-value-equivalent to 20px assert_equals: round(up, 15px, 10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(up, 13px, 10px) should be used-value-equivalent to 20px assert_equals: round(up, 13px, 10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(up, -13px, 10px) should be used-value-equivalent to -10px assert_equals: round(up, -13px, 10px) and -10px serialize to the same thing in used values. expected "-10px" but got "0px"
-FAIL round(up, -18px, 10px) should be used-value-equivalent to -10px assert_equals: round(up, -18px, 10px) and -10px serialize to the same thing in used values. expected "-10px" but got "0px"
-FAIL round(to-zero, 23px, 10px) should be used-value-equivalent to 20px assert_equals: round(to-zero, 23px, 10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(to-zero, 18px, 10px) should be used-value-equivalent to 10px assert_equals: round(to-zero, 18px, 10px) and 10px serialize to the same thing in used values. expected "10px" but got "0px"
-FAIL round(to-zero, 15px, 10px) should be used-value-equivalent to 10px assert_equals: round(to-zero, 15px, 10px) and 10px serialize to the same thing in used values. expected "10px" but got "0px"
-FAIL round(to-zero, 13px, 10px) should be used-value-equivalent to 10px assert_equals: round(to-zero, 13px, 10px) and 10px serialize to the same thing in used values. expected "10px" but got "0px"
-FAIL round(to-zero, -13px, 10px) should be used-value-equivalent to -10px assert_equals: round(to-zero, -13px, 10px) and -10px serialize to the same thing in used values. expected "-10px" but got "0px"
-FAIL round(to-zero, -18px, 10px) should be used-value-equivalent to -10px assert_equals: round(to-zero, -18px, 10px) and -10px serialize to the same thing in used values. expected "-10px" but got "0px"
-FAIL round(23px, -10px) should be used-value-equivalent to 20px assert_equals: round(23px, -10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(18px, -10px) should be used-value-equivalent to 20px assert_equals: round(18px, -10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(15px, -10px) should be used-value-equivalent to 20px assert_equals: round(15px, -10px) and 20px serialize to the same thing in used values. expected "20px" but got "0px"
-FAIL round(13px, -10px) should be used-value-equivalent to 10px assert_equals: round(13px, -10px) and 10px serialize to the same thing in used values. expected "10px" but got "0px"
-FAIL round(-13px, -10px) should be used-value-equivalent to -10px assert_equals: round(-13px, -10px) and -10px serialize to the same thing in used values. expected "-10px" but got "0px"
-FAIL round(-18px, -10px) should be used-value-equivalent to -20px assert_equals: round(-18px, -10px) and -20px serialize to the same thing in used values. expected "-20px" but got "0px"
+PASS round(23px, 10px) should be used-value-equivalent to 20px
+PASS round(18px, 10px) should be used-value-equivalent to 20px
+PASS round(15px, 10px) should be used-value-equivalent to 20px
+PASS round(13px, 10px) should be used-value-equivalent to 10px
+PASS round(-13px, 10px) should be used-value-equivalent to -10px
+PASS round(-18px, 10px) should be used-value-equivalent to -20px
+PASS round(nearest, 23px, 10px) should be used-value-equivalent to 20px
+PASS round(nearest, 18px, 10px) should be used-value-equivalent to 20px
+PASS round(nearest, 15px, 10px) should be used-value-equivalent to 20px
+PASS round(nearest, 13px, 10px) should be used-value-equivalent to 10px
+PASS round(nearest, -13px, 10px) should be used-value-equivalent to -10px
+PASS round(nearest, -18px, 10px) should be used-value-equivalent to -20px
+PASS round(down, 23px, 10px) should be used-value-equivalent to 20px
+PASS round(down, 18px, 10px) should be used-value-equivalent to 10px
+PASS round(down, 15px, 10px) should be used-value-equivalent to 10px
+PASS round(down, 13px, 10px) should be used-value-equivalent to 10px
+PASS round(down, -13px, 10px) should be used-value-equivalent to -20px
+PASS round(down, -18px, 10px) should be used-value-equivalent to -20px
+PASS round(up, 23px, 10px) should be used-value-equivalent to 30px
+PASS round(up, 18px, 10px) should be used-value-equivalent to 20px
+PASS round(up, 15px, 10px) should be used-value-equivalent to 20px
+PASS round(up, 13px, 10px) should be used-value-equivalent to 20px
+PASS round(up, -13px, 10px) should be used-value-equivalent to -10px
+PASS round(up, -18px, 10px) should be used-value-equivalent to -10px
+PASS round(to-zero, 23px, 10px) should be used-value-equivalent to 20px
+PASS round(to-zero, 18px, 10px) should be used-value-equivalent to 10px
+PASS round(to-zero, 15px, 10px) should be used-value-equivalent to 10px
+PASS round(to-zero, 13px, 10px) should be used-value-equivalent to 10px
+PASS round(to-zero, -13px, 10px) should be used-value-equivalent to -10px
+PASS round(to-zero, -18px, 10px) should be used-value-equivalent to -10px
+PASS round(23px, -10px) should be used-value-equivalent to 20px
+PASS round(18px, -10px) should be used-value-equivalent to 20px
+PASS round(15px, -10px) should be used-value-equivalent to 20px
+PASS round(13px, -10px) should be used-value-equivalent to 10px
+PASS round(-13px, -10px) should be used-value-equivalent to -10px
+PASS round(-18px, -10px) should be used-value-equivalent to -20px
PASS round(5, 0) should be used-value-equivalent to calc(NaN)
PASS calc(-1 * round(5, 0)) should be used-value-equivalent to calc(NaN)
PASS round(infinity, infinity) should be used-value-equivalent to calc(NaN)
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-computed-expected.txt (0 => 283073)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-computed-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-computed-expected.txt 2021-09-25 05:03:08 UTC (rev 283073)
@@ -0,0 +1,91 @@
+
+PASS round(10,10) should be used-value-equivalent to 10
+PASS mod(1,1) should be used-value-equivalent to 0
+PASS rem(1,1) should be used-value-equivalent to 0
+PASS calc(round(100,10)) should be used-value-equivalent to 100
+PASS calc(round(up, 101,10)) should be used-value-equivalent to 110
+PASS calc(round(down, 106,10)) should be used-value-equivalent to 100
+PASS calc(round(to-zero,105, 10)) should be used-value-equivalent to 100
+PASS calc(round(to-zero,-105, 10)) should be used-value-equivalent to -100
+PASS calc(round(-100,10)) should be used-value-equivalent to -100
+PASS calc(round(up, -103,10)) should be used-value-equivalent to -100
+PASS mod(18,5) should be used-value-equivalent to 3
+PASS rem(18,5) should be used-value-equivalent to 3
+PASS mod(-140,-90) should be used-value-equivalent to -50
+PASS mod(-18,5) should be used-value-equivalent to 2
+PASS rem(-18,5) should be used-value-equivalent to -3
+PASS mod(140,-90) should be used-value-equivalent to -40
+PASS rem(140,-90) should be used-value-equivalent to 50
+PASS calc(round(round(100,10), 10)) should be used-value-equivalent to 100
+PASS calc(round(up, round(100,10) + 1,10)) should be used-value-equivalent to 110
+PASS calc(round(down, round(100,10) + 2 * 3,10)) should be used-value-equivalent to 100
+PASS calc(round(to-zero,round(100,10) * 2 - 95, 10)) should be used-value-equivalent to 100
+PASS calc(round(round(100,10)* -1,10)) should be used-value-equivalent to -100
+PASS calc(round(up, -103 + -103 / -103 - 1,10)) should be used-value-equivalent to -100
+PASS calc(mod(18,5) * 2 + mod(17,5)) should be used-value-equivalent to 8
+PASS calc(rem(mod(18,5),5)) should be used-value-equivalent to 3
+PASS calc(rem(mod(18,5),mod(17,5))) should be used-value-equivalent to 1
+PASS calc(mod(-140,-90)) should be used-value-equivalent to -50
+PASS calc(mod(rem(1,18)* -1,5)) should be used-value-equivalent to -1
+PASS round(10px,6px) should be used-value-equivalent to 12px
+PASS round(10cm,6cm) should be used-value-equivalent to 12cm
+PASS round(10mm,6mm) should be used-value-equivalent to 12mm
+PASS round(10Q, 6Q) should be used-value-equivalent to 12Q
+PASS round(10in,6in) should be used-value-equivalent to 12in
+PASS round(10pc,6pc) should be used-value-equivalent to 12pc
+PASS round(10pt,6pt) should be used-value-equivalent to 12pt
+PASS round(10em,6em) should be used-value-equivalent to 12em
+PASS round(10ex,6ex) should be used-value-equivalent to 12ex
+PASS round(10ch,6ch) should be used-value-equivalent to 12ch
+PASS round(10rem,6rem) should be used-value-equivalent to 12rem
+PASS round(10vh,6vh) should be used-value-equivalent to 12vh
+PASS round(10vw,6vw) should be used-value-equivalent to 12vw
+PASS round(10vmin,6vmin) should be used-value-equivalent to 12vmin
+PASS round(10vmax,6vmax) should be used-value-equivalent to 12vmax
+PASS round(10s,6s) should be used-value-equivalent to 12s
+PASS round(10ms,6ms) should be used-value-equivalent to 12ms
+PASS round(10deg,6deg) should be used-value-equivalent to 12deg
+PASS round(10grad,6grad) should be used-value-equivalent to 12grad
+PASS round(10rad,6rad) should be used-value-equivalent to 12rad
+PASS round(10turn,6turn) should be used-value-equivalent to 12turn
+PASS mod(10px,6px) should be used-value-equivalent to 4px
+PASS mod(10cm,6cm) should be used-value-equivalent to 4cm
+PASS mod(10mm,6mm) should be used-value-equivalent to 4mm
+PASS mod(10Q, 6Q) should be used-value-equivalent to 4Q
+PASS mod(10in,6in) should be used-value-equivalent to 4in
+PASS mod(10pc,6pc) should be used-value-equivalent to 4pc
+PASS mod(10em,6em) should be used-value-equivalent to 4em
+PASS mod(10ex,6ex) should be used-value-equivalent to 4ex
+PASS mod(10ch,6ch) should be used-value-equivalent to 4ch
+PASS mod(10rem,6rem) should be used-value-equivalent to 4rem
+PASS mod(10vh,6vh) should be used-value-equivalent to 4vh
+PASS mod(10vw,6vw) should be used-value-equivalent to 4vw
+PASS mod(10vmin,6vmin) should be used-value-equivalent to 4vmin
+PASS mod(10vmax,6vmax) should be used-value-equivalent to 4vmax
+PASS mod(10s,6s) should be used-value-equivalent to 4s
+PASS mod(10ms,6ms) should be used-value-equivalent to 4ms
+PASS mod(10deg,6deg) should be used-value-equivalent to 4deg
+PASS mod(10grad,6grad) should be used-value-equivalent to 4grad
+PASS mod(10rad,6rad) should be used-value-equivalent to 4rad
+PASS mod(10turn,6turn) should be used-value-equivalent to 4turn
+PASS rem(10px,6px) should be used-value-equivalent to 4px
+PASS rem(10cm,6cm) should be used-value-equivalent to 4cm
+PASS rem(10mm,6mm) should be used-value-equivalent to 4mm
+PASS rem(10Q, 6Q) should be used-value-equivalent to 4Q
+PASS rem(10in,6in) should be used-value-equivalent to 4in
+PASS rem(10pc,6pc) should be used-value-equivalent to 4pc
+PASS rem(10em,6em) should be used-value-equivalent to 4em
+PASS rem(10ex,6ex) should be used-value-equivalent to 4ex
+PASS rem(10ch,6ch) should be used-value-equivalent to 4ch
+PASS rem(10rem,6rem) should be used-value-equivalent to 4rem
+PASS rem(10vh,6vh) should be used-value-equivalent to 4vh
+PASS rem(10vw,6vw) should be used-value-equivalent to 4vw
+PASS rem(10vmin,6vmin) should be used-value-equivalent to 4vmin
+PASS rem(10vmax,6vmax) should be used-value-equivalent to 4vmax
+PASS rem(10s,6s) should be used-value-equivalent to 4s
+PASS rem(10ms,6ms) should be used-value-equivalent to 4ms
+PASS rem(10deg,6deg) should be used-value-equivalent to 4deg
+PASS rem(10grad,6grad) should be used-value-equivalent to 4grad
+PASS rem(10rad,6rad) should be used-value-equivalent to 4rad
+PASS rem(10turn,6turn) should be used-value-equivalent to 4turn
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-computed.html (0 => 283073)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-computed.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-computed.html 2021-09-25 05:03:08 UTC (rev 283073)
@@ -0,0 +1,111 @@
+<!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>
+// Simple tests
+test_math_used('round(10,10)', '10', {type:'number'});
+test_math_used('mod(1,1)', '0', {type:'number'});
+test_math_used('rem(1,1)', '0', {type:'number'});
+
+//Test basic round
+test_math_used('calc(round(100,10))', '100', {type:'number'});
+test_math_used('calc(round(up, 101,10))', '110', {type:'number'});
+test_math_used('calc(round(down, 106,10))', '100', {type:'number'});
+test_math_used('calc(round(to-zero,105, 10))', '100', {type:'number'});
+test_math_used('calc(round(to-zero,-105, 10))', '-100', {type:'number'});
+test_math_used('calc(round(-100,10))', '-100', {type:'number'});
+test_math_used('calc(round(up, -103,10))', '-100', {type:'number'});
+
+//Test basic mod/rem
+test_math_used('mod(18,5)', '3', {type:'number'});
+test_math_used('rem(18,5)', '3', {type:'number'});
+test_math_used('mod(-140,-90)', '-50', {type:'number'});
+test_math_used('mod(-18,5)', '2', {type:'number'});
+test_math_used('rem(-18,5)', '-3', {type:'number'});
+test_math_used('mod(140,-90)', '-40', {type:'number'});
+test_math_used('rem(140,-90)', '50', {type:'number'});
+
+//Test basic calculations
+test_math_used('calc(round(round(100,10), 10))', '100', {type:'number'});
+test_math_used('calc(round(up, round(100,10) + 1,10))', '110', {type:'number'});
+test_math_used('calc(round(down, round(100,10) + 2 * 3,10))', '100', {type:'number'});
+test_math_used('calc(round(to-zero,round(100,10) * 2 - 95, 10))', '100', {type:'number'});
+test_math_used('calc(round(round(100,10)* -1,10))', '-100', {type:'number'});
+test_math_used('calc(round(up, -103 + -103 / -103 - 1,10))', '-100', {type:'number'});
+test_math_used('calc(mod(18,5) * 2 + mod(17,5))', '8', {type:'number'});
+test_math_used('calc(rem(mod(18,5),5))', '3', {type:'number'});
+test_math_used('calc(rem(mod(18,5),mod(17,5)))', '1', {type:'number'});
+test_math_used('calc(mod(-140,-90))', '-50', {type:'number'});
+test_math_used('calc(mod(rem(1,18)* -1,5))', '-1', {type:'number'});
+
+// Type check
+test_math_used('round(10px,6px)', '12px');
+test_math_used('round(10cm,6cm)', '12cm');
+test_math_used('round(10mm,6mm)', '12mm');
+test_math_used('round(10Q, 6Q)', '12Q');
+test_math_used('round(10in,6in)', '12in');
+test_math_used('round(10pc,6pc)', '12pc');
+test_math_used('round(10pt,6pt)', '12pt');
+test_math_used('round(10em,6em)', '12em');
+test_math_used('round(10ex,6ex)', '12ex');
+test_math_used('round(10ch,6ch)', '12ch');
+test_math_used('round(10rem,6rem)', '12rem');
+test_math_used('round(10vh,6vh)', '12vh');
+test_math_used('round(10vw,6vw)', '12vw');
+test_math_used('round(10vmin,6vmin)', '12vmin');
+test_math_used('round(10vmax,6vmax)', '12vmax');
+test_math_used('round(10s,6s)', '12s');
+test_math_used('round(10ms,6ms)', '12ms');
+test_math_used('round(10deg,6deg)', '12deg', {type:'angle', approx:0.1});
+test_math_used('round(10grad,6grad)', '12grad', {type:'angle', approx:0.1});
+test_math_used('round(10rad,6rad)', '12rad',{type:'angle', approx:0.1});
+test_math_used('round(10turn,6turn)', '12turn',{type:'angle', approx:0.1});
+
+test_math_used('mod(10px,6px)', '4px');
+test_math_used('mod(10cm,6cm)', '4cm');
+test_math_used('mod(10mm,6mm)', '4mm');
+test_math_used('mod(10Q, 6Q)', '4Q');
+test_math_used('mod(10in,6in)', '4in');
+test_math_used('mod(10pc,6pc)', '4pc');
+test_math_used('mod(10em,6em)', '4em');
+test_math_used('mod(10ex,6ex)', '4ex');
+test_math_used('mod(10ch,6ch)', '4ch');
+test_math_used('mod(10rem,6rem)', '4rem');
+test_math_used('mod(10vh,6vh)', '4vh');
+test_math_used('mod(10vw,6vw)', '4vw');
+test_math_used('mod(10vmin,6vmin)', '4vmin');
+test_math_used('mod(10vmax,6vmax)', '4vmax');
+test_math_used('mod(10s,6s)', '4s');
+test_math_used('mod(10ms,6ms)', '4ms');
+test_math_used('mod(10deg,6deg)', '4deg', {type:'angle', approx:0.1});
+test_math_used('mod(10grad,6grad)', '4grad', {type:'angle', approx:0.1});
+test_math_used('mod(10rad,6rad)', '4rad',{type:'angle', approx:0.1});
+test_math_used('mod(10turn,6turn)', '4turn',{type:'angle', approx:0.1});
+
+test_math_used('rem(10px,6px)', '4px');
+test_math_used('rem(10cm,6cm)', '4cm');
+test_math_used('rem(10mm,6mm)', '4mm');
+test_math_used('rem(10Q, 6Q)', '4Q');
+test_math_used('rem(10in,6in)', '4in');
+test_math_used('rem(10pc,6pc)', '4pc');
+test_math_used('rem(10em,6em)', '4em');
+test_math_used('rem(10ex,6ex)', '4ex');
+test_math_used('rem(10ch,6ch)', '4ch');
+test_math_used('rem(10rem,6rem)', '4rem');
+test_math_used('rem(10vh,6vh)', '4vh');
+test_math_used('rem(10vw,6vw)', '4vw');
+test_math_used('rem(10vmin,6vmin)', '4vmin');
+test_math_used('rem(10vmax,6vmax)', '4vmax');
+test_math_used('rem(10s,6s)', '4s');
+test_math_used('rem(10ms,6ms)', '4ms');
+test_math_used('rem(10deg,6deg)', '4deg', {type:'angle', approx:0.1});
+test_math_used('rem(10grad,6grad)', '4grad', {type:'angle', approx:0.1});
+test_math_used('rem(10rad,6rad)', '4rad',{type:'angle', approx:0.1});
+test_math_used('rem(10turn,6turn)', '4turn',{type:'angle', approx:0.1});
+</script>
\ No newline at end of file
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-invalid-expected.txt (0 => 283073)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-invalid-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-invalid-expected.txt 2021-09-25 05:03:08 UTC (rev 283073)
@@ -0,0 +1,79 @@
+
+PASS e.style['opacity'] = "round()" should not set the property value
+PASS e.style['opacity'] = "round( )" should not set the property value
+PASS e.style['opacity'] = "round(,)" should not set the property value
+PASS e.style['opacity'] = "round(1, )" should not set the property value
+PASS e.style['opacity'] = "round(, 1)" should not set the property value
+PASS e.style['opacity'] = "round(1 + )" should not set the property value
+PASS e.style['opacity'] = "round(1 - )" should not set the property value
+PASS e.style['opacity'] = "round(1 * )" should not set the property value
+PASS e.style['opacity'] = "round(1 / )" should not set the property value
+PASS e.style['opacity'] = "round(1 2)" should not set the property value
+PASS e.style['opacity'] = "round(nearest, 1 2)" should not set the property value
+PASS e.style['opacity'] = "round(1, nearest, 12)" should not set the property value
+PASS e.style['opacity'] = "round(1, nearest)" should not set the property value
+PASS e.style['opacity'] = "round(nearest, 1, nearest)" should not set the property value
+PASS e.style['opacity'] = "round(nearest, 1)" should not set the property value
+PASS e.style['opacity'] = "round(1, , 2)" should not set the property value
+PASS e.style['opacity'] = "mod()" should not set the property value
+PASS e.style['opacity'] = "mod( )" should not set the property value
+PASS e.style['opacity'] = "mod(,)" should not set the property value
+PASS e.style['opacity'] = "mod(1, )" should not set the property value
+PASS e.style['opacity'] = "mod(, 1)" should not set the property value
+PASS e.style['opacity'] = "mod(1 + )" should not set the property value
+PASS e.style['opacity'] = "mod(1 - )" should not set the property value
+PASS e.style['opacity'] = "mod(1 * )" should not set the property value
+PASS e.style['opacity'] = "mod(1 / )" should not set the property value
+PASS e.style['opacity'] = "mod(1 2)" should not set the property value
+PASS e.style['opacity'] = "mod(1, , 2)" should not set the property value
+PASS e.style['opacity'] = "rem()" should not set the property value
+PASS e.style['opacity'] = "rem( )" should not set the property value
+PASS e.style['opacity'] = "rem(,)" should not set the property value
+PASS e.style['opacity'] = "rem(1, )" should not set the property value
+PASS e.style['opacity'] = "rem(, 1)" should not set the property value
+PASS e.style['opacity'] = "rem(1 + )" should not set the property value
+PASS e.style['opacity'] = "rem(1 - )" should not set the property value
+PASS e.style['opacity'] = "rem(1 * )" should not set the property value
+PASS e.style['opacity'] = "rem(1 / )" should not set the property value
+PASS e.style['opacity'] = "rem(1 2)" should not set the property value
+PASS e.style['opacity'] = "rem(1, , 2)" should not set the property value
+PASS e.style['opacity'] = "round(0px)" should not set the property value
+PASS e.style['opacity'] = "round(0s)" should not set the property value
+PASS e.style['opacity'] = "round(0deg)" should not set the property value
+PASS e.style['opacity'] = "round(0Hz)" should not set the property value
+PASS e.style['opacity'] = "round(0dpi)" should not set the property value
+PASS e.style['opacity'] = "round(0fr)" should not set the property value
+PASS e.style['opacity'] = "round(1, 1%)" should not set the property value
+PASS e.style['opacity'] = "round(1, 0px)" should not set the property value
+PASS e.style['opacity'] = "round(1, 0s)" should not set the property value
+PASS e.style['opacity'] = "round(1, 0deg)" should not set the property value
+PASS e.style['opacity'] = "round(1, 0Hz)" should not set the property value
+PASS e.style['opacity'] = "round(1, 0dpi)" should not set the property value
+PASS e.style['opacity'] = "round(1, 0fr)" should not set the property value
+PASS e.style['opacity'] = "mod(0px)" should not set the property value
+PASS e.style['opacity'] = "mod(0s)" should not set the property value
+PASS e.style['opacity'] = "mod(0deg)" should not set the property value
+PASS e.style['opacity'] = "mod(0Hz)" should not set the property value
+PASS e.style['opacity'] = "mod(0dpi)" should not set the property value
+PASS e.style['opacity'] = "mod(0fr)" should not set the property value
+PASS e.style['opacity'] = "mod(1, 1%)" should not set the property value
+PASS e.style['opacity'] = "mod(1, 0px)" should not set the property value
+PASS e.style['opacity'] = "mod(1, 0s)" should not set the property value
+PASS e.style['opacity'] = "mod(1, 0deg)" should not set the property value
+PASS e.style['opacity'] = "mod(1, 0Hz)" should not set the property value
+PASS e.style['opacity'] = "mod(1, 0dpi)" should not set the property value
+PASS e.style['opacity'] = "mod(1, 0fr)" should not set the property value
+PASS e.style['opacity'] = "rem(0px)" should not set the property value
+PASS e.style['opacity'] = "rem(0s)" should not set the property value
+PASS e.style['opacity'] = "rem(0deg)" should not set the property value
+PASS e.style['opacity'] = "rem(0Hz)" should not set the property value
+PASS e.style['opacity'] = "rem(0dpi)" should not set the property value
+PASS e.style['opacity'] = "rem(0fr)" should not set the property value
+PASS e.style['opacity'] = "rem(1, 1%)" should not set the property value
+PASS e.style['opacity'] = "rem(1, 0px)" should not set the property value
+PASS e.style['opacity'] = "rem(1, 0s)" should not set the property value
+PASS e.style['opacity'] = "rem(1, 0deg)" should not set the property value
+PASS e.style['opacity'] = "rem(1, 0Hz)" should not set the property value
+PASS e.style['opacity'] = "rem(1, 0dpi)" should not set the property value
+PASS e.style['opacity'] = "rem(1, 0fr)" should not set the property value
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-invalid.html (0 => 283073)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-invalid.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-invalid.html 2021-09-25 05:03:08 UTC (rev 283073)
@@ -0,0 +1,94 @@
+<!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_number(value) {
+ test_invalid_value('opacity', value);
+}
+
+// Syntax checking
+test_invalid_number('round()');
+test_invalid_number('round( )');
+test_invalid_number('round(,)');
+test_invalid_number('round(1, )');
+test_invalid_number('round(, 1)');
+test_invalid_number('round(1 + )');
+test_invalid_number('round(1 - )');
+test_invalid_number('round(1 * )');
+test_invalid_number('round(1 / )');
+test_invalid_number('round(1 2)');
+test_invalid_number('round(nearest, 1 2)');
+test_invalid_number('round(1, nearest, 12)');
+test_invalid_number('round(1, nearest)');
+test_invalid_number('round(nearest, 1, nearest)');
+test_invalid_number('round(nearest, 1)');
+test_invalid_number('round(1, , 2)');
+test_invalid_number('mod()');
+test_invalid_number('mod( )');
+test_invalid_number('mod(,)');
+test_invalid_number('mod(1, )');
+test_invalid_number('mod(, 1)');
+test_invalid_number('mod(1 + )');
+test_invalid_number('mod(1 - )');
+test_invalid_number('mod(1 * )');
+test_invalid_number('mod(1 / )');
+test_invalid_number('mod(1 2)');
+test_invalid_number('mod(1, , 2)');
+test_invalid_number('rem()');
+test_invalid_number('rem( )');
+test_invalid_number('rem(,)');
+test_invalid_number('rem(1, )');
+test_invalid_number('rem(, 1)');
+test_invalid_number('rem(1 + )');
+test_invalid_number('rem(1 - )');
+test_invalid_number('rem(1 * )');
+test_invalid_number('rem(1 / )');
+test_invalid_number('rem(1 2)');
+test_invalid_number('rem(1, , 2)');
+
+// Type checking
+test_invalid_number('round(0px)');
+test_invalid_number('round(0s)');
+test_invalid_number('round(0deg)');
+test_invalid_number('round(0Hz)');
+test_invalid_number('round(0dpi)');
+test_invalid_number('round(0fr)');
+test_invalid_number('round(1, 1%)');
+test_invalid_number('round(1, 0px)');
+test_invalid_number('round(1, 0s)');
+test_invalid_number('round(1, 0deg)');
+test_invalid_number('round(1, 0Hz)');
+test_invalid_number('round(1, 0dpi)');
+test_invalid_number('round(1, 0fr)');
+test_invalid_number('mod(0px)');
+test_invalid_number('mod(0s)');
+test_invalid_number('mod(0deg)');
+test_invalid_number('mod(0Hz)');
+test_invalid_number('mod(0dpi)');
+test_invalid_number('mod(0fr)');
+test_invalid_number('mod(1, 1%)');
+test_invalid_number('mod(1, 0px)');
+test_invalid_number('mod(1, 0s)');
+test_invalid_number('mod(1, 0deg)');
+test_invalid_number('mod(1, 0Hz)');
+test_invalid_number('mod(1, 0dpi)');
+test_invalid_number('mod(1, 0fr)');
+test_invalid_number('rem(0px)');
+test_invalid_number('rem(0s)');
+test_invalid_number('rem(0deg)');
+test_invalid_number('rem(0Hz)');
+test_invalid_number('rem(0dpi)');
+test_invalid_number('rem(0fr)');
+test_invalid_number('rem(1, 1%)');
+test_invalid_number('rem(1, 0px)');
+test_invalid_number('rem(1, 0s)');
+test_invalid_number('rem(1, 0deg)');
+test_invalid_number('rem(1, 0Hz)');
+test_invalid_number('rem(1, 0dpi)');
+test_invalid_number('rem(1, 0fr)');
+</script>
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-serialize-expected.txt (0 => 283073)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-serialize-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-serialize-expected.txt 2021-09-25 05:03:08 UTC (rev 283073)
@@ -0,0 +1,14 @@
+
+FAIL 'round(1.1,1)' as a specified value should serialize as 'calc(1)'. assert_equals: 'round(1.1,1)' and 'calc(1)' should serialize the same in specified values. expected "calc(1)" but got "round(nearest, 1.1, 1)"
+FAIL 'scale(round(1.1,1))' as a specified value should serialize as 'scale(calc(1))'. assert_equals: 'scale(round(1.1,1))' and 'scale(calc(1))' should serialize the same in specified values. expected "scale(calc(1))" but got "scale(round(nearest, 1.1, 1))"
+PASS 'round(1.1,1)' as a computed value should serialize as '1'.
+PASS 'scale(round(1.1,1))' as a computed value should serialize as 'matrix(1, 0, 0, 1, 0, 0)'.
+FAIL 'mod(1,1)' as a specified value should serialize as 'calc(0)'. assert_equals: 'mod(1,1)' and 'calc(0)' should serialize the same in specified values. expected "calc(0)" but got "mod(1, 1)"
+FAIL 'scale(mod(1,1))' as a specified value should serialize as 'scale(calc(0))'. assert_equals: 'scale(mod(1,1))' and 'scale(calc(0))' should serialize the same in specified values. expected "scale(calc(0))" but got "scale(mod(1, 1))"
+PASS 'mod(1,1)' as a computed value should serialize as '0'.
+PASS 'scale(mod(1,1))' as a computed value should serialize as 'matrix(0, 0, 0, 0, 0, 0)'.
+FAIL 'rem(1,1)' as a specified value should serialize as 'calc(0)'. assert_equals: 'rem(1,1)' and 'calc(0)' should serialize the same in specified values. expected "calc(0)" but got "rem(1, 1)"
+FAIL 'scale(rem(1,1))' as a specified value should serialize as 'scale(calc(0))'. assert_equals: 'scale(rem(1,1))' and 'scale(calc(0))' should serialize the same in specified values. expected "scale(calc(0))" but got "scale(rem(1, 1))"
+PASS 'rem(1,1)' as a computed value should serialize as '0'.
+PASS 'scale(rem(1,1))' as a computed value should serialize as 'matrix(0, 0, 0, 0, 0, 0)'.
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-serialize.html (0 => 283073)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-serialize.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-values/round-mod-rem-serialize.html 2021-09-25 05:03:08 UTC (rev 283073)
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<link rel="help" href=""
+<link rel="help" href=""
+<link rel="help" href=""
+<link rel="author" title="Xiaocheng Hu" href=""
+<link rel="author" title="Apple Inc">
+<script src=""
+<script src=""
+<script src=""
+<div id=target></div>
+<script>
+function test_serialization(t,s,c) {
+ test_specified_serialization('opacity', t, s);
+ test_specified_serialization('transform', `scale(${t})`, `scale(calc(${c}))`);
+ test_computed_serialization('opacity', t, c);
+ test_computed_serialization('transform', `scale(${t})`, `matrix(${c}, 0, 0, ${c}, 0, 0)`);
+}
+
+test_serialization(
+ 'round(1.1,1)',
+ 'calc(1)',
+ '1');
+test_serialization(
+ 'mod(1,1)',
+ 'calc(0)',
+ '0');
+test_serialization(
+ 'rem(1,1)',
+ 'calc(0)',
+ '0');
+</script>
Modified: trunk/Source/WebCore/ChangeLog (283072 => 283073)
--- trunk/Source/WebCore/ChangeLog 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/Source/WebCore/ChangeLog 2021-09-25 05:03:08 UTC (rev 283073)
@@ -1,3 +1,53 @@
+2021-09-24 Nikos Mouchtaris <nmouchta...@apple.com>
+
+ Implement round,mod,rem functions for calc
+ https://bugs.webkit.org/show_bug.cgi?id=230073
+
+ Reviewed by Simon Fraser.
+
+ Implemented round, mod and rem calc functions. Involved adding css keywords for the functions
+ and the keywords associated with the round function, as well as implementing the parsing and
+ computation of the _expression_. The spec for these functions:
+ https://drafts.csswg.org/css-values-4/#round-func.
+
+ Tests: imported/w3c/web-platform-tests/css/css-values/round-mod-rem-computed.html
+ imported/w3c/web-platform-tests/css/css-values/round-mod-rem-invalid.html
+ imported/w3c/web-platform-tests/css/css-values/round-mod-rem-serialize.html
+
+ * css/CSSValueKeywords.in:
+ * css/calc/CSSCalcExpressionNodeParser.cpp:
+ (WebCore::CSSCalcExpressionNodeParser::parseCalcFunction):
+ (WebCore::checkRoundKeyword):
+ Addition of functionID to parsing so the round keywords are only parsed within round
+ function.
+ (WebCore::CSSCalcExpressionNodeParser::parseValue):
+ (WebCore::CSSCalcExpressionNodeParser::parseCalcValue):
+ (WebCore::CSSCalcExpressionNodeParser::parseCalcProduct):
+ (WebCore::CSSCalcExpressionNodeParser::parseCalcSum):
+ * css/calc/CSSCalcExpressionNodeParser.h:
+ * css/calc/CSSCalcOperationNode.cpp:
+ (WebCore::determineCategory):
+ (WebCore::functionFromOperator):
+ (WebCore::CSSCalcOperationNode::createStep):
+ (WebCore::validateRoundChildren):
+ (WebCore::CSSCalcOperationNode::createRound):
+ (WebCore::CSSCalcOperationNode::createRoundConstant):
+ (WebCore::CSSCalcOperationNode::combineChildren):
+ (WebCore::CSSCalcOperationNode::simplifyNode):
+ (WebCore::functionPrefixForOperator):
+ (WebCore::getNearestMultiples):
+ (WebCore::CSSCalcOperationNode::evaluateOperator):
+ * css/calc/CSSCalcOperationNode.h:
+ * css/calc/CSSCalcValue.cpp:
+ (WebCore::createCSS):
+ (WebCore::CSSCalcValue::isCalcFunction):
+ * platform/calc/CalcExpressionOperation.cpp:
+ (WebCore::getNearestMultiples):
+ (WebCore::CalcExpressionOperation::evaluate const):
+ * platform/calc/CalcOperator.cpp:
+ (WebCore::operator<<):
+ * platform/calc/CalcOperator.h:
+
2021-09-24 Simon Fraser <simon.fra...@apple.com>
Add a ScrollAnimations log channel
Modified: trunk/Source/WebCore/css/CSSValueKeywords.in (283072 => 283073)
--- trunk/Source/WebCore/css/CSSValueKeywords.in 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/Source/WebCore/css/CSSValueKeywords.in 2021-09-25 05:03:08 UTC (rev 283073)
@@ -1359,6 +1359,10 @@
atan2
abs
sign
+mod
+rem
+to-zero
+nearest
from-image
Modified: trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.cpp (283072 => 283073)
--- trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.cpp 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.cpp 2021-09-25 05:03:08 UTC (rev 283073)
@@ -129,10 +129,18 @@
minArgumentCount = 3;
maxArgumentCount = 3;
break;
-
case CSSValueLog:
maxArgumentCount = 2;
break;
+ case CSSValueRound:
+ minArgumentCount = 2;
+ maxArgumentCount = 3;
+ break;
+ case CSSValueMod:
+ case CSSValueRem:
+ minArgumentCount = 2;
+ maxArgumentCount = 2;
+ break;
case CSSValueExp:
case CSSValueSin:
case CSSValueCos:
@@ -163,7 +171,7 @@
return false;
RefPtr<CSSCalcExpressionNode> node;
- if (!parseCalcSum(tokens, depth, node))
+ if (!parseCalcSum(tokens, functionID, depth, node))
return false;
++argumentCount;
@@ -196,6 +204,15 @@
case CSSValueTan:
result = CSSCalcOperationNode::createTrig(CalcOperator::Tan, WTFMove(nodes));
break;
+ case CSSValueRound:
+ result = CSSCalcOperationNode::createRound(WTFMove(nodes));
+ break;
+ case CSSValueMod:
+ result = CSSCalcOperationNode::createStep(CalcOperator::Mod, WTFMove(nodes));
+ break;
+ case CSSValueRem:
+ result = CSSCalcOperationNode::createStep(CalcOperator::Rem, WTFMove(nodes));
+ break;
case CSSValueWebkitCalc:
case CSSValueCalc:
result = CSSCalcOperationNode::createSum(WTFMove(nodes));
@@ -232,8 +249,30 @@
return !!result;
}
-bool CSSCalcExpressionNodeParser::parseValue(CSSParserTokenRange& tokens, RefPtr<CSSCalcExpressionNode>& result)
+static bool checkRoundKeyword(CSSValueID functionID, RefPtr<CSSCalcExpressionNode>& result, CSSValueID constantID)
{
+ if (functionID != CSSValueRound)
+ return false;
+ switch (constantID) {
+ case CSSValueNearest:
+ result = CSSCalcOperationNode::createRoundConstant(CalcOperator::Nearest);
+ return true;
+ case CSSValueToZero:
+ result = CSSCalcOperationNode::createRoundConstant(CalcOperator::ToZero);
+ return true;
+ case CSSValueUp:
+ result = CSSCalcOperationNode::createRoundConstant(CalcOperator::Up);
+ return true;
+ case CSSValueDown:
+ result = CSSCalcOperationNode::createRoundConstant(CalcOperator::Down);
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool CSSCalcExpressionNodeParser::parseValue(CSSParserTokenRange& tokens, CSSValueID functionID, RefPtr<CSSCalcExpressionNode>& result)
+{
auto makeCSSCalcPrimitiveValueNode = [&] (CSSUnitType type, double value) -> bool {
if (calcUnitCategory(type) == CalculationCategory::Other)
return false;
@@ -246,6 +285,8 @@
switch (token.type()) {
case IdentToken: {
+ if (checkRoundKeyword(functionID, result, token.id()))
+ return true;
auto value = m_symbolTable.get(token.id());
value = value ? value : getConstantTable().get(token.id());
if (!value)
@@ -266,7 +307,7 @@
return false;
}
-bool CSSCalcExpressionNodeParser::parseCalcValue(CSSParserTokenRange& tokens, int depth, RefPtr<CSSCalcExpressionNode>& result)
+bool CSSCalcExpressionNodeParser::parseCalcValue(CSSParserTokenRange& tokens, CSSValueID functionID, int depth, RefPtr<CSSCalcExpressionNode>& result)
{
if (checkDepthAndIndex(depth, tokens) != OK)
return false;
@@ -289,16 +330,16 @@
return parseCalcFunction(innerRange, functionId, depth + 1, result);
}
- return parseValue(tokens, result);
+ return parseValue(tokens, functionID, result);
}
-bool CSSCalcExpressionNodeParser::parseCalcProduct(CSSParserTokenRange& tokens, int depth, RefPtr<CSSCalcExpressionNode>& result)
+bool CSSCalcExpressionNodeParser::parseCalcProduct(CSSParserTokenRange& tokens, CSSValueID functionID, int depth, RefPtr<CSSCalcExpressionNode>& result)
{
if (checkDepthAndIndex(depth, tokens) != OK)
return false;
RefPtr<CSSCalcExpressionNode> firstValue;
- if (!parseCalcValue(tokens, depth, firstValue))
+ if (!parseCalcValue(tokens, functionID, depth, firstValue))
return false;
Vector<Ref<CSSCalcExpressionNode>> nodes;
@@ -310,7 +351,7 @@
tokens.consumeIncludingWhitespace();
RefPtr<CSSCalcExpressionNode> nextValue;
- if (!parseCalcValue(tokens, depth, nextValue) || !nextValue)
+ if (!parseCalcValue(tokens, functionID, depth, nextValue) || !nextValue)
return false;
if (operatorCharacter == static_cast<char>(CalcOperator::Divide))
@@ -331,13 +372,13 @@
return !!result;
}
-bool CSSCalcExpressionNodeParser::parseCalcSum(CSSParserTokenRange& tokens, int depth, RefPtr<CSSCalcExpressionNode>& result)
+bool CSSCalcExpressionNodeParser::parseCalcSum(CSSParserTokenRange& tokens, CSSValueID functionID, int depth, RefPtr<CSSCalcExpressionNode>& result)
{
if (checkDepthAndIndex(depth, tokens) != OK)
return false;
RefPtr<CSSCalcExpressionNode> firstValue;
- if (!parseCalcProduct(tokens, depth, firstValue))
+ if (!parseCalcProduct(tokens, functionID, depth, firstValue))
return false;
Vector<Ref<CSSCalcExpressionNode>> nodes;
@@ -357,7 +398,7 @@
tokens.consumeIncludingWhitespace();
RefPtr<CSSCalcExpressionNode> nextValue;
- if (!parseCalcProduct(tokens, depth, nextValue) || !nextValue)
+ if (!parseCalcProduct(tokens, functionID, depth, nextValue) || !nextValue)
return false;
if (operatorCharacter == static_cast<char>(CalcOperator::Subtract))
Modified: trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.h (283072 => 283073)
--- trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.h 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/Source/WebCore/css/calc/CSSCalcExpressionNodeParser.h 2021-09-25 05:03:08 UTC (rev 283073)
@@ -49,12 +49,12 @@
private:
char operatorValue(const CSSParserToken&);
- bool parseValue(CSSParserTokenRange&, RefPtr<CSSCalcExpressionNode>&);
- bool parseValueTerm(CSSParserTokenRange&, int depth, RefPtr<CSSCalcExpressionNode>&);
+ bool parseValue(CSSParserTokenRange&, CSSValueID, RefPtr<CSSCalcExpressionNode>&);
+ bool parseValueTerm(CSSParserTokenRange&, CSSValueID, int depth, RefPtr<CSSCalcExpressionNode>&);
bool parseCalcFunction(CSSParserTokenRange&, CSSValueID, int depth, RefPtr<CSSCalcExpressionNode>&);
- bool parseCalcSum(CSSParserTokenRange&, int depth, RefPtr<CSSCalcExpressionNode>&);
- bool parseCalcProduct(CSSParserTokenRange&, int depth, RefPtr<CSSCalcExpressionNode>&);
- bool parseCalcValue(CSSParserTokenRange&, int depth, RefPtr<CSSCalcExpressionNode>&);
+ bool parseCalcSum(CSSParserTokenRange&, CSSValueID, int depth, RefPtr<CSSCalcExpressionNode>&);
+ bool parseCalcProduct(CSSParserTokenRange&, CSSValueID, int depth, RefPtr<CSSCalcExpressionNode>&);
+ bool parseCalcValue(CSSParserTokenRange&, CSSValueID, int depth, RefPtr<CSSCalcExpressionNode>&);
CalculationCategory m_destinationCategory;
const CSSCalcSymbolTable& m_symbolTable;
Modified: trunk/Source/WebCore/css/calc/CSSCalcOperationNode.cpp (283072 => 283073)
--- trunk/Source/WebCore/css/calc/CSSCalcOperationNode.cpp 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/Source/WebCore/css/calc/CSSCalcOperationNode.cpp 2021-09-25 05:03:08 UTC (rev 283073)
@@ -87,6 +87,13 @@
case CalcOperator::Atan2:
case CalcOperator::Abs:
case CalcOperator::Sign:
+ case CalcOperator::Mod:
+ case CalcOperator::Rem:
+ case CalcOperator::Round:
+ case CalcOperator::Up:
+ case CalcOperator::Down:
+ case CalcOperator::Nearest:
+ case CalcOperator::ToZero:
ASSERT_NOT_REACHED();
return CalculationCategory::Other;
}
@@ -166,6 +173,13 @@
case CalcOperator::Acos:
case CalcOperator::Atan:
case CalcOperator::Atan2:
+ case CalcOperator::Mod:
+ case CalcOperator::Rem:
+ case CalcOperator::Round:
+ case CalcOperator::Up:
+ case CalcOperator::Down:
+ case CalcOperator::Nearest:
+ case CalcOperator::ToZero:
// The type of a min(), max(), or clamp() _expression_ is the result of adding the types of its comma-separated calculations
return CalculationCategory::Other;
}
@@ -299,6 +313,20 @@
return CSSValueAbs;
case CalcOperator::Sign:
return CSSValueSign;
+ case CalcOperator::Mod:
+ return CSSValueMod;
+ case CalcOperator::Rem:
+ return CSSValueRem;
+ case CalcOperator::Round:
+ return CSSValueRound;
+ case CalcOperator::Up:
+ return CSSValueUp;
+ case CalcOperator::Down:
+ return CSSValueDown;
+ case CalcOperator::Nearest:
+ return CSSValueNearest;
+ case CalcOperator::ToZero:
+ return CSSValueToZero;
}
return CSSValueCalc;
}
@@ -476,6 +504,68 @@
return adoptRef(new CSSCalcOperationNode(newCategory, op, WTFMove(values)));
}
+RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::createStep(CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& values)
+{
+ if (values.size() != 2)
+ return nullptr;
+
+ if (values[0]->category() != values[1]->category()) {
+ LOG_WITH_STREAM(Calc, stream << "Failed to create stepped value node because unable to determine category from " << prettyPrintNodes(values));
+ return nullptr;
+ }
+
+ if (!values[1]->doubleValue(values[1]->primitiveType())) {
+ LOG_WITH_STREAM(Calc, stream << "Failed to create stepped value node because unable to determine category from " << prettyPrintNodes(values));
+ return nullptr;
+ }
+
+ return adoptRef(new CSSCalcOperationNode(values[0]->category(), op, WTFMove(values)));
+}
+
+static bool validateRoundChildren(Vector<Ref<CSSCalcExpressionNode>>& values)
+{
+ // for 3 children 1st node must be round constant
+ if (values.size() == 3) {
+ if (!is<CSSCalcOperationNode>(values[0]) || !(downcast<CSSCalcOperationNode>(values[0].get()).isRoundOperation()))
+ return false;
+ }
+ // for 2 children should not have round constant anywhere but first node of 3
+ for (size_t i = values.size() == 2 ? 0 : 1; i < values.size(); i++) {
+ if (is<CSSCalcOperationNode>(values[i])) {
+ if (downcast<CSSCalcOperationNode>(values[i].get()).isRoundConstant())
+ return false;
+ }
+ }
+ // check that two categories of numerical values are the same
+ return values.rbegin()[1]->category() == values.rbegin()[0]->category();
+
+}
+
+RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::createRound(Vector<Ref<CSSCalcExpressionNode>>&& values)
+{
+ if (values.size() != 2 && values.size() != 3)
+ return nullptr;
+
+ if (!validateRoundChildren(values)) {
+ LOG_WITH_STREAM(Calc, stream << "Failed to create round node because unable to determine category from " << prettyPrintNodes(values));
+ return nullptr;
+ }
+
+ CalcOperator roundType = values.size() == 2 ? CalcOperator::Nearest : downcast<CSSCalcOperationNode>(values[0].get()).calcOperator();
+ if (values.size() == 3)
+ values.remove(0);
+ if (!values[1]->doubleValue(values[1]->primitiveType())) {
+ LOG_WITH_STREAM(Calc, stream << "Failed to create round node because unable to determine category from " << prettyPrintNodes(values));
+ return nullptr;
+ }
+ return adoptRef(new CSSCalcOperationNode(values.rbegin()[0]->category(), roundType, WTFMove(values)));
+}
+
+RefPtr<CSSCalcOperationNode> CSSCalcOperationNode::createRoundConstant(CalcOperator op)
+{
+ return adoptRef(new CSSCalcOperationNode(CalculationCategory::Number, op, { }));
+}
+
void CSSCalcOperationNode::hoistChildrenWithOperator(CalcOperator op)
{
ASSERT(op == CalcOperator::Add || op == CalcOperator::Multiply);
@@ -710,6 +800,20 @@
m_children.clear();
m_children.append(WTFMove(newChild));
}
+ if (isSteppedNode()) {
+ auto combinedUnitType = m_children[0]->primitiveType();
+ double resolvedValue = doubleValue(combinedUnitType);
+ auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, combinedUnitType));
+ m_children.clear();
+ m_children.append(WTFMove(newChild));
+ }
+ if (isRoundOperation()) {
+ auto combinedUnitType = m_children[0]->primitiveType();
+ double resolvedValue = doubleValue(combinedUnitType);
+ auto newChild = CSSCalcPrimitiveValueNode::create(CSSPrimitiveValue::create(resolvedValue, combinedUnitType));
+ m_children.clear();
+ m_children.append(WTFMove(newChild));
+ }
}
// https://drafts.csswg.org/css-values-4/#simplify-a-calculation-tree
@@ -798,6 +902,11 @@
if (calcOperationNode.isSignNode() && depth)
calcOperationNode.combineChildren();
+ if (calcOperationNode.isSteppedNode() && depth)
+ calcOperationNode.combineChildren();
+
+ if (calcOperationNode.isRoundOperation() && depth)
+ calcOperationNode.combineChildren();
// If only one child remains, return the child (except at the root).
auto shouldCombineParentWithOnlyChild = [](const CSSCalcOperationNode& parent, int depth)
{
@@ -1003,6 +1112,13 @@
case CalcOperator::Atan2: return "atan2(";
case CalcOperator::Abs: return "abs(";
case CalcOperator::Sign: return "sign(";
+ case CalcOperator::Mod: return "mod(";
+ case CalcOperator::Rem: return "rem(";
+ case CalcOperator::Round: return "round(";
+ case CalcOperator::Up: return "round(up, ";
+ case CalcOperator::Down: return "round(down, ";
+ case CalcOperator::Nearest: return "round(nearest, ";
+ case CalcOperator::ToZero: return "round(to-zero, ";
}
return "";
@@ -1157,6 +1273,13 @@
return true;
}
+static std::pair<double, double> getNearestMultiples(double a, double b)
+{
+ double lowerB = std::floor(a / std::abs(b))*std::abs(b);
+ double upperB = lowerB + std::abs(b);
+ return std::make_pair(lowerB, upperB);
+}
+
double CSSCalcOperationNode::evaluateOperator(CalcOperator op, const Vector<double>& children)
{
switch (op) {
@@ -1265,7 +1388,57 @@
return -1;
return children[0];
}
+ case CalcOperator::Mod: {
+ if (children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ float left = children[0];
+ float right = children[1];
+ if (!right)
+ return std::numeric_limits<double>::quiet_NaN();
+ if ((left < 0) == (right < 0))
+ return std::fmod(left, right);
+ return std::remainder(left, right);
}
+ case CalcOperator::Rem: {
+ if (children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ float left = children[0];
+ float right = children[1];
+ if (!right)
+ return std::numeric_limits<double>::quiet_NaN();
+ return std::fmod(left, right);
+ }
+ case CalcOperator::Round:
+ return std::numeric_limits<double>::quiet_NaN();
+ case CalcOperator::Up: {
+ if (children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ auto ret = getNearestMultiples(children[0], children[1]);
+ return ret.second;
+ }
+ case CalcOperator::Down: {
+ if (children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ auto ret = getNearestMultiples(children[0], children[1]);
+ return ret.first;
+ }
+ case CalcOperator::Nearest: {
+ if (children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ auto ret = getNearestMultiples(children[0], children[1]);
+ auto upperB = ret.second;
+ auto lowerB = ret.first;
+ return std::abs(upperB - children[0]) <= std::abs(children[1]) / 2 ? upperB : lowerB;
+ }
+ case CalcOperator::ToZero: {
+ if (children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ auto ret = getNearestMultiples(children[0], children[1]);
+ auto upperB = ret.second;
+ auto lowerB = ret.first;
+ return std::abs(upperB) < std::abs(lowerB) ? upperB : lowerB;
+ }
+ }
ASSERT_NOT_REACHED();
return 0;
}
Modified: trunk/Source/WebCore/css/calc/CSSCalcOperationNode.h (283072 => 283073)
--- trunk/Source/WebCore/css/calc/CSSCalcOperationNode.h 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/Source/WebCore/css/calc/CSSCalcOperationNode.h 2021-09-25 05:03:08 UTC (rev 283073)
@@ -43,6 +43,9 @@
static RefPtr<CSSCalcOperationNode> createInverseTrig(CalcOperator, Vector<Ref<CSSCalcExpressionNode>>&& values);
static RefPtr<CSSCalcOperationNode> createAtan2(Vector<Ref<CSSCalcExpressionNode>>&& values);
static RefPtr<CSSCalcOperationNode> createSign(CalcOperator, Vector<Ref<CSSCalcExpressionNode>>&& values);
+ static RefPtr<CSSCalcOperationNode> createStep(CalcOperator, Vector<Ref<CSSCalcExpressionNode>>&& values);
+ static RefPtr<CSSCalcOperationNode> createRound(Vector<Ref<CSSCalcExpressionNode>>&& values);
+ static RefPtr<CSSCalcOperationNode> createRoundConstant(CalcOperator);
static Ref<CSSCalcExpressionNode> simplify(Ref<CSSCalcExpressionNode>&&);
static void buildCSSText(const CSSCalcExpressionNode&, StringBuilder&);
@@ -57,6 +60,9 @@
bool isAtan2Node() const { return m_operator == CalcOperator::Atan2; }
bool isSignNode() const { return m_operator == CalcOperator::Abs || m_operator == CalcOperator::Sign; }
bool shouldSortChildren() const { return isCalcSumNode() || isCalcProductNode(); }
+ bool isSteppedNode() const { return m_operator == CalcOperator::Mod || m_operator == CalcOperator::Rem || m_operator == CalcOperator::Round; }
+ bool isRoundOperation() const { return m_operator == CalcOperator::Down || m_operator == CalcOperator::Up || m_operator == CalcOperator::ToZero || m_operator == CalcOperator::Nearest; }
+ bool isRoundConstant() const { return (isRoundOperation()) && !m_children.size(); }
void hoistChildrenWithOperator(CalcOperator);
void combineChildren();
Modified: trunk/Source/WebCore/css/calc/CSSCalcValue.cpp (283072 => 283073)
--- trunk/Source/WebCore/css/calc/CSSCalcValue.cpp 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/Source/WebCore/css/calc/CSSCalcValue.cpp 2021-09-25 05:03:08 UTC (rev 283073)
@@ -213,7 +213,21 @@
return nullptr;
return CSSCalcOperationNode::createSign(op, WTFMove(children));
}
+ case CalcOperator::Mod:
+ case CalcOperator::Rem:
+ case CalcOperator::Round: {
+ auto children = createCSS(operationChildren, style);
+ if (children.size() != 2)
+ return nullptr;
+ return CSSCalcOperationNode::createStep(op, WTFMove(children));
}
+ case CalcOperator::Nearest:
+ case CalcOperator::ToZero:
+ case CalcOperator::Up:
+ case CalcOperator::Down: {
+ return CSSCalcOperationNode::createRoundConstant(op);
+ }
+ }
return nullptr;
}
case CalcExpressionNodeType::BlendLength: {
@@ -335,6 +349,9 @@
case CSSValueAtan2:
case CSSValueAbs:
case CSSValueSign:
+ case CSSValueRound:
+ case CSSValueMod:
+ case CSSValueRem:
return true;
default:
return false;
Modified: trunk/Source/WebCore/platform/calc/CalcExpressionOperation.cpp (283072 => 283073)
--- trunk/Source/WebCore/platform/calc/CalcExpressionOperation.cpp 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/Source/WebCore/platform/calc/CalcExpressionOperation.cpp 2021-09-25 05:03:08 UTC (rev 283073)
@@ -31,6 +31,14 @@
namespace WebCore {
+static std::pair<double, double> getNearestMultiples(double a, double b)
+{
+ auto absB = std::abs(b);
+ double lowerB = std::floor(a / absB) * absB;
+ double upperB = lowerB + absB;
+ return std::make_pair(lowerB, upperB);
+}
+
float CalcExpressionOperation::evaluate(float maxValue) const
{
switch (m_operator) {
@@ -148,7 +156,59 @@
return -1;
return m_children[0]->evaluate(maxValue);
}
+ case CalcOperator::Mod: {
+ if (m_children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ float left = m_children[0]->evaluate(maxValue);
+ float right = m_children[1]->evaluate(maxValue);
+ if (!right)
+ return std::numeric_limits<double>::quiet_NaN();
+ if ((left < 0) == (right < 0))
+ return std::fmod(left, right);
+ return std::remainder(left, right);
}
+ case CalcOperator::Rem: {
+ if (m_children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ float left = m_children[0]->evaluate(maxValue);
+ float right = m_children[1]->evaluate(maxValue);
+ if (!right)
+ return std::numeric_limits<double>::quiet_NaN();
+ return std::fmod(left, right);
+ }
+ case CalcOperator::Round:
+ return std::numeric_limits<double>::quiet_NaN();
+ case CalcOperator::Up: {
+ if (m_children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ auto ret = getNearestMultiples(m_children[0]->evaluate(maxValue), m_children[1]->evaluate(maxValue));
+ return ret.second;
+ }
+ case CalcOperator::Down: {
+ if (m_children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ auto ret = getNearestMultiples(m_children[0]->evaluate(maxValue), m_children[1]->evaluate(maxValue));
+ return ret.first;
+ }
+ case CalcOperator::Nearest: {
+ if (m_children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ auto a = m_children[0]->evaluate(maxValue);
+ auto b = m_children[1]->evaluate(maxValue);
+ auto ret = getNearestMultiples(a, b);
+ auto upperB = ret.second;
+ auto lowerB = ret.first;
+ return std::abs(upperB - a) <= std::abs(b) / 2 ? upperB : lowerB;
+ }
+ case CalcOperator::ToZero: {
+ if (m_children.size() != 2)
+ return std::numeric_limits<double>::quiet_NaN();
+ auto ret = getNearestMultiples(m_children[0]->evaluate(maxValue), m_children[1]->evaluate(maxValue));
+ auto upperB = ret.second;
+ auto lowerB = ret.first;
+ return std::abs(upperB) < std::abs(lowerB) ? upperB : lowerB;
+ }
+ }
ASSERT_NOT_REACHED();
return std::numeric_limits<float>::quiet_NaN();
}
Modified: trunk/Source/WebCore/platform/calc/CalcOperator.cpp (283072 => 283073)
--- trunk/Source/WebCore/platform/calc/CalcOperator.cpp 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/Source/WebCore/platform/calc/CalcOperator.cpp 2021-09-25 05:03:08 UTC (rev 283073)
@@ -51,6 +51,13 @@
case CalcOperator::Atan2: ts << "atan2"; break;
case CalcOperator::Abs: ts << "abs"; break;
case CalcOperator::Sign: ts << "sign"; break;
+ case CalcOperator::Mod: ts << "mod"; break;
+ case CalcOperator::Rem: ts << "rem"; break;
+ case CalcOperator::Round: ts << "round"; break;
+ case CalcOperator::Up: ts << "up"; break;
+ case CalcOperator::Down: ts << "down"; break;
+ case CalcOperator::ToZero: ts << "to-zero"; break;
+ case CalcOperator::Nearest: ts << "nearest"; break;
}
return ts;
}
Modified: trunk/Source/WebCore/platform/calc/CalcOperator.h (283072 => 283073)
--- trunk/Source/WebCore/platform/calc/CalcOperator.h 2021-09-25 03:39:35 UTC (rev 283072)
+++ trunk/Source/WebCore/platform/calc/CalcOperator.h 2021-09-25 05:03:08 UTC (rev 283073)
@@ -49,6 +49,13 @@
Atan2,
Abs,
Sign,
+ Mod,
+ Rem,
+ Round,
+ Nearest,
+ Up,
+ Down,
+ ToZero,
};
TextStream& operator<<(TextStream&, CalcOperator);