Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "config.h" | 5 #include "config.h" |
| 6 #include "core/css/parser/CSSPropertyParser.h" | 6 #include "core/css/parser/CSSPropertyParser.h" |
| 7 | 7 |
| 8 #include "core/StylePropertyShorthand.h" | 8 #include "core/StylePropertyShorthand.h" |
| 9 #include "core/css/CSSCalculationValue.h" | 9 #include "core/css/CSSCalculationValue.h" |
| 10 #include "core/css/CSSCrossfadeValue.h" | |
| 10 #include "core/css/CSSCursorImageValue.h" | 11 #include "core/css/CSSCursorImageValue.h" |
| 11 #include "core/css/CSSCustomIdentValue.h" | 12 #include "core/css/CSSCustomIdentValue.h" |
| 12 #include "core/css/CSSFontFaceSrcValue.h" | 13 #include "core/css/CSSFontFaceSrcValue.h" |
| 13 #include "core/css/CSSFontFeatureValue.h" | 14 #include "core/css/CSSFontFeatureValue.h" |
| 14 #include "core/css/CSSFunctionValue.h" | 15 #include "core/css/CSSFunctionValue.h" |
| 15 #include "core/css/CSSImageSetValue.h" | 16 #include "core/css/CSSImageSetValue.h" |
| 16 #include "core/css/CSSPathValue.h" | 17 #include "core/css/CSSPathValue.h" |
| 17 #include "core/css/CSSPrimitiveValueMappings.h" | 18 #include "core/css/CSSPrimitiveValueMappings.h" |
| 18 #include "core/css/CSSQuadValue.h" | 19 #include "core/css/CSSQuadValue.h" |
| 19 #include "core/css/CSSSVGDocumentValue.h" | 20 #include "core/css/CSSSVGDocumentValue.h" |
| (...skipping 2378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2398 cursorType = consumeIdent(range); | 2399 cursorType = consumeIdent(range); |
| 2399 } | 2400 } |
| 2400 | 2401 |
| 2401 if (!list) | 2402 if (!list) |
| 2402 return cursorType.release(); | 2403 return cursorType.release(); |
| 2403 if (cursorType) | 2404 if (cursorType) |
| 2404 list->append(cursorType.release()); | 2405 list->append(cursorType.release()); |
| 2405 return list.release(); | 2406 return list.release(); |
| 2406 } | 2407 } |
| 2407 | 2408 |
| 2409 static bool consumeGradientColorStops(CSSParserTokenRange& range, CSSParserConte xt context, CSSGradientValue* gradient, bool expectComma) | |
| 2410 { | |
| 2411 bool supportsColorHints = gradient->gradientType() == CSSLinearGradient || g radient->gradientType() == CSSRadialGradient; | |
| 2412 | |
| 2413 // The first color stop cannot be a color hint. | |
| 2414 bool previousStopWasColorHint = true; | |
| 2415 while (!range.atEnd()) { | |
|
Timothy Loh
2015/12/09 06:59:57
Can we just use a regular do-while loop here and m
rwlbuis
2015/12/09 21:31:13
Done.
| |
| 2416 if (expectComma && !consumeCommaIncludingWhitespace(range)) | |
| 2417 return false; | |
| 2418 | |
| 2419 CSSGradientColorStop stop; | |
| 2420 stop.m_color = consumeColor(range, context); | |
| 2421 | |
| 2422 // Two hints in a row are not allowed. | |
| 2423 if (!stop.m_color && (!supportsColorHints || previousStopWasColorHint)) | |
| 2424 return false; | |
| 2425 previousStopWasColorHint = !stop.m_color; | |
| 2426 stop.m_position = consumeLengthOrPercent(range, context.mode(), ValueRan geAll); | |
| 2427 if (!stop.m_color && !stop.m_position) | |
| 2428 return false; | |
| 2429 | |
| 2430 gradient->addStop(stop); | |
| 2431 expectComma = true; | |
| 2432 } | |
| 2433 | |
| 2434 // The last color stop cannot be a color hint. | |
| 2435 if (previousStopWasColorHint) | |
| 2436 return false; | |
| 2437 | |
| 2438 // Must have 2 or more stops to be valid. | |
| 2439 return gradient->stopCount() >= 2; | |
| 2440 } | |
| 2441 | |
| 2442 static PassRefPtrWillBeRawPtr<CSSValue> consumeRadialGradient(CSSParserTokenRang e args, CSSParserContext context, CSSGradientRepeat repeating) | |
| 2443 { | |
| 2444 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue:: create(repeating, CSSRadialGradient); | |
| 2445 | |
| 2446 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr; | |
|
Timothy Loh
2015/12/09 06:59:57
imo shapeValue -> shape, sizeValue -> sizeKeyword
rwlbuis
2015/12/09 21:31:13
Done.
| |
| 2447 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr; | |
| 2448 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr; | |
| 2449 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr; | |
| 2450 | |
| 2451 // First part of grammar, the size/shape clause: | |
| 2452 // [ circle || <length> ] | | |
| 2453 // [ ellipse || [ <length> | <percentage> ]{2} ] | | |
| 2454 // [ [ circle | ellipse] || <size-keyword> ] | |
| 2455 for (int i = 0; i < 3; ++i) { | |
| 2456 if (args.peek().type() == IdentToken) { | |
| 2457 CSSValueID id = args.peek().id(); | |
| 2458 if (id == CSSValueCircle || id == CSSValueEllipse) { | |
| 2459 if (shapeValue) | |
| 2460 return nullptr; | |
| 2461 shapeValue = consumeIdent(args); | |
| 2462 } else if (id == CSSValueClosestSide || id == CSSValueClosestCorner || id == CSSValueFarthestSide || id == CSSValueFarthestCorner) { | |
| 2463 if (sizeValue || horizontalSize) | |
|
Timothy Loh
2015/12/09 06:59:57
Probably nicer to leave out the horizontalSize che
rwlbuis
2015/12/09 21:31:14
Done.
| |
| 2464 return nullptr; | |
| 2465 sizeValue = consumeIdent(args); | |
| 2466 } else { | |
| 2467 break; | |
| 2468 } | |
| 2469 } else { | |
| 2470 RefPtrWillBeRawPtr<CSSPrimitiveValue> center = consumeLengthOrPercen t(args, context.mode(), ValueRangeAll); | |
| 2471 if (!center) | |
| 2472 break; | |
| 2473 if (sizeValue || horizontalSize) | |
|
Timothy Loh
2015/12/09 06:59:57
and leave out the sizeValue check here
rwlbuis
2015/12/09 21:31:14
Done.
| |
| 2474 return nullptr; | |
| 2475 horizontalSize = center; | |
| 2476 | |
| 2477 if ((center = consumeLengthOrPercent(args, context.mode(), ValueRang eAll))) { | |
| 2478 verticalSize = center.release(); | |
| 2479 ++i; | |
| 2480 } | |
| 2481 } | |
| 2482 } | |
| 2483 | |
| 2484 // You can specify size as a keyword or a length/percentage, not both. | |
| 2485 if (sizeValue && horizontalSize) | |
| 2486 return nullptr; | |
| 2487 // Circles must have 0 or 1 lengths. | |
| 2488 if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize ) | |
| 2489 return nullptr; | |
| 2490 // Ellipses must have 0 or 2 length/percentages. | |
| 2491 if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalS ize && !verticalSize) | |
| 2492 return nullptr; | |
| 2493 // If there's only one size, it must be a length. | |
| 2494 if (!verticalSize && horizontalSize && horizontalSize->isPercentage()) | |
|
Timothy Loh
2015/12/09 06:59:57
// TODO(timloh): Calcs with both lengths and perce
rwlbuis
2015/12/09 21:31:13
Done.
| |
| 2495 return nullptr; | |
| 2496 | |
| 2497 result->setShape(shapeValue); | |
| 2498 result->setSizingBehavior(sizeValue); | |
| 2499 result->setEndHorizontalSize(horizontalSize); | |
| 2500 result->setEndVerticalSize(verticalSize); | |
| 2501 | |
| 2502 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr; | |
| 2503 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr; | |
| 2504 if (args.peek().id() == CSSValueAt) { | |
| 2505 args.consumeIncludingWhitespace(); | |
| 2506 | |
| 2507 consumePosition(args, context.mode(), UnitlessQuirk::Forbid, centerX, ce nterY); | |
| 2508 if (!(centerX && centerY)) | |
| 2509 return nullptr; | |
| 2510 | |
| 2511 result->setFirstX(centerX); | |
| 2512 result->setFirstY(centerY); | |
| 2513 // Right now, CSS radial gradients have the same start and end centers. | |
| 2514 result->setSecondX(centerX); | |
| 2515 result->setSecondY(centerY); | |
| 2516 } | |
| 2517 | |
| 2518 bool expectComma = shapeValue || sizeValue || horizontalSize || centerX || c enterY; | |
| 2519 if (!consumeGradientColorStops(args, context, result.get(), expectComma) || !args.atEnd()) | |
| 2520 return nullptr; | |
| 2521 | |
| 2522 return result.release(); | |
| 2523 } | |
| 2524 | |
| 2525 static PassRefPtrWillBeRawPtr<CSSValue> consumeLinearGradient(CSSParserTokenRang e args, CSSParserContext context, CSSGradientRepeat repeating, CSSGradientType g radientType) | |
| 2526 { | |
| 2527 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue:: create(repeating, gradientType); | |
| 2528 | |
| 2529 bool expectComma = true; | |
| 2530 RefPtrWillBeRawPtr<CSSPrimitiveValue> angle = consumeAngle(args, context.mod e()); | |
| 2531 if (angle) { | |
| 2532 result->setAngle(angle.release()); | |
| 2533 } else if (gradientType == CSSPrefixedLinearGradient || consumeIdent<CSSValu eTo>(args)) { | |
| 2534 RefPtrWillBeRawPtr<CSSPrimitiveValue> endX = consumeIdent<CSSValueLeft, CSSValueRight>(args); | |
| 2535 RefPtrWillBeRawPtr<CSSPrimitiveValue> endY = consumeIdent<CSSValueBottom , CSSValueTop>(args); | |
| 2536 if (!endX && !endY) | |
| 2537 return nullptr; | |
| 2538 RefPtrWillBeRawPtr<CSSPrimitiveValue> location = consumeIdent<CSSValueLe ft, CSSValueRight>(args); | |
|
Timothy Loh
2015/12/09 06:59:57
Should be enough to just write
if (!endX)
end
rwlbuis
2015/12/09 21:31:13
I think endX and location have to be separate. Oth
rwlbuis
2015/12/09 23:08:46
Oh, I see why you mean here too now, should be fix
| |
| 2539 if (location) { | |
| 2540 if (endX) | |
| 2541 return nullptr; | |
| 2542 endX = location; | |
| 2543 } else if ((location = consumeIdent<CSSValueBottom, CSSValueTop>(args))) { | |
| 2544 if (endY) | |
| 2545 return nullptr; | |
| 2546 endY = location; | |
| 2547 } | |
| 2548 | |
| 2549 if (!endX && !endY) { | |
| 2550 endY = cssValuePool().createIdentifierValue(CSSValueTop); | |
|
Timothy Loh
2015/12/09 06:59:57
Unreachable?
rwlbuis
2015/12/09 21:31:13
Sorry, I merged a patch wrong, this is still neede
| |
| 2551 expectComma = false; | |
| 2552 } | |
| 2553 | |
| 2554 result->setFirstX(endX.release()); | |
| 2555 result->setFirstY(endY.release()); | |
| 2556 } | |
| 2557 | |
| 2558 if (!consumeGradientColorStops(args, context, result.get(), expectComma) || !args.atEnd()) | |
| 2559 return nullptr; | |
| 2560 | |
| 2561 return result.release(); | |
| 2562 } | |
| 2563 | |
| 2564 static PassRefPtrWillBeRawPtr<CSSValue> consumeImage(CSSParserTokenRange&, CSSPa rserContext); | |
| 2565 | |
| 2566 static PassRefPtrWillBeRawPtr<CSSValue> consumeCrossFade(CSSParserTokenRange arg s, CSSParserContext context) | |
| 2567 { | |
| 2568 RefPtrWillBeRawPtr<CSSValue> fromImageValue = consumeImage(args, context); | |
| 2569 if (!fromImageValue || !consumeCommaIncludingWhitespace(args)) | |
| 2570 return nullptr; | |
| 2571 RefPtrWillBeRawPtr<CSSValue> toImageValue = consumeImage(args, context); | |
| 2572 if (!toImageValue || !consumeCommaIncludingWhitespace(args)) | |
| 2573 return nullptr; | |
| 2574 | |
| 2575 RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage = nullptr; | |
| 2576 const CSSParserToken& percentageArg = args.consumeIncludingWhitespace(); | |
| 2577 if (percentageArg.type() == PercentageToken) | |
| 2578 percentage = cssValuePool().createValue(clampTo<double>(percentageArg.nu mericValue() / 100, 0, 1), CSSPrimitiveValue::UnitType::Number); | |
| 2579 else if (percentageArg.type() == NumberToken) | |
| 2580 percentage = cssValuePool().createValue(clampTo<double>(percentageArg.nu mericValue(), 0, 1), CSSPrimitiveValue::UnitType::Number); | |
| 2581 | |
| 2582 if (!percentage || !args.atEnd()) | |
| 2583 return nullptr; | |
| 2584 | |
| 2585 return CSSCrossfadeValue::create(fromImageValue, toImageValue, percentage); | |
| 2586 } | |
| 2587 | |
| 2588 static PassRefPtrWillBeRawPtr<CSSValue> consumeGeneratedImage(CSSParserTokenRang e& range, CSSParserContext context) | |
|
Timothy Loh
2015/12/09 06:59:57
As usual, we need to make sure this doesn't accide
rwlbuis
2015/12/09 21:31:14
Done.
Timothy Loh
2015/12/10 04:20:07
Any reason to not use else if here? (which imo mak
| |
| 2589 { | |
| 2590 CSSValueID id = range.peek().functionId(); | |
| 2591 if (id == CSSValueRadialGradient) | |
| 2592 return consumeRadialGradient(consumeFunction(range), context, NonRepeati ng); | |
| 2593 if (id == CSSValueWebkitLinearGradient) { | |
| 2594 // FIXME: This should send a deprecation message. | |
| 2595 if (context.useCounter()) | |
| 2596 context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradie nt); | |
| 2597 return consumeLinearGradient(consumeFunction(range), context, NonRepeati ng, CSSPrefixedLinearGradient); | |
| 2598 } | |
| 2599 if (id == CSSValueWebkitRepeatingLinearGradient) { | |
| 2600 // FIXME: This should send a deprecation message. | |
| 2601 if (context.useCounter()) | |
| 2602 context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLin earGradient); | |
| 2603 return consumeLinearGradient(consumeFunction(range), context, Repeating, CSSPrefixedLinearGradient); | |
| 2604 } | |
| 2605 if (id == CSSValueLinearGradient) | |
| 2606 return consumeLinearGradient(consumeFunction(range), context, NonRepeati ng, CSSLinearGradient); | |
| 2607 if (id == CSSValueWebkitCrossFade) | |
| 2608 return consumeCrossFade(consumeFunction(range), context); | |
| 2609 return nullptr; | |
| 2610 } | |
| 2611 | |
| 2612 static PassRefPtrWillBeRawPtr<CSSValue> consumeImage(CSSParserTokenRange& range, CSSParserContext context) | |
| 2613 { | |
| 2614 if (range.peek().id() == CSSValueNone) | |
| 2615 return consumeIdent(range); | |
| 2616 | |
| 2617 AtomicString uri(consumeUrl(range)); | |
| 2618 if (!uri.isNull()) | |
| 2619 return CSSPropertyParser::createCSSImageValueWithReferrer(uri, context); | |
| 2620 if (range.peek().type() == FunctionToken) { | |
| 2621 CSSValueID id = range.peek().functionId(); | |
| 2622 if (id == CSSValueWebkitImageSet) | |
| 2623 return consumeImageSet(range, context); | |
| 2624 if (CSSPropertyParser::isGeneratedImage(id)) | |
| 2625 return consumeGeneratedImage(range, context); | |
| 2626 } | |
| 2627 return nullptr; | |
| 2628 } | |
| 2629 | |
| 2408 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSProperty ID unresolvedProperty) | 2630 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSProperty ID unresolvedProperty) |
| 2409 { | 2631 { |
| 2410 CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty); | 2632 CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty); |
| 2411 switch (property) { | 2633 switch (property) { |
| 2412 case CSSPropertyWillChange: | 2634 case CSSPropertyWillChange: |
| 2413 return consumeWillChange(m_range); | 2635 return consumeWillChange(m_range); |
| 2414 case CSSPropertyPage: | 2636 case CSSPropertyPage: |
| 2415 return consumePage(m_range); | 2637 return consumePage(m_range); |
| 2416 case CSSPropertyQuotes: | 2638 case CSSPropertyQuotes: |
| 2417 return consumeQuotes(m_range); | 2639 return consumeQuotes(m_range); |
| (...skipping 816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3234 return consumeShorthandGreedily(flexFlowShorthand(), important); | 3456 return consumeShorthandGreedily(flexFlowShorthand(), important); |
| 3235 case CSSPropertyWebkitColumnRule: | 3457 case CSSPropertyWebkitColumnRule: |
| 3236 return consumeShorthandGreedily(webkitColumnRuleShorthand(), important); | 3458 return consumeShorthandGreedily(webkitColumnRuleShorthand(), important); |
| 3237 default: | 3459 default: |
| 3238 m_currentShorthand = oldShorthand; | 3460 m_currentShorthand = oldShorthand; |
| 3239 return false; | 3461 return false; |
| 3240 } | 3462 } |
| 3241 } | 3463 } |
| 3242 | 3464 |
| 3243 } // namespace blink | 3465 } // namespace blink |
| OLD | NEW |