Changeset 251595 in webkit
- Timestamp:
- Oct 25, 2019 10:16:23 AM (5 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r251594 r251595 1 2019-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 1 46 2019-10-25 youenn fablet <youenn@apple.com> 2 47 -
trunk/Source/WebCore/css/CSSCalculationValue.cpp
r249013 r251595 150 150 } 151 151 152 String CSSCalcValue::customCSSText() const153 {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) const161 {162 return compareCSSValue(m_expression, other.m_expression);163 }164 165 inline double CSSCalcValue::clampToPermittedRange(double value) const166 {167 return m_shouldClampToNonNegative && value < 0 ? 0 : value;168 }169 170 double CSSCalcValue::doubleValue() const171 {172 return clampToPermittedRange(m_expression->doubleValue());173 }174 175 double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const176 {177 return clampToPermittedRange(m_expression->computeLengthPx(conversionData));178 }179 152 180 153 class CSSCalcPrimitiveValue final : public CSSCalcExpressionNode { … … 199 172 } 200 173 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 201 189 String customCSSText() const final 202 190 { 203 191 return m_value->cssText(); 204 }205 206 std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final207 {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 converted218 // 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 final231 {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 final239 {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 final260 {261 m_value->collectDirectComputationalDependencies(values);262 }263 264 void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const final265 {266 m_value->collectDirectRootComputationalDependencies(values);267 }268 269 bool equals(const CSSCalcExpressionNode& other) const final270 {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 final279 {280 return CSSPrimitiveValue::UnitType(m_value->primitiveType());281 192 } 282 193 … … 290 201 Ref<CSSPrimitiveValue> m_value; 291 202 }; 203 204 std::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 228 double CSSCalcPrimitiveValue::doubleValue() const 229 { 230 if (hasDoubleValue(primitiveType())) 231 return m_value->doubleValue(); 232 ASSERT_NOT_REACHED(); 233 return 0; 234 } 235 236 double 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 257 void CSSCalcPrimitiveValue::collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const 258 { 259 m_value->collectDirectComputationalDependencies(values); 260 } 261 262 void CSSCalcPrimitiveValue::collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const 263 { 264 m_value->collectDirectRootComputationalDependencies(values); 265 } 266 267 bool 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 292 278 293 279 static const CalculationCategory addSubtractResult[static_cast<unsigned>(CalculationCategory::Angle)][static_cast<unsigned>(CalculationCategory::Angle)] = { … … 387 373 WTF_MAKE_FAST_ALLOCATED; 388 374 public: 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); 495 378 496 379 private: 497 bool isZero() const final498 {499 return !doubleValue();500 }501 502 std::unique_ptr<CalcExpressionNode> createCalcExpression(const CSSToLengthConversionData& conversionData) const final503 {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 final517 {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 final525 {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 final533 {534 for (auto& child : m_children)535 child->collectDirectComputationalDependencies(values);536 }537 538 void collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const final539 {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 final579 {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 final587 {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 final606 {607 switch (category()) {608 case CalculationCategory::Number:609 #if !ASSERT_DISABLED610 for (auto& child : m_children)611 ASSERT(child->category() == CalculationCategory::Number);612 #endif613 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 646 380 CSSCalcOperation(CalculationCategory category, CalcOperator op, Ref<CSSCalcExpressionNode>&& leftSide, Ref<CSSCalcExpressionNode>&& rightSide) 647 381 : CSSCalcExpressionNode(category, isIntegerResult(op, leftSide.get(), rightSide.get())) … … 659 393 { 660 394 } 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; 661 415 662 416 static CSSCalcExpressionNode* getNumberSide(CSSCalcExpressionNode& leftSide, CSSCalcExpressionNode& rightSide) … … 674 428 } 675 429 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); 713 432 714 433 const CalcOperator m_operator; 715 434 Vector<Ref<CSSCalcExpressionNode>> m_children; 716 435 }; 436 437 RefPtr<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 452 RefPtr<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 483 RefPtr<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 544 CSSPrimitiveValue::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 585 std::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 599 double 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 607 double 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 615 void CSSCalcOperation::collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const 616 { 617 for (auto& child : m_children) 618 child->collectDirectComputationalDependencies(values); 619 } 620 621 void CSSCalcOperation::collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const 622 { 623 for (auto& child : m_children) 624 child->collectDirectRootComputationalDependencies(values); 625 } 626 627 String 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 661 String 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 669 bool 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 686 double 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 725 class CSSCalcExpressionNodeParser { 726 public: 727 explicit CSSCalcExpressionNodeParser(CalculationCategory destinationCategory) 728 : m_destinationCategory(destinationCategory) 729 { } 730 731 RefPtr<CSSCalcExpressionNode> parseCalc(CSSParserTokenRange, CSSValueID function); 732 733 private: 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 756 RefPtr<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 770 bool 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 } 717 785 718 786 static ParseState checkDepthAndIndex(int* depth, CSSParserTokenRange tokens) … … 726 794 } 727 795 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;796 bool 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(); 737 805 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 820 bool 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)) 764 836 return false; 765 837 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 847 bool 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)) 768 868 return false; 769 869 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) 779 872 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 878 bool 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) 803 895 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 866 898 if (!parseValueExpression(tokens, depth, &value)) 867 899 return false; 868 900 869 Vector<Ref<CSSCalcExpressionNode>> nodes;870 901 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 908 bool CSSCalcExpressionNodeParser::parseValueExpression(CSSParserTokenRange& tokens, int depth, Value* result) 909 { 910 return parseAdditiveValueExpression(tokens, depth, result); 911 } 912 895 913 896 914 static inline RefPtr<CSSCalcOperation> createBlendHalf(const Length& length, const RenderStyle& style, float progress) … … 964 982 } 965 983 984 String 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 992 bool CSSCalcValue::equals(const CSSCalcValue& other) const 993 { 994 return compareCSSValue(m_expression, other.m_expression); 995 } 996 997 inline double CSSCalcValue::clampToPermittedRange(double value) const 998 { 999 return m_shouldClampToNonNegative && value < 0 ? 0 : value; 1000 } 1001 1002 double CSSCalcValue::doubleValue() const 1003 { 1004 return clampToPermittedRange(m_expression->doubleValue()); 1005 } 1006 1007 double CSSCalcValue::computeLengthPx(const CSSToLengthConversionData& conversionData) const 1008 { 1009 return clampToPermittedRange(m_expression->computeLengthPx(conversionData)); 1010 } 1011 966 1012 RefPtr<CSSCalcValue> CSSCalcValue::create(CSSValueID function, const CSSParserTokenRange& tokens, CalculationCategory destinationCategory, ValueRange range) 967 1013 {
Note: See TracChangeset
for help on using the changeset viewer.