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