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