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