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