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