summaryrefslogtreecommitdiff
path: root/Source/WebCore/css/CSSCalculationValue.cpp
diff options
context:
space:
mode:
authorKonstantin Tokarev <annulen@yandex.ru>2016-08-25 19:20:41 +0300
committerKonstantin Tokarev <annulen@yandex.ru>2017-02-02 12:30:55 +0000
commit6882a04fb36642862b11efe514251d32070c3d65 (patch)
treeb7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebCore/css/CSSCalculationValue.cpp
parentab6df191029eeeb0b0f16f127d553265659f739e (diff)
downloadqtwebkit-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.cpp564
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, &currentIndex, 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