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