2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "core/css/CSSCalculationValue.h"
34 #include "core/css/CSSPrimitiveValueMappings.h"
35 #include "core/css/resolver/StyleResolver.h"
36 #include "wtf/MathExtras.h"
37 #include "wtf/OwnPtr.h"
38 #include "wtf/text/StringBuilder.h"
40 static const int maxExpressionDepth = 100;
50 static CalculationCategory unitCategory(CSSPrimitiveValue::UnitTypes type)
53 case CSSPrimitiveValue::CSS_NUMBER:
54 case CSSPrimitiveValue::CSS_PARSER_INTEGER:
56 case CSSPrimitiveValue::CSS_PERCENTAGE:
58 case CSSPrimitiveValue::CSS_EMS:
59 case CSSPrimitiveValue::CSS_EXS:
60 case CSSPrimitiveValue::CSS_PX:
61 case CSSPrimitiveValue::CSS_CM:
62 case CSSPrimitiveValue::CSS_MM:
63 case CSSPrimitiveValue::CSS_IN:
64 case CSSPrimitiveValue::CSS_PT:
65 case CSSPrimitiveValue::CSS_PC:
66 case CSSPrimitiveValue::CSS_REMS:
67 case CSSPrimitiveValue::CSS_CHS:
68 case CSSPrimitiveValue::CSS_VW:
69 case CSSPrimitiveValue::CSS_VH:
70 case CSSPrimitiveValue::CSS_VMIN:
71 case CSSPrimitiveValue::CSS_VMAX:
78 static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type)
81 case CSSPrimitiveValue::CSS_NUMBER:
82 case CSSPrimitiveValue::CSS_PARSER_INTEGER:
83 case CSSPrimitiveValue::CSS_PERCENTAGE:
84 case CSSPrimitiveValue::CSS_EMS:
85 case CSSPrimitiveValue::CSS_EXS:
86 case CSSPrimitiveValue::CSS_CHS:
87 case CSSPrimitiveValue::CSS_REMS:
88 case CSSPrimitiveValue::CSS_PX:
89 case CSSPrimitiveValue::CSS_CM:
90 case CSSPrimitiveValue::CSS_MM:
91 case CSSPrimitiveValue::CSS_IN:
92 case CSSPrimitiveValue::CSS_PT:
93 case CSSPrimitiveValue::CSS_PC:
94 case CSSPrimitiveValue::CSS_DEG:
95 case CSSPrimitiveValue::CSS_RAD:
96 case CSSPrimitiveValue::CSS_GRAD:
97 case CSSPrimitiveValue::CSS_MS:
98 case CSSPrimitiveValue::CSS_S:
99 case CSSPrimitiveValue::CSS_HZ:
100 case CSSPrimitiveValue::CSS_KHZ:
101 case CSSPrimitiveValue::CSS_DIMENSION:
102 case CSSPrimitiveValue::CSS_VW:
103 case CSSPrimitiveValue::CSS_VH:
104 case CSSPrimitiveValue::CSS_VMIN:
105 case CSSPrimitiveValue::CSS_VMAX:
106 case CSSPrimitiveValue::CSS_DPPX:
107 case CSSPrimitiveValue::CSS_DPI:
108 case CSSPrimitiveValue::CSS_DPCM:
109 case CSSPrimitiveValue::CSS_FR:
111 case CSSPrimitiveValue::CSS_UNKNOWN:
112 case CSSPrimitiveValue::CSS_STRING:
113 case CSSPrimitiveValue::CSS_URI:
114 case CSSPrimitiveValue::CSS_IDENT:
115 case CSSPrimitiveValue::CSS_ATTR:
116 case CSSPrimitiveValue::CSS_COUNTER:
117 case CSSPrimitiveValue::CSS_RECT:
118 case CSSPrimitiveValue::CSS_RGBCOLOR:
119 case CSSPrimitiveValue::CSS_PAIR:
120 case CSSPrimitiveValue::CSS_UNICODE_RANGE:
121 case CSSPrimitiveValue::CSS_PARSER_OPERATOR:
122 case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR:
123 case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER:
124 case CSSPrimitiveValue::CSS_TURN:
125 case CSSPrimitiveValue::CSS_COUNTER_NAME:
126 case CSSPrimitiveValue::CSS_SHAPE:
127 case CSSPrimitiveValue::CSS_QUAD:
128 case CSSPrimitiveValue::CSS_CALC:
129 case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER:
130 case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH:
131 case CSSPrimitiveValue::CSS_PROPERTY_ID:
132 case CSSPrimitiveValue::CSS_VALUE_ID:
135 ASSERT_NOT_REACHED();
139 static String buildCSSText(const String& expression)
141 StringBuilder result;
142 result.append("calc");
143 bool expressionHasSingleTerm = expression[0] != '(';
144 if (expressionHasSingleTerm)
146 result.append(expression);
147 if (expressionHasSingleTerm)
149 return result.toString();
152 String CSSCalcValue::customCSSText() const
154 return buildCSSText(m_expression->customCSSText());
157 bool CSSCalcValue::equals(const CSSCalcValue& other) const
159 return compareCSSValuePtr(m_expression, other.m_expression);
162 double CSSCalcValue::clampToPermittedRange(double value) const
164 return m_nonNegative && value < 0 ? 0 : value;
167 double CSSCalcValue::doubleValue() const
169 return clampToPermittedRange(m_expression->doubleValue());
172 double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const
174 return clampToPermittedRange(m_expression->computeLengthPx(conversionData));
177 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CSSCalcExpressionNode)
179 class CSSCalcPrimitiveValue FINAL : public CSSCalcExpressionNode {
180 WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
183 static PassRefPtrWillBeRawPtr<CSSCalcPrimitiveValue> create(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> value, bool isInteger)
185 return adoptRefWillBeNoop(new CSSCalcPrimitiveValue(value, isInteger));
188 static PassRefPtrWillBeRawPtr<CSSCalcPrimitiveValue> create(double value, CSSPrimitiveValue::UnitTypes type, bool isInteger)
190 if (std::isnan(value) || std::isinf(value))
192 return adoptRefWillBeNoop(new CSSCalcPrimitiveValue(CSSPrimitiveValue::create(value, type).get(), isInteger));
195 virtual bool isZero() const OVERRIDE
197 return !m_value->getDoubleValue();
200 virtual String customCSSText() const OVERRIDE
202 return m_value->cssText();
205 virtual void accumulatePixelsAndPercent(const CSSToLengthConversionData& conversionData, PixelsAndPercent& value, float multiplier) const OVERRIDE
207 switch (m_category) {
209 value.pixels += m_value->computeLength<float>(conversionData) * multiplier;
212 ASSERT(m_value->isPercentage());
213 value.percent += m_value->getDoubleValue() * multiplier;
216 ASSERT_NOT_REACHED();
220 virtual double doubleValue() const OVERRIDE
222 if (hasDoubleValue(primitiveType()))
223 return m_value->getDoubleValue();
224 ASSERT_NOT_REACHED();
228 virtual double computeLengthPx(const CSSToLengthConversionData& conversionData) const OVERRIDE
230 switch (m_category) {
232 return m_value->computeLength<double>(conversionData);
235 return m_value->getDoubleValue();
236 case CalcPercentLength:
237 case CalcPercentNumber:
239 ASSERT_NOT_REACHED();
242 ASSERT_NOT_REACHED();
246 virtual void accumulateLengthArray(CSSLengthArray& lengthArray, double multiplier) const
248 ASSERT(category() != CalcNumber);
249 m_value->accumulateLengthArray(lengthArray, multiplier);
252 virtual bool equals(const CSSCalcExpressionNode& other) const OVERRIDE
254 if (type() != other.type())
257 return compareCSSValuePtr(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value);
260 virtual Type type() const OVERRIDE { return CssCalcPrimitiveValue; }
261 virtual CSSPrimitiveValue::UnitTypes primitiveType() const OVERRIDE
263 return CSSPrimitiveValue::UnitTypes(m_value->primitiveType());
267 virtual void trace(Visitor* visitor)
269 visitor->trace(m_value);
270 CSSCalcExpressionNode::trace(visitor);
274 CSSCalcPrimitiveValue(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> value, bool isInteger)
275 : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitTypes)value->primitiveType()), isInteger)
280 RefPtrWillBeMember<CSSPrimitiveValue> m_value;
283 static const CalculationCategory addSubtractResult[CalcOther][CalcOther] = {
284 // CalcNumber CalcLength CalcPercent CalcPercentNumber CalcPercentLength
285 /* CalcNumber */ { CalcNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther },
286 /* CalcLength */ { CalcOther, CalcLength, CalcPercentLength, CalcOther, CalcPercentLength },
287 /* CalcPercent */ { CalcPercentNumber, CalcPercentLength, CalcPercent, CalcPercentNumber, CalcPercentLength },
288 /* CalcPercentNumber */ { CalcPercentNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther },
289 /* CalcPercentLength */ { CalcOther, CalcPercentLength, CalcPercentLength, CalcOther, CalcPercentLength },
292 static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide, CalcOperator op)
294 CalculationCategory leftCategory = leftSide.category();
295 CalculationCategory rightCategory = rightSide.category();
297 if (leftCategory == CalcOther || rightCategory == CalcOther)
303 return addSubtractResult[leftCategory][rightCategory];
305 if (leftCategory != CalcNumber && rightCategory != CalcNumber)
307 return leftCategory == CalcNumber ? rightCategory : leftCategory;
309 if (rightCategory != CalcNumber || rightSide.isZero())
314 ASSERT_NOT_REACHED();
318 static bool isIntegerResult(const CSSCalcExpressionNode* leftSide, const CSSCalcExpressionNode* rightSide, CalcOperator op)
320 // Not testing for actual integer values.
321 // Performs W3C spec's type checking for calc integers.
322 // http://www.w3.org/TR/css3-values/#calc-type-checking
323 return op != CalcDivide && leftSide->isInteger() && rightSide->isInteger();
326 class CSSCalcBinaryOperation FINAL : public CSSCalcExpressionNode {
328 static PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> create(PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> leftSide, PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> rightSide, CalcOperator op)
330 ASSERT(leftSide->category() != CalcOther && rightSide->category() != CalcOther);
332 CalculationCategory newCategory = determineCategory(*leftSide, *rightSide, op);
333 if (newCategory == CalcOther)
336 return adoptRefWillBeNoop(new CSSCalcBinaryOperation(leftSide, rightSide, op, newCategory));
339 static PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> createSimplified(PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> leftSide, PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> rightSide, CalcOperator op)
341 CalculationCategory leftCategory = leftSide->category();
342 CalculationCategory rightCategory = rightSide->category();
343 ASSERT(leftCategory != CalcOther && rightCategory != CalcOther);
345 bool isInteger = isIntegerResult(leftSide.get(), rightSide.get(), op);
348 if (leftCategory == CalcNumber && rightCategory == CalcNumber) {
349 CSSPrimitiveValue::UnitTypes evaluationType = isInteger ? CSSPrimitiveValue::CSS_PARSER_INTEGER : CSSPrimitiveValue::CSS_NUMBER;
350 return CSSCalcPrimitiveValue::create(evaluateOperator(leftSide->doubleValue(), rightSide->doubleValue(), op), evaluationType, isInteger);
353 // Simplify addition and subtraction between same types.
354 if (op == CalcAdd || op == CalcSubtract) {
355 if (leftCategory == rightSide->category()) {
356 CSSPrimitiveValue::UnitTypes leftType = leftSide->primitiveType();
357 if (hasDoubleValue(leftType)) {
358 CSSPrimitiveValue::UnitTypes rightType = rightSide->primitiveType();
359 if (leftType == rightType)
360 return CSSCalcPrimitiveValue::create(evaluateOperator(leftSide->doubleValue(), rightSide->doubleValue(), op), leftType, isInteger);
361 CSSPrimitiveValue::UnitCategory leftUnitCategory = CSSPrimitiveValue::unitCategory(leftType);
362 if (leftUnitCategory != CSSPrimitiveValue::UOther && leftUnitCategory == CSSPrimitiveValue::unitCategory(rightType)) {
363 CSSPrimitiveValue::UnitTypes canonicalType = CSSPrimitiveValue::canonicalUnitTypeForCategory(leftUnitCategory);
364 if (canonicalType != CSSPrimitiveValue::CSS_UNKNOWN) {
365 double leftValue = leftSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(leftType);
366 double rightValue = rightSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(rightType);
367 return CSSCalcPrimitiveValue::create(evaluateOperator(leftValue, rightValue, op), canonicalType, isInteger);
373 // Simplify multiplying or dividing by a number for simplifiable types.
374 ASSERT(op == CalcMultiply || op == CalcDivide);
375 CSSCalcExpressionNode* numberSide = getNumberSide(leftSide.get(), rightSide.get());
377 return create(leftSide, rightSide, op);
378 if (numberSide == leftSide && op == CalcDivide)
380 CSSCalcExpressionNode* otherSide = leftSide == numberSide ? rightSide.get() : leftSide.get();
382 double number = numberSide->doubleValue();
383 if (std::isnan(number) || std::isinf(number))
385 if (op == CalcDivide && !number)
388 CSSPrimitiveValue::UnitTypes otherType = otherSide->primitiveType();
389 if (hasDoubleValue(otherType))
390 return CSSCalcPrimitiveValue::create(evaluateOperator(otherSide->doubleValue(), number, op), otherType, isInteger);
393 return create(leftSide, rightSide, op);
396 virtual bool isZero() const OVERRIDE
398 return !doubleValue();
401 virtual void accumulatePixelsAndPercent(const CSSToLengthConversionData& conversionData, PixelsAndPercent& value, float multiplier) const OVERRIDE
403 switch (m_operator) {
405 m_leftSide->accumulatePixelsAndPercent(conversionData, value, multiplier);
406 m_rightSide->accumulatePixelsAndPercent(conversionData, value, multiplier);
409 m_leftSide->accumulatePixelsAndPercent(conversionData, value, multiplier);
410 m_rightSide->accumulatePixelsAndPercent(conversionData, value, -multiplier);
413 ASSERT((m_leftSide->category() == CalcNumber) != (m_rightSide->category() == CalcNumber));
414 if (m_leftSide->category() == CalcNumber)
415 m_rightSide->accumulatePixelsAndPercent(conversionData, value, multiplier * m_leftSide->doubleValue());
417 m_leftSide->accumulatePixelsAndPercent(conversionData, value, multiplier * m_rightSide->doubleValue());
420 ASSERT(m_rightSide->category() == CalcNumber);
421 m_leftSide->accumulatePixelsAndPercent(conversionData, value, multiplier / m_rightSide->doubleValue());
424 ASSERT_NOT_REACHED();
428 virtual double doubleValue() const OVERRIDE
430 return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue());
433 virtual double computeLengthPx(const CSSToLengthConversionData& conversionData) const OVERRIDE
435 const double leftValue = m_leftSide->computeLengthPx(conversionData);
436 const double rightValue = m_rightSide->computeLengthPx(conversionData);
437 return evaluate(leftValue, rightValue);
440 virtual void accumulateLengthArray(CSSLengthArray& lengthArray, double multiplier) const
442 switch (m_operator) {
444 m_leftSide->accumulateLengthArray(lengthArray, multiplier);
445 m_rightSide->accumulateLengthArray(lengthArray, multiplier);
448 m_leftSide->accumulateLengthArray(lengthArray, multiplier);
449 m_rightSide->accumulateLengthArray(lengthArray, -multiplier);
452 ASSERT((m_leftSide->category() == CalcNumber) != (m_rightSide->category() == CalcNumber));
453 if (m_leftSide->category() == CalcNumber)
454 m_rightSide->accumulateLengthArray(lengthArray, multiplier * m_leftSide->doubleValue());
456 m_leftSide->accumulateLengthArray(lengthArray, multiplier * m_rightSide->doubleValue());
459 ASSERT(m_rightSide->category() == CalcNumber);
460 m_leftSide->accumulateLengthArray(lengthArray, multiplier / m_rightSide->doubleValue());
463 ASSERT_NOT_REACHED();
467 static String buildCSSText(const String& leftExpression, const String& rightExpression, CalcOperator op)
469 StringBuilder result;
471 result.append(leftExpression);
473 result.append(static_cast<char>(op));
475 result.append(rightExpression);
478 return result.toString();
481 virtual String customCSSText() const OVERRIDE
483 return buildCSSText(m_leftSide->customCSSText(), m_rightSide->customCSSText(), m_operator);
486 virtual bool equals(const CSSCalcExpressionNode& exp) const OVERRIDE
488 if (type() != exp.type())
491 const CSSCalcBinaryOperation& other = static_cast<const CSSCalcBinaryOperation&>(exp);
492 return compareCSSValuePtr(m_leftSide, other.m_leftSide)
493 && compareCSSValuePtr(m_rightSide, other.m_rightSide)
494 && m_operator == other.m_operator;
497 virtual Type type() const OVERRIDE { return CssCalcBinaryOperation; }
499 virtual CSSPrimitiveValue::UnitTypes primitiveType() const OVERRIDE
501 switch (m_category) {
503 ASSERT(m_leftSide->category() == CalcNumber && m_rightSide->category() == CalcNumber);
505 return CSSPrimitiveValue::CSS_PARSER_INTEGER;
506 return CSSPrimitiveValue::CSS_NUMBER;
509 if (m_leftSide->category() == CalcNumber)
510 return m_rightSide->primitiveType();
511 if (m_rightSide->category() == CalcNumber)
512 return m_leftSide->primitiveType();
513 CSSPrimitiveValue::UnitTypes leftType = m_leftSide->primitiveType();
514 if (leftType == m_rightSide->primitiveType())
516 return CSSPrimitiveValue::CSS_UNKNOWN;
518 case CalcPercentLength:
519 case CalcPercentNumber:
521 return CSSPrimitiveValue::CSS_UNKNOWN;
523 ASSERT_NOT_REACHED();
524 return CSSPrimitiveValue::CSS_UNKNOWN;
527 virtual void trace(Visitor* visitor)
529 visitor->trace(m_leftSide);
530 visitor->trace(m_rightSide);
531 CSSCalcExpressionNode::trace(visitor);
535 CSSCalcBinaryOperation(PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> leftSide, PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> rightSide, CalcOperator op, CalculationCategory category)
536 : CSSCalcExpressionNode(category, isIntegerResult(leftSide.get(), rightSide.get(), op))
537 , m_leftSide(leftSide)
538 , m_rightSide(rightSide)
543 static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode* leftSide, CSSCalcExpressionNode* rightSide)
545 if (leftSide->category() == CalcNumber)
547 if (rightSide->category() == CalcNumber)
552 double evaluate(double leftSide, double rightSide) const
554 return evaluateOperator(leftSide, rightSide, m_operator);
557 static double evaluateOperator(double leftValue, double rightValue, CalcOperator op)
561 return leftValue + rightValue;
563 return leftValue - rightValue;
565 return leftValue * rightValue;
568 return leftValue / rightValue;
569 return std::numeric_limits<double>::quiet_NaN();
574 const RefPtrWillBeMember<CSSCalcExpressionNode> m_leftSide;
575 const RefPtrWillBeMember<CSSCalcExpressionNode> m_rightSide;
576 const CalcOperator m_operator;
579 static ParseState checkDepthAndIndex(int* depth, unsigned index, CSSParserValueList* tokens)
582 if (*depth > maxExpressionDepth)
584 if (index >= tokens->size())
589 class CSSCalcExpressionNodeParser {
592 PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> parseCalc(CSSParserValueList* tokens)
596 bool ok = parseValueExpression(tokens, 0, &index, &result);
597 ASSERT_WITH_SECURITY_IMPLICATION(index <= tokens->size());
598 if (!ok || index != tokens->size())
607 RefPtrWillBeMember<CSSCalcExpressionNode> value;
610 char operatorValue(CSSParserValueList* tokens, unsigned index)
612 if (index >= tokens->size())
614 CSSParserValue* value = tokens->valueAt(index);
615 if (value->unit != CSSParserValue::Operator)
618 return value->iValue;
621 bool parseValue(CSSParserValueList* tokens, unsigned* index, Value* result)
623 CSSParserValue* parserValue = tokens->valueAt(*index);
624 if (parserValue->unit == CSSParserValue::Operator)
627 RefPtrWillBeRawPtr<CSSValue> value = parserValue->createCSSValue();
628 if (!value || !value->isPrimitiveValue())
631 result->value = CSSCalcPrimitiveValue::create(toCSSPrimitiveValue(value.get()), parserValue->isInt);
637 bool parseValueTerm(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
639 if (checkDepthAndIndex(&depth, *index, tokens) != OK)
642 if (operatorValue(tokens, *index) == '(') {
643 unsigned currentIndex = *index + 1;
644 if (!parseValueExpression(tokens, depth, ¤tIndex, result))
647 if (operatorValue(tokens, currentIndex) != ')')
649 *index = currentIndex + 1;
653 return parseValue(tokens, index, result);
656 bool parseValueMultiplicativeExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
658 if (checkDepthAndIndex(&depth, *index, tokens) != OK)
661 if (!parseValueTerm(tokens, depth, index, result))
664 while (*index < tokens->size() - 1) {
665 char operatorCharacter = operatorValue(tokens, *index);
666 if (operatorCharacter != CalcMultiply && operatorCharacter != CalcDivide)
671 if (!parseValueTerm(tokens, depth, index, &rhs))
674 result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast<CalcOperator>(operatorCharacter));
679 ASSERT_WITH_SECURITY_IMPLICATION(*index <= tokens->size());
683 bool parseAdditiveValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
685 if (checkDepthAndIndex(&depth, *index, tokens) != OK)
688 if (!parseValueMultiplicativeExpression(tokens, depth, index, result))
691 while (*index < tokens->size() - 1) {
692 char operatorCharacter = operatorValue(tokens, *index);
693 if (operatorCharacter != CalcAdd && operatorCharacter != CalcSubtract)
698 if (!parseValueMultiplicativeExpression(tokens, depth, index, &rhs))
701 result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast<CalcOperator>(operatorCharacter));
706 ASSERT_WITH_SECURITY_IMPLICATION(*index <= tokens->size());
710 bool parseValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
712 return parseAdditiveValueExpression(tokens, depth, index, result);
716 PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> value, bool isInteger)
718 return CSSCalcPrimitiveValue::create(value, isInteger);
721 PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> leftSide, PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> rightSide, CalcOperator op)
723 return CSSCalcBinaryOperation::create(leftSide, rightSide, op);
726 PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(double pixels, double percent)
728 return createExpressionNode(
729 createExpressionNode(CSSPrimitiveValue::create(pixels, CSSPrimitiveValue::CSS_PX), pixels == trunc(pixels)),
730 createExpressionNode(CSSPrimitiveValue::create(percent, CSSPrimitiveValue::CSS_PERCENTAGE), percent == trunc(percent)),
734 PassRefPtrWillBeRawPtr<CSSCalcValue> CSSCalcValue::create(CSSParserString name, CSSParserValueList* parserValueList, ValueRange range)
736 CSSCalcExpressionNodeParser parser;
737 RefPtrWillBeRawPtr<CSSCalcExpressionNode> expression = nullptr;
739 if (equalIgnoringCase(name, "calc(") || equalIgnoringCase(name, "-webkit-calc("))
740 expression = parser.parseCalc(parserValueList);
741 // FIXME calc (http://webkit.org/b/16662) Add parsing for min and max here
743 return expression ? adoptRefWillBeNoop(new CSSCalcValue(expression, range)) : nullptr;
746 PassRefPtrWillBeRawPtr<CSSCalcValue> CSSCalcValue::create(PassRefPtrWillBeRawPtr<CSSCalcExpressionNode> expression, ValueRange range)
748 return adoptRefWillBeNoop(new CSSCalcValue(expression, range));
751 void CSSCalcValue::traceAfterDispatch(Visitor* visitor)
753 visitor->trace(m_expression);
754 CSSValue::traceAfterDispatch(visitor);
757 } // namespace WebCore