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