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