[CSS Parser] flex-basis should be pixel units not percentages.
[WebKit-https.git] / Source / WebCore / css / parser / CSSPropertyParser.cpp
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Copyright (C) 2016 Apple Inc. All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //    * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //    * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //    * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "config.h"
31 #include "CSSPropertyParser.h"
32
33 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
34 #include "CSSAnimationTriggerScrollValue.h"
35 #endif
36 #include "CSSAspectRatioValue.h"
37 #include "CSSBasicShapes.h"
38 #include "CSSBorderImage.h"
39 #include "CSSBorderImageSliceValue.h"
40 #include "CSSContentDistributionValue.h"
41 #include "CSSCursorImageValue.h"
42 #include "CSSCustomIdentValue.h"
43 #include "CSSFontFaceSrcValue.h"
44 #include "CSSFontFeatureValue.h"
45 #if ENABLE(VARIATION_FONTS)
46 #include "CSSFontVariationValue.h"
47 #endif
48 #include "CSSFunctionValue.h"
49 #include "CSSGridAutoRepeatValue.h"
50 #include "CSSGridLineNamesValue.h"
51 #include "CSSGridTemplateAreasValue.h"
52 #include "CSSInheritedValue.h"
53 #include "CSSInitialValue.h"
54 #include "CSSLineBoxContainValue.h"
55 #include "CSSParserFastPaths.h"
56 #include "CSSParserIdioms.h"
57 #include "CSSPendingSubstitutionValue.h"
58 #include "CSSPrimitiveValueMappings.h"
59 #include "CSSPropertyParserHelpers.h"
60 #include "CSSReflectValue.h"
61 #include "CSSRevertValue.h"
62 #include "CSSShadowValue.h"
63 #include "CSSTimingFunctionValue.h"
64 #include "CSSUnicodeRangeValue.h"
65 #include "CSSUnsetValue.h"
66 #include "CSSVariableParser.h"
67 #include "CSSVariableReferenceValue.h"
68 #include "Counter.h"
69 #include "FontFace.h"
70 #include "HashTools.h"
71 // FIXME-NEWPARSER: Replace Pair and Rect with actual CSSValue subclasses (CSSValuePair and CSSQuadValue).
72 #include "Pair.h"
73 #include "Rect.h"
74 #include "RenderTheme.h"
75 #include "RuntimeEnabledFeatures.h"
76 #include "SVGPathByteStream.h"
77 #include "SVGPathUtilities.h"
78 #include "StylePropertyShorthand.h"
79 #include "StylePropertyShorthandFunctions.h"
80 #include "WebKitCSSTransformValue.h"
81 #include <bitset>
82 #include <memory>
83 #include <wtf/text/StringBuilder.h>
84
85 using namespace WTF;
86
87 namespace WebCore {
88
89 static bool hasPrefix(const char* string, unsigned length, const char* prefix)
90 {
91     for (unsigned i = 0; i < length; ++i) {
92         if (!prefix[i])
93             return true;
94         if (string[i] != prefix[i])
95             return false;
96     }
97     return false;
98 }
99
100 #if PLATFORM(IOS)
101 static void cssPropertyNameIOSAliasing(const char* propertyName, const char*& propertyNameAlias, unsigned& newLength)
102 {
103     if (!strcmp(propertyName, "-webkit-hyphenate-locale")) {
104         // Worked in iOS 4.2.
105         static const char webkitLocale[] = "-webkit-locale";
106         propertyNameAlias = webkitLocale;
107         newLength = strlen(webkitLocale);
108     }
109 }
110 #endif
111
112 template <typename CharacterType>
113 static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
114 {
115     char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
116     
117     for (unsigned i = 0; i != length; ++i) {
118         CharacterType c = propertyName[i];
119         if (!c || c >= 0x7F)
120             return CSSPropertyInvalid; // illegal character
121         buffer[i] = toASCIILower(c);
122     }
123     buffer[length] = '\0';
124     
125     const char* name = buffer;
126     if (buffer[0] == '-') {
127 #if ENABLE(LEGACY_CSS_VENDOR_PREFIXES)
128         // If the prefix is -apple- or -khtml-, change it to -webkit-.
129         // This makes the string one character longer.
130         if (RuntimeEnabledFeatures::sharedFeatures().legacyCSSVendorPrefixesEnabled()
131             && (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-"))) {
132             memmove(buffer + 7, buffer + 6, length + 1 - 6);
133             memcpy(buffer, "-webkit", 7);
134             ++length;
135         }
136 #endif
137 #if PLATFORM(IOS)
138         cssPropertyNameIOSAliasing(buffer, name, length);
139 #endif
140     }
141     
142     const Property* hashTableEntry = findProperty(name, length);
143     return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
144 }
145
146 static bool isAppleLegacyCssValueKeyword(const char* valueKeyword, unsigned length)
147 {
148     static const char applePrefix[] = "-apple-";
149     static const char appleSystemPrefix[] = "-apple-system";
150     static const char* appleWirelessPlaybackTargetActive = getValueName(CSSValueAppleWirelessPlaybackTargetActive);
151     
152     return hasPrefix(valueKeyword, length, applePrefix)
153     && !hasPrefix(valueKeyword, length, appleSystemPrefix)
154     && !WTF::equal(reinterpret_cast<const LChar*>(valueKeyword), reinterpret_cast<const LChar*>(appleWirelessPlaybackTargetActive), length);
155 }
156
157 template <typename CharacterType>
158 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
159 {
160     char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
161     
162     for (unsigned i = 0; i != length; ++i) {
163         CharacterType c = valueKeyword[i];
164         if (!c || c >= 0x7F)
165             return CSSValueInvalid; // illegal keyword.
166         buffer[i] = WTF::toASCIILower(c);
167     }
168     buffer[length] = '\0';
169     
170     if (buffer[0] == '-') {
171         // If the prefix is -apple- or -khtml-, change it to -webkit-.
172         // This makes the string one character longer.
173         // On iOS we don't want to change values starting with -apple-system to -webkit-system.
174         // FIXME: Remove this mangling without breaking the web.
175         if (isAppleLegacyCssValueKeyword(buffer, length) || hasPrefix(buffer, length, "-khtml-")) {
176             memmove(buffer + 7, buffer + 6, length + 1 - 6);
177             memcpy(buffer, "-webkit", 7);
178             ++length;
179         }
180     }
181     
182     const Value* hashTableEntry = findValue(buffer, length);
183     return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
184 }
185
186 CSSValueID cssValueKeywordID(StringView string)
187 {
188     unsigned length = string.length();
189     if (!length)
190         return CSSValueInvalid;
191     if (length > maxCSSValueKeywordLength)
192         return CSSValueInvalid;
193     
194     return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
195 }
196
197 CSSPropertyID cssPropertyID(StringView string)
198 {
199     unsigned length = string.length();
200     
201     if (!length)
202         return CSSPropertyInvalid;
203     if (length > maxCSSPropertyNameLength)
204         return CSSPropertyInvalid;
205     
206     return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
207 }
208     
209 using namespace CSSPropertyParserHelpers;
210
211 CSSPropertyParser::CSSPropertyParser(const CSSParserTokenRange& range,
212     const CSSParserContext& context, Vector<CSSProperty, 256>* parsedProperties)
213     : m_range(range)
214     , m_context(context)
215     , m_parsedProperties(parsedProperties)
216 {
217     m_range.consumeWhitespace();
218 }
219
220 void CSSPropertyParser::addProperty(CSSPropertyID property, CSSPropertyID currentShorthand, Ref<CSSValue>&& value, bool important, bool implicit)
221 {
222     int shorthandIndex = 0;
223     bool setFromShorthand = false;
224
225     if (currentShorthand) {
226         auto shorthands = matchingShorthandsForLonghand(property);
227         setFromShorthand = true;
228         if (shorthands.size() > 1)
229             shorthandIndex = indexOfShorthandForLonghand(currentShorthand, shorthands);
230     }
231
232     m_parsedProperties->append(CSSProperty(property, WTFMove(value), important, setFromShorthand, shorthandIndex, implicit));
233 }
234
235 void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID property, Ref<CSSValue>&& value, bool important)
236 {
237     const StylePropertyShorthand& shorthand = shorthandForProperty(property);
238     unsigned shorthandLength = shorthand.length();
239     ASSERT(shorthandLength);
240     const CSSPropertyID* longhands = shorthand.properties();
241     for (unsigned i = 0; i < shorthandLength; ++i)
242         addProperty(longhands[i], property, value.copyRef(), important);
243 }
244     
245 bool CSSPropertyParser::parseValue(CSSPropertyID propertyID, bool important,
246     const CSSParserTokenRange& range, const CSSParserContext& context,
247     ParsedPropertyVector& parsedProperties, StyleRule::Type ruleType)
248 {
249     int parsedPropertiesSize = parsedProperties.size();
250
251     CSSPropertyParser parser(range, context, &parsedProperties);
252     bool parseSuccess;
253
254 #if ENABLE(CSS_DEVICE_ADAPTATION)
255     if (ruleType == StyleRule::Viewport)
256         parseSuccess = parser.parseViewportDescriptor(propertyID, important);
257     else
258 #endif
259     if (ruleType == StyleRule::FontFace)
260         parseSuccess = parser.parseFontFaceDescriptor(propertyID);
261     else
262         parseSuccess = parser.parseValueStart(propertyID, important);
263
264     if (!parseSuccess)
265         parsedProperties.shrink(parsedPropertiesSize);
266
267     return parseSuccess;
268 }
269
270 RefPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID property, const CSSParserTokenRange& range, const CSSParserContext& context)
271 {
272     CSSPropertyParser parser(range, context, nullptr);
273     RefPtr<CSSValue> value = parser.parseSingleValue(property);
274     if (!value || !parser.m_range.atEnd())
275         return nullptr;
276     return value;
277 }
278
279 static bool isLegacyBreakProperty(CSSPropertyID propertyID)
280 {
281     switch (propertyID) {
282     case CSSPropertyPageBreakAfter:
283     case CSSPropertyPageBreakBefore:
284     case CSSPropertyPageBreakInside:
285     case CSSPropertyWebkitColumnBreakAfter:
286     case CSSPropertyWebkitColumnBreakBefore:
287     case CSSPropertyWebkitColumnBreakInside:
288 #if ENABLE(CSS_REGIONS)
289     case CSSPropertyWebkitRegionBreakAfter:
290     case CSSPropertyWebkitRegionBreakBefore:
291     case CSSPropertyWebkitRegionBreakInside:
292 #endif
293         return true;
294     default:
295         break;
296     }
297     return false;
298 }
299
300 bool CSSPropertyParser::parseValueStart(CSSPropertyID propertyID, bool important)
301 {
302     if (consumeCSSWideKeyword(propertyID, important))
303         return true;
304
305     CSSParserTokenRange originalRange = m_range;
306     bool isShorthand = isShorthandCSSProperty(propertyID);
307
308     if (isShorthand) {
309         // Variable references will fail to parse here and will fall out to the variable ref parser below.
310         if (parseShorthand(propertyID, important))
311             return true;
312     } else if (isLegacyBreakProperty(propertyID)) {
313         // FIXME-NEWPARSER: Can turn this into a shorthand once old parser is gone, and then
314         // we don't need the special case.
315         if (consumeLegacyBreakProperty(propertyID, important))
316             return true;
317     } else {
318         RefPtr<CSSValue> parsedValue = parseSingleValue(propertyID);
319         if (parsedValue && m_range.atEnd()) {
320             addProperty(propertyID, CSSPropertyInvalid, *parsedValue, important);
321             return true;
322         }
323     }
324
325     if (CSSVariableParser::containsValidVariableReferences(originalRange)) {
326         RefPtr<CSSVariableReferenceValue> variable = CSSVariableReferenceValue::create(CSSVariableData::create(originalRange));
327
328         if (isShorthand) {
329             RefPtr<CSSPendingSubstitutionValue> pendingValue = CSSPendingSubstitutionValue::create(propertyID, variable.releaseNonNull());
330             addExpandedPropertyForValue(propertyID, pendingValue.releaseNonNull(), important);
331         } else
332             addProperty(propertyID, CSSPropertyInvalid, variable.releaseNonNull(), important);
333         return true;
334     }
335
336     return false;
337 }
338  
339 bool CSSPropertyParser::consumeCSSWideKeyword(CSSPropertyID propertyID, bool important)
340 {
341     CSSParserTokenRange rangeCopy = m_range;
342     CSSValueID valueID = rangeCopy.consumeIncludingWhitespace().id();
343     if (!rangeCopy.atEnd())
344         return false;
345
346     RefPtr<CSSValue> value;
347     if (valueID == CSSValueInherit)
348         value = CSSValuePool::singleton().createInheritedValue();
349     else if (valueID == CSSValueInitial)
350         value = CSSValuePool::singleton().createExplicitInitialValue();
351     else if (valueID == CSSValueUnset)
352         value = CSSValuePool::singleton().createUnsetValue();
353     else if (valueID == CSSValueRevert)
354         value = CSSValuePool::singleton().createRevertValue();
355     else
356         return false;
357     
358     const StylePropertyShorthand& shorthand = shorthandForProperty(propertyID);
359     if (!shorthand.length()) {
360         if (CSSProperty::isDescriptorOnly(propertyID))
361             return false;
362         addProperty(propertyID, CSSPropertyInvalid, value.releaseNonNull(), important);
363     } else
364         addExpandedPropertyForValue(propertyID, value.releaseNonNull(), important);
365     m_range = rangeCopy;
366     return true;
367 }
368
369 bool CSSPropertyParser::consumeTransformOrigin(bool important)
370 {
371     RefPtr<CSSPrimitiveValue> resultX;
372     RefPtr<CSSPrimitiveValue> resultY;
373     if (consumeOneOrTwoValuedPosition(m_range, m_context.mode, UnitlessQuirk::Forbid, resultX, resultY)) {
374         m_range.consumeWhitespace();
375         bool atEnd = m_range.atEnd();
376         RefPtr<CSSPrimitiveValue> resultZ = consumeLength(m_range, m_context.mode, ValueRangeAll);
377         if (!resultZ && !atEnd)
378             return false;
379         if (!resultZ)
380             resultZ = CSSValuePool::singleton().createValue(0, CSSPrimitiveValue::UnitTypes::CSS_PX);
381         addProperty(CSSPropertyTransformOriginX, CSSPropertyTransformOrigin, resultX.releaseNonNull(), important);
382         addProperty(CSSPropertyTransformOriginY, CSSPropertyTransformOrigin, resultY.releaseNonNull(), important);
383         addProperty(CSSPropertyTransformOriginZ, CSSPropertyTransformOrigin, resultZ.releaseNonNull(), important);
384         
385         return true;
386     }
387     return false;
388 }
389
390 bool CSSPropertyParser::consumePerspectiveOrigin(bool important)
391 {
392     RefPtr<CSSPrimitiveValue> resultX;
393     RefPtr<CSSPrimitiveValue> resultY;
394     if (consumePosition(m_range, m_context.mode, UnitlessQuirk::Forbid, resultX, resultY)) {
395         addProperty(CSSPropertyPerspectiveOriginX, CSSPropertyPerspectiveOrigin, resultX.releaseNonNull(), important);
396         addProperty(CSSPropertyPerspectiveOriginY, CSSPropertyPerspectiveOrigin, resultY.releaseNonNull(), important);
397         return true;
398     }
399     return false;
400 }
401
402 // Methods for consuming non-shorthand properties starts here.
403 static RefPtr<CSSValue> consumeWillChange(CSSParserTokenRange& range)
404 {
405     if (range.peek().id() == CSSValueAuto)
406         return consumeIdent(range);
407
408     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
409     // Every comma-separated list of identifiers is a valid will-change value,
410     // unless the list includes an explicitly disallowed identifier.
411     while (true) {
412         if (range.peek().type() != IdentToken)
413             return nullptr;
414         CSSPropertyID propertyID = cssPropertyID(range.peek().value());
415         if (propertyID != CSSPropertyInvalid) {
416             // Now "all" is used by both CSSValue and CSSPropertyValue.
417             // Need to return nullptr when currentValue is CSSPropertyAll.
418             if (propertyID == CSSPropertyWillChange || propertyID == CSSPropertyAll)
419                 return nullptr;
420             // FIXME-NEWPARSER: Use CSSCustomIdentValue someday.
421             values->append(CSSValuePool::singleton().createIdentifierValue(propertyID));
422             range.consumeIncludingWhitespace();
423         } else {
424             switch (range.peek().id()) {
425             case CSSValueNone:
426             case CSSValueAll:
427             case CSSValueAuto:
428             case CSSValueDefault:
429             case CSSValueInitial:
430             case CSSValueInherit:
431                 return nullptr;
432             case CSSValueContents:
433             case CSSValueScrollPosition:
434                 values->append(consumeIdent(range).releaseNonNull());
435                 break;
436             default:
437                 // Append properties we don't recognize, but that are legal, as strings.
438                 values->append(consumeCustomIdent(range).releaseNonNull());
439                 break;
440             }
441         }
442
443         if (range.atEnd())
444             break;
445         if (!consumeCommaIncludingWhitespace(range))
446             return nullptr;
447     }
448
449     return values;
450 }
451
452 static RefPtr<CSSFontFeatureValue> consumeFontFeatureTag(CSSParserTokenRange& range)
453 {
454     // Feature tag name consists of 4-letter characters.
455     static const unsigned tagNameLength = 4;
456
457     const CSSParserToken& token = range.consumeIncludingWhitespace();
458     // Feature tag name comes first
459     if (token.type() != StringToken)
460         return nullptr;
461     if (token.value().length() != tagNameLength)
462         return nullptr;
463     
464     FontTag tag;
465     for (unsigned i = 0; i < tag.size(); ++i) {
466         // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
467         UChar character = token.value()[i];
468         if (character < 0x20 || character > 0x7E)
469             return nullptr;
470         tag[i] = toASCIILower(character);
471     }
472
473     int tagValue = 1;
474     // Feature tag values could follow: <integer> | on | off
475     if (range.peek().type() == NumberToken && range.peek().numericValueType() == IntegerValueType && range.peek().numericValue() >= 0) {
476         tagValue = clampTo<int>(range.consumeIncludingWhitespace().numericValue());
477         if (tagValue < 0)
478             return nullptr;
479     } else if (range.peek().id() == CSSValueOn || range.peek().id() == CSSValueOff) {
480         tagValue = range.consumeIncludingWhitespace().id() == CSSValueOn;
481     }
482     return CSSFontFeatureValue::create(WTFMove(tag), tagValue);
483 }
484
485 static RefPtr<CSSValue> consumeFontFeatureSettings(CSSParserTokenRange& range)
486 {
487     if (range.peek().id() == CSSValueNormal)
488         return consumeIdent(range);
489     RefPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
490     do {
491         RefPtr<CSSFontFeatureValue> fontFeatureValue = consumeFontFeatureTag(range);
492         if (!fontFeatureValue)
493             return nullptr;
494         settings->append(fontFeatureValue.releaseNonNull());
495     } while (consumeCommaIncludingWhitespace(range));
496     return settings;
497 }
498
499 #if ENABLE(VARIATION_FONTS)
500 static RefPtr<CSSValue> consumeFontVariationTag(CSSParserTokenRange& range)
501 {
502     if (range.peek().type() != StringToken)
503         return nullptr;
504     
505     auto string = range.consumeIncludingWhitespace().value().toString();
506     
507     FontTag tag;
508     if (string.length() != tag.size())
509         return nullptr;
510     for (unsigned i = 0; i < tag.size(); ++i) {
511         // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
512         UChar character = string[i];
513         if (character < 0x20 || character > 0x7E)
514             return nullptr;
515         tag[i] = character;
516     }
517     
518     if (range.atEnd() || range.peek().type() != NumberToken)
519         return nullptr;
520
521     float tagValue = range.consumeIncludingWhitespace().numericValue();
522     
523     return CSSFontVariationValue::create(tag, tagValue);
524 }
525     
526 static RefPtr<CSSValue> consumeFontVariationSettings(CSSParserTokenRange& range)
527 {
528     if (range.peek().id() == CSSValueNormal)
529         return consumeIdent(range);
530     
531     auto settings = CSSValueList::createCommaSeparated();
532     do {
533         RefPtr<CSSValue> variationValue = consumeFontVariationTag(range);
534         if (!variationValue)
535             return nullptr;
536         settings->append(variationValue.releaseNonNull());
537     } while (consumeCommaIncludingWhitespace(range));
538     
539     if (!settings->length())
540         return nullptr;
541
542     return WTFMove(settings);
543 }
544 #endif // ENABLE(VARIATION_FONTS)
545
546 static RefPtr<CSSValue> consumePage(CSSParserTokenRange& range)
547 {
548     if (range.peek().id() == CSSValueAuto)
549         return consumeIdent(range);
550     return consumeCustomIdent(range);
551 }
552
553 static RefPtr<CSSValue> consumeQuotes(CSSParserTokenRange& range)
554 {
555     if (range.peek().id() == CSSValueNone)
556         return consumeIdent(range);
557     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
558     while (!range.atEnd()) {
559         RefPtr<CSSPrimitiveValue> parsedValue = consumeString(range);
560         if (!parsedValue)
561             return nullptr;
562         values->append(parsedValue.releaseNonNull());
563     }
564     if (values->length() && values->length() % 2 == 0)
565         return values;
566     return nullptr;
567 }
568
569 class FontVariantLigaturesParser {
570 public:
571     FontVariantLigaturesParser()
572         : m_sawCommonLigaturesValue(false)
573         , m_sawDiscretionaryLigaturesValue(false)
574         , m_sawHistoricalLigaturesValue(false)
575         , m_sawContextualLigaturesValue(false)
576         , m_result(CSSValueList::createSpaceSeparated())
577     {
578     }
579
580     enum class ParseResult {
581         ConsumedValue,
582         DisallowedValue,
583         UnknownValue
584     };
585
586     ParseResult consumeLigature(CSSParserTokenRange& range)
587     {
588         CSSValueID valueID = range.peek().id();
589         switch (valueID) {
590         case CSSValueNoCommonLigatures:
591         case CSSValueCommonLigatures:
592             if (m_sawCommonLigaturesValue)
593                 return ParseResult::DisallowedValue;
594             m_sawCommonLigaturesValue = true;
595             break;
596         case CSSValueNoDiscretionaryLigatures:
597         case CSSValueDiscretionaryLigatures:
598             if (m_sawDiscretionaryLigaturesValue)
599                 return ParseResult::DisallowedValue;
600             m_sawDiscretionaryLigaturesValue = true;
601             break;
602         case CSSValueNoHistoricalLigatures:
603         case CSSValueHistoricalLigatures:
604             if (m_sawHistoricalLigaturesValue)
605                 return ParseResult::DisallowedValue;
606             m_sawHistoricalLigaturesValue = true;
607             break;
608         case CSSValueNoContextual:
609         case CSSValueContextual:
610             if (m_sawContextualLigaturesValue)
611                 return ParseResult::DisallowedValue;
612             m_sawContextualLigaturesValue = true;
613             break;
614         default:
615             return ParseResult::UnknownValue;
616         }
617         m_result->append(consumeIdent(range).releaseNonNull());
618         return ParseResult::ConsumedValue;
619     }
620
621     RefPtr<CSSValue> finalizeValue()
622     {
623         if (!m_result->length())
624             return CSSValuePool::singleton().createIdentifierValue(CSSValueNormal);
625         return m_result.release();
626     }
627
628 private:
629     bool m_sawCommonLigaturesValue;
630     bool m_sawDiscretionaryLigaturesValue;
631     bool m_sawHistoricalLigaturesValue;
632     bool m_sawContextualLigaturesValue;
633     RefPtr<CSSValueList> m_result;
634 };
635
636 static RefPtr<CSSValue> consumeFontVariantLigatures(CSSParserTokenRange& range)
637 {
638     if (range.peek().id() == CSSValueNormal || range.peek().id() == CSSValueNone)
639         return consumeIdent(range);
640
641     FontVariantLigaturesParser ligaturesParser;
642     do {
643         if (ligaturesParser.consumeLigature(range) !=
644             FontVariantLigaturesParser::ParseResult::ConsumedValue)
645             return nullptr;
646     } while (!range.atEnd());
647
648     return ligaturesParser.finalizeValue();
649 }
650
651 static RefPtr<CSSPrimitiveValue> consumeFontVariantCaps(CSSParserTokenRange& range)
652 {
653     return consumeIdent<CSSValueNormal, CSSValueSmallCaps, CSSValueAllSmallCaps,
654         CSSValuePetiteCaps, CSSValueAllPetiteCaps,
655         CSSValueUnicase, CSSValueTitlingCaps>(range);
656 }
657
658 class FontVariantNumericParser {
659 public:
660     FontVariantNumericParser()
661         : m_sawNumericFigureValue(false)
662         , m_sawNumericSpacingValue(false)
663         , m_sawNumericFractionValue(false)
664         , m_sawOrdinalValue(false)
665         , m_sawSlashedZeroValue(false)
666         , m_result(CSSValueList::createSpaceSeparated())
667     {
668     }
669
670     enum class ParseResult {
671         ConsumedValue,
672         DisallowedValue,
673         UnknownValue
674     };
675
676     ParseResult consumeNumeric(CSSParserTokenRange& range)
677     {
678         CSSValueID valueID = range.peek().id();
679         switch (valueID) {
680         case CSSValueLiningNums:
681         case CSSValueOldstyleNums:
682             if (m_sawNumericFigureValue)
683                 return ParseResult::DisallowedValue;
684             m_sawNumericFigureValue = true;
685             break;
686         case CSSValueProportionalNums:
687         case CSSValueTabularNums:
688             if (m_sawNumericSpacingValue)
689                 return ParseResult::DisallowedValue;
690             m_sawNumericSpacingValue = true;
691             break;
692         case CSSValueDiagonalFractions:
693         case CSSValueStackedFractions:
694             if (m_sawNumericFractionValue)
695                 return ParseResult::DisallowedValue;
696             m_sawNumericFractionValue = true;
697             break;
698         case CSSValueOrdinal:
699             if (m_sawOrdinalValue)
700                 return ParseResult::DisallowedValue;
701             m_sawOrdinalValue = true;
702             break;
703         case CSSValueSlashedZero:
704             if (m_sawSlashedZeroValue)
705                 return ParseResult::DisallowedValue;
706             m_sawSlashedZeroValue = true;
707             break;
708         default:
709             return ParseResult::UnknownValue;
710         }
711         m_result->append(consumeIdent(range).releaseNonNull());
712         return ParseResult::ConsumedValue;
713     }
714
715     RefPtr<CSSValue> finalizeValue()
716     {
717         if (!m_result->length())
718             return CSSValuePool::singleton().createIdentifierValue(CSSValueNormal);
719         return m_result.release();
720     }
721
722
723 private:
724     bool m_sawNumericFigureValue;
725     bool m_sawNumericSpacingValue;
726     bool m_sawNumericFractionValue;
727     bool m_sawOrdinalValue;
728     bool m_sawSlashedZeroValue;
729     RefPtr<CSSValueList> m_result;
730 };
731
732 static RefPtr<CSSValue> consumeFontVariantNumeric(CSSParserTokenRange& range)
733 {
734     if (range.peek().id() == CSSValueNormal)
735         return consumeIdent(range);
736
737     FontVariantNumericParser numericParser;
738     do {
739         if (numericParser.consumeNumeric(range) !=
740             FontVariantNumericParser::ParseResult::ConsumedValue)
741             return nullptr;
742     } while (!range.atEnd());
743
744     return numericParser.finalizeValue();
745 }
746
747 static RefPtr<CSSPrimitiveValue> consumeFontVariantCSS21(CSSParserTokenRange& range)
748 {
749     return consumeIdent<CSSValueNormal, CSSValueSmallCaps>(range);
750 }
751
752 static RefPtr<CSSValue> consumeFontVariantList(CSSParserTokenRange& range)
753 {
754     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
755     do {
756         if (range.peek().id() == CSSValueAll) {
757             // FIXME: CSSPropertyParser::parseFontVariant() implements
758             // the old css3 draft:
759             // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#font-variant
760             // 'all' is only allowed in @font-face and with no other values.
761             if (values->length())
762                 return nullptr;
763             return consumeIdent(range);
764         }
765         RefPtr<CSSPrimitiveValue> fontVariant = consumeFontVariantCSS21(range);
766         if (fontVariant)
767             values->append(fontVariant.releaseNonNull());
768     } while (consumeCommaIncludingWhitespace(range));
769
770     if (values->length())
771         return values;
772
773     return nullptr;
774 }
775
776 static RefPtr<CSSPrimitiveValue> consumeFontWeight(CSSParserTokenRange& range)
777 {
778     const CSSParserToken& token = range.peek();
779     if (token.id() >= CSSValueNormal && token.id() <= CSSValueLighter)
780         return consumeIdent(range);
781     if (token.type() != NumberToken || token.numericValueType() != IntegerValueType)
782         return nullptr;
783     int weight = static_cast<int>(token.numericValue());
784     if ((weight % 100) || weight < 100 || weight > 900)
785         return nullptr;
786     range.consumeIncludingWhitespace();
787     return CSSValuePool::singleton().createIdentifierValue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1));
788 }
789
790 static String concatenateFamilyName(CSSParserTokenRange& range)
791 {
792     StringBuilder builder;
793     bool addedSpace = false;
794     const CSSParserToken& firstToken = range.peek();
795     while (range.peek().type() == IdentToken) {
796         if (!builder.isEmpty()) {
797             builder.append(' ');
798             addedSpace = true;
799         }
800         builder.append(range.consumeIncludingWhitespace().value());
801     }
802     if (!addedSpace && isCSSWideKeyword(firstToken.id()))
803         return String();
804     return builder.toString();
805 }
806
807 static RefPtr<CSSValue> consumeFamilyName(CSSParserTokenRange& range)
808 {
809     if (range.peek().type() == StringToken)
810         return CSSValuePool::singleton().createFontFamilyValue(range.consumeIncludingWhitespace().value().toString());
811     if (range.peek().type() != IdentToken)
812         return nullptr;
813     String familyName = concatenateFamilyName(range);
814     if (familyName.isNull())
815         return nullptr;
816     return CSSValuePool::singleton().createFontFamilyValue(familyName);
817 }
818
819 static RefPtr<CSSValue> consumeGenericFamily(CSSParserTokenRange& range)
820 {
821     return consumeIdentRange(range, CSSValueSerif, CSSValueWebkitBody);
822 }
823
824 static RefPtr<CSSValueList> consumeFontFamily(CSSParserTokenRange& range)
825 {
826     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
827     do {
828         RefPtr<CSSValue> parsedValue = consumeGenericFamily(range);
829         if (parsedValue) {
830             list->append(parsedValue.releaseNonNull());
831         } else {
832             parsedValue = consumeFamilyName(range);
833             if (parsedValue) {
834                 list->append(parsedValue.releaseNonNull());
835             } else {
836                 return nullptr;
837             }
838         }
839     } while (consumeCommaIncludingWhitespace(range));
840     return list;
841 }
842
843 static RefPtr<CSSValue> consumeFontSynthesis(CSSParserTokenRange& range)
844 {
845     // none | [ weight || style ]
846     CSSValueID id = range.peek().id();
847     if (id == CSSValueNone)
848         return consumeIdent(range);
849     
850     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
851     while (true) {
852         auto ident = consumeIdent<CSSValueWeight, CSSValueStyle>(range);
853         if (!ident)
854             break;
855         if (list->hasValue(ident.get()))
856             return nullptr;
857         list->append(ident.releaseNonNull());
858     }
859     
860     if (!list->length())
861         return nullptr;
862     return list;
863 }
864
865 static RefPtr<CSSValue> consumeLetterSpacing(CSSParserTokenRange& range, CSSParserMode cssParserMode)
866 {
867     if (range.peek().id() == CSSValueNormal)
868         return consumeIdent(range);
869     
870     return consumeLength(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
871 }
872
873 static RefPtr<CSSValue> consumeWordSpacing(CSSParserTokenRange& range, CSSParserMode cssParserMode)
874 {
875     if (range.peek().id() == CSSValueNormal)
876         return consumeIdent(range);
877     
878     return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
879 }
880     
881 static RefPtr<CSSValue> consumeTabSize(CSSParserTokenRange& range, CSSParserMode cssParserMode)
882 {
883     RefPtr<CSSPrimitiveValue> parsedValue = consumeInteger(range, 0);
884     if (parsedValue)
885         return parsedValue;
886     return consumeLength(range, cssParserMode, ValueRangeNonNegative);
887 }
888
889 #if ENABLE(TEXT_AUTOSIZING)
890 static RefPtr<CSSValue> consumeTextSizeAdjust(CSSParserTokenRange& range, CSSParserMode /* cssParserMode */)
891 {
892     if (range.peek().id() == CSSValueAuto)
893         return consumeIdent(range);
894     if (range.peek().id() == CSSValueNone)
895         return consumeIdent(range);
896     return consumePercent(range, ValueRangeNonNegative);
897 }
898 #endif
899
900 static RefPtr<CSSValue> consumeFontSize(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless = UnitlessQuirk::Forbid)
901 {
902     if (range.peek().id() >= CSSValueXxSmall && range.peek().id() <= CSSValueLarger)
903         return consumeIdent(range);
904     return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative, unitless);
905 }
906
907 static RefPtr<CSSPrimitiveValue> consumeLineHeight(CSSParserTokenRange& range, CSSParserMode cssParserMode)
908 {
909     if (range.peek().id() == CSSValueNormal)
910         return consumeIdent(range);
911
912     RefPtr<CSSPrimitiveValue> lineHeight = consumeNumber(range, ValueRangeNonNegative);
913     if (lineHeight)
914         return lineHeight;
915     return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
916 }
917
918 template<typename... Args>
919 static Ref<CSSPrimitiveValue> createPrimitiveValuePair(Args&&... args)
920 {
921     return CSSValuePool::singleton().createValue(Pair::create(std::forward<Args>(args)...));
922 }
923
924 static RefPtr<CSSValue> consumeCounter(CSSParserTokenRange& range, int defaultValue)
925 {
926     if (range.peek().id() == CSSValueNone)
927         return consumeIdent(range);
928
929     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
930     do {
931         RefPtr<CSSPrimitiveValue> counterName = consumeCustomIdent(range);
932         if (!counterName)
933             return nullptr;
934         int i = defaultValue;
935         if (RefPtr<CSSPrimitiveValue> counterValue = consumeInteger(range))
936             i = counterValue->intValue();
937         list->append(createPrimitiveValuePair(counterName.releaseNonNull(), CSSPrimitiveValue::create(i, CSSPrimitiveValue::UnitTypes::CSS_NUMBER), Pair::IdenticalValueEncoding::Coalesce));
938     } while (!range.atEnd());
939     return list;
940 }
941
942 static RefPtr<CSSValue> consumePageSize(CSSParserTokenRange& range)
943 {
944     return consumeIdent<CSSValueA3, CSSValueA4, CSSValueA5, CSSValueB4, CSSValueB5, CSSValueLedger, CSSValueLegal, CSSValueLetter>(range);
945 }
946
947 static RefPtr<CSSValueList> consumeSize(CSSParserTokenRange& range, CSSParserMode cssParserMode)
948 {
949     RefPtr<CSSValueList> result = CSSValueList::createSpaceSeparated();
950
951     if (range.peek().id() == CSSValueAuto) {
952         result->append(consumeIdent(range).releaseNonNull());
953         return result;
954     }
955
956     if (RefPtr<CSSValue> width = consumeLength(range, cssParserMode, ValueRangeNonNegative)) {
957         RefPtr<CSSValue> height = consumeLength(range, cssParserMode, ValueRangeNonNegative);
958         result->append(width.releaseNonNull());
959         if (height)
960             result->append(height.releaseNonNull());
961         return result;
962     }
963
964     RefPtr<CSSValue> pageSize = consumePageSize(range);
965     RefPtr<CSSValue> orientation = consumeIdent<CSSValuePortrait, CSSValueLandscape>(range);
966     if (!pageSize)
967         pageSize = consumePageSize(range);
968
969     if (!orientation && !pageSize)
970         return nullptr;
971     if (pageSize)
972         result->append(pageSize.releaseNonNull());
973     if (orientation)
974         result->append(orientation.releaseNonNull());
975     return result;
976 }
977
978 static RefPtr<CSSValue> consumeTextIndent(CSSParserTokenRange& range, CSSParserMode cssParserMode)
979 {
980     // [ <length> | <percentage> ] && hanging? && each-line?
981     // Keywords only allowed when css3Text is enabled.
982     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
983
984     bool hasLengthOrPercentage = false;
985 //    bool hasEachLine = false;
986     bool hasHanging = false;
987
988     do {
989         if (!hasLengthOrPercentage) {
990             if (RefPtr<CSSValue> textIndent = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow)) {
991                 list->append(*textIndent);
992                 hasLengthOrPercentage = true;
993                 continue;
994             }
995         }
996
997         CSSValueID id = range.peek().id();
998  /* FIXME-NEWPARSER: We don't support this yet.
999         if (!hasEachLine && id == CSSValueEachLine) {
1000             list->append(*consumeIdent(range));
1001             hasEachLine = true;
1002             continue;
1003         }
1004 */
1005         
1006         if (!hasHanging && id == CSSValueHanging) {
1007             list->append(consumeIdent(range).releaseNonNull());
1008             hasHanging = true;
1009             continue;
1010         }
1011         
1012         return nullptr;
1013     } while (!range.atEnd());
1014
1015     if (!hasLengthOrPercentage)
1016         return nullptr;
1017
1018     return list;
1019 }
1020
1021 // FIXME-NEWPARSER: Drop the prefix on min-content, max-content and fit-content.
1022 static bool validWidthOrHeightKeyword(CSSValueID id, const CSSParserContext& /*context*/)
1023 {
1024     if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent) {
1025         return true;
1026     }
1027     return false;
1028 }
1029
1030 static RefPtr<CSSValue> consumeMaxWidthOrHeight(CSSParserTokenRange& range, const CSSParserContext& context, UnitlessQuirk unitless = UnitlessQuirk::Forbid)
1031 {
1032     if (range.peek().id() == CSSValueNone || validWidthOrHeightKeyword(range.peek().id(), context))
1033         return consumeIdent(range);
1034     return consumeLengthOrPercent(range, context.mode, ValueRangeNonNegative, unitless);
1035 }
1036
1037 static RefPtr<CSSValue> consumeWidthOrHeight(CSSParserTokenRange& range, const CSSParserContext& context, UnitlessQuirk unitless = UnitlessQuirk::Forbid)
1038 {
1039     if (range.peek().id() == CSSValueAuto || validWidthOrHeightKeyword(range.peek().id(), context))
1040         return consumeIdent(range);
1041     return consumeLengthOrPercent(range, context.mode, ValueRangeNonNegative, unitless);
1042 }
1043
1044 static RefPtr<CSSValue> consumeMarginOrOffset(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
1045 {
1046     if (range.peek().id() == CSSValueAuto)
1047         return consumeIdent(range);
1048     return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, unitless);
1049 }
1050
1051 static RefPtr<CSSPrimitiveValue> consumeClipComponent(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1052 {
1053     if (range.peek().id() == CSSValueAuto)
1054         return consumeIdent(range);
1055     return consumeLength(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
1056 }
1057
1058 static RefPtr<CSSValue> consumeClip(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1059 {
1060     if (range.peek().id() == CSSValueAuto)
1061         return consumeIdent(range);
1062
1063     if (range.peek().functionId() != CSSValueRect)
1064         return nullptr;
1065
1066     CSSParserTokenRange args = consumeFunction(range);
1067     // rect(t, r, b, l) || rect(t r b l)
1068     RefPtr<CSSPrimitiveValue> top = consumeClipComponent(args, cssParserMode);
1069     if (!top)
1070         return nullptr;
1071     bool needsComma = consumeCommaIncludingWhitespace(args);
1072     RefPtr<CSSPrimitiveValue> right = consumeClipComponent(args, cssParserMode);
1073     if (!right || (needsComma && !consumeCommaIncludingWhitespace(args)))
1074         return nullptr;
1075     RefPtr<CSSPrimitiveValue> bottom = consumeClipComponent(args, cssParserMode);
1076     if (!bottom || (needsComma && !consumeCommaIncludingWhitespace(args)))
1077         return nullptr;
1078     RefPtr<CSSPrimitiveValue> left = consumeClipComponent(args, cssParserMode);
1079     if (!left || !args.atEnd())
1080         return nullptr;
1081     
1082     auto rect = Rect::create();
1083     rect->setLeft(left.releaseNonNull());
1084     rect->setTop(top.releaseNonNull());
1085     rect->setRight(right.releaseNonNull());
1086     rect->setBottom(bottom.releaseNonNull());
1087     return CSSValuePool::singleton().createValue(WTFMove(rect));
1088 }
1089
1090 #if ENABLE(TOUCH_EVENTS)
1091 static RefPtr<CSSValue> consumeTouchAction(CSSParserTokenRange& range)
1092 {
1093     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1094     CSSValueID id = range.peek().id();
1095     if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueManipulation) {
1096         list->append(consumeIdent(range).releaseNonNull());
1097         return list;
1098     }
1099     // FIXME-NEWPARSER: Support pan.
1100     return nullptr;
1101 }
1102 #endif
1103
1104 static RefPtr<CSSPrimitiveValue> consumeLineClamp(CSSParserTokenRange& range)
1105 {
1106     if (range.peek().type() != PercentageToken && range.peek().type() != NumberToken)
1107         return nullptr;
1108     RefPtr<CSSPrimitiveValue> clampValue = consumePercent(range, ValueRangeNonNegative);
1109     if (clampValue)
1110         return clampValue;
1111     // When specifying number of lines, don't allow 0 as a valid value.
1112     return consumePositiveInteger(range);
1113 }
1114
1115 static RefPtr<CSSValue> consumeLocale(CSSParserTokenRange& range)
1116 {
1117     if (range.peek().id() == CSSValueAuto)
1118         return consumeIdent(range);
1119     return consumeString(range);
1120 }
1121
1122 static RefPtr<CSSValue> consumeHyphenateLimit(CSSParserTokenRange& range, CSSValueID valueID)
1123 {
1124     if (range.peek().id() == valueID)
1125         return consumeIdent(range);
1126     return consumeNumber(range, ValueRangeNonNegative);
1127 }
1128
1129 static RefPtr<CSSValue> consumeColumnWidth(CSSParserTokenRange& range)
1130 {
1131     if (range.peek().id() == CSSValueAuto)
1132         return consumeIdent(range);
1133     // Always parse lengths in strict mode here, since it would be ambiguous otherwise when used in
1134     // the 'columns' shorthand property.
1135     RefPtr<CSSPrimitiveValue> columnWidth = consumeLength(range, HTMLStandardMode, ValueRangeNonNegative);
1136     if (!columnWidth || (!columnWidth->isCalculated() && columnWidth->doubleValue() == 0))
1137         return nullptr;
1138     return columnWidth;
1139 }
1140
1141 static RefPtr<CSSValue> consumeColumnCount(CSSParserTokenRange& range)
1142 {
1143     if (range.peek().id() == CSSValueAuto)
1144         return consumeIdent(range);
1145     return consumePositiveInteger(range);
1146 }
1147
1148 static RefPtr<CSSValue> consumeColumnGap(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1149 {
1150     if (range.peek().id() == CSSValueNormal)
1151         return consumeIdent(range);
1152     return consumeLength(range, cssParserMode, ValueRangeNonNegative);
1153 }
1154
1155 static RefPtr<CSSValue> consumeColumnSpan(CSSParserTokenRange& range)
1156 {
1157     return consumeIdent<CSSValueAll, CSSValueNone>(range);
1158 }
1159
1160 static RefPtr<CSSValue> consumeZoom(CSSParserTokenRange& range, const CSSParserContext& /*context*/)
1161 {
1162     const CSSParserToken& token = range.peek();
1163     RefPtr<CSSPrimitiveValue> zoom;
1164     if (token.type() == IdentToken)
1165         zoom = consumeIdent<CSSValueNormal, CSSValueReset, CSSValueDocument>(range);
1166     else {
1167         zoom = consumePercent(range, ValueRangeNonNegative);
1168         if (!zoom)
1169             zoom = consumeNumber(range, ValueRangeNonNegative);
1170     }
1171     return zoom;
1172 }
1173
1174 static RefPtr<CSSValue> consumeAnimationIterationCount(CSSParserTokenRange& range)
1175 {
1176     if (range.peek().id() == CSSValueInfinite)
1177         return consumeIdent(range);
1178     return consumeNumber(range, ValueRangeNonNegative);
1179 }
1180
1181 static RefPtr<CSSValue> consumeAnimationName(CSSParserTokenRange& range)
1182 {
1183     if (range.peek().id() == CSSValueNone)
1184         return consumeIdent(range);
1185
1186     if (range.peek().type() == StringToken) {
1187         const CSSParserToken& token = range.consumeIncludingWhitespace();
1188         if (equalIgnoringASCIICase(token.value(), "none"))
1189             return CSSValuePool::singleton().createIdentifierValue(CSSValueNone);
1190         // FIXME-NEWPARSER: Want to use a CSSCustomIdentValue here eventually.
1191         return CSSValuePool::singleton().createValue(token.value().toString(), CSSPrimitiveValue::UnitTypes::CSS_STRING);
1192     }
1193
1194     return consumeCustomIdent(range);
1195 }
1196
1197 static RefPtr<CSSValue> consumeTransitionProperty(CSSParserTokenRange& range)
1198 {
1199     const CSSParserToken& token = range.peek();
1200     if (token.type() != IdentToken)
1201         return nullptr;
1202     if (token.id() == CSSValueNone)
1203         return consumeIdent(range);
1204
1205     if (CSSPropertyID property = token.parseAsCSSPropertyID()) {
1206         range.consumeIncludingWhitespace();
1207         
1208         // FIXME-NEWPARSER: Want to use a CSSCustomIdentValue here eventually.
1209         return CSSValuePool::singleton().createIdentifierValue(property);
1210     }
1211     return consumeCustomIdent(range);
1212 }
1213
1214     
1215 static RefPtr<CSSValue> consumeSteps(CSSParserTokenRange& range) {
1216     ASSERT(range.peek().functionId() == CSSValueSteps);
1217     CSSParserTokenRange rangeCopy = range;
1218     CSSParserTokenRange args = consumeFunction(rangeCopy);
1219     
1220     RefPtr<CSSPrimitiveValue> steps = consumePositiveInteger(args);
1221     if (!steps)
1222         return nullptr;
1223     
1224     // FIXME-NEWPARSER: Support the middle value and change from a boolean to an enum.
1225     bool stepAtStart = false;
1226     if (consumeCommaIncludingWhitespace(args)) {
1227         switch (args.consumeIncludingWhitespace().id()) {
1228             case CSSValueStart:
1229                 stepAtStart = true;
1230             break;
1231             case CSSValueEnd:
1232                 stepAtStart = false;
1233                 break;
1234             default:
1235                 return nullptr;
1236         }
1237     }
1238     
1239     if (!args.atEnd())
1240         return nullptr;
1241     
1242     range = rangeCopy;
1243     return CSSStepsTimingFunctionValue::create(steps->intValue(), stepAtStart);
1244 }
1245
1246 static RefPtr<CSSValue> consumeCubicBezier(CSSParserTokenRange& range)
1247 {
1248     ASSERT(range.peek().functionId() == CSSValueCubicBezier);
1249     CSSParserTokenRange rangeCopy = range;
1250     CSSParserTokenRange args = consumeFunction(rangeCopy);
1251
1252     double x1, y1, x2, y2;
1253     if (consumeNumberRaw(args, x1)
1254         && x1 >= 0 && x1 <= 1
1255         && consumeCommaIncludingWhitespace(args)
1256         && consumeNumberRaw(args, y1)
1257         && consumeCommaIncludingWhitespace(args)
1258         && consumeNumberRaw(args, x2)
1259         && x2 >= 0 && x2 <= 1
1260         && consumeCommaIncludingWhitespace(args)
1261         && consumeNumberRaw(args, y2)
1262         && args.atEnd()) {
1263         range = rangeCopy;
1264         return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
1265     }
1266
1267     return nullptr;
1268 }
1269
1270 static RefPtr<CSSValue> consumeSpringFunction(CSSParserTokenRange& range)
1271 {
1272     ASSERT(range.peek().functionId() == CSSValueSpring);
1273     CSSParserTokenRange rangeCopy = range;
1274     CSSParserTokenRange args = consumeFunction(rangeCopy);
1275
1276     // Mass must be greater than 0.
1277     double mass;
1278     if (!consumeNumberRaw(args, mass) || mass <= 0)
1279         return nullptr;
1280     
1281     // Stiffness must be greater than 0.
1282     double stiffness;
1283     if (!consumeNumberRaw(args, stiffness) || stiffness <= 0)
1284         return nullptr;
1285     
1286     // Damping coefficient must be greater than or equal to 0.
1287     double damping;
1288     if (!consumeNumberRaw(args, damping) || damping < 0)
1289         return nullptr;
1290     
1291     // Initial velocity may have any value.
1292     double initialVelocity;
1293     if (!consumeNumberRaw(args, initialVelocity))
1294         return nullptr;
1295
1296     if (!args.atEnd())
1297         return nullptr;
1298
1299     range = rangeCopy;
1300
1301     return CSSSpringTimingFunctionValue::create(mass, stiffness, damping, initialVelocity);
1302 }
1303
1304 static RefPtr<CSSValue> consumeAnimationTimingFunction(CSSParserTokenRange& range, const CSSParserContext& context)
1305 {
1306     CSSValueID id = range.peek().id();
1307     if (id == CSSValueEase || id == CSSValueLinear || id == CSSValueEaseIn
1308         || id == CSSValueEaseOut || id == CSSValueEaseInOut || id == CSSValueStepStart || id == CSSValueStepEnd)
1309         return consumeIdent(range);
1310
1311     CSSValueID function = range.peek().functionId();
1312     if (function == CSSValueCubicBezier)
1313         return consumeCubicBezier(range);
1314     if (function == CSSValueSteps)
1315         return consumeSteps(range);
1316     if (context.springTimingFunctionEnabled && function == CSSValueSpring)
1317         return consumeSpringFunction(range);
1318     return nullptr;
1319 }
1320
1321 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
1322 static RefPtr<CSSValue> consumeWebkitAnimationTrigger(CSSParserTokenRange& range, CSSParserMode mode)
1323 {
1324     if (range.peek().id() == CSSValueAuto)
1325         return consumeIdent(range);
1326     
1327     if (range.peek().functionId() != CSSValueContainerScroll)
1328         return nullptr;
1329     
1330     CSSParserTokenRange rangeCopy = range;
1331     CSSParserTokenRange args = consumeFunction(rangeCopy);
1332
1333     RefPtr<CSSPrimitiveValue> startValue = consumeLength(args, mode, ValueRangeAll, UnitlessQuirk::Forbid);
1334     if (!startValue)
1335         return nullptr;
1336     
1337     if (args.atEnd()) {
1338         range = rangeCopy;
1339         return CSSAnimationTriggerScrollValue::create(startValue.releaseNonNull());
1340     }
1341
1342     if (!consumeCommaIncludingWhitespace(args))
1343         return nullptr;
1344
1345     RefPtr<CSSPrimitiveValue> endValue = consumeLength(args, mode, ValueRangeAll, UnitlessQuirk::Forbid);
1346     if (!endValue || !args.atEnd())
1347         return nullptr;
1348
1349     range = rangeCopy;
1350
1351     return CSSAnimationTriggerScrollValue::create(startValue.releaseNonNull(), endValue.releaseNonNull());
1352 }
1353 #endif
1354     
1355 static RefPtr<CSSValue> consumeAnimationValue(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
1356 {
1357     switch (property) {
1358     case CSSPropertyAnimationDelay:
1359     case CSSPropertyTransitionDelay:
1360         return consumeTime(range, context.mode, ValueRangeAll, UnitlessQuirk::Forbid);
1361     case CSSPropertyAnimationDirection:
1362         return consumeIdent<CSSValueNormal, CSSValueAlternate, CSSValueReverse, CSSValueAlternateReverse>(range);
1363     case CSSPropertyAnimationDuration:
1364     case CSSPropertyTransitionDuration:
1365         return consumeTime(range, context.mode, ValueRangeNonNegative, UnitlessQuirk::Forbid);
1366     case CSSPropertyAnimationFillMode:
1367         return consumeIdent<CSSValueNone, CSSValueForwards, CSSValueBackwards, CSSValueBoth>(range);
1368     case CSSPropertyAnimationIterationCount:
1369         return consumeAnimationIterationCount(range);
1370     case CSSPropertyAnimationName:
1371         return consumeAnimationName(range);
1372     case CSSPropertyAnimationPlayState:
1373         return consumeIdent<CSSValueRunning, CSSValuePaused>(range);
1374     case CSSPropertyTransitionProperty:
1375         return consumeTransitionProperty(range);
1376     case CSSPropertyAnimationTimingFunction:
1377     case CSSPropertyTransitionTimingFunction:
1378         return consumeAnimationTimingFunction(range, context);
1379 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
1380     case CSSPropertyWebkitAnimationTrigger:
1381         return consumeWebkitAnimationTrigger(range, context.mode);
1382 #endif
1383     default:
1384         ASSERT_NOT_REACHED();
1385         return nullptr;
1386     }
1387 }
1388
1389 static bool isValidAnimationPropertyList(CSSPropertyID property, const CSSValueList& valueList)
1390 {
1391     if (property != CSSPropertyTransitionProperty || valueList.length() < 2)
1392         return true;
1393     for (auto& value : valueList) {
1394         if (value->isPrimitiveValue() && downcast<CSSPrimitiveValue>(value.get()).isValueID()
1395             && downcast<CSSPrimitiveValue>(value.get()).valueID() == CSSValueNone)
1396             return false;
1397     }
1398     return true;
1399 }
1400
1401 static RefPtr<CSSValueList> consumeAnimationPropertyList(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
1402 {
1403     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
1404     do {
1405         RefPtr<CSSValue> value = consumeAnimationValue(property, range, context);
1406         if (!value)
1407             return nullptr;
1408         list->append(value.releaseNonNull());
1409     } while (consumeCommaIncludingWhitespace(range));
1410     if (!isValidAnimationPropertyList(property, *list))
1411         return nullptr;
1412     ASSERT(list->length());
1413     return list;
1414 }
1415
1416 bool CSSPropertyParser::consumeAnimationShorthand(const StylePropertyShorthand& shorthand, bool important)
1417 {
1418     const unsigned longhandCount = shorthand.length();
1419     RefPtr<CSSValueList> longhands[8];
1420     ASSERT(longhandCount <= 8);
1421     for (size_t i = 0; i < longhandCount; ++i)
1422         longhands[i] = CSSValueList::createCommaSeparated();
1423
1424     do {
1425         bool parsedLonghand[8] = { false };
1426         do {
1427             bool foundProperty = false;
1428             for (size_t i = 0; i < longhandCount; ++i) {
1429                 if (parsedLonghand[i])
1430                     continue;
1431
1432                 if (RefPtr<CSSValue> value = consumeAnimationValue(shorthand.properties()[i], m_range, m_context)) {
1433                     parsedLonghand[i] = true;
1434                     foundProperty = true;
1435                     longhands[i]->append(*value);
1436                     break;
1437                 }
1438             }
1439             if (!foundProperty)
1440                 return false;
1441         } while (!m_range.atEnd() && m_range.peek().type() != CommaToken);
1442
1443         // FIXME: This will make invalid longhands, see crbug.com/386459
1444         for (size_t i = 0; i < longhandCount; ++i) {
1445             if (!parsedLonghand[i])
1446                 longhands[i]->append(CSSValuePool::singleton().createImplicitInitialValue());
1447             parsedLonghand[i] = false;
1448         }
1449     } while (consumeCommaIncludingWhitespace(m_range));
1450
1451     for (size_t i = 0; i < longhandCount; ++i) {
1452         if (!isValidAnimationPropertyList(shorthand.properties()[i], *longhands[i]))
1453             return false;
1454     }
1455
1456     for (size_t i = 0; i < longhandCount; ++i)
1457         addProperty(shorthand.properties()[i], shorthand.id(), *longhands[i], important);
1458
1459     return m_range.atEnd();
1460 }
1461
1462 static RefPtr<CSSValue> consumeZIndex(CSSParserTokenRange& range)
1463 {
1464     if (range.peek().id() == CSSValueAuto)
1465         return consumeIdent(range);
1466     return consumeInteger(range);
1467 }
1468
1469 static RefPtr<CSSValue> consumeShadow(CSSParserTokenRange& range, CSSParserMode cssParserMode, bool isBoxShadowProperty)
1470 {
1471     if (range.peek().id() == CSSValueNone)
1472         return consumeIdent(range);
1473
1474     RefPtr<CSSValueList> shadowValueList = CSSValueList::createCommaSeparated();
1475     do {
1476         if (RefPtr<CSSShadowValue> shadowValue = consumeSingleShadow(range, cssParserMode, isBoxShadowProperty, isBoxShadowProperty))
1477             shadowValueList->append(*shadowValue);
1478         else
1479             return nullptr;
1480     } while (consumeCommaIncludingWhitespace(range));
1481     return shadowValueList;
1482 }
1483
1484 static RefPtr<CSSValue> consumeTextDecorationLine(CSSParserTokenRange& range)
1485 {
1486     CSSValueID id = range.peek().id();
1487     if (id == CSSValueNone)
1488         return consumeIdent(range);
1489
1490     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1491     while (true) {
1492         RefPtr<CSSPrimitiveValue> ident = consumeIdent<CSSValueBlink, CSSValueUnderline, CSSValueOverline, CSSValueLineThrough>(range);
1493         if (!ident)
1494             break;
1495         if (list->hasValue(ident.get()))
1496             return nullptr;
1497         list->append(ident.releaseNonNull());
1498     }
1499
1500     if (!list->length())
1501         return nullptr;
1502     return list;
1503 }
1504
1505 static RefPtr<CSSValue> consumeTextDecorationSkip(CSSParserTokenRange& range)
1506 {
1507     CSSValueID id = range.peek().id();
1508     if (id == CSSValueNone)
1509         return consumeIdent(range);
1510
1511     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1512     while (true) {
1513         auto ident = consumeIdent<CSSValueAuto, CSSValueInk, CSSValueObjects>(range);
1514         if (!ident)
1515             break;
1516         if (list->hasValue(ident.get()))
1517             return nullptr;
1518         list->append(ident.releaseNonNull());
1519     }
1520
1521     if (!list->length())
1522         return nullptr;
1523     return list;
1524 }
1525
1526 static RefPtr<CSSValue> consumeTextEmphasisStyle(CSSParserTokenRange& range)
1527 {
1528     CSSValueID id = range.peek().id();
1529     if (id == CSSValueNone)
1530         return consumeIdent(range);
1531
1532     if (RefPtr<CSSValue> textEmphasisStyle = consumeString(range))
1533         return textEmphasisStyle;
1534
1535     RefPtr<CSSPrimitiveValue> fill = consumeIdent<CSSValueFilled, CSSValueOpen>(range);
1536     RefPtr<CSSPrimitiveValue> shape = consumeIdent<CSSValueDot, CSSValueCircle, CSSValueDoubleCircle, CSSValueTriangle, CSSValueSesame>(range);
1537     if (!fill)
1538         fill = consumeIdent<CSSValueFilled, CSSValueOpen>(range);
1539     if (fill && shape) {
1540         RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
1541         parsedValues->append(fill.releaseNonNull());
1542         parsedValues->append(shape.releaseNonNull());
1543         return parsedValues;
1544     }
1545     if (fill)
1546         return fill;
1547     if (shape)
1548         return shape;
1549     return nullptr;
1550 }
1551
1552 static RefPtr<CSSValue> consumeOutlineColor(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1553 {
1554     // Allow the special focus color even in HTML Standard parsing mode.
1555     if (range.peek().id() == CSSValueWebkitFocusRingColor)
1556         return consumeIdent(range);
1557     return consumeColor(range, cssParserMode);
1558 }
1559
1560 static RefPtr<CSSPrimitiveValue> consumeLineWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
1561 {
1562     CSSValueID id = range.peek().id();
1563     if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
1564         return consumeIdent(range);
1565     return consumeLength(range, cssParserMode, ValueRangeNonNegative, unitless);
1566 }
1567
1568 static RefPtr<CSSPrimitiveValue> consumeBorderWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
1569 {
1570     return consumeLineWidth(range, cssParserMode, unitless);
1571 }
1572
1573 static RefPtr<CSSPrimitiveValue> consumeTextStrokeWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1574 {
1575     return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid);
1576 }
1577
1578 static RefPtr<CSSPrimitiveValue> consumeColumnRuleWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1579 {
1580     return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid);
1581 }
1582
1583 static bool consumeTranslate3d(CSSParserTokenRange& args, CSSParserMode cssParserMode, RefPtr<WebKitCSSTransformValue>& transformValue)
1584 {
1585     unsigned numberOfArguments = 2;
1586     RefPtr<CSSValue> parsedValue;
1587     do {
1588         parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
1589         if (!parsedValue)
1590             return false;
1591         transformValue->append(*parsedValue);
1592         if (!consumeCommaIncludingWhitespace(args))
1593             return false;
1594     } while (--numberOfArguments);
1595     parsedValue = consumeLength(args, cssParserMode, ValueRangeAll);
1596     if (!parsedValue)
1597         return false;
1598     transformValue->append(*parsedValue);
1599     return true;
1600 }
1601
1602 static bool consumeNumbers(CSSParserTokenRange& args, RefPtr<WebKitCSSTransformValue>& transformValue, unsigned numberOfArguments)
1603 {
1604     do {
1605         RefPtr<CSSPrimitiveValue> parsedValue = consumeNumber(args, ValueRangeAll);
1606         if (!parsedValue)
1607             return false;
1608         transformValue->append(parsedValue.releaseNonNull());
1609         if (--numberOfArguments && !consumeCommaIncludingWhitespace(args))
1610             return false;
1611     } while (numberOfArguments);
1612     return true;
1613 }
1614
1615 static bool consumePerspective(CSSParserTokenRange& args, CSSParserMode cssParserMode, RefPtr<WebKitCSSTransformValue>& transformValue)
1616 {
1617     RefPtr<CSSPrimitiveValue> parsedValue = consumeLength(args, cssParserMode, ValueRangeNonNegative);
1618     if (!parsedValue) {
1619         double perspective;
1620         if (!consumeNumberRaw(args, perspective) || perspective < 0)
1621             return false;
1622         parsedValue = CSSPrimitiveValue::create(perspective, CSSPrimitiveValue::UnitTypes::CSS_PX);
1623     }
1624     if (!parsedValue)
1625         return false;
1626     transformValue->append(parsedValue.releaseNonNull());
1627     return true;
1628 }
1629
1630 // FIXME-NEWPARSER: This has no reason to exist once we eliminate WebkitCSSTransformValue in favor
1631 // of CSSFunctionValue.
1632 static WebKitCSSTransformValue::TransformOperationType transformOperationForCSSValueID(CSSValueID functionId)
1633 {
1634     switch (functionId) {
1635     case CSSValueRotate:
1636         return WebKitCSSTransformValue::RotateTransformOperation;
1637     case CSSValueRotatex:
1638         return WebKitCSSTransformValue::RotateXTransformOperation;
1639     case CSSValueRotatey:
1640         return WebKitCSSTransformValue::RotateYTransformOperation;
1641     case CSSValueRotatez:
1642         return WebKitCSSTransformValue::RotateZTransformOperation;
1643     case CSSValueSkewx:
1644         return WebKitCSSTransformValue::SkewXTransformOperation;
1645     case CSSValueSkewy:
1646         return WebKitCSSTransformValue::SkewYTransformOperation;
1647     case CSSValueSkew:
1648         return WebKitCSSTransformValue::SkewTransformOperation;
1649     case CSSValueScalex:
1650         return WebKitCSSTransformValue::ScaleXTransformOperation;
1651     case CSSValueScaley:
1652         return WebKitCSSTransformValue::ScaleYTransformOperation;
1653     case CSSValueScalez:
1654         return WebKitCSSTransformValue::ScaleZTransformOperation;
1655     case CSSValueScale:
1656         return WebKitCSSTransformValue::ScaleTransformOperation;
1657     case CSSValuePerspective:
1658         return WebKitCSSTransformValue::PerspectiveTransformOperation;
1659     case CSSValueTranslatex:
1660         return WebKitCSSTransformValue::TranslateXTransformOperation;
1661     case CSSValueTranslatey:
1662         return WebKitCSSTransformValue::TranslateYTransformOperation;
1663     case CSSValueTranslate:
1664         return WebKitCSSTransformValue::TranslateTransformOperation;
1665     case CSSValueTranslatez:
1666         return WebKitCSSTransformValue::TranslateZTransformOperation;
1667     case CSSValueMatrix:
1668         return WebKitCSSTransformValue::MatrixTransformOperation;
1669     case CSSValueMatrix3d:
1670         return WebKitCSSTransformValue::Matrix3DTransformOperation;
1671     case CSSValueScale3d:
1672         return WebKitCSSTransformValue::Scale3DTransformOperation;
1673     case CSSValueRotate3d:
1674         return WebKitCSSTransformValue::Rotate3DTransformOperation;
1675     case CSSValueTranslate3d:
1676         return WebKitCSSTransformValue::Translate3DTransformOperation;
1677     default:
1678         return WebKitCSSTransformValue::UnknownTransformOperation;
1679     }
1680 }
1681
1682 static RefPtr<CSSValue> consumeTransformValue(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1683 {
1684     CSSValueID functionId = range.peek().functionId();
1685     if (functionId == CSSValueInvalid)
1686         return nullptr;
1687     CSSParserTokenRange args = consumeFunction(range);
1688     if (args.atEnd())
1689         return nullptr;
1690     
1691     // FIXME-NEWPARSER: Do we really need WebkitCSSTransformValue? A CSSFunctionValue is good
1692     // enough and has the CSSValueID as the operation type. Blink has eliminated it.
1693     RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(transformOperationForCSSValueID(functionId));
1694     RefPtr<CSSValue> parsedValue;
1695     switch (functionId) {
1696     case CSSValueRotate:
1697     case CSSValueRotatex:
1698     case CSSValueRotatey:
1699     case CSSValueRotatez:
1700     case CSSValueSkewx:
1701     case CSSValueSkewy:
1702     case CSSValueSkew:
1703         parsedValue = consumeAngle(args, cssParserMode, UnitlessQuirk::Forbid);
1704         if (!parsedValue)
1705             return nullptr;
1706         if (functionId == CSSValueSkew && consumeCommaIncludingWhitespace(args)) {
1707             transformValue->append(*parsedValue);
1708             parsedValue = consumeAngle(args, cssParserMode, UnitlessQuirk::Forbid);
1709             if (!parsedValue)
1710                 return nullptr;
1711         }
1712         break;
1713     case CSSValueScalex:
1714     case CSSValueScaley:
1715     case CSSValueScalez:
1716     case CSSValueScale:
1717         parsedValue = consumeNumber(args, ValueRangeAll);
1718         if (!parsedValue)
1719             return nullptr;
1720         if (functionId == CSSValueScale && consumeCommaIncludingWhitespace(args)) {
1721             transformValue->append(*parsedValue);
1722             parsedValue = consumeNumber(args, ValueRangeAll);
1723             if (!parsedValue)
1724                 return nullptr;
1725         }
1726         break;
1727     case CSSValuePerspective:
1728         if (!consumePerspective(args, cssParserMode, transformValue))
1729             return nullptr;
1730         break;
1731     case CSSValueTranslatex:
1732     case CSSValueTranslatey:
1733     case CSSValueTranslate:
1734         parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
1735         if (!parsedValue)
1736             return nullptr;
1737         if (functionId == CSSValueTranslate && consumeCommaIncludingWhitespace(args)) {
1738             transformValue->append(*parsedValue);
1739             parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
1740             if (!parsedValue)
1741                 return nullptr;
1742         }
1743         break;
1744     case CSSValueTranslatez:
1745         parsedValue = consumeLength(args, cssParserMode, ValueRangeAll);
1746         break;
1747     case CSSValueMatrix:
1748     case CSSValueMatrix3d:
1749         if (!consumeNumbers(args, transformValue, (functionId == CSSValueMatrix3d) ? 16 : 6))
1750             return nullptr;
1751         break;
1752     case CSSValueScale3d:
1753         if (!consumeNumbers(args, transformValue, 3))
1754             return nullptr;
1755         break;
1756     case CSSValueRotate3d:
1757         if (!consumeNumbers(args, transformValue, 3) || !consumeCommaIncludingWhitespace(args))
1758             return nullptr;
1759         parsedValue = consumeAngle(args, cssParserMode, UnitlessQuirk::Forbid);
1760         if (!parsedValue)
1761             return nullptr;
1762         break;
1763     case CSSValueTranslate3d:
1764         if (!consumeTranslate3d(args, cssParserMode, transformValue))
1765             return nullptr;
1766         break;
1767     default:
1768         return nullptr;
1769     }
1770     if (parsedValue)
1771         transformValue->append(*parsedValue);
1772     if (!args.atEnd())
1773         return nullptr;
1774     return transformValue;
1775 }
1776
1777 static RefPtr<CSSValue> consumeTransform(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1778 {
1779     if (range.peek().id() == CSSValueNone)
1780         return consumeIdent(range);
1781
1782     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1783     do {
1784         RefPtr<CSSValue> parsedTransformValue = consumeTransformValue(range, cssParserMode);
1785         if (!parsedTransformValue)
1786             return nullptr;
1787         list->append(parsedTransformValue.releaseNonNull());
1788     } while (!range.atEnd());
1789
1790     return list;
1791 }
1792
1793 template <CSSValueID start, CSSValueID end>
1794 static RefPtr<CSSPrimitiveValue> consumePositionLonghand(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1795 {
1796     if (range.peek().type() == IdentToken) {
1797         CSSValueID id = range.peek().id();
1798         int percent;
1799         if (id == start)
1800             percent = 0;
1801         else if (id == CSSValueCenter)
1802             percent = 50;
1803         else if (id == end)
1804             percent = 100;
1805         else
1806             return nullptr;
1807         range.consumeIncludingWhitespace();
1808         return CSSPrimitiveValue::create(percent, CSSPrimitiveValue::UnitTypes::CSS_PERCENTAGE);
1809     }
1810     return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
1811 }
1812
1813 static RefPtr<CSSPrimitiveValue> consumePositionX(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1814 {
1815     return consumePositionLonghand<CSSValueLeft, CSSValueRight>(range, cssParserMode);
1816 }
1817
1818 static RefPtr<CSSPrimitiveValue> consumePositionY(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1819 {
1820     return consumePositionLonghand<CSSValueTop, CSSValueBottom>(range, cssParserMode);
1821 }
1822
1823 static RefPtr<CSSValue> consumePaintStroke(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1824 {
1825     if (range.peek().id() == CSSValueNone)
1826         return consumeIdent(range);
1827     RefPtr<CSSPrimitiveValue> url = consumeUrl(range);
1828     if (url) {
1829         RefPtr<CSSValue> parsedValue;
1830         if (range.peek().id() == CSSValueNone)
1831             parsedValue = consumeIdent(range);
1832         else
1833             parsedValue = consumeColor(range, cssParserMode);
1834         if (parsedValue) {
1835             RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
1836             values->append(url.releaseNonNull());
1837             values->append(parsedValue.releaseNonNull());
1838             return values;
1839         }
1840         return url;
1841     }
1842     return consumeColor(range, cssParserMode);
1843 }
1844
1845 static RefPtr<CSSValue> consumePaintOrder(CSSParserTokenRange& range)
1846 {
1847     if (range.peek().id() == CSSValueNormal)
1848         return consumeIdent(range);
1849
1850     Vector<CSSValueID, 3> paintTypeList;
1851     RefPtr<CSSPrimitiveValue> fill;
1852     RefPtr<CSSPrimitiveValue> stroke;
1853     RefPtr<CSSPrimitiveValue> markers;
1854     do {
1855         CSSValueID id = range.peek().id();
1856         if (id == CSSValueFill && !fill)
1857             fill = consumeIdent(range);
1858         else if (id == CSSValueStroke && !stroke)
1859             stroke = consumeIdent(range);
1860         else if (id == CSSValueMarkers && !markers)
1861             markers = consumeIdent(range);
1862         else
1863             return nullptr;
1864         paintTypeList.append(id);
1865     } while (!range.atEnd());
1866
1867     // After parsing we serialize the paint-order list. Since it is not possible to
1868     // pop a last list items from CSSValueList without bigger cost, we create the
1869     // list after parsing.
1870     CSSValueID firstPaintOrderType = paintTypeList.at(0);
1871     RefPtr<CSSValueList> paintOrderList = CSSValueList::createSpaceSeparated();
1872     switch (firstPaintOrderType) {
1873     case CSSValueFill:
1874     case CSSValueStroke:
1875         paintOrderList->append(firstPaintOrderType == CSSValueFill ? fill.releaseNonNull() : stroke.releaseNonNull());
1876         if (paintTypeList.size() > 1) {
1877             if (paintTypeList.at(1) == CSSValueMarkers)
1878                 paintOrderList->append(markers.releaseNonNull());
1879         }
1880         break;
1881     case CSSValueMarkers:
1882         paintOrderList->append(markers.releaseNonNull());
1883         if (paintTypeList.size() > 1) {
1884             if (paintTypeList.at(1) == CSSValueStroke)
1885                 paintOrderList->append(stroke.releaseNonNull());
1886         }
1887         break;
1888     default:
1889         ASSERT_NOT_REACHED();
1890     }
1891
1892     return paintOrderList;
1893 }
1894
1895 static RefPtr<CSSValue> consumeNoneOrURI(CSSParserTokenRange& range)
1896 {
1897     if (range.peek().id() == CSSValueNone)
1898         return consumeIdent(range);
1899     return consumeUrl(range);
1900 }
1901
1902 static RefPtr<CSSValue> consumeFlexBasis(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1903 {
1904     // FIXME: Support intrinsic dimensions too.
1905     if (range.peek().id() == CSSValueAuto)
1906         return consumeIdent(range);
1907     return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
1908 }
1909
1910 static RefPtr<CSSValue> consumeStrokeDasharray(CSSParserTokenRange& range)
1911 {
1912     CSSValueID id = range.peek().id();
1913     if (id == CSSValueNone)
1914         return consumeIdent(range);
1915
1916     RefPtr<CSSValueList> dashes = CSSValueList::createCommaSeparated();
1917     do {
1918         RefPtr<CSSPrimitiveValue> dash = consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeNonNegative);
1919         if (!dash || (consumeCommaIncludingWhitespace(range) && range.atEnd()))
1920             return nullptr;
1921         dashes->append(dash.releaseNonNull());
1922     } while (!range.atEnd());
1923     return dashes;
1924 }
1925
1926 static RefPtr<CSSPrimitiveValue> consumeBaselineShift(CSSParserTokenRange& range)
1927 {
1928     CSSValueID id = range.peek().id();
1929     if (id == CSSValueBaseline || id == CSSValueSub || id == CSSValueSuper)
1930         return consumeIdent(range);
1931     return consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeAll);
1932 }
1933
1934 static RefPtr<CSSPrimitiveValue> consumeRxOrRy(CSSParserTokenRange& range)
1935 {
1936     if (range.peek().id() == CSSValueAuto)
1937         return consumeIdent(range);
1938     return consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
1939 }
1940
1941 static RefPtr<CSSValue> consumeCursor(CSSParserTokenRange& range, const CSSParserContext& context, bool inQuirksMode)
1942 {
1943     RefPtr<CSSValueList> list;
1944     while (RefPtr<CSSValue> image = consumeImage(range, context, ConsumeGeneratedImage::Forbid)) {
1945         double num;
1946         IntPoint hotSpot(-1, -1);
1947         bool hotSpotSpecified = false;
1948         if (consumeNumberRaw(range, num)) {
1949             hotSpot.setX(int(num));
1950             if (!consumeNumberRaw(range, num))
1951                 return nullptr;
1952             hotSpot.setY(int(num));
1953             hotSpotSpecified = true;
1954         }
1955
1956         if (!list)
1957             list = CSSValueList::createCommaSeparated();
1958
1959         list->append(CSSCursorImageValue::create(image.releaseNonNull(), hotSpotSpecified, hotSpot));
1960         if (!consumeCommaIncludingWhitespace(range))
1961             return nullptr;
1962     }
1963
1964     CSSValueID id = range.peek().id();
1965     RefPtr<CSSValue> cursorType;
1966     if (id == CSSValueHand) {
1967         if (!inQuirksMode) // Non-standard behavior
1968             return nullptr;
1969         cursorType = CSSValuePool::singleton().createIdentifierValue(CSSValuePointer);
1970         range.consumeIncludingWhitespace();
1971     } else if ((id >= CSSValueAuto && id <= CSSValueWebkitZoomOut) || id == CSSValueCopy || id == CSSValueNone) {
1972         cursorType = consumeIdent(range);
1973     } else {
1974         return nullptr;
1975     }
1976
1977     if (!list)
1978         return cursorType;
1979     list->append(cursorType.releaseNonNull());
1980     return list;
1981 }
1982
1983 static RefPtr<CSSValue> consumeAttr(CSSParserTokenRange args, CSSParserContext context)
1984 {
1985     if (args.peek().type() != IdentToken)
1986         return nullptr;
1987     
1988     CSSParserToken token = args.consumeIncludingWhitespace();
1989     if (context.isHTMLDocument)
1990         token.convertToASCIILowercaseInPlace();
1991
1992     String attrName = token.value().toString();
1993     if (!args.atEnd())
1994         return nullptr;
1995
1996     // FIXME-NEWPARSER: We want to use a CSSCustomIdentValue here eventually for the attrName.
1997     // FIXME-NEWPARSER: We want to use a CSSFunctionValue rather than relying on a custom
1998     // attr() primitive value.
1999     return CSSValuePool::singleton().createValue(attrName, CSSPrimitiveValue::CSS_ATTR);
2000 }
2001
2002 static RefPtr<CSSValue> consumeCounterContent(CSSParserTokenRange args, bool counters)
2003 {
2004     RefPtr<CSSPrimitiveValue> identifier = consumeCustomIdent(args);
2005     if (!identifier)
2006         return nullptr;
2007
2008     RefPtr<CSSPrimitiveValue> separator;
2009     if (!counters)
2010         separator = CSSPrimitiveValue::create(String(), CSSPrimitiveValue::UnitTypes::CSS_STRING);
2011     else {
2012         if (!consumeCommaIncludingWhitespace(args) || args.peek().type() != StringToken)
2013             return nullptr;
2014         separator = CSSPrimitiveValue::create(args.consumeIncludingWhitespace().value().toString(), CSSPrimitiveValue::UnitTypes::CSS_STRING);
2015     }
2016
2017     RefPtr<CSSPrimitiveValue> listStyle;
2018     if (consumeCommaIncludingWhitespace(args)) {
2019         CSSValueID id = args.peek().id();
2020         if ((id != CSSValueNone && (id < CSSValueDisc || id > CSSValueKatakanaIroha)))
2021             return nullptr;
2022         listStyle = consumeIdent(args);
2023     } else
2024         listStyle = CSSValuePool::singleton().createIdentifierValue(CSSValueDecimal);
2025
2026     if (!args.atEnd())
2027         return nullptr;
2028     
2029     // FIXME-NEWPARSER: Should just have a CSSCounterValue.
2030     return CSSValuePool::singleton().createValue(Counter::create(identifier.releaseNonNull(), listStyle.releaseNonNull(), separator.releaseNonNull()));
2031 }
2032
2033 static RefPtr<CSSValue> consumeContent(CSSParserTokenRange& range, CSSParserContext context)
2034 {
2035     if (identMatches<CSSValueNone, CSSValueNormal>(range.peek().id()))
2036         return consumeIdent(range);
2037
2038     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
2039
2040     do {
2041         RefPtr<CSSValue> parsedValue = consumeImage(range, context);
2042         if (!parsedValue)
2043             parsedValue = consumeIdent<CSSValueOpenQuote, CSSValueCloseQuote, CSSValueNoOpenQuote, CSSValueNoCloseQuote>(range);
2044         if (!parsedValue)
2045             parsedValue = consumeString(range);
2046         if (!parsedValue) {
2047             if (range.peek().functionId() == CSSValueAttr)
2048                 parsedValue = consumeAttr(consumeFunction(range), context);
2049             else if (range.peek().functionId() == CSSValueCounter)
2050                 parsedValue = consumeCounterContent(consumeFunction(range), false);
2051             else if (range.peek().functionId() == CSSValueCounters)
2052                 parsedValue = consumeCounterContent(consumeFunction(range), true);
2053             if (!parsedValue)
2054                 return nullptr;
2055         }
2056         values->append(parsedValue.releaseNonNull());
2057     } while (!range.atEnd());
2058
2059     return values;
2060 }
2061
2062 static RefPtr<CSSPrimitiveValue> consumePerspective(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2063 {
2064     if (range.peek().id() == CSSValueNone)
2065         return consumeIdent(range);
2066     RefPtr<CSSPrimitiveValue> parsedValue = consumeLength(range, cssParserMode, ValueRangeAll);
2067     if (!parsedValue) {
2068         // FIXME: Make this quirk only apply to the webkit prefixed version of the property.
2069         double perspective;
2070         if (!consumeNumberRaw(range, perspective))
2071             return nullptr;
2072         parsedValue = CSSPrimitiveValue::create(perspective, CSSPrimitiveValue::UnitTypes::CSS_PX);
2073     }
2074     if (parsedValue && (parsedValue->isCalculated() || parsedValue->doubleValue() > 0))
2075         return parsedValue;
2076     return nullptr;
2077 }
2078
2079 #if ENABLE(CSS_SCROLL_SNAP)
2080
2081 static RefPtr<CSSValueList> consumeSnapPointCoordinateList(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2082 {
2083     RefPtr<CSSValueList> positions = CSSValueList::createSpaceSeparated();
2084     do {
2085         
2086         RefPtr<CSSPrimitiveValue> first = consumePositionX(range, cssParserMode);
2087         if (!first || range.atEnd())
2088             return nullptr;
2089         RefPtr<CSSPrimitiveValue> second = consumePositionY(range, cssParserMode);
2090         if (!second)
2091             return nullptr;
2092         RefPtr<CSSValue> position = createPrimitiveValuePair(first.releaseNonNull(), second.releaseNonNull(), Pair::IdenticalValueEncoding::DoNotCoalesce);
2093         positions->append(position.releaseNonNull());
2094     } while (!range.atEnd());
2095     return positions;
2096 }
2097
2098 static RefPtr<CSSValue> consumeScrollSnapCoordinate(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2099 {
2100     if (range.peek().id() == CSSValueNone)
2101         return consumeIdent(range);
2102     return consumeSnapPointCoordinateList(range, cssParserMode);
2103 }
2104
2105 static RefPtr<CSSValue> consumeScrollSnapDestination(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2106 {
2107     RefPtr<CSSPrimitiveValue> first = consumePositionX(range, cssParserMode);
2108     if (!first || range.atEnd())
2109         return nullptr;
2110     RefPtr<CSSPrimitiveValue> second = consumePositionY(range, cssParserMode);
2111     if (!second)
2112         return nullptr;
2113     return createPrimitiveValuePair(first.releaseNonNull(), second.releaseNonNull(), Pair::IdenticalValueEncoding::DoNotCoalesce);
2114 }
2115
2116 static RefPtr<CSSValue> consumeScrollSnapPoints(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2117 {
2118     if (range.peek().id() == CSSValueNone || range.peek().id() == CSSValueElements)
2119         return consumeIdent(range);
2120     
2121     RefPtr<CSSValueList> points = CSSValueList::createSpaceSeparated();
2122     do {
2123         if (range.peek().functionId() == CSSValueRepeat) {
2124             CSSParserTokenRange args = consumeFunction(range);
2125             RefPtr<CSSPrimitiveValue> parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeNonNegative);
2126             if (args.atEnd() && parsedValue && (parsedValue->isCalculated() || parsedValue->doubleValue() > 0)) {
2127                 Ref<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueRepeat);
2128                 result->append(parsedValue.releaseNonNull());
2129                 points->append(WTFMove(result));
2130             }
2131         } else {
2132             RefPtr<CSSValue> length = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Forbid);
2133             if (!length)
2134                 return nullptr;
2135             points->append(length.releaseNonNull());
2136         }
2137     } while (!range.atEnd());
2138     
2139     
2140     return points;
2141 }
2142
2143 #endif
2144
2145 static RefPtr<CSSValue> consumeBorderRadiusCorner(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2146 {
2147     RefPtr<CSSPrimitiveValue> parsedValue1 = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
2148     if (!parsedValue1)
2149         return nullptr;
2150     RefPtr<CSSPrimitiveValue> parsedValue2 = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
2151     if (!parsedValue2)
2152         parsedValue2 = parsedValue1;
2153     return createPrimitiveValuePair(parsedValue1.releaseNonNull(), parsedValue2.releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce);
2154 }
2155
2156 static RefPtr<CSSPrimitiveValue> consumeVerticalAlign(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2157 {
2158     RefPtr<CSSPrimitiveValue> parsedValue = consumeIdentRange(range, CSSValueBaseline, CSSValueWebkitBaselineMiddle);
2159     if (!parsedValue)
2160         parsedValue = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
2161     return parsedValue;
2162 }
2163
2164 static RefPtr<CSSPrimitiveValue> consumeShapeRadius(CSSParserTokenRange& args, CSSParserMode cssParserMode)
2165 {
2166     if (identMatches<CSSValueClosestSide, CSSValueFarthestSide>(args.peek().id()))
2167         return consumeIdent(args);
2168     return consumeLengthOrPercent(args, cssParserMode, ValueRangeNonNegative);
2169 }
2170
2171 static RefPtr<CSSBasicShapeCircle> consumeBasicShapeCircle(CSSParserTokenRange& args, const CSSParserContext& context)
2172 {
2173     // spec: https://drafts.csswg.org/css-shapes/#supported-basic-shapes
2174     // circle( [<shape-radius>]? [at <position>]? )
2175     RefPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
2176     if (RefPtr<CSSPrimitiveValue> radius = consumeShapeRadius(args, context.mode))
2177         shape->setRadius(radius.releaseNonNull());
2178     if (consumeIdent<CSSValueAt>(args)) {
2179         RefPtr<CSSPrimitiveValue> centerX;
2180         RefPtr<CSSPrimitiveValue> centerY;
2181         if (!consumePosition(args, context.mode, UnitlessQuirk::Forbid, centerX, centerY))
2182             return nullptr;
2183         shape->setCenterX(centerX.releaseNonNull());
2184         shape->setCenterY(centerY.releaseNonNull());
2185     }
2186     return shape;
2187 }
2188
2189 static RefPtr<CSSBasicShapeEllipse> consumeBasicShapeEllipse(CSSParserTokenRange& args, const CSSParserContext& context)
2190 {
2191     // spec: https://drafts.csswg.org/css-shapes/#supported-basic-shapes
2192     // ellipse( [<shape-radius>{2}]? [at <position>]? )
2193     RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
2194     if (RefPtr<CSSPrimitiveValue> radiusX = consumeShapeRadius(args, context.mode)) {
2195         shape->setRadiusX(radiusX.releaseNonNull());
2196         if (RefPtr<CSSPrimitiveValue> radiusY = consumeShapeRadius(args, context.mode))
2197             shape->setRadiusY(radiusY.releaseNonNull());
2198     }
2199     if (consumeIdent<CSSValueAt>(args)) {
2200         RefPtr<CSSPrimitiveValue> centerX;
2201         RefPtr<CSSPrimitiveValue> centerY;
2202         if (!consumePosition(args, context.mode, UnitlessQuirk::Forbid, centerX, centerY))
2203             return nullptr;
2204         shape->setCenterX(centerX.releaseNonNull());
2205         shape->setCenterY(centerY.releaseNonNull());
2206     }
2207     return shape;
2208 }
2209
2210 static RefPtr<CSSBasicShapePolygon> consumeBasicShapePolygon(CSSParserTokenRange& args, const CSSParserContext& context)
2211 {
2212     RefPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
2213     if (identMatches<CSSValueEvenodd, CSSValueNonzero>(args.peek().id())) {
2214         shape->setWindRule(args.consumeIncludingWhitespace().id() == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
2215         if (!consumeCommaIncludingWhitespace(args))
2216             return nullptr;
2217     }
2218
2219     do {
2220         RefPtr<CSSPrimitiveValue> xLength = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2221         if (!xLength)
2222             return nullptr;
2223         RefPtr<CSSPrimitiveValue> yLength = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2224         if (!yLength)
2225             return nullptr;
2226         shape->appendPoint(xLength.releaseNonNull(), yLength.releaseNonNull());
2227     } while (consumeCommaIncludingWhitespace(args));
2228     return shape;
2229 }
2230
2231 static RefPtr<CSSBasicShapePath> consumeBasicShapePath(CSSParserTokenRange& args)
2232 {
2233     WindRule windRule = RULE_NONZERO;
2234     if (identMatches<CSSValueEvenodd, CSSValueNonzero>(args.peek().id())) {
2235         windRule = args.consumeIncludingWhitespace().id() == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO;
2236         if (!consumeCommaIncludingWhitespace(args))
2237             return nullptr;
2238     }
2239
2240     if (args.peek().type() != StringToken)
2241         return nullptr;
2242     
2243     auto byteStream = std::make_unique<SVGPathByteStream>();
2244     if (!buildSVGPathByteStreamFromString(args.consumeIncludingWhitespace().value().toString(), *byteStream, UnalteredParsing))
2245         return nullptr;
2246     
2247     auto shape = CSSBasicShapePath::create(WTFMove(byteStream));
2248     shape->setWindRule(windRule);
2249     
2250     return WTFMove(shape);
2251 }
2252
2253 static void complete4Sides(RefPtr<CSSPrimitiveValue> side[4])
2254 {
2255     if (side[3])
2256         return;
2257     if (!side[2]) {
2258         if (!side[1])
2259             side[1] = side[0];
2260         side[2] = side[0];
2261     }
2262     side[3] = side[1];
2263 }
2264
2265 static bool consumeRadii(RefPtr<CSSPrimitiveValue> horizontalRadii[4], RefPtr<CSSPrimitiveValue> verticalRadii[4], CSSParserTokenRange& range, CSSParserMode cssParserMode, bool useLegacyParsing)
2266 {
2267     unsigned i = 0;
2268     for (; i < 4 && !range.atEnd() && range.peek().type() != DelimiterToken; ++i) {
2269         horizontalRadii[i] = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
2270         if (!horizontalRadii[i])
2271             return false;
2272     }
2273     if (!horizontalRadii[0])
2274         return false;
2275     if (range.atEnd()) {
2276         // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
2277         if (useLegacyParsing && i == 2) {
2278             verticalRadii[0] = horizontalRadii[1];
2279             horizontalRadii[1] = nullptr;
2280         } else {
2281             complete4Sides(horizontalRadii);
2282             for (unsigned i = 0; i < 4; ++i)
2283                 verticalRadii[i] = horizontalRadii[i];
2284             return true;
2285         }
2286     } else {
2287         if (!consumeSlashIncludingWhitespace(range))
2288             return false;
2289         for (i = 0; i < 4 && !range.atEnd(); ++i) {
2290             verticalRadii[i] = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
2291             if (!verticalRadii[i])
2292                 return false;
2293         }
2294         if (!verticalRadii[0] || !range.atEnd())
2295             return false;
2296     }
2297     complete4Sides(horizontalRadii);
2298     complete4Sides(verticalRadii);
2299     return true;
2300 }
2301
2302 static RefPtr<CSSBasicShapeInset> consumeBasicShapeInset(CSSParserTokenRange& args, const CSSParserContext& context)
2303 {
2304     RefPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create();
2305     RefPtr<CSSPrimitiveValue> top = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2306     if (!top)
2307         return nullptr;
2308     RefPtr<CSSPrimitiveValue> right = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2309     RefPtr<CSSPrimitiveValue> bottom;
2310     RefPtr<CSSPrimitiveValue> left;
2311     if (right) {
2312         bottom = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2313         if (bottom)
2314             left = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2315     }
2316     if (left)
2317         shape->updateShapeSize4Values(top.releaseNonNull(), right.releaseNonNull(), bottom.releaseNonNull(), left.releaseNonNull());
2318     else if (bottom)
2319         shape->updateShapeSize3Values(top.releaseNonNull(), right.releaseNonNull(), bottom.releaseNonNull());
2320     else if (right)
2321         shape->updateShapeSize2Values(top.releaseNonNull(), right.releaseNonNull());
2322     else
2323         shape->updateShapeSize1Value(top.releaseNonNull());
2324
2325     if (consumeIdent<CSSValueRound>(args)) {
2326         RefPtr<CSSPrimitiveValue> horizontalRadii[4] = { 0 };
2327         RefPtr<CSSPrimitiveValue> verticalRadii[4] = { 0 };
2328         if (!consumeRadii(horizontalRadii, verticalRadii, args, context.mode, false))
2329             return nullptr;
2330         shape->setTopLeftRadius(createPrimitiveValuePair(horizontalRadii[0].releaseNonNull(), verticalRadii[0].releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce));
2331         shape->setTopRightRadius(createPrimitiveValuePair(horizontalRadii[1].releaseNonNull(), verticalRadii[1].releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce));
2332         shape->setBottomRightRadius(createPrimitiveValuePair(horizontalRadii[2].releaseNonNull(), verticalRadii[2].releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce));
2333         shape->setBottomLeftRadius(createPrimitiveValuePair(horizontalRadii[3].releaseNonNull(), verticalRadii[3].releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce));
2334     }
2335     return shape;
2336 }
2337
2338 static RefPtr<CSSValue> consumeBasicShape(CSSParserTokenRange& range, const CSSParserContext& context)
2339 {
2340     RefPtr<CSSValue> result;
2341     if (range.peek().type() != FunctionToken)
2342         return nullptr;
2343     CSSValueID id = range.peek().functionId();
2344     CSSParserTokenRange rangeCopy = range;
2345     CSSParserTokenRange args = consumeFunction(rangeCopy);
2346     
2347     // FIXME-NEWPARSER: CSSBasicShape should be a CSSValue, and shapes should not be primitive values.
2348     RefPtr<CSSBasicShape> shape;
2349     if (id == CSSValueCircle)
2350         shape = consumeBasicShapeCircle(args, context);
2351     else if (id == CSSValueEllipse)
2352         shape = consumeBasicShapeEllipse(args, context);
2353     else if (id == CSSValuePolygon)
2354         shape = consumeBasicShapePolygon(args, context);
2355     else if (id == CSSValueInset)
2356         shape = consumeBasicShapeInset(args, context);
2357     else if (id == CSSValuePath)
2358         shape = consumeBasicShapePath(args);
2359     if (!shape)
2360         return nullptr;
2361     range = rangeCopy;
2362     
2363     if (!args.atEnd())
2364         return nullptr;
2365
2366     return CSSValuePool::singleton().createValue(shape.releaseNonNull());
2367 }
2368
2369 static RefPtr<CSSValue> consumeBasicShapeOrBox(CSSParserTokenRange& range, const CSSParserContext& context)
2370 {
2371     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
2372     bool shapeFound = false;
2373     bool boxFound = false;
2374     while (!range.atEnd() && !(shapeFound && boxFound)) {
2375         RefPtr<CSSValue> componentValue;
2376         if (range.peek().type() == FunctionToken && !shapeFound) {
2377             componentValue = consumeBasicShape(range, context);
2378             shapeFound = true;
2379         } else if (range.peek().type() == IdentToken && !boxFound) {
2380             componentValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox, CSSValueFill, CSSValueStroke, CSSValueViewBox>(range);
2381             boxFound = true;
2382         }
2383         if (!componentValue)
2384             return nullptr;
2385         list->append(componentValue.releaseNonNull());
2386     }
2387     
2388     if (!range.atEnd())
2389         return nullptr;
2390     
2391     return list;
2392 }
2393     
2394 static RefPtr<CSSValue> consumeWebkitClipPath(CSSParserTokenRange& range, const CSSParserContext& context)
2395 {
2396     if (range.peek().id() == CSSValueNone)
2397         return consumeIdent(range);
2398     if (RefPtr<CSSPrimitiveValue> url = consumeUrl(range))
2399         return url;
2400     return consumeBasicShapeOrBox(range, context);
2401 }
2402
2403 static RefPtr<CSSValue> consumeShapeOutside(CSSParserTokenRange& range, const CSSParserContext& context)
2404 {
2405     if (RefPtr<CSSValue> imageValue = consumeImageOrNone(range, context))
2406         return imageValue;
2407     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
2408     if (RefPtr<CSSValue> boxValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox>(range))
2409         list->append(boxValue.releaseNonNull());
2410     if (RefPtr<CSSValue> shapeValue = consumeBasicShape(range, context)) {
2411         list->append(shapeValue.releaseNonNull());
2412         if (list->length() < 2) {
2413             if (RefPtr<CSSValue> boxValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox>(range))
2414                 list->append(boxValue.releaseNonNull());
2415         }
2416     }
2417     if (!list->length())
2418         return nullptr;
2419     return list;
2420 }
2421
2422 static RefPtr<CSSValue> consumeContentDistributionOverflowPosition(CSSParserTokenRange& range)
2423 {
2424     if (identMatches<CSSValueNormal, CSSValueBaseline, CSSValueLastBaseline>(range.peek().id()))
2425         return CSSContentDistributionValue::create(CSSValueInvalid, range.consumeIncludingWhitespace().id(), CSSValueInvalid);
2426
2427     CSSValueID distribution = CSSValueInvalid;
2428     CSSValueID position = CSSValueInvalid;
2429     CSSValueID overflow = CSSValueInvalid;
2430     do {
2431         CSSValueID id = range.peek().id();
2432         if (identMatches<CSSValueSpaceBetween, CSSValueSpaceAround, CSSValueSpaceEvenly, CSSValueStretch>(id)) {
2433             if (distribution != CSSValueInvalid)
2434                 return nullptr;
2435             distribution = id;
2436         } else if (identMatches<CSSValueStart, CSSValueEnd, CSSValueCenter, CSSValueFlexStart, CSSValueFlexEnd, CSSValueLeft, CSSValueRight>(id)) {
2437             if (position != CSSValueInvalid)
2438                 return nullptr;
2439             position = id;
2440         } else if (identMatches<CSSValueUnsafe, CSSValueSafe>(id)) {
2441             if (overflow != CSSValueInvalid)
2442                 return nullptr;
2443             overflow = id;
2444         } else {
2445             return nullptr;
2446         }
2447         range.consumeIncludingWhitespace();
2448     } while (!range.atEnd());
2449
2450     // The grammar states that we should have at least <content-distribution> or <content-position>.
2451     if (position == CSSValueInvalid && distribution == CSSValueInvalid)
2452         return nullptr;
2453
2454     // The grammar states that <overflow-position> must be associated to <content-position>.
2455     if (overflow != CSSValueInvalid && position == CSSValueInvalid)
2456         return nullptr;
2457
2458     return CSSContentDistributionValue::create(distribution, position, overflow);
2459 }
2460
2461 static RefPtr<CSSPrimitiveValue> consumeBorderImageRepeatKeyword(CSSParserTokenRange& range)
2462 {
2463     return consumeIdent<CSSValueStretch, CSSValueRepeat, CSSValueSpace, CSSValueRound>(range);
2464 }
2465
2466 static RefPtr<CSSValue> consumeBorderImageRepeat(CSSParserTokenRange& range)
2467 {
2468     RefPtr<CSSPrimitiveValue> horizontal = consumeBorderImageRepeatKeyword(range);
2469     if (!horizontal)
2470         return nullptr;
2471     RefPtr<CSSPrimitiveValue> vertical = consumeBorderImageRepeatKeyword(range);
2472     if (!vertical)
2473         vertical = horizontal;
2474     return createPrimitiveValuePair(horizontal.releaseNonNull(), vertical.releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce);
2475 }
2476
2477 static RefPtr<CSSValue> consumeBorderImageSlice(CSSPropertyID property, CSSParserTokenRange& range)
2478 {
2479     bool fill = consumeIdent<CSSValueFill>(range);
2480     RefPtr<CSSPrimitiveValue> slices[4] = { 0 };
2481
2482     for (size_t index = 0; index < 4; ++index) {
2483         RefPtr<CSSPrimitiveValue> value = consumePercent(range, ValueRangeNonNegative);
2484         if (!value)
2485             value = consumeNumber(range, ValueRangeNonNegative);
2486         if (!value)
2487             break;
2488         slices[index] = value;
2489     }
2490     if (!slices[0])
2491         return nullptr;
2492     if (consumeIdent<CSSValueFill>(range)) {
2493         if (fill)
2494             return nullptr;
2495         fill = true;
2496     }
2497     complete4Sides(slices);
2498     // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
2499     // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
2500     if (property == CSSPropertyWebkitBorderImage || property == CSSPropertyWebkitMaskBoxImage || property == CSSPropertyWebkitBoxReflect)
2501         fill = true;
2502     
2503     // Now build a rect value to hold all four of our primitive values.
2504     // FIXME-NEWPARSER: Should just have a CSSQuadValue.
2505     auto quad = Quad::create();
2506     quad->setTop(slices[0].releaseNonNull());
2507     quad->setRight(slices[1].releaseNonNull());
2508     quad->setBottom(slices[2].releaseNonNull());
2509     quad->setLeft(slices[3].releaseNonNull());
2510     
2511     // Make our new border image value now.
2512     return CSSBorderImageSliceValue::create(CSSValuePool::singleton().createValue(WTFMove(quad)), fill);
2513 }
2514
2515 static RefPtr<CSSValue> consumeBorderImageOutset(CSSParserTokenRange& range)
2516 {
2517     RefPtr<CSSPrimitiveValue> outsets[4] = { 0 };
2518
2519     RefPtr<CSSPrimitiveValue> value;
2520     for (size_t index = 0; index < 4; ++index) {
2521         value = consumeNumber(range, ValueRangeNonNegative);
2522         if (!value)
2523             value = consumeLength(range, HTMLStandardMode, ValueRangeNonNegative);
2524         if (!value)
2525             break;
2526         outsets[index] = value;
2527     }
2528     if (!outsets[0])
2529         return nullptr;
2530     complete4Sides(outsets);
2531     
2532     // FIXME-NEWPARSER: Should just have a CSSQuadValue.
2533     auto quad = Quad::create();
2534     quad->setTop(outsets[0].releaseNonNull());
2535     quad->setRight(outsets[1].releaseNonNull());
2536     quad->setBottom(outsets[2].releaseNonNull());
2537     quad->setLeft(outsets[3].releaseNonNull());
2538     
2539     return CSSValuePool::singleton().createValue(WTFMove(quad));
2540 }
2541
2542 static RefPtr<CSSValue> consumeBorderImageWidth(CSSParserTokenRange& range)
2543 {
2544     RefPtr<CSSPrimitiveValue> widths[4];
2545
2546     RefPtr<CSSPrimitiveValue> value;
2547     for (size_t index = 0; index < 4; ++index) {
2548         value = consumeNumber(range, ValueRangeNonNegative);
2549         if (!value)
2550             value = consumeLengthOrPercent(range, HTMLStandardMode, ValueRangeNonNegative, UnitlessQuirk::Forbid);
2551         if (!value)
2552             value = consumeIdent<CSSValueAuto>(range);
2553         if (!value)
2554             break;
2555         widths[index] = value;
2556     }
2557     if (!widths[0])
2558         return nullptr;
2559     complete4Sides(widths);
2560     
2561     // FIXME-NEWPARSER: Should just have a CSSQuadValue.
2562     auto quad = Quad::create();
2563     quad->setTop(widths[0].releaseNonNull());
2564     quad->setRight(widths[1].releaseNonNull());
2565     quad->setBottom(widths[2].releaseNonNull());
2566     quad->setLeft(widths[3].releaseNonNull());
2567     
2568     return CSSValuePool::singleton().createValue(WTFMove(quad));
2569 }
2570
2571 static bool consumeBorderImageComponents(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context, RefPtr<CSSValue>& source,
2572     RefPtr<CSSValue>& slice, RefPtr<CSSValue>& width, RefPtr<CSSValue>& outset, RefPtr<CSSValue>& repeat)
2573 {
2574     do {
2575         if (!source) {
2576             source = consumeImageOrNone(range, context);
2577             if (source)
2578                 continue;
2579         }
2580         if (!repeat) {
2581             repeat = consumeBorderImageRepeat(range);
2582             if (repeat)
2583                 continue;
2584         }
2585         if (!slice) {
2586             slice = consumeBorderImageSlice(property, range);
2587             if (slice) {
2588                 ASSERT(!width && !outset);
2589                 if (consumeSlashIncludingWhitespace(range)) {
2590                     width = consumeBorderImageWidth(range);
2591                     if (consumeSlashIncludingWhitespace(range)) {
2592                         outset = consumeBorderImageOutset(range);
2593                         if (!outset)
2594                             return false;
2595                     } else if (!width) {
2596                         return false;
2597                     }
2598                 }
2599             } else {
2600                 return false;
2601             }
2602         } else {
2603             return false;
2604         }
2605     } while (!range.atEnd());
2606     return true;
2607 }
2608
2609 static RefPtr<CSSValue> consumeWebkitBorderImage(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
2610 {
2611     RefPtr<CSSValue> source;
2612     RefPtr<CSSValue> slice;
2613     RefPtr<CSSValue> width;
2614     RefPtr<CSSValue> outset;
2615     RefPtr<CSSValue> repeat;
2616     if (consumeBorderImageComponents(property, range, context, source, slice, width, outset, repeat))
2617         return createBorderImageValue(WTFMove(source), WTFMove(slice), WTFMove(width), WTFMove(outset), WTFMove(repeat));
2618     return nullptr;
2619 }
2620
2621 static RefPtr<CSSValue> consumeReflect(CSSParserTokenRange& range, const CSSParserContext& context)
2622 {
2623     RefPtr<CSSPrimitiveValue> direction = consumeIdent<CSSValueAbove, CSSValueBelow, CSSValueLeft, CSSValueRight>(range);
2624     if (!direction)
2625         return nullptr;
2626
2627     RefPtr<CSSPrimitiveValue> offset;
2628     if (range.atEnd())
2629         offset = CSSValuePool::singleton().createValue(0, CSSPrimitiveValue::UnitTypes::CSS_PX);
2630     else {
2631         offset = consumeLengthOrPercent(range, context.mode, ValueRangeAll, UnitlessQuirk::Forbid);
2632         if (!offset)
2633             return nullptr;
2634     }
2635
2636     RefPtr<CSSValue> mask;
2637     if (!range.atEnd()) {
2638         mask = consumeWebkitBorderImage(CSSPropertyWebkitBoxReflect, range, context);
2639         if (!mask)
2640             return nullptr;
2641     }
2642     return CSSReflectValue::create(direction.releaseNonNull(), offset.releaseNonNull(), WTFMove(mask));
2643 }
2644
2645 #if ENABLE(CSS_IMAGE_ORIENTATION)
2646 static RefPtr<CSSValue> consumeImageOrientation(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless = UnitlessQuirk::Forbid)
2647 {
2648     if (range.peek().type() != NumberToken) {
2649         RefPtr<CSSPrimitiveValue> angle = consumeAngle(range, cssParserMode, unitless);
2650         if (angle && angle->doubleValue() == 0)
2651             return angle;
2652     }
2653     return nullptr;
2654 }
2655 #endif
2656
2657 static RefPtr<CSSPrimitiveValue> consumeBackgroundBlendMode(CSSParserTokenRange& range)
2658 {
2659     CSSValueID id = range.peek().id();
2660     if (id == CSSValueNormal || id == CSSValueOverlay || (id >= CSSValueMultiply && id <= CSSValueLuminosity))
2661         return consumeIdent(range);
2662     return nullptr;
2663 }
2664
2665 static RefPtr<CSSPrimitiveValue> consumeBackgroundAttachment(CSSParserTokenRange& range)
2666 {
2667     return consumeIdent<CSSValueScroll, CSSValueFixed, CSSValueLocal>(range);
2668 }
2669
2670 static RefPtr<CSSPrimitiveValue> consumeBackgroundBox(CSSParserTokenRange& range)
2671 {
2672     return consumeIdent<CSSValueBorderBox, CSSValuePaddingBox, CSSValueContentBox, CSSValueWebkitText>(range);
2673 }
2674
2675 static RefPtr<CSSPrimitiveValue> consumeBackgroundComposite(CSSParserTokenRange& range)
2676 {
2677     return consumeIdentRange(range, CSSValueClear, CSSValuePlusLighter);
2678 }
2679
2680 static RefPtr<CSSPrimitiveValue> consumeWebkitMaskSourceType(CSSParserTokenRange& range)
2681 {
2682     return consumeIdent<CSSValueAuto, CSSValueAlpha, CSSValueLuminance>(range);
2683 }
2684
2685 static RefPtr<CSSPrimitiveValue> consumePrefixedBackgroundBox(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& /*context*/)
2686 {
2687     // The values 'border', 'padding' and 'content' are deprecated and do not apply to the version of the property that has the -webkit- prefix removed.
2688     if (RefPtr<CSSPrimitiveValue> value = consumeIdentRange(range, CSSValueBorder, CSSValuePaddingBox))
2689         return value;
2690     if (range.peek().id() == CSSValueWebkitText || ((property == CSSPropertyWebkitBackgroundClip || property == CSSPropertyWebkitMaskClip) && range.peek().id() == CSSValueText))
2691         return consumeIdent(range);
2692     return nullptr;
2693 }
2694
2695 static RefPtr<CSSPrimitiveValue> consumeBackgroundSize(CSSPropertyID property, CSSParserTokenRange& range, CSSParserMode cssParserMode)
2696 {
2697     if (identMatches<CSSValueContain, CSSValueCover>(range.peek().id()))
2698         return consumeIdent(range);
2699
2700     // FIXME: We're allowing the unitless quirk on this property because our
2701     // tests assume that. Other browser engines don't allow it though.
2702     RefPtr<CSSPrimitiveValue> horizontal = consumeIdent<CSSValueAuto>(range);
2703     if (!horizontal)
2704         horizontal = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
2705
2706     RefPtr<CSSPrimitiveValue> vertical;
2707     if (!range.atEnd()) {
2708         if (range.peek().id() == CSSValueAuto) // `auto' is the default
2709             range.consumeIncludingWhitespace();
2710         else
2711             vertical = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
2712     } else if (!vertical && property == CSSPropertyWebkitBackgroundSize) {
2713         // Legacy syntax: "-webkit-background-size: 10px" is equivalent to "background-size: 10px 10px".
2714         vertical = horizontal;
2715     }
2716     if (!vertical)
2717         return horizontal;
2718     return createPrimitiveValuePair(horizontal.releaseNonNull(), vertical.releaseNonNull(), Pair::IdenticalValueEncoding::DoNotCoalesce);
2719 }
2720
2721 #if ENABLE(CSS_GRID_LAYOUT)
2722 static RefPtr<CSSValueList> consumeGridAutoFlow(CSSParserTokenRange& range)
2723 {
2724     RefPtr<CSSPrimitiveValue> rowOrColumnValue = consumeIdent<CSSValueRow, CSSValueColumn>(range);
2725     RefPtr<CSSPrimitiveValue> denseAlgorithm = consumeIdent<CSSValueDense>(range);
2726     if (!rowOrColumnValue) {
2727         rowOrColumnValue = consumeIdent<CSSValueRow, CSSValueColumn>(range);
2728         if (!rowOrColumnValue && !denseAlgorithm)
2729             return nullptr;
2730     }
2731     RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
2732     if (rowOrColumnValue)
2733         parsedValues->append(rowOrColumnValue.releaseNonNull());
2734     if (denseAlgorithm)
2735         parsedValues->append(denseAlgorithm.releaseNonNull());
2736     return parsedValues;
2737 }
2738 #endif
2739
2740 static RefPtr<CSSValue> consumeBackgroundComponent(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
2741 {
2742     switch (property) {
2743     case CSSPropertyBackgroundClip:
2744         return consumeBackgroundBox(range);
2745     case CSSPropertyBackgroundBlendMode:
2746         return consumeBackgroundBlendMode(range);
2747     case CSSPropertyBackgroundAttachment:
2748         return consumeBackgroundAttachment(range);
2749     case CSSPropertyBackgroundOrigin:
2750         return consumeBackgroundBox(range);
2751     case CSSPropertyWebkitMaskComposite:
2752     case CSSPropertyWebkitBackgroundComposite:
2753         return consumeBackgroundComposite(range);
2754     case CSSPropertyWebkitBackgroundClip:
2755     case CSSPropertyWebkitBackgroundOrigin:
2756     case CSSPropertyWebkitMaskClip:
2757     case CSSPropertyWebkitMaskOrigin:
2758         return consumePrefixedBackgroundBox(property, range, context);
2759     case CSSPropertyBackgroundImage:
2760     case CSSPropertyWebkitMaskImage:
2761         return consumeImageOrNone(range, context);
2762     case CSSPropertyWebkitMaskSourceType:
2763         return consumeWebkitMaskSourceType(range);
2764     case CSSPropertyBackgroundPositionX:
2765     case CSSPropertyWebkitMaskPositionX:
2766         return consumePositionX(range, context.mode);
2767     case CSSPropertyBackgroundPositionY:
2768     case CSSPropertyWebkitMaskPositionY:
2769         return consumePositionY(range, context.mode);
2770     case CSSPropertyBackgroundSize:
2771     case CSSPropertyWebkitBackgroundSize:
2772     case CSSPropertyWebkitMaskSize:
2773         return consumeBackgroundSize(property, range, context.mode);
2774     case CSSPropertyBackgroundColor:
2775         return consumeColor(range, context.mode);
2776     default:
2777         break;
2778     };
2779     return nullptr;
2780 }
2781
2782 static void addBackgroundValue(RefPtr<CSSValue>& list, Ref<CSSValue>&& value)
2783 {
2784     if (list) {
2785         if (!list->isBaseValueList()) {
2786             RefPtr<CSSValue> firstValue = list;
2787             list = CSSValueList::createCommaSeparated();
2788             downcast<CSSValueList>(*list).append(firstValue.releaseNonNull());
2789         }
2790         downcast<CSSValueList>(*list).append(WTFMove(value));
2791     } else {
2792         // To conserve memory we don't actually wrap a single value in a list.
2793         list = WTFMove(value);
2794     }
2795 }
2796
2797 static RefPtr<CSSValue> consumeCommaSeparatedBackgroundComponent(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
2798 {
2799     RefPtr<CSSValue> result;
2800     do {
2801         RefPtr<CSSValue> value = consumeBackgroundComponent(property, range, context);
2802         if (!value)
2803             return nullptr;
2804         addBackgroundValue(result, value.releaseNonNull());
2805     } while (consumeCommaIncludingWhitespace(range));
2806     return result;
2807 }
2808
2809 #if ENABLE(CSS_GRID_LAYOUT)
2810 static RefPtr<CSSPrimitiveValue> consumeSelfPositionKeyword(CSSParserTokenRange& range)
2811 {
2812     CSSValueID id = range.peek().id();
2813     if (id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
2814         || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
2815         || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight)
2816         return consumeIdent(range);
2817     return nullptr;
2818 }
2819
2820 static RefPtr<CSSValue> consumeSelfPositionOverflowPosition(CSSParserTokenRange& range)
2821 {
2822     if (identMatches<CSSValueAuto, CSSValueNormal, CSSValueStretch, CSSValueBaseline, CSSValueLastBaseline>(range.peek().id()))
2823         return consumeIdent(range);
2824
2825     RefPtr<CSSPrimitiveValue> overflowPosition = consumeIdent<CSSValueUnsafe, CSSValueSafe>(range);
2826     RefPtr<CSSPrimitiveValue> selfPosition = consumeSelfPositionKeyword(range);
2827     if (!selfPosition)
2828         return nullptr;
2829     if (!overflowPosition)
2830         overflowPosition = consumeIdent<CSSValueUnsafe, CSSValueSafe>(range);
2831     if (overflowPosition)
2832         return createPrimitiveValuePair(selfPosition.releaseNonNull(), overflowPosition.releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce);
2833     return selfPosition;
2834 }
2835
2836 static RefPtr<CSSValue> consumeAlignItems(CSSParserTokenRange& range)
2837 {
2838     // align-items property does not allow the 'auto' value.
2839     if (identMatches<CSSValueAuto>(range.peek().id()))
2840         return nullptr;
2841     return consumeSelfPositionOverflowPosition(range);
2842 }
2843
2844 static RefPtr<CSSValue> consumeJustifyItems(CSSParserTokenRange& range)
2845 {
2846     CSSParserTokenRange rangeCopy = range;
2847     RefPtr<CSSPrimitiveValue> legacy = consumeIdent<CSSValueLegacy>(rangeCopy);
2848     RefPtr<CSSPrimitiveValue> positionKeyword = consumeIdent<CSSValueCenter, CSSValueLeft, CSSValueRight>(rangeCopy);
2849     if (!legacy)
2850         legacy = consumeIdent<CSSValueLegacy>(rangeCopy);
2851     if (legacy && positionKeyword) {
2852         range = rangeCopy;
2853         return createPrimitiveValuePair(legacy.releaseNonNull(), positionKeyword.releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce);
2854     }
2855     return consumeSelfPositionOverflowPosition(range);
2856 }
2857
2858 static RefPtr<CSSValue> consumeFitContent(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2859 {
2860     CSSParserTokenRange rangeCopy = range;
2861     CSSParserTokenRange args = consumeFunction(rangeCopy);
2862     RefPtr<CSSPrimitiveValue> length = consumeLengthOrPercent(args, cssParserMode, ValueRangeNonNegative, UnitlessQuirk::Allow);
2863     if (!length || !args.atEnd())
2864         return nullptr;
2865     range = rangeCopy;
2866     RefPtr<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueFitContent);
2867     result->append(length.releaseNonNull());
2868     return result;
2869 }
2870
2871 static RefPtr<CSSPrimitiveValue> consumeCustomIdentForGridLine(CSSParserTokenRange& range)
2872 {
2873     if (range.peek().id() == CSSValueAuto || range.peek().id() == CSSValueSpan)
2874         return nullptr;
2875     return consumeCustomIdent(range);
2876 }
2877
2878 static RefPtr<CSSValue> consumeGridLine(CSSParserTokenRange& range)
2879 {
2880     if (range.peek().id() == CSSValueAuto)
2881         return consumeIdent(range);
2882
2883     RefPtr<CSSPrimitiveValue> spanValue;
2884     RefPtr<CSSPrimitiveValue> gridLineName;
2885     RefPtr<CSSPrimitiveValue> numericValue = consumeInteger(range);
2886     if (numericValue) {
2887         gridLineName = consumeCustomIdentForGridLine(range);
2888         spanValue = consumeIdent<CSSValueSpan>(range);
2889     } else {
2890         spanValue = consumeIdent<CSSValueSpan>(range);
2891         if (spanValue) {
2892             numericValue = consumeInteger(range);
2893             gridLineName = consumeCustomIdentForGridLine(range);
2894             if (!numericValue)
2895                 numericValue = consumeInteger(range);
2896         } else {
2897             gridLineName = consumeCustomIdentForGridLine(range);
2898             if (gridLineName) {
2899                 numericValue = consumeInteger(range);
2900                 spanValue = consumeIdent<CSSValueSpan>(range);
2901                 if (!spanValue && !numericValue)
2902                     return gridLineName;
2903             } else {
2904                 return nullptr;
2905             }
2906         }
2907     }
2908
2909     if (spanValue && !numericValue && !gridLineName)
2910         return nullptr; // "span" keyword alone is invalid.
2911     if (spanValue && numericValue && numericValue->intValue() < 0)
2912         return nullptr; // Negative numbers are not allowed for span.
2913     if (numericValue && numericValue->intValue() == 0)
2914         return nullptr; // An <integer> value of zero makes the declaration invalid.
2915
2916     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
2917     if (spanValue)
2918         values->append(spanValue.releaseNonNull());
2919     if (numericValue)
2920         values->append(numericValue.releaseNonNull());
2921     if (gridLineName)
2922         values->append(gridLineName.releaseNonNull());
2923     ASSERT(values->length());
2924     return values;
2925 }
2926
2927 static bool isGridTrackFixedSized(const CSSPrimitiveValue& primitiveValue)
2928 {
2929     CSSValueID valueID = primitiveValue.valueID();
2930     if (valueID == CSSValueWebkitMinContent || valueID == CSSValueWebkitMaxContent || valueID == CSSValueAuto || primitiveValue.isFlex())
2931         return false;
2932
2933     return true;
2934 }
2935
2936 static bool isGridTrackFixedSized(const CSSValue& value)
2937 {
2938     if (value.isPrimitiveValue())
2939         return isGridTrackFixedSized(downcast<CSSPrimitiveValue>(value));
2940
2941     ASSERT(value.isFunctionValue());
2942     auto& function = downcast<CSSFunctionValue>(value);
2943     if (function.name() == CSSValueFitContent || function.arguments() == nullptr || function.arguments()->length() < 2)
2944         return false;
2945
2946     CSSValue* minPrimitiveValue = downcast<CSSPrimitiveValue>(function.arguments()->item(0));
2947     CSSValue* maxPrimitiveValue = downcast<CSSPrimitiveValue>(function.arguments()->item(1));
2948     return isGridTrackFixedSized(*minPrimitiveValue) || isGridTrackFixedSized(*maxPrimitiveValue);
2949 }
2950
2951 static Vector<String> parseGridTemplateAreasColumnNames(const String& gridRowNames)
2952 {
2953     ASSERT(!gridRowNames.isEmpty());
2954     Vector<String> columnNames;
2955     // Using StringImpl to avoid checks and indirection in every call to String::operator[].
2956     StringImpl& text = *gridRowNames.impl();
2957
2958     StringBuilder areaName;
2959     for (unsigned i = 0; i < text.length(); ++i) {
2960         if (isCSSSpace(text[i])) {
2961             if (!areaName.isEmpty()) {
2962                 columnNames.append(areaName.toString());
2963                 areaName.clear();
2964             }
2965             continue;
2966         }
2967         if (text[i] == '.') {
2968             if (areaName == ".")
2969                 continue;
2970             if (!areaName.isEmpty()) {
2971                 columnNames.append(areaName.toString());
2972                 areaName.clear();
2973             }
2974         } else {
2975             if (!isNameCodePoint(text[i]))
2976                 return Vector<String>();
2977             if (areaName == ".") {
2978                 columnNames.append(areaName.toString());
2979                 areaName.clear();
2980             }
2981         }
2982
2983         areaName.append(text[i]);
2984     }
2985
2986     if (!areaName.isEmpty())
2987         columnNames.append(areaName.toString());
2988
2989     return columnNames;
2990 }
2991
2992 static bool parseGridTemplateAreasRow(const String& gridRowNames, NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount)
2993 {
2994     if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace())
2995         return false;
2996
2997     Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames);
2998     if (rowCount == 0) {
2999         columnCount = columnNames.size();
3000         if (columnCount == 0)
3001             return false;
3002     } else if (columnCount != columnNames.size()) {
3003         // The declaration is invalid if all the rows don't have the number of columns.
3004         return false;
3005     }
3006
3007     for (size_t currentColumn = 0; currentColumn < columnCount; ++currentColumn) {
3008         const String& gridAreaName = columnNames[currentColumn];
3009
3010         // Unamed areas are always valid (we consider them to be 1x1).
3011         if (gridAreaName == ".")
3012             continue;
3013
3014         size_t lookAheadColumn = currentColumn + 1;
3015         while (lookAheadColumn < columnCount && columnNames[lookAheadColumn] == gridAreaName)
3016             lookAheadColumn++;
3017
3018         NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
3019         if (gridAreaIt == gridAreaMap.end()) {
3020             gridAreaMap.add(gridAreaName, GridArea(GridSpan::translatedDefiniteGridSpan(rowCount, rowCount + 1), GridSpan::translatedDefiniteGridSpan(currentColumn, lookAheadColumn)));
3021         } else {
3022             GridArea& gridArea = gridAreaIt->value;
3023
3024             // The following checks test that the grid area is a single filled-in rectangle.
3025             // 1. The new row is adjacent to the previously parsed row.
3026             if (rowCount != gridArea.rows.endLine())
3027                 return false;
3028
3029             // 2. The new area starts at the same position as the previously parsed area.
3030             if (currentColumn != gridArea.columns.startLine())
3031                 return false;
3032
3033             // 3. The new area ends at the same position as the previously parsed area.
3034             if (lookAheadColumn != gridArea.columns.endLine())
3035                 return false;
3036
3037             gridArea.rows = GridSpan::translatedDefiniteGridSpan(gridArea.rows.startLine(), gridArea.rows.endLine() + 1);
3038         }
3039         currentColumn = lookAheadColumn - 1;
3040     }
3041
3042     return true;
3043 }
3044
3045 static RefPtr<CSSPrimitiveValue> consumeGridBreadth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
3046 {
3047     const CSSParserToken& token = range.peek();
3048     if (identMatches<CSSValueWebkitMinContent, CSSValueWebkitMaxContent, CSSValueAuto>(token.id()))
3049         return consumeIdent(range);
3050     if (token.type() == DimensionToken && token.unitType() == CSSPrimitiveValue::UnitTypes::CSS_FR) {
3051         if (range.peek().numericValue() < 0)
3052             return nullptr;
3053         return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitTypes::CSS_FR);
3054     }
3055     return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative, UnitlessQuirk::Allow);
3056 }
3057
3058 static RefPtr<CSSValue> consumeGridTrackSize(CSSParserTokenRange& range, CSSParserMode cssParserMode)
3059 {
3060     const CSSParserToken& token = range.peek();
3061     if (identMatches<CSSValueAuto>(token.id()))
3062         return consumeIdent(range);
3063
3064     if (token.functionId() == CSSValueMinmax) {
3065         CSSParserTokenRange rangeCopy = range;
3066         CSSParserTokenRange args = consumeFunction(rangeCopy);
3067         RefPtr<CSSPrimitiveValue> minTrackBreadth = consumeGridBreadth(args, cssParserMode);
3068         if (!minTrackBreadth || minTrackBreadth->isFlex() || !consumeCommaIncludingWhitespace(args))
3069             return nullptr;
3070         RefPtr<CSSPrimitiveValue> maxTrackBreadth = consumeGridBreadth(args, cssParserMode);
3071         if (!maxTrackBreadth || !args.atEnd())
3072             return nullptr;
3073         range = rangeCopy;
3074         RefPtr<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueMinmax);
3075         result->append(minTrackBreadth.releaseNonNull());
3076         result->append(maxTrackBreadth.releaseNonNull());
3077         return result;
3078     }
3079
3080     if (token.functionId() == CSSValueFitContent)
3081         return consumeFitContent(range, cssParserMode);
3082
3083     return consumeGridBreadth(range, cssParserMode);
3084 }
3085
3086 // Appends to the passed in CSSGridLineNamesValue if any, otherwise creates a new one.
3087 static RefPtr<CSSGridLineNamesValue> consumeGridLineNames(CSSParserTokenRange& range, CSSGridLineNamesValue* lineNames = nullptr)
3088 {
3089     CSSParserTokenRange rangeCopy = range;
3090     if (rangeCopy.consumeIncludingWhitespace().type() != LeftBracketToken)
3091         return nullptr;
3092     
3093     RefPtr<CSSGridLineNamesValue> result = lineNames;
3094     if (!result)
3095         result = CSSGridLineNamesValue::create();
3096     while (RefPtr<CSSPrimitiveValue> lineName = consumeCustomIdentForGridLine(rangeCopy))
3097         result->append(lineName.releaseNonNull());
3098     if (rangeCopy.consumeIncludingWhitespace().type() != RightBracketToken)
3099         return nullptr;
3100     range = rangeCopy;
3101     return result;
3102 }
3103
3104 static bool consumeGridTrackRepeatFunction(CSSParserTokenRange& range, CSSParserMode cssParserMode, CSSValueList& list, bool& isAutoRepeat, bool& allTracksAreFixedSized)
3105 {
3106     CSSParserTokenRange args = consumeFunction(range);
3107     // The number of repetitions for <auto-repeat> is not important at parsing level
3108     // because it will be computed later, let's set it to 1.
3109     size_t repetitions = 1;
3110     isAutoRepeat = identMatches<CSSValueAutoFill, CSSValueAutoFit>(args.peek().id());
3111     RefPtr<CSSValueList> repeatedValues;
3112     if (isAutoRepeat)
3113         repeatedValues = CSSGridAutoRepeatValue::create(args.consumeIncludingWhitespace().id());
3114     else {
3115         // FIXME: a consumeIntegerRaw would be more efficient here.
3116         RefPtr<CSSPrimitiveValue> repetition = consumePositiveInteger(args);
3117         if (!repetition)
3118             return false;
3119         repetitions = clampTo<size_t>(repetition->doubleValue(), 0, kGridMaxTracks);
3120         repeatedValues = CSSValueList::createSpaceSeparated();
3121     }
3122     if (!consumeCommaIncludingWhitespace(args))
3123         return false;
3124     RefPtr<CSSGridLineNamesValue> lineNames = consumeGridLineNames(args);
3125     if (lineNames)
3126         repeatedValues->append(lineNames.releaseNonNull());
3127
3128     size_t numberOfTracks = 0;
3129     while (!args.atEnd()) {
3130         RefPtr<CSSValue> trackSize = consumeGridTrackSize(args, cssParserMode);
3131         if (!trackSize)
3132             return false;
3133         if (allTracksAreFixedSized)
3134             allTracksAreFixedSized = isGridTrackFixedSized(*trackSize);
3135         repeatedValues->append(trackSize.releaseNonNull());
3136         ++numberOfTracks;
3137         lineNames = consumeGridLineNames(args);
3138         if (lineNames)
3139             repeatedValues->append(lineNames.releaseNonNull());
3140     }
3141     // We should have found at least one <track-size> or else it is not a valid <track-list>.
3142     if (!numberOfTracks)
3143         return false;
3144
3145     if (isAutoRepeat)
3146         list.append(repeatedValues.releaseNonNull());
3147     else {
3148         // We clamp the repetitions to a multiple of the repeat() track list's size, while staying below the max grid size.
3149         repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks);
3150         for (size_t i = 0; i < repetitions; ++i) {
3151             for (size_t j = 0; j < repeatedValues->length(); ++j)
3152                 list.append(*repeatedValues->itemWithoutBoundsCheck(j));
3153         }
3154     }
3155     return true;
3156 }
3157
3158 enum TrackListType { GridTemplate, GridTemplateNoRepeat, GridAuto };
3159
3160 static RefPtr<CSSValue> consumeGridTrackList(CSSParserTokenRange& range, CSSParserMode cssParserMode, TrackListType trackListType)
3161 {
3162     bool allowGridLineNames = trackListType != GridAuto;
3163     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
3164     RefPtr<CSSGridLineNamesValue> lineNames = consumeGridLineNames(range);
3165     if (lineNames) {
3166         if (!allowGridLineNames)
3167             return nullptr;
3168         values->append(lineNames.releaseNonNull());
3169     }
3170     
3171     bool allowRepeat = trackListType == GridTemplate;
3172     bool seenAutoRepeat = false;
3173     bool allTracksAreFixedSized = true;
3174     do {
3175         bool isAutoRepeat;
3176         if (range.peek().functionId() == CSSValueRepeat) {
3177             if (!allowRepeat)
3178                 return nullptr;
3179             if (!consumeGridTrackRepeatFunction(range, cssParserMode, *values, isAutoRepeat, allTracksAreFixedSized))
3180                 return nullptr;
3181             if (isAutoRepeat && seenAutoRepeat)
3182                 return nullptr;
3183             seenAutoRepeat = seenAutoRepeat || isAutoRepeat;
3184         } else if (RefPtr<CSSValue> value = consumeGridTrackSize(range, cssParserMode)) {
3185             if (allTracksAreFixedSized)
3186                 allTracksAreFixedSized = isGridTrackFixedSized(*value);
3187             values->append(value.releaseNonNull());
3188         } else {
3189             return nullptr;
3190         }
3191         if (seenAutoRepeat && !allTracksAreFixedSized)
3192             return nullptr;
3193         lineNames = consumeGridLineNames(range);
3194         if (lineNames) {
3195             if (!allowGridLineNames)
3196                 return nullptr;
3197             values->append(lineNames.releaseNonNull());
3198         }
3199     } while (!range.atEnd() && range.peek().type() != DelimiterToken);
3200     return values;
3201 }
3202
3203 static RefPtr<CSSValue> consumeGridTemplatesRowsOrColumns(CSSParserTokenRange& range, CSSParserMode cssParserMode)
3204 {
3205     if (range.peek().id() == CSSValueNone)
3206         return consumeIdent(range);
3207     return consumeGridTrackList(range, cssParserMode, GridTemplate);
3208 }
3209
3210 static RefPtr<CSSValue> consumeGridTemplateAreas(CSSParserTokenRange& range)
3211 {
3212     if (range.peek().id() == CSSValueNone)
3213         return consumeIdent(range);
3214
3215     NamedGridAreaMap gridAreaMap;
3216     size_t rowCount = 0;
3217     size_t columnCount = 0;
3218
3219     while (range.peek().type() == StringToken) {
3220         if (!parseGridTemplateAreasRow(range.consumeIncludingWhitespace().value().toString(), gridAreaMap, rowCount, columnCount))
3221             return nullptr;
3222         ++rowCount;
3223     }
3224
3225     if (rowCount == 0)
3226         return nullptr;
3227     ASSERT(columnCount);
3228     return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
3229 }
3230 #endif
3231
3232 #if ENABLE(CSS_REGIONS)
3233 static RefPtr<CSSValue> consumeFlowProperty(CSSParserTokenRange& range)
3234 {
3235     RefPtr<CSSValue> result;
3236     if (range.peek().id() == CSSValueNone)
3237         result = consumeIdent(range);
3238     else
3239         result = consumeCustomIdent(range);
3240     return result;
3241 }
3242 #endif
3243
3244 static RefPtr<CSSValue> consumeLineBoxContain(CSSParserTokenRange& range)
3245 {
3246     if (range.peek().id() == CSSValueNone)
3247         return consumeIdent(range);
3248
3249     LineBoxContain lineBoxContain = LineBoxContainNone;
3250     
3251     while (range.peek().type() == IdentToken) {
3252         auto id = range.peek().id();
3253         if (id == CSSValueBlock) {
3254             if (lineBoxContain & LineBoxContainBlock)
3255                 return nullptr;
3256             lineBoxContain |= LineBoxContainBlock;
3257         } else if (id == CSSValueInline) {
3258             if (lineBoxContain & LineBoxContainInline)
3259                 return nullptr;
3260             lineBoxContain |= LineBoxContainInline;
3261         } else if (id == CSSValueFont) {
3262             if (lineBoxContain & LineBoxContainFont)
3263                 return nullptr;
3264             lineBoxContain |= LineBoxContainFont;
3265         } else if (id == CSSValueGlyphs) {
3266             if (lineBoxContain & LineBoxContainGlyphs)
3267                 return nullptr;
3268             lineBoxContain |= LineBoxContainGlyphs;
3269         } else if (id == CSSValueReplaced) {
3270             if (lineBoxContain & LineBoxContainReplaced)
3271                 return nullptr;
3272             lineBoxContain |= LineBoxContainReplaced;
3273         } else if (id == CSSValueInlineBox) {
3274             if (lineBoxContain & LineBoxContainInlineBox)
3275                 return nullptr;
3276             lineBoxContain |= LineBoxContainInlineBox;
3277         } else if (id == CSSValueInitialLetter) {
3278             if (lineBoxContain & LineBoxContainInitialLetter)
3279                 return nullptr;
3280             lineBoxContain |= LineBoxContainInitialLetter;
3281         } else
3282             return nullptr;
3283         range.consumeIncludingWhitespace();
3284     }
3285     
3286     if (!lineBoxContain)
3287         return nullptr;
3288     
3289     return CSSLineBoxContainValue::create(lineBoxContain);
3290 }
3291
3292 static RefPtr<CSSValue> consumeLineGrid(CSSParserTokenRange& range)
3293 {
3294     if (range.peek().id() == CSSValueNone)
3295         return consumeIdent(range);
3296     return consumeCustomIdent(range);
3297 }
3298
3299 static RefPtr<CSSValue> consumeInitialLetter(CSSParserTokenRange& range)
3300 {
3301     RefPtr<CSSValue> ident = consumeIdent<CSSValueNormal>(range);
3302     if (ident)
3303         return ident;
3304     
3305     RefPtr<CSSPrimitiveValue> height = consumeNumber(range, ValueRangeNonNegative);
3306     if (!height)
3307         return nullptr;
3308     
3309     RefPtr<CSSPrimitiveValue> position;
3310     if (!range.atEnd()) {
3311         position = consumeNumber(range, ValueRangeNonNegative);
3312         if (!position || !range.atEnd())
3313             return nullptr;
3314     } else
3315         position = height.copyRef();
3316     
3317     return createPrimitiveValuePair(position.releaseNonNull(), WTFMove(height));
3318 }
3319
3320 static RefPtr<CSSValue> consumeHangingPunctuation(CSSParserTokenRange& range)
3321 {
3322     if (range.peek().id() == CSSValueNone)
3323         return consumeIdent(range);
3324     
3325     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
3326     std::bitset<numCSSValueKeywords> seenValues;
3327
3328     bool seenForceEnd = false;
3329     bool seenAllowEnd = false;
3330     bool seenFirst = false;
3331     bool seenLast = false;
3332
3333     while (!range.atEnd()) {
3334         CSSValueID valueID = range.peek().id();
3335         if ((valueID == CSSValueFirst && seenFirst)
3336             || (valueID == CSSValueLast && seenLast)
3337             || (valueID == CSSValueAllowEnd && (seenAllowEnd || seenForceEnd))
3338             || (valueID == CSSValueForceEnd && (seenAllowEnd || seenForceEnd)))
3339             return nullptr;
3340         RefPtr<CSSValue> ident = consumeIdent<CSSValueAllowEnd, CSSValueForceEnd, CSSValueFirst, CSSValueLast>(range);
3341         if (!ident)
3342             return nullptr;
3343         switch (valueID) {
3344         case CSSValueAllowEnd:
3345             seenAllowEnd = true;
3346             break;
3347         case CSSValueForceEnd:
3348             seenForceEnd = true;
3349             break;
3350         case CSSValueFirst:
3351             seenFirst = true;
3352             break;
3353         case CSSValueLast:
3354             seenLast = true;
3355             break;
3356         default:
3357             break;
3358         }
3359         list->append(ident.releaseNonNull());
3360     }
3361     
3362     return list->length() ? list : nullptr;
3363 }
3364
3365 static RefPtr<CSSValue> consumeWebkitMarqueeIncrement(CSSParserTokenRange& range, CSSParserMode cssParserMode)
3366 {
3367     if (range.peek().type() == IdentToken)
3368         return consumeIdent<CSSValueSmall, CSSValueMedium, CSSValueLarge>(range);
3369     return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
3370 }
3371
3372 static RefPtr<CSSValue> consumeWebkitMarqueeRepetition(CSSParserTokenRange& range)
3373 {
3374     if (range.peek().type() == IdentToken)
3375         return consumeIdent<CSSValueInfinite>(range);
3376     return consumeNumber(range, ValueRangeNonNegative);
3377 }
3378
3379 static RefPtr<CSSValue> consumeWebkitMarqueeSpeed(CSSParserTokenRange& range, CSSParserMode cssParserMode)
3380 {
3381     if (range.peek().type() == IdentToken)
3382         return consumeIdent<CSSValueSlow, CSSValueNormal, CSSValueFast>(range);
3383     return consumeTime(range, cssParserMode, ValueRangeNonNegative, UnitlessQuirk::Allow);
3384 }
3385
3386 static RefPtr<CSSValue> consumeAlt(CSSParserTokenRange& range, const CSSParserContext& context)
3387 {
3388     if (range.peek().type() == StringToken)
3389         return consumeString(range);
3390     
3391     if (range.peek().functionId() != CSSValueAttr)
3392         return nullptr;
3393     
3394     return consumeAttr(consumeFunction(range), context);
3395 }
3396
3397 static RefPtr<CSSValue> consumeWebkitAspectRatio(CSSParserTokenRange& range)
3398 {
3399     if (range.peek().type() == IdentToken)
3400         return consumeIdent<CSSValueAuto, CSSValueFromDimensions, CSSValueFromIntrinsic>(range);
3401     
3402     RefPtr<CSSPrimitiveValue> leftValue = consumeNumber(range, ValueRangeNonNegative);
3403     if (!leftValue || range.atEnd() || !consumeSlashIncludingWhitespace(range))
3404         return nullptr;
3405     RefPtr<CSSPrimitiveValue> rightValue = consumeNumber(range, ValueRangeNonNegative);
3406     if (!rightValue)
3407         return nullptr;
3408     
3409     return CSSAspectRatioValue::create(leftValue->floatValue(), rightValue->floatValue());
3410 }
3411
3412 static RefPtr<CSSValue> consumeTextEmphasisPosition(CSSParserTokenRange& range)
3413 {
3414     bool foundOverOrUnder = false;
3415     CSSValueID overUnderValueID = CSSValueOver;
3416     bool foundLeftOrRight = false;
3417     CSSValueID leftRightValueID = CSSValueRight;
3418     while (!range.atEnd()) {
3419         switch (range.peek().id()) {
3420         case CSSValueOver:
3421             if (foundOverOrUnder)
3422                 return nullptr;
3423             foundOverOrUnder = true;
3424             overUnderValueID = CSSValueOver;
3425             break;
3426         case CSSValueUnder:
3427             if (foundOverOrUnder)
3428                 return nullptr;
3429             foundOverOrUnder = true;
3430             overUnderValueID = CSSValueUnder;
3431             break;
3432         case CSSValueLeft:
3433             if (foundLeftOrRight)
3434                 return nullptr;
3435             foundLeftOrRight = true;
3436             leftRightValueID = CSSValueLeft;
3437             break;
3438         case CSSValueRight:
3439             if (foundLeftOrRight)
3440                 return nullptr;
3441             foundLeftOrRight = true;
3442             leftRightValueID = CSSValueRight;
3443             break;
3444         default:
3445             return nullptr;
3446         }
3447         
3448         range.consumeIncludingWhitespace();
3449     }
3450     if (!foundOverOrUnder)
3451         return nullptr;
3452     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
3453     list->append(CSSValuePool::singleton().createIdentifierValue(overUnderValueID));
3454     if (foundLeftOrRight)
3455         list->append(CSSValuePool::singleton().createIdentifierValue(leftRightValueID));
3456     return list;
3457 }
3458     
3459 RefPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID property, CSSPropertyID currentShorthand)
3460 {
3461     if (CSSParserFastPaths::isKeywordPropertyID(property)) {
3462         if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(property, m_range.peek().id(), m_context.mode))
3463             return nullptr;
3464         return consumeIdent(m_range);
3465     }
3466     switch (property) {
3467     case CSSPropertyWillChange:
3468         return consumeWillChange(m_range);
3469     case CSSPropertyPage:
3470         return consumePage(m_range);
3471     case CSSPropertyQuotes:
3472         return consumeQuotes(m_range);
3473     case CSSPropertyFontVariantCaps:
3474         return consumeFontVariantCaps(m_range);
3475     case CSSPropertyFontVariantLigatures:
3476         return consumeFontVariantLigatures(m_range);
3477     case CSSPropertyFontVariantNumeric:
3478         return consumeFontVariantNumeric(m_range);
3479     case CSSPropertyFontFeatureSettings:
3480         return consumeFontFeatureSettings(m_range);
3481     case CSSPropertyFontFamily:
3482         return consumeFontFamily(m_range);
3483     case CSSPropertyFontWeight:
3484         return consumeFontWeight(m_range);
3485     case CSSPropertyFontSynthesis:
3486         return consumeFontSynthesis(m_range);
3487 #if ENABLE(VARIATION_FONTS)
3488     case CSSPropertyFontVariationSettings:
3489         if (m_context.variationFontsEnabled)
3490             return consumeFontVariationSettings(m_range);
3491         return nullptr;
3492 #endif
3493     case CSSPropertyLetterSpacing:
3494         return consumeLetterSpacing(m_range, m_context.mode);
3495     case CSSPropertyWordSpacing:
3496         return consumeWordSpacing(m_range, m_context.mode);
3497     case CSSPropertyTabSize:
3498         return consumeTabSize(m_range, m_context.mode);
3499 #if ENABLE(TEXT_AUTOSIZING)
3500     case CSSPropertyWebkitTextSizeAdjust:
3501         // FIXME: Support toggling the validation of this property via a runtime setting that is independent of
3502         // whether isTextAutosizingEnabled() is true. We want to enable this property on iOS, when simulating
3503         // a iOS device in Safari's responsive design mode and when optionally enabled in DRT/WTR. Otherwise,
3504         // this property should be disabled by default.
3505 #if !PLATFORM(IOS)
3506         if (!m_context.textAutosizingEnabled)
3507             return nullptr;
3508 #endif
3509         return consumeTextSizeAdjust(m_range, m_context.mode);
3510 #endif
3511     case CSSPropertyFontSize:
3512         return consumeFontSize(m_range, m_context.mode, UnitlessQuirk::Allow);
3513     case CSSPropertyLineHeight:
3514         return consumeLineHeight(m_range, m_context.mode);
3515     case CSSPropertyWebkitBorderHorizontalSpacing:
3516     case CSSPropertyWebkitBorderVerticalSpacing:
3517         return consumeLength(m_range, m_context.mode, ValueRangeNonNegative);
3518     case CSSPropertyCounterIncrement:
3519     case CSSPropertyCounterReset:
3520         return consumeCounter(m_range, property == CSSPropertyCounterIncrement ? 1 : 0);
3521     case CSSPropertySize:
3522         return consumeSize(m_range, m_context.mode);
3523     case CSSPropertyTextIndent:
3524         return consumeTextIndent(m_range, m_context.mode);
3525     case CSSPropertyMaxWidth:
3526     case CSSPropertyMaxHeight:
3527         return consumeMaxWidthOrHeight(m_range, m_context, UnitlessQuirk::Allow);
3528     case CSSPropertyWebkitMaxLogicalWidth:
3529     case CSSPropertyWebkitMaxLogicalHeight:
3530         return consumeMaxWidthOrHeight(m_range, m_context);
3531     case CSSPropertyMinWidth:
3532     case CSSPropertyMinHeight:
3533     case CSSPropertyWidth:
3534     case CSSPropertyHeight:
3535         return consumeWidthOrHeight(m_range, m_context, UnitlessQuirk::Allow);
3536     case CSSPropertyWebkitMinLogicalWidth:
3537     case CSSPropertyWebkitMinLogicalHeight:
3538     case CSSPropertyWebkitLogicalWidth:
3539     case CSSPropertyWebkitLogicalHeight:
3540         return consumeWidthOrHeight(m_range, m_context);
3541     case CSSPropertyMarginTop:
3542     case CSSPropertyMarginRight:
3543     case CSSPropertyMarginBottom:
3544     case CSSPropertyMarginLeft:
3545     case CSSPropertyBottom:
3546     case CSSPropertyLeft:
3547     case CSSPropertyRight:
3548     case CSSPropertyTop:
3549         return consumeMarginOrOffset(m_range, m_context.mode, UnitlessQuirk::Allow);
3550     case CSSPropertyWebkitMarginStart:
3551     case CSSPropertyWebkitMarginEnd:
3552     case CSSPropertyWebkitMarginBefore:
3553     case CSSPropertyWebkitMarginAfter:
3554         return consumeMarginOrOffset(m_range, m_context.mode, UnitlessQuirk::Forbid);
3555     case CSSPropertyPaddingTop:
3556     case CSSPropertyPaddingRight:
3557     case CSSPropertyPaddingBottom:
3558     case CSSPropertyPaddingLeft:
3559         return consumeLengthOrPercent(m_range, m_context.mode, ValueRangeNonNegative, UnitlessQuirk::Allow);
3560     case CSSPropertyWebkitPaddingStart:
3561     case CSSPropertyWebkitPaddingEnd:
3562     case CSSPropertyWebkitPaddingBefore:
3563     case CSSPropertyWebkitPaddingAfter:
3564         return consumeLengthOrPercent(m_range, m_context.mode, ValueRangeNonNegative, UnitlessQuirk::Forbid);
3565     case CSSPropertyClip:
3566         return consumeClip(m_range, m_context.mode);
3567 #if ENABLE(TOUCH_EVENTS)
3568     case CSSPropertyTouchAction:
3569         return consumeTouchAction(m_range);
3570 #endif
3571     case CSSPropertyObjectPosition:
3572         return consumePosition(m_range, m_context.mode, UnitlessQuirk::Forbid);
3573     case CSSPropertyWebkitLineClamp:
3574         return consumeLineClamp(m_range);
3575     case CSSPropertyWebkitFontSizeDelta:
3576         return consumeLength(m_range, m_context.mode, ValueRangeAll, UnitlessQuirk::Allow);
3577     case CSSPropertyWebkitHyphenateCharacter:
3578     case CSSPropertyWebkitLocale:
3579         return consumeLocale(m_range);
3580     case CSSPropertyWebkitHyphenateLimitBefore:
3581     case CSSPropertyWebkitHyphenateLimitAfter:
3582         return consumeHyphenateLimit(m_range, CSSValueAuto);
3583     case CSSPropertyWebkitHyphenateLimitLines:
3584         return consumeHyphenateLimit(m_range, CSSValueNoLimit);
3585     case CSSPropertyColumnWidth:
3586         return consumeColumnWidth(m_range);
3587     case CSSPropertyColumnCount:
3588         return consumeColumnCount(m_range);
3589     case CSSPropertyColumnGap:
3590         return consumeColumnGap(m_range, m_context.mode);
3591     case CSSPropertyColumnSpan:
3592         return consumeColumnSpan(m_range);
3593     case CSSPropertyZoom:
3594         return consumeZoom(m_range, m_context);
3595     case CSSPropertyAnimationDelay:
3596     case CSSPropertyTransitionDelay:
3597     case CSSPropertyAnimationDirection:
3598     case CSSPropertyAnimationDuration:
3599     case CSSPropertyTransitionDuration:
3600     case CSSPropertyAnimationFillMode:
3601     case CSSPropertyAnimationIterationCount:
3602     case CSSPropertyAnimationName:
3603     case CSSPropertyAnimationPlayState:
3604     case CSSPropertyTransitionProperty:
3605     case CSSPropertyAnimationTimingFunction:
3606     case CSSPropertyTransitionTimingFunction:
3607 #if ENABLE(CSS_ANIMATIONS_LEVEL_2)
3608     case CSSPropertyWebkitAnimationTrigger:
3609 #endif
3610         return consumeAnimationPropertyList(property, m_range, m_context);
3611 #if ENABLE(CSS_GRID_LAYOUT)
3612     case CSSPropertyGridColumnGap:
3613     case CSSPropertyGridRowGap:
3614         return consumeLength(m_range, m_context.mode, ValueRangeNonNegative);
3615 #endif
3616     case CSSPropertyShapeMargin:
3617         return consumeLengthOrPercent(m_range, m_context.mode, ValueRangeNonNegative);
3618     case CSSPropertyShapeImageThreshold:
3619         return consumeNumber(m_range, ValueRangeAll);
3620     case CSSPropertyWebkitBoxOrdinalGroup:
3621     case CSSPropertyOrphans:
3622     case CSSPropertyWidows:
3623         return consumePositiveInteger(m_range);
3624     case CSSPropertyWebkitTextDecorationColor:
3625         return consumeColor(m_range, m_context.mode);
3626     case CSSPropertyWebkitTextDecorationSkip:
3627         return consumeTextDecorationSkip(m_range);
3628     case CSSPropertyWebkitTextStrokeWidth:
3629         return consumeTextStrokeWidth(m_range, m_context.mode);
3630     case CSSPropertyWebkitTextFillColor:
3631 #if ENABLE(TOUCH_EVENTS)
3632     case CSSPropertyWebkitTapHighlightColor:
3633 #endif
3634     case CSSPropertyWebkitTextEmphasisColor:
3635     case CSSPropertyWebkitBorderStartColor:
3636     case CSSPropertyWebkitBorderEndColor:
3637     case CSSPropertyWebkitBorderBeforeColor:
3638     case CSSPropertyWebkitBorderAfterColor:
3639     case CSSPropertyWebkitTextStrokeColor:
3640     case CSSPropertyStopColor:
3641     case CSSPropertyFloodColor:
3642     case CSSPropertyLightingColor:
3643     case CSSPropertyColumnRuleColor:
3644         return consumeColor(m_range, m_context.mode);
3645     case CSSPropertyColor:
3646     case CSSPropertyBackgroundColor:
3647         return consumeColor(m_range, m_context.mode, inQuirksMode());
3648     case CSSPropertyWebkitBorderStartWidth:
3649     case CSSPropertyWebkitBorderEndWidth:
3650     case CSSPropertyWebkitBorderBeforeWidth:
3651     case CSSPropertyWebkitBorderAfterWidth:
3652         return consumeBorderWidth(m_range, m_context.mode, UnitlessQuirk::Forbid);
3653     case CSSPropertyBorderBottomColor:
3654     case CSSPropertyBorderLeftColor:
3655     case CSSPropertyBorderRightColor:
3656     case CSSPropertyBorderTopColor: {
3657         bool allowQuirkyColors = inQuirksMode()
3658             && (currentShorthand == CSSPropertyInvalid || currentShorthand == CSSPropertyBorderColor);
3659         return consumeColor(m_range, m_context.mode, allowQuirkyColors);
3660     }
3661     case CSSPropertyBorderBottomWidth:
3662     case CSSPropertyBorderLeftWidth:
3663     case CSSPropertyBorderRightWidth:
3664     case CSSPropertyBorderTopWidth: {
3665         bool allowQuirkyLengths = inQuirksMode()
3666             && (currentShorthand == CSSPropertyInvalid || currentShorthand == CSSPropertyBorderWidth);
3667         UnitlessQuirk unitless = allowQuirkyLengths ? UnitlessQuirk::Allow : UnitlessQuirk::Forbid;
3668         return consumeBorderWidth(m_range, m_context.mode, unitless);
3669     }
3670     case CSSPropertyZIndex:
3671         return consumeZIndex(m_range);
3672     case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
3673     case CSSPropertyBoxShadow:
3674     case CSSPropertyWebkitBoxShadow:
3675     case CSSPropertyWebkitSvgShadow:
3676         return consumeShadow(m_range, m_context.mode, property == CSSPropertyBoxShadow || property == CSSPropertyWebkitBoxShadow);
3677     case CSSPropertyFilter:
3678 #if ENABLE(FILTERS_LEVEL_2)
3679     case CSSPropertyWebkitBackdropFilter:
3680 #endif
3681         return consumeFilter(m_range, m_context);
3682     case CSSPropertyTextDecoration:
3683     case CSSPropertyWebkitTextDecorationsInEffect:
3684     case CSSPropertyWebkitTextDecorationLine:
3685         return consumeTextDecorationLine(m_range);
3686     case CSSPropertyWebkitTextEmphasisStyle:
3687         return consumeTextEmphasisStyle(m_range);
3688     case CSSPropertyOutlineColor:
3689         return consumeOutlineColor(m_range, m_context.mode);
3690     case CSSPropertyOutlineOffset:
3691         return consumeLength(m_range, m_context.mode, ValueRangeAll);
3692     case CSSPropertyOutlineWidth:
3693         return consumeLineWidth(m_range, m_context.mode, UnitlessQuirk::Forbid);
3694     case CSSPropertyTransform:
3695         return consumeTransform(m_range, m_context.mode);
3696     case CSSPropertyTransformOriginX:
3697     case CSSPropertyPerspectiveOriginX:
3698         return consumePositionX(m_range, m_context.mode);
3699     case CSSPropertyTransformOriginY:
3700     case CSSPropertyPerspectiveOriginY:
3701         return consumePositionY(m_range, m_context.mode);
3702     case CSSPropertyTransformOriginZ:
3703         return consumeLength(m_range, m_context.mode, ValueRangeAll);
3704     case CSSPropertyFill:
3705     case CSSPropertyStroke:
3706         return consumePaintStroke(m_range, m_context.mode);
3707     case CSSPropertyPaintOrder:
3708         return consumePaintOrder(m_range);
3709     case CSSPropertyMarkerStart:
3710     case CSSPropertyMarkerMid:
3711     case CSSPropertyMarkerEnd:
3712     case CSSPropertyClipPath:
3713     case CSSPropertyMask:
3714         return consumeNoneOrURI(m_range);
3715     case CSSPropertyFlexBasis:
3716         return consumeFlexBasis(m_range, m_context.mode);
3717     case CSSPropertyFlexGrow:
3718     case CSSPropertyFlexShrink:
3719         return consumeNumber(m_range, ValueRangeNonNegative);
3720     case CSSPropertyStrokeDasharray:
3721         return consumeStrokeDasharray(m_range);
3722     case CSSPropertyColumnRuleWidth:
3723         return consumeColumnRuleWidth(m_range, m_context.mode);
3724     case CSSPropertyStrokeOpacity:
3725     case CSSPropertyFillOpacity:
3726     case CSSPropertyStopOpacity:
3727     case CSSPropertyFloodOpacity:
3728     case CSSPropertyOpacity:
3729     case CSSPropertyWebkitBoxFlex:
3730         return consumeNumber(m_range, ValueRangeAll);
3731     case CSSPropertyBaselineShift:
3732         return consumeBaselineShift(m_range);
3733     case CSSPropertyStrokeMiterlimit:
3734         return consumeNumber(m_range, ValueRangeNonNegative);
3735     case CSSPropertyStrokeWidth:
3736     case CSSPropertyStrokeDashoffset:
3737     case CSSPropertyCx:
3738     case CSSPropertyCy:
3739     case CSSPropertyX:
3740     case CSSPropertyY:
3741     case CSSPropertyR:
3742         return consumeLengthOrPercent(m_range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
3743     case CSSPropertyRx:
3744     case CSSPropertyRy:
3745         return consumeRxOrRy(m_range);
3746     case CSSPropertyCursor:
3747         return consumeCursor(m_range, m_context, inQuirksMode());
3748     case CSSPropertyContent:
3749         return consumeContent(m_range, m_context);
3750     case CSSPropertyListStyleImage:
3751     case CSSPropertyBorderImageSource:
3752     case CSSPropertyWebkitMaskBoxImageSource:
3753         return consumeImageOrNone(m_range, m_context);
3754     case CSSPropertyPerspective:
3755         return consumePerspective(m_range, m_context.mode);
3756 #if ENABLE(CSS_SCROLL_SNAP)
3757     case CSSPropertyWebkitScrollSnapCoordinate:
3758         return consumeScrollSnapCoordinate(m_range, m_context.mode);
3759     case CSSPropertyWebkitScrollSnapDestination:
3760         return consumeScrollSnapDestination(m_range, m_context.mode);
3761     case CSSPropertyWebkitScrollSnapPointsX:
3762     case CSSPropertyWebkitScrollSnapPointsY:
3763         return consumeScrollSnapPoints(m_range, m_context.mode);
3764 #endif
3765     case CSSPropertyBorderTopRightRadius:
3766     case CSSPropertyBorderTopLeftRadius:
3767     case CSSPropertyBorderBottomLeftRadius:
3768     case CSSPropertyBorderBottomRightRadius:
3769         return consumeBorderRadiusCorner(m_range, m_context.mode);
3770     case CSSPropertyWebkitBoxFlexGroup:
3771         return consumeInteger(m_range, 0);
3772     case CSSPropertyOrder:
3773         return consumeInteger(m_range);
3774     case CSSPropertyWebkitTextUnderlinePosition:
3775         // auto | [ under || [ left | right ] ], but we only support auto | under for now
3776         return consumeIdent<CSSValueAuto, CSSValueUnder>(m_range);
3777     case CSSPropertyVerticalAlign:
3778         return consumeVerticalAlign(m_range, m_context.mode);
3779     case CSSPropertyShapeOutside:
3780         return consumeShapeOutside(m_range, m_context);
3781     case CSSPropertyWebkitClipPath:
3782         return consumeWebkitClipPath(m_range, m_context);
3783     case CSSPropertyJustifyContent:
3784     case CSSPropertyAlignContent:
3785         return consumeContentDistributionOverflowPosition(m_range);
3786     case CSSPropertyBorderImageRepeat:
3787     case CSSPropertyWebkitMaskBoxImageRepeat:
3788         return consumeBorderImageRepeat(m_range);
3789     case CSSPropertyBorderImageSlice:
3790     case CSSPropertyWebkitMaskBoxImageSlice:
3791         return consumeBorderImageSlice(property, m_range);
3792     case CSSPropertyBorderImageOutset:
3793     case CSSPropertyWebkitMaskBoxImageOutset:
3794         return consumeBorderImageOutset(m_range);
3795     case CSSPropertyBorderImageWidth:
3796     case CSSPropertyWebkitMaskBoxImageWidth:
3797         return consumeBorderImageWidth(m_range);
3798     case CSSPropertyWebkitBorderImage:
3799     case CSSPropertyWebkitMaskBoxImage:
3800         return consumeWebkitBorderImage(property, m_range, m_context);
3801     case CSSPropertyWebkitBoxReflect:
3802         return consumeReflect(m_range, m_context);
3803     case CSSPropertyWebkitLineBoxContain:
3804         return consumeLineBoxContain(m_range);
3805 #if ENABLE(CSS_IMAGE_ORIENTATION)
3806     case CSSPropertyImageOrientation:
3807         return consumeImageOrientation(m_range, m_context.mode);
3808 #endif
3809     case CSSPropertyBackgroundAttachment:
3810     case CSSPropertyBackgroundBlendMode:
3811     case CSSPropertyBackgroundClip:
3812     case CSSPropertyBackgroundImage:
3813     case CSSPropertyBackgroundOrigin:
3814     case CSSPropertyBackgroundPositionX:
3815     case CSSPropertyBackgroundPositionY:
3816     case CSSPropertyBackgroundSize:
3817     case CSSPropertyWebkitBackgroundClip:
3818     case CSSPropertyWebkitBackgroundOrigin:
3819     case CSSPropertyWebkitBackgroundComposite:
3820     case CSSPropertyWebkitBackgroundSize:
3821     case CSSPropertyWebkitMaskClip:
3822     case CSSPropertyWebkitMaskComposite:
3823     case CSSPropertyWebkitMaskImage:
3824     case CSSPropertyWebkitMaskOrigin:
3825     case CSSPropertyWebkitMaskPositionX:
3826     case CSSPropertyWebkitMaskPositionY:
3827     case CSSPropertyWebkitMaskSize:
3828     case CSSPropertyWebkitMaskSourceType:
3829         return consumeCommaSeparatedBackgroundComponent(property, m_range, m_context);
3830     case CSSPropertyWebkitMaskRepeatX:
3831     case CSSPropertyWebkitMaskRepeatY:
3832         return nullptr;
3833 #if ENABLE(CSS_GRID_LAYOUT)
3834     case CSSPropertyAlignItems:
3835         if (!m_context.cssGridLayoutEnabled)
3836             return nullptr;
3837         return consumeAlignItems(m_range);
3838     case CSSPropertyJustifySelf:
3839     case CSSPropertyAlignSelf:
3840         if (!m_context.cssGridLayoutEnabled)
3841             return nullptr;
3842         return consumeSelfPositionOverflowPosition(m_range);
3843     case CSSPropertyJustifyItems:
3844         if (!m_context.cssGridLayoutEnabled)
3845             return nullptr;
3846         return consumeJustifyItems(m_range);
3847     case CSSPropertyGridColumnEnd:
3848     case CSSPropertyGridColumnStart:
3849     case CSSPropertyGridRowEnd:
3850     case CSSPropertyGridRowStart:
3851         if (!m_context.cssGridLayoutEnabled)
3852             return nullptr;
3853         return consumeGridLine(m_range);
3854     case CSSPropertyGridAutoColumns:
3855     case CSSPropertyGridAutoRows:
3856         if (!m_context.cssGridLayoutEnabled)
3857             return nullptr;
3858         return consumeGridTrackList(m_range, m_context.mode, GridAuto);
3859     case CSSPropertyGridTemplateColumns: