diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/css/CSSCalculationValue.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/css/CSSCalculationValue.cpp')
-rw-r--r-- | Source/WebCore/css/CSSCalculationValue.cpp | 508 |
1 files changed, 253 insertions, 255 deletions
diff --git a/Source/WebCore/css/CSSCalculationValue.cpp b/Source/WebCore/css/CSSCalculationValue.cpp index 02329cdd4..5976d7f01 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,14 +32,11 @@ #include "config.h" #include "CSSCalculationValue.h" +#include "CSSParser.h" +#include "CSSParserTokenRange.h" #include "CSSPrimitiveValueMappings.h" -#include "CSSValueList.h" -#include "Length.h" #include "StyleResolver.h" - #include <wtf/MathExtras.h> -#include <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> #include <wtf/text/StringBuilder.h> static const int maxExpressionDepth = 100; @@ -51,14 +49,14 @@ enum ParseState { namespace WebCore { -static CalculationCategory unitCategory(CSSPrimitiveValue::UnitTypes type) +static RefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode&, const RenderStyle&); +static RefPtr<CSSCalcExpressionNode> createCSS(const Length&, const RenderStyle&); + +static CalculationCategory unitCategory(CSSPrimitiveValue::UnitType 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: @@ -69,18 +67,34 @@ 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; + 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) +static bool hasDoubleValue(CSSPrimitiveValue::UnitType 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: @@ -95,6 +109,7 @@ static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type) 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: @@ -110,6 +125,7 @@ static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type) 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: @@ -118,13 +134,10 @@ static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type) 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_TURN: case CSSPrimitiveValue::CSS_COUNTER_NAME: case CSSPrimitiveValue::CSS_SHAPE: case CSSPrimitiveValue::CSS_QUAD: + case CSSPrimitiveValue::CSS_QUIRKY_EMS: case CSSPrimitiveValue::CSS_CALC: case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER: case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH: @@ -142,7 +155,7 @@ static bool hasDoubleValue(CSSPrimitiveValue::UnitTypes type) static String buildCssText(const String& expression) { StringBuilder result; - result.append("calc"); + result.appendLiteral("calc"); bool expressionHasSingleTerm = expression[0] != '('; if (expressionHasSingleTerm) result.append('('); @@ -159,12 +172,12 @@ String CSSCalcValue::customCSSText() const bool CSSCalcValue::equals(const CSSCalcValue& other) const { - return compareCSSValuePtr(m_expression, other.m_expression); + return compareCSSValue(m_expression, other.m_expression); } -double CSSCalcValue::clampToPermittedRange(double value) const +inline double CSSCalcValue::clampToPermittedRange(double value) const { - return m_nonNegative && value < 0 ? 0 : value; + return m_shouldClampToNonNegative && value < 0 ? 0 : value; } double CSSCalcValue::doubleValue() const @@ -172,82 +185,82 @@ double CSSCalcValue::doubleValue() const return clampToPermittedRange(m_expression->doubleValue()); } -double CSSCalcValue::computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const -{ - return clampToPermittedRange(m_expression->computeLengthPx(currentStyle, rootStyle, multiplier, computingFontSize)); -} - -CSSCalcExpressionNode::~CSSCalcExpressionNode() +double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const { + return clampToPermittedRange(m_expression->computeLengthPx(conversionData)); } -class CSSCalcPrimitiveValue : public CSSCalcExpressionNode { +class CSSCalcPrimitiveValue final : public CSSCalcExpressionNode { WTF_MAKE_FAST_ALLOCATED; public: - - static PassRefPtr<CSSCalcPrimitiveValue> create(PassRefPtr<CSSPrimitiveValue> value, bool isInteger) + static Ref<CSSCalcPrimitiveValue> create(Ref<CSSPrimitiveValue>&& value, bool isInteger) { - return adoptRef(new CSSCalcPrimitiveValue(value, isInteger)); + return adoptRef(*new CSSCalcPrimitiveValue(WTFMove(value), isInteger)); } - static PassRefPtr<CSSCalcPrimitiveValue> create(double value, CSSPrimitiveValue::UnitTypes type, bool isInteger) + static RefPtr<CSSCalcPrimitiveValue> create(double value, CSSPrimitiveValue::UnitType type, bool isInteger) { - if (std::isnan(value) || std::isinf(value)) - return 0; + if (!std::isfinite(value)) + return nullptr; return adoptRef(new CSSCalcPrimitiveValue(CSSPrimitiveValue::create(value, type), isInteger)); } - virtual bool isZero() const +private: + bool isZero() const final { - return !m_value->getDoubleValue(); + return !m_value->doubleValue(); } - virtual String customCSSText() const + String customCSSText() const final { return m_value->cssText(); } - virtual PassOwnPtr<CalcExpressionNode> toCalcValue(const RenderStyle* style, const RenderStyle* rootStyle, double zoom) const + std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final { - switch (m_category) { + switch (category()) { case CalcNumber: - return adoptPtr(new CalcExpressionNumber(m_value->getFloatValue())); + return std::make_unique<CalcExpressionNumber>(m_value->floatValue()); 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: { - CSSPrimitiveValue* primitiveValue = m_value.get(); - return adoptPtr(new CalcExpressionLength(primitiveValue - ? primitiveValue->convertToLength<FixedFloatConversion | PercentConversion | FractionConversion>(style, rootStyle, zoom) - : Length(Undefined))); + return std::make_unique<CalcExpressionLength>(m_value->convertToLength<FixedFloatConversion | PercentConversion>(conversionData)); } // 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: + case CalcAngle: + case CalcTime: + case CalcFrequency: case CalcOther: ASSERT_NOT_REACHED(); } + ASSERT_NOT_REACHED(); return nullptr; } - virtual double doubleValue() const + double doubleValue() const final { if (hasDoubleValue(primitiveType())) - return m_value->getDoubleValue(); + return m_value->doubleValue(); ASSERT_NOT_REACHED(); return 0; } - virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const + double computeLengthPx(const CSSToLengthConversionData& conversionData) const final { - 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(); + return m_value->doubleValue(); case CalcPercentLength: case CalcPercentNumber: + case CalcAngle: + case CalcTime: + case CalcFrequency: case CalcOther: ASSERT_NOT_REACHED(); break; @@ -256,31 +269,31 @@ public: return 0; } - virtual bool equals(const CSSCalcExpressionNode& other) const + bool equals(const CSSCalcExpressionNode& other) const final { if (type() != other.type()) return false; - return compareCSSValuePtr(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value); + return compareCSSValue(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value); } - virtual Type type() const { return CssCalcPrimitiveValue; } - virtual CSSPrimitiveValue::UnitTypes primitiveType() const + Type type() const final { return CssCalcPrimitiveValue; } + CSSPrimitiveValue::UnitType primitiveType() const final { - return CSSPrimitiveValue::UnitTypes(m_value->primitiveType()); + return CSSPrimitiveValue::UnitType(m_value->primitiveType()); } private: - explicit CSSCalcPrimitiveValue(PassRefPtr<CSSPrimitiveValue> value, bool isInteger) - : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitTypes)value->primitiveType()), isInteger) - , m_value(value) + explicit CSSCalcPrimitiveValue(Ref<CSSPrimitiveValue>&& value, bool isInteger) + : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitType)value->primitiveType()), isInteger) + , m_value(WTFMove(value)) { } - RefPtr<CSSPrimitiveValue> m_value; + Ref<CSSPrimitiveValue> m_value; }; -static const CalculationCategory addSubtractResult[CalcOther][CalcOther] = { +static const CalculationCategory addSubtractResult[CalcAngle][CalcAngle] = { // CalcNumber CalcLength CalcPercent CalcPercentNumber CalcPercentLength { CalcNumber, CalcOther, CalcPercentNumber, CalcPercentNumber, CalcOther }, // CalcNumber { CalcOther, CalcLength, CalcPercentLength, CalcOther, CalcPercentLength }, // CalcLength @@ -293,14 +306,17 @@ static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSi { CalculationCategory leftCategory = leftSide.category(); CalculationCategory rightCategory = rightSide.category(); - - if (leftCategory == CalcOther || rightCategory == CalcOther) - return CalcOther; + ASSERT(leftCategory < CalcOther); + ASSERT(rightCategory < CalcOther); switch (op) { case CalcAdd: case CalcSubtract: - return addSubtractResult[leftCategory][rightCategory]; + if (leftCategory < CalcAngle && rightCategory < CalcAngle) + return addSubtractResult[leftCategory][rightCategory]; + if (leftCategory == rightCategory) + return leftCategory; + return CalcOther; case CalcMultiply: if (leftCategory != CalcNumber && rightCategory != CalcNumber) return CalcOther; @@ -315,57 +331,63 @@ static CalculationCategory determineCategory(const CSSCalcExpressionNode& leftSi return CalcOther; } -static bool isIntegerResult(const CSSCalcExpressionNode* leftSide, const CSSCalcExpressionNode* rightSide, CalcOperator op) +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(); + return op != CalcDivide && leftSide.isInteger() && rightSide.isInteger(); } -class CSSCalcBinaryOperation : public CSSCalcExpressionNode { - +class CSSCalcBinaryOperation final : public CSSCalcExpressionNode { + WTF_MAKE_FAST_ALLOCATED; public: - static PassRefPtr<CSSCalcExpressionNode> create(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide, CalcOperator op) + static RefPtr<CSSCalcBinaryOperation> create(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide) { - ASSERT(leftSide->category() != CalcOther && rightSide->category() != CalcOther); + if (!leftSide || !rightSide) + return nullptr; - CalculationCategory newCategory = determineCategory(*leftSide, *rightSide, op); + ASSERT(leftSide->category() < CalcOther); + ASSERT(rightSide->category() < CalcOther); + auto newCategory = determineCategory(*leftSide, *rightSide, op); if (newCategory == CalcOther) - return 0; - - return adoptRef(new CSSCalcBinaryOperation(leftSide, rightSide, op, newCategory)); + return nullptr; + return adoptRef(new CSSCalcBinaryOperation(newCategory, op, leftSide.releaseNonNull(), rightSide.releaseNonNull())); } - static PassRefPtr<CSSCalcExpressionNode> createSimplified(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide, CalcOperator op) + static RefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide) { - CalculationCategory leftCategory = leftSide->category(); - CalculationCategory rightCategory = rightSide->category(); - ASSERT(leftCategory != CalcOther && rightCategory != CalcOther); + if (!leftSide || !rightSide) + return nullptr; + + auto leftCategory = leftSide->category(); + auto rightCategory = rightSide->category(); + ASSERT(leftCategory < CalcOther); + ASSERT(rightCategory < CalcOther); - bool isInteger = isIntegerResult(leftSide.get(), rightSide.get(), op); + 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(leftSide->doubleValue(), rightSide->doubleValue(), op), evaluationType, isInteger); + CSSPrimitiveValue::UnitType evaluationType = 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(); + CSSPrimitiveValue::UnitType leftType = leftSide->primitiveType(); if (hasDoubleValue(leftType)) { - CSSPrimitiveValue::UnitTypes rightType = rightSide->primitiveType(); + CSSPrimitiveValue::UnitType rightType = rightSide->primitiveType(); if (leftType == rightType) - return CSSCalcPrimitiveValue::create(evaluateOperator(leftSide->doubleValue(), rightSide->doubleValue(), op), leftType, isInteger); + 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); + CSSPrimitiveValue::UnitType 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(leftValue, rightValue, op), canonicalType, isInteger); + return CSSCalcPrimitiveValue::create(evaluateOperator(op, leftValue, rightValue), canonicalType, isInteger); } } } @@ -373,52 +395,53 @@ public: } else { // Simplify multiplying or dividing by a number for simplifiable types. ASSERT(op == CalcMultiply || op == CalcDivide); - CSSCalcExpressionNode* numberSide = getNumberSide(leftSide.get(), rightSide.get()); + auto* numberSide = getNumberSide(*leftSide, *rightSide); if (!numberSide) - return create(leftSide, rightSide, op); + return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull()); if (numberSide == leftSide && op == CalcDivide) - return 0; - CSSCalcExpressionNode* otherSide = leftSide == numberSide ? rightSide.get() : leftSide.get(); + return nullptr; + auto& otherSide = leftSide == numberSide ? *rightSide : *leftSide; double number = numberSide->doubleValue(); - if (std::isnan(number) || std::isinf(number)) - return 0; + if (!std::isfinite(number)) + return nullptr; if (op == CalcDivide && !number) - return 0; + return nullptr; - CSSPrimitiveValue::UnitTypes otherType = otherSide->primitiveType(); + auto otherType = otherSide.primitiveType(); if (hasDoubleValue(otherType)) - return CSSCalcPrimitiveValue::create(evaluateOperator(otherSide->doubleValue(), number, op), otherType, isInteger); + return CSSCalcPrimitiveValue::create(evaluateOperator(op, otherSide.doubleValue(), number), otherType, isInteger); } - return create(leftSide, rightSide, op); + return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull()); } - virtual bool isZero() const +private: + bool isZero() const final { return !doubleValue(); } - virtual PassOwnPtr<CalcExpressionNode> toCalcValue(const RenderStyle* style, const RenderStyle* rootStyle, double zoom) const + std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final { - OwnPtr<CalcExpressionNode> left(m_leftSide->toCalcValue(style, rootStyle, zoom)); + auto left = m_leftSide->createCalcExpression(conversionData); if (!left) return nullptr; - OwnPtr<CalcExpressionNode> right(m_rightSide->toCalcValue(style, rootStyle, zoom)); + auto 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 + double doubleValue() const final { return evaluate(m_leftSide->doubleValue(), m_rightSide->doubleValue()); } - virtual double computeLengthPx(const RenderStyle* currentStyle, const RenderStyle* rootStyle, double multiplier, bool computingFontSize) const + double computeLengthPx(const CSSToLengthConversionData& conversionData) const final { - 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); } @@ -436,13 +459,12 @@ public: return result.toString(); } - virtual String customCSSText() const + String customCSSText() const final { return buildCssText(m_leftSide->customCSSText(), m_rightSide->customCSSText(), m_operator); } - - virtual bool equals(const CSSCalcExpressionNode& exp) const + bool equals(const CSSCalcExpressionNode& exp) const final { if (type() != exp.type()) return false; @@ -453,15 +475,13 @@ public: && m_operator == other.m_operator; } - virtual Type type() const { return CssCalcBinaryOperation; } + Type type() const final { return CssCalcBinaryOperation; } - virtual CSSPrimitiveValue::UnitTypes primitiveType() const + CSSPrimitiveValue::UnitType primitiveType() const final { - switch (m_category) { + switch (category()) { case CalcNumber: ASSERT(m_leftSide->category() == CalcNumber && m_rightSide->category() == CalcNumber); - if (m_isInteger) - return CSSPrimitiveValue::CSS_PARSER_INTEGER; return CSSPrimitiveValue::CSS_NUMBER; case CalcLength: case CalcPercent: { @@ -469,11 +489,17 @@ public: return m_rightSide->primitiveType(); if (m_rightSide->category() == CalcNumber) return m_leftSide->primitiveType(); - CSSPrimitiveValue::UnitTypes leftType = m_leftSide->primitiveType(); + CSSPrimitiveValue::UnitType 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: @@ -483,30 +509,29 @@ public: return CSSPrimitiveValue::CSS_UNKNOWN; } -private: - CSSCalcBinaryOperation(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide, CalcOperator op, CalculationCategory category) - : CSSCalcExpressionNode(category, isIntegerResult(leftSide.get(), rightSide.get(), op)) - , m_leftSide(leftSide) - , m_rightSide(rightSide) + CSSCalcBinaryOperation(CalculationCategory category, CalcOperator op, Ref<CSSCalcExpressionNode>&& leftSide, Ref<CSSCalcExpressionNode>&& rightSide) + : CSSCalcExpressionNode(category, isIntegerResult(op, leftSide.get(), rightSide.get())) + , m_leftSide(WTFMove(leftSide)) + , m_rightSide(WTFMove(rightSide)) , m_operator(op) { } - static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode* leftSide, CSSCalcExpressionNode* rightSide) + static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide) { - if (leftSide->category() == CalcNumber) - return leftSide; - if (rightSide->category() == CalcNumber) - return rightSide; - return 0; + if (leftSide.category() == CalcNumber) + return &leftSide; + if (rightSide.category() == CalcNumber) + return &rightSide; + return nullptr; } double evaluate(double leftSide, double rightSide) const { - return evaluateOperator(leftSide, rightSide, m_operator); + return evaluateOperator(m_operator, leftSide, rightSide); } - static double evaluateOperator(double leftValue, double rightValue, CalcOperator op) + static double evaluateOperator(CalcOperator op, double leftValue, double rightValue) { switch (op) { case CalcAdd: @@ -520,6 +545,7 @@ private: return leftValue / rightValue; return std::numeric_limits<double>::quiet_NaN(); } + ASSERT_NOT_REACHED(); return 0; } @@ -528,200 +554,174 @@ private: const CalcOperator m_operator; }; -static ParseState checkDepthAndIndex(int* depth, unsigned index, CSSParserValueList* tokens) +static ParseState checkDepthAndIndex(int* depth, CSSParserTokenRange tokens) { (*depth)++; + if (tokens.atEnd()) + return NoMoreTokens; if (*depth > maxExpressionDepth) return TooDeep; - if (index >= tokens->size()) - return NoMoreTokens; return OK; } class CSSCalcExpressionNodeParser { public: - PassRefPtr<CSSCalcExpressionNode> parseCalc(CSSParserValueList* tokens) + RefPtr<CSSCalcExpressionNode> parseCalc(CSSParserTokenRange 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; + tokens.consumeWhitespace(); + bool ok = parseValueExpression(tokens, 0, &result); + if (!ok || !tokens.atEnd()) + return nullptr; return result.value; } - + private: struct Value { RefPtr<CSSCalcExpressionNode> value; }; - - char operatorValue(CSSParserValueList* tokens, unsigned index) + + char operatorValue(const CSSParserToken& token) { - if (index >= tokens->size()) - return 0; - CSSParserValue* value = tokens->valueAt(index); - if (value->unit != CSSParserValue::Operator) - return 0; - - return value->iValue; + if (token.type() == DelimiterToken) + return token.delimiter(); + return 0; } - - bool parseValue(CSSParserValueList* tokens, unsigned* index, Value* result) + + bool parseValue(CSSParserTokenRange& tokens, Value* result) { - CSSParserValue* parserValue = tokens->valueAt(*index); - if (parserValue->unit == CSSParserValue::Operator || parserValue->unit == CSSParserValue::Function) + CSSParserToken token = tokens.consumeIncludingWhitespace(); + if (!(token.type() == NumberToken || token.type() == PercentageToken || token.type() == DimensionToken)) return false; - - RefPtr<CSSValue> value = parserValue->createCSSValue(); - if (!value || !value->isPrimitiveValue()) + + CSSPrimitiveValue::UnitType type = token.unitType(); + if (unitCategory(type) == CalcOther) return false; - - CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value.get()); - result->value = CSSCalcPrimitiveValue::create(primitiveValue, parserValue->isInt); - - ++*index; + + bool isInteger = token.numericValueType() == IntegerValueType || (token.numericValueType() == NumberValueType && token.numericValue() == trunc(token.numericValue())); + result->value = CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(token.numericValue(), type), isInteger); + return true; } - - bool parseValueTerm(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) + + bool parseValueTerm(CSSParserTokenRange& tokens, int depth, Value* result) { - if (checkDepthAndIndex(&depth, *index, tokens) != OK) + if (checkDepthAndIndex(&depth, tokens) != OK) return false; - - if (operatorValue(tokens, *index) == '(') { - unsigned currentIndex = *index + 1; - if (!parseValueExpression(tokens, depth, ¤tIndex, result)) - return false; - - if (operatorValue(tokens, currentIndex) != ')') - return false; - *index = currentIndex + 1; - return true; + + if (tokens.peek().type() == LeftParenthesisToken || tokens.peek().functionId() == CSSValueCalc) { + CSSParserTokenRange innerRange = tokens.consumeBlock(); + tokens.consumeWhitespace(); + innerRange.consumeWhitespace(); + return parseValueExpression(innerRange, depth, result); } - - return parseValue(tokens, index, result); + + return parseValue(tokens, result); } - - bool parseValueMultiplicativeExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) + + bool parseValueMultiplicativeExpression(CSSParserTokenRange& tokens, int depth, Value* result) { - if (checkDepthAndIndex(&depth, *index, tokens) != OK) + if (checkDepthAndIndex(&depth, tokens) != OK) return false; - - if (!parseValueTerm(tokens, depth, index, result)) + + if (!parseValueTerm(tokens, depth, result)) return false; - - while (*index < tokens->size() - 1) { - char operatorCharacter = operatorValue(tokens, *index); + + while (!tokens.atEnd()) { + char operatorCharacter = operatorValue(tokens.peek()); if (operatorCharacter != CalcMultiply && operatorCharacter != CalcDivide) break; - ++*index; - + tokens.consumeIncludingWhitespace(); + Value rhs; - if (!parseValueTerm(tokens, depth, index, &rhs)) + if (!parseValueTerm(tokens, depth, &rhs)) return false; + + result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value)); - result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast<CalcOperator>(operatorCharacter)); if (!result->value) return false; } - - ASSERT_WITH_SECURITY_IMPLICATION(*index <= tokens->size()); + return true; } - - bool parseAdditiveValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) + + bool parseAdditiveValueExpression(CSSParserTokenRange& tokens, int depth, Value* result) { - if (checkDepthAndIndex(&depth, *index, tokens) != OK) + if (checkDepthAndIndex(&depth, tokens) != OK) return false; - - if (!parseValueMultiplicativeExpression(tokens, depth, index, result)) + + if (!parseValueMultiplicativeExpression(tokens, depth, result)) return false; - - while (*index < tokens->size() - 1) { - char operatorCharacter = operatorValue(tokens, *index); + + while (!tokens.atEnd()) { + char operatorCharacter = operatorValue(tokens.peek()); if (operatorCharacter != CalcAdd && operatorCharacter != CalcSubtract) break; - ++*index; - + if ((&tokens.peek() - 1)->type() != WhitespaceToken) + return false; // calc(1px+ 2px) is invalid + tokens.consume(); + if (tokens.peek().type() != WhitespaceToken) + return false; // calc(1px +2px) is invalid + tokens.consumeIncludingWhitespace(); + Value rhs; - if (!parseValueMultiplicativeExpression(tokens, depth, index, &rhs)) + if (!parseValueMultiplicativeExpression(tokens, depth, &rhs)) return false; - - result->value = CSSCalcBinaryOperation::createSimplified(result->value, rhs.value, static_cast<CalcOperator>(operatorCharacter)); + + result->value = CSSCalcBinaryOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value)); if (!result->value) return false; } - - ASSERT_WITH_SECURITY_IMPLICATION(*index <= tokens->size()); + return true; } - - bool parseValueExpression(CSSParserValueList* tokens, int depth, unsigned* index, Value* result) + + bool parseValueExpression(CSSParserTokenRange& tokens, int depth, Value* result) { - return parseAdditiveValueExpression(tokens, depth, index, result); + return parseAdditiveValueExpression(tokens, depth, result); } }; -PassRefPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(PassRefPtr<CSSPrimitiveValue> value, bool isInteger) +static inline RefPtr<CSSCalcBinaryOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress) { - return CSSCalcPrimitiveValue::create(value, isInteger); + return CSSCalcBinaryOperation::create(CalcMultiply, createCSS(length, style), + CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), !progress || progress == 1)); } -PassRefPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(PassRefPtr<CSSCalcExpressionNode> leftSide, PassRefPtr<CSSCalcExpressionNode> rightSide, CalcOperator op) +static RefPtr<CSSCalcExpressionNode> createCSS(const CalcExpressionNode& node, const RenderStyle& style) { - return CSSCalcBinaryOperation::create(leftSide, rightSide, op); -} - -PassRefPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(const CalcExpressionNode* node, const RenderStyle* style) -{ - switch (node->type()) { + switch (node.type()) { case CalcExpressionNodeNumber: { - float value = toCalcExpressionNumber(node)->value(); - return createExpressionNode(CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER), value == trunc(value)); + float value = toCalcExpressionNumber(node).value(); + return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(value, CSSPrimitiveValue::CSS_NUMBER), value == std::trunc(value)); } case CalcExpressionNodeLength: - return createExpressionNode(toCalcExpressionLength(node)->length(), style); + return createCSS(toCalcExpressionLength(node).length(), style); case CalcExpressionNodeBinaryOperation: { - const CalcExpressionBinaryOperation* binaryNode = toCalcExpressionBinaryOperation(node); - return createExpressionNode(createExpressionNode(binaryNode->leftSide(), style), createExpressionNode(binaryNode->rightSide(), style), binaryNode->getOperator()); + 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. - const CalcExpressionBlendLength* blendNode = toCalcExpressionBlendLength(node); - const double progress = blendNode->progress(); - const bool isInteger = !progress || (progress == 1); - return createExpressionNode( - createExpressionNode( - createExpressionNode(blendNode->from(), style), - createExpressionNode(CSSPrimitiveValue::create(1 - progress, CSSPrimitiveValue::CSS_NUMBER), isInteger), - CalcMultiply), - createExpressionNode( - createExpressionNode(blendNode->to(), style), - createExpressionNode(CSSPrimitiveValue::create(progress, CSSPrimitiveValue::CSS_NUMBER), isInteger), - CalcMultiply), - CalcAdd); + 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 0; } - ASSERT_NOT_REACHED(); - return 0; + return nullptr; } -PassRefPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(const Length& length, const RenderStyle* style) +static RefPtr<CSSCalcExpressionNode> createCSS(const Length& length, const RenderStyle& style) { switch (length.type()) { case Percent: - case ViewportPercentageWidth: - case ViewportPercentageHeight: - case ViewportPercentageMin: - case ViewportPercentageMax: case Fixed: - return createExpressionNode(CSSPrimitiveValue::create(length, style), length.value() == trunc(length.value())); + return CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(length, style), length.value() == trunc(length.value())); case Calculated: - return createExpressionNode(length.calculationValue()->expression(), style); + return createCSS(length.calculationValue().expression(), style); case Auto: case Intrinsic: case MinIntrinsic: @@ -732,27 +732,25 @@ PassRefPtr<CSSCalcExpressionNode> CSSCalcValue::createExpressionNode(const Lengt case Relative: case Undefined: ASSERT_NOT_REACHED(); - return 0; } - ASSERT_NOT_REACHED(); - return 0; + return nullptr; } -PassRefPtr<CSSCalcValue> CSSCalcValue::create(CSSParserString name, CSSParserValueList* parserValueList, CalculationPermittedValueRange range) +RefPtr<CSSCalcValue> CSSCalcValue::create(const CSSParserTokenRange& tokens, ValueRange 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; + auto expression = parser.parseCalc(tokens); + if (!expression) + return nullptr; + return adoptRef(new CSSCalcValue(expression.releaseNonNull(), range != ValueRangeAll)); } - -PassRef<CSSCalcValue> CSSCalcValue::create(PassRefPtr<CSSCalcExpressionNode> expression, CalculationPermittedValueRange range) + +RefPtr<CSSCalcValue> CSSCalcValue::create(const CalculationValue& value, const RenderStyle& style) { - return adoptRef(*new CSSCalcValue(expression, range)); + auto expression = createCSS(value.expression(), style); + if (!expression) + return nullptr; + return adoptRef(new CSSCalcValue(expression.releaseNonNull(), value.shouldClampToNonNegative())); } } // namespace WebCore |