5a9041d1c21a55a4a7b87a74b923277ef4198f3c
[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 "CSSPrimitiveValueMappings.h"
36 #include "StyleResolver.h"
37 #include <wtf/MathExtras.h>
38 #include <wtf/text/StringBuilder.h>
39
40 static const int maxExpressionDepth = 100;
41
42 enum ParseState {
43     OK,
44     TooDeep,
45     NoMoreTokens
46 };
47
48 namespace WebCore {
49
50 static PassRefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode&, const RenderStyle&);
51 static PassRefPtr<CSSCalcExpressionNode> createCSS(const Length&, const RenderStyle&);
52
53 static CalculationCategory unitCategory(CSSPrimitiveValue::UnitTypes type)
54 {
55     switch (type) {
56     case CSSPrimitiveValue::CSS_NUMBER:
57     case CSSPrimitiveValue::CSS_PARSER_INTEGER:
58         return CalcNumber;
59     case CSSPrimitiveValue::CSS_EMS:
60     case CSSPrimitiveValue::CSS_EXS:
61     case CSSPrimitiveValue::CSS_PX:
62     case CSSPrimitiveValue::CSS_CM:
63     case CSSPrimitiveValue::CSS_MM:
64     case CSSPrimitiveValue::CSS_IN:
65     case CSSPrimitiveValue::CSS_PT:
66     case CSSPrimitiveValue::CSS_PC:
67     case CSSPrimitiveValue::CSS_REMS:
68     case CSSPrimitiveValue::CSS_CHS:
69     case CSSPrimitiveValue::CSS_VW:
70     case CSSPrimitiveValue::CSS_VH:
71     case CSSPrimitiveValue::CSS_VMIN:
72     case CSSPrimitiveValue::CSS_VMAX:
73         return CalcLength;
74     case CSSPrimitiveValue::CSS_PERCENTAGE:
75         return CalcPercent;
76     case CSSPrimitiveValue::CSS_DEG:
77     case CSSPrimitiveValue::CSS_RAD:
78     case CSSPrimitiveValue::CSS_GRAD:
79     case CSSPrimitiveValue::CSS_TURN:
80         return CalcAngle;
81     case CSSPrimitiveValue::CSS_MS:
82     case CSSPrimitiveValue::CSS_S:
83         return CalcTime;
84     case CSSPrimitiveValue::CSS_HZ:
85     case CSSPrimitiveValue::CSS_KHZ:
86         return CalcFrequency;
87     default:
88         return CalcOther;
89     }
90 }
91
92 static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type)
93 {
94     switch (type) {
95     case CSSPrimitiveValue::CSS_FR:
96     case CSSPrimitiveValue::CSS_NUMBER:
97     case CSSPrimitiveValue::CSS_PARSER_INTEGER:
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_MS:
113     case CSSPrimitiveValue::CSS_S:
114     case CSSPrimitiveValue::CSS_HZ:
115     case CSSPrimitiveValue::CSS_KHZ:
116     case CSSPrimitiveValue::CSS_DIMENSION:
117     case CSSPrimitiveValue::CSS_VW:
118     case CSSPrimitiveValue::CSS_VH:
119     case CSSPrimitiveValue::CSS_VMIN:
120     case CSSPrimitiveValue::CSS_VMAX:
121     case CSSPrimitiveValue::CSS_DPPX:
122     case CSSPrimitiveValue::CSS_DPI:
123     case CSSPrimitiveValue::CSS_DPCM:
124         return true;
125     case CSSPrimitiveValue::CSS_UNKNOWN:
126     case CSSPrimitiveValue::CSS_STRING:
127     case CSSPrimitiveValue::CSS_URI:
128     case CSSPrimitiveValue::CSS_IDENT:
129     case CSSPrimitiveValue::CSS_ATTR:
130     case CSSPrimitiveValue::CSS_COUNTER:
131     case CSSPrimitiveValue::CSS_RECT:
132     case CSSPrimitiveValue::CSS_RGBCOLOR:
133     case CSSPrimitiveValue::CSS_PAIR:
134     case CSSPrimitiveValue::CSS_UNICODE_RANGE:
135     case CSSPrimitiveValue::CSS_PARSER_OPERATOR:
136     case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR:
137     case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER:
138     case CSSPrimitiveValue::CSS_TURN:
139     case CSSPrimitiveValue::CSS_COUNTER_NAME:
140     case CSSPrimitiveValue::CSS_SHAPE:
141     case CSSPrimitiveValue::CSS_QUAD:
142 #if ENABLE(CSS_SCROLL_SNAP)
143     case CSSPrimitiveValue::CSS_LENGTH_REPEAT:
144 #endif
145     case CSSPrimitiveValue::CSS_CALC:
146     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER:
147     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH:
148     case CSSPrimitiveValue::CSS_PROPERTY_ID:
149     case CSSPrimitiveValue::CSS_VALUE_ID:
150 #if ENABLE(DASHBOARD_SUPPORT)
151     case CSSPrimitiveValue::CSS_DASHBOARD_REGION:
152 #endif
153         return false;
154     };
155     ASSERT_NOT_REACHED();
156     return false;
157 }
158
159 static String buildCssText(const String& expression)
160 {
161     StringBuilder result;
162     result.appendLiteral("calc");
163     bool expressionHasSingleTerm = expression[0] != '(';
164     if (expressionHasSingleTerm)
165         result.append('(');
166     result.append(expression);
167     if (expressionHasSingleTerm)
168         result.append(')');
169     return result.toString();
170 }
171
172 String CSSCalcValue::customCSSText() const
173 {
174     return buildCssText(m_expression->customCSSText());
175 }
176
177 bool CSSCalcValue::equals(const CSSCalcValue& other) const
178 {
179     return compareCSSValue(m_expression, other.m_expression);
180 }
181
182 inline double CSSCalcValue::clampToPermittedRange(double value) const
183 {
184     return m_shouldClampToNonNegative && value < 0 ? 0 : value;
185 }
186
187 double CSSCalcValue::doubleValue() const
188 {
189     return clampToPermittedRange(m_expression->doubleValue());
190 }
191
192 double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const
193 {
194     return clampToPermittedRange(m_expression->computeLengthPx(conversionData));
195 }
196
197 class CSSCalcPrimitiveValue final : public CSSCalcExpressionNode {
198     WTF_MAKE_FAST_ALLOCATED;
199 public:
200     static PassRef<CSSCalcPrimitiveValue> create(PassRefPtr<CSSPrimitiveValue> value, bool isInteger)
201     {
202         return adoptRef(*new CSSCalcPrimitiveValue(value, isInteger));
203     }
204
205     static PassRefPtr<CSSCalcPrimitiveValue> create(double value, CSSPrimitiveValue::UnitTypes type, bool isInteger)
206     {
207         if (std::isnan(value) || std::isinf(value))
208             return nullptr;
209         return adoptRef(new CSSCalcPrimitiveValue(CSSPrimitiveValue::create(value, type), isInteger));
210     }
211
212 private:
213     virtual bool isZero() const override
214     {
215         return !m_value->getDoubleValue();
216     }
217
218     virtual String customCSSText() const override
219     {
220         return m_value->cssText();
221     }
222
223     virtual std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const override
224     {
225         switch (category()) {
226         case CalcNumber:
227             return std::make_unique<CalcExpressionNumber>(m_value->getFloatValue());
228         case CalcLength:
229             return std::make_unique<CalcExpressionLength>(Length(m_value->computeLength<float>(conversionData), WebCore::Fixed));
230         case CalcPercent:
231         case CalcPercentLength: {
232             CSSPrimitiveValue* primitiveValue = m_value.get();
233             return std::make_unique<CalcExpressionLength>(primitiveValue
234                 ? primitiveValue->convertToLength<FixedFloatConversion | PercentConversion>(conversionData) : Length(Undefined));
235         }
236         // Only types that could be part of a Length expression can be converted
237         // to a CalcExpressionNode. CalcPercentNumber makes no sense as a Length.
238         case CalcPercentNumber:
239         case CalcAngle:
240         case CalcTime:
241         case CalcFrequency:
242         case CalcOther:
243             ASSERT_NOT_REACHED();
244         }
245         return nullptr;
246     }
247
248     virtual double doubleValue() const override
249     {
250         if (hasDoubleValue(primitiveType()))
251             return m_value->getDoubleValue();
252         ASSERT_NOT_REACHED();
253         return 0;
254     }
255
256     virtual double computeLengthPx(const CSSToLengthConversionData& conversionData) const override
257     {
258         switch (category()) {
259         case CalcLength:
260             return m_value->computeLength<double>(conversionData);
261         case CalcPercent:
262         case CalcNumber:
263             return m_value->getDoubleValue();
264         case CalcPercentLength:
265         case CalcPercentNumber:
266         case CalcAngle:
267         case CalcTime:
268         case CalcFrequency:
269         case CalcOther:
270             ASSERT_NOT_REACHED();
271             break;
272         }
273         ASSERT_NOT_REACHED();
274         return 0;
275     }
276
277     virtual bool equals(const CSSCalcExpressionNode& other) const override
278     {
279         if (type() != other.type())
280             return false;
281
282         return compareCSSValuePtr(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value);
283     }
284
285     virtual Type type() const override { return CssCalcPrimitiveValue; }
286     virtual CSSPrimitiveValue::UnitTypes primitiveType() const override
287     {
288         return CSSPrimitiveValue::UnitTypes(m_value->primitiveType());
289     }
290
291 private:
292     explicit CSSCalcPrimitiveValue(PassRefPtr<CSSPrimitiveValue> value, bool isInteger)
293         : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitTypes)value->primitiveType()), isInteger)
294         , m_value(value)
295     {
296     }
297
298     RefPtr<CSSPrimitiveValue> m_value;
299 };
300
301 static const CalculationCategory addSubtractResult[CalcAngle][CalcAngle] = {
302 //    CalcNumber         CalcLength         CalcPercent        CalcPercentNumber  CalcPercentLength
303     { CalcNumber,        CalcOther,         CalcPercentNumber, CalcPercentNumber, CalcOther }, //         CalcNumber
304     { CalcOther,         CalcLength,        CalcPercentLength, CalcOther,         CalcPercentLength }, // CalcLength
305     { CalcPercentNumber, CalcPercentLength, CalcPercent,       CalcPercentNumber, CalcPercentLength }, // CalcPercent
306     { CalcPercentNumber, CalcOther,         CalcPercentNumber, CalcPercentNumber, CalcOther }, //         CalcPercentNumber
307     { CalcOther,         CalcPercentLength, CalcPercentLength, CalcOther,         CalcPercentLength }, // CalcPercentLength
308 };
309
310 static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide, CalcOperator op)
311 {
312     CalculationCategory leftCategory = leftSide.category();
313     CalculationCategory rightCategory = rightSide.category();
314
315     if (leftCategory == CalcOther || rightCategory == CalcOther)
316         return CalcOther;
317
318     switch (op) {
319     case CalcAdd:
320     case CalcSubtract:
321         if (leftCategory < CalcAngle || rightCategory < CalcAngle)
322             return addSubtractResult[leftCategory][rightCategory];
323         if (leftCategory == rightCategory)
324             return leftCategory;
325         return CalcOther;
326     case CalcMultiply:
327         if (leftCategory != CalcNumber && rightCategory != CalcNumber)
328             return CalcOther;
329         return leftCategory == CalcNumber ? rightCategory : leftCategory;
330     case CalcDivide:
331         if (rightCategory != CalcNumber || rightSide.isZero())
332             return CalcOther;
333         return leftCategory;
334     }
335
336     ASSERT_NOT_REACHED();
337     return CalcOther;
338 }
339
340 static inline bool isIntegerResult(CalcOperator op, const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide)
341 {
342     // Performs W3C spec's type checking for calc integers.
343     // http://www.w3.org/TR/css3-values/#calc-type-checking
344     return op != CalcDivide && leftSide.isInteger() && rightSide.isInteger();
345 }
346
347 class CSSCalcBinaryOperation final : public CSSCalcExpressionNode {
348     WTF_MAKE_FAST_ALLOCATED;
349 public:
350     static PassRefPtr<CSSCalcBinaryOperation> create(CalcOperator op, PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide)
351     {
352         ASSERT(leftSide->category() != CalcOther && rightSide->category() != CalcOther);
353
354         CalculationCategory newCategory = determineCategory(*leftSide, *rightSide, op);
355
356         if (newCategory == CalcOther)
357             return nullptr;
358
359         return adoptRef(new CSSCalcBinaryOperation(newCategory, op, leftSide, rightSide));
360     }
361
362     static PassRefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator op, PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide)
363     {
364         CalculationCategory leftCategory = leftSide->category();
365         CalculationCategory rightCategory = rightSide->category();
366         ASSERT(leftCategory != CalcOther && rightCategory != CalcOther);
367
368         bool isInteger = isIntegerResult(op, *leftSide, *rightSide);
369
370         // Simplify numbers.
371         if (leftCategory == CalcNumber && rightCategory == CalcNumber) {
372             CSSPrimitiveValue::UnitTypes evaluationType = isInteger ? CSSPrimitiveValue::CSS_PARSER_INTEGER : CSSPrimitiveValue::CSS_NUMBER;
373             return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftSide->doubleValue(), rightSide->doubleValue()), evaluationType, isInteger);
374         }
375
376         // Simplify addition and subtraction between same types.
377         if (op == CalcAdd || op == CalcSubtract) {
378             if (leftCategory == rightSide->category()) {
379                 CSSPrimitiveValue::UnitTypes leftType = leftSide->primitiveType();
380                 if (hasDoubleValue(leftType)) {
381                     CSSPrimitiveValue::UnitTypes rightType = rightSide->primitiveType();
382                     if (leftType == rightType)
383                         return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftSide->doubleValue(), rightSide->doubleValue()), leftType, isInteger);
384                     CSSPrimitiveValue::UnitCategory leftUnitCategory = CSSPrimitiveValue::unitCategory(leftType);
385                     if (leftUnitCategory != CSSPrimitiveValue::UOther && leftUnitCategory == CSSPrimitiveValue::unitCategory(rightType)) {
386                         CSSPrimitiveValue::UnitTypes canonicalType = CSSPrimitiveValue::canonicalUnitTypeForCategory(leftUnitCategory);
387                         if (canonicalType != CSSPrimitiveValue::CSS_UNKNOWN) {
388                             double leftValue = leftSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(leftType);
389                             double rightValue = rightSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(rightType);
390                             return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftValue, rightValue), canonicalType, isInteger);
391                         }
392                     }
393                 }
394             }
395         } else {
396             // Simplify multiplying or dividing by a number for simplifiable types.
397             ASSERT(op == CalcMultiply || op == CalcDivide);
398             CSSCalcExpressionNode* numberSide = getNumberSide(*leftSide, *rightSide);
399             if (!numberSide)
400                 return create(op, leftSide, rightSide);
401             if (numberSide == leftSide && op == CalcDivide)
402                 return nullptr;
403             CSSCalcExpressionNode* otherSide = leftSide == numberSide ? rightSide.get() : leftSide.get();
404
405             double number = numberSide->doubleValue();
406             if (std::isnan(number) || std::isinf(number))
407                 return nullptr;
408             if (op == CalcDivide && !number)
409                 return nullptr;
410
411             CSSPrimitiveValue::UnitTypes otherType = otherSide->primitiveType();
412             if (hasDoubleValue(otherType))
413                 return CSSCalcPrimitiveValue::create(evaluateOperator(op, otherSide->doubleValue(), number), otherType, isInteger);
414         }
415
416         return create(op, leftSide, rightSide);
417     }
418
419 private:
420     virtual bool isZero() const override
421     {
422         return !doubleValue();
423     }
424
425     virtual std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const override
426     {
427         std::unique_ptr<CalcExpressionNode> left(m_leftSide->createCalcExpression(conversionData));
428         if (!left)
429             return nullptr;
430         std::unique_ptr<CalcExpressionNode> right(m_rightSide->createCalcExpression(conversionData));
431         if (!right)
432             return nullptr;
433         return std::make_unique<CalcExpressionBinaryOperation>(WTF::move(left), WTF::move(right), m_operator);
434     }
435
436     virtual double doubleValue() const override
437     {
438         return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue());
439     }
440
441     virtual double computeLengthPx(const CSSToLengthConversionData& conversionData) const override
442     {
443         const double leftValue = m_leftSide->computeLengthPx(conversionData);
444         const double rightValue = m_rightSide->computeLengthPx(conversionData);
445         return evaluate(leftValue, rightValue);
446     }
447
448     static String buildCssText(const String& leftExpression, const String& rightExpression, CalcOperator op)
449     {
450         StringBuilder result;
451         result.append('(');
452         result.append(leftExpression);
453         result.append(' ');
454         result.append(static_cast<char>(op));
455         result.append(' ');
456         result.append(rightExpression);
457         result.append(')');
458
459         return result.toString();
460     }
461
462     virtual String customCSSText() const override
463     {
464         return buildCssText(m_leftSide->customCSSText(), m_rightSide->customCSSText(), m_operator);
465     }
466
467     virtual bool equals(const CSSCalcExpressionNode& exp) const override
468     {
469         if (type() != exp.type())
470             return false;
471
472         const CSSCalcBinaryOperation& other = static_cast<const CSSCalcBinaryOperation&>(exp);
473         return compareCSSValuePtr(m_leftSide, other.m_leftSide)
474             && compareCSSValuePtr(m_rightSide, other.m_rightSide)
475             && m_operator == other.m_operator;
476     }
477
478     virtual Type type() const override { return CssCalcBinaryOperation; }
479
480     virtual CSSPrimitiveValue::UnitTypes primitiveType() const override
481     {
482         switch (category()) {
483         case CalcNumber:
484             ASSERT(m_leftSide->category() == CalcNumber && m_rightSide->category() == CalcNumber);
485             if (isInteger())
486                 return CSSPrimitiveValue::CSS_PARSER_INTEGER;
487             return CSSPrimitiveValue::CSS_NUMBER;
488         case CalcLength:
489         case CalcPercent: {
490             if (m_leftSide->category() == CalcNumber)
491                 return m_rightSide->primitiveType();
492             if (m_rightSide->category() == CalcNumber)
493                 return m_leftSide->primitiveType();
494             CSSPrimitiveValue::UnitTypes leftType = m_leftSide->primitiveType();
495             if (leftType == m_rightSide->primitiveType())
496                 return leftType;
497             return CSSPrimitiveValue::CSS_UNKNOWN;
498         }
499         case CalcAngle:
500             return CSSPrimitiveValue::CSS_DEG;
501         case CalcTime:
502             return CSSPrimitiveValue::CSS_MS;
503         case CalcFrequency:
504             return CSSPrimitiveValue::CSS_HZ;
505         case CalcPercentLength:
506         case CalcPercentNumber:
507         case CalcOther:
508             return CSSPrimitiveValue::CSS_UNKNOWN;
509         }
510         ASSERT_NOT_REACHED();
511         return CSSPrimitiveValue::CSS_UNKNOWN;
512     }
513
514     CSSCalcBinaryOperation(CalculationCategory category, CalcOperator op, PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide)
515         : CSSCalcExpressionNode(category, isIntegerResult(op, *leftSide, *rightSide))
516         , m_leftSide(leftSide)
517         , m_rightSide(rightSide)
518         , m_operator(op)
519     {
520     }
521
522     static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide)
523     {
524         if (leftSide.category() == CalcNumber)
525             return &leftSide;
526         if (rightSide.category() == CalcNumber)
527             return &rightSide;
528         return nullptr;
529     }
530
531     double evaluate(double leftSide, double rightSide) const
532     {
533         return evaluateOperator(m_operator, leftSide, rightSide);
534     }
535
536     static double evaluateOperator(CalcOperator op, double leftValue, double rightValue)
537     {
538         switch (op) {
539         case CalcAdd:
540             return leftValue + rightValue;
541         case CalcSubtract:
542             return leftValue - rightValue;
543         case CalcMultiply:
544             return leftValue * rightValue;
545         case CalcDivide:
546             if (rightValue)
547                 return leftValue / rightValue;
548             return std::numeric_limits<double>::quiet_NaN();
549         }
550         ASSERT_NOT_REACHED();
551         return 0;
552     }
553
554     const RefPtr<CSSCalcExpressionNode> m_leftSide;
555     const RefPtr<CSSCalcExpressionNode> m_rightSide;
556     const CalcOperator m_operator;
557 };
558
559 static ParseState checkDepthAndIndex(int* depth, unsigned index, CSSParserValueList* tokens)
560 {
561     (*depth)++;
562     if (*depth > maxExpressionDepth)
563         return TooDeep;
564     if (index >= tokens->size())
565         return NoMoreTokens;
566     return OK;
567 }
568
569 class CSSCalcExpressionNodeParser {
570 public:
571     PassRefPtr<CSSCalcExpressionNode> parseCalc(CSSParserValueList* tokens)
572     {
573         unsigned index = 0;
574         Value result;
575         bool ok = parseValueExpression(tokens, 0, &index, &result);
576         ASSERT_WITH_SECURITY_IMPLICATION(index <= tokens->size());
577         if (!ok || index != tokens->size())
578             return nullptr;
579         return result.value;
580     }
581
582 private:
583     struct Value {
584         RefPtr<CSSCalcExpressionNode> value;
585     };
586
587     char operatorValue(CSSParserValueList* tokens, unsigned index)
588     {
589         if (index >= tokens->size())
590             return 0;
591         CSSParserValue* value = tokens->valueAt(index);
592         if (value->unit != CSSParserValue::Operator)
593             return 0;
594
595         return value->iValue;
596     }
597
598     bool parseValue(CSSParserValueList* tokens, unsigned* index, Value* result)
599     {
600         CSSParserValue* parserValue = tokens->valueAt(*index);
601         if (parserValue->unit == CSSParserValue::Operator || parserValue->unit == CSSParserValue::Function)
602             return false;
603
604         RefPtr<CSSValue> value = parserValue->createCSSValue();
605         if (!is<CSSPrimitiveValue>(value.get()))
606             return false;
607
608         CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(*value);
609         result->value = CSSCalcPrimitiveValue::create(&primitiveValue, parserValue->isInt);
610
611         ++*index;
612         return true;
613     }
614
615     bool parseValueTerm(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
616     {
617         if (checkDepthAndIndex(&depth, *index, tokens) != OK)
618             return false;
619
620         if (operatorValue(tokens, *index) == '(') {
621             unsigned currentIndex = *index + 1;
622             if (!parseValueExpression(tokens, depth, &currentIndex, result))
623                 return false;
624
625             if (operatorValue(tokens, currentIndex) != ')')
626                 return false;
627             *index = currentIndex + 1;
628             return true;
629         }
630
631         return parseValue(tokens, index, result);
632     }
633
634     bool parseValueMultiplicativeExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
635     {
636         if (checkDepthAndIndex(&depth, *index, tokens) != OK)
637             return false;
638
639         if (!parseValueTerm(tokens, depth, index, result))
640             return false;
641
642         while (*index < tokens->size() - 1) {
643             char operatorCharacter = operatorValue(tokens, *index);
644             if (operatorCharacter != CalcMultiply && operatorCharacter != CalcDivide)
645                 break;
646             ++*index;
647
648             Value rhs;
649             if (!parseValueTerm(tokens, depth, index, &rhs))
650                 return false;
651
652             result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), result->value, rhs.value);
653             if (!result->value)
654                 return false;
655         }
656
657         ASSERT_WITH_SECURITY_IMPLICATION(*index <= tokens->size());
658         return true;
659     }
660
661     bool parseAdditiveValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
662     {
663         if (checkDepthAndIndex(&depth, *index, tokens) != OK)
664             return false;
665
666         if (!parseValueMultiplicativeExpression(tokens, depth, index, result))
667             return false;
668
669         while (*index < tokens->size() - 1) {
670             char operatorCharacter = operatorValue(tokens, *index);
671             if (operatorCharacter != CalcAdd && operatorCharacter != CalcSubtract)
672                 break;
673             ++*index;
674
675             Value rhs;
676             if (!parseValueMultiplicativeExpression(tokens, depth, index, &rhs))
677                 return false;
678
679             result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), result->value, rhs.value);
680             if (!result->value)
681                 return false;
682         }
683
684         ASSERT_WITH_SECURITY_IMPLICATION(*index <= tokens->size());
685         return true;
686     }
687
688     bool parseValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
689     {
690         return parseAdditiveValueExpression(tokens, depth, index, result);
691     }
692 };
693
694 static inline PassRefPtr<CSSCalcBinaryOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress)
695 {
696     return CSSCalcBinaryOperation::create(CalcMultiply, createCSS(length, style),
697         CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), !progress || progress == 1));
698 }
699
700 static PassRefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode& node, const RenderStyle& style)
701 {
702     switch (node.type()) {
703     case CalcExpressionNodeNumber: {
704         float value = toCalcExpressionNumber(node).value();
705         return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER), value == truncf(value));
706     }
707     case CalcExpressionNodeLength:
708         return createCSS(toCalcExpressionLength(node).length(), style);
709     case CalcExpressionNodeBinaryOperation: {
710         auto& binaryNode = toCalcExpressionBinaryOperation(node);
711         return CSSCalcBinaryOperation::create(binaryNode.getOperator(), createCSS(binaryNode.leftSide(), style), createCSS(binaryNode.rightSide(), style));
712     }
713     case CalcExpressionNodeBlendLength: {
714         // FIXME: (http://webkit.org/b/122036) Create a CSSCalcExpressionNode equivalent of CalcExpressionBlendLength.
715         auto& blend = toCalcExpressionBlendLength(node);
716         float progress = blend.progress();
717         return CSSCalcBinaryOperation::create(CalcAdd, createBlendHalf(blend.from(), style, 1 - progress), createBlendHalf(blend.to(), style, progress));
718     }
719     case CalcExpressionNodeUndefined:
720         ASSERT_NOT_REACHED();
721         return nullptr;
722     }
723     ASSERT_NOT_REACHED();
724     return nullptr;
725 }
726
727 static PassRefPtr<CSSCalcExpressionNode> createCSS(const Length& length, const RenderStyle& style)
728 {
729     switch (length.type()) {
730     case Percent:
731     case Fixed:
732         return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(length, &style), length.value() == trunc(length.value()));
733     case Calculated:
734         return createCSS(length.calculationValue().expression(), style);
735     case Auto:
736     case Intrinsic:
737     case MinIntrinsic:
738     case MinContent:
739     case MaxContent:
740     case FillAvailable:
741     case FitContent:
742     case Relative:
743     case Undefined:
744         ASSERT_NOT_REACHED();
745         return nullptr;
746     }
747     ASSERT_NOT_REACHED();
748     return nullptr;
749 }
750
751 PassRefPtr<CSSCalcValue> CSSCalcValue::create(CSSParserString name, CSSParserValueList& parserValueList, CalculationPermittedValueRange range)
752 {
753     CSSCalcExpressionNodeParser parser;
754     RefPtr<CSSCalcExpressionNode> expression;
755
756     if (equalIgnoringCase(name, "calc(") || equalIgnoringCase(name, "-webkit-calc("))
757         expression = parser.parseCalc(&parserValueList);
758     // FIXME: calc (http://webkit.org/b/16662) Add parsing for min and max here
759
760     return expression ? adoptRef(new CSSCalcValue(expression.releaseNonNull(), range != CalculationRangeAll)) : nullptr;
761 }
762
763 PassRefPtr<CSSCalcValue> CSSCalcValue::create(const CalculationValue& value, const RenderStyle& style)
764 {
765     RefPtr<CSSCalcExpressionNode> expression = createCSS(value.expression(), style);
766     if (!expression)
767         return nullptr;
768     return adoptRef(new CSSCalcValue(expression.releaseNonNull(), value.shouldClampToNonNegative()));
769 }
770
771 } // namespace WebCore