diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebCore/css/CSSCalculationValue.cpp | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
download | qtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebCore/css/CSSCalculationValue.cpp')
-rw-r--r-- | Source/WebCore/css/CSSCalculationValue.cpp | 564 |
1 files changed, 394 insertions, 170 deletions
diff --git a/Source/WebCore/css/CSSCalculationValue.cpp b/Source/WebCore/css/CSSCalculationValue.cpp index dca177991..5d563b35a 100644 --- a/Source/WebCore/css/CSSCalculationValue.cpp +++ b/Source/WebCore/css/CSSCalculationValue.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2011, 2012 Google Inc. All rights reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -31,12 +32,9 @@ #include "config.h" #include "CSSCalculationValue.h" -#include "CSSValueList.h" -#include "Length.h" +#include "CSSPrimitiveValueMappings.h" #include "StyleResolver.h" - -#include <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> +#include <wtf/MathExtras.h> #include <wtf/text/StringBuilder.h> static const int maxExpressionDepth = 100; @@ -49,14 +47,15 @@ enum ParseState { namespace WebCore { +static RefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode&, const RenderStyle&); +static RefPtr<CSSCalcExpressionNode> createCSS(const Length&, const RenderStyle&); + static CalculationCategory unitCategory(CSSPrimitiveValue::UnitTypes type) { switch (type) { case CSSPrimitiveValue::CSS_NUMBER: case CSSPrimitiveValue::CSS_PARSER_INTEGER: return CalcNumber; - case CSSPrimitiveValue::CSS_PERCENTAGE: - return CalcPercent; case CSSPrimitiveValue::CSS_EMS: case CSSPrimitiveValue::CSS_EXS: case CSSPrimitiveValue::CSS_PX: @@ -67,163 +66,218 @@ static CalculationCategory unitCategory(CSSPrimitiveValue::UnitTypes type) case CSSPrimitiveValue::CSS_PC: case CSSPrimitiveValue::CSS_REMS: case CSSPrimitiveValue::CSS_CHS: + case CSSPrimitiveValue::CSS_VW: + case CSSPrimitiveValue::CSS_VH: + case CSSPrimitiveValue::CSS_VMIN: + case CSSPrimitiveValue::CSS_VMAX: return CalcLength; -#if ENABLE(CSS_VARIABLES) - case CSSPrimitiveValue::CSS_VARIABLE_NAME: - return CalcVariable; -#endif + case CSSPrimitiveValue::CSS_PERCENTAGE: + return CalcPercent; + case CSSPrimitiveValue::CSS_DEG: + case CSSPrimitiveValue::CSS_RAD: + case CSSPrimitiveValue::CSS_GRAD: + case CSSPrimitiveValue::CSS_TURN: + return CalcAngle; + case CSSPrimitiveValue::CSS_MS: + case CSSPrimitiveValue::CSS_S: + return CalcTime; + case CSSPrimitiveValue::CSS_HZ: + case CSSPrimitiveValue::CSS_KHZ: + return CalcFrequency; default: return CalcOther; } } +static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type) +{ + switch (type) { + case CSSPrimitiveValue::CSS_FR: + case CSSPrimitiveValue::CSS_NUMBER: + case CSSPrimitiveValue::CSS_PARSER_INTEGER: + case CSSPrimitiveValue::CSS_PERCENTAGE: + case CSSPrimitiveValue::CSS_EMS: + case CSSPrimitiveValue::CSS_EXS: + case CSSPrimitiveValue::CSS_CHS: + case CSSPrimitiveValue::CSS_REMS: + case CSSPrimitiveValue::CSS_PX: + case CSSPrimitiveValue::CSS_CM: + case CSSPrimitiveValue::CSS_MM: + case CSSPrimitiveValue::CSS_IN: + case CSSPrimitiveValue::CSS_PT: + case CSSPrimitiveValue::CSS_PC: + case CSSPrimitiveValue::CSS_DEG: + case CSSPrimitiveValue::CSS_RAD: + case CSSPrimitiveValue::CSS_GRAD: + case CSSPrimitiveValue::CSS_TURN: + case CSSPrimitiveValue::CSS_MS: + case CSSPrimitiveValue::CSS_S: + case CSSPrimitiveValue::CSS_HZ: + case CSSPrimitiveValue::CSS_KHZ: + case CSSPrimitiveValue::CSS_DIMENSION: + case CSSPrimitiveValue::CSS_VW: + case CSSPrimitiveValue::CSS_VH: + case CSSPrimitiveValue::CSS_VMIN: + case CSSPrimitiveValue::CSS_VMAX: + case CSSPrimitiveValue::CSS_DPPX: + case CSSPrimitiveValue::CSS_DPI: + case CSSPrimitiveValue::CSS_DPCM: + return true; + case CSSPrimitiveValue::CSS_UNKNOWN: + case CSSPrimitiveValue::CSS_STRING: + case CSSPrimitiveValue::CSS_FONT_FAMILY: + case CSSPrimitiveValue::CSS_URI: + case CSSPrimitiveValue::CSS_IDENT: + case CSSPrimitiveValue::CSS_ATTR: + case CSSPrimitiveValue::CSS_COUNTER: + case CSSPrimitiveValue::CSS_RECT: + case CSSPrimitiveValue::CSS_RGBCOLOR: + case CSSPrimitiveValue::CSS_PAIR: + case CSSPrimitiveValue::CSS_UNICODE_RANGE: + case CSSPrimitiveValue::CSS_PARSER_OPERATOR: + case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR: + case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER: + case CSSPrimitiveValue::CSS_PARSER_WHITESPACE: + case CSSPrimitiveValue::CSS_COUNTER_NAME: + case CSSPrimitiveValue::CSS_SHAPE: + case CSSPrimitiveValue::CSS_QUAD: +#if ENABLE(CSS_SCROLL_SNAP) + case CSSPrimitiveValue::CSS_LENGTH_REPEAT: +#endif + case CSSPrimitiveValue::CSS_CALC: + case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER: + case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH: + case CSSPrimitiveValue::CSS_PROPERTY_ID: + case CSSPrimitiveValue::CSS_VALUE_ID: +#if ENABLE(DASHBOARD_SUPPORT) + case CSSPrimitiveValue::CSS_DASHBOARD_REGION: +#endif + return false; + }; + ASSERT_NOT_REACHED(); + return false; +} + static String buildCssText(const String& expression) { StringBuilder result; - result.append("calc"); + result.appendLiteral("calc"); bool expressionHasSingleTerm = expression[0] != '('; if (expressionHasSingleTerm) result.append('('); result.append(expression); if (expressionHasSingleTerm) result.append(')'); - return result.toString(); + return result.toString(); } -String CSSCalcValue::customCssText() const +String CSSCalcValue::customCSSText() const { - return buildCssText(m_expression->customCssText()); + return buildCssText(m_expression->customCSSText()); } bool CSSCalcValue::equals(const CSSCalcValue& other) const { - return compareCSSValuePtr(m_expression, other.m_expression); + return compareCSSValue(m_expression, other.m_expression); } -#if ENABLE(CSS_VARIABLES) -String CSSCalcValue::customSerializeResolvingVariables(const HashMap<AtomicString, String>& variables) const +inline double CSSCalcValue::clampToPermittedRange(double value) const { - return buildCssText(m_expression->serializeResolvingVariables(variables)); + return m_shouldClampToNonNegative && value < 0 ? 0 : value; } -bool CSSCalcValue::hasVariableReference() const -{ - return m_expression->hasVariableReference(); -} -#endif - -double CSSCalcValue::clampToPermittedRange(double value) const +double CSSCalcValue::doubleValue() const { - return m_nonNegative && value < 0 ? 0 : value; -} - -double CSSCalcValue::doubleValue() const -{ return clampToPermittedRange(m_expression->doubleValue()); } -double CSSCalcValue::computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const +double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const { - return clampToPermittedRange(m_expression->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize)); + return clampToPermittedRange(m_expression->computeLengthPx(conversionData)); } - -CSSCalcExpressionNode::~CSSCalcExpressionNode() -{ -} - -class CSSCalcPrimitiveValue : public CSSCalcExpressionNode { + +class CSSCalcPrimitiveValue final : public CSSCalcExpressionNode { WTF_MAKE_FAST_ALLOCATED; public: - - static PassRefPtr<CSSCalcPrimitiveValue> create(CSSPrimitiveValue* value, bool isInteger) + static Ref<CSSCalcPrimitiveValue> create(PassRefPtr<CSSPrimitiveValue> value, bool isInteger) { - return adoptRef(new CSSCalcPrimitiveValue(value, isInteger)); - } - - virtual bool isZero() const - { - return !m_value->getDoubleValue(); + return adoptRef(*new CSSCalcPrimitiveValue(value, isInteger)); } - virtual String customCssText() const + static RefPtr<CSSCalcPrimitiveValue> create(double value, CSSPrimitiveValue::UnitTypes type, bool isInteger) { - return m_value->cssText(); + if (std::isnan(value) || std::isinf(value)) + return nullptr; + return adoptRef(new CSSCalcPrimitiveValue(CSSPrimitiveValue::create(value, type), isInteger)); } -#if ENABLE(CSS_VARIABLES) - virtual String serializeResolvingVariables(const HashMap<AtomicString, String>& variables) const +private: + virtual bool isZero() const override { - return m_value->customSerializeResolvingVariables(variables); + return !m_value->getDoubleValue(); } - - virtual bool hasVariableReference() const + + virtual String customCSSText() const override { - return m_value->isVariableName(); + return m_value->cssText(); } -#endif - virtual PassOwnPtr<CalcExpressionNode> toCalcValue(const RenderStyle* style, const RenderStyle* rootStyle, double zoom) const + virtual std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const override { - switch (m_category) { + switch (category()) { case CalcNumber: - return adoptPtr(new CalcExpressionNumber(m_value->getFloatValue())); + return std::make_unique<CalcExpressionNumber>(m_value->getFloatValue()); case CalcLength: - return adoptPtr(new CalcExpressionNumber(m_value->computeLength<float>(style, rootStyle, zoom))); + return std::make_unique<CalcExpressionLength>(Length(m_value->computeLength<float>(conversionData), WebCore::Fixed)); case CalcPercent: - case CalcPercentLength: - return adoptPtr(new CalcExpressionLength(StyleResolver::convertToFloatLength(m_value.get(), style, rootStyle, zoom))); + case CalcPercentLength: { + CSSPrimitiveValue* primitiveValue = m_value.get(); + return std::make_unique<CalcExpressionLength>(primitiveValue + ? primitiveValue->convertToLength<FixedFloatConversion | PercentConversion>(conversionData) : Length(Undefined)); + } // Only types that could be part of a Length expression can be converted // to a CalcExpressionNode. CalcPercentNumber makes no sense as a Length. case CalcPercentNumber: -#if ENABLE(CSS_VARIABLES) - case CalcVariable: -#endif + case CalcAngle: + case CalcTime: + case CalcFrequency: case CalcOther: ASSERT_NOT_REACHED(); } + ASSERT_NOT_REACHED(); return nullptr; } - virtual double doubleValue() const + virtual double doubleValue() const override { - switch (m_category) { - case CalcNumber: - case CalcPercent: + if (hasDoubleValue(primitiveType())) return m_value->getDoubleValue(); - case CalcLength: - case CalcPercentLength: - case CalcPercentNumber: -#if ENABLE(CSS_VARIABLES) - case CalcVariable: -#endif - case CalcOther: - ASSERT_NOT_REACHED(); - break; - } + ASSERT_NOT_REACHED(); return 0; } - - virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const + + virtual double computeLengthPx(const CSSToLengthConversionData& conversionData) const override { - switch (m_category) { + switch (category()) { case CalcLength: - return m_value->computeLength<double>(currentStyle, rootStyle, multiplier, computingFontSize); + return m_value->computeLength<double>(conversionData); case CalcPercent: case CalcNumber: return m_value->getDoubleValue(); case CalcPercentLength: case CalcPercentNumber: -#if ENABLE(CSS_VARIABLES) - case CalcVariable: -#endif + case CalcAngle: + case CalcTime: + case CalcFrequency: case CalcOther: ASSERT_NOT_REACHED(); break; } - return 0; + ASSERT_NOT_REACHED(); + return 0; } - virtual bool equals(const CSSCalcExpressionNode& other) const + virtual bool equals(const CSSCalcExpressionNode& other) const override { if (type() != other.type()) return false; @@ -231,10 +285,14 @@ public: return compareCSSValuePtr(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value); } - virtual Type type() const { return CssCalcPrimitiveValue; } - + virtual Type type() const override { return CssCalcPrimitiveValue; } + virtual CSSPrimitiveValue::UnitTypes primitiveType() const override + { + return CSSPrimitiveValue::UnitTypes(m_value->primitiveType()); + } + private: - explicit CSSCalcPrimitiveValue(CSSPrimitiveValue* value, bool isInteger) + explicit CSSCalcPrimitiveValue(PassRefPtr<CSSPrimitiveValue> value, bool isInteger) : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitTypes)value->primitiveType()), isInteger) , m_value(value) { @@ -243,33 +301,32 @@ private: RefPtr<CSSPrimitiveValue> m_value; }; -static const CalculationCategory addSubtractResult[CalcOther][CalcOther] = { - { CalcNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther }, - { CalcOther, CalcLength, CalcPercentLength, CalcOther, CalcPercentLength }, - { CalcPercentNumber, CalcPercentLength, CalcPercent, CalcPercentNumber, CalcPercentLength }, - { CalcPercentNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther }, - { CalcOther, CalcPercentLength, CalcPercentLength, CalcOther, CalcPercentLength }, -}; +static const CalculationCategory addSubtractResult[CalcAngle][CalcAngle] = { +// CalcNumber CalcLength CalcPercent CalcPercentNumber CalcPercentLength + { CalcNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther }, // CalcNumber + { CalcOther, CalcLength, CalcPercentLength, CalcOther, CalcPercentLength }, // CalcLength + { CalcPercentNumber, CalcPercentLength, CalcPercent, CalcPercentNumber, CalcPercentLength }, // CalcPercent + { CalcPercentNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther }, // CalcPercentNumber + { CalcOther, CalcPercentLength, CalcPercentLength, CalcOther, CalcPercentLength }, // CalcPercentLength +}; static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide, CalcOperator op) { CalculationCategory leftCategory = leftSide.category(); CalculationCategory rightCategory = rightSide.category(); - - if (leftCategory == CalcOther || rightCategory == CalcOther) - return CalcOther; - -#if ENABLE(CSS_VARIABLES) - if (leftCategory == CalcVariable || rightCategory == CalcVariable) - return CalcVariable; -#endif + ASSERT(leftCategory < CalcOther); + ASSERT(rightCategory < CalcOther); switch (op) { case CalcAdd: - case CalcSubtract: - return addSubtractResult[leftCategory][rightCategory]; + case CalcSubtract: + if (leftCategory < CalcAngle && rightCategory < CalcAngle) + return addSubtractResult[leftCategory][rightCategory]; + if (leftCategory == rightCategory) + return leftCategory; + return CalcOther; case CalcMultiply: - if (leftCategory != CalcNumber && rightCategory != CalcNumber) + if (leftCategory != CalcNumber && rightCategory != CalcNumber) return CalcOther; return leftCategory == CalcNumber ? rightCategory : leftCategory; case CalcDivide: @@ -277,51 +334,118 @@ static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSi return CalcOther; return leftCategory; } - + ASSERT_NOT_REACHED(); return CalcOther; } -class CSSCalcBinaryOperation : public CSSCalcExpressionNode { +static inline bool isIntegerResult(CalcOperator op, const CSSCalcExpressionNode& leftSide, const CSSCalcExpressionNode& rightSide) +{ + // Performs W3C spec's type checking for calc integers. + // http://www.w3.org/TR/css3-values/#calc-type-checking + return op != CalcDivide && leftSide.isInteger() && rightSide.isInteger(); +} +class CSSCalcBinaryOperation final : public CSSCalcExpressionNode { + WTF_MAKE_FAST_ALLOCATED; public: - static PassRefPtr<CSSCalcBinaryOperation> create(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide, CalcOperator op) + static RefPtr<CSSCalcBinaryOperation> create(CalcOperator op, PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide) { - ASSERT(leftSide->category() != CalcOther && rightSide->category() != CalcOther); - + ASSERT(leftSide->category() < CalcOther); + ASSERT(rightSide->category() < CalcOther); + CalculationCategory newCategory = determineCategory(*leftSide, *rightSide, op); if (newCategory == CalcOther) - return 0; + return nullptr; - return adoptRef(new CSSCalcBinaryOperation(leftSide, rightSide, op, newCategory)); + return adoptRef(new CSSCalcBinaryOperation(newCategory, op, leftSide, rightSide)); } - - virtual bool isZero() const + + static RefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator op, PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide) + { + CalculationCategory leftCategory = leftSide->category(); + CalculationCategory rightCategory = rightSide->category(); + ASSERT(leftCategory < CalcOther); + ASSERT(rightCategory < CalcOther); + + bool isInteger = isIntegerResult(op, *leftSide, *rightSide); + + // Simplify numbers. + if (leftCategory == CalcNumber && rightCategory == CalcNumber) { + CSSPrimitiveValue::UnitTypes evaluationType = isInteger ? CSSPrimitiveValue::CSS_PARSER_INTEGER : CSSPrimitiveValue::CSS_NUMBER; + return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftSide->doubleValue(), rightSide->doubleValue()), evaluationType, isInteger); + } + + // Simplify addition and subtraction between same types. + if (op == CalcAdd || op == CalcSubtract) { + if (leftCategory == rightSide->category()) { + CSSPrimitiveValue::UnitTypes leftType = leftSide->primitiveType(); + if (hasDoubleValue(leftType)) { + CSSPrimitiveValue::UnitTypes rightType = rightSide->primitiveType(); + if (leftType == rightType) + return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftSide->doubleValue(), rightSide->doubleValue()), leftType, isInteger); + CSSPrimitiveValue::UnitCategory leftUnitCategory = CSSPrimitiveValue::unitCategory(leftType); + if (leftUnitCategory != CSSPrimitiveValue::UOther && leftUnitCategory == CSSPrimitiveValue::unitCategory(rightType)) { + CSSPrimitiveValue::UnitTypes canonicalType = CSSPrimitiveValue::canonicalUnitTypeForCategory(leftUnitCategory); + if (canonicalType != CSSPrimitiveValue::CSS_UNKNOWN) { + double leftValue = leftSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(leftType); + double rightValue = rightSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(rightType); + return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftValue, rightValue), canonicalType, isInteger); + } + } + } + } + } else { + // Simplify multiplying or dividing by a number for simplifiable types. + ASSERT(op == CalcMultiply || op == CalcDivide); + CSSCalcExpressionNode* numberSide = getNumberSide(*leftSide, *rightSide); + if (!numberSide) + return create(op, leftSide, rightSide); + if (numberSide == leftSide && op == CalcDivide) + return nullptr; + CSSCalcExpressionNode* otherSide = leftSide == numberSide ? rightSide.get() : leftSide.get(); + + double number = numberSide->doubleValue(); + if (std::isnan(number) || std::isinf(number)) + return nullptr; + if (op == CalcDivide && !number) + return nullptr; + + CSSPrimitiveValue::UnitTypes otherType = otherSide->primitiveType(); + if (hasDoubleValue(otherType)) + return CSSCalcPrimitiveValue::create(evaluateOperator(op, otherSide->doubleValue(), number), otherType, isInteger); + } + + return create(op, leftSide, rightSide); + } + +private: + virtual bool isZero() const override { return !doubleValue(); } - virtual PassOwnPtr<CalcExpressionNode> toCalcValue(const RenderStyle* style, const RenderStyle* rootStyle, double zoom) const + virtual std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const override { - OwnPtr<CalcExpressionNode> left(m_leftSide->toCalcValue(style, rootStyle, zoom)); + std::unique_ptr<CalcExpressionNode> left(m_leftSide->createCalcExpression(conversionData)); if (!left) return nullptr; - OwnPtr<CalcExpressionNode> right(m_rightSide->toCalcValue(style, rootStyle, zoom)); + std::unique_ptr<CalcExpressionNode> right(m_rightSide->createCalcExpression(conversionData)); if (!right) return nullptr; - return adoptPtr(new CalcExpressionBinaryOperation(left.release(), right.release(), m_operator)); + return std::make_unique<CalcExpressionBinaryOperation>(WTFMove(left), WTFMove(right), m_operator); } - virtual double doubleValue() const + virtual double doubleValue() const override { return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue()); } - - virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const + + virtual double computeLengthPx(const CSSToLengthConversionData& conversionData) const override { - const double leftValue = m_leftSide->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize); - const double rightValue = m_rightSide->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize); + const double leftValue = m_leftSide->computeLengthPx(conversionData); + const double rightValue = m_rightSide->computeLengthPx(conversionData); return evaluate(leftValue, rightValue); } @@ -335,28 +459,16 @@ public: result.append(' '); result.append(rightExpression); result.append(')'); - - return result.toString(); - } - virtual String customCssText() const - { - return buildCssText(m_leftSide->customCssText(), m_rightSide->customCssText(), m_operator); + return result.toString(); } -#if ENABLE(CSS_VARIABLES) - virtual String serializeResolvingVariables(const HashMap<AtomicString, String>& variables) const + virtual String customCSSText() const override { - return buildCssText(m_leftSide->serializeResolvingVariables(variables), m_rightSide->serializeResolvingVariables(variables), m_operator); + return buildCssText(m_leftSide->customCSSText(), m_rightSide->customCSSText(), m_operator); } - virtual bool hasVariableReference() const - { - return m_leftSide->hasVariableReference() || m_rightSide->hasVariableReference(); - } -#endif - - virtual bool equals(const CSSCalcExpressionNode& exp) const + virtual bool equals(const CSSCalcExpressionNode& exp) const override { if (type() != exp.type()) return false; @@ -367,20 +479,67 @@ public: && m_operator == other.m_operator; } - virtual Type type() const { return CssCalcBinaryOperation; } + virtual Type type() const override { return CssCalcBinaryOperation; } -private: - CSSCalcBinaryOperation(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide, CalcOperator op, CalculationCategory category) - : CSSCalcExpressionNode(category, leftSide->isInteger() && rightSide->isInteger()) + virtual CSSPrimitiveValue::UnitTypes primitiveType() const override + { + switch (category()) { + case CalcNumber: + ASSERT(m_leftSide->category() == CalcNumber && m_rightSide->category() == CalcNumber); + if (isInteger()) + return CSSPrimitiveValue::CSS_PARSER_INTEGER; + return CSSPrimitiveValue::CSS_NUMBER; + case CalcLength: + case CalcPercent: { + if (m_leftSide->category() == CalcNumber) + return m_rightSide->primitiveType(); + if (m_rightSide->category() == CalcNumber) + return m_leftSide->primitiveType(); + CSSPrimitiveValue::UnitTypes leftType = m_leftSide->primitiveType(); + if (leftType == m_rightSide->primitiveType()) + return leftType; + return CSSPrimitiveValue::CSS_UNKNOWN; + } + case CalcAngle: + return CSSPrimitiveValue::CSS_DEG; + case CalcTime: + return CSSPrimitiveValue::CSS_MS; + case CalcFrequency: + return CSSPrimitiveValue::CSS_HZ; + case CalcPercentLength: + case CalcPercentNumber: + case CalcOther: + return CSSPrimitiveValue::CSS_UNKNOWN; + } + ASSERT_NOT_REACHED(); + return CSSPrimitiveValue::CSS_UNKNOWN; + } + + CSSCalcBinaryOperation(CalculationCategory category, CalcOperator op, PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide) + : CSSCalcExpressionNode(category, isIntegerResult(op, *leftSide, *rightSide)) , m_leftSide(leftSide) , m_rightSide(rightSide) , m_operator(op) { } - - double evaluate(double leftValue, double rightValue) const + + static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide) { - switch (m_operator) { + if (leftSide.category() == CalcNumber) + return &leftSide; + if (rightSide.category() == CalcNumber) + return &rightSide; + return nullptr; + } + + double evaluate(double leftSide, double rightSide) const + { + return evaluateOperator(m_operator, leftSide, rightSide); + } + + static double evaluateOperator(CalcOperator op, double leftValue, double rightValue) + { + switch (op) { case CalcAdd: return leftValue + rightValue; case CalcSubtract: @@ -392,9 +551,10 @@ private: return leftValue / rightValue; return std::numeric_limits<double>::quiet_NaN(); } + ASSERT_NOT_REACHED(); return 0; } - + const RefPtr<CSSCalcExpressionNode> m_leftSide; const RefPtr<CSSCalcExpressionNode> m_rightSide; const CalcOperator m_operator; @@ -412,14 +572,14 @@ static ParseState checkDepthAndIndex(int* depth, unsigned index, CSSParserValueL class CSSCalcExpressionNodeParser { public: - PassRefPtr<CSSCalcExpressionNode> parseCalc(CSSParserValueList* tokens) + RefPtr<CSSCalcExpressionNode> parseCalc(CSSParserValueList* tokens) { unsigned index = 0; Value result; bool ok = parseValueExpression(tokens, 0, &index, &result); ASSERT_WITH_SECURITY_IMPLICATION(index <= tokens->size()); if (!ok || index != tokens->size()) - return 0; + return nullptr; return result.value; } @@ -446,11 +606,11 @@ private: return false; RefPtr<CSSValue> value = parserValue->createCSSValue(); - if (!value || !value->isPrimitiveValue()) + if (!is<CSSPrimitiveValue>(value.get())) return false; - CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value.get()); - result->value = CSSCalcPrimitiveValue::create(primitiveValue, parserValue->isInt); + CSSPrimitiveValue& primitiveValue = downcast<CSSPrimitiveValue>(*value); + result->value = CSSCalcPrimitiveValue::create(&primitiveValue, parserValue->isInt); ++*index; return true; @@ -459,8 +619,8 @@ private: bool parseValueTerm(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) { if (checkDepthAndIndex(&depth, *index, tokens) != OK) - return false; - + return false; + if (operatorValue(tokens, *index) == '(') { unsigned currentIndex = *index + 1; if (!parseValueExpression(tokens, depth, ¤tIndex, result)) @@ -478,7 +638,7 @@ private: bool parseValueMultiplicativeExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) { if (checkDepthAndIndex(&depth, *index, tokens) != OK) - return false; + return false; if (!parseValueTerm(tokens, depth, index, result)) return false; @@ -493,7 +653,7 @@ private: if (!parseValueTerm(tokens, depth, index, &rhs)) return false; - result->value = CSSCalcBinaryOperation::create(result->value, rhs.value, static_cast<CalcOperator>(operatorCharacter)); + result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), result->value, rhs.value); if (!result->value) return false; } @@ -505,7 +665,7 @@ private: bool parseAdditiveValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) { if (checkDepthAndIndex(&depth, *index, tokens) != OK) - return false; + return false; if (!parseValueMultiplicativeExpression(tokens, depth, index, result)) return false; @@ -520,7 +680,7 @@ private: if (!parseValueMultiplicativeExpression(tokens, depth, index, &rhs)) return false; - result->value = CSSCalcBinaryOperation::create(result->value, rhs.value, static_cast<CalcOperator>(operatorCharacter)); + result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), result->value, rhs.value); if (!result->value) return false; } @@ -535,16 +695,80 @@ private: } }; -PassRefPtr<CSSCalcValue> CSSCalcValue::create(CSSParserString name, CSSParserValueList* parserValueList, CalculationPermittedValueRange range) -{ - CSSCalcExpressionNodeParser parser; +static inline RefPtr<CSSCalcBinaryOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress) +{ + return CSSCalcBinaryOperation::create(CalcMultiply, createCSS(length, style), + CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), !progress || progress == 1)); +} + +static RefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode& node, const RenderStyle& style) +{ + switch (node.type()) { + case CalcExpressionNodeNumber: { + float value = toCalcExpressionNumber(node).value(); + return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER), value == truncf(value)); + } + case CalcExpressionNodeLength: + return createCSS(toCalcExpressionLength(node).length(), style); + case CalcExpressionNodeBinaryOperation: { + auto& binaryNode = toCalcExpressionBinaryOperation(node); + return CSSCalcBinaryOperation::create(binaryNode.getOperator(), createCSS(binaryNode.leftSide(), style), createCSS(binaryNode.rightSide(), style)); + } + case CalcExpressionNodeBlendLength: { + // FIXME: (http://webkit.org/b/122036) Create a CSSCalcExpressionNode equivalent of CalcExpressionBlendLength. + auto& blend = toCalcExpressionBlendLength(node); + float progress = blend.progress(); + return CSSCalcBinaryOperation::create(CalcAdd, createBlendHalf(blend.from(), style, 1 - progress), createBlendHalf(blend.to(), style, progress)); + } + case CalcExpressionNodeUndefined: + ASSERT_NOT_REACHED(); + return nullptr; + } + ASSERT_NOT_REACHED(); + return nullptr; +} + +static RefPtr<CSSCalcExpressionNode> createCSS(const Length& length, const RenderStyle& style) +{ + switch (length.type()) { + case Percent: + case Fixed: + return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(length, style), length.value() == trunc(length.value())); + case Calculated: + return createCSS(length.calculationValue().expression(), style); + case Auto: + case Intrinsic: + case MinIntrinsic: + case MinContent: + case MaxContent: + case FillAvailable: + case FitContent: + case Relative: + case Undefined: + ASSERT_NOT_REACHED(); + return nullptr; + } + ASSERT_NOT_REACHED(); + return nullptr; +} + +RefPtr<CSSCalcValue> CSSCalcValue::create(CSSParserString name, CSSParserValueList& parserValueList, CalculationPermittedValueRange range) +{ + CSSCalcExpressionNodeParser parser; RefPtr<CSSCalcExpressionNode> expression; - - if (equalIgnoringCase(name, "calc(") || equalIgnoringCase(name, "-webkit-calc(")) - expression = parser.parseCalc(parserValueList); - // FIXME calc (http://webkit.org/b/16662) Add parsing for min and max here - return expression ? adoptRef(new CSSCalcValue(expression, range)) : 0; + if (equalLettersIgnoringASCIICase(name, "calc(") || equalLettersIgnoringASCIICase(name, "-webkit-calc(")) + expression = parser.parseCalc(&parserValueList); + + return expression ? adoptRef(new CSSCalcValue(expression.releaseNonNull(), range != CalculationRangeAll)) : nullptr; +} + +RefPtr<CSSCalcValue> CSSCalcValue::create(const CalculationValue& value, const RenderStyle& style) +{ + RefPtr<CSSCalcExpressionNode> expression = createCSS(value.expression(), style); + if (!expression) + return nullptr; + return adoptRef(new CSSCalcValue(expression.releaseNonNull(), value.shouldClampToNonNegative())); } } // namespace WebCore |