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