Title: [223099] branches/safari-604-branch

Diff

Modified: branches/safari-604-branch/LayoutTests/ChangeLog (223098 => 223099)


--- branches/safari-604-branch/LayoutTests/ChangeLog	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/LayoutTests/ChangeLog	2017-10-10 00:08:14 UTC (rev 223099)
@@ -1,5 +1,25 @@
 2017-10-02  Jason Marcell  <[email protected]>
 
+        Cherry-pick r222190. rdar://problem/34771470
+
+    2017-09-18  Tim Horton  <[email protected]>
+
+            Support min() and max() in calc()
+            https://bugs.webkit.org/show_bug.cgi?id=167000
+            <rdar://problem/30153481>
+
+            Reviewed by David Hyatt.
+            Patch originally by Myles Maxfield.
+
+            * css3/calc/minmax-errors-expected.txt:
+            * css3/calc/minmax-errors.html:
+            * css3/calc/simple-minmax-expected.txt:
+            * css3/calc/simple-minmax.html:
+            Revive previously-unused tests for an earlier never-implemented version
+            of this feature, and add a bunch more interesting test cases from reading the spec.
+
+2017-10-02  Jason Marcell  <[email protected]>
+
         Cherry-pick r221016. rdar://problem/34770830
 
     2017-08-22  Jer Noble  <[email protected]>

Modified: branches/safari-604-branch/LayoutTests/css3/calc/minmax-errors-expected.txt (223098 => 223099)


--- branches/safari-604-branch/LayoutTests/css3/calc/minmax-errors-expected.txt	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/LayoutTests/css3/calc/minmax-errors-expected.txt	2017-10-10 00:08:14 UTC (rev 223099)
@@ -1,6 +1,6 @@
 All boxes below should be 100px * 100px and green.
 
-MIN
+Bare min()
 unclosed min => PASS
 unclosed min with garbage => PASS
 garbage => PASS
@@ -12,7 +12,23 @@
 mix number and length => PASS
 mix percent and number => PASS
 mix number and percent => PASS
-MAX
+
+
+min() inside calc()
+unclosed min => PASS
+unclosed min with garbage => PASS
+garbage => PASS
+extra trailing comma => PASS
+leading comma => PASS
+trailing garbage => PASS
+bad _expression_ => PASS
+mix length and number => PASS
+mix number and length => PASS
+mix percent and number => PASS
+mix number and percent => PASS
+
+
+Bare max()
 unclosed max => PASS
 unclosed max with garbage => PASS
 mix length and number => PASS
@@ -19,3 +35,12 @@
 mix number and length => PASS
 mix percent and number => PASS
 mix number and percent => PASS
+
+
+max() inside calc
+unclosed max => PASS
+unclosed max with garbage => PASS
+mix length and number => PASS
+mix number and length => PASS
+mix percent and number => PASS
+mix number and percent => PASS

Modified: branches/safari-604-branch/LayoutTests/css3/calc/minmax-errors.html (223098 => 223099)


--- branches/safari-604-branch/LayoutTests/css3/calc/minmax-errors.html	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/LayoutTests/css3/calc/minmax-errors.html	2017-10-10 00:08:14 UTC (rev 223099)
@@ -12,27 +12,48 @@
 
 <div id="test">
 
-MIN
-<div style="width: 100px; width: -webkit-min(">unclosed min</div>
-<div style="width: 100px; width: -webkit-min( bob">unclosed min with garbage</div>
-<div style="width: 100px; width: -webkit-min( bob );">garbage</div>
-<div style="width: 100px; width: -webkit-min(20px,);">extra trailing comma</div>
-<div style="width: 100px; width: -webkit-min(,20px);">leading comma</div>
-<div style="width: 100px; width: -webkit-min(20px, bob);">trailing garbage</div>
-<div style="width: 100px; width: -webmit-min(20px, 10px + flim);">bad _expression_</div>
-<div style="width: 100px; width: -webkit-min(256px, 120);">mix length and number</div>
-<div style="width: 100px; width: -webkit-min(256, 120px);">mix number and length</div>
-<div style="width: 100px; width: -webkit-min(50%, 150);">mix percent and number</div>
-<div style="width: 100px; width: -webkit-min(150, 50%);">mix number and percent</div>
+Bare min()
+<div style="width: 100px; width: min(">unclosed min</div>
+<div style="width: 100px; width: min( bob">unclosed min with garbage</div>
+<div style="width: 100px; width: min( bob );">garbage</div>
+<div style="width: 100px; width: min(20px,);">extra trailing comma</div>
+<div style="width: 100px; width: min(,20px);">leading comma</div>
+<div style="width: 100px; width: min(20px, bob);">trailing garbage</div>
+<div style="width: 100px; width: min(20px, 10px + flim);">bad _expression_</div>
+<div style="width: 100px; width: min(256px, 120);">mix length and number</div>
+<div style="width: 100px; width: min(256, 120px);">mix number and length</div>
+<div style="width: 100px; width: min(50%, 150);">mix percent and number</div>
+<div style="width: 100px; width: min(150, 50%);">mix number and percent</div>
 
-MAX
-<div style="width: 100px; width: -webkit-max(">unclosed max</div>
-<div style="width: 100px; width: -webkit-max( bob">unclosed max with garbage</div>
-<div style="width: 100px; width: -webkit-max(256px, 120);">mix length and number</div>
-<div style="width: 100px; width: -webkit-max(256, 120px);">mix number and length</div>
-<div style="width: 100px; width: -webkit-max(50%, 150);">mix percent and number</div>
-<div style="width: 100px; width: -webkit-max(150, 50%);">mix number and percent</div>
+<br/><br/>min() inside calc()
+<div style="width: 100px; width: calc(min(">unclosed min</div>
+<div style="width: 100px; width: calc(min( bob">unclosed min with garbage</div>
+<div style="width: 100px; width: calc(min( bob ));">garbage</div>
+<div style="width: 100px; width: calc(min(20px,));">extra trailing comma</div>
+<div style="width: 100px; width: calc(min(,20px));">leading comma</div>
+<div style="width: 100px; width: calc(min(20px, bob));">trailing garbage</div>
+<div style="width: 100px; width: calc(min(20px, 10px + flim));">bad _expression_</div>
+<div style="width: 100px; width: calc(min(256px, 120));">mix length and number</div>
+<div style="width: 100px; width: calc(min(256, 120px));">mix number and length</div>
+<div style="width: 100px; width: calc(min(50%, 150));">mix percent and number</div>
+<div style="width: 100px; width: calc(min(150, 50%));">mix number and percent</div>
 
+<br/><br/>Bare max()
+<div style="width: 100px; width: max(">unclosed max</div>
+<div style="width: 100px; width: max( bob">unclosed max with garbage</div>
+<div style="width: 100px; width: max(256px, 120);">mix length and number</div>
+<div style="width: 100px; width: max(256, 120px);">mix number and length</div>
+<div style="width: 100px; width: max(50%, 150);">mix percent and number</div>
+<div style="width: 100px; width: max(150, 50%);">mix number and percent</div>
+
+<br/><br/>max() inside calc
+<div style="width: 100px; width: calc(max(">unclosed max</div>
+<div style="width: 100px; width: calc(max( bob">unclosed max with garbage</div>
+<div style="width: 100px; width: calc(max(256px, 120));">mix length and number</div>
+<div style="width: 100px; width: calc(max(256, 120px));">mix number and length</div>
+<div style="width: 100px; width: calc(max(50%, 150));">mix percent and number</div>
+<div style="width: 100px; width: calc(max(150, 50%));">mix number and percent</div>
+
 </div>
 
 <script>

Modified: branches/safari-604-branch/LayoutTests/css3/calc/simple-minmax-expected.txt (223098 => 223099)


--- branches/safari-604-branch/LayoutTests/css3/calc/simple-minmax-expected.txt	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/LayoutTests/css3/calc/simple-minmax-expected.txt	2017-10-10 00:08:14 UTC (rev 223099)
@@ -1,18 +1,54 @@
 All boxes below should be 100px * 100px and green.
 
-min(100px) => FAIL: expected width of 100, but was 256
-min( 100px ) => FAIL: expected width of 100, but was 256
-min((((100px)))) => FAIL: expected width of 100, but was 256
-min(150px,100px) => FAIL: expected width of 100, but was 256
-min(150px,100px,200px) => FAIL: expected width of 100, but was 256
-min( 150px , 100px ,200px) => FAIL: expected width of 100, but was 256
-min(90px + 50px ,100px) => FAIL: expected width of 100, but was 256
-min(100%,100px) - where 100% is 200px => FAIL: expected width of 100, but was 256
-min(100px,100%) - where 100% is 200px => FAIL: expected width of 100, but was 256
-max(100px) => FAIL: expected width of 100, but was 256
-max(50px,100px) => FAIL: expected width of 100, but was 256
-max(50px,100px,20px) => FAIL: expected width of 100, but was 256
-max(120px - 50px,100px) => FAIL: expected width of 100, but was 256
-max(100%,100px) - where 100% is 50px => FAIL: expected width of 100, but was 256
-max(100px,100%) - where 100% is 50px => FAIL: expected width of 100, but was 256
-min(200px,100px) => FAIL: expected height of 100, but was 50
+Bare min()
+min(100px) => PASS
+min( 100px ) => PASS
+min((((100px)))) => PASS
+min(150px,100px) => PASS
+min(150px,100px,200px) => PASS
+min( 150px , 100px ,200px) => PASS
+min(90px + 50px ,100px) => PASS
+min(100%,100px) - where 100% is 200px => PASS
+min(50%,150px) - where 50% is 100px => PASS
+min(100% - 50px,100px) - where 100% is 200px => PASS
+min(25% + 50px,150px) - where 25% is 50px => PASS
+min(100px,100%) - where 100% is 200px => PASS
+min(200px,100px) => PASS
+
+
+min() inside calc()
+calc(min(100px)) => PASS
+calc(min(150px, 200px) - 50px) => PASS
+calc(50 + min(150px, 50px)) => PASS
+calc(min(250px, 200px) / 2) => PASS
+calc(min( 100px )) => PASS
+calc(min((((100px))))) => PASS
+calc(min(150px,100px)) => PASS
+calc(min(150px,100px,200px)) => PASS
+calc(min( 150px , 100px ,200px)) => PASS
+calc(min(90px + 50px ,100px)) => PASS
+calc(min(100%,100px)) - where 100% is 200px => PASS
+calc(min(50%,150px)) - where 50% is 100px => PASS
+calc(min(100% - 50px,100px)) - where 100% is 200px => PASS
+calc(min(25% + 50px,150px)) - where 25% is 50px => PASS
+calc(min(100px,100%)) - where 100% is 200px => PASS
+calc(min(200px,100px)) => PASS
+
+
+Bare max()
+max(100px) => PASS
+calc(max(150px, 100px) - 50px) => PASS
+max(50px,100px) => PASS
+max(50px,100px,20px) => PASS
+max(120px - 50px,100px) => PASS
+max(100%,100px) - where 100% is 50px => PASS
+max(100px,100%) - where 100% is 50px => PASS
+
+
+max() inside calc()
+calc(max(100px)) => PASS
+calc(max(50px,100px)) => PASS
+calc(max(50px,100px,20px)) => PASS
+calc(max(120px - 50px,100px)) => PASS
+calc(max(100%,100px)) - where 100% is 50px => PASS
+calc(max(100px,100%)) - where 100% is 50px => PASS

Modified: branches/safari-604-branch/LayoutTests/css3/calc/simple-minmax.html (223098 => 223099)


--- branches/safari-604-branch/LayoutTests/css3/calc/simple-minmax.html	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/LayoutTests/css3/calc/simple-minmax.html	2017-10-10 00:08:14 UTC (rev 223099)
@@ -19,32 +19,83 @@
 
 <div id="test">
 
-<div class="width-test" style="width: -webkit-min(100px);">min(100px)</div>
-<div class="width-test" style="width: -webkit-min( 100px );">min( 100px )</div>
-<div class="width-test" style="width: -webkit-min((((100px))));">min((((100px))))</div>
-<div class="width-test" style="width: -webkit-min(150px,100px);">min(150px,100px)</div>
-<div class="width-test" style="width: -webkit-min(150px,100px,200px);">min(150px,100px,200px)</div>
-<div class="width-test" style="width: -webkit-min(  150px ,  100px  ,200px);">min(  150px  ,  100px  ,200px)</div>
-<div class="width-test" style="width: -webkit-min(90px + 50px ,100px);">min(90px + 50px ,100px)</div>
+Bare min()
+<div class="width-test" style="width: min(100px);">min(100px)</div>
+<div class="width-test" style="width: min( 100px );">min( 100px )</div>
+<div class="width-test" style="width: min((((100px))));">min((((100px))))</div>
+<div class="width-test" style="width: min(150px,100px);">min(150px,100px)</div>
+<div class="width-test" style="width: min(150px,100px,200px);">min(150px,100px,200px)</div>
+<div class="width-test" style="width: min(  150px ,  100px  ,200px);">min(  150px  ,  100px  ,200px)</div>
+<div class="width-test" style="width: min(90px + 50px ,100px);">min(90px + 50px ,100px)</div>
 <div style="width: 200px; background-color: white;" class="wrapper">
-  <div class="width-test" style="width: -webkit-min(100%,100px);">min(100%,100px) - where 100% is 200px</div>
+  <div class="width-test" style="width: min(100%,100px);">min(100%,100px) - where 100% is 200px</div>
 </div>
 <div style="width: 200px; background-color: white;" class="wrapper">
-  <div class="width-test" style="width: -webkit-min(100px,100%);">min(100px,100%) - where 100% is 200px</div>
+  <div class="width-test" style="width: min(50%,150px);">min(50%,150px) - where 50% is 100px</div>
 </div>
+<div style="width: 200px; background-color: white;" class="wrapper">
+  <div class="width-test" style="width: min(100% - 50px,100px);">min(100% - 50px,100px) - where 100% is 200px</div>
+</div>
+<div style="width: 200px; background-color: white;" class="wrapper">
+  <div class="width-test" style="width: min(25% + 50px,150px);">min(25% + 50px,150px) - where 25% is 50px</div>
+</div>
+<div style="width: 200px; background-color: white;" class="wrapper">
+  <div class="width-test" style="width: min(100px,100%);">min(100px,100%) - where 100% is 200px</div>
+</div>
+<div class="height-test" style="height: min(200px, 100px);">min(200px,100px)</div>
 
-<div class="width-test" style="width: -webkit-max(100px);">max(100px)</div>
-<div class="width-test" style="width: -webkit-max(50px,100px);">max(50px,100px)</div>
-<div class="width-test" style="width: -webkit-max(50px,100px,20px);">max(50px,100px,20px)</div>
-<div class="width-test" style="width: -webkit-max(120px - 50px,100px);">max(120px - 50px,100px)</div>
+<br/><br/>min() inside calc()
+<div class="width-test" style="width: calc(min(100px));">calc(min(100px))</div>
+<div class="width-test" style="width: calc(min(150px, 200px) - 50px);">calc(min(150px, 200px) - 50px)</div>
+<div class="width-test" style="width: calc(50px + min(150px, 50px));">calc(50 + min(150px, 50px))</div>
+<div class="width-test" style="width: calc(min(250px, 200px) / 2);">calc(min(250px, 200px) / 2)</div>
+<div class="width-test" style="width: calc(min( 100px ));">calc(min( 100px ))</div>
+<div class="width-test" style="width: calc(min((((100px)))));">calc(min((((100px)))))</div>
+<div class="width-test" style="width: calc(min(150px,100px));">calc(min(150px,100px))</div>
+<div class="width-test" style="width: calc(min(150px,100px,200px));">calc(min(150px,100px,200px))</div>
+<div class="width-test" style="width: calc(min(  150px ,  100px  ,200px));">calc(min(  150px  ,  100px  ,200px))</div>
+<div class="width-test" style="width: calc(min(90px + 50px ,100px));">calc(min(90px + 50px ,100px))</div>
+<div style="width: 200px; background-color: white;" class="wrapper">
+  <div class="width-test" style="width: calc(min(100%,100px));">calc(min(100%,100px)) - where 100% is 200px</div>
+</div>
+<div style="width: 200px; background-color: white;" class="wrapper">
+  <div class="width-test" style="width: calc(min(50%,150px));">calc(min(50%,150px)) - where 50% is 100px</div>
+</div>
+<div style="width: 200px; background-color: white;" class="wrapper">
+  <div class="width-test" style="width: calc(min(100% - 50px,100px));">calc(min(100% - 50px,100px)) - where 100% is 200px</div>
+</div>
+<div style="width: 200px; background-color: white;" class="wrapper">
+  <div class="width-test" style="width: calc(min(25% + 50px,150px));">calc(min(25% + 50px,150px)) - where 25% is 50px</div>
+</div>
+<div style="width: 200px; background-color: white;" class="wrapper">
+  <div class="width-test" style="width: calc(min(100px,100%));">calc(min(100px,100%)) - where 100% is 200px</div>
+</div>
+<div class="height-test" style="height: calc(min(200px, 100px));">calc(min(200px,100px))</div>
+
+<br/><br/>Bare max()
+<div class="width-test" style="width: max(100px);">max(100px)</div>
+<div class="width-test" style="width: calc(max(150px, 100px) - 50px);">calc(max(150px, 100px) - 50px)</div>
+<div class="width-test" style="width: max(50px,100px);">max(50px,100px)</div>
+<div class="width-test" style="width: max(50px,100px,20px);">max(50px,100px,20px)</div>
+<div class="width-test" style="width: max(120px - 50px,100px);">max(120px - 50px,100px)</div>
 <div style="width: 50px; background-color: white;" class="wrapper">
-  <div class="width-test" style="width: -webkit-max(100%,100px);">max(100%,100px) - where 100% is 50px</div>
+  <div class="width-test" style="width: max(100%,100px);">max(100%,100px) - where 100% is 50px</div>
 </div>
 <div style="width: 50px; background-color: white;" class="wrapper">
-  <div class="width-test" style="width: -webkit-max(100px,100%);">max(100px,100%) - where 100% is 50px</div>
+  <div class="width-test" style="width: max(100px,100%);">max(100px,100%) - where 100% is 50px</div>
 </div>
 
-<div class="height-test" style="height: -webkit-min(200px, 100px);">min(200px,100px)</div>
+<br/><br/>max() inside calc()
+<div class="width-test" style="width: calc(max(100px));">calc(max(100px))</div>
+<div class="width-test" style="width: calc(max(50px,100px));">calc(max(50px,100px))</div>
+<div class="width-test" style="width: calc(max(50px,100px,20px));">calc(max(50px,100px,20px))</div>
+<div class="width-test" style="width: calc(max(120px - 50px,100px));">calc(max(120px - 50px,100px))</div>
+<div style="width: 50px; background-color: white;" class="wrapper">
+  <div class="width-test" style="width: calc(max(100%,100px));">calc(max(100%,100px)) - where 100% is 50px</div>
+</div>
+<div style="width: 50px; background-color: white;" class="wrapper">
+  <div class="width-test" style="width: calc(max(100px,100%));">calc(max(100px,100%)) - where 100% is 50px</div>
+</div>
 
 </div>
 

Modified: branches/safari-604-branch/Source/WebCore/ChangeLog (223098 => 223099)


--- branches/safari-604-branch/Source/WebCore/ChangeLog	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/Source/WebCore/ChangeLog	2017-10-10 00:08:14 UTC (rev 223099)
@@ -1,5 +1,137 @@
 2017-10-02  Jason Marcell  <[email protected]>
 
+        Cherry-pick r222190. rdar://problem/34771470
+
+    2017-09-18  Tim Horton  <[email protected]>
+
+            Support min() and max() in calc()
+            https://bugs.webkit.org/show_bug.cgi?id=167000
+            <rdar://problem/30153481>
+
+            Reviewed by David Hyatt.
+            Patch originally by Myles Maxfield.
+
+            Add two new toplevel functions to CSS, min() and max(), which take an
+            arbirary number of arguments and resolve to the minimum and maximum of
+            the resolved value of the arguments, respectively. It is also possible
+            to use min() and max() inside calc(), and to use calc()-like math
+            inside min() and max().
+
+            * css/CSSCalculationValue.cpp:
+            (WebCore::determineCategory):
+            min and max operators don't use determineCategory; we have a specific
+            implementation for them in createMinOrMax.
+
+            (WebCore::resolvedTypeForMinOrMax):
+            The spec says that min() and max() should be marked as invalid if they
+            have values of more than one type, but that percentages should resolve
+            against the destination type before making this determination. So,
+            if the destination type is length, percent turns into percent-length,
+            and similarly for number.
+
+            (WebCore::isIntegerResult):
+            Add an n-way implementation of isIntegerResult.
+
+            (WebCore::isSamePair):
+            (WebCore::CSSCalcOperation::createMinOrMax): Create a min() or max()
+            operation, as long as the types of arguments are all the same. Allow
+            lengths to upgrade the whole operation to percent-length, and numbers
+            to percent-number, which will cause us to use CalculationValue and friends
+            in order to do proper resolution of all of the parameters instead of
+            just comparing their numeric values.
+
+            (WebCore::CSSCalcOperation::createCalcExpression):
+            (WebCore::CSSCalcOperation::doubleValue):
+            (WebCore::CSSCalcOperation::computeLengthPx):
+            (WebCore::CSSCalcOperation::customCSSText):
+            (WebCore::CSSCalcOperation::primitiveType):
+            (WebCore::CSSCalcOperation::CSSCalcOperation):
+            (WebCore::CSSCalcOperation::evaluate):
+            (WebCore::CSSCalcOperation::evaluateOperator):
+            Adapt to child counts greater than two.
+
+            (WebCore::CSSCalcOperation::buildCssText):
+            Add support for min() and max().
+
+            (WebCore::CSSCalcExpressionNodeParser::parseCalc):
+            parseCalc now accepts a CSSValueID parameter indicating which calc function
+            it should parse (calc, webkit-calc, min, or max), and delegates to either
+            parseValueExpression or parseMinMaxExpression.
+
+            (WebCore::CSSCalcExpressionNodeParser::operatorValue):
+            (WebCore::CSSCalcExpressionNodeParser::parseValue):
+            If min() or max() are found while parsing a value (i.e. nested inside
+            either calc or themselves), use parseMinMaxExpression on that subtree.
+
+            (WebCore::CSSCalcExpressionNodeParser::parseValueTerm):
+            (WebCore::CSSCalcExpressionNodeParser::parseValueMultiplicativeExpression):
+            (WebCore::CSSCalcExpressionNodeParser::parseAdditiveValueExpression):
+            Adjust to the CSSCalcBinaryOperation->CSSCalcOperation rename.
+
+            (WebCore::CSSCalcExpressionNodeParser::parseMinMaxExpression):
+            Added. Parse an arbitrary number of comma-and-whitespace-separated children.
+
+            (WebCore::createBlendHalf):
+            Adjust to the CSSCalcBinaryOperation->CSSCalcOperation rename.
+
+            (WebCore::createCSS):
+            Build the CSSCalcOperation for the platform-independent min and max operations.
+
+            (WebCore::CSSCalcValue::create):
+            Pass the function being parsed and the destination calc category for the
+            property being parsed for into create, and then into the parser so that
+            it can know which function it is parsing for, and what kind of result it
+            needs (as previously mentioned above in resolvedTypeForMinOrMax).
+
+            * css/CSSCalculationValue.h:
+            * css/CSSValueKeywords.in:
+            Add min and max functions as CSS keywords.
+
+            * css/StyleBuilderConverter.h:
+            (WebCore::StyleBuilderConverter::convertLength):
+            (WebCore::StyleBuilderConverter::convertTo100PercentMinusLength):
+            * platform/Length.cpp:
+            (WebCore::convertTo100PercentMinusLength):
+            Adapt to the CalcExpressionOperation constructor taking a vector of
+            arguments instead of two.
+
+            * css/parser/CSSPropertyParserHelpers.cpp:
+            (WebCore::CSSPropertyParserHelpers::CalcParser::CalcParser):
+            Store and pass the specific function being parsed down into CSSCalcValue.
+
+            (WebCore::CSSPropertyParserHelpers::consumeInteger):
+            (WebCore::CSSPropertyParserHelpers::consumePositiveIntegerRaw):
+            (WebCore::CSSPropertyParserHelpers::consumeNumberRaw):
+            (WebCore::CSSPropertyParserHelpers::consumeNumber):
+            (WebCore::CSSPropertyParserHelpers::consumeFontWeightNumber):
+            (WebCore::CSSPropertyParserHelpers::consumeLength):
+            (WebCore::CSSPropertyParserHelpers::consumePercent):
+            (WebCore::CSSPropertyParserHelpers::consumeLengthOrPercent):
+            (WebCore::CSSPropertyParserHelpers::consumeAngle):
+            (WebCore::CSSPropertyParserHelpers::consumeTime):
+            Pass the destination type into each calc parser.
+
+            * platform/CalculationValue.cpp:
+            (WebCore::CalcExpressionOperation::evaluate const):
+            (WebCore::CalcExpressionOperation::operator== const):
+            (WebCore::CalcExpressionOperation::dump const):
+            (WebCore::operator<<):
+            (WebCore::CalcExpressionBinaryOperation::evaluate const): Deleted.
+            (WebCore::CalcExpressionBinaryOperation::operator== const): Deleted.
+            (WebCore::CalcExpressionBinaryOperation::dump const): Deleted.
+            * platform/CalculationValue.h:
+            (WebCore::CalcExpressionOperation::CalcExpressionOperation):
+            (WebCore::operator==):
+            (WebCore::toCalcExpressionOperation):
+            (WebCore::CalcExpressionBinaryOperation::CalcExpressionBinaryOperation): Deleted.
+            (WebCore::toCalcExpressionBinaryOperation): Deleted.
+            Adjust to the CSSCalcBinaryOperation->CSSCalcOperation rename.
+            Adjust to having n>2 children.
+            Support min() and max() operators in various places.
+
+
+2017-10-02  Jason Marcell  <[email protected]>
+
         Cherry-pick r221100. rdar://problem/34771028
 
     2017-08-23  Jer Noble  <[email protected]>

Modified: branches/safari-604-branch/Source/WebCore/css/CSSCalculationValue.cpp (223098 => 223099)


--- branches/safari-604-branch/Source/WebCore/css/CSSCalculationValue.cpp	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/Source/WebCore/css/CSSCalculationValue.cpp	2017-10-10 00:08:14 UTC (rev 223099)
@@ -325,6 +325,10 @@
         if (rightCategory != CalcNumber || rightSide.isZero())
             return CalcOther;
         return leftCategory;
+    case CalcMin:
+    case CalcMax:
+        ASSERT_NOT_REACHED();
+        return CalcOther;
     }
 
     ASSERT_NOT_REACHED();
@@ -331,6 +335,30 @@
     return CalcOther;
 }
 
+static CalculationCategory resolvedTypeForMinOrMax(CalculationCategory category, CalculationCategory destinationCategory)
+{
+    switch (category) {
+    case CalcNumber:
+    case CalcLength:
+    case CalcPercentNumber:
+    case CalcPercentLength:
+    case CalcAngle:
+    case CalcTime:
+    case CalcFrequency:
+    case CalcOther:
+        return category;
+
+    case CalcPercent:
+        if (destinationCategory == CalcLength)
+            return CalcPercentLength;
+        if (destinationCategory == CalcNumber)
+            return CalcPercentNumber;
+        return category;
+    }
+
+    return CalcOther;
+}
+
 static inline bool isIntegerResult(CalcOperator op, const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide)
 {
     // Performs W3C spec's type checking for calc integers.
@@ -338,10 +366,30 @@
     return op != CalcDivide && leftSide.isInteger() && rightSide.isInteger();
 }
 
-class CSSCalcBinaryOperation final : public CSSCalcExpressionNode {
+static inline bool isIntegerResult(CalcOperator op, const Vector<Ref<CSSCalcExpressionNode>>& nodes)
+{
+    // Performs W3C spec's type checking for calc integers.
+    // http://www.w3.org/TR/css3-values/#calc-type-checking
+    if (op == CalcDivide)
+        return false;
+
+    for (auto& node : nodes) {
+        if (!node->isInteger())
+            return false;
+    }
+
+    return true;
+}
+
+static bool isSamePair(CalculationCategory a, CalculationCategory b, CalculationCategory x, CalculationCategory y)
+{
+    return (a == x && b == y) || (a == y && b == x);
+}
+
+class CSSCalcOperation final : public CSSCalcExpressionNode {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    static RefPtr<CSSCalcBinaryOperation> create(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
+    static RefPtr<CSSCalcOperation> create(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
     {
         if (!leftSide || !rightSide)
             return nullptr;
@@ -352,9 +400,41 @@
         auto newCategory = determineCategory(*leftSide, *rightSide, op);
         if (newCategory == CalcOther)
             return nullptr;
-        return adoptRef(new CSSCalcBinaryOperation(newCategory, op, leftSide.releaseNonNull(), rightSide.releaseNonNull()));
+
+        return adoptRef(new CSSCalcOperation(newCategory, op, leftSide.releaseNonNull(), rightSide.releaseNonNull()));
     }
 
+    static RefPtr<CSSCalcOperation> createMinOrMax(CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& values, CalculationCategory destinationCategory)
+    {
+        ASSERT(op == CalcMin || op == CalcMax);
+
+        std::optional<CalculationCategory> category = std::nullopt;
+        for (auto& value : values) {
+            auto valueCategory = resolvedTypeForMinOrMax(value->category(), destinationCategory);
+
+            ASSERT(valueCategory < CalcOther);
+            if (!category) {
+                if (valueCategory == CalcOther)
+                    return nullptr;
+                category = valueCategory;
+            }
+
+            if (category != valueCategory) {
+                if (isSamePair(category.value(), valueCategory, CalcLength, CalcPercentLength)) {
+                    category = CalcPercentLength;
+                    continue;
+                }
+                if (isSamePair(category.value(), valueCategory, CalcNumber, CalcPercentNumber)) {
+                    category = CalcPercentNumber;
+                    continue;
+                }
+                return nullptr;
+            }
+        }
+
+        return adoptRef(new CSSCalcOperation(category.value(), op, WTFMove(values)));
+    }
+
     static RefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
     {
         if (!leftSide || !rightSide)
@@ -370,7 +450,7 @@
         // Simplify numbers.
         if (leftCategory == CalcNumber && rightCategory == CalcNumber) {
             CSSPrimitiveValue::UnitType evaluationType = CSSPrimitiveValue::CSS_NUMBER;
-            return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftSide->doubleValue(), rightSide->doubleValue()), evaluationType, isInteger);
+            return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftSide->doubleValue(), rightSide->doubleValue() }), evaluationType, isInteger);
         }
 
         // Simplify addition and subtraction between same types.
@@ -380,7 +460,7 @@
                 if (hasDoubleValue(leftType)) {
                     CSSPrimitiveValue::UnitType rightType = rightSide->primitiveType();
                     if (leftType == rightType)
-                        return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftSide->doubleValue(), rightSide->doubleValue()), leftType, isInteger);
+                        return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftSide->doubleValue(), rightSide->doubleValue() }), leftType, isInteger);
                     CSSPrimitiveValue::UnitCategory leftUnitCategory = CSSPrimitiveValue::unitCategory(leftType);
                     if (leftUnitCategory != CSSPrimitiveValue::UOther && leftUnitCategory == CSSPrimitiveValue::unitCategory(rightType)) {
                         CSSPrimitiveValue::UnitType canonicalType = CSSPrimitiveValue::canonicalUnitTypeForCategory(leftUnitCategory);
@@ -387,7 +467,7 @@
                         if (canonicalType != CSSPrimitiveValue::CSS_UNKNOWN) {
                             double leftValue = leftSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(leftType);
                             double rightValue = rightSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(rightType);
-                            return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftValue, rightValue), canonicalType, isInteger);
+                            return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftValue, rightValue }), canonicalType, isInteger);
                         }
                     }
                 }
@@ -410,7 +490,7 @@
 
             auto otherType = otherSide.primitiveType();
             if (hasDoubleValue(otherType))
-                return CSSCalcPrimitiveValue::create(evaluateOperator(op, otherSide.doubleValue(), number), otherType, isInteger);
+                return CSSCalcPrimitiveValue::create(evaluateOperator(op, { otherSide.doubleValue(), number }), otherType, isInteger);
         }
 
         return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
@@ -424,36 +504,63 @@
 
     std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final
     {
-        auto left = m_leftSide->createCalcExpression(conversionData);
-        if (!left)
-            return nullptr;
-        auto right = m_rightSide->createCalcExpression(conversionData);
-        if (!right)
-            return nullptr;
-        return std::make_unique<CalcExpressionBinaryOperation>(WTFMove(left), WTFMove(right), m_operator);
+        Vector<std::unique_ptr<CalcExpressionNode>> nodes;
+        nodes.reserveInitialCapacity(m_children.size());
+
+        for (auto& child : m_children) {
+            auto node = child->createCalcExpression(conversionData);
+            if (!node)
+                return nullptr;
+            nodes.uncheckedAppend(WTFMove(node));
+        }
+        return std::make_unique<CalcExpressionOperation>(WTFMove(nodes), m_operator);
     }
 
     double doubleValue() const final
     {
-        return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue());
+        Vector<double> doubleValues;
+        for (auto& child : m_children)
+            doubleValues.append(child->doubleValue());
+        return evaluate(doubleValues);
     }
 
     double computeLengthPx(const CSSToLengthConversionData& conversionData) const final
     {
-        const double leftValue = m_leftSide->computeLengthPx(conversionData);
-        const double rightValue = m_rightSide->computeLengthPx(conversionData);
-        return evaluate(leftValue, rightValue);
+        Vector<double> doubleValues;
+        for (auto& child : m_children)
+            doubleValues.append(child->computeLengthPx(conversionData));
+        return evaluate(doubleValues);
     }
 
-    static String buildCssText(const String& leftExpression, const String& rightExpression, CalcOperator op)
+    static String buildCssText(Vector<String> childExpressions, CalcOperator op)
     {
         StringBuilder result;
         result.append('(');
-        result.append(leftExpression);
-        result.append(' ');
-        result.append(static_cast<char>(op));
-        result.append(' ');
-        result.append(rightExpression);
+        switch (op) {
+        case CalcAdd:
+        case CalcSubtract:
+        case CalcMultiply:
+        case CalcDivide:
+            ASSERT(childExpressions.size() == 2);
+            result.append(childExpressions[0]);
+            result.append(' ');
+            result.append(static_cast<char>(op));
+            result.append(' ');
+            result.append(childExpressions[1]);
+            break;
+        case CalcMin:
+        case CalcMax:
+            ASSERT(!childExpressions.isEmpty());
+            const char* functionName = op == CalcMin ? "min(" : "max(";
+            result.append(functionName);
+            result.append(childExpressions[0]);
+            for (size_t i = 1; i < childExpressions.size(); ++i) {
+                result.append(',');
+                result.append(' ');
+                result.append(childExpressions[i]);
+            }
+            result.append(')');
+        }
         result.append(')');
 
         return result.toString();
@@ -461,7 +568,10 @@
 
     String customCSSText() const final
     {
-        return buildCssText(m_leftSide->customCSSText(), m_rightSide->customCSSText(), m_operator);
+        Vector<String> cssTexts;
+        for (auto& child : m_children)
+            cssTexts.append(child->customCSSText());
+        return buildCssText(cssTexts, m_operator);
     }
 
     bool equals(const CSSCalcExpressionNode& exp) const final
@@ -469,30 +579,45 @@
         if (type() != exp.type())
             return false;
 
-        const CSSCalcBinaryOperation& other = static_cast<const CSSCalcBinaryOperation&>(exp);
-        return compareCSSValuePtr(m_leftSide, other.m_leftSide)
-            && compareCSSValuePtr(m_rightSide, other.m_rightSide)
-            && m_operator == other.m_operator;
+        const CSSCalcOperation& other = static_cast<const CSSCalcOperation&>(exp);
+
+        if (m_children.size() != other.m_children.size() || m_operator != other.m_operator)
+            return false;
+
+        for (size_t i = 0; i < m_children.size(); ++i) {
+            if (!compareCSSValue(m_children[i], other.m_children[i]))
+                return false;
+        }
+        return true;
     }
 
-    Type type() const final { return CssCalcBinaryOperation; }
+    Type type() const final { return CssCalcOperation; }
 
     CSSPrimitiveValue::UnitType primitiveType() const final
     {
         switch (category()) {
         case CalcNumber:
-            ASSERT(m_leftSide->category() == CalcNumber && m_rightSide->category() == CalcNumber);
+#if !ASSERT_DISABLED
+            for (auto& child : m_children)
+                ASSERT(child->category() == CalcNumber);
+#endif
             return CSSPrimitiveValue::CSS_NUMBER;
         case CalcLength:
         case CalcPercent: {
-            if (m_leftSide->category() == CalcNumber)
-                return m_rightSide->primitiveType();
-            if (m_rightSide->category() == CalcNumber)
-                return m_leftSide->primitiveType();
-            CSSPrimitiveValue::UnitType leftType = m_leftSide->primitiveType();
-            if (leftType == m_rightSide->primitiveType())
-                return leftType;
-            return CSSPrimitiveValue::CSS_UNKNOWN;
+            if (m_children.isEmpty())
+                return CSSPrimitiveValue::CSS_UNKNOWN;
+            if (m_children.size() == 2) {
+                if (m_children[0]->category() == CalcNumber)
+                    return m_children[1]->primitiveType();
+                if (m_children[1]->category() == CalcNumber)
+                    return m_children[0]->primitiveType();
+            }
+            CSSPrimitiveValue::UnitType firstType = m_children[0]->primitiveType();
+            for (auto& child : m_children) {
+                if (firstType != child->primitiveType())
+                    return CSSPrimitiveValue::CSS_UNKNOWN;
+            }
+            return firstType;
         }
         case CalcAngle:
             return CSSPrimitiveValue::CSS_DEG;
@@ -509,14 +634,21 @@
         return CSSPrimitiveValue::CSS_UNKNOWN;
     }
 
-    CSSCalcBinaryOperation(CalculationCategory category, CalcOperator op, Ref<CSSCalcExpressionNode>&& leftSide, Ref<CSSCalcExpressionNode>&& rightSide)
+    CSSCalcOperation(CalculationCategory category, CalcOperator op, Ref<CSSCalcExpressionNode>&& leftSide, Ref<CSSCalcExpressionNode>&& rightSide)
         : CSSCalcExpressionNode(category, isIntegerResult(op, leftSide.get(), rightSide.get()))
-        , m_leftSide(WTFMove(leftSide))
-        , m_rightSide(WTFMove(rightSide))
         , m_operator(op)
     {
+        m_children.append(WTFMove(leftSide));
+        m_children.append(WTFMove(rightSide));
     }
 
+    CSSCalcOperation(CalculationCategory category, CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& children)
+        : CSSCalcExpressionNode(category, isIntegerResult(op, children))
+        , m_children(WTFMove(children))
+        , m_operator(op)
+    {
+    }
+
     static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide)
     {
         if (leftSide.category() == CalcNumber)
@@ -526,31 +658,50 @@
         return nullptr;
     }
 
-    double evaluate(double leftSide, double rightSide) const
+    double evaluate(const Vector<double>& children) const
     {
-        return evaluateOperator(m_operator, leftSide, rightSide);
+        return evaluateOperator(m_operator, children);
     }
 
-    static double evaluateOperator(CalcOperator op, double leftValue, double rightValue)
+    static double evaluateOperator(CalcOperator op, const Vector<double>& children)
     {
         switch (op) {
         case CalcAdd:
-            return leftValue + rightValue;
+            ASSERT(children.size() == 2);
+            return children[0] + children[1];
         case CalcSubtract:
-            return leftValue - rightValue;
+            ASSERT(children.size() == 2);
+            return children[0] - children[1];
         case CalcMultiply:
-            return leftValue * rightValue;
+            ASSERT(children.size() == 2);
+            return children[0] * children[1];
         case CalcDivide:
-            if (rightValue)
-                return leftValue / rightValue;
-            return std::numeric_limits<double>::quiet_NaN();
+            ASSERT(children.size() == 1 || children.size() == 2);
+            if (children.size() == 1)
+                return std::numeric_limits<double>::quiet_NaN();
+            return children[0] / children[1];
+        case CalcMin: {
+            if (children.isEmpty())
+                return std::numeric_limits<double>::quiet_NaN();
+            double minimum = children[0];
+            for (auto child : children)
+                minimum = std::min(minimum, child);
+            return minimum;
         }
+        case CalcMax: {
+            if (children.isEmpty())
+                return std::numeric_limits<double>::quiet_NaN();
+            double maximum = children[0];
+            for (auto child : children)
+                maximum = std::max(maximum, child);
+            return maximum;
+        }
+        }
         ASSERT_NOT_REACHED();
         return 0;
     }
 
-    const RefPtr<CSSCalcExpressionNode> m_leftSide;
-    const RefPtr<CSSCalcExpressionNode> m_rightSide;
+    Vector<Ref<CSSCalcExpressionNode>> m_children;
     const CalcOperator m_operator;
 };
 
@@ -566,11 +717,19 @@
 
 class CSSCalcExpressionNodeParser {
 public:
-    RefPtr<CSSCalcExpressionNode> parseCalc(CSSParserTokenRange tokens)
+    explicit CSSCalcExpressionNodeParser(CalculationCategory destinationCategory)
+        : m_destinationCategory(destinationCategory)
+    { }
+
+    RefPtr<CSSCalcExpressionNode> parseCalc(CSSParserTokenRange tokens, CSSValueID function)
     {
         Value result;
         tokens.consumeWhitespace();
-        bool ok = parseValueExpression(tokens, 0, &result);
+        bool ok = false;
+        if (function == CSSValueCalc || function == CSSValueWebkitCalc)
+            ok = parseValueExpression(tokens, 0, &result);
+        else if (function == CSSValueMin || function == CSSValueMax)
+            ok = parseMinMaxExpression(tokens, function, 0, &result);
         if (!ok || !tokens.atEnd())
             return nullptr;
         return result.value;
@@ -608,13 +767,22 @@
     {
         if (checkDepthAndIndex(&depth, tokens) != OK)
             return false;
+
+        auto functionId = tokens.peek().functionId();
         
-        if (tokens.peek().type() == LeftParenthesisToken || tokens.peek().functionId() == CSSValueCalc) {
+        if (tokens.peek().type() == LeftParenthesisToken || functionId == CSSValueCalc) {
             CSSParserTokenRange innerRange = tokens.consumeBlock();
             tokens.consumeWhitespace();
             innerRange.consumeWhitespace();
             return parseValueExpression(innerRange, depth, result);
         }
+
+        if (functionId == CSSValueMax || functionId == CSSValueMin) {
+            CSSParserTokenRange innerRange = tokens.consumeBlock();
+            tokens.consumeWhitespace();
+            innerRange.consumeWhitespace();
+            return parseMinMaxExpression(innerRange, functionId, depth, result);
+        }
         
         return parseValue(tokens, result);
     }
@@ -637,7 +805,7 @@
             if (!parseValueTerm(tokens, depth, &rhs))
                 return false;
             
-            result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
+            result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
 
             if (!result->value)
                 return false;
@@ -669,7 +837,7 @@
             if (!parseValueMultiplicativeExpression(tokens, depth, &rhs))
                 return false;
             
-            result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
+            result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
             if (!result->value)
                 return false;
         }
@@ -676,16 +844,48 @@
         
         return true;
     }
-    
+
+    bool parseMinMaxExpression(CSSParserTokenRange& tokens, CSSValueID minMaxFunction, int depth, Value* result)
+    {
+        if (checkDepthAndIndex(&depth, tokens) != OK)
+            return false;
+
+        CalcOperator op = (minMaxFunction == CSSValueMin) ? CalcMin : CalcMax;
+
+        Value value;
+        if (!parseValueExpression(tokens, depth, &value))
+            return false;
+
+        Vector<Ref<CSSCalcExpressionNode>> nodes;
+        nodes.append(value.value.releaseNonNull());
+
+        while (!tokens.atEnd()) {
+            tokens.consumeWhitespace();
+            if (tokens.consume().type() != CommaToken)
+                return false;
+            tokens.consumeWhitespace();
+
+            if (!parseValueExpression(tokens, depth, &value))
+                return false;
+
+            nodes.append(value.value.releaseNonNull());
+        }
+
+        result->value = CSSCalcOperation::createMinOrMax(op, WTFMove(nodes), m_destinationCategory);
+        return result->value;
+    }
+
     bool parseValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
     {
         return parseAdditiveValueExpression(tokens, depth, result);
     }
+
+    CalculationCategory m_destinationCategory;
 };
 
-static inline RefPtr<CSSCalcBinaryOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress)
+static inline RefPtr<CSSCalcOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress)
 {
-    return CSSCalcBinaryOperation::create(CalcMultiply, createCSS(length, style),
+    return CSSCalcOperation::create(CalcMultiply, createCSS(length, style),
         CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), !progress || progress == 1));
 }
 
@@ -698,15 +898,32 @@
     }
     case CalcExpressionNodeLength:
         return createCSS(toCalcExpressionLength(node).length(), style);
-    case CalcExpressionNodeBinaryOperation: {
-        auto& binaryNode = toCalcExpressionBinaryOperation(node);
-        return CSSCalcBinaryOperation::create(binaryNode.getOperator(), createCSS(binaryNode.leftSide(), style), createCSS(binaryNode.rightSide(), style));
+    case CalcExpressionNodeOperation: {
+        auto& operationNode = toCalcExpressionOperation(node);
+        auto& operationChildren = operationNode.children();
+        CalcOperator op = operationNode.getOperator();
+        if (op == CalcMin || op == CalcMax) {
+            Vector<Ref<CSSCalcExpressionNode>> values;
+            values.reserveInitialCapacity(operationChildren.size());
+            for (auto& child : operationChildren) {
+                auto cssNode = createCSS(*child, style);
+                if (!cssNode)
+                    return nullptr;
+                values.uncheckedAppend(*cssNode);
+            }
+            return CSSCalcOperation::createMinOrMax(operationNode.getOperator(), WTFMove(values), CalcOther);
+        }
+
+        if (operationChildren.size() == 2)
+            return CSSCalcOperation::create(operationNode.getOperator(), createCSS(*operationChildren[0], style), createCSS(*operationChildren[1], style));
+
+        return nullptr;
     }
     case CalcExpressionNodeBlendLength: {
         // FIXME: (http://webkit.org/b/122036) Create a CSSCalcExpressionNode equivalent of CalcExpressionBlendLength.
         auto& blend = toCalcExpressionBlendLength(node);
         float progress = blend.progress();
-        return CSSCalcBinaryOperation::create(CalcAdd, createBlendHalf(blend.from(), style, 1 - progress), createBlendHalf(blend.to(), style, progress));
+        return CSSCalcOperation::create(CalcAdd, createBlendHalf(blend.from(), style, 1 - progress), createBlendHalf(blend.to(), style, progress));
     }
     case CalcExpressionNodeUndefined:
         ASSERT_NOT_REACHED();
@@ -736,10 +953,10 @@
     return nullptr;
 }
 
-RefPtr<CSSCalcValue> CSSCalcValue::create(const CSSParserTokenRange& tokens, ValueRange range)
+RefPtr<CSSCalcValue> CSSCalcValue::create(CSSValueID function, const CSSParserTokenRange& tokens, CalculationCategory destinationCategory, ValueRange range)
 {
-    CSSCalcExpressionNodeParser parser;
-    auto _expression_ = parser.parseCalc(tokens);
+    CSSCalcExpressionNodeParser parser(destinationCategory);
+    auto _expression_ = parser.parseCalc(tokens, function);
     if (!_expression_)
         return nullptr;
     return adoptRef(new CSSCalcValue(_expression_.releaseNonNull(), range != ValueRangeAll));

Modified: branches/safari-604-branch/Source/WebCore/css/CSSCalculationValue.h (223098 => 223099)


--- branches/safari-604-branch/Source/WebCore/css/CSSCalculationValue.h	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/Source/WebCore/css/CSSCalculationValue.h	2017-10-10 00:08:14 UTC (rev 223099)
@@ -55,7 +55,7 @@
 public:
     enum Type {
         CssCalcPrimitiveValue = 1,
-        CssCalcBinaryOperation
+        CssCalcOperation
     };
 
     virtual ~CSSCalcExpressionNode() { }
@@ -85,8 +85,8 @@
 
 class CSSCalcValue final : public CSSValue {
 public:
-    static RefPtr<CSSCalcValue> create(const CSSParserTokenRange&, ValueRange);
-    
+    static RefPtr<CSSCalcValue> create(CSSValueID function, const CSSParserTokenRange&, CalculationCategory destinationCategory, ValueRange);
+
     static RefPtr<CSSCalcValue> create(const CalculationValue&, const RenderStyle&);
 
     CalculationCategory category() const { return m_expression->category(); }

Modified: branches/safari-604-branch/Source/WebCore/css/CSSValueKeywords.in (223098 => 223099)


--- branches/safari-604-branch/Source/WebCore/css/CSSValueKeywords.in	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/Source/WebCore/css/CSSValueKeywords.in	2017-10-10 00:08:14 UTC (rev 223099)
@@ -1258,6 +1258,8 @@
 
 calc
 -webkit-calc
+min
+max
 
 #if defined(ENABLE_CSS_IMAGE_RESOLUTION) && ENABLE_CSS_IMAGE_RESOLUTION
 from-image

Modified: branches/safari-604-branch/Source/WebCore/css/StyleBuilderConverter.h (223098 => 223099)


--- branches/safari-604-branch/Source/WebCore/css/StyleBuilderConverter.h	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/Source/WebCore/css/StyleBuilderConverter.h	2017-10-10 00:08:14 UTC (rev 223099)
@@ -322,9 +322,11 @@
         return Length(100 - length.value(), Percent);
     
     // Turn this into a calc _expression_: calc(100% - length)
-    auto lhs = std::make_unique<CalcExpressionLength>(Length(100, Percent));
-    auto rhs = std::make_unique<CalcExpressionLength>(length);
-    auto op = std::make_unique<CalcExpressionBinaryOperation>(WTFMove(lhs), WTFMove(rhs), CalcSubtract);
+    Vector<std::unique_ptr<CalcExpressionNode>> lengths;
+    lengths.reserveInitialCapacity(2);
+    lengths.uncheckedAppend(std::make_unique<CalcExpressionLength>(Length(100, Percent)));
+    lengths.uncheckedAppend(std::make_unique<CalcExpressionLength>(length));
+    auto op = std::make_unique<CalcExpressionOperation>(WTFMove(lengths), CalcSubtract);
     return Length(CalculationValue::create(WTFMove(op), ValueRangeAll));
 }
 

Modified: branches/safari-604-branch/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp (223098 => 223099)


--- branches/safari-604-branch/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/Source/WebCore/css/parser/CSSPropertyParserHelpers.cpp	2017-10-10 00:08:14 UTC (rev 223099)
@@ -78,13 +78,14 @@
 class CalcParser {
 
 public:
-    explicit CalcParser(CSSParserTokenRange& range, ValueRange valueRange = ValueRangeAll)
+    explicit CalcParser(CSSParserTokenRange& range, CalculationCategory destinationCategory, ValueRange valueRange = ValueRangeAll)
         : m_sourceRange(range)
         , m_range(range)
     {
         const CSSParserToken& token = range.peek();
-        if (token.functionId() == CSSValueCalc || token.functionId() == CSSValueWebkitCalc)
-            m_calcValue = CSSCalcValue::create(consumeFunction(m_range), valueRange);
+        auto functionId = token.functionId();
+        if (functionId == CSSValueCalc || functionId == CSSValueWebkitCalc || functionId == CSSValueMin || functionId == CSSValueMax)
+            m_calcValue = CSSCalcValue::create(functionId, consumeFunction(m_range), destinationCategory, valueRange);
     }
 
     const CSSCalcValue* value() const { return m_calcValue.get(); }
@@ -137,7 +138,7 @@
             return nullptr;
         return CSSValuePool::singleton().createValue(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitType::CSS_NUMBER);
     }
-    CalcParser calcParser(range);
+    CalcParser calcParser(range, CalcNumber);
     if (const CSSCalcValue* calculation = calcParser.value()) {
         if (calculation->category() != CalcNumber || !calculation->isInt())
             return nullptr;
@@ -163,7 +164,7 @@
         result = range.consumeIncludingWhitespace().numericValue();
         return true;
     }
-    CalcParser calcParser(range);
+    CalcParser calcParser(range, CalcNumber);
     return calcParser.consumePositiveIntegerRaw(result);
 }
     
@@ -173,7 +174,7 @@
         result = range.consumeIncludingWhitespace().numericValue();
         return true;
     }
-    CalcParser calcParser(range, ValueRangeAll);
+    CalcParser calcParser(range, CalcNumber, ValueRangeAll);
     return calcParser.consumeNumberRaw(result);
 }
 
@@ -186,7 +187,7 @@
             return nullptr;
         return CSSValuePool::singleton().createValue(range.consumeIncludingWhitespace().numericValue(), token.unitType());
     }
-    CalcParser calcParser(range, ValueRangeAll);
+    CalcParser calcParser(range, CalcNumber, ValueRangeAll);
     if (const CSSCalcValue* calculation = calcParser.value()) {
         // FIXME: Calcs should not be subject to parse time range checks.
         // spec: https://drafts.csswg.org/css-values-3/#calc-range
@@ -216,7 +217,7 @@
         return consumeNumber(range, ValueRangeAll);
 
     // "[For calc()], the used value resulting from an _expression_ must be clamped to the range allowed in the target context."
-    CalcParser calcParser(range, ValueRangeAll);
+    CalcParser calcParser(range, CalcNumber, ValueRangeAll);
     double result;
     if (calcParser.consumeNumberRaw(result)
 #if !ENABLE(VARIATION_FONTS)
@@ -278,7 +279,7 @@
         CSSPrimitiveValue::UnitType unitType = CSSPrimitiveValue::UnitType::CSS_PX;
         return CSSValuePool::singleton().createValue(range.consumeIncludingWhitespace().numericValue(), unitType);
     }
-    CalcParser calcParser(range, valueRange);
+    CalcParser calcParser(range, CalcLength, valueRange);
     if (calcParser.value() && calcParser.value()->category() == CalcLength)
         return calcParser.consumeValue();
     return nullptr;
@@ -292,7 +293,7 @@
             return nullptr;
         return CSSValuePool::singleton().createValue(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitType::CSS_PERCENTAGE);
     }
-    CalcParser calcParser(range, valueRange);
+    CalcParser calcParser(range, CalcPercent, valueRange);
     if (const CSSCalcValue* calculation = calcParser.value()) {
         if (calculation->category() == CalcPercent)
             return calcParser.consumeValue();
@@ -321,7 +322,7 @@
         return consumeLength(range, cssParserMode, valueRange, unitless);
     if (token.type() == PercentageToken)
         return consumePercent(range, valueRange);
-    CalcParser calcParser(range, valueRange);
+    CalcParser calcParser(range, CalcLength, valueRange);
     if (const CSSCalcValue* calculation = calcParser.value()) {
         if (canConsumeCalcValue(calculation->category(), cssParserMode))
             return calcParser.consumeValue();
@@ -347,7 +348,7 @@
         return CSSValuePool::singleton().createValue(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitType::CSS_DEG);
     }
 
-    CalcParser calcParser(range, ValueRangeAll);
+    CalcParser calcParser(range, CalcAngle, ValueRangeAll);
     if (const CSSCalcValue* calculation = calcParser.value()) {
         if (calculation->category() == CalcAngle)
             return calcParser.consumeValue();
@@ -369,7 +370,7 @@
             return CSSValuePool::singleton().createValue(range.consumeIncludingWhitespace().numericValue(), unit);
         return nullptr;
     }
-    CalcParser calcParser(range, valueRange);
+    CalcParser calcParser(range, CalcTime, valueRange);
     if (const CSSCalcValue* calculation = calcParser.value()) {
         if (calculation->category() == CalcTime)
             return calcParser.consumeValue();

Modified: branches/safari-604-branch/Source/WebCore/platform/CalculationValue.cpp (223098 => 223099)


--- branches/safari-604-branch/Source/WebCore/platform/CalculationValue.cpp	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/Source/WebCore/platform/CalculationValue.cpp	2017-10-10 00:08:14 UTC (rev 223099)
@@ -68,34 +68,74 @@
     return m_shouldClampToNonNegative && result < 0 ? 0 : result;
 }
 
-float CalcExpressionBinaryOperation::evaluate(float maxValue) const
+float CalcExpressionOperation::evaluate(float maxValue) const
 {
-    float left = m_leftSide->evaluate(maxValue);
-    float right = m_rightSide->evaluate(maxValue);
     switch (m_operator) {
-    case CalcAdd:
+    case CalcAdd: {
+        ASSERT(m_children.size() == 2);
+        float left = m_children[0]->evaluate(maxValue);
+        float right = m_children[1]->evaluate(maxValue);
         return left + right;
-    case CalcSubtract:
+    }
+    case CalcSubtract: {
+        ASSERT(m_children.size() == 2);
+        float left = m_children[0]->evaluate(maxValue);
+        float right = m_children[1]->evaluate(maxValue);
         return left - right;
-    case CalcMultiply:
+    }
+    case CalcMultiply: {
+        ASSERT(m_children.size() == 2);
+        float left = m_children[0]->evaluate(maxValue);
+        float right = m_children[1]->evaluate(maxValue);
         return left * right;
-    case CalcDivide:
-        if (!right)
+    }
+    case CalcDivide: {
+        ASSERT(m_children.size() == 1 || m_children.size() == 2);
+        if (m_children.size() == 1)
             return std::numeric_limits<float>::quiet_NaN();
+        float left = m_children[0]->evaluate(maxValue);
+        float right = m_children[1]->evaluate(maxValue);
         return left / right;
     }
+    case CalcMin: {
+        if (m_children.isEmpty())
+            return std::numeric_limits<float>::quiet_NaN();
+        float minimum = m_children[0]->evaluate(maxValue);
+        for (auto& child : m_children)
+            minimum = std::min(minimum, child->evaluate(maxValue));
+        return minimum;
+    }
+    case CalcMax: {
+        if (m_children.isEmpty())
+            return std::numeric_limits<float>::quiet_NaN();
+        float maximum = m_children[0]->evaluate(maxValue);
+        for (auto& child : m_children)
+            maximum = std::max(maximum, child->evaluate(maxValue));
+        return maximum;
+    }
+    }
     ASSERT_NOT_REACHED();
     return std::numeric_limits<float>::quiet_NaN();
 }
 
-bool CalcExpressionBinaryOperation::operator==(const CalcExpressionNode& other) const
+bool CalcExpressionOperation::operator==(const CalcExpressionNode& other) const
 {
-    return other.type() == CalcExpressionNodeBinaryOperation && *this == toCalcExpressionBinaryOperation(other);
+    return other.type() == CalcExpressionNodeOperation && *this == toCalcExpressionOperation(other);
 }
 
-void CalcExpressionBinaryOperation::dump(TextStream& ts) const
+void CalcExpressionOperation::dump(TextStream& ts) const
 {
-    ts << *m_leftSide << " " << m_operator << " " << *m_rightSide;
+    if (m_operator == CalcMin || m_operator == CalcMax) {
+        ts << m_operator << "(";
+        size_t childrenCount = m_children.size();
+        for (size_t i = 0; i < childrenCount; i++) {
+            ts << m_children[i].get();
+            if (i < childrenCount - 1)
+                ts << ", ";
+        }
+        ts << ")";
+    } else
+        ts << m_children[0].get() << " " << m_operator << " " << m_children[1].get();
 }
 
 float CalcExpressionLength::evaluate(float maxValue) const
@@ -135,6 +175,8 @@
     case CalcSubtract: ts << "-"; break;
     case CalcMultiply: ts << "*"; break;
     case CalcDivide: ts << "/"; break;
+    case CalcMin: ts << "max"; break;
+    case CalcMax: ts << "min"; break;
     }
     return ts;
 }

Modified: branches/safari-604-branch/Source/WebCore/platform/CalculationValue.h (223098 => 223099)


--- branches/safari-604-branch/Source/WebCore/platform/CalculationValue.h	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/Source/WebCore/platform/CalculationValue.h	2017-10-10 00:08:14 UTC (rev 223099)
@@ -35,6 +35,7 @@
 #include <memory>
 #include <wtf/Ref.h>
 #include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
 
 namespace WebCore {
 
@@ -44,7 +45,9 @@
     CalcAdd = '+',
     CalcSubtract = '-',
     CalcMultiply = '*',
-    CalcDivide = '/'
+    CalcDivide = '/',
+    CalcMin = 0,
+    CalcMax = 1,
 };
 
 enum CalcExpressionNodeType {
@@ -51,7 +54,7 @@
     CalcExpressionNodeUndefined,
     CalcExpressionNodeNumber,
     CalcExpressionNodeLength,
-    CalcExpressionNodeBinaryOperation,
+    CalcExpressionNodeOperation,
     CalcExpressionNodeBlendLength,
 };
 
@@ -99,21 +102,20 @@
     Length m_length;
 };
 
-class CalcExpressionBinaryOperation final : public CalcExpressionNode {
+class CalcExpressionOperation final : public CalcExpressionNode {
 public:
-    CalcExpressionBinaryOperation(std::unique_ptr<CalcExpressionNode> leftSide, std::unique_ptr<CalcExpressionNode> rightSide, CalcOperator);
+    CalcExpressionOperation(Vector<std::unique_ptr<CalcExpressionNode>>&& children, CalcOperator);
 
-    const CalcExpressionNode& leftSide() const { return *m_leftSide; }
-    const CalcExpressionNode& rightSide() const { return *m_rightSide; }
     CalcOperator getOperator() const { return m_operator; }
 
+    const Vector<std::unique_ptr<CalcExpressionNode>>& children() const { return m_children; }
+
 private:
     float evaluate(float maxValue) const override;
     bool operator==(const CalcExpressionNode&) const override;
     void dump(TextStream&) const override;
 
-    std::unique_ptr<CalcExpressionNode> m_leftSide;
-    std::unique_ptr<CalcExpressionNode> m_rightSide;
+    Vector<std::unique_ptr<CalcExpressionNode>> m_children;
     CalcOperator m_operator;
 };
 
@@ -200,23 +202,22 @@
     return static_cast<const CalcExpressionLength&>(value);
 }
 
-inline CalcExpressionBinaryOperation::CalcExpressionBinaryOperation(std::unique_ptr<CalcExpressionNode> leftSide, std::unique_ptr<CalcExpressionNode> rightSide, CalcOperator op)
-    : CalcExpressionNode(CalcExpressionNodeBinaryOperation)
-    , m_leftSide(WTFMove(leftSide))
-    , m_rightSide(WTFMove(rightSide))
+inline CalcExpressionOperation::CalcExpressionOperation(Vector<std::unique_ptr<CalcExpressionNode>>&& children, CalcOperator op)
+    : CalcExpressionNode(CalcExpressionNodeOperation)
+    , m_children(WTFMove(children))
     , m_operator(op)
 {
 }
 
-inline bool operator==(const CalcExpressionBinaryOperation& a, const CalcExpressionBinaryOperation& b)
+inline bool operator==(const CalcExpressionOperation& a, const CalcExpressionOperation& b)
 {
-    return a.getOperator() == b.getOperator() && a.leftSide() == b.leftSide() && a.rightSide() == b.rightSide();
+    return a.getOperator() == b.getOperator() && a.children() == b.children();
 }
 
-inline const CalcExpressionBinaryOperation& toCalcExpressionBinaryOperation(const CalcExpressionNode& value)
+inline const CalcExpressionOperation& toCalcExpressionOperation(const CalcExpressionNode& value)
 {
-    ASSERT_WITH_SECURITY_IMPLICATION(value.type() == CalcExpressionNodeBinaryOperation);
-    return static_cast<const CalcExpressionBinaryOperation&>(value);
+    ASSERT_WITH_SECURITY_IMPLICATION(value.type() == CalcExpressionNodeOperation);
+    return static_cast<const CalcExpressionOperation&>(value);
 }
 
 inline CalcExpressionBlendLength::CalcExpressionBlendLength(Length from, Length to, float progress)

Modified: branches/safari-604-branch/Source/WebCore/platform/Length.cpp (223098 => 223099)


--- branches/safari-604-branch/Source/WebCore/platform/Length.cpp	2017-10-10 00:08:09 UTC (rev 223098)
+++ branches/safari-604-branch/Source/WebCore/platform/Length.cpp	2017-10-10 00:08:14 UTC (rev 223099)
@@ -290,9 +290,11 @@
         return Length(100 - length.value(), Percent);
     
     // Turn this into a calc _expression_: calc(100% - length)
-    auto lhs = std::make_unique<CalcExpressionLength>(Length(100, Percent));
-    auto rhs = std::make_unique<CalcExpressionLength>(length);
-    auto op = std::make_unique<CalcExpressionBinaryOperation>(WTFMove(lhs), WTFMove(rhs), CalcSubtract);
+    Vector<std::unique_ptr<CalcExpressionNode>> lengths;
+    lengths.reserveInitialCapacity(2);
+    lengths.uncheckedAppend(std::make_unique<CalcExpressionLength>(Length(100, Percent)));
+    lengths.uncheckedAppend(std::make_unique<CalcExpressionLength>(length));
+    auto op = std::make_unique<CalcExpressionOperation>(WTFMove(lengths), CalcSubtract);
     return Length(CalculationValue::create(WTFMove(op), ValueRangeAll));
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to