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) | |
Timothy Loh
2015/12/10 04:20:07
Can you update all the CSSParserContext arguments
rwlbuis
2015/12/10 14:00:08
Done.
| |
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 do { | |
2416 CSSGradientColorStop stop; | |
2417 stop.m_color = consumeColor(range, context); | |
2418 // Two hints in a row are not allowed. | |
2419 if (!stop.m_color && (!supportsColorHints || previousStopWasColorHint)) | |
2420 return false; | |
2421 previousStopWasColorHint = !stop.m_color; | |
2422 stop.m_position = consumeLengthOrPercent(range, context.mode(), ValueRan geAll); | |
2423 if (!stop.m_color && !stop.m_position) | |
2424 return false; | |
2425 gradient->addStop(stop); | |
2426 } while (consumeCommaIncludingWhitespace(range)); | |
2427 | |
2428 // The last color stop cannot be a color hint. | |
2429 if (previousStopWasColorHint) | |
2430 return false; | |
2431 | |
2432 // Must have 2 or more stops to be valid. | |
2433 return gradient->stopCount() >= 2; | |
2434 } | |
2435 | |
2436 static PassRefPtrWillBeRawPtr<CSSValue> consumeRadialGradient(CSSParserTokenRang e& args, CSSParserContext context, CSSGradientRepeat repeating) | |
2437 { | |
2438 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue:: create(repeating, CSSRadialGradient); | |
2439 | |
2440 RefPtrWillBeRawPtr<CSSPrimitiveValue> shape = nullptr; | |
2441 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeKeyword = nullptr; | |
2442 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr; | |
2443 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr; | |
2444 | |
2445 // First part of grammar, the size/shape clause: | |
2446 // [ circle || <length> ] | | |
2447 // [ ellipse || [ <length> | <percentage> ]{2} ] | | |
2448 // [ [ circle | ellipse] || <size-keyword> ] | |
2449 for (int i = 0; i < 3; ++i) { | |
2450 if (args.peek().type() == IdentToken) { | |
2451 CSSValueID id = args.peek().id(); | |
2452 if (id == CSSValueCircle || id == CSSValueEllipse) { | |
2453 if (shape) | |
2454 return nullptr; | |
2455 shape = consumeIdent(args); | |
2456 } else if (id == CSSValueClosestSide || id == CSSValueClosestCorner || id == CSSValueFarthestSide || id == CSSValueFarthestCorner) { | |
2457 if (sizeKeyword) | |
2458 return nullptr; | |
2459 sizeKeyword = consumeIdent(args); | |
2460 } else { | |
2461 break; | |
2462 } | |
2463 } else { | |
2464 RefPtrWillBeRawPtr<CSSPrimitiveValue> center = consumeLengthOrPercen t(args, context.mode(), ValueRangeAll); | |
2465 if (!center) | |
2466 break; | |
2467 if (horizontalSize) | |
2468 return nullptr; | |
2469 horizontalSize = center; | |
2470 if ((center = consumeLengthOrPercent(args, context.mode(), ValueRang eAll))) { | |
2471 verticalSize = center.release(); | |
2472 ++i; | |
2473 } | |
2474 } | |
2475 } | |
2476 | |
2477 // You can specify size as a keyword or a length/percentage, not both. | |
2478 if (sizeKeyword && horizontalSize) | |
2479 return nullptr; | |
2480 // Circles must have 0 or 1 lengths. | |
2481 if (shape && shape->getValueID() == CSSValueCircle && verticalSize) | |
2482 return nullptr; | |
2483 // Ellipses must have 0 or 2 length/percentages. | |
2484 if (shape && shape->getValueID() == CSSValueEllipse && horizontalSize && !ve rticalSize) | |
2485 return nullptr; | |
2486 // If there's only one size, it must be a length. | |
2487 // TODO(timloh): Calcs with both lengths and percentages should be rejected. | |
2488 if (!verticalSize && horizontalSize && horizontalSize->isPercentage()) | |
2489 return nullptr; | |
2490 | |
2491 result->setShape(shape); | |
2492 result->setSizingBehavior(sizeKeyword); | |
2493 result->setEndHorizontalSize(horizontalSize); | |
2494 result->setEndVerticalSize(verticalSize); | |
2495 | |
2496 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr; | |
2497 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr; | |
2498 if (args.peek().id() == CSSValueAt) { | |
2499 args.consumeIncludingWhitespace(); | |
2500 consumePosition(args, context.mode(), UnitlessQuirk::Forbid, centerX, ce nterY); | |
2501 if (!(centerX && centerY)) | |
2502 return nullptr; | |
2503 result->setFirstX(centerX); | |
2504 result->setFirstY(centerY); | |
2505 // Right now, CSS radial gradients have the same start and end centers. | |
2506 result->setSecondX(centerX); | |
2507 result->setSecondY(centerY); | |
2508 } | |
2509 | |
2510 if ((shape || sizeKeyword || horizontalSize || centerX || centerY) && !consu meCommaIncludingWhitespace(args)) | |
2511 return nullptr; | |
2512 if (!consumeGradientColorStops(args, context, result.get())) | |
2513 return nullptr; | |
2514 return result.release(); | |
2515 } | |
2516 | |
2517 static PassRefPtrWillBeRawPtr<CSSValue> consumeLinearGradient(CSSParserTokenRang e& args, CSSParserContext context, CSSGradientRepeat repeating, CSSGradientType gradientType) | |
2518 { | |
2519 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue:: create(repeating, gradientType); | |
2520 | |
2521 bool expectComma = true; | |
2522 RefPtrWillBeRawPtr<CSSPrimitiveValue> angle = consumeAngle(args, context.mod e()); | |
2523 if (angle) { | |
2524 result->setAngle(angle.release()); | |
2525 } else if (gradientType == CSSPrefixedLinearGradient || consumeIdent<CSSValu eTo>(args)) { | |
2526 RefPtrWillBeRawPtr<CSSPrimitiveValue> endX = consumeIdent<CSSValueLeft, CSSValueRight>(args); | |
2527 RefPtrWillBeRawPtr<CSSPrimitiveValue> endY = consumeIdent<CSSValueBottom , CSSValueTop>(args); | |
2528 if (gradientType == CSSLinearGradient && !endX && !endY) | |
Timothy Loh
2015/12/10 04:20:07
Clearer like this IMO, moving the two !endX && !en
rwlbuis
2015/12/10 14:00:08
Much better, done.
| |
2529 return nullptr; | |
2530 if (!endX) | |
2531 endX = consumeIdent<CSSValueLeft, CSSValueRight>(args); | |
2532 if (!endY) | |
2533 endY = consumeIdent<CSSValueBottom, CSSValueTop>(args); | |
2534 | |
2535 if (!endX && !endY) { | |
2536 endY = cssValuePool().createIdentifierValue(CSSValueTop); | |
2537 expectComma = false; | |
2538 } | |
2539 | |
2540 result->setFirstX(endX.release()); | |
2541 result->setFirstY(endY.release()); | |
2542 } | |
Timothy Loh
2015/12/10 04:20:07
Since you made expectComma start at true, we need
rwlbuis
2015/12/10 14:00:08
Done.
| |
2543 | |
2544 if (expectComma && !consumeCommaIncludingWhitespace(args)) | |
2545 return nullptr; | |
2546 if (!consumeGradientColorStops(args, context, result.get())) | |
2547 return nullptr; | |
2548 return result.release(); | |
2549 } | |
2550 | |
2551 static PassRefPtrWillBeRawPtr<CSSValue> consumeImage(CSSParserTokenRange&, CSSPa rserContext); | |
2552 | |
2553 static PassRefPtrWillBeRawPtr<CSSValue> consumeCrossFade(CSSParserTokenRange& ar gs, CSSParserContext context) | |
2554 { | |
2555 RefPtrWillBeRawPtr<CSSValue> fromImageValue = consumeImage(args, context); | |
2556 if (!fromImageValue || !consumeCommaIncludingWhitespace(args)) | |
2557 return nullptr; | |
2558 RefPtrWillBeRawPtr<CSSValue> toImageValue = consumeImage(args, context); | |
2559 if (!toImageValue || !consumeCommaIncludingWhitespace(args)) | |
2560 return nullptr; | |
2561 | |
2562 RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage = nullptr; | |
2563 const CSSParserToken& percentageArg = args.consumeIncludingWhitespace(); | |
2564 if (percentageArg.type() == PercentageToken) | |
2565 percentage = cssValuePool().createValue(clampTo<double>(percentageArg.nu mericValue() / 100, 0, 1), CSSPrimitiveValue::UnitType::Number); | |
2566 else if (percentageArg.type() == NumberToken) | |
2567 percentage = cssValuePool().createValue(clampTo<double>(percentageArg.nu mericValue(), 0, 1), CSSPrimitiveValue::UnitType::Number); | |
2568 | |
2569 if (!percentage) | |
2570 return nullptr; | |
2571 return CSSCrossfadeValue::create(fromImageValue, toImageValue, percentage); | |
2572 } | |
2573 | |
2574 static PassRefPtrWillBeRawPtr<CSSValue> consumeGeneratedImage(CSSParserTokenRang e& range, CSSParserContext context) | |
2575 { | |
2576 CSSValueID id = range.peek().functionId(); | |
2577 CSSParserTokenRange rangeCopy = range; | |
2578 CSSParserTokenRange args = consumeFunction(rangeCopy); | |
2579 RefPtrWillBeRawPtr<CSSValue> result = nullptr; | |
2580 if (id == CSSValueRadialGradient) | |
2581 result = consumeRadialGradient(args, context, NonRepeating); | |
2582 if (id == CSSValueWebkitLinearGradient) { | |
2583 // FIXME: This should send a deprecation message. | |
2584 if (context.useCounter()) | |
2585 context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradie nt); | |
2586 result = consumeLinearGradient(args, context, NonRepeating, CSSPrefixedL inearGradient); | |
2587 } | |
2588 if (id == CSSValueWebkitRepeatingLinearGradient) { | |
2589 // FIXME: This should send a deprecation message. | |
2590 if (context.useCounter()) | |
2591 context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLin earGradient); | |
2592 result = consumeLinearGradient(args, context, Repeating, CSSPrefixedLine arGradient); | |
2593 } | |
2594 if (id == CSSValueLinearGradient) | |
2595 result = consumeLinearGradient(args, context, NonRepeating, CSSLinearGra dient); | |
2596 if (id == CSSValueWebkitCrossFade) | |
2597 result = consumeCrossFade(args, context); | |
2598 if (!result || !args.atEnd()) | |
2599 return nullptr; | |
2600 range = rangeCopy; | |
2601 return result; | |
2602 } | |
2603 | |
2604 static PassRefPtrWillBeRawPtr<CSSValue> consumeImage(CSSParserTokenRange& range, CSSParserContext context) | |
2605 { | |
2606 if (range.peek().id() == CSSValueNone) | |
2607 return consumeIdent(range); | |
2608 | |
2609 AtomicString uri(consumeUrl(range)); | |
2610 if (!uri.isNull()) | |
2611 return CSSPropertyParser::createCSSImageValueWithReferrer(uri, context); | |
2612 if (range.peek().type() == FunctionToken) { | |
2613 CSSValueID id = range.peek().functionId(); | |
2614 if (id == CSSValueWebkitImageSet) | |
2615 return consumeImageSet(range, context); | |
2616 if (CSSPropertyParser::isGeneratedImage(id)) | |
2617 return consumeGeneratedImage(range, context); | |
2618 } | |
2619 return nullptr; | |
2620 } | |
2621 | |
2408 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSProperty ID unresolvedProperty) | 2622 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSProperty ID unresolvedProperty) |
2409 { | 2623 { |
2410 CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty); | 2624 CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty); |
2411 switch (property) { | 2625 switch (property) { |
2412 case CSSPropertyWillChange: | 2626 case CSSPropertyWillChange: |
2413 return consumeWillChange(m_range); | 2627 return consumeWillChange(m_range); |
2414 case CSSPropertyPage: | 2628 case CSSPropertyPage: |
2415 return consumePage(m_range); | 2629 return consumePage(m_range); |
2416 case CSSPropertyQuotes: | 2630 case CSSPropertyQuotes: |
2417 return consumeQuotes(m_range); | 2631 return consumeQuotes(m_range); |
(...skipping 816 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3234 return consumeShorthandGreedily(flexFlowShorthand(), important); | 3448 return consumeShorthandGreedily(flexFlowShorthand(), important); |
3235 case CSSPropertyWebkitColumnRule: | 3449 case CSSPropertyWebkitColumnRule: |
3236 return consumeShorthandGreedily(webkitColumnRuleShorthand(), important); | 3450 return consumeShorthandGreedily(webkitColumnRuleShorthand(), important); |
3237 default: | 3451 default: |
3238 m_currentShorthand = oldShorthand; | 3452 m_currentShorthand = oldShorthand; |
3239 return false; | 3453 return false; |
3240 } | 3454 } |
3241 } | 3455 } |
3242 | 3456 |
3243 } // namespace blink | 3457 } // namespace blink |
OLD | NEW |