2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2014 Apple Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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.
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.
33 #include "CSSCalculationValue.h"
35 #include "CSSPrimitiveValueMappings.h"
36 #include "StyleResolver.h"
37 #include <wtf/MathExtras.h>
38 #include <wtf/text/StringBuilder.h>
40 static const int maxExpressionDepth = 100;
50 static PassRefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode&, const RenderStyle&);
51 static PassRefPtr<CSSCalcExpressionNode> createCSS(const Length&, const RenderStyle&);
53 static CalculationCategory unitCategory(CSSPrimitiveValue::UnitTypes type)
56 case CSSPrimitiveValue::CSS_NUMBER:
57 case CSSPrimitiveValue::CSS_PARSER_INTEGER:
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:
74 case CSSPrimitiveValue::CSS_PERCENTAGE:
76 case CSSPrimitiveValue::CSS_DEG:
77 case CSSPrimitiveValue::CSS_RAD:
78 case CSSPrimitiveValue::CSS_GRAD:
79 case CSSPrimitiveValue::CSS_TURN:
81 case CSSPrimitiveValue::CSS_MS:
82 case CSSPrimitiveValue::CSS_S:
84 case CSSPrimitiveValue::CSS_HZ:
85 case CSSPrimitiveValue::CSS_KHZ:
92 static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes 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:
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:
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:
155 ASSERT_NOT_REACHED();
159 static String buildCssText(const String& expression)
161 StringBuilder result;
162 result.appendLiteral("calc");
163 bool expressionHasSingleTerm = expression[0] != '(';
164 if (expressionHasSingleTerm)
166 result.append(expression);
167 if (expressionHasSingleTerm)
169 return result.toString();
172 String CSSCalcValue::customCSSText() const
174 return buildCssText(m_expression->customCSSText());
177 bool CSSCalcValue::equals(const CSSCalcValue& other) const
179 return compareCSSValue(m_expression, other.m_expression);
182 inline double CSSCalcValue::clampToPermittedRange(double value) const
184 return m_shouldClampToNonNegative && value < 0 ? 0 : value;
187 double CSSCalcValue::doubleValue() const
189 return clampToPermittedRange(m_expression->doubleValue());
192 double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const
194 return clampToPermittedRange(m_expression->computeLengthPx(conversionData));
197 class CSSCalcPrimitiveValue final : public CSSCalcExpressionNode {
198 WTF_MAKE_FAST_ALLOCATED;
200 static PassRef<CSSCalcPrimitiveValue> create(PassRefPtr<CSSPrimitiveValue> value, bool isInteger)
202 return adoptRef(*new CSSCalcPrimitiveValue(value, isInteger));
205 static PassRefPtr<CSSCalcPrimitiveValue> create(double value, CSSPrimitiveValue::UnitTypes type, bool isInteger)
207 if (std::isnan(value) || std::isinf(value))
209 return adoptRef(new CSSCalcPrimitiveValue(CSSPrimitiveValue::create(value, type), isInteger));
213 virtual bool isZero() const override
215 return !m_value->getDoubleValue();
218 virtual String customCSSText() const override
220 return m_value->cssText();
223 virtual std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const override
225 switch (category()) {
227 return std::make_unique<CalcExpressionNumber>(m_value->getFloatValue());
229 return std::make_unique<CalcExpressionLength>(Length(m_value->computeLength<float>(conversionData), WebCore::Fixed));
231 case CalcPercentLength: {
232 CSSPrimitiveValue* primitiveValue = m_value.get();
233 return std::make_unique<CalcExpressionLength>(primitiveValue
234 ? primitiveValue->convertToLength<FixedFloatConversion | PercentConversion>(conversionData) : Length(Undefined));
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:
243 ASSERT_NOT_REACHED();
248 virtual double doubleValue() const override
250 if (hasDoubleValue(primitiveType()))
251 return m_value->getDoubleValue();
252 ASSERT_NOT_REACHED();
256 virtual double computeLengthPx(const CSSToLengthConversionData& conversionData) const override
258 switch (category()) {
260 return m_value->computeLength<double>(conversionData);
263 return m_value->getDoubleValue();
264 case CalcPercentLength:
265 case CalcPercentNumber:
270 ASSERT_NOT_REACHED();
273 ASSERT_NOT_REACHED();
277 virtual bool equals(const CSSCalcExpressionNode& other) const override
279 if (type() != other.type())
282 return compareCSSValuePtr(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value);
285 virtual Type type() const override { return CssCalcPrimitiveValue; }
286 virtual CSSPrimitiveValue::UnitTypes primitiveType() const override
288 return CSSPrimitiveValue::UnitTypes(m_value->primitiveType());
292 explicit CSSCalcPrimitiveValue(PassRefPtr<CSSPrimitiveValue> value, bool isInteger)
293 : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitTypes)value->primitiveType()), isInteger)
298 RefPtr<CSSPrimitiveValue> m_value;
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
310 static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide, CalcOperator op)
312 CalculationCategory leftCategory = leftSide.category();
313 CalculationCategory rightCategory = rightSide.category();
315 if (leftCategory == CalcOther || rightCategory == CalcOther)
321 if (leftCategory < CalcAngle || rightCategory < CalcAngle)
322 return addSubtractResult[leftCategory][rightCategory];
323 if (leftCategory == rightCategory)
327 if (leftCategory != CalcNumber && rightCategory != CalcNumber)
329 return leftCategory == CalcNumber ? rightCategory : leftCategory;
331 if (rightCategory != CalcNumber || rightSide.isZero())
336 ASSERT_NOT_REACHED();
340 static inline bool isIntegerResult(CalcOperator op, const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide)
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();
347 class CSSCalcBinaryOperation final : public CSSCalcExpressionNode {
348 WTF_MAKE_FAST_ALLOCATED;
350 static PassRefPtr<CSSCalcBinaryOperation> create(CalcOperator op, PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide)
352 ASSERT(leftSide->category() != CalcOther && rightSide->category() != CalcOther);
354 CalculationCategory newCategory = determineCategory(*leftSide, *rightSide, op);
356 if (newCategory == CalcOther)
359 return adoptRef(new CSSCalcBinaryOperation(newCategory, op, leftSide, rightSide));
362 static PassRefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator op, PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide)
364 CalculationCategory leftCategory = leftSide->category();
365 CalculationCategory rightCategory = rightSide->category();
366 ASSERT(leftCategory != CalcOther && rightCategory != CalcOther);
368 bool isInteger = isIntegerResult(op, *leftSide, *rightSide);
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);
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);
396 // Simplify multiplying or dividing by a number for simplifiable types.
397 ASSERT(op == CalcMultiply || op == CalcDivide);
398 CSSCalcExpressionNode* numberSide = getNumberSide(*leftSide, *rightSide);
400 return create(op, leftSide, rightSide);
401 if (numberSide == leftSide && op == CalcDivide)
403 CSSCalcExpressionNode* otherSide = leftSide == numberSide ? rightSide.get() : leftSide.get();
405 double number = numberSide->doubleValue();
406 if (std::isnan(number) || std::isinf(number))
408 if (op == CalcDivide && !number)
411 CSSPrimitiveValue::UnitTypes otherType = otherSide->primitiveType();
412 if (hasDoubleValue(otherType))
413 return CSSCalcPrimitiveValue::create(evaluateOperator(op, otherSide->doubleValue(), number), otherType, isInteger);
416 return create(op, leftSide, rightSide);
420 virtual bool isZero() const override
422 return !doubleValue();
425 virtual std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const override
427 std::unique_ptr<CalcExpressionNode> left(m_leftSide->createCalcExpression(conversionData));
430 std::unique_ptr<CalcExpressionNode> right(m_rightSide->createCalcExpression(conversionData));
433 return std::make_unique<CalcExpressionBinaryOperation>(WTF::move(left), WTF::move(right), m_operator);
436 virtual double doubleValue() const override
438 return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue());
441 virtual double computeLengthPx(const CSSToLengthConversionData& conversionData) const override
443 const double leftValue = m_leftSide->computeLengthPx(conversionData);
444 const double rightValue = m_rightSide->computeLengthPx(conversionData);
445 return evaluate(leftValue, rightValue);
448 static String buildCssText(const String& leftExpression, const String& rightExpression, CalcOperator op)
450 StringBuilder result;
452 result.append(leftExpression);
454 result.append(static_cast<char>(op));
456 result.append(rightExpression);
459 return result.toString();
462 virtual String customCSSText() const override
464 return buildCssText(m_leftSide->customCSSText(), m_rightSide->customCSSText(), m_operator);
467 virtual bool equals(const CSSCalcExpressionNode& exp) const override
469 if (type() != exp.type())
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;
478 virtual Type type() const override { return CssCalcBinaryOperation; }
480 virtual CSSPrimitiveValue::UnitTypes primitiveType() const override
482 switch (category()) {
484 ASSERT(m_leftSide->category() == CalcNumber && m_rightSide->category() == CalcNumber);
486 return CSSPrimitiveValue::CSS_PARSER_INTEGER;
487 return CSSPrimitiveValue::CSS_NUMBER;
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())
497 return CSSPrimitiveValue::CSS_UNKNOWN;
500 return CSSPrimitiveValue::CSS_DEG;
502 return CSSPrimitiveValue::CSS_MS;
504 return CSSPrimitiveValue::CSS_HZ;
505 case CalcPercentLength:
506 case CalcPercentNumber:
508 return CSSPrimitiveValue::CSS_UNKNOWN;
510 ASSERT_NOT_REACHED();
511 return CSSPrimitiveValue::CSS_UNKNOWN;
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)
522 static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide)
524 if (leftSide.category() == CalcNumber)
526 if (rightSide.category() == CalcNumber)
531 double evaluate(double leftSide, double rightSide) const
533 return evaluateOperator(m_operator, leftSide, rightSide);
536 static double evaluateOperator(CalcOperator op, double leftValue, double rightValue)
540 return leftValue + rightValue;
542 return leftValue - rightValue;
544 return leftValue * rightValue;
547 return leftValue / rightValue;
548 return std::numeric_limits<double>::quiet_NaN();
550 ASSERT_NOT_REACHED();
554 const RefPtr<CSSCalcExpressionNode> m_leftSide;
555 const RefPtr<CSSCalcExpressionNode> m_rightSide;
556 const CalcOperator m_operator;
559 static ParseState checkDepthAndIndex(int* depth, unsigned index, CSSParserValueList* tokens)
562 if (*depth > maxExpressionDepth)
564 if (index >= tokens->size())
569 class CSSCalcExpressionNodeParser {
571 PassRefPtr<CSSCalcExpressionNode> parseCalc(CSSParserValueList* tokens)
575 bool ok = parseValueExpression(tokens, 0, &index, &result);
576 ASSERT_WITH_SECURITY_IMPLICATION(index <= tokens->size());
577 if (!ok || index != tokens->size())
584 RefPtr<CSSCalcExpressionNode> value;
587 char operatorValue(CSSParserValueList* tokens, unsigned index)
589 if (index >= tokens->size())
591 CSSParserValue* value = tokens->valueAt(index);
592 if (value->unit != CSSParserValue::Operator)
595 return value->iValue;
598 bool parseValue(CSSParserValueList* tokens, unsigned* index, Value* result)
600 CSSParserValue* parserValue = tokens->valueAt(*index);
601 if (parserValue->unit == CSSParserValue::Operator || parserValue->unit == CSSParserValue::Function)
604 RefPtr<CSSValue> value = parserValue->createCSSValue();
605 if (!is<CSSPrimitiveValue>(value.get()))
608 CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(*value);
609 result->value = CSSCalcPrimitiveValue::create(&primitiveValue, parserValue->isInt);
615 bool parseValueTerm(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
617 if (checkDepthAndIndex(&depth, *index, tokens) != OK)
620 if (operatorValue(tokens, *index) == '(') {
621 unsigned currentIndex = *index + 1;
622 if (!parseValueExpression(tokens, depth, ¤tIndex, result))
625 if (operatorValue(tokens, currentIndex) != ')')
627 *index = currentIndex + 1;
631 return parseValue(tokens, index, result);
634 bool parseValueMultiplicativeExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
636 if (checkDepthAndIndex(&depth, *index, tokens) != OK)
639 if (!parseValueTerm(tokens, depth, index, result))
642 while (*index < tokens->size() - 1) {
643 char operatorCharacter = operatorValue(tokens, *index);
644 if (operatorCharacter != CalcMultiply && operatorCharacter != CalcDivide)
649 if (!parseValueTerm(tokens, depth, index, &rhs))
652 result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), result->value, rhs.value);
657 ASSERT_WITH_SECURITY_IMPLICATION(*index <= tokens->size());
661 bool parseAdditiveValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
663 if (checkDepthAndIndex(&depth, *index, tokens) != OK)
666 if (!parseValueMultiplicativeExpression(tokens, depth, index, result))
669 while (*index < tokens->size() - 1) {
670 char operatorCharacter = operatorValue(tokens, *index);
671 if (operatorCharacter != CalcAdd && operatorCharacter != CalcSubtract)
676 if (!parseValueMultiplicativeExpression(tokens, depth, index, &rhs))
679 result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), result->value, rhs.value);
684 ASSERT_WITH_SECURITY_IMPLICATION(*index <= tokens->size());
688 bool parseValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result)
690 return parseAdditiveValueExpression(tokens, depth, index, result);
694 static inline PassRefPtr<CSSCalcBinaryOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress)
696 return CSSCalcBinaryOperation::create(CalcMultiply, createCSS(length, style),
697 CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), !progress || progress == 1));
700 static PassRefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode& node, const RenderStyle& style)
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));
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));
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));
719 case CalcExpressionNodeUndefined:
720 ASSERT_NOT_REACHED();
723 ASSERT_NOT_REACHED();
727 static PassRefPtr<CSSCalcExpressionNode> createCSS(const Length& length, const RenderStyle& style)
729 switch (length.type()) {
732 return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(length, &style), length.value() == trunc(length.value()));
734 return createCSS(length.calculationValue().expression(), style);
744 ASSERT_NOT_REACHED();
747 ASSERT_NOT_REACHED();
751 PassRefPtr<CSSCalcValue> CSSCalcValue::create(CSSParserString name, CSSParserValueList& parserValueList, CalculationPermittedValueRange range)
753 CSSCalcExpressionNodeParser parser;
754 RefPtr<CSSCalcExpressionNode> expression;
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
760 return expression ? adoptRef(new CSSCalcValue(expression.releaseNonNull(), range != CalculationRangeAll)) : nullptr;
763 PassRefPtr<CSSCalcValue> CSSCalcValue::create(const CalculationValue& value, const RenderStyle& style)
765 RefPtr<CSSCalcExpressionNode> expression = createCSS(value.expression(), style);
768 return adoptRef(new CSSCalcValue(expression.releaseNonNull(), value.shouldClampToNonNegative()));
771 } // namespace WebCore