Changeset 251595 in webkit


Ignore:
Timestamp:
Oct 25, 2019 10:16:23 AM (5 years ago)
Author:
Simon Fraser
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):

Location:
trunk/Source/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r251594 r251595  
     12019-10-25  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Move code around in CSSCalculationValue.cpp
     4        https://bugs.webkit.org/show_bug.cgi?id=203397
     5
     6        Reviewed by Zalan Bujtas.
     7
     8        Large amounts of code were in inline (but virtual) functions in CSSCalcPrimitiveValue, CSSCalcOperation
     9        and CSSCalcExpressionNodeParser, making it hard to navigate around this file. Move code into
     10        out-of-line functions. No behavior changes.
     11
     12        * css/CSSCalculationValue.cpp:
     13        (WebCore::CSSCalcPrimitiveValue::createCalcExpression const):
     14        (WebCore::CSSCalcPrimitiveValue::doubleValue const):
     15        (WebCore::CSSCalcPrimitiveValue::computeLengthPx const):
     16        (WebCore::CSSCalcPrimitiveValue::collectDirectComputationalDependencies const):
     17        (WebCore::CSSCalcPrimitiveValue::collectDirectRootComputationalDependencies const):
     18        (WebCore::CSSCalcPrimitiveValue::equals const):
     19        (WebCore::CSSCalcOperation::create):
     20        (WebCore::CSSCalcOperation::createMinOrMax):
     21        (WebCore::CSSCalcOperation::createSimplified):
     22        (WebCore::CSSCalcOperation::primitiveType const):
     23        (WebCore::CSSCalcOperation::createCalcExpression const):
     24        (WebCore::CSSCalcOperation::doubleValue const):
     25        (WebCore::CSSCalcOperation::computeLengthPx const):
     26        (WebCore::CSSCalcOperation::collectDirectComputationalDependencies const):
     27        (WebCore::CSSCalcOperation::collectDirectRootComputationalDependencies const):
     28        (WebCore::CSSCalcOperation::buildCssText):
     29        (WebCore::CSSCalcOperation::customCSSText const):
     30        (WebCore::CSSCalcOperation::equals const):
     31        (WebCore::CSSCalcOperation::evaluateOperator):
     32        (WebCore::CSSCalcExpressionNodeParser::parseCalc):
     33        (WebCore::CSSCalcExpressionNodeParser::parseValue):
     34        (WebCore::checkDepthAndIndex):
     35        (WebCore::CSSCalcExpressionNodeParser::parseValueTerm):
     36        (WebCore::CSSCalcExpressionNodeParser::parseValueMultiplicativeExpression):
     37        (WebCore::CSSCalcExpressionNodeParser::parseAdditiveValueExpression):
     38        (WebCore::CSSCalcExpressionNodeParser::parseMinMaxExpression):
     39        (WebCore::CSSCalcExpressionNodeParser::parseValueExpression):
     40        (WebCore::CSSCalcValue::customCSSText const):
     41        (WebCore::CSSCalcValue::equals const):
     42        (WebCore::CSSCalcValue::clampToPermittedRange const):
     43        (WebCore::CSSCalcValue::doubleValue const):
     44        (WebCore::CSSCalcValue::computeLengthPx const):
     45
    1462019-10-25  youenn fablet  <youenn@apple.com>
    247
  • trunk/Source/WebCore/css/CSSCalculationValue.cpp

    r249013 r251595  
    150150}
    151151
    152 String CSSCalcValue::customCSSText() const
    153 {
    154     auto expression = m_expression->customCSSText();
    155     if (expression[0] == '(')
    156         return makeString("calc", expression);
    157     return makeString("calc(", expression, ')');
    158 }
    159 
    160 bool CSSCalcValue::equals(const CSSCalcValue& other) const
    161 {
    162     return compareCSSValue(m_expression, other.m_expression);
    163 }
    164 
    165 inline double CSSCalcValue::clampToPermittedRange(double value) const
    166 {
    167     return m_shouldClampToNonNegative && value < 0 ? 0 : value;
    168 }
    169 
    170 double CSSCalcValue::doubleValue() const
    171 {
    172     return clampToPermittedRange(m_expression->doubleValue());
    173 }
    174 
    175 double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const
    176 {
    177     return clampToPermittedRange(m_expression->computeLengthPx(conversionData));
    178 }
    179152
    180153class CSSCalcPrimitiveValue final : public CSSCalcExpressionNode {
     
    199172    }
    200173
     174    bool equals(const CSSCalcExpressionNode& other) const final;
     175    Type type() const final { return CssCalcPrimitiveValue; }
     176
     177    CSSPrimitiveValue::UnitType primitiveType() const final
     178    {
     179        return CSSPrimitiveValue::UnitType(m_value->primitiveType());
     180    }
     181
     182    std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData&) const final;
     183    double doubleValue() const final;
     184
     185    double computeLengthPx(const CSSToLengthConversionData&) const final;
     186    void collectDirectComputationalDependencies(HashSet<CSSPropertyID>&) const final;
     187    void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>&) const final;
     188
    201189    String customCSSText() const final
    202190    {
    203191        return m_value->cssText();
    204     }
    205 
    206     std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final
    207     {
    208         switch (category()) {
    209         case CalculationCategory::Number:
    210             return makeUnique<CalcExpressionNumber>(m_value->floatValue());
    211         case CalculationCategory::Length:
    212             return makeUnique<CalcExpressionLength>(Length(m_value->computeLength<float>(conversionData), WebCore::Fixed));
    213         case CalculationCategory::Percent:
    214         case CalculationCategory::PercentLength: {
    215             return makeUnique<CalcExpressionLength>(m_value->convertToLength<FixedFloatConversion | PercentConversion>(conversionData));
    216         }
    217         // Only types that could be part of a Length expression can be converted
    218         // to a CalcExpressionNode. CalculationCategory::PercentNumber makes no sense as a Length.
    219         case CalculationCategory::PercentNumber:
    220         case CalculationCategory::Angle:
    221         case CalculationCategory::Time:
    222         case CalculationCategory::Frequency:
    223         case CalculationCategory::Other:
    224             ASSERT_NOT_REACHED();
    225         }
    226         ASSERT_NOT_REACHED();
    227         return nullptr;
    228     }
    229 
    230     double doubleValue() const final
    231     {
    232         if (hasDoubleValue(primitiveType()))
    233             return m_value->doubleValue();
    234         ASSERT_NOT_REACHED();
    235         return 0;
    236     }
    237 
    238     double computeLengthPx(const CSSToLengthConversionData& conversionData) const final
    239     {
    240         switch (category()) {
    241         case CalculationCategory::Length:
    242             return m_value->computeLength<double>(conversionData);
    243         case CalculationCategory::Percent:
    244         case CalculationCategory::Number:
    245             return m_value->doubleValue();
    246         case CalculationCategory::PercentLength:
    247         case CalculationCategory::PercentNumber:
    248         case CalculationCategory::Angle:
    249         case CalculationCategory::Time:
    250         case CalculationCategory::Frequency:
    251         case CalculationCategory::Other:
    252             ASSERT_NOT_REACHED();
    253             break;
    254         }
    255         ASSERT_NOT_REACHED();
    256         return 0;
    257     }
    258 
    259     void collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const final
    260     {
    261         m_value->collectDirectComputationalDependencies(values);
    262     }
    263 
    264     void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const final
    265     {
    266         m_value->collectDirectRootComputationalDependencies(values);
    267     }
    268 
    269     bool equals(const CSSCalcExpressionNode& other) const final
    270     {
    271         if (type() != other.type())
    272             return false;
    273 
    274         return compareCSSValue(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value);
    275     }
    276 
    277     Type type() const final { return CssCalcPrimitiveValue; }
    278     CSSPrimitiveValue::UnitType primitiveType() const final
    279     {
    280         return CSSPrimitiveValue::UnitType(m_value->primitiveType());
    281192    }
    282193
     
    290201    Ref<CSSPrimitiveValue> m_value;
    291202};
     203
     204std::unique_ptr<CalcExpressionNode> CSSCalcPrimitiveValue::createCalcExpression(const CSSToLengthConversionData& conversionData) const
     205{
     206    switch (category()) {
     207    case CalculationCategory::Number:
     208        return makeUnique<CalcExpressionNumber>(m_value->floatValue());
     209    case CalculationCategory::Length:
     210        return makeUnique<CalcExpressionLength>(Length(m_value->computeLength<float>(conversionData), WebCore::Fixed));
     211    case CalculationCategory::Percent:
     212    case CalculationCategory::PercentLength: {
     213        return makeUnique<CalcExpressionLength>(m_value->convertToLength<FixedFloatConversion | PercentConversion>(conversionData));
     214    }
     215    // Only types that could be part of a Length expression can be converted
     216    // to a CalcExpressionNode. CalculationCategory::PercentNumber makes no sense as a Length.
     217    case CalculationCategory::PercentNumber:
     218    case CalculationCategory::Angle:
     219    case CalculationCategory::Time:
     220    case CalculationCategory::Frequency:
     221    case CalculationCategory::Other:
     222        ASSERT_NOT_REACHED();
     223    }
     224    ASSERT_NOT_REACHED();
     225    return nullptr;
     226}
     227
     228double CSSCalcPrimitiveValue::doubleValue() const
     229{
     230    if (hasDoubleValue(primitiveType()))
     231        return m_value->doubleValue();
     232    ASSERT_NOT_REACHED();
     233    return 0;
     234}
     235
     236double CSSCalcPrimitiveValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const
     237{
     238    switch (category()) {
     239    case CalculationCategory::Length:
     240        return m_value->computeLength<double>(conversionData);
     241    case CalculationCategory::Percent:
     242    case CalculationCategory::Number:
     243        return m_value->doubleValue();
     244    case CalculationCategory::PercentLength:
     245    case CalculationCategory::PercentNumber:
     246    case CalculationCategory::Angle:
     247    case CalculationCategory::Time:
     248    case CalculationCategory::Frequency:
     249    case CalculationCategory::Other:
     250        ASSERT_NOT_REACHED();
     251        break;
     252    }
     253    ASSERT_NOT_REACHED();
     254    return 0;
     255}
     256
     257void CSSCalcPrimitiveValue::collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const
     258{
     259    m_value->collectDirectComputationalDependencies(values);
     260}
     261
     262void CSSCalcPrimitiveValue::collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const
     263{
     264    m_value->collectDirectRootComputationalDependencies(values);
     265}
     266
     267bool CSSCalcPrimitiveValue::equals(const CSSCalcExpressionNode& other) const
     268{
     269    if (type() != other.type())
     270        return false;
     271
     272    return compareCSSValue(m_value, static_cast<const CSSCalcPrimitiveValue&>(other).m_value);
     273}
     274
     275
     276
     277
    292278
    293279static const CalculationCategory addSubtractResult[static_cast<unsigned>(CalculationCategory::Angle)][static_cast<unsigned>(CalculationCategory::Angle)] = {
     
    387373    WTF_MAKE_FAST_ALLOCATED;
    388374public:
    389     static RefPtr<CSSCalcOperation> create(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
    390     {
    391         if (!leftSide || !rightSide)
    392             return nullptr;
    393 
    394         ASSERT(leftSide->category() < CalculationCategory::Other);
    395         ASSERT(rightSide->category() < CalculationCategory::Other);
    396 
    397         auto newCategory = determineCategory(*leftSide, *rightSide, op);
    398         if (newCategory == CalculationCategory::Other)
    399             return nullptr;
    400 
    401         return adoptRef(new CSSCalcOperation(newCategory, op, leftSide.releaseNonNull(), rightSide.releaseNonNull()));
    402     }
    403 
    404     static RefPtr<CSSCalcOperation> createMinOrMax(CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& values, CalculationCategory destinationCategory)
    405     {
    406         ASSERT(op == CalcOperator::Min || op == CalcOperator::Max);
    407 
    408         Optional<CalculationCategory> category = WTF::nullopt;
    409         for (auto& value : values) {
    410             auto valueCategory = resolvedTypeForMinOrMax(value->category(), destinationCategory);
    411 
    412             ASSERT(valueCategory < CalculationCategory::Other);
    413             if (!category) {
    414                 if (valueCategory == CalculationCategory::Other)
    415                     return nullptr;
    416                 category = valueCategory;
    417             }
    418 
    419             if (category != valueCategory) {
    420                 if (isSamePair(category.value(), valueCategory, CalculationCategory::Length, CalculationCategory::PercentLength)) {
    421                     category = CalculationCategory::PercentLength;
    422                     continue;
    423                 }
    424                 if (isSamePair(category.value(), valueCategory, CalculationCategory::Number, CalculationCategory::PercentNumber)) {
    425                     category = CalculationCategory::PercentNumber;
    426                     continue;
    427                 }
    428                 return nullptr;
    429             }
    430         }
    431 
    432         return adoptRef(new CSSCalcOperation(category.value(), op, WTFMove(values)));
    433     }
    434 
    435     static RefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
    436     {
    437         if (!leftSide || !rightSide)
    438             return nullptr;
    439 
    440         auto leftCategory = leftSide->category();
    441         auto rightCategory = rightSide->category();
    442         ASSERT(leftCategory < CalculationCategory::Other);
    443         ASSERT(rightCategory < CalculationCategory::Other);
    444 
    445         bool isInteger = isIntegerResult(op, *leftSide, *rightSide);
    446 
    447         // Simplify numbers.
    448         if (leftCategory == CalculationCategory::Number && rightCategory == CalculationCategory::Number) {
    449             CSSPrimitiveValue::UnitType evaluationType = CSSPrimitiveValue::CSS_NUMBER;
    450             return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftSide->doubleValue(), rightSide->doubleValue() }), evaluationType, isInteger);
    451         }
    452 
    453         // Simplify addition and subtraction between same types.
    454         if (op == CalcOperator::Add || op == CalcOperator::Subtract) {
    455             if (leftCategory == rightSide->category()) {
    456                 CSSPrimitiveValue::UnitType leftType = leftSide->primitiveType();
    457                 if (hasDoubleValue(leftType)) {
    458                     CSSPrimitiveValue::UnitType rightType = rightSide->primitiveType();
    459                     if (leftType == rightType)
    460                         return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftSide->doubleValue(), rightSide->doubleValue() }), leftType, isInteger);
    461                     CSSPrimitiveValue::UnitCategory leftUnitCategory = CSSPrimitiveValue::unitCategory(leftType);
    462                     if (leftUnitCategory != CSSPrimitiveValue::UOther && leftUnitCategory == CSSPrimitiveValue::unitCategory(rightType)) {
    463                         CSSPrimitiveValue::UnitType canonicalType = CSSPrimitiveValue::canonicalUnitTypeForCategory(leftUnitCategory);
    464                         if (canonicalType != CSSPrimitiveValue::CSS_UNKNOWN) {
    465                             double leftValue = leftSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(leftType);
    466                             double rightValue = rightSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(rightType);
    467                             return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftValue, rightValue }), canonicalType, isInteger);
    468                         }
    469                     }
    470                 }
    471             }
    472         } else {
    473             // Simplify multiplying or dividing by a number for simplifiable types.
    474             ASSERT(op == CalcOperator::Multiply || op == CalcOperator::Divide);
    475             auto* numberSide = getNumberSide(*leftSide, *rightSide);
    476             if (!numberSide)
    477                 return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
    478             if (numberSide == leftSide && op == CalcOperator::Divide)
    479                 return nullptr;
    480             auto& otherSide = leftSide == numberSide ? *rightSide : *leftSide;
    481 
    482             double number = numberSide->doubleValue();
    483             if (!std::isfinite(number))
    484                 return nullptr;
    485             if (op == CalcOperator::Divide && !number)
    486                 return nullptr;
    487 
    488             auto otherType = otherSide.primitiveType();
    489             if (hasDoubleValue(otherType))
    490                 return CSSCalcPrimitiveValue::create(evaluateOperator(op, { otherSide.doubleValue(), number }), otherType, isInteger);
    491         }
    492 
    493         return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
    494     }
     375    static RefPtr<CSSCalcOperation> create(CalcOperator, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide);
     376    static RefPtr<CSSCalcOperation> createMinOrMax(CalcOperator, Vector<Ref<CSSCalcExpressionNode>>&& values, CalculationCategory destinationCategory);
     377    static RefPtr<CSSCalcExpressionNode> createSimplified(CalcOperator, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide);
    495378
    496379private:
    497     bool isZero() const final
    498     {
    499         return !doubleValue();
    500     }
    501 
    502     std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final
    503     {
    504         Vector<std::unique_ptr<CalcExpressionNode>> nodes;
    505         nodes.reserveInitialCapacity(m_children.size());
    506 
    507         for (auto& child : m_children) {
    508             auto node = child->createCalcExpression(conversionData);
    509             if (!node)
    510                 return nullptr;
    511             nodes.uncheckedAppend(WTFMove(node));
    512         }
    513         return makeUnique<CalcExpressionOperation>(WTFMove(nodes), m_operator);
    514     }
    515 
    516     double doubleValue() const final
    517     {
    518         Vector<double> doubleValues;
    519         for (auto& child : m_children)
    520             doubleValues.append(child->doubleValue());
    521         return evaluate(doubleValues);
    522     }
    523 
    524     double computeLengthPx(const CSSToLengthConversionData& conversionData) const final
    525     {
    526         Vector<double> doubleValues;
    527         for (auto& child : m_children)
    528             doubleValues.append(child->computeLengthPx(conversionData));
    529         return evaluate(doubleValues);
    530     }
    531 
    532     void collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const final
    533     {
    534         for (auto& child : m_children)
    535             child->collectDirectComputationalDependencies(values);
    536     }
    537 
    538     void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const final
    539     {
    540         for (auto& child : m_children)
    541             child->collectDirectRootComputationalDependencies(values);
    542     }
    543 
    544     static String buildCssText(Vector<String> childExpressions, CalcOperator op)
    545     {
    546         StringBuilder result;
    547         result.append('(');
    548         switch (op) {
    549         case CalcOperator::Add:
    550         case CalcOperator::Subtract:
    551         case CalcOperator::Multiply:
    552         case CalcOperator::Divide:
    553             ASSERT(childExpressions.size() == 2);
    554             result.append(childExpressions[0]);
    555             result.append(' ');
    556             result.append(static_cast<char>(op));
    557             result.append(' ');
    558             result.append(childExpressions[1]);
    559             break;
    560         case CalcOperator::Min:
    561         case CalcOperator::Max:
    562             ASSERT(!childExpressions.isEmpty());
    563             const char* functionName = op == CalcOperator::Min ? "min(" : "max(";
    564             result.append(functionName);
    565             result.append(childExpressions[0]);
    566             for (size_t i = 1; i < childExpressions.size(); ++i) {
    567                 result.append(',');
    568                 result.append(' ');
    569                 result.append(childExpressions[i]);
    570             }
    571             result.append(')');
    572         }
    573         result.append(')');
    574 
    575         return result.toString();
    576     }
    577 
    578     String customCSSText() const final
    579     {
    580         Vector<String> cssTexts;
    581         for (auto& child : m_children)
    582             cssTexts.append(child->customCSSText());
    583         return buildCssText(cssTexts, m_operator);
    584     }
    585 
    586     bool equals(const CSSCalcExpressionNode& exp) const final
    587     {
    588         if (type() != exp.type())
    589             return false;
    590 
    591         const CSSCalcOperation& other = static_cast<const CSSCalcOperation&>(exp);
    592 
    593         if (m_children.size() != other.m_children.size() || m_operator != other.m_operator)
    594             return false;
    595 
    596         for (size_t i = 0; i < m_children.size(); ++i) {
    597             if (!compareCSSValue(m_children[i], other.m_children[i]))
    598                 return false;
    599         }
    600         return true;
    601     }
    602 
    603     Type type() const final { return CssCalcOperation; }
    604 
    605     CSSPrimitiveValue::UnitType primitiveType() const final
    606     {
    607         switch (category()) {
    608         case CalculationCategory::Number:
    609 #if !ASSERT_DISABLED
    610             for (auto& child : m_children)
    611                 ASSERT(child->category() == CalculationCategory::Number);
    612 #endif
    613             return CSSPrimitiveValue::CSS_NUMBER;
    614         case CalculationCategory::Length:
    615         case CalculationCategory::Percent: {
    616             if (m_children.isEmpty())
    617                 return CSSPrimitiveValue::CSS_UNKNOWN;
    618             if (m_children.size() == 2) {
    619                 if (m_children[0]->category() == CalculationCategory::Number)
    620                     return m_children[1]->primitiveType();
    621                 if (m_children[1]->category() == CalculationCategory::Number)
    622                     return m_children[0]->primitiveType();
    623             }
    624             CSSPrimitiveValue::UnitType firstType = m_children[0]->primitiveType();
    625             for (auto& child : m_children) {
    626                 if (firstType != child->primitiveType())
    627                     return CSSPrimitiveValue::CSS_UNKNOWN;
    628             }
    629             return firstType;
    630         }
    631         case CalculationCategory::Angle:
    632             return CSSPrimitiveValue::CSS_DEG;
    633         case CalculationCategory::Time:
    634             return CSSPrimitiveValue::CSS_MS;
    635         case CalculationCategory::Frequency:
    636             return CSSPrimitiveValue::CSS_HZ;
    637         case CalculationCategory::PercentLength:
    638         case CalculationCategory::PercentNumber:
    639         case CalculationCategory::Other:
    640             return CSSPrimitiveValue::CSS_UNKNOWN;
    641         }
    642         ASSERT_NOT_REACHED();
    643         return CSSPrimitiveValue::CSS_UNKNOWN;
    644     }
    645 
    646380    CSSCalcOperation(CalculationCategory category, CalcOperator op, Ref<CSSCalcExpressionNode>&& leftSide, Ref<CSSCalcExpressionNode>&& rightSide)
    647381        : CSSCalcExpressionNode(category, isIntegerResult(op, leftSide.get(), rightSide.get()))
     
    659393    {
    660394    }
     395
     396    Type type() const final { return CssCalcOperation; }
     397
     398    bool isZero() const final
     399    {
     400        return !doubleValue();
     401    }
     402
     403    bool equals(const CSSCalcExpressionNode&) const final;
     404
     405    std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData&) const final;
     406
     407    CSSPrimitiveValue::UnitType primitiveType() const final;
     408    double doubleValue() const final;
     409    double computeLengthPx(const CSSToLengthConversionData&) const final;
     410
     411    void collectDirectComputationalDependencies(HashSet<CSSPropertyID>&) const final;
     412    void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>&) const final;
     413
     414    String customCSSText() const final;
    661415
    662416    static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide)
     
    674428    }
    675429
    676     static double evaluateOperator(CalcOperator op, const Vector<double>& children)
    677     {
    678         switch (op) {
    679         case CalcOperator::Add:
    680             ASSERT(children.size() == 2);
    681             return children[0] + children[1];
    682         case CalcOperator::Subtract:
    683             ASSERT(children.size() == 2);
    684             return children[0] - children[1];
    685         case CalcOperator::Multiply:
    686             ASSERT(children.size() == 2);
    687             return children[0] * children[1];
    688         case CalcOperator::Divide:
    689             ASSERT(children.size() == 1 || children.size() == 2);
    690             if (children.size() == 1)
    691                 return std::numeric_limits<double>::quiet_NaN();
    692             return children[0] / children[1];
    693         case CalcOperator::Min: {
    694             if (children.isEmpty())
    695                 return std::numeric_limits<double>::quiet_NaN();
    696             double minimum = children[0];
    697             for (auto child : children)
    698                 minimum = std::min(minimum, child);
    699             return minimum;
    700         }
    701         case CalcOperator::Max: {
    702             if (children.isEmpty())
    703                 return std::numeric_limits<double>::quiet_NaN();
    704             double maximum = children[0];
    705             for (auto child : children)
    706                 maximum = std::max(maximum, child);
    707             return maximum;
    708         }
    709         }
    710         ASSERT_NOT_REACHED();
    711         return 0;
    712     }
     430    static double evaluateOperator(CalcOperator, const Vector<double>&);
     431    static String buildCssText(Vector<String>, CalcOperator);
    713432
    714433    const CalcOperator m_operator;
    715434    Vector<Ref<CSSCalcExpressionNode>> m_children;
    716435};
     436
     437RefPtr<CSSCalcOperation> CSSCalcOperation::create(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
     438{
     439    if (!leftSide || !rightSide)
     440        return nullptr;
     441
     442    ASSERT(leftSide->category() < CalculationCategory::Other);
     443    ASSERT(rightSide->category() < CalculationCategory::Other);
     444
     445    auto newCategory = determineCategory(*leftSide, *rightSide, op);
     446    if (newCategory == CalculationCategory::Other)
     447        return nullptr;
     448
     449    return adoptRef(new CSSCalcOperation(newCategory, op, leftSide.releaseNonNull(), rightSide.releaseNonNull()));
     450}
     451
     452RefPtr<CSSCalcOperation> CSSCalcOperation::createMinOrMax(CalcOperator op, Vector<Ref<CSSCalcExpressionNode>>&& values, CalculationCategory destinationCategory)
     453{
     454    ASSERT(op == CalcOperator::Min || op == CalcOperator::Max);
     455
     456    Optional<CalculationCategory> category = WTF::nullopt;
     457    for (auto& value : values) {
     458        auto valueCategory = resolvedTypeForMinOrMax(value->category(), destinationCategory);
     459
     460        ASSERT(valueCategory < CalculationCategory::Other);
     461        if (!category) {
     462            if (valueCategory == CalculationCategory::Other)
     463                return nullptr;
     464            category = valueCategory;
     465        }
     466
     467        if (category != valueCategory) {
     468            if (isSamePair(category.value(), valueCategory, CalculationCategory::Length, CalculationCategory::PercentLength)) {
     469                category = CalculationCategory::PercentLength;
     470                continue;
     471            }
     472            if (isSamePair(category.value(), valueCategory, CalculationCategory::Number, CalculationCategory::PercentNumber)) {
     473                category = CalculationCategory::PercentNumber;
     474                continue;
     475            }
     476            return nullptr;
     477        }
     478    }
     479
     480    return adoptRef(new CSSCalcOperation(category.value(), op, WTFMove(values)));
     481}
     482
     483RefPtr<CSSCalcExpressionNode> CSSCalcOperation::createSimplified(CalcOperator op, RefPtr<CSSCalcExpressionNode>&& leftSide, RefPtr<CSSCalcExpressionNode>&& rightSide)
     484{
     485    if (!leftSide || !rightSide)
     486        return nullptr;
     487
     488    auto leftCategory = leftSide->category();
     489    auto rightCategory = rightSide->category();
     490    ASSERT(leftCategory < CalculationCategory::Other);
     491    ASSERT(rightCategory < CalculationCategory::Other);
     492
     493    bool isInteger = isIntegerResult(op, *leftSide, *rightSide);
     494
     495    // Simplify numbers.
     496    if (leftCategory == CalculationCategory::Number && rightCategory == CalculationCategory::Number) {
     497        CSSPrimitiveValue::UnitType evaluationType = CSSPrimitiveValue::CSS_NUMBER;
     498        return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftSide->doubleValue(), rightSide->doubleValue() }), evaluationType, isInteger);
     499    }
     500
     501    // Simplify addition and subtraction between same types.
     502    if (op == CalcOperator::Add || op == CalcOperator::Subtract) {
     503        if (leftCategory == rightSide->category()) {
     504            CSSPrimitiveValue::UnitType leftType = leftSide->primitiveType();
     505            if (hasDoubleValue(leftType)) {
     506                CSSPrimitiveValue::UnitType rightType = rightSide->primitiveType();
     507                if (leftType == rightType)
     508                    return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftSide->doubleValue(), rightSide->doubleValue() }), leftType, isInteger);
     509                CSSPrimitiveValue::UnitCategory leftUnitCategory = CSSPrimitiveValue::unitCategory(leftType);
     510                if (leftUnitCategory != CSSPrimitiveValue::UOther && leftUnitCategory == CSSPrimitiveValue::unitCategory(rightType)) {
     511                    CSSPrimitiveValue::UnitType canonicalType = CSSPrimitiveValue::canonicalUnitTypeForCategory(leftUnitCategory);
     512                    if (canonicalType != CSSPrimitiveValue::CSS_UNKNOWN) {
     513                        double leftValue = leftSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(leftType);
     514                        double rightValue = rightSide->doubleValue() * CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(rightType);
     515                        return CSSCalcPrimitiveValue::create(evaluateOperator(op, { leftValue, rightValue }), canonicalType, isInteger);
     516                    }
     517                }
     518            }
     519        }
     520    } else {
     521        // Simplify multiplying or dividing by a number for simplifiable types.
     522        ASSERT(op == CalcOperator::Multiply || op == CalcOperator::Divide);
     523        auto* numberSide = getNumberSide(*leftSide, *rightSide);
     524        if (!numberSide)
     525            return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
     526        if (numberSide == leftSide && op == CalcOperator::Divide)
     527            return nullptr;
     528        auto& otherSide = leftSide == numberSide ? *rightSide : *leftSide;
     529
     530        double number = numberSide->doubleValue();
     531        if (!std::isfinite(number))
     532            return nullptr;
     533        if (op == CalcOperator::Divide && !number)
     534            return nullptr;
     535
     536        auto otherType = otherSide.primitiveType();
     537        if (hasDoubleValue(otherType))
     538            return CSSCalcPrimitiveValue::create(evaluateOperator(op, { otherSide.doubleValue(), number }), otherType, isInteger);
     539    }
     540
     541    return create(op, leftSide.releaseNonNull(), rightSide.releaseNonNull());
     542}
     543
     544CSSPrimitiveValue::UnitType CSSCalcOperation::primitiveType() const
     545{
     546    switch (category()) {
     547    case CalculationCategory::Number:
     548#if !ASSERT_DISABLED
     549        for (auto& child : m_children)
     550            ASSERT(child->category() == CalculationCategory::Number);
     551#endif
     552        return CSSPrimitiveValue::CSS_NUMBER;
     553    case CalculationCategory::Length:
     554    case CalculationCategory::Percent: {
     555        if (m_children.isEmpty())
     556            return CSSPrimitiveValue::CSS_UNKNOWN;
     557        if (m_children.size() == 2) {
     558            if (m_children[0]->category() == CalculationCategory::Number)
     559                return m_children[1]->primitiveType();
     560            if (m_children[1]->category() == CalculationCategory::Number)
     561                return m_children[0]->primitiveType();
     562        }
     563        CSSPrimitiveValue::UnitType firstType = m_children[0]->primitiveType();
     564        for (auto& child : m_children) {
     565            if (firstType != child->primitiveType())
     566                return CSSPrimitiveValue::CSS_UNKNOWN;
     567        }
     568        return firstType;
     569    }
     570    case CalculationCategory::Angle:
     571        return CSSPrimitiveValue::CSS_DEG;
     572    case CalculationCategory::Time:
     573        return CSSPrimitiveValue::CSS_MS;
     574    case CalculationCategory::Frequency:
     575        return CSSPrimitiveValue::CSS_HZ;
     576    case CalculationCategory::PercentLength:
     577    case CalculationCategory::PercentNumber:
     578    case CalculationCategory::Other:
     579        return CSSPrimitiveValue::CSS_UNKNOWN;
     580    }
     581    ASSERT_NOT_REACHED();
     582    return CSSPrimitiveValue::CSS_UNKNOWN;
     583}
     584
     585std::unique_ptr<CalcExpressionNode> CSSCalcOperation::createCalcExpression(const CSSToLengthConversionData& conversionData) const
     586{
     587    Vector<std::unique_ptr<CalcExpressionNode>> nodes;
     588    nodes.reserveInitialCapacity(m_children.size());
     589
     590    for (auto& child : m_children) {
     591        auto node = child->createCalcExpression(conversionData);
     592        if (!node)
     593            return nullptr;
     594        nodes.uncheckedAppend(WTFMove(node));
     595    }
     596    return makeUnique<CalcExpressionOperation>(WTFMove(nodes), m_operator);
     597}
     598
     599double CSSCalcOperation::doubleValue() const
     600{
     601    Vector<double> doubleValues;
     602    for (auto& child : m_children)
     603        doubleValues.append(child->doubleValue());
     604    return evaluate(doubleValues);
     605}
     606
     607double CSSCalcOperation::computeLengthPx(const CSSToLengthConversionData& conversionData) const
     608{
     609    Vector<double> doubleValues;
     610    for (auto& child : m_children)
     611        doubleValues.append(child->computeLengthPx(conversionData));
     612    return evaluate(doubleValues);
     613}
     614
     615void CSSCalcOperation::collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const
     616{
     617    for (auto& child : m_children)
     618        child->collectDirectComputationalDependencies(values);
     619}
     620
     621void CSSCalcOperation::collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const
     622{
     623    for (auto& child : m_children)
     624        child->collectDirectRootComputationalDependencies(values);
     625}
     626
     627String CSSCalcOperation::buildCssText(Vector<String> childExpressions, CalcOperator op)
     628{
     629    StringBuilder result;
     630    result.append('(');
     631    switch (op) {
     632    case CalcOperator::Add:
     633    case CalcOperator::Subtract:
     634    case CalcOperator::Multiply:
     635    case CalcOperator::Divide:
     636        ASSERT(childExpressions.size() == 2);
     637        result.append(childExpressions[0]);
     638        result.append(' ');
     639        result.append(static_cast<char>(op));
     640        result.append(' ');
     641        result.append(childExpressions[1]);
     642        break;
     643    case CalcOperator::Min:
     644    case CalcOperator::Max:
     645        ASSERT(!childExpressions.isEmpty());
     646        const char* functionName = op == CalcOperator::Min ? "min(" : "max(";
     647        result.append(functionName);
     648        result.append(childExpressions[0]);
     649        for (size_t i = 1; i < childExpressions.size(); ++i) {
     650            result.append(',');
     651            result.append(' ');
     652            result.append(childExpressions[i]);
     653        }
     654        result.append(')');
     655    }
     656    result.append(')');
     657
     658    return result.toString();
     659}
     660
     661String CSSCalcOperation::customCSSText() const
     662{
     663    Vector<String> cssTexts;
     664    for (auto& child : m_children)
     665        cssTexts.append(child->customCSSText());
     666    return buildCssText(cssTexts, m_operator);
     667}
     668
     669bool CSSCalcOperation::equals(const CSSCalcExpressionNode& exp) const
     670{
     671    if (type() != exp.type())
     672        return false;
     673
     674    const CSSCalcOperation& other = static_cast<const CSSCalcOperation&>(exp);
     675
     676    if (m_children.size() != other.m_children.size() || m_operator != other.m_operator)
     677        return false;
     678
     679    for (size_t i = 0; i < m_children.size(); ++i) {
     680        if (!compareCSSValue(m_children[i], other.m_children[i]))
     681            return false;
     682    }
     683    return true;
     684}
     685
     686double CSSCalcOperation::evaluateOperator(CalcOperator op, const Vector<double>& children)
     687{
     688    switch (op) {
     689    case CalcOperator::Add:
     690        ASSERT(children.size() == 2);
     691        return children[0] + children[1];
     692    case CalcOperator::Subtract:
     693        ASSERT(children.size() == 2);
     694        return children[0] - children[1];
     695    case CalcOperator::Multiply:
     696        ASSERT(children.size() == 2);
     697        return children[0] * children[1];
     698    case CalcOperator::Divide:
     699        ASSERT(children.size() == 1 || children.size() == 2);
     700        if (children.size() == 1)
     701            return std::numeric_limits<double>::quiet_NaN();
     702        return children[0] / children[1];
     703    case CalcOperator::Min: {
     704        if (children.isEmpty())
     705            return std::numeric_limits<double>::quiet_NaN();
     706        double minimum = children[0];
     707        for (auto child : children)
     708            minimum = std::min(minimum, child);
     709        return minimum;
     710    }
     711    case CalcOperator::Max: {
     712        if (children.isEmpty())
     713            return std::numeric_limits<double>::quiet_NaN();
     714        double maximum = children[0];
     715        for (auto child : children)
     716            maximum = std::max(maximum, child);
     717        return maximum;
     718    }
     719    }
     720    ASSERT_NOT_REACHED();
     721    return 0;
     722}
     723
     724
     725class CSSCalcExpressionNodeParser {
     726public:
     727    explicit CSSCalcExpressionNodeParser(CalculationCategory destinationCategory)
     728        : m_destinationCategory(destinationCategory)
     729    { }
     730
     731    RefPtr<CSSCalcExpressionNode> parseCalc(CSSParserTokenRange, CSSValueID function);
     732   
     733private:
     734    struct Value {
     735        RefPtr<CSSCalcExpressionNode> value;
     736    };
     737   
     738    char operatorValue(const CSSParserToken& token)
     739    {
     740        if (token.type() == DelimiterToken)
     741            return token.delimiter();
     742        return 0;
     743    }
     744
     745    bool parseValue(CSSParserTokenRange&, Value* result);
     746    bool parseValueTerm(CSSParserTokenRange&, int depth, Value* result);
     747    bool parseValueMultiplicativeExpression(CSSParserTokenRange&, int depth, Value* result);
     748    bool parseAdditiveValueExpression(CSSParserTokenRange&, int depth, Value* result);
     749    bool parseMinMaxExpression(CSSParserTokenRange&, CSSValueID minMaxFunction, int depth, Value* result);
     750    bool parseValueExpression(CSSParserTokenRange&, int depth, Value* result);
     751
     752    CalculationCategory m_destinationCategory;
     753};
     754
     755
     756RefPtr<CSSCalcExpressionNode> CSSCalcExpressionNodeParser::parseCalc(CSSParserTokenRange tokens, CSSValueID function)
     757{
     758    Value result;
     759    tokens.consumeWhitespace();
     760    bool ok = false;
     761    if (function == CSSValueCalc || function == CSSValueWebkitCalc)
     762        ok = parseValueExpression(tokens, 0, &result);
     763    else if (function == CSSValueMin || function == CSSValueMax)
     764        ok = parseMinMaxExpression(tokens, function, 0, &result);
     765    if (!ok || !tokens.atEnd())
     766        return nullptr;
     767    return result.value;
     768}
     769
     770bool CSSCalcExpressionNodeParser::parseValue(CSSParserTokenRange& tokens, Value* result)
     771{
     772    CSSParserToken token = tokens.consumeIncludingWhitespace();
     773    if (!(token.type() == NumberToken || token.type() == PercentageToken || token.type() == DimensionToken))
     774        return false;
     775   
     776    CSSPrimitiveValue::UnitType type = token.unitType();
     777    if (unitCategory(type) == CalculationCategory::Other)
     778        return false;
     779   
     780    bool isInteger = token.numericValueType() == IntegerValueType || (token.numericValueType() == NumberValueType && token.numericValue() == trunc(token.numericValue()));
     781    result->value = CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(token.numericValue(), type), isInteger);
     782   
     783    return true;
     784}
    717785
    718786static ParseState checkDepthAndIndex(int* depth, CSSParserTokenRange tokens)
     
    726794}
    727795
    728 class CSSCalcExpressionNodeParser {
    729 public:
    730     explicit CSSCalcExpressionNodeParser(CalculationCategory destinationCategory)
    731         : m_destinationCategory(destinationCategory)
    732     { }
    733 
    734     RefPtr<CSSCalcExpressionNode> parseCalc(CSSParserTokenRange tokens, CSSValueID function)
    735     {
    736         Value result;
     796bool CSSCalcExpressionNodeParser::parseValueTerm(CSSParserTokenRange& tokens, int depth, Value* result)
     797{
     798    if (checkDepthAndIndex(&depth, tokens) != OK)
     799        return false;
     800
     801    auto functionId = tokens.peek().functionId();
     802   
     803    if (tokens.peek().type() == LeftParenthesisToken || functionId == CSSValueCalc) {
     804        CSSParserTokenRange innerRange = tokens.consumeBlock();
    737805        tokens.consumeWhitespace();
    738         bool ok = false;
    739         if (function == CSSValueCalc || function == CSSValueWebkitCalc)
    740             ok = parseValueExpression(tokens, 0, &result);
    741         else if (function == CSSValueMin || function == CSSValueMax)
    742             ok = parseMinMaxExpression(tokens, function, 0, &result);
    743         if (!ok || !tokens.atEnd())
    744             return nullptr;
    745         return result.value;
    746     }
    747    
    748 private:
    749     struct Value {
    750         RefPtr<CSSCalcExpressionNode> value;
    751     };
    752    
    753     char operatorValue(const CSSParserToken& token)
    754     {
    755         if (token.type() == DelimiterToken)
    756             return token.delimiter();
    757         return 0;
    758     }
    759    
    760     bool parseValue(CSSParserTokenRange& tokens, Value* result)
    761     {
    762         CSSParserToken token = tokens.consumeIncludingWhitespace();
    763         if (!(token.type() == NumberToken || token.type() == PercentageToken || token.type() == DimensionToken))
     806        innerRange.consumeWhitespace();
     807        return parseValueExpression(innerRange, depth, result);
     808    }
     809
     810    if (functionId == CSSValueMax || functionId == CSSValueMin) {
     811        CSSParserTokenRange innerRange = tokens.consumeBlock();
     812        tokens.consumeWhitespace();
     813        innerRange.consumeWhitespace();
     814        return parseMinMaxExpression(innerRange, functionId, depth, result);
     815    }
     816   
     817    return parseValue(tokens, result);
     818}
     819
     820bool CSSCalcExpressionNodeParser::parseValueMultiplicativeExpression(CSSParserTokenRange& tokens, int depth, Value* result)
     821{
     822    if (checkDepthAndIndex(&depth, tokens) != OK)
     823        return false;
     824   
     825    if (!parseValueTerm(tokens, depth, result))
     826        return false;
     827   
     828    while (!tokens.atEnd()) {
     829        char operatorCharacter = operatorValue(tokens.peek());
     830        if (operatorCharacter != static_cast<char>(CalcOperator::Multiply) && operatorCharacter != static_cast<char>(CalcOperator::Divide))
     831            break;
     832        tokens.consumeIncludingWhitespace();
     833       
     834        Value rhs;
     835        if (!parseValueTerm(tokens, depth, &rhs))
    764836            return false;
    765837       
    766         CSSPrimitiveValue::UnitType type = token.unitType();
    767         if (unitCategory(type) == CalculationCategory::Other)
     838        result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
     839
     840        if (!result->value)
     841            return false;
     842    }
     843   
     844    return true;
     845}
     846
     847bool CSSCalcExpressionNodeParser::parseAdditiveValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
     848{
     849    if (checkDepthAndIndex(&depth, tokens) != OK)
     850        return false;
     851   
     852    if (!parseValueMultiplicativeExpression(tokens, depth, result))
     853        return false;
     854   
     855    while (!tokens.atEnd()) {
     856        char operatorCharacter = operatorValue(tokens.peek());
     857        if (operatorCharacter != static_cast<char>(CalcOperator::Add) && operatorCharacter != static_cast<char>(CalcOperator::Subtract))
     858            break;
     859        if ((&tokens.peek() - 1)->type() != WhitespaceToken)
     860            return false; // calc(1px+ 2px) is invalid
     861        tokens.consume();
     862        if (tokens.peek().type() != WhitespaceToken)
     863            return false; // calc(1px +2px) is invalid
     864        tokens.consumeIncludingWhitespace();
     865       
     866        Value rhs;
     867        if (!parseValueMultiplicativeExpression(tokens, depth, &rhs))
    768868            return false;
    769869       
    770         bool isInteger = token.numericValueType() == IntegerValueType || (token.numericValueType() == NumberValueType && token.numericValue() == trunc(token.numericValue()));
    771         result->value = CSSCalcPrimitiveValue::create(CSSPrimitiveValue::create(token.numericValue(), type), isInteger);
    772        
    773         return true;
    774     }
    775    
    776     bool parseValueTerm(CSSParserTokenRange& tokens, int depth, Value* result)
    777     {
    778         if (checkDepthAndIndex(&depth, tokens) != OK)
     870        result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
     871        if (!result->value)
    779872            return false;
    780 
    781         auto functionId = tokens.peek().functionId();
    782        
    783         if (tokens.peek().type() == LeftParenthesisToken || functionId == CSSValueCalc) {
    784             CSSParserTokenRange innerRange = tokens.consumeBlock();
    785             tokens.consumeWhitespace();
    786             innerRange.consumeWhitespace();
    787             return parseValueExpression(innerRange, depth, result);
    788         }
    789 
    790         if (functionId == CSSValueMax || functionId == CSSValueMin) {
    791             CSSParserTokenRange innerRange = tokens.consumeBlock();
    792             tokens.consumeWhitespace();
    793             innerRange.consumeWhitespace();
    794             return parseMinMaxExpression(innerRange, functionId, depth, result);
    795         }
    796        
    797         return parseValue(tokens, result);
    798     }
    799    
    800     bool parseValueMultiplicativeExpression(CSSParserTokenRange& tokens, int depth, Value* result)
    801     {
    802         if (checkDepthAndIndex(&depth, tokens) != OK)
     873    }
     874   
     875    return true;
     876}
     877
     878bool CSSCalcExpressionNodeParser::parseMinMaxExpression(CSSParserTokenRange& tokens, CSSValueID minMaxFunction, int depth, Value* result)
     879{
     880    if (checkDepthAndIndex(&depth, tokens) != OK)
     881        return false;
     882
     883    CalcOperator op = (minMaxFunction == CSSValueMin) ? CalcOperator::Min : CalcOperator::Max;
     884
     885    Value value;
     886    if (!parseValueExpression(tokens, depth, &value))
     887        return false;
     888
     889    Vector<Ref<CSSCalcExpressionNode>> nodes;
     890    nodes.append(value.value.releaseNonNull());
     891
     892    while (!tokens.atEnd()) {
     893        tokens.consumeWhitespace();
     894        if (tokens.consume().type() != CommaToken)
    803895            return false;
    804        
    805         if (!parseValueTerm(tokens, depth, result))
    806             return false;
    807        
    808         while (!tokens.atEnd()) {
    809             char operatorCharacter = operatorValue(tokens.peek());
    810             if (operatorCharacter != static_cast<char>(CalcOperator::Multiply) && operatorCharacter != static_cast<char>(CalcOperator::Divide))
    811                 break;
    812             tokens.consumeIncludingWhitespace();
    813            
    814             Value rhs;
    815             if (!parseValueTerm(tokens, depth, &rhs))
    816                 return false;
    817            
    818             result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
    819 
    820             if (!result->value)
    821                 return false;
    822         }
    823        
    824         return true;
    825     }
    826    
    827     bool parseAdditiveValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
    828     {
    829         if (checkDepthAndIndex(&depth, tokens) != OK)
    830             return false;
    831        
    832         if (!parseValueMultiplicativeExpression(tokens, depth, result))
    833             return false;
    834        
    835         while (!tokens.atEnd()) {
    836             char operatorCharacter = operatorValue(tokens.peek());
    837             if (operatorCharacter != static_cast<char>(CalcOperator::Add) && operatorCharacter != static_cast<char>(CalcOperator::Subtract))
    838                 break;
    839             if ((&tokens.peek() - 1)->type() != WhitespaceToken)
    840                 return false; // calc(1px+ 2px) is invalid
    841             tokens.consume();
    842             if (tokens.peek().type() != WhitespaceToken)
    843                 return false; // calc(1px +2px) is invalid
    844             tokens.consumeIncludingWhitespace();
    845            
    846             Value rhs;
    847             if (!parseValueMultiplicativeExpression(tokens, depth, &rhs))
    848                 return false;
    849            
    850             result->value = CSSCalcOperation::createSimplified(static_cast<CalcOperator>(operatorCharacter), WTFMove(result->value), WTFMove(rhs.value));
    851             if (!result->value)
    852                 return false;
    853         }
    854        
    855         return true;
    856     }
    857 
    858     bool parseMinMaxExpression(CSSParserTokenRange& tokens, CSSValueID minMaxFunction, int depth, Value* result)
    859     {
    860         if (checkDepthAndIndex(&depth, tokens) != OK)
    861             return false;
    862 
    863         CalcOperator op = (minMaxFunction == CSSValueMin) ? CalcOperator::Min : CalcOperator::Max;
    864 
    865         Value value;
     896        tokens.consumeWhitespace();
     897
    866898        if (!parseValueExpression(tokens, depth, &value))
    867899            return false;
    868900
    869         Vector<Ref<CSSCalcExpressionNode>> nodes;
    870901        nodes.append(value.value.releaseNonNull());
    871 
    872         while (!tokens.atEnd()) {
    873             tokens.consumeWhitespace();
    874             if (tokens.consume().type() != CommaToken)
    875                 return false;
    876             tokens.consumeWhitespace();
    877 
    878             if (!parseValueExpression(tokens, depth, &value))
    879                 return false;
    880 
    881             nodes.append(value.value.releaseNonNull());
    882         }
    883 
    884         result->value = CSSCalcOperation::createMinOrMax(op, WTFMove(nodes), m_destinationCategory);
    885         return result->value;
    886     }
    887 
    888     bool parseValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
    889     {
    890         return parseAdditiveValueExpression(tokens, depth, result);
    891     }
    892 
    893     CalculationCategory m_destinationCategory;
    894 };
     902    }
     903
     904    result->value = CSSCalcOperation::createMinOrMax(op, WTFMove(nodes), m_destinationCategory);
     905    return result->value;
     906}
     907
     908bool CSSCalcExpressionNodeParser::parseValueExpression(CSSParserTokenRange& tokens, int depth, Value* result)
     909{
     910    return parseAdditiveValueExpression(tokens, depth, result);
     911}
     912
    895913
    896914static inline RefPtr<CSSCalcOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress)
     
    964982}
    965983
     984String CSSCalcValue::customCSSText() const
     985{
     986    auto expression = m_expression->customCSSText();
     987    if (expression[0] == '(')
     988        return makeString("calc", expression);
     989    return makeString("calc(", expression, ')');
     990}
     991
     992bool CSSCalcValue::equals(const CSSCalcValue& other) const
     993{
     994    return compareCSSValue(m_expression, other.m_expression);
     995}
     996
     997inline double CSSCalcValue::clampToPermittedRange(double value) const
     998{
     999    return m_shouldClampToNonNegative && value < 0 ? 0 : value;
     1000}
     1001
     1002double CSSCalcValue::doubleValue() const
     1003{
     1004    return clampToPermittedRange(m_expression->doubleValue());
     1005}
     1006
     1007double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const
     1008{
     1009    return clampToPermittedRange(m_expression->computeLengthPx(conversionData));
     1010}
     1011
    9661012RefPtr<CSSCalcValue> CSSCalcValue::create(CSSValueID function, const CSSParserTokenRange& tokens, CalculationCategory destinationCategory, ValueRange range)
    9671013{
Note: See TracChangeset for help on using the changeset viewer.