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