Title: [251595] trunk/Source/WebCore
Revision
251595
Author
simon.fra...@apple.com
Date
2019-10-25 10:16:23 -0700 (Fri, 25 Oct 2019)

Log Message

Move code around in CSSCalculationValue.cpp
https://bugs.webkit.org/show_bug.cgi?id=203397

Reviewed by Zalan Bujtas.

Large amounts of code were in inline (but virtual) functions in CSSCalcPrimitiveValue, CSSCalcOperation
and CSSCalcExpressionNodeParser, making it hard to navigate around this file. Move code into
out-of-line functions. No behavior changes.

* css/CSSCalculationValue.cpp:
(WebCore::CSSCalcPrimitiveValue::createCalcExpression const):
(WebCore::CSSCalcPrimitiveValue::doubleValue const):
(WebCore::CSSCalcPrimitiveValue::computeLengthPx const):
(WebCore::CSSCalcPrimitiveValue::collectDirectComputationalDependencies const):
(WebCore::CSSCalcPrimitiveValue::collectDirectRootComputationalDependencies const):
(WebCore::CSSCalcPrimitiveValue::equals const):
(WebCore::CSSCalcOperation::create):
(WebCore::CSSCalcOperation::createMinOrMax):
(WebCore::CSSCalcOperation::createSimplified):
(WebCore::CSSCalcOperation::primitiveType const):
(WebCore::CSSCalcOperation::createCalcExpression const):
(WebCore::CSSCalcOperation::doubleValue const):
(WebCore::CSSCalcOperation::computeLengthPx const):
(WebCore::CSSCalcOperation::collectDirectComputationalDependencies const):
(WebCore::CSSCalcOperation::collectDirectRootComputationalDependencies const):
(WebCore::CSSCalcOperation::buildCssText):
(WebCore::CSSCalcOperation::customCSSText const):
(WebCore::CSSCalcOperation::equals const):
(WebCore::CSSCalcOperation::evaluateOperator):
(WebCore::CSSCalcExpressionNodeParser::parseCalc):
(WebCore::CSSCalcExpressionNodeParser::parseValue):
(WebCore::checkDepthAndIndex):
(WebCore::CSSCalcExpressionNodeParser::parseValueTerm):
(WebCore::CSSCalcExpressionNodeParser::parseValueMultiplicativeExpression):
(WebCore::CSSCalcExpressionNodeParser::parseAdditiveValueExpression):
(WebCore::CSSCalcExpressionNodeParser::parseMinMaxExpression):
(WebCore::CSSCalcExpressionNodeParser::parseValueExpression):
(WebCore::CSSCalcValue::customCSSText const):
(WebCore::CSSCalcValue::equals const):
(WebCore::CSSCalcValue::clampToPermittedRange const):
(WebCore::CSSCalcValue::doubleValue const):
(WebCore::CSSCalcValue::computeLengthPx const):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (251594 => 251595)


--- trunk/Source/WebCore/ChangeLog	2019-10-25 16:20:22 UTC (rev 251594)
+++ trunk/Source/WebCore/ChangeLog	2019-10-25 17:16:23 UTC (rev 251595)
@@ -1,3 +1,48 @@
+2019-10-25  Simon Fraser  <simon.fra...@apple.com>
+
+        Move code around in CSSCalculationValue.cpp
+        https://bugs.webkit.org/show_bug.cgi?id=203397
+
+        Reviewed by Zalan Bujtas.
+
+        Large amounts of code were in inline (but virtual) functions in CSSCalcPrimitiveValue, CSSCalcOperation
+        and CSSCalcExpressionNodeParser, making it hard to navigate around this file. Move code into
+        out-of-line functions. No behavior changes.
+
+        * css/CSSCalculationValue.cpp:
+        (WebCore::CSSCalcPrimitiveValue::createCalcExpression const):
+        (WebCore::CSSCalcPrimitiveValue::doubleValue const):
+        (WebCore::CSSCalcPrimitiveValue::computeLengthPx const):
+        (WebCore::CSSCalcPrimitiveValue::collectDirectComputationalDependencies const):
+        (WebCore::CSSCalcPrimitiveValue::collectDirectRootComputationalDependencies const):
+        (WebCore::CSSCalcPrimitiveValue::equals const):
+        (WebCore::CSSCalcOperation::create):
+        (WebCore::CSSCalcOperation::createMinOrMax):
+        (WebCore::CSSCalcOperation::createSimplified):
+        (WebCore::CSSCalcOperation::primitiveType const):
+        (WebCore::CSSCalcOperation::createCalcExpression const):
+        (WebCore::CSSCalcOperation::doubleValue const):
+        (WebCore::CSSCalcOperation::computeLengthPx const):
+        (WebCore::CSSCalcOperation::collectDirectComputationalDependencies const):
+        (WebCore::CSSCalcOperation::collectDirectRootComputationalDependencies const):
+        (WebCore::CSSCalcOperation::buildCssText):
+        (WebCore::CSSCalcOperation::customCSSText const):
+        (WebCore::CSSCalcOperation::equals const):
+        (WebCore::CSSCalcOperation::evaluateOperator):
+        (WebCore::CSSCalcExpressionNodeParser::parseCalc):
+        (WebCore::CSSCalcExpressionNodeParser::parseValue):
+        (WebCore::checkDepthAndIndex):
+        (WebCore::CSSCalcExpressionNodeParser::parseValueTerm):
+        (WebCore::CSSCalcExpressionNodeParser::parseValueMultiplicativeExpression):
+        (WebCore::CSSCalcExpressionNodeParser::parseAdditiveValueExpression):
+        (WebCore::CSSCalcExpressionNodeParser::parseMinMaxExpression):
+        (WebCore::CSSCalcExpressionNodeParser::parseValueExpression):
+        (WebCore::CSSCalcValue::customCSSText const):
+        (WebCore::CSSCalcValue::equals const):
+        (WebCore::CSSCalcValue::clampToPermittedRange const):
+        (WebCore::CSSCalcValue::doubleValue const):
+        (WebCore::CSSCalcValue::computeLengthPx const):
+
 2019-10-25  youenn fablet  <you...@apple.com>
 
         mp4 video element broken with service worker

Modified: trunk/Source/WebCore/css/CSSCalculationValue.cpp (251594 => 251595)


--- trunk/Source/WebCore/css/CSSCalculationValue.cpp	2019-10-25 16:20:22 UTC (rev 251594)
+++ trunk/Source/WebCore/css/CSSCalculationValue.cpp	2019-10-25 17:16:23 UTC (rev 251595)
@@ -149,34 +149,7 @@
     return false;
 }
 
-String CSSCalcValue::customCSSText() const
-{
-    auto _expression_ = m_expression->customCSSText();
-    if (_expression_[0] == '(')
-        return makeString("calc", _expression_);
-    return makeString("calc(", _expression_, ')');
-}
 
-bool CSSCalcValue::equals(const CSSCalcValue& other) const
-{
-    return compareCSSValue(m_expression, other.m_expression);
-}
-
-inline double CSSCalcValue::clampToPermittedRange(double value) const
-{
-    return m_shouldClampToNonNegative && value < 0 ? 0 : value;
-}
-
-double CSSCalcValue::doubleValue() const
-{
-    return clampToPermittedRange(m_expression->doubleValue());
-}
-
-double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const
-{
-    return clampToPermittedRange(m_expression->computeLengthPx(conversionData));
-}
-
 class CSSCalcPrimitiveValue final : public CSSCalcExpressionNode {
     WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -198,98 +171,111 @@
         return !m_value->doubleValue();
     }
 
+    bool equals(const CSSCalcExpressionNode& other) const final;
+    Type type() const final { return CssCalcPrimitiveValue; }
+
+    CSSPrimitiveValue::UnitType primitiveType() const final
+    {
+        return CSSPrimitiveValue::UnitType(m_value->primitiveType());
+    }
+
+    std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData&) const final;
+    double doubleValue() const final;
+
+    double computeLengthPx(const CSSToLengthConversionData&) const final;
+    void collectDirectComputationalDependencies(HashSet<CSSPropertyID>&) const final;
+    void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>&) const final;
+
     String customCSSText() const final
     {
         return m_value->cssText();
     }
 
-    std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final
+private:
+    explicit CSSCalcPrimitiveValue(Ref<CSSPrimitiveValue>&& value, bool isInteger)
+        : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitType)value->primitiveType()), isInteger)
+        , m_value(WTFMove(value))
     {
-        switch (category()) {
-        case CalculationCategory::Number:
-            return makeUnique<CalcExpressionNumber>(m_value->floatValue());
-        case CalculationCategory::Length:
-            return makeUnique<CalcExpressionLength>(Length(m_value->computeLength<float>(conversionData), WebCore::Fixed));
-        case CalculationCategory::Percent:
-        case CalculationCategory::PercentLength: {
-            return makeUnique<CalcExpressionLength>(m_value->convertToLength<FixedFloatConversion | PercentConversion>(conversionData));
-        }
-        // Only types that could be part of a Length _expression_ can be converted
-        // to a CalcExpressionNode. CalculationCategory::PercentNumber makes no sense as a Length.
-        case CalculationCategory::PercentNumber:
-        case CalculationCategory::Angle:
-        case CalculationCategory::Time:
-        case CalculationCategory::Frequency:
-        case CalculationCategory::Other:
-            ASSERT_NOT_REACHED();
-        }
-        ASSERT_NOT_REACHED();
-        return nullptr;
     }
 
-    double doubleValue() const final
-    {
-        if (hasDoubleValue(primitiveType()))
-            return m_value->doubleValue();
+    Ref<CSSPrimitiveValue> m_value;
+};
+
+std::unique_ptr<CalcExpressionNode> CSSCalcPrimitiveValue::createCalcExpression(const CSSToLengthConversionData& conversionData) const
+{
+    switch (category()) {
+    case CalculationCategory::Number:
+        return makeUnique<CalcExpressionNumber>(m_value->floatValue());
+    case CalculationCategory::Length:
+        return makeUnique<CalcExpressionLength>(Length(m_value->computeLength<float>(conversionData), WebCore::Fixed));
+    case CalculationCategory::Percent:
+    case CalculationCategory::PercentLength: {
+        return makeUnique<CalcExpressionLength>(m_value->convertToLength<FixedFloatConversion | PercentConversion>(conversionData));
+    }
+    // Only types that could be part of a Length _expression_ can be converted
+    // to a CalcExpressionNode. CalculationCategory::PercentNumber makes no sense as a Length.
+    case CalculationCategory::PercentNumber:
+    case CalculationCategory::Angle:
+    case CalculationCategory::Time:
+    case CalculationCategory::Frequency:
+    case CalculationCategory::Other:
         ASSERT_NOT_REACHED();
-        return 0;
     }
+    ASSERT_NOT_REACHED();
+    return nullptr;
+}
 
-    double computeLengthPx(const CSSToLengthConversionData& conversionData) const final
-    {
-        switch (category()) {
-        case CalculationCategory::Length:
-            return m_value->computeLength<double>(conversionData);
-        case CalculationCategory::Percent:
-        case CalculationCategory::Number:
-            return m_value->doubleValue();
-        case CalculationCategory::PercentLength:
-        case CalculationCategory::PercentNumber:
-        case CalculationCategory::Angle:
-        case CalculationCategory::Time:
-        case CalculationCategory::Frequency:
-        case CalculationCategory::Other:
-            ASSERT_NOT_REACHED();
-            break;
-        }
+double CSSCalcPrimitiveValue::doubleValue() const
+{
+    if (hasDoubleValue(primitiveType()))
+        return m_value->doubleValue();
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+double CSSCalcPrimitiveValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const
+{
+    switch (category()) {
+    case CalculationCategory::Length:
+        return m_value->computeLength<double>(conversionData);
+    case CalculationCategory::Percent:
+    case CalculationCategory::Number:
+        return m_value->doubleValue();
+    case CalculationCategory::PercentLength:
+    case CalculationCategory::PercentNumber:
+    case CalculationCategory::Angle:
+    case CalculationCategory::Time:
+    case CalculationCategory::Frequency:
+    case CalculationCategory::Other:
         ASSERT_NOT_REACHED();
-        return 0;
+        break;
     }
+    ASSERT_NOT_REACHED();
+    return 0;
+}
 
-    void collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const final
-    {
-        m_value->collectDirectComputationalDependencies(values);
-    }
+void CSSCalcPrimitiveValue::collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const
+{
+    m_value->collectDirectComputationalDependencies(values);
+}
 
-    void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const final
-    {
-        m_value->collectDirectRootComputationalDependencies(values);
-    }
+void CSSCalcPrimitiveValue::collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const
+{
+    m_value->collectDirectRootComputationalDependencies(values);
+}
 
-    bool equals(const CSSCalcExpressionNode& other) const final
-    {
-        if (type() != other.type())
-            return false;
+bool CSSCalcPrimitiveValue::equals(const CSSCalcExpressionNode& other) const
+{
+    if (type() != other.type())
+        return false;
 
-        return compareCSSValue(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value);
-    }
+    return compareCSSValue(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value);
+}
 
-    Type type() const final { return CssCalcPrimitiveValue; }
-    CSSPrimitiveValue::UnitType primitiveType() const final
-    {
-        return CSSPrimitiveValue::UnitType(m_value->primitiveType());
-    }
 
-private:
-    explicit CSSCalcPrimitiveValue(Ref<CSSPrimitiveValue>&& value, bool isInteger)
-        : CSSCalcExpressionNode(unitCategory((CSSPrimitiveValue::UnitType)value->primitiveType()), isInteger)
-        , m_value(WTFMove(value))
-    {
-    }
 
-    Ref<CSSPrimitiveValue> m_value;
-};
 
+
 static const CalculationCategory addSubtractResult[static_cast<unsigned>(CalculationCategory::Angle)][static_cast<unsigned>(CalculationCategory::Angle)] = {
 //    CalculationCategory::Number         CalculationCategory::Length         CalculationCategory::Percent        CalculationCategory::PercentNumber  CalculationCategory::PercentLength
     { CalculationCategory::Number,        CalculationCategory::Other,         CalculationCategory::PercentNumber, CalculationCategory::PercentNumber, CalculationCategory::Other }, //         CalculationCategory::Number
@@ -386,345 +372,356 @@
 class CSSCalcOperation final : public CSSCalcExpressionNode {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    static RefPtr<CSSCalcOperation> create(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
+    static RefPtr<CSSCalcOperation> create(CalcOperator, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide);
+    static RefPtr<CSSCalcOperation> createMinOrMax(CalcOperator, Vector<Ref<CSSCalcExpressionNode>>&& values, CalculationCategory destinationCategory);
+    static RefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide);
+
+private:
+    CSSCalcOperation(CalculationCategory category, CalcOperator op, Ref<CSSCalcExpressionNode>&& leftSide, Ref<CSSCalcExpressionNode>&& rightSide)
+        : CSSCalcExpressionNode(category, isIntegerResult(op, leftSide.get(), rightSide.get()))
+        , m_operator(op)
     {
-        if (!leftSide || !rightSide)
-            return nullptr;
+        m_children.reserveInitialCapacity(2);
+        m_children.uncheckedAppend(WTFMove(leftSide));
+        m_children.uncheckedAppend(WTFMove(rightSide));
+    }
 
-        ASSERT(leftSide->category() < CalculationCategory::Other);
-        ASSERT(rightSide->category() < CalculationCategory::Other);
+    CSSCalcOperation(CalculationCategory category, CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& children)
+        : CSSCalcExpressionNode(category, isIntegerResult(op, children))
+        , m_operator(op)
+        , m_children(WTFMove(children))
+    {
+    }
 
-        auto newCategory = determineCategory(*leftSide, *rightSide, op);
-        if (newCategory == CalculationCategory::Other)
-            return nullptr;
+    Type type() const final { return CssCalcOperation; }
 
-        return adoptRef(new CSSCalcOperation(newCategory, op, leftSide.releaseNonNull(), rightSide.releaseNonNull()));
+    bool isZero() const final
+    {
+        return !doubleValue();
     }
 
-    static RefPtr<CSSCalcOperation> createMinOrMax(CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& values, CalculationCategory destinationCategory)
-    {
-        ASSERT(op == CalcOperator::Min || op == CalcOperator::Max);
+    bool equals(const CSSCalcExpressionNode&) const final;
 
-        Optional<CalculationCategory> category = WTF::nullopt;
-        for (auto& value : values) {
-            auto valueCategory = resolvedTypeForMinOrMax(value->category(), destinationCategory);
+    std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData&) const final;
 
-            ASSERT(valueCategory < CalculationCategory::Other);
-            if (!category) {
-                if (valueCategory == CalculationCategory::Other)
-                    return nullptr;
-                category = valueCategory;
-            }
+    CSSPrimitiveValue::UnitType primitiveType() const final;
+    double doubleValue() const final;
+    double computeLengthPx(const CSSToLengthConversionData&) const final;
 
-            if (category != valueCategory) {
-                if (isSamePair(category.value(), valueCategory, CalculationCategory::Length, CalculationCategory::PercentLength)) {
-                    category = CalculationCategory::PercentLength;
-                    continue;
-                }
-                if (isSamePair(category.value(), valueCategory, CalculationCategory::Number, CalculationCategory::PercentNumber)) {
-                    category = CalculationCategory::PercentNumber;
-                    continue;
-                }
-                return nullptr;
-            }
-        }
+    void collectDirectComputationalDependencies(HashSet<CSSPropertyID>&) const final;
+    void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>&) const final;
 
-        return adoptRef(new CSSCalcOperation(category.value(), op, WTFMove(values)));
+    String customCSSText() const final;
+
+    static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide)
+    {
+        if (leftSide.category() == CalculationCategory::Number)
+            return &leftSide;
+        if (rightSide.category() == CalculationCategory::Number)
+            return &rightSide;
+        return nullptr;
     }
 
-    static RefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
+    double evaluate(const Vector<double>& children) const
     {
-        if (!leftSide || !rightSide)
-            return nullptr;
+        return evaluateOperator(m_operator, children);
+    }
 
-        auto leftCategory = leftSide->category();
-        auto rightCategory = rightSide->category();
-        ASSERT(leftCategory < CalculationCategory::Other);
-        ASSERT(rightCategory < CalculationCategory::Other);
+    static double evaluateOperator(CalcOperator, const Vector<double>&);
+    static String buildCssText(Vector<String>, CalcOperator);
 
-        bool isInteger = isIntegerResult(op, *leftSide, *rightSide);
+    const CalcOperator m_operator;
+    Vector<Ref<CSSCalcExpressionNode>> m_children;
+};
 
-        // Simplify numbers.
-        if (leftCategory == CalculationCategory::Number && rightCategory == CalculationCategory::Number) {
-            CSSPrimitiveValue::UnitType evaluationType = CSSPrimitiveValue::CSS_NUMBER;
-            return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftSide->doubleValue(), rightSide->doubleValue() }), evaluationType, isInteger);
-        }
+RefPtr<CSSCalcOperation> CSSCalcOperation::create(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
+{
+    if (!leftSide || !rightSide)
+        return nullptr;
 
-        // Simplify addition and subtraction between same types.
-        if (op == CalcOperator::Add || op == CalcOperator::Subtract) {
-            if (leftCategory == rightSide->category()) {
-                CSSPrimitiveValue::UnitType leftType = leftSide->primitiveType();
-                if (hasDoubleValue(leftType)) {
-                    CSSPrimitiveValue::UnitType 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::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(op, { leftValue, rightValue }), canonicalType, isInteger);
-                        }
-                    }
-                }
-            }
-        } else {
-            // Simplify multiplying or dividing by a number for simplifiable types.
-            ASSERT(op == CalcOperator::Multiply || op == CalcOperator::Divide);
-            auto* numberSide = getNumberSide(*leftSide, *rightSide);
-            if (!numberSide)
-                return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
-            if (numberSide == leftSide && op == CalcOperator::Divide)
-                return nullptr;
-            auto& otherSide = leftSide == numberSide ? *rightSide : *leftSide;
+    ASSERT(leftSide->category() < CalculationCategory::Other);
+    ASSERT(rightSide->category() < CalculationCategory::Other);
 
-            double number = numberSide->doubleValue();
-            if (!std::isfinite(number))
-                return nullptr;
-            if (op == CalcOperator::Divide && !number)
-                return nullptr;
+    auto newCategory = determineCategory(*leftSide, *rightSide, op);
+    if (newCategory == CalculationCategory::Other)
+        return nullptr;
 
-            auto otherType = otherSide.primitiveType();
-            if (hasDoubleValue(otherType))
-                return CSSCalcPrimitiveValue::create(evaluateOperator(op, { otherSide.doubleValue(), number }), otherType, isInteger);
-        }
+    return adoptRef(new CSSCalcOperation(newCategory, op, leftSide.releaseNonNull(), rightSide.releaseNonNull()));
+}
 
-        return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
-    }
+RefPtr<CSSCalcOperation> CSSCalcOperation::createMinOrMax(CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& values, CalculationCategory destinationCategory)
+{
+    ASSERT(op == CalcOperator::Min || op == CalcOperator::Max);
 
-private:
-    bool isZero() const final
-    {
-        return !doubleValue();
-    }
+    Optional<CalculationCategory> category = WTF::nullopt;
+    for (auto& value : values) {
+        auto valueCategory = resolvedTypeForMinOrMax(value->category(), destinationCategory);
 
-    std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final
-    {
-        Vector<std::unique_ptr<CalcExpressionNode>> nodes;
-        nodes.reserveInitialCapacity(m_children.size());
-
-        for (auto& child : m_children) {
-            auto node = child->createCalcExpression(conversionData);
-            if (!node)
+        ASSERT(valueCategory < CalculationCategory::Other);
+        if (!category) {
+            if (valueCategory == CalculationCategory::Other)
                 return nullptr;
-            nodes.uncheckedAppend(WTFMove(node));
+            category = valueCategory;
         }
-        return makeUnique<CalcExpressionOperation>(WTFMove(nodes), m_operator);
-    }
 
-    double doubleValue() const final
-    {
-        Vector<double> doubleValues;
-        for (auto& child : m_children)
-            doubleValues.append(child->doubleValue());
-        return evaluate(doubleValues);
+        if (category != valueCategory) {
+            if (isSamePair(category.value(), valueCategory, CalculationCategory::Length, CalculationCategory::PercentLength)) {
+                category = CalculationCategory::PercentLength;
+                continue;
+            }
+            if (isSamePair(category.value(), valueCategory, CalculationCategory::Number, CalculationCategory::PercentNumber)) {
+                category = CalculationCategory::PercentNumber;
+                continue;
+            }
+            return nullptr;
+        }
     }
 
-    double computeLengthPx(const CSSToLengthConversionData& conversionData) const final
-    {
-        Vector<double> doubleValues;
-        for (auto& child : m_children)
-            doubleValues.append(child->computeLengthPx(conversionData));
-        return evaluate(doubleValues);
-    }
+    return adoptRef(new CSSCalcOperation(category.value(), op, WTFMove(values)));
+}
 
-    void collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const final
-    {
-        for (auto& child : m_children)
-            child->collectDirectComputationalDependencies(values);
-    }
+RefPtr<CSSCalcExpressionNode> CSSCalcOperation::createSimplified(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
+{
+    if (!leftSide || !rightSide)
+        return nullptr;
 
-    void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const final
-    {
-        for (auto& child : m_children)
-            child->collectDirectRootComputationalDependencies(values);
+    auto leftCategory = leftSide->category();
+    auto rightCategory = rightSide->category();
+    ASSERT(leftCategory < CalculationCategory::Other);
+    ASSERT(rightCategory < CalculationCategory::Other);
+
+    bool isInteger = isIntegerResult(op, *leftSide, *rightSide);
+
+    // Simplify numbers.
+    if (leftCategory == CalculationCategory::Number && rightCategory == CalculationCategory::Number) {
+        CSSPrimitiveValue::UnitType evaluationType = CSSPrimitiveValue::CSS_NUMBER;
+        return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftSide->doubleValue(), rightSide->doubleValue() }), evaluationType, isInteger);
     }
 
-    static String buildCssText(Vector<String> childExpressions, CalcOperator op)
-    {
-        StringBuilder result;
-        result.append('(');
-        switch (op) {
-        case CalcOperator::Add:
-        case CalcOperator::Subtract:
-        case CalcOperator::Multiply:
-        case CalcOperator::Divide:
-            ASSERT(childExpressions.size() == 2);
-            result.append(childExpressions[0]);
-            result.append(' ');
-            result.append(static_cast<char>(op));
-            result.append(' ');
-            result.append(childExpressions[1]);
-            break;
-        case CalcOperator::Min:
-        case CalcOperator::Max:
-            ASSERT(!childExpressions.isEmpty());
-            const char* functionName = op == CalcOperator::Min ? "min(" : "max(";
-            result.append(functionName);
-            result.append(childExpressions[0]);
-            for (size_t i = 1; i < childExpressions.size(); ++i) {
-                result.append(',');
-                result.append(' ');
-                result.append(childExpressions[i]);
+    // Simplify addition and subtraction between same types.
+    if (op == CalcOperator::Add || op == CalcOperator::Subtract) {
+        if (leftCategory == rightSide->category()) {
+            CSSPrimitiveValue::UnitType leftType = leftSide->primitiveType();
+            if (hasDoubleValue(leftType)) {
+                CSSPrimitiveValue::UnitType 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::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(op, { leftValue, rightValue }), canonicalType, isInteger);
+                    }
+                }
             }
-            result.append(')');
         }
-        result.append(')');
+    } else {
+        // Simplify multiplying or dividing by a number for simplifiable types.
+        ASSERT(op == CalcOperator::Multiply || op == CalcOperator::Divide);
+        auto* numberSide = getNumberSide(*leftSide, *rightSide);
+        if (!numberSide)
+            return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
+        if (numberSide == leftSide && op == CalcOperator::Divide)
+            return nullptr;
+        auto& otherSide = leftSide == numberSide ? *rightSide : *leftSide;
 
-        return result.toString();
-    }
+        double number = numberSide->doubleValue();
+        if (!std::isfinite(number))
+            return nullptr;
+        if (op == CalcOperator::Divide && !number)
+            return nullptr;
 
-    String customCSSText() const final
-    {
-        Vector<String> cssTexts;
-        for (auto& child : m_children)
-            cssTexts.append(child->customCSSText());
-        return buildCssText(cssTexts, m_operator);
+        auto otherType = otherSide.primitiveType();
+        if (hasDoubleValue(otherType))
+            return CSSCalcPrimitiveValue::create(evaluateOperator(op, { otherSide.doubleValue(), number }), otherType, isInteger);
     }
 
-    bool equals(const CSSCalcExpressionNode& exp) const final
-    {
-        if (type() != exp.type())
-            return false;
+    return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
+}
 
-        const CSSCalcOperation& other = static_cast<const CSSCalcOperation&>(exp);
-
-        if (m_children.size() != other.m_children.size() || m_operator != other.m_operator)
-            return false;
-
-        for (size_t i = 0; i < m_children.size(); ++i) {
-            if (!compareCSSValue(m_children[i], other.m_children[i]))
-                return false;
-        }
-        return true;
-    }
-
-    Type type() const final { return CssCalcOperation; }
-
-    CSSPrimitiveValue::UnitType primitiveType() const final
-    {
-        switch (category()) {
-        case CalculationCategory::Number:
+CSSPrimitiveValue::UnitType CSSCalcOperation::primitiveType() const
+{
+    switch (category()) {
+    case CalculationCategory::Number:
 #if !ASSERT_DISABLED
-            for (auto& child : m_children)
-                ASSERT(child->category() == CalculationCategory::Number);
+        for (auto& child : m_children)
+            ASSERT(child->category() == CalculationCategory::Number);
 #endif
-            return CSSPrimitiveValue::CSS_NUMBER;
-        case CalculationCategory::Length:
-        case CalculationCategory::Percent: {
-            if (m_children.isEmpty())
+        return CSSPrimitiveValue::CSS_NUMBER;
+    case CalculationCategory::Length:
+    case CalculationCategory::Percent: {
+        if (m_children.isEmpty())
+            return CSSPrimitiveValue::CSS_UNKNOWN;
+        if (m_children.size() == 2) {
+            if (m_children[0]->category() == CalculationCategory::Number)
+                return m_children[1]->primitiveType();
+            if (m_children[1]->category() == CalculationCategory::Number)
+                return m_children[0]->primitiveType();
+        }
+        CSSPrimitiveValue::UnitType firstType = m_children[0]->primitiveType();
+        for (auto& child : m_children) {
+            if (firstType != child->primitiveType())
                 return CSSPrimitiveValue::CSS_UNKNOWN;
-            if (m_children.size() == 2) {
-                if (m_children[0]->category() == CalculationCategory::Number)
-                    return m_children[1]->primitiveType();
-                if (m_children[1]->category() == CalculationCategory::Number)
-                    return m_children[0]->primitiveType();
-            }
-            CSSPrimitiveValue::UnitType firstType = m_children[0]->primitiveType();
-            for (auto& child : m_children) {
-                if (firstType != child->primitiveType())
-                    return CSSPrimitiveValue::CSS_UNKNOWN;
-            }
-            return firstType;
         }
-        case CalculationCategory::Angle:
-            return CSSPrimitiveValue::CSS_DEG;
-        case CalculationCategory::Time:
-            return CSSPrimitiveValue::CSS_MS;
-        case CalculationCategory::Frequency:
-            return CSSPrimitiveValue::CSS_HZ;
-        case CalculationCategory::PercentLength:
-        case CalculationCategory::PercentNumber:
-        case CalculationCategory::Other:
-            return CSSPrimitiveValue::CSS_UNKNOWN;
-        }
-        ASSERT_NOT_REACHED();
+        return firstType;
+    }
+    case CalculationCategory::Angle:
+        return CSSPrimitiveValue::CSS_DEG;
+    case CalculationCategory::Time:
+        return CSSPrimitiveValue::CSS_MS;
+    case CalculationCategory::Frequency:
+        return CSSPrimitiveValue::CSS_HZ;
+    case CalculationCategory::PercentLength:
+    case CalculationCategory::PercentNumber:
+    case CalculationCategory::Other:
         return CSSPrimitiveValue::CSS_UNKNOWN;
     }
+    ASSERT_NOT_REACHED();
+    return CSSPrimitiveValue::CSS_UNKNOWN;
+}
 
-    CSSCalcOperation(CalculationCategory category, CalcOperator op, Ref<CSSCalcExpressionNode>&& leftSide, Ref<CSSCalcExpressionNode>&& rightSide)
-        : CSSCalcExpressionNode(category, isIntegerResult(op, leftSide.get(), rightSide.get()))
-        , m_operator(op)
-    {
-        m_children.reserveInitialCapacity(2);
-        m_children.uncheckedAppend(WTFMove(leftSide));
-        m_children.uncheckedAppend(WTFMove(rightSide));
-    }
+std::unique_ptr<CalcExpressionNode> CSSCalcOperation::createCalcExpression(const CSSToLengthConversionData& conversionData) const
+{
+    Vector<std::unique_ptr<CalcExpressionNode>> nodes;
+    nodes.reserveInitialCapacity(m_children.size());
 
-    CSSCalcOperation(CalculationCategory category, CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& children)
-        : CSSCalcExpressionNode(category, isIntegerResult(op, children))
-        , m_operator(op)
-        , m_children(WTFMove(children))
-    {
+    for (auto& child : m_children) {
+        auto node = child->createCalcExpression(conversionData);
+        if (!node)
+            return nullptr;
+        nodes.uncheckedAppend(WTFMove(node));
     }
+    return makeUnique<CalcExpressionOperation>(WTFMove(nodes), m_operator);
+}
 
-    static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide)
-    {
-        if (leftSide.category() == CalculationCategory::Number)
-            return &leftSide;
-        if (rightSide.category() == CalculationCategory::Number)
-            return &rightSide;
-        return nullptr;
-    }
+double CSSCalcOperation::doubleValue() const
+{
+    Vector<double> doubleValues;
+    for (auto& child : m_children)
+        doubleValues.append(child->doubleValue());
+    return evaluate(doubleValues);
+}
 
-    double evaluate(const Vector<double>& children) const
-    {
-        return evaluateOperator(m_operator, children);
-    }
+double CSSCalcOperation::computeLengthPx(const CSSToLengthConversionData& conversionData) const
+{
+    Vector<double> doubleValues;
+    for (auto& child : m_children)
+        doubleValues.append(child->computeLengthPx(conversionData));
+    return evaluate(doubleValues);
+}
 
-    static double evaluateOperator(CalcOperator op, const Vector<double>& children)
-    {
-        switch (op) {
-        case CalcOperator::Add:
-            ASSERT(children.size() == 2);
-            return children[0] + children[1];
-        case CalcOperator::Subtract:
-            ASSERT(children.size() == 2);
-            return children[0] - children[1];
-        case CalcOperator::Multiply:
-            ASSERT(children.size() == 2);
-            return children[0] * children[1];
-        case CalcOperator::Divide:
-            ASSERT(children.size() == 1 || children.size() == 2);
-            if (children.size() == 1)
-                return std::numeric_limits<double>::quiet_NaN();
-            return children[0] / children[1];
-        case CalcOperator::Min: {
-            if (children.isEmpty())
-                return std::numeric_limits<double>::quiet_NaN();
-            double minimum = children[0];
-            for (auto child : children)
-                minimum = std::min(minimum, child);
-            return minimum;
+void CSSCalcOperation::collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const
+{
+    for (auto& child : m_children)
+        child->collectDirectComputationalDependencies(values);
+}
+
+void CSSCalcOperation::collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const
+{
+    for (auto& child : m_children)
+        child->collectDirectRootComputationalDependencies(values);
+}
+
+String CSSCalcOperation::buildCssText(Vector<String> childExpressions, CalcOperator op)
+{
+    StringBuilder result;
+    result.append('(');
+    switch (op) {
+    case CalcOperator::Add:
+    case CalcOperator::Subtract:
+    case CalcOperator::Multiply:
+    case CalcOperator::Divide:
+        ASSERT(childExpressions.size() == 2);
+        result.append(childExpressions[0]);
+        result.append(' ');
+        result.append(static_cast<char>(op));
+        result.append(' ');
+        result.append(childExpressions[1]);
+        break;
+    case CalcOperator::Min:
+    case CalcOperator::Max:
+        ASSERT(!childExpressions.isEmpty());
+        const char* functionName = op == CalcOperator::Min ? "min(" : "max(";
+        result.append(functionName);
+        result.append(childExpressions[0]);
+        for (size_t i = 1; i < childExpressions.size(); ++i) {
+            result.append(',');
+            result.append(' ');
+            result.append(childExpressions[i]);
         }
-        case CalcOperator::Max: {
-            if (children.isEmpty())
-                return std::numeric_limits<double>::quiet_NaN();
-            double maximum = children[0];
-            for (auto child : children)
-                maximum = std::max(maximum, child);
-            return maximum;
-        }
-        }
-        ASSERT_NOT_REACHED();
-        return 0;
+        result.append(')');
     }
+    result.append(')');
 
-    const CalcOperator m_operator;
-    Vector<Ref<CSSCalcExpressionNode>> m_children;
-};
+    return result.toString();
+}
 
-static ParseState checkDepthAndIndex(int* depth, CSSParserTokenRange tokens)
+String CSSCalcOperation::customCSSText() const
 {
-    (*depth)++;
-    if (tokens.atEnd())
-        return NoMoreTokens;
-    if (*depth > maxExpressionDepth)
-        return TooDeep;
-    return OK;
+    Vector<String> cssTexts;
+    for (auto& child : m_children)
+        cssTexts.append(child->customCSSText());
+    return buildCssText(cssTexts, m_operator);
 }
 
+bool CSSCalcOperation::equals(const CSSCalcExpressionNode& exp) const
+{
+    if (type() != exp.type())
+        return false;
+
+    const CSSCalcOperation& other = static_cast<const CSSCalcOperation&>(exp);
+
+    if (m_children.size() != other.m_children.size() || m_operator != other.m_operator)
+        return false;
+
+    for (size_t i = 0; i < m_children.size(); ++i) {
+        if (!compareCSSValue(m_children[i], other.m_children[i]))
+            return false;
+    }
+    return true;
+}
+
+double CSSCalcOperation::evaluateOperator(CalcOperator op, const Vector<double>& children)
+{
+    switch (op) {
+    case CalcOperator::Add:
+        ASSERT(children.size() == 2);
+        return children[0] + children[1];
+    case CalcOperator::Subtract:
+        ASSERT(children.size() == 2);
+        return children[0] - children[1];
+    case CalcOperator::Multiply:
+        ASSERT(children.size() == 2);
+        return children[0] * children[1];
+    case CalcOperator::Divide:
+        ASSERT(children.size() == 1 || children.size() == 2);
+        if (children.size() == 1)
+            return std::numeric_limits<double>::quiet_NaN();
+        return children[0] / children[1];
+    case CalcOperator::Min: {
+        if (children.isEmpty())
+            return std::numeric_limits<double>::quiet_NaN();
+        double minimum = children[0];
+        for (auto child : children)
+            minimum = std::min(minimum, child);
+        return minimum;
+    }
+    case CalcOperator::Max: {
+        if (children.isEmpty())
+            return std::numeric_limits<double>::quiet_NaN();
+        double maximum = children[0];
+        for (auto child : children)
+            maximum = std::max(maximum, child);
+        return maximum;
+    }
+    }
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+
 class CSSCalcExpressionNodeParser {
 public:
     explicit CSSCalcExpressionNodeParser(CalculationCategory destinationCategory)
@@ -731,19 +728,7 @@
         : m_destinationCategory(destinationCategory)
     { }
 
-    RefPtr<CSSCalcExpressionNode> parseCalc(CSSParserTokenRange tokens, CSSValueID function)
-    {
-        Value result;
-        tokens.consumeWhitespace();
-        bool ok = false;
-        if (function == CSSValueCalc || function == CSSValueWebkitCalc)
-            ok = parseValueExpression(tokens, 0, &result);
-        else if (function == CSSValueMin || function == CSSValueMax)
-            ok = parseMinMaxExpression(tokens, function, 0, &result);
-        if (!ok || !tokens.atEnd())
-            return nullptr;
-        return result.value;
-    }
+    RefPtr<CSSCalcExpressionNode> parseCalc(CSSParserTokenRange, CSSValueID function);
     
 private:
     struct Value {
@@ -756,143 +741,176 @@
             return token.delimiter();
         return 0;
     }
+
+    bool parseValue(CSSParserTokenRange&, Value* result);
+    bool parseValueTerm(CSSParserTokenRange&, int depth, Value* result);
+    bool parseValueMultiplicativeExpression(CSSParserTokenRange&, int depth, Value* result);
+    bool parseAdditiveValueExpression(CSSParserTokenRange&, int depth, Value* result);
+    bool parseMinMaxExpression(CSSParserTokenRange&, CSSValueID minMaxFunction, int depth, Value* result);
+    bool parseValueExpression(CSSParserTokenRange&, int depth, Value* result);
+
+    CalculationCategory m_destinationCategory;
+};
+
+
+RefPtr<CSSCalcExpressionNode> CSSCalcExpressionNodeParser::parseCalc(CSSParserTokenRange tokens, CSSValueID function)
+{
+    Value result;
+    tokens.consumeWhitespace();
+    bool ok = false;
+    if (function == CSSValueCalc || function == CSSValueWebkitCalc)
+        ok = parseValueExpression(tokens, 0, &result);
+    else if (function == CSSValueMin || function == CSSValueMax)
+        ok = parseMinMaxExpression(tokens, function, 0, &result);
+    if (!ok || !tokens.atEnd())
+        return nullptr;
+    return result.value;
+}
+
+bool CSSCalcExpressionNodeParser::parseValue(CSSParserTokenRange& tokens, Value* result)
+{
+    CSSParserToken token = tokens.consumeIncludingWhitespace();
+    if (!(token.type() == NumberToken || token.type() == PercentageToken || token.type() == DimensionToken))
+        return false;
     
-    bool parseValue(CSSParserTokenRange& tokens, Value* result)
-    {
-        CSSParserToken token = tokens.consumeIncludingWhitespace();
-        if (!(token.type() == NumberToken || token.type() == PercentageToken || token.type() == DimensionToken))
-            return false;
-        
-        CSSPrimitiveValue::UnitType type = token.unitType();
-        if (unitCategory(type) == CalculationCategory::Other)
-            return false;
-        
-        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;
-    }
+    CSSPrimitiveValue::UnitType type = token.unitType();
+    if (unitCategory(type) == CalculationCategory::Other)
+        return false;
     
-    bool parseValueTerm(CSSParserTokenRange& tokens, int depth, Value* result)
-    {
-        if (checkDepthAndIndex(&depth, tokens) != OK)
-            return false;
+    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;
+}
 
-        auto functionId = tokens.peek().functionId();
-        
-        if (tokens.peek().type() == LeftParenthesisToken || functionId == CSSValueCalc) {
-            CSSParserTokenRange innerRange = tokens.consumeBlock();
-            tokens.consumeWhitespace();
-            innerRange.consumeWhitespace();
-            return parseValueExpression(innerRange, depth, result);
-        }
+static ParseState checkDepthAndIndex(int* depth, CSSParserTokenRange tokens)
+{
+    (*depth)++;
+    if (tokens.atEnd())
+        return NoMoreTokens;
+    if (*depth > maxExpressionDepth)
+        return TooDeep;
+    return OK;
+}
 
-        if (functionId == CSSValueMax || functionId == CSSValueMin) {
-            CSSParserTokenRange innerRange = tokens.consumeBlock();
-            tokens.consumeWhitespace();
-            innerRange.consumeWhitespace();
-            return parseMinMaxExpression(innerRange, functionId, depth, result);
-        }
-        
-        return parseValue(tokens, result);
+bool CSSCalcExpressionNodeParser::parseValueTerm(CSSParserTokenRange& tokens, int depth, Value* result)
+{
+    if (checkDepthAndIndex(&depth, tokens) != OK)
+        return false;
+
+    auto functionId = tokens.peek().functionId();
+    
+    if (tokens.peek().type() == LeftParenthesisToken || functionId == CSSValueCalc) {
+        CSSParserTokenRange innerRange = tokens.consumeBlock();
+        tokens.consumeWhitespace();
+        innerRange.consumeWhitespace();
+        return parseValueExpression(innerRange, depth, result);
     }
+
+    if (functionId == CSSValueMax || functionId == CSSValueMin) {
+        CSSParserTokenRange innerRange = tokens.consumeBlock();
+        tokens.consumeWhitespace();
+        innerRange.consumeWhitespace();
+        return parseMinMaxExpression(innerRange, functionId, depth, result);
+    }
     
-    bool parseValueMultiplicativeExpression(CSSParserTokenRange& tokens, int depth, Value* result)
-    {
-        if (checkDepthAndIndex(&depth, tokens) != OK)
-            return false;
+    return parseValue(tokens, result);
+}
+
+bool CSSCalcExpressionNodeParser::parseValueMultiplicativeExpression(CSSParserTokenRange& tokens, int depth, Value* result)
+{
+    if (checkDepthAndIndex(&depth, tokens) != OK)
+        return false;
+    
+    if (!parseValueTerm(tokens, depth, result))
+        return false;
+    
+    while (!tokens.atEnd()) {
+        char operatorCharacter = operatorValue(tokens.peek());
+        if (operatorCharacter != static_cast<char>(CalcOperator::Multiply) && operatorCharacter != static_cast<char>(CalcOperator::Divide))
+            break;
+        tokens.consumeIncludingWhitespace();
         
-        if (!parseValueTerm(tokens, depth, result))
+        Value rhs;
+        if (!parseValueTerm(tokens, depth, &rhs))
             return false;
         
-        while (!tokens.atEnd()) {
-            char operatorCharacter = operatorValue(tokens.peek());
-            if (operatorCharacter != static_cast<char>(CalcOperator::Multiply) && operatorCharacter != static_cast<char>(CalcOperator::Divide))
-                break;
-            tokens.consumeIncludingWhitespace();
-            
-            Value rhs;
-            if (!parseValueTerm(tokens, depth, &rhs))
-                return false;
-            
-            result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
+        result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
 
-            if (!result->value)
-                return false;
-        }
-        
-        return true;
+        if (!result->value)
+            return false;
     }
     
-    bool parseAdditiveValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
-    {
-        if (checkDepthAndIndex(&depth, tokens) != OK)
+    return true;
+}
+
+bool CSSCalcExpressionNodeParser::parseAdditiveValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
+{
+    if (checkDepthAndIndex(&depth, tokens) != OK)
+        return false;
+    
+    if (!parseValueMultiplicativeExpression(tokens, depth, result))
+        return false;
+    
+    while (!tokens.atEnd()) {
+        char operatorCharacter = operatorValue(tokens.peek());
+        if (operatorCharacter != static_cast<char>(CalcOperator::Add) && operatorCharacter != static_cast<char>(CalcOperator::Subtract))
+            break;
+        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, &rhs))
             return false;
         
-        if (!parseValueMultiplicativeExpression(tokens, depth, result))
+        result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
+        if (!result->value)
             return false;
-        
-        while (!tokens.atEnd()) {
-            char operatorCharacter = operatorValue(tokens.peek());
-            if (operatorCharacter != static_cast<char>(CalcOperator::Add) && operatorCharacter != static_cast<char>(CalcOperator::Subtract))
-                break;
-            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, &rhs))
-                return false;
-            
-            result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
-            if (!result->value)
-                return false;
-        }
-        
-        return true;
     }
+    
+    return true;
+}
 
-    bool parseMinMaxExpression(CSSParserTokenRange& tokens, CSSValueID minMaxFunction, int depth, Value* result)
-    {
-        if (checkDepthAndIndex(&depth, tokens) != OK)
+bool CSSCalcExpressionNodeParser::parseMinMaxExpression(CSSParserTokenRange& tokens, CSSValueID minMaxFunction, int depth, Value* result)
+{
+    if (checkDepthAndIndex(&depth, tokens) != OK)
+        return false;
+
+    CalcOperator op = (minMaxFunction == CSSValueMin) ? CalcOperator::Min : CalcOperator::Max;
+
+    Value value;
+    if (!parseValueExpression(tokens, depth, &value))
+        return false;
+
+    Vector<Ref<CSSCalcExpressionNode>> nodes;
+    nodes.append(value.value.releaseNonNull());
+
+    while (!tokens.atEnd()) {
+        tokens.consumeWhitespace();
+        if (tokens.consume().type() != CommaToken)
             return false;
+        tokens.consumeWhitespace();
 
-        CalcOperator op = (minMaxFunction == CSSValueMin) ? CalcOperator::Min : CalcOperator::Max;
-
-        Value value;
         if (!parseValueExpression(tokens, depth, &value))
             return false;
 
-        Vector<Ref<CSSCalcExpressionNode>> nodes;
         nodes.append(value.value.releaseNonNull());
+    }
 
-        while (!tokens.atEnd()) {
-            tokens.consumeWhitespace();
-            if (tokens.consume().type() != CommaToken)
-                return false;
-            tokens.consumeWhitespace();
+    result->value = CSSCalcOperation::createMinOrMax(op, WTFMove(nodes), m_destinationCategory);
+    return result->value;
+}
 
-            if (!parseValueExpression(tokens, depth, &value))
-                return false;
+bool CSSCalcExpressionNodeParser::parseValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
+{
+    return parseAdditiveValueExpression(tokens, depth, result);
+}
 
-            nodes.append(value.value.releaseNonNull());
-        }
 
-        result->value = CSSCalcOperation::createMinOrMax(op, WTFMove(nodes), m_destinationCategory);
-        return result->value;
-    }
-
-    bool parseValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
-    {
-        return parseAdditiveValueExpression(tokens, depth, result);
-    }
-
-    CalculationCategory m_destinationCategory;
-};
-
 static inline RefPtr<CSSCalcOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress)
 {
     return CSSCalcOperation::create(CalcOperator::Multiply, createCSS(length, style),
@@ -963,6 +981,34 @@
     return nullptr;
 }
 
+String CSSCalcValue::customCSSText() const
+{
+    auto _expression_ = m_expression->customCSSText();
+    if (_expression_[0] == '(')
+        return makeString("calc", _expression_);
+    return makeString("calc(", _expression_, ')');
+}
+
+bool CSSCalcValue::equals(const CSSCalcValue& other) const
+{
+    return compareCSSValue(m_expression, other.m_expression);
+}
+
+inline double CSSCalcValue::clampToPermittedRange(double value) const
+{
+    return m_shouldClampToNonNegative && value < 0 ? 0 : value;
+}
+
+double CSSCalcValue::doubleValue() const
+{
+    return clampToPermittedRange(m_expression->doubleValue());
+}
+
+double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const
+{
+    return clampToPermittedRange(m_expression->computeLengthPx(conversionData));
+}
+
 RefPtr<CSSCalcValue> CSSCalcValue::create(CSSValueID function, const CSSParserTokenRange& tokens, CalculationCategory destinationCategory, ValueRange range)
 {
     CSSCalcExpressionNodeParser parser(destinationCategory);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to