summaryrefslogtreecommitdiff
path: root/Source/WebCore/css/CSSCalculationValue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/css/CSSCalculationValue.cpp')
-rw-r--r--Source/WebCore/css/CSSCalculationValue.cpp508
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, &currentIndex, 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