OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "core/css/parser/CSSPropertyParserHelpers.h" | 5 #include "core/css/parser/CSSPropertyParserHelpers.h" |
6 | 6 |
7 #include "core/css/CSSCalculationValue.h" | 7 #include "core/css/CSSCalculationValue.h" |
8 #include "core/css/CSSColorValue.h" | 8 #include "core/css/CSSColorValue.h" |
| 9 #include "core/css/CSSCrossfadeValue.h" |
| 10 #include "core/css/CSSGradientValue.h" |
| 11 #include "core/css/CSSImageSetValue.h" |
| 12 #include "core/css/CSSImageValue.h" |
| 13 #include "core/css/CSSPaintValue.h" |
9 #include "core/css/CSSStringValue.h" | 14 #include "core/css/CSSStringValue.h" |
10 #include "core/css/CSSValuePair.h" | 15 #include "core/css/CSSValuePair.h" |
| 16 #include "core/frame/UseCounter.h" |
11 | 17 |
12 namespace blink { | 18 namespace blink { |
13 | 19 |
14 namespace CSSPropertyParserHelpers { | 20 namespace CSSPropertyParserHelpers { |
15 | 21 |
16 bool consumeCommaIncludingWhitespace(CSSParserTokenRange& range) | 22 bool consumeCommaIncludingWhitespace(CSSParserTokenRange& range) |
17 { | 23 { |
18 CSSParserToken value = range.peek(); | 24 CSSParserToken value = range.peek(); |
19 if (value.type() != CommaToken) | 25 if (value.type() != CommaToken) |
20 return false; | 26 return false; |
(...skipping 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 if (!value1) | 612 if (!value1) |
607 return false; | 613 return false; |
608 CSSPrimitiveValue* value2 = consumePositionComponent(range, cssParserMode, u
nitless); | 614 CSSPrimitiveValue* value2 = consumePositionComponent(range, cssParserMode, u
nitless); |
609 if (!value2) { | 615 if (!value2) { |
610 positionFromOneValue(value1, resultX, resultY); | 616 positionFromOneValue(value1, resultX, resultY); |
611 return true; | 617 return true; |
612 } | 618 } |
613 return positionFromTwoValues(value1, value2, resultX, resultY); | 619 return positionFromTwoValues(value1, value2, resultX, resultY); |
614 } | 620 } |
615 | 621 |
| 622 // This should go away once we drop support for -webkit-gradient |
| 623 static CSSPrimitiveValue* consumeDeprecatedGradientPoint(CSSParserTokenRange& ar
gs, bool horizontal) |
| 624 { |
| 625 if (args.peek().type() == IdentToken) { |
| 626 if ((horizontal && consumeIdent<CSSValueLeft>(args)) || (!horizontal &&
consumeIdent<CSSValueTop>(args))) |
| 627 return CSSPrimitiveValue::create(0., CSSPrimitiveValue::UnitType::Pe
rcentage); |
| 628 if ((horizontal && consumeIdent<CSSValueRight>(args)) || (!horizontal &&
consumeIdent<CSSValueBottom>(args))) |
| 629 return CSSPrimitiveValue::create(100., CSSPrimitiveValue::UnitType::
Percentage); |
| 630 if (consumeIdent<CSSValueCenter>(args)) |
| 631 return CSSPrimitiveValue::create(50., CSSPrimitiveValue::UnitType::P
ercentage); |
| 632 return nullptr; |
| 633 } |
| 634 CSSPrimitiveValue* result = consumePercent(args, ValueRangeAll); |
| 635 if (!result) |
| 636 result = consumeNumber(args, ValueRangeAll); |
| 637 return result; |
| 638 } |
| 639 |
| 640 // Used to parse colors for -webkit-gradient(...). |
| 641 static CSSValue* consumeDeprecatedGradientStopColor(CSSParserTokenRange& args, C
SSParserMode cssParserMode) |
| 642 { |
| 643 if (args.peek().id() == CSSValueCurrentcolor) |
| 644 return nullptr; |
| 645 return consumeColor(args, cssParserMode); |
| 646 } |
| 647 |
| 648 static bool consumeDeprecatedGradientColorStop(CSSParserTokenRange& range, CSSGr
adientColorStop& stop, CSSParserMode cssParserMode) |
| 649 { |
| 650 CSSValueID id = range.peek().functionId(); |
| 651 if (id != CSSValueFrom && id != CSSValueTo && id != CSSValueColorStop) |
| 652 return false; |
| 653 |
| 654 CSSParserTokenRange args = consumeFunction(range); |
| 655 double position; |
| 656 if (id == CSSValueFrom || id == CSSValueTo) { |
| 657 position = (id == CSSValueFrom) ? 0 : 1; |
| 658 } else { |
| 659 DCHECK(id == CSSValueColorStop); |
| 660 const CSSParserToken& arg = args.consumeIncludingWhitespace(); |
| 661 if (arg.type() == PercentageToken) |
| 662 position = arg.numericValue() / 100.0; |
| 663 else if (arg.type() == NumberToken) |
| 664 position = arg.numericValue(); |
| 665 else |
| 666 return false; |
| 667 |
| 668 if (!consumeCommaIncludingWhitespace(args)) |
| 669 return false; |
| 670 } |
| 671 |
| 672 stop.m_position = CSSPrimitiveValue::create(position, CSSPrimitiveValue::Uni
tType::Number); |
| 673 stop.m_color = consumeDeprecatedGradientStopColor(args, cssParserMode); |
| 674 return stop.m_color && args.atEnd(); |
| 675 } |
| 676 |
| 677 static CSSValue* consumeDeprecatedGradient(CSSParserTokenRange& args, CSSParserM
ode cssParserMode) |
| 678 { |
| 679 CSSGradientValue* result = nullptr; |
| 680 CSSValueID id = args.consumeIncludingWhitespace().id(); |
| 681 bool isDeprecatedRadialGradient = (id == CSSValueRadial); |
| 682 if (isDeprecatedRadialGradient) |
| 683 result = CSSRadialGradientValue::create(NonRepeating, CSSDeprecatedRadia
lGradient); |
| 684 else if (id == CSSValueLinear) |
| 685 result = CSSLinearGradientValue::create(NonRepeating, CSSDeprecatedLinea
rGradient); |
| 686 if (!result || !consumeCommaIncludingWhitespace(args)) |
| 687 return nullptr; |
| 688 |
| 689 CSSPrimitiveValue* point = consumeDeprecatedGradientPoint(args, true); |
| 690 if (!point) |
| 691 return nullptr; |
| 692 result->setFirstX(point); |
| 693 point = consumeDeprecatedGradientPoint(args, false); |
| 694 if (!point) |
| 695 return nullptr; |
| 696 result->setFirstY(point); |
| 697 |
| 698 if (!consumeCommaIncludingWhitespace(args)) |
| 699 return nullptr; |
| 700 |
| 701 // For radial gradients only, we now expect a numeric radius. |
| 702 if (isDeprecatedRadialGradient) { |
| 703 CSSPrimitiveValue* radius = consumeNumber(args, ValueRangeAll); |
| 704 if (!radius || !consumeCommaIncludingWhitespace(args)) |
| 705 return nullptr; |
| 706 toCSSRadialGradientValue(result)->setFirstRadius(radius); |
| 707 } |
| 708 |
| 709 point = consumeDeprecatedGradientPoint(args, true); |
| 710 if (!point) |
| 711 return nullptr; |
| 712 result->setSecondX(point); |
| 713 point = consumeDeprecatedGradientPoint(args, false); |
| 714 if (!point) |
| 715 return nullptr; |
| 716 result->setSecondY(point); |
| 717 |
| 718 // For radial gradients only, we now expect the second radius. |
| 719 if (isDeprecatedRadialGradient) { |
| 720 if (!consumeCommaIncludingWhitespace(args)) |
| 721 return nullptr; |
| 722 CSSPrimitiveValue* radius = consumeNumber(args, ValueRangeAll); |
| 723 if (!radius) |
| 724 return nullptr; |
| 725 toCSSRadialGradientValue(result)->setSecondRadius(radius); |
| 726 } |
| 727 |
| 728 CSSGradientColorStop stop; |
| 729 while (consumeCommaIncludingWhitespace(args)) { |
| 730 if (!consumeDeprecatedGradientColorStop(args, stop, cssParserMode)) |
| 731 return nullptr; |
| 732 result->addStop(stop); |
| 733 } |
| 734 |
| 735 return result; |
| 736 } |
| 737 |
| 738 static bool consumeGradientColorStops(CSSParserTokenRange& range, CSSParserMode
cssParserMode, CSSGradientValue* gradient) |
| 739 { |
| 740 bool supportsColorHints = gradient->gradientType() == CSSLinearGradient || g
radient->gradientType() == CSSRadialGradient; |
| 741 |
| 742 // The first color stop cannot be a color hint. |
| 743 bool previousStopWasColorHint = true; |
| 744 do { |
| 745 CSSGradientColorStop stop; |
| 746 stop.m_color = consumeColor(range, cssParserMode); |
| 747 // Two hints in a row are not allowed. |
| 748 if (!stop.m_color && (!supportsColorHints || previousStopWasColorHint)) |
| 749 return false; |
| 750 previousStopWasColorHint = !stop.m_color; |
| 751 stop.m_position = consumeLengthOrPercent(range, cssParserMode, ValueRang
eAll); |
| 752 if (!stop.m_color && !stop.m_position) |
| 753 return false; |
| 754 gradient->addStop(stop); |
| 755 } while (consumeCommaIncludingWhitespace(range)); |
| 756 |
| 757 // The last color stop cannot be a color hint. |
| 758 if (previousStopWasColorHint) |
| 759 return false; |
| 760 |
| 761 // Must have 2 or more stops to be valid. |
| 762 return gradient->stopCount() >= 2; |
| 763 } |
| 764 |
| 765 static CSSValue* consumeDeprecatedRadialGradient(CSSParserTokenRange& args, CSSP
arserMode cssParserMode, CSSGradientRepeat repeating) |
| 766 { |
| 767 CSSRadialGradientValue* result = CSSRadialGradientValue::create(repeating, C
SSPrefixedRadialGradient); |
| 768 CSSValue* centerX = nullptr; |
| 769 CSSValue* centerY = nullptr; |
| 770 consumeOneOrTwoValuedPosition(args, cssParserMode, UnitlessQuirk::Forbid, ce
nterX, centerY); |
| 771 if ((centerX || centerY) && !consumeCommaIncludingWhitespace(args)) |
| 772 return nullptr; |
| 773 |
| 774 result->setFirstX(toCSSPrimitiveValue(centerX)); |
| 775 result->setSecondX(toCSSPrimitiveValue(centerX)); |
| 776 result->setFirstY(toCSSPrimitiveValue(centerY)); |
| 777 result->setSecondY(toCSSPrimitiveValue(centerY)); |
| 778 |
| 779 CSSPrimitiveValue* shape = consumeIdent<CSSValueCircle, CSSValueEllipse>(arg
s); |
| 780 CSSPrimitiveValue* sizeKeyword = consumeIdent<CSSValueClosestSide, CSSValueC
losestCorner, CSSValueFarthestSide, CSSValueFarthestCorner, CSSValueContain, CSS
ValueCover>(args); |
| 781 if (!shape) |
| 782 shape = consumeIdent<CSSValueCircle, CSSValueEllipse>(args); |
| 783 result->setShape(shape); |
| 784 result->setSizingBehavior(sizeKeyword); |
| 785 |
| 786 // Or, two lengths or percentages |
| 787 if (!shape && !sizeKeyword) { |
| 788 CSSPrimitiveValue* horizontalSize = consumeLengthOrPercent(args, cssPars
erMode, ValueRangeAll); |
| 789 CSSPrimitiveValue* verticalSize = nullptr; |
| 790 if (horizontalSize) { |
| 791 verticalSize = consumeLengthOrPercent(args, cssParserMode, ValueRang
eAll); |
| 792 if (!verticalSize) |
| 793 return nullptr; |
| 794 consumeCommaIncludingWhitespace(args); |
| 795 result->setEndHorizontalSize(horizontalSize); |
| 796 result->setEndVerticalSize(verticalSize); |
| 797 } |
| 798 } else { |
| 799 consumeCommaIncludingWhitespace(args); |
| 800 } |
| 801 if (!consumeGradientColorStops(args, cssParserMode, result)) |
| 802 return nullptr; |
| 803 |
| 804 return result; |
| 805 } |
| 806 |
| 807 static CSSValue* consumeRadialGradient(CSSParserTokenRange& args, CSSParserMode
cssParserMode, CSSGradientRepeat repeating) |
| 808 { |
| 809 CSSRadialGradientValue* result = CSSRadialGradientValue::create(repeating, C
SSRadialGradient); |
| 810 |
| 811 CSSPrimitiveValue* shape = nullptr; |
| 812 CSSPrimitiveValue* sizeKeyword = nullptr; |
| 813 CSSPrimitiveValue* horizontalSize = nullptr; |
| 814 CSSPrimitiveValue* verticalSize = nullptr; |
| 815 |
| 816 // First part of grammar, the size/shape clause: |
| 817 // [ circle || <length> ] | |
| 818 // [ ellipse || [ <length> | <percentage> ]{2} ] | |
| 819 // [ [ circle | ellipse] || <size-keyword> ] |
| 820 for (int i = 0; i < 3; ++i) { |
| 821 if (args.peek().type() == IdentToken) { |
| 822 CSSValueID id = args.peek().id(); |
| 823 if (id == CSSValueCircle || id == CSSValueEllipse) { |
| 824 if (shape) |
| 825 return nullptr; |
| 826 shape = consumeIdent(args); |
| 827 } else if (id == CSSValueClosestSide || id == CSSValueClosestCorner
|| id == CSSValueFarthestSide || id == CSSValueFarthestCorner) { |
| 828 if (sizeKeyword) |
| 829 return nullptr; |
| 830 sizeKeyword = consumeIdent(args); |
| 831 } else { |
| 832 break; |
| 833 } |
| 834 } else { |
| 835 CSSPrimitiveValue* center = consumeLengthOrPercent(args, cssParserMo
de, ValueRangeAll); |
| 836 if (!center) |
| 837 break; |
| 838 if (horizontalSize) |
| 839 return nullptr; |
| 840 horizontalSize = center; |
| 841 center = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll); |
| 842 if (center) { |
| 843 verticalSize = center; |
| 844 ++i; |
| 845 } |
| 846 } |
| 847 } |
| 848 |
| 849 // You can specify size as a keyword or a length/percentage, not both. |
| 850 if (sizeKeyword && horizontalSize) |
| 851 return nullptr; |
| 852 // Circles must have 0 or 1 lengths. |
| 853 if (shape && shape->getValueID() == CSSValueCircle && verticalSize) |
| 854 return nullptr; |
| 855 // Ellipses must have 0 or 2 length/percentages. |
| 856 if (shape && shape->getValueID() == CSSValueEllipse && horizontalSize && !ve
rticalSize) |
| 857 return nullptr; |
| 858 // If there's only one size, it must be a length. |
| 859 if (!verticalSize && horizontalSize && horizontalSize->isPercentage()) |
| 860 return nullptr; |
| 861 if ((horizontalSize && horizontalSize->isCalculatedPercentageWithLength()) |
| 862 || (verticalSize && verticalSize->isCalculatedPercentageWithLength())) |
| 863 return nullptr; |
| 864 |
| 865 result->setShape(shape); |
| 866 result->setSizingBehavior(sizeKeyword); |
| 867 result->setEndHorizontalSize(horizontalSize); |
| 868 result->setEndVerticalSize(verticalSize); |
| 869 |
| 870 CSSValue* centerX = nullptr; |
| 871 CSSValue* centerY = nullptr; |
| 872 if (args.peek().id() == CSSValueAt) { |
| 873 args.consumeIncludingWhitespace(); |
| 874 consumePosition(args, cssParserMode, UnitlessQuirk::Forbid, centerX, cen
terY); |
| 875 if (!(centerX && centerY)) |
| 876 return nullptr; |
| 877 result->setFirstX(centerX); |
| 878 result->setFirstY(centerY); |
| 879 // Right now, CSS radial gradients have the same start and end centers. |
| 880 result->setSecondX(centerX); |
| 881 result->setSecondY(centerY); |
| 882 } |
| 883 |
| 884 if ((shape || sizeKeyword || horizontalSize || centerX || centerY) && !consu
meCommaIncludingWhitespace(args)) |
| 885 return nullptr; |
| 886 if (!consumeGradientColorStops(args, cssParserMode, result)) |
| 887 return nullptr; |
| 888 return result; |
| 889 } |
| 890 |
| 891 static CSSValue* consumeLinearGradient(CSSParserTokenRange& args, CSSParserMode
cssParserMode, CSSGradientRepeat repeating, CSSGradientType gradientType) |
| 892 { |
| 893 CSSLinearGradientValue* result = CSSLinearGradientValue::create(repeating, g
radientType); |
| 894 |
| 895 bool expectComma = true; |
| 896 CSSPrimitiveValue* angle = consumeAngle(args); |
| 897 if (angle) { |
| 898 result->setAngle(angle); |
| 899 } else if (gradientType == CSSPrefixedLinearGradient || consumeIdent<CSSValu
eTo>(args)) { |
| 900 CSSPrimitiveValue* endX = consumeIdent<CSSValueLeft, CSSValueRight>(args
); |
| 901 CSSPrimitiveValue* endY = consumeIdent<CSSValueBottom, CSSValueTop>(args
); |
| 902 if (!endX && !endY) { |
| 903 if (gradientType == CSSLinearGradient) |
| 904 return nullptr; |
| 905 endY = CSSPrimitiveValue::createIdentifier(CSSValueTop); |
| 906 expectComma = false; |
| 907 } else if (!endX) { |
| 908 endX = consumeIdent<CSSValueLeft, CSSValueRight>(args); |
| 909 } |
| 910 |
| 911 result->setFirstX(endX); |
| 912 result->setFirstY(endY); |
| 913 } else { |
| 914 expectComma = false; |
| 915 } |
| 916 |
| 917 if (expectComma && !consumeCommaIncludingWhitespace(args)) |
| 918 return nullptr; |
| 919 if (!consumeGradientColorStops(args, cssParserMode, result)) |
| 920 return nullptr; |
| 921 return result; |
| 922 } |
| 923 |
| 924 CSSValue* consumeImageOrNone(CSSParserTokenRange& range, CSSParserContext contex
t) |
| 925 { |
| 926 if (range.peek().id() == CSSValueNone) |
| 927 return consumeIdent(range); |
| 928 return consumeImage(range, context); |
| 929 } |
| 930 |
| 931 static CSSValue* consumeCrossFade(CSSParserTokenRange& args, CSSParserContext co
ntext) |
| 932 { |
| 933 CSSValue* fromImageValue = consumeImageOrNone(args, context); |
| 934 if (!fromImageValue || !consumeCommaIncludingWhitespace(args)) |
| 935 return nullptr; |
| 936 CSSValue* toImageValue = consumeImageOrNone(args, context); |
| 937 if (!toImageValue || !consumeCommaIncludingWhitespace(args)) |
| 938 return nullptr; |
| 939 |
| 940 CSSPrimitiveValue* percentage = nullptr; |
| 941 const CSSParserToken& percentageArg = args.consumeIncludingWhitespace(); |
| 942 if (percentageArg.type() == PercentageToken) |
| 943 percentage = CSSPrimitiveValue::create(clampTo<double>(percentageArg.num
ericValue() / 100, 0, 1), CSSPrimitiveValue::UnitType::Number); |
| 944 else if (percentageArg.type() == NumberToken) |
| 945 percentage = CSSPrimitiveValue::create(clampTo<double>(percentageArg.num
ericValue(), 0, 1), CSSPrimitiveValue::UnitType::Number); |
| 946 |
| 947 if (!percentage) |
| 948 return nullptr; |
| 949 return CSSCrossfadeValue::create(fromImageValue, toImageValue, percentage); |
| 950 } |
| 951 |
| 952 static CSSValue* consumePaint(CSSParserTokenRange& args, CSSParserContext contex
t) |
| 953 { |
| 954 DCHECK(RuntimeEnabledFeatures::cssPaintAPIEnabled()); |
| 955 |
| 956 CSSCustomIdentValue* name = consumeCustomIdent(args); |
| 957 if (!name) |
| 958 return nullptr; |
| 959 |
| 960 return CSSPaintValue::create(name); |
| 961 } |
| 962 |
| 963 static CSSValue* consumeGeneratedImage(CSSParserTokenRange& range, CSSParserCont
ext context) |
| 964 { |
| 965 CSSValueID id = range.peek().functionId(); |
| 966 CSSParserTokenRange rangeCopy = range; |
| 967 CSSParserTokenRange args = consumeFunction(rangeCopy); |
| 968 CSSValue* result = nullptr; |
| 969 if (id == CSSValueRadialGradient) { |
| 970 result = consumeRadialGradient(args, context.mode(), NonRepeating); |
| 971 } else if (id == CSSValueRepeatingRadialGradient) { |
| 972 result = consumeRadialGradient(args, context.mode(), Repeating); |
| 973 } else if (id == CSSValueWebkitLinearGradient) { |
| 974 // FIXME: This should send a deprecation message. |
| 975 if (context.useCounter()) |
| 976 context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradie
nt); |
| 977 result = consumeLinearGradient(args, context.mode(), NonRepeating, CSSPr
efixedLinearGradient); |
| 978 } else if (id == CSSValueWebkitRepeatingLinearGradient) { |
| 979 // FIXME: This should send a deprecation message. |
| 980 if (context.useCounter()) |
| 981 context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLin
earGradient); |
| 982 result = consumeLinearGradient(args, context.mode(), Repeating, CSSPrefi
xedLinearGradient); |
| 983 } else if (id == CSSValueRepeatingLinearGradient) { |
| 984 result = consumeLinearGradient(args, context.mode(), Repeating, CSSLinea
rGradient); |
| 985 } else if (id == CSSValueLinearGradient) { |
| 986 result = consumeLinearGradient(args, context.mode(), NonRepeating, CSSLi
nearGradient); |
| 987 } else if (id == CSSValueWebkitGradient) { |
| 988 // FIXME: This should send a deprecation message. |
| 989 if (context.useCounter()) |
| 990 context.useCounter()->count(UseCounter::DeprecatedWebKitGradient); |
| 991 result = consumeDeprecatedGradient(args, context.mode()); |
| 992 } else if (id == CSSValueWebkitRadialGradient) { |
| 993 // FIXME: This should send a deprecation message. |
| 994 if (context.useCounter()) |
| 995 context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGradie
nt); |
| 996 result = consumeDeprecatedRadialGradient(args, context.mode(), NonRepeat
ing); |
| 997 } else if (id == CSSValueWebkitRepeatingRadialGradient) { |
| 998 if (context.useCounter()) |
| 999 context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingRad
ialGradient); |
| 1000 result = consumeDeprecatedRadialGradient(args, context.mode(), Repeating
); |
| 1001 } else if (id == CSSValueWebkitCrossFade) { |
| 1002 result = consumeCrossFade(args, context); |
| 1003 } else if (id == CSSValuePaint) { |
| 1004 result = RuntimeEnabledFeatures::cssPaintAPIEnabled() ? consumePaint(arg
s, context) : nullptr; |
| 1005 } |
| 1006 if (!result || !args.atEnd()) |
| 1007 return nullptr; |
| 1008 range = rangeCopy; |
| 1009 return result; |
| 1010 } |
| 1011 |
| 1012 static CSSValue* createCSSImageValueWithReferrer(const AtomicString& rawValue, c
onst CSSParserContext& context) |
| 1013 { |
| 1014 CSSValue* imageValue = CSSImageValue::create(rawValue, context.completeURL(r
awValue)); |
| 1015 toCSSImageValue(imageValue)->setReferrer(context.referrer()); |
| 1016 return imageValue; |
| 1017 } |
| 1018 |
| 1019 static CSSValue* consumeImageSet(CSSParserTokenRange& range, const CSSParserCont
ext& context) |
| 1020 { |
| 1021 CSSParserTokenRange rangeCopy = range; |
| 1022 CSSParserTokenRange args = consumeFunction(rangeCopy); |
| 1023 CSSImageSetValue* imageSet = CSSImageSetValue::create(); |
| 1024 do { |
| 1025 AtomicString urlValue = consumeUrl(args).toAtomicString(); |
| 1026 if (urlValue.isNull()) |
| 1027 return nullptr; |
| 1028 |
| 1029 CSSValue* image = createCSSImageValueWithReferrer(urlValue, context); |
| 1030 imageSet->append(*image); |
| 1031 |
| 1032 const CSSParserToken& token = args.consumeIncludingWhitespace(); |
| 1033 if (token.type() != DimensionToken) |
| 1034 return nullptr; |
| 1035 if (token.value() != "x") |
| 1036 return nullptr; |
| 1037 DCHECK(token.unitType() == CSSPrimitiveValue::UnitType::Unknown); |
| 1038 double imageScaleFactor = token.numericValue(); |
| 1039 if (imageScaleFactor <= 0) |
| 1040 return nullptr; |
| 1041 imageSet->append(*CSSPrimitiveValue::create(imageScaleFactor, CSSPrimiti
veValue::UnitType::Number)); |
| 1042 } while (consumeCommaIncludingWhitespace(args)); |
| 1043 if (!args.atEnd()) |
| 1044 return nullptr; |
| 1045 range = rangeCopy; |
| 1046 return imageSet; |
| 1047 } |
| 1048 |
| 1049 static bool isGeneratedImage(CSSValueID id) |
| 1050 { |
| 1051 return id == CSSValueLinearGradient || id == CSSValueRadialGradient |
| 1052 || id == CSSValueRepeatingLinearGradient || id == CSSValueRepeatingRadia
lGradient |
| 1053 || id == CSSValueWebkitLinearGradient || id == CSSValueWebkitRadialGradi
ent |
| 1054 || id == CSSValueWebkitRepeatingLinearGradient || id == CSSValueWebkitRe
peatingRadialGradient |
| 1055 || id == CSSValueWebkitGradient || id == CSSValueWebkitCrossFade || id =
= CSSValuePaint; |
| 1056 } |
| 1057 |
| 1058 CSSValue* consumeImage(CSSParserTokenRange& range, CSSParserContext context, Con
sumeGeneratedImage generatedImage) |
| 1059 { |
| 1060 AtomicString uri = consumeUrl(range).toAtomicString(); |
| 1061 if (!uri.isNull()) |
| 1062 return createCSSImageValueWithReferrer(uri, context); |
| 1063 if (range.peek().type() == FunctionToken) { |
| 1064 CSSValueID id = range.peek().functionId(); |
| 1065 if (id == CSSValueWebkitImageSet) |
| 1066 return consumeImageSet(range, context); |
| 1067 if (generatedImage == ConsumeGeneratedImage::Allow && isGeneratedImage(i
d)) |
| 1068 return consumeGeneratedImage(range, context); |
| 1069 } |
| 1070 return nullptr; |
| 1071 } |
| 1072 |
616 } // namespace CSSPropertyParserHelpers | 1073 } // namespace CSSPropertyParserHelpers |
617 | 1074 |
618 } // namespace blink | 1075 } // namespace blink |
OLD | NEW |