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 |