Remove PassRefPtr use from the "css" directory, related cleanup
[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 CalcNumber;
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 CalcLength;
75     case CSSPrimitiveValue::CSS_PERCENTAGE:
76         return CalcPercent;
77     case CSSPrimitiveValue::CSS_DEG:
78     case CSSPrimitiveValue::CSS_RAD:
79     case CSSPrimitiveValue::CSS_GRAD:
80     case CSSPrimitiveValue::CSS_TURN:
81         return CalcAngle;
82     case CSSPrimitiveValue::CSS_MS:
83     case CSSPrimitiveValue::CSS_S:
84         return CalcTime;
85     case CSSPrimitiveValue::CSS_HZ:
86     case CSSPrimitiveValue::CSS_KHZ:
87         return CalcFrequency;
88     default:
89         return CalcOther;
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 CalcNumber:
223             return std::make_unique<CalcExpressionNumber>(m_value->floatValue());
224         case CalcLength:
225             return std::make_unique<CalcExpressionLength>(Length(m_value->computeLength<float>(conversionData), WebCore::Fixed));
226         case CalcPercent:
227         case CalcPercentLength: {
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. CalcPercentNumber makes no sense as a Length.
232         case CalcPercentNumber:
233         case CalcAngle:
234         case CalcTime:
235         case CalcFrequency:
236         case CalcOther:
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 CalcLength:
255             return m_value->computeLength<double>(conversionData);
256         case CalcPercent:
257         case CalcNumber:
258             return m_value->doubleValue();
259         case CalcPercentLength:
260         case CalcPercentNumber:
261         case CalcAngle:
262         case CalcTime:
263         case CalcFrequency:
264         case CalcOther:
265             ASSERT_NOT_REACHED();
266             break;
267         }
268         ASSERT_NOT_REACHED();
269         return 0;
270     }
271
272     bool equals(const CSSCalcExpressionNode& other) const final
273     {
274         if (type() != other.type())
275             return false;
276
277         return compareCSSValue(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value);
278     }
279
280     Type type() const final { return CssCalcPrimitiveValue; }
281     CSSPrimitiveValue::UnitType primitiveType() const final
282     {
283         return CSSPrimitiveValue::UnitType(m_value->primitiveType());
284     }
285
286 private:
287     explicit CSSCalcPrimitiveValue(Ref<CSSPrimitiveValue>&& value, bool isInteger)
288         : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitType)value->primitiveType()), isInteger)
289         , m_value(WTFMove(value))
290     {
291     }
292
293     Ref<CSSPrimitiveValue> m_value;
294 };
295
296 static const CalculationCategory addSubtractResult[CalcAngle][CalcAngle] = {
297 //    CalcNumber         CalcLength         CalcPercent        CalcPercentNumber  CalcPercentLength
298     { CalcNumber,        CalcOther,         CalcPercentNumber, CalcPercentNumber, CalcOther }, //         CalcNumber
299     { CalcOther,         CalcLength,        CalcPercentLength, CalcOther,         CalcPercentLength }, // CalcLength
300     { CalcPercentNumber, CalcPercentLength, CalcPercent,       CalcPercentNumber, CalcPercentLength }, // CalcPercent
301     { CalcPercentNumber, CalcOther,         CalcPercentNumber, CalcPercentNumber, CalcOther }, //         CalcPercentNumber
302     { CalcOther,         CalcPercentLength, CalcPercentLength, CalcOther,         CalcPercentLength }, // CalcPercentLength
303 };
304
305 static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide, CalcOperator op)
306 {
307     CalculationCategory leftCategory = leftSide.category();
308     CalculationCategory rightCategory = rightSide.category();
309     ASSERT(leftCategory < CalcOther);
310     ASSERT(rightCategory < CalcOther);
311
312     switch (op) {
313     case CalcAdd:
314     case CalcSubtract:
315         if (leftCategory < CalcAngle && rightCategory < CalcAngle)
316             return addSubtractResult[leftCategory][rightCategory];
317         if (leftCategory == rightCategory)
318             return leftCategory;
319         return CalcOther;
320     case CalcMultiply:
321         if (leftCategory != CalcNumber && rightCategory != CalcNumber)
322             return CalcOther;
323         return leftCategory == CalcNumber ? rightCategory : leftCategory;
324     case CalcDivide:
325         if (rightCategory != CalcNumber || rightSide.isZero())
326             return CalcOther;
327         return leftCategory;
328     }
329
330     ASSERT_NOT_REACHED();
331     return CalcOther;
332 }
333
334 static inline bool isIntegerResult(CalcOperator op, const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide)
335 {
336     // Performs W3C spec's type checking for calc integers.
337     // http://www.w3.org/TR/css3-values/#calc-type-checking
338     return op != CalcDivide && leftSide.isInteger() && rightSide.isInteger();
339 }
340
341 class CSSCalcBinaryOperation final : public CSSCalcExpressionNode {
342     WTF_MAKE_FAST_ALLOCATED;
343 public:
344     static RefPtr<CSSCalcBinaryOperation> create(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
345     {
346         if (!leftSide || !rightSide)
347             return nullptr;
348
349         ASSERT(leftSide->category() < CalcOther);
350         ASSERT(rightSide->category() < CalcOther);
351
352         auto newCategory = determineCategory(*leftSide, *rightSide, op);
353         if (newCategory == CalcOther)
354             return nullptr;
355         return adoptRef(new CSSCalcBinaryOperation(newCategory, op, leftSide.releaseNonNull(), rightSide.releaseNonNull()));
356     }
357
358     static RefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
359     {
360         if (!leftSide || !rightSide)
361             return nullptr;
362
363         auto leftCategory = leftSide->category();
364         auto rightCategory = rightSide->category();
365         ASSERT(leftCategory < CalcOther);
366         ASSERT(rightCategory < CalcOther);
367
368         bool isInteger = isIntegerResult(op, *leftSide, *rightSide);
369
370         // Simplify numbers.
371         if (leftCategory == CalcNumber && rightCategory == CalcNumber) {
372             CSSPrimitiveValue::UnitType evaluationType = 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::UnitType leftType = leftSide->primitiveType();
380                 if (hasDoubleValue(leftType)) {
381                     CSSPrimitiveValue::UnitType 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::UnitType 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             auto* numberSide = getNumberSide(*leftSide, *rightSide);
399             if (!numberSide)
400                 return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
401             if (numberSide == leftSide && op == CalcDivide)
402                 return nullptr;
403             auto& otherSide = leftSide == numberSide ? *rightSide : *leftSide;
404
405             double number = numberSide->doubleValue();
406             if (!std::isfinite(number))
407                 return nullptr;
408             if (op == CalcDivide && !number)
409                 return nullptr;
410
411             auto 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.releaseNonNull(), rightSide.releaseNonNull());
417     }
418
419 private:
420     bool isZero() const final
421     {
422         return !doubleValue();
423     }
424
425     std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final
426     {
427         auto left = m_leftSide->createCalcExpression(conversionData);
428         if (!left)
429             return nullptr;
430         auto right = m_rightSide->createCalcExpression(conversionData);
431         if (!right)
432             return nullptr;
433         return std::make_unique<CalcExpressionBinaryOperation>(WTFMove(left), WTFMove(right), m_operator);
434     }
435
436     double doubleValue() const final
437     {
438         return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue());
439     }
440
441     double computeLengthPx(const CSSToLengthConversionData& conversionData) const final
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     String customCSSText() const final
463     {
464         return buildCssText(m_leftSide->customCSSText(), m_rightSide->customCSSText(), m_operator);
465     }
466
467     bool equals(const CSSCalcExpressionNode& exp) const final
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     Type type() const final { return CssCalcBinaryOperation; }
479
480     CSSPrimitiveValue::UnitType primitiveType() const final
481     {
482         switch (category()) {
483         case CalcNumber:
484             ASSERT(m_leftSide->category() == CalcNumber && m_rightSide->category() == CalcNumber);
485             return CSSPrimitiveValue::CSS_NUMBER;
486         case CalcLength:
487         case CalcPercent: {
488             if (m_leftSide->category() == CalcNumber)
489                 return m_rightSide->primitiveType();
490             if (m_rightSide->category() == CalcNumber)
491                 return m_leftSide->primitiveType();
492             CSSPrimitiveValue::UnitType leftType = m_leftSide->primitiveType();
493             if (leftType == m_rightSide->primitiveType())
494                 return leftType;
495             return CSSPrimitiveValue::CSS_UNKNOWN;
496         }
497         case CalcAngle:
498             return CSSPrimitiveValue::CSS_DEG;
499         case CalcTime:
500             return CSSPrimitiveValue::CSS_MS;
501         case CalcFrequency:
502             return CSSPrimitiveValue::CSS_HZ;
503         case CalcPercentLength:
504         case CalcPercentNumber:
505         case CalcOther:
506             return CSSPrimitiveValue::CSS_UNKNOWN;
507         }
508         ASSERT_NOT_REACHED();
509         return CSSPrimitiveValue::CSS_UNKNOWN;
510     }
511
512     CSSCalcBinaryOperation(CalculationCategory category, CalcOperator op, Ref<CSSCalcExpressionNode>&& leftSide, Ref<CSSCalcExpressionNode>&& rightSide)
513         : CSSCalcExpressionNode(category, isIntegerResult(op, leftSide.get(), rightSide.get()))
514         , m_leftSide(WTFMove(leftSide))
515         , m_rightSide(WTFMove(rightSide))
516         , m_operator(op)
517     {
518     }
519
520     static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide)
521     {
522         if (leftSide.category() == CalcNumber)
523             return &leftSide;
524         if (rightSide.category() == CalcNumber)
525             return &rightSide;
526         return nullptr;
527     }
528
529     double evaluate(double leftSide, double rightSide) const
530     {
531         return evaluateOperator(m_operator, leftSide, rightSide);
532     }
533
534     static double evaluateOperator(CalcOperator op, double leftValue, double rightValue)
535     {
536         switch (op) {
537         case CalcAdd:
538             return leftValue + rightValue;
539         case CalcSubtract:
540             return leftValue - rightValue;
541         case CalcMultiply:
542             return leftValue * rightValue;
543         case CalcDivide:
544             if (rightValue)
545                 return leftValue / rightValue;
546             return std::numeric_limits<double>::quiet_NaN();
547         }
548         ASSERT_NOT_REACHED();
549         return 0;
550     }
551
552     const RefPtr<CSSCalcExpressionNode> m_leftSide;
553     const RefPtr<CSSCalcExpressionNode> m_rightSide;
554     const CalcOperator m_operator;
555 };
556
557 static ParseState checkDepthAndIndex(int* depth, CSSParserTokenRange tokens)
558 {
559     (*depth)++;
560     if (tokens.atEnd())
561         return NoMoreTokens;
562     if (*depth > maxExpressionDepth)
563         return TooDeep;
564     return OK;
565 }
566
567 class CSSCalcExpressionNodeParser {
568 public:
569     RefPtr<CSSCalcExpressionNode> parseCalc(CSSParserTokenRange tokens)
570     {
571         Value result;
572         tokens.consumeWhitespace();
573         bool ok = parseValueExpression(tokens, 0, &result);
574         if (!ok || !tokens.atEnd())
575             return nullptr;
576         return result.value;
577     }
578     
579 private:
580     struct Value {
581         RefPtr<CSSCalcExpressionNode> value;
582     };
583     
584     char operatorValue(const CSSParserToken& token)
585     {
586         if (token.type() == DelimiterToken)
587             return token.delimiter();
588         return 0;
589     }
590     
591     bool parseValue(CSSParserTokenRange& tokens, Value* result)
592     {
593         CSSParserToken token = tokens.consumeIncludingWhitespace();
594         if (!(token.type() == NumberToken || token.type() == PercentageToken || token.type() == DimensionToken))
595             return false;
596         
597         CSSPrimitiveValue::UnitType type = token.unitType();
598         if (unitCategory(type) == CalcOther)
599             return false;
600         
601         result->value = CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(token.numericValue(), type), token.numericValueType() == IntegerValueType);
602         
603         return true;
604     }
605     
606     bool parseValueTerm(CSSParserTokenRange& tokens, int depth, Value* result)
607     {
608         if (checkDepthAndIndex(&depth, tokens) != OK)
609             return false;
610         
611         if (tokens.peek().type() == LeftParenthesisToken || tokens.peek().functionId() == CSSValueCalc) {
612             CSSParserTokenRange innerRange = tokens.consumeBlock();
613             tokens.consumeWhitespace();
614             innerRange.consumeWhitespace();
615             return parseValueExpression(innerRange, depth, result);
616         }
617         
618         return parseValue(tokens, result);
619     }
620     
621     bool parseValueMultiplicativeExpression(CSSParserTokenRange& tokens, int depth, Value* result)
622     {
623         if (checkDepthAndIndex(&depth, tokens) != OK)
624             return false;
625         
626         if (!parseValueTerm(tokens, depth, result))
627             return false;
628         
629         while (!tokens.atEnd()) {
630             char operatorCharacter = operatorValue(tokens.peek());
631             if (operatorCharacter != CalcMultiply && operatorCharacter != CalcDivide)
632                 break;
633             tokens.consumeIncludingWhitespace();
634             
635             Value rhs;
636             if (!parseValueTerm(tokens, depth, &rhs))
637                 return false;
638             
639             result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
640
641             if (!result->value)
642                 return false;
643         }
644         
645         return true;
646     }
647     
648     bool parseAdditiveValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
649     {
650         if (checkDepthAndIndex(&depth, tokens) != OK)
651             return false;
652         
653         if (!parseValueMultiplicativeExpression(tokens, depth, result))
654             return false;
655         
656         while (!tokens.atEnd()) {
657             char operatorCharacter = operatorValue(tokens.peek());
658             if (operatorCharacter != CalcAdd && operatorCharacter != CalcSubtract)
659                 break;
660             if ((&tokens.peek() - 1)->type() != WhitespaceToken)
661                 return false; // calc(1px+ 2px) is invalid
662             tokens.consume();
663             if (tokens.peek().type() != WhitespaceToken)
664                 return false; // calc(1px +2px) is invalid
665             tokens.consumeIncludingWhitespace();
666             
667             Value rhs;
668             if (!parseValueMultiplicativeExpression(tokens, depth, &rhs))
669                 return false;
670             
671             result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
672             if (!result->value)
673                 return false;
674         }
675         
676         return true;
677     }
678     
679     bool parseValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
680     {
681         return parseAdditiveValueExpression(tokens, depth, result);
682     }
683 };
684
685 static inline RefPtr<CSSCalcBinaryOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress)
686 {
687     return CSSCalcBinaryOperation::create(CalcMultiply, createCSS(length, style),
688         CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), !progress || progress == 1));
689 }
690
691 static RefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode& node, const RenderStyle& style)
692 {
693     switch (node.type()) {
694     case CalcExpressionNodeNumber: {
695         float value = toCalcExpressionNumber(node).value();
696         return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER), value == std::trunc(value));
697     }
698     case CalcExpressionNodeLength:
699         return createCSS(toCalcExpressionLength(node).length(), style);
700     case CalcExpressionNodeBinaryOperation: {
701         auto& binaryNode = toCalcExpressionBinaryOperation(node);
702         return CSSCalcBinaryOperation::create(binaryNode.getOperator(), createCSS(binaryNode.leftSide(), style), createCSS(binaryNode.rightSide(), style));
703     }
704     case CalcExpressionNodeBlendLength: {
705         // FIXME: (http://webkit.org/b/122036) Create a CSSCalcExpressionNode equivalent of CalcExpressionBlendLength.
706         auto& blend = toCalcExpressionBlendLength(node);
707         float progress = blend.progress();
708         return CSSCalcBinaryOperation::create(CalcAdd, createBlendHalf(blend.from(), style, 1 - progress), createBlendHalf(blend.to(), style, progress));
709     }
710     case CalcExpressionNodeUndefined:
711         ASSERT_NOT_REACHED();
712     }
713     return nullptr;
714 }
715
716 static RefPtr<CSSCalcExpressionNode> createCSS(const Length& length, const RenderStyle& style)
717 {
718     switch (length.type()) {
719     case Percent:
720     case Fixed:
721         return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(length, style), length.value() == trunc(length.value()));
722     case Calculated:
723         return createCSS(length.calculationValue().expression(), style);
724     case Auto:
725     case Intrinsic:
726     case MinIntrinsic:
727     case MinContent:
728     case MaxContent:
729     case FillAvailable:
730     case FitContent:
731     case Relative:
732     case Undefined:
733         ASSERT_NOT_REACHED();
734     }
735     return nullptr;
736 }
737
738 RefPtr<CSSCalcValue> CSSCalcValue::create(const CSSParserTokenRange& tokens, ValueRange range)
739 {
740     CSSCalcExpressionNodeParser parser;
741     auto expression = parser.parseCalc(tokens);
742     if (!expression)
743         return nullptr;
744     return adoptRef(new CSSCalcValue(expression.releaseNonNull(), range != ValueRangeAll));
745 }
746     
747 RefPtr<CSSCalcValue> CSSCalcValue::create(const CalculationValue& value, const RenderStyle& style)
748 {
749     auto expression = createCSS(value.expression(), style);
750     if (!expression)
751         return nullptr;
752     return adoptRef(new CSSCalcValue(expression.releaseNonNull(), value.shouldClampToNonNegative()));
753 }
754
755 } // namespace WebCore