Add modern API for overriding the page's specified viewport configuration
[WebKit-https.git] / Source / WebCore / css / CSSCalculationValue.cpp
1 /*
2  * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
3  * Copyright (C) 2014 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "CSSCalculationValue.h"
34
35 #include "CSSParser.h"
36 #include "CSSParserTokenRange.h"
37 #include "CSSPrimitiveValueMappings.h"
38 #include "StyleResolver.h"
39 #include <wtf/MathExtras.h>
40 #include <wtf/text/StringBuilder.h>
41
42 static const int maxExpressionDepth = 100;
43
44 enum ParseState {
45     OK,
46     TooDeep,
47     NoMoreTokens
48 };
49
50 namespace WebCore {
51
52 static RefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode&, const RenderStyle&);
53 static RefPtr<CSSCalcExpressionNode> createCSS(const Length&, const RenderStyle&);
54
55 static CalculationCategory unitCategory(CSSPrimitiveValue::UnitType type)
56 {
57     switch (type) {
58     case CSSPrimitiveValue::CSS_NUMBER:
59         return CalculationCategory::Number;
60     case CSSPrimitiveValue::CSS_EMS:
61     case CSSPrimitiveValue::CSS_EXS:
62     case CSSPrimitiveValue::CSS_PX:
63     case CSSPrimitiveValue::CSS_CM:
64     case CSSPrimitiveValue::CSS_MM:
65     case CSSPrimitiveValue::CSS_IN:
66     case CSSPrimitiveValue::CSS_PT:
67     case CSSPrimitiveValue::CSS_PC:
68     case CSSPrimitiveValue::CSS_REMS:
69     case CSSPrimitiveValue::CSS_CHS:
70     case CSSPrimitiveValue::CSS_VW:
71     case CSSPrimitiveValue::CSS_VH:
72     case CSSPrimitiveValue::CSS_VMIN:
73     case CSSPrimitiveValue::CSS_VMAX:
74         return CalculationCategory::Length;
75     case CSSPrimitiveValue::CSS_PERCENTAGE:
76         return CalculationCategory::Percent;
77     case CSSPrimitiveValue::CSS_DEG:
78     case CSSPrimitiveValue::CSS_RAD:
79     case CSSPrimitiveValue::CSS_GRAD:
80     case CSSPrimitiveValue::CSS_TURN:
81         return CalculationCategory::Angle;
82     case CSSPrimitiveValue::CSS_MS:
83     case CSSPrimitiveValue::CSS_S:
84         return CalculationCategory::Time;
85     case CSSPrimitiveValue::CSS_HZ:
86     case CSSPrimitiveValue::CSS_KHZ:
87         return CalculationCategory::Frequency;
88     default:
89         return CalculationCategory::Other;
90     }
91 }
92
93 static bool hasDoubleValue(CSSPrimitiveValue::UnitType type)
94 {
95     switch (type) {
96     case CSSPrimitiveValue::CSS_FR:
97     case CSSPrimitiveValue::CSS_NUMBER:
98     case CSSPrimitiveValue::CSS_PERCENTAGE:
99     case CSSPrimitiveValue::CSS_EMS:
100     case CSSPrimitiveValue::CSS_EXS:
101     case CSSPrimitiveValue::CSS_CHS:
102     case CSSPrimitiveValue::CSS_REMS:
103     case CSSPrimitiveValue::CSS_PX:
104     case CSSPrimitiveValue::CSS_CM:
105     case CSSPrimitiveValue::CSS_MM:
106     case CSSPrimitiveValue::CSS_IN:
107     case CSSPrimitiveValue::CSS_PT:
108     case CSSPrimitiveValue::CSS_PC:
109     case CSSPrimitiveValue::CSS_DEG:
110     case CSSPrimitiveValue::CSS_RAD:
111     case CSSPrimitiveValue::CSS_GRAD:
112     case CSSPrimitiveValue::CSS_TURN:
113     case CSSPrimitiveValue::CSS_MS:
114     case CSSPrimitiveValue::CSS_S:
115     case CSSPrimitiveValue::CSS_HZ:
116     case CSSPrimitiveValue::CSS_KHZ:
117     case CSSPrimitiveValue::CSS_DIMENSION:
118     case CSSPrimitiveValue::CSS_VW:
119     case CSSPrimitiveValue::CSS_VH:
120     case CSSPrimitiveValue::CSS_VMIN:
121     case CSSPrimitiveValue::CSS_VMAX:
122     case CSSPrimitiveValue::CSS_DPPX:
123     case CSSPrimitiveValue::CSS_DPI:
124     case CSSPrimitiveValue::CSS_DPCM:
125         return true;
126     case CSSPrimitiveValue::CSS_UNKNOWN:
127     case CSSPrimitiveValue::CSS_STRING:
128     case CSSPrimitiveValue::CSS_FONT_FAMILY:
129     case CSSPrimitiveValue::CSS_URI:
130     case CSSPrimitiveValue::CSS_IDENT:
131     case CSSPrimitiveValue::CSS_ATTR:
132     case CSSPrimitiveValue::CSS_COUNTER:
133     case CSSPrimitiveValue::CSS_RECT:
134     case CSSPrimitiveValue::CSS_RGBCOLOR:
135     case CSSPrimitiveValue::CSS_PAIR:
136     case CSSPrimitiveValue::CSS_UNICODE_RANGE:
137     case CSSPrimitiveValue::CSS_COUNTER_NAME:
138     case CSSPrimitiveValue::CSS_SHAPE:
139     case CSSPrimitiveValue::CSS_QUAD:
140     case CSSPrimitiveValue::CSS_QUIRKY_EMS:
141     case CSSPrimitiveValue::CSS_CALC:
142     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER:
143     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH:
144     case CSSPrimitiveValue::CSS_PROPERTY_ID:
145     case CSSPrimitiveValue::CSS_VALUE_ID:
146 #if ENABLE(DASHBOARD_SUPPORT)
147     case CSSPrimitiveValue::CSS_DASHBOARD_REGION:
148 #endif
149         return false;
150     };
151     ASSERT_NOT_REACHED();
152     return false;
153 }
154
155 static String buildCssText(const String& expression)
156 {
157     StringBuilder result;
158     result.appendLiteral("calc");
159     bool expressionHasSingleTerm = expression[0] != '(';
160     if (expressionHasSingleTerm)
161         result.append('(');
162     result.append(expression);
163     if (expressionHasSingleTerm)
164         result.append(')');
165     return result.toString();
166 }
167
168 String CSSCalcValue::customCSSText() const
169 {
170     return buildCssText(m_expression->customCSSText());
171 }
172
173 bool CSSCalcValue::equals(const CSSCalcValue& other) const
174 {
175     return compareCSSValue(m_expression, other.m_expression);
176 }
177
178 inline double CSSCalcValue::clampToPermittedRange(double value) const
179 {
180     return m_shouldClampToNonNegative && value < 0 ? 0 : value;
181 }
182
183 double CSSCalcValue::doubleValue() const
184 {
185     return clampToPermittedRange(m_expression->doubleValue());
186 }
187
188 double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const
189 {
190     return clampToPermittedRange(m_expression->computeLengthPx(conversionData));
191 }
192
193 class CSSCalcPrimitiveValue final : public CSSCalcExpressionNode {
194     WTF_MAKE_FAST_ALLOCATED;
195 public:
196     static Ref<CSSCalcPrimitiveValue> create(Ref<CSSPrimitiveValue>&& value, bool isInteger)
197     {
198         return adoptRef(*new CSSCalcPrimitiveValue(WTFMove(value), isInteger));
199     }
200
201     static RefPtr<CSSCalcPrimitiveValue> create(double value, CSSPrimitiveValue::UnitType type, bool isInteger)
202     {
203         if (!std::isfinite(value))
204             return nullptr;
205         return adoptRef(new CSSCalcPrimitiveValue(CSSPrimitiveValue::create(value, type), isInteger));
206     }
207
208 private:
209     bool isZero() const final
210     {
211         return !m_value->doubleValue();
212     }
213
214     String customCSSText() const final
215     {
216         return m_value->cssText();
217     }
218
219     std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final
220     {
221         switch (category()) {
222         case CalculationCategory::Number:
223             return std::make_unique<CalcExpressionNumber>(m_value->floatValue());
224         case CalculationCategory::Length:
225             return std::make_unique<CalcExpressionLength>(Length(m_value->computeLength<float>(conversionData), WebCore::Fixed));
226         case CalculationCategory::Percent:
227         case CalculationCategory::PercentLength: {
228             return std::make_unique<CalcExpressionLength>(m_value->convertToLength<FixedFloatConversion | PercentConversion>(conversionData));
229         }
230         // Only types that could be part of a Length expression can be converted
231         // to a CalcExpressionNode. CalculationCategory::PercentNumber makes no sense as a Length.
232         case CalculationCategory::PercentNumber:
233         case CalculationCategory::Angle:
234         case CalculationCategory::Time:
235         case CalculationCategory::Frequency:
236         case CalculationCategory::Other:
237             ASSERT_NOT_REACHED();
238         }
239         ASSERT_NOT_REACHED();
240         return nullptr;
241     }
242
243     double doubleValue() const final
244     {
245         if (hasDoubleValue(primitiveType()))
246             return m_value->doubleValue();
247         ASSERT_NOT_REACHED();
248         return 0;
249     }
250
251     double computeLengthPx(const CSSToLengthConversionData& conversionData) const final
252     {
253         switch (category()) {
254         case CalculationCategory::Length:
255             return m_value->computeLength<double>(conversionData);
256         case CalculationCategory::Percent:
257         case CalculationCategory::Number:
258             return m_value->doubleValue();
259         case CalculationCategory::PercentLength:
260         case CalculationCategory::PercentNumber:
261         case CalculationCategory::Angle:
262         case CalculationCategory::Time:
263         case CalculationCategory::Frequency:
264         case CalculationCategory::Other:
265             ASSERT_NOT_REACHED();
266             break;
267         }
268         ASSERT_NOT_REACHED();
269         return 0;
270     }
271
272     void collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const final
273     {
274         m_value->collectDirectComputationalDependencies(values);
275     }
276
277     void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const final
278     {
279         m_value->collectDirectRootComputationalDependencies(values);
280     }
281
282     bool equals(const CSSCalcExpressionNode& other) const final
283     {
284         if (type() != other.type())
285             return false;
286
287         return compareCSSValue(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value);
288     }
289
290     Type type() const final { return CssCalcPrimitiveValue; }
291     CSSPrimitiveValue::UnitType primitiveType() const final
292     {
293         return CSSPrimitiveValue::UnitType(m_value->primitiveType());
294     }
295
296 private:
297     explicit CSSCalcPrimitiveValue(Ref<CSSPrimitiveValue>&& value, bool isInteger)
298         : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitType)value->primitiveType()), isInteger)
299         , m_value(WTFMove(value))
300     {
301     }
302
303     Ref<CSSPrimitiveValue> m_value;
304 };
305
306 static const CalculationCategory addSubtractResult[static_cast<unsigned>(CalculationCategory::Angle)][static_cast<unsigned>(CalculationCategory::Angle)] = {
307 //    CalculationCategory::Number         CalculationCategory::Length         CalculationCategory::Percent        CalculationCategory::PercentNumber  CalculationCategory::PercentLength
308     { CalculationCategory::Number,        CalculationCategory::Other,         CalculationCategory::PercentNumber, CalculationCategory::PercentNumber, CalculationCategory::Other }, //         CalculationCategory::Number
309     { CalculationCategory::Other,         CalculationCategory::Length,        CalculationCategory::PercentLength, CalculationCategory::Other,         CalculationCategory::PercentLength }, // CalculationCategory::Length
310     { CalculationCategory::PercentNumber, CalculationCategory::PercentLength, CalculationCategory::Percent,       CalculationCategory::PercentNumber, CalculationCategory::PercentLength }, // CalculationCategory::Percent
311     { CalculationCategory::PercentNumber, CalculationCategory::Other,         CalculationCategory::PercentNumber, CalculationCategory::PercentNumber, CalculationCategory::Other }, //         CalculationCategory::PercentNumber
312     { CalculationCategory::Other,         CalculationCategory::PercentLength, CalculationCategory::PercentLength, CalculationCategory::Other,         CalculationCategory::PercentLength }, // CalculationCategory::PercentLength
313 };
314
315 static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide, CalcOperator op)
316 {
317     CalculationCategory leftCategory = leftSide.category();
318     CalculationCategory rightCategory = rightSide.category();
319     ASSERT(leftCategory < CalculationCategory::Other);
320     ASSERT(rightCategory < CalculationCategory::Other);
321
322     switch (op) {
323     case CalcOperator::Add:
324     case CalcOperator::Subtract:
325         if (leftCategory < CalculationCategory::Angle && rightCategory < CalculationCategory::Angle)
326             return addSubtractResult[static_cast<unsigned>(leftCategory)][static_cast<unsigned>(rightCategory)];
327         if (leftCategory == rightCategory)
328             return leftCategory;
329         return CalculationCategory::Other;
330     case CalcOperator::Multiply:
331         if (leftCategory != CalculationCategory::Number && rightCategory != CalculationCategory::Number)
332             return CalculationCategory::Other;
333         return leftCategory == CalculationCategory::Number ? rightCategory : leftCategory;
334     case CalcOperator::Divide:
335         if (rightCategory != CalculationCategory::Number || rightSide.isZero())
336             return CalculationCategory::Other;
337         return leftCategory;
338     case CalcOperator::Min:
339     case CalcOperator::Max:
340         ASSERT_NOT_REACHED();
341         return CalculationCategory::Other;
342     }
343
344     ASSERT_NOT_REACHED();
345     return CalculationCategory::Other;
346 }
347
348 static CalculationCategory resolvedTypeForMinOrMax(CalculationCategory category, CalculationCategory destinationCategory)
349 {
350     switch (category) {
351     case CalculationCategory::Number:
352     case CalculationCategory::Length:
353     case CalculationCategory::PercentNumber:
354     case CalculationCategory::PercentLength:
355     case CalculationCategory::Angle:
356     case CalculationCategory::Time:
357     case CalculationCategory::Frequency:
358     case CalculationCategory::Other:
359         return category;
360
361     case CalculationCategory::Percent:
362         if (destinationCategory == CalculationCategory::Length)
363             return CalculationCategory::PercentLength;
364         if (destinationCategory == CalculationCategory::Number)
365             return CalculationCategory::PercentNumber;
366         return category;
367     }
368
369     return CalculationCategory::Other;
370 }
371
372 static inline bool isIntegerResult(CalcOperator op, const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide)
373 {
374     // Performs W3C spec's type checking for calc integers.
375     // http://www.w3.org/TR/css3-values/#calc-type-checking
376     return op != CalcOperator::Divide && leftSide.isInteger() && rightSide.isInteger();
377 }
378
379 static inline bool isIntegerResult(CalcOperator op, const Vector<Ref<CSSCalcExpressionNode>>& nodes)
380 {
381     // Performs W3C spec's type checking for calc integers.
382     // http://www.w3.org/TR/css3-values/#calc-type-checking
383     if (op == CalcOperator::Divide)
384         return false;
385
386     for (auto& node : nodes) {
387         if (!node->isInteger())
388             return false;
389     }
390
391     return true;
392 }
393
394 static bool isSamePair(CalculationCategory a, CalculationCategory b, CalculationCategory x, CalculationCategory y)
395 {
396     return (a == x && b == y) || (a == y && b == x);
397 }
398
399 class CSSCalcOperation final : public CSSCalcExpressionNode {
400     WTF_MAKE_FAST_ALLOCATED;
401 public:
402     static RefPtr<CSSCalcOperation> create(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
403     {
404         if (!leftSide || !rightSide)
405             return nullptr;
406
407         ASSERT(leftSide->category() < CalculationCategory::Other);
408         ASSERT(rightSide->category() < CalculationCategory::Other);
409
410         auto newCategory = determineCategory(*leftSide, *rightSide, op);
411         if (newCategory == CalculationCategory::Other)
412             return nullptr;
413
414         return adoptRef(new CSSCalcOperation(newCategory, op, leftSide.releaseNonNull(), rightSide.releaseNonNull()));
415     }
416
417     static RefPtr<CSSCalcOperation> createMinOrMax(CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& values, CalculationCategory destinationCategory)
418     {
419         ASSERT(op == CalcOperator::Min || op == CalcOperator::Max);
420
421         Optional<CalculationCategory> category = WTF::nullopt;
422         for (auto& value : values) {
423             auto valueCategory = resolvedTypeForMinOrMax(value->category(), destinationCategory);
424
425             ASSERT(valueCategory < CalculationCategory::Other);
426             if (!category) {
427                 if (valueCategory == CalculationCategory::Other)
428                     return nullptr;
429                 category = valueCategory;
430             }
431
432             if (category != valueCategory) {
433                 if (isSamePair(category.value(), valueCategory, CalculationCategory::Length, CalculationCategory::PercentLength)) {
434                     category = CalculationCategory::PercentLength;
435                     continue;
436                 }
437                 if (isSamePair(category.value(), valueCategory, CalculationCategory::Number, CalculationCategory::PercentNumber)) {
438                     category = CalculationCategory::PercentNumber;
439                     continue;
440                 }
441                 return nullptr;
442             }
443         }
444
445         return adoptRef(new CSSCalcOperation(category.value(), op, WTFMove(values)));
446     }
447
448     static RefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
449     {
450         if (!leftSide || !rightSide)
451             return nullptr;
452
453         auto leftCategory = leftSide->category();
454         auto rightCategory = rightSide->category();
455         ASSERT(leftCategory < CalculationCategory::Other);
456         ASSERT(rightCategory < CalculationCategory::Other);
457
458         bool isInteger = isIntegerResult(op, *leftSide, *rightSide);
459
460         // Simplify numbers.
461         if (leftCategory == CalculationCategory::Number && rightCategory == CalculationCategory::Number) {
462             CSSPrimitiveValue::UnitType evaluationType = CSSPrimitiveValue::CSS_NUMBER;
463             return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftSide->doubleValue(), rightSide->doubleValue() }), evaluationType, isInteger);
464         }
465
466         // Simplify addition and subtraction between same types.
467         if (op == CalcOperator::Add || op == CalcOperator::Subtract) {
468             if (leftCategory == rightSide->category()) {
469                 CSSPrimitiveValue::UnitType leftType = leftSide->primitiveType();
470                 if (hasDoubleValue(leftType)) {
471                     CSSPrimitiveValue::UnitType rightType = rightSide->primitiveType();
472                     if (leftType == rightType)
473                         return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftSide->doubleValue(), rightSide->doubleValue() }), leftType, isInteger);
474                     CSSPrimitiveValue::UnitCategory leftUnitCategory = CSSPrimitiveValue::unitCategory(leftType);
475                     if (leftUnitCategory != CSSPrimitiveValue::UOther && leftUnitCategory == CSSPrimitiveValue::unitCategory(rightType)) {
476                         CSSPrimitiveValue::UnitType canonicalType = CSSPrimitiveValue::canonicalUnitTypeForCategory(leftUnitCategory);
477                         if (canonicalType != CSSPrimitiveValue::CSS_UNKNOWN) {
478                             double leftValue = leftSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(leftType);
479                             double rightValue = rightSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(rightType);
480                             return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftValue, rightValue }), canonicalType, isInteger);
481                         }
482                     }
483                 }
484             }
485         } else {
486             // Simplify multiplying or dividing by a number for simplifiable types.
487             ASSERT(op == CalcOperator::Multiply || op == CalcOperator::Divide);
488             auto* numberSide = getNumberSide(*leftSide, *rightSide);
489             if (!numberSide)
490                 return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
491             if (numberSide == leftSide && op == CalcOperator::Divide)
492                 return nullptr;
493             auto& otherSide = leftSide == numberSide ? *rightSide : *leftSide;
494
495             double number = numberSide->doubleValue();
496             if (!std::isfinite(number))
497                 return nullptr;
498             if (op == CalcOperator::Divide && !number)
499                 return nullptr;
500
501             auto otherType = otherSide.primitiveType();
502             if (hasDoubleValue(otherType))
503                 return CSSCalcPrimitiveValue::create(evaluateOperator(op, { otherSide.doubleValue(), number }), otherType, isInteger);
504         }
505
506         return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
507     }
508
509 private:
510     bool isZero() const final
511     {
512         return !doubleValue();
513     }
514
515     std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final
516     {
517         Vector<std::unique_ptr<CalcExpressionNode>> nodes;
518         nodes.reserveInitialCapacity(m_children.size());
519
520         for (auto& child : m_children) {
521             auto node = child->createCalcExpression(conversionData);
522             if (!node)
523                 return nullptr;
524             nodes.uncheckedAppend(WTFMove(node));
525         }
526         return std::make_unique<CalcExpressionOperation>(WTFMove(nodes), m_operator);
527     }
528
529     double doubleValue() const final
530     {
531         Vector<double> doubleValues;
532         for (auto& child : m_children)
533             doubleValues.append(child->doubleValue());
534         return evaluate(doubleValues);
535     }
536
537     double computeLengthPx(const CSSToLengthConversionData& conversionData) const final
538     {
539         Vector<double> doubleValues;
540         for (auto& child : m_children)
541             doubleValues.append(child->computeLengthPx(conversionData));
542         return evaluate(doubleValues);
543     }
544
545     void collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const final
546     {
547         for (auto& child : m_children)
548             child->collectDirectComputationalDependencies(values);
549     }
550
551     void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const final
552     {
553         for (auto& child : m_children)
554             child->collectDirectRootComputationalDependencies(values);
555     }
556
557     static String buildCssText(Vector<String> childExpressions, CalcOperator op)
558     {
559         StringBuilder result;
560         result.append('(');
561         switch (op) {
562         case CalcOperator::Add:
563         case CalcOperator::Subtract:
564         case CalcOperator::Multiply:
565         case CalcOperator::Divide:
566             ASSERT(childExpressions.size() == 2);
567             result.append(childExpressions[0]);
568             result.append(' ');
569             result.append(static_cast<char>(op));
570             result.append(' ');
571             result.append(childExpressions[1]);
572             break;
573         case CalcOperator::Min:
574         case CalcOperator::Max:
575             ASSERT(!childExpressions.isEmpty());
576             const char* functionName = op == CalcOperator::Min ? "min(" : "max(";
577             result.append(functionName);
578             result.append(childExpressions[0]);
579             for (size_t i = 1; i < childExpressions.size(); ++i) {
580                 result.append(',');
581                 result.append(' ');
582                 result.append(childExpressions[i]);
583             }
584             result.append(')');
585         }
586         result.append(')');
587
588         return result.toString();
589     }
590
591     String customCSSText() const final
592     {
593         Vector<String> cssTexts;
594         for (auto& child : m_children)
595             cssTexts.append(child->customCSSText());
596         return buildCssText(cssTexts, m_operator);
597     }
598
599     bool equals(const CSSCalcExpressionNode& exp) const final
600     {
601         if (type() != exp.type())
602             return false;
603
604         const CSSCalcOperation& other = static_cast<const CSSCalcOperation&>(exp);
605
606         if (m_children.size() != other.m_children.size() || m_operator != other.m_operator)
607             return false;
608
609         for (size_t i = 0; i < m_children.size(); ++i) {
610             if (!compareCSSValue(m_children[i], other.m_children[i]))
611                 return false;
612         }
613         return true;
614     }
615
616     Type type() const final { return CssCalcOperation; }
617
618     CSSPrimitiveValue::UnitType primitiveType() const final
619     {
620         switch (category()) {
621         case CalculationCategory::Number:
622 #if !ASSERT_DISABLED
623             for (auto& child : m_children)
624                 ASSERT(child->category() == CalculationCategory::Number);
625 #endif
626             return CSSPrimitiveValue::CSS_NUMBER;
627         case CalculationCategory::Length:
628         case CalculationCategory::Percent: {
629             if (m_children.isEmpty())
630                 return CSSPrimitiveValue::CSS_UNKNOWN;
631             if (m_children.size() == 2) {
632                 if (m_children[0]->category() == CalculationCategory::Number)
633                     return m_children[1]->primitiveType();
634                 if (m_children[1]->category() == CalculationCategory::Number)
635                     return m_children[0]->primitiveType();
636             }
637             CSSPrimitiveValue::UnitType firstType = m_children[0]->primitiveType();
638             for (auto& child : m_children) {
639                 if (firstType != child->primitiveType())
640                     return CSSPrimitiveValue::CSS_UNKNOWN;
641             }
642             return firstType;
643         }
644         case CalculationCategory::Angle:
645             return CSSPrimitiveValue::CSS_DEG;
646         case CalculationCategory::Time:
647             return CSSPrimitiveValue::CSS_MS;
648         case CalculationCategory::Frequency:
649             return CSSPrimitiveValue::CSS_HZ;
650         case CalculationCategory::PercentLength:
651         case CalculationCategory::PercentNumber:
652         case CalculationCategory::Other:
653             return CSSPrimitiveValue::CSS_UNKNOWN;
654         }
655         ASSERT_NOT_REACHED();
656         return CSSPrimitiveValue::CSS_UNKNOWN;
657     }
658
659     CSSCalcOperation(CalculationCategory category, CalcOperator op, Ref<CSSCalcExpressionNode>&& leftSide, Ref<CSSCalcExpressionNode>&& rightSide)
660         : CSSCalcExpressionNode(category, isIntegerResult(op, leftSide.get(), rightSide.get()))
661         , m_operator(op)
662     {
663         m_children.reserveInitialCapacity(2);
664         m_children.uncheckedAppend(WTFMove(leftSide));
665         m_children.uncheckedAppend(WTFMove(rightSide));
666     }
667
668     CSSCalcOperation(CalculationCategory category, CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& children)
669         : CSSCalcExpressionNode(category, isIntegerResult(op, children))
670         , m_operator(op)
671         , m_children(WTFMove(children))
672     {
673     }
674
675     static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide)
676     {
677         if (leftSide.category() == CalculationCategory::Number)
678             return &leftSide;
679         if (rightSide.category() == CalculationCategory::Number)
680             return &rightSide;
681         return nullptr;
682     }
683
684     double evaluate(const Vector<double>& children) const
685     {
686         return evaluateOperator(m_operator, children);
687     }
688
689     static double evaluateOperator(CalcOperator op, const Vector<double>& children)
690     {
691         switch (op) {
692         case CalcOperator::Add:
693             ASSERT(children.size() == 2);
694             return children[0] + children[1];
695         case CalcOperator::Subtract:
696             ASSERT(children.size() == 2);
697             return children[0] - children[1];
698         case CalcOperator::Multiply:
699             ASSERT(children.size() == 2);
700             return children[0] * children[1];
701         case CalcOperator::Divide:
702             ASSERT(children.size() == 1 || children.size() == 2);
703             if (children.size() == 1)
704                 return std::numeric_limits<double>::quiet_NaN();
705             return children[0] / children[1];
706         case CalcOperator::Min: {
707             if (children.isEmpty())
708                 return std::numeric_limits<double>::quiet_NaN();
709             double minimum = children[0];
710             for (auto child : children)
711                 minimum = std::min(minimum, child);
712             return minimum;
713         }
714         case CalcOperator::Max: {
715             if (children.isEmpty())
716                 return std::numeric_limits<double>::quiet_NaN();
717             double maximum = children[0];
718             for (auto child : children)
719                 maximum = std::max(maximum, child);
720             return maximum;
721         }
722         }
723         ASSERT_NOT_REACHED();
724         return 0;
725     }
726
727     const CalcOperator m_operator;
728     Vector<Ref<CSSCalcExpressionNode>> m_children;
729 };
730
731 static ParseState checkDepthAndIndex(int* depth, CSSParserTokenRange tokens)
732 {
733     (*depth)++;
734     if (tokens.atEnd())
735         return NoMoreTokens;
736     if (*depth > maxExpressionDepth)
737         return TooDeep;
738     return OK;
739 }
740
741 class CSSCalcExpressionNodeParser {
742 public:
743     explicit CSSCalcExpressionNodeParser(CalculationCategory destinationCategory)
744         : m_destinationCategory(destinationCategory)
745     { }
746
747     RefPtr<CSSCalcExpressionNode> parseCalc(CSSParserTokenRange tokens, CSSValueID function)
748     {
749         Value result;
750         tokens.consumeWhitespace();
751         bool ok = false;
752         if (function == CSSValueCalc || function == CSSValueWebkitCalc)
753             ok = parseValueExpression(tokens, 0, &result);
754         else if (function == CSSValueMin || function == CSSValueMax)
755             ok = parseMinMaxExpression(tokens, function, 0, &result);
756         if (!ok || !tokens.atEnd())
757             return nullptr;
758         return result.value;
759     }
760     
761 private:
762     struct Value {
763         RefPtr<CSSCalcExpressionNode> value;
764     };
765     
766     char operatorValue(const CSSParserToken& token)
767     {
768         if (token.type() == DelimiterToken)
769             return token.delimiter();
770         return 0;
771     }
772     
773     bool parseValue(CSSParserTokenRange& tokens, Value* result)
774     {
775         CSSParserToken token = tokens.consumeIncludingWhitespace();
776         if (!(token.type() == NumberToken || token.type() == PercentageToken || token.type() == DimensionToken))
777             return false;
778         
779         CSSPrimitiveValue::UnitType type = token.unitType();
780         if (unitCategory(type) == CalculationCategory::Other)
781             return false;
782         
783         bool isInteger = token.numericValueType() == IntegerValueType || (token.numericValueType() == NumberValueType && token.numericValue() == trunc(token.numericValue()));
784         result->value = CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(token.numericValue(), type), isInteger);
785         
786         return true;
787     }
788     
789     bool parseValueTerm(CSSParserTokenRange& tokens, int depth, Value* result)
790     {
791         if (checkDepthAndIndex(&depth, tokens) != OK)
792             return false;
793
794         auto functionId = tokens.peek().functionId();
795         
796         if (tokens.peek().type() == LeftParenthesisToken || functionId == CSSValueCalc) {
797             CSSParserTokenRange innerRange = tokens.consumeBlock();
798             tokens.consumeWhitespace();
799             innerRange.consumeWhitespace();
800             return parseValueExpression(innerRange, depth, result);
801         }
802
803         if (functionId == CSSValueMax || functionId == CSSValueMin) {
804             CSSParserTokenRange innerRange = tokens.consumeBlock();
805             tokens.consumeWhitespace();
806             innerRange.consumeWhitespace();
807             return parseMinMaxExpression(innerRange, functionId, depth, result);
808         }
809         
810         return parseValue(tokens, result);
811     }
812     
813     bool parseValueMultiplicativeExpression(CSSParserTokenRange& tokens, int depth, Value* result)
814     {
815         if (checkDepthAndIndex(&depth, tokens) != OK)
816             return false;
817         
818         if (!parseValueTerm(tokens, depth, result))
819             return false;
820         
821         while (!tokens.atEnd()) {
822             char operatorCharacter = operatorValue(tokens.peek());
823             if (operatorCharacter != static_cast<char>(CalcOperator::Multiply) && operatorCharacter != static_cast<char>(CalcOperator::Divide))
824                 break;
825             tokens.consumeIncludingWhitespace();
826             
827             Value rhs;
828             if (!parseValueTerm(tokens, depth, &rhs))
829                 return false;
830             
831             result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
832
833             if (!result->value)
834                 return false;
835         }
836         
837         return true;
838     }
839     
840     bool parseAdditiveValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
841     {
842         if (checkDepthAndIndex(&depth, tokens) != OK)
843             return false;
844         
845         if (!parseValueMultiplicativeExpression(tokens, depth, result))
846             return false;
847         
848         while (!tokens.atEnd()) {
849             char operatorCharacter = operatorValue(tokens.peek());
850             if (operatorCharacter != static_cast<char>(CalcOperator::Add) && operatorCharacter != static_cast<char>(CalcOperator::Subtract))
851                 break;
852             if ((&tokens.peek() - 1)->type() != WhitespaceToken)
853                 return false; // calc(1px+ 2px) is invalid
854             tokens.consume();
855             if (tokens.peek().type() != WhitespaceToken)
856                 return false; // calc(1px +2px) is invalid
857             tokens.consumeIncludingWhitespace();
858             
859             Value rhs;
860             if (!parseValueMultiplicativeExpression(tokens, depth, &rhs))
861                 return false;
862             
863             result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
864             if (!result->value)
865                 return false;
866         }
867         
868         return true;
869     }
870
871     bool parseMinMaxExpression(CSSParserTokenRange& tokens, CSSValueID minMaxFunction, int depth, Value* result)
872     {
873         if (checkDepthAndIndex(&depth, tokens) != OK)
874             return false;
875
876         CalcOperator op = (minMaxFunction == CSSValueMin) ? CalcOperator::Min : CalcOperator::Max;
877
878         Value value;
879         if (!parseValueExpression(tokens, depth, &value))
880             return false;
881
882         Vector<Ref<CSSCalcExpressionNode>> nodes;
883         nodes.append(value.value.releaseNonNull());
884
885         while (!tokens.atEnd()) {
886             tokens.consumeWhitespace();
887             if (tokens.consume().type() != CommaToken)
888                 return false;
889             tokens.consumeWhitespace();
890
891             if (!parseValueExpression(tokens, depth, &value))
892                 return false;
893
894             nodes.append(value.value.releaseNonNull());
895         }
896
897         result->value = CSSCalcOperation::createMinOrMax(op, WTFMove(nodes), m_destinationCategory);
898         return result->value;
899     }
900
901     bool parseValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
902     {
903         return parseAdditiveValueExpression(tokens, depth, result);
904     }
905
906     CalculationCategory m_destinationCategory;
907 };
908
909 static inline RefPtr<CSSCalcOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress)
910 {
911     return CSSCalcOperation::create(CalcOperator::Multiply, createCSS(length, style),
912         CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), !progress || progress == 1));
913 }
914
915 static RefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode& node, const RenderStyle& style)
916 {
917     switch (node.type()) {
918     case CalcExpressionNodeType::Number: {
919         float value = toCalcExpressionNumber(node).value();
920         return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER), value == std::trunc(value));
921     }
922     case CalcExpressionNodeType::Length:
923         return createCSS(toCalcExpressionLength(node).length(), style);
924     case CalcExpressionNodeType::Operation: {
925         auto& operationNode = toCalcExpressionOperation(node);
926         auto& operationChildren = operationNode.children();
927         CalcOperator op = operationNode.getOperator();
928         if (op == CalcOperator::Min || op == CalcOperator::Max) {
929             Vector<Ref<CSSCalcExpressionNode>> values;
930             values.reserveInitialCapacity(operationChildren.size());
931             for (auto& child : operationChildren) {
932                 auto cssNode = createCSS(*child, style);
933                 if (!cssNode)
934                     return nullptr;
935                 values.uncheckedAppend(*cssNode);
936             }
937             return CSSCalcOperation::createMinOrMax(operationNode.getOperator(), WTFMove(values), CalculationCategory::Other);
938         }
939
940         if (operationChildren.size() == 2)
941             return CSSCalcOperation::create(operationNode.getOperator(), createCSS(*operationChildren[0], style), createCSS(*operationChildren[1], style));
942
943         return nullptr;
944     }
945     case CalcExpressionNodeType::BlendLength: {
946         // FIXME: (http://webkit.org/b/122036) Create a CSSCalcExpressionNode equivalent of CalcExpressionBlendLength.
947         auto& blend = toCalcExpressionBlendLength(node);
948         float progress = blend.progress();
949         return CSSCalcOperation::create(CalcOperator::Add, createBlendHalf(blend.from(), style, 1 - progress), createBlendHalf(blend.to(), style, progress));
950     }
951     case CalcExpressionNodeType::Undefined:
952         ASSERT_NOT_REACHED();
953     }
954     return nullptr;
955 }
956
957 static RefPtr<CSSCalcExpressionNode> createCSS(const Length& length, const RenderStyle& style)
958 {
959     switch (length.type()) {
960     case Percent:
961     case Fixed:
962         return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(length, style), length.value() == trunc(length.value()));
963     case Calculated:
964         return createCSS(length.calculationValue().expression(), style);
965     case Auto:
966     case Intrinsic:
967     case MinIntrinsic:
968     case MinContent:
969     case MaxContent:
970     case FillAvailable:
971     case FitContent:
972     case Relative:
973     case Undefined:
974         ASSERT_NOT_REACHED();
975     }
976     return nullptr;
977 }
978
979 RefPtr<CSSCalcValue> CSSCalcValue::create(CSSValueID function, const CSSParserTokenRange& tokens, CalculationCategory destinationCategory, ValueRange range)
980 {
981     CSSCalcExpressionNodeParser parser(destinationCategory);
982     auto expression = parser.parseCalc(tokens, function);
983     if (!expression)
984         return nullptr;
985     return adoptRef(new CSSCalcValue(expression.releaseNonNull(), range != ValueRangeAll));
986 }
987     
988 RefPtr<CSSCalcValue> CSSCalcValue::create(const CalculationValue& value, const RenderStyle& style)
989 {
990     auto expression = createCSS(value.expression(), style);
991     if (!expression)
992         return nullptr;
993     return adoptRef(new CSSCalcValue(expression.releaseNonNull(), value.shouldClampToNonNegative()));
994 }
995
996 } // namespace WebCore