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