[CSS Parser] Miscellaneous bug fixes
[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         return CSSCustomIdentValue::create(token.value().toString());
1107     }
1108
1109     return consumeCustomIdent(range);
1110 }
1111
1112 static RefPtr<CSSValue> consumeTransitionProperty(CSSParserTokenRange& range)
1113 {
1114     const CSSParserToken& token = range.peek();
1115     if (token.type() != IdentToken)
1116         return nullptr;
1117     if (token.id() == CSSValueNone)
1118         return consumeIdent(range);
1119
1120     if (CSSPropertyID property = token.parseAsCSSPropertyID()) {
1121         range.consumeIncludingWhitespace();
1122         return CSSCustomIdentValue::create(property);
1123     }
1124     return consumeCustomIdent(range);
1125 }
1126
1127     
1128 static RefPtr<CSSValue> consumeSteps(CSSParserTokenRange& range) {
1129     ASSERT(range.peek().functionId() == CSSValueSteps);
1130     CSSParserTokenRange rangeCopy = range;
1131     CSSParserTokenRange args = consumeFunction(rangeCopy);
1132     
1133     RefPtr<CSSPrimitiveValue> steps = consumePositiveInteger(args);
1134     if (!steps)
1135         return nullptr;
1136     
1137     // FIXME-NEWPARSER: Support the middle value and change from a boolean to an enum.
1138     bool stepAtStart = false;
1139     if (consumeCommaIncludingWhitespace(args)) {
1140         switch (args.consumeIncludingWhitespace().id()) {
1141             case CSSValueStart:
1142                 stepAtStart = true;
1143             break;
1144             case CSSValueEnd:
1145                 stepAtStart = false;
1146                 break;
1147             default:
1148                 return nullptr;
1149         }
1150     }
1151     
1152     if (!args.atEnd())
1153         return nullptr;
1154     
1155     range = rangeCopy;
1156     return CSSStepsTimingFunctionValue::create(steps->intValue(), stepAtStart);
1157 }
1158
1159 static RefPtr<CSSValue> consumeCubicBezier(CSSParserTokenRange& range)
1160 {
1161     ASSERT(range.peek().functionId() == CSSValueCubicBezier);
1162     CSSParserTokenRange rangeCopy = range;
1163     CSSParserTokenRange args = consumeFunction(rangeCopy);
1164
1165     double x1, y1, x2, y2;
1166     if (consumeNumberRaw(args, x1)
1167         && x1 >= 0 && x1 <= 1
1168         && consumeCommaIncludingWhitespace(args)
1169         && consumeNumberRaw(args, y1)
1170         && consumeCommaIncludingWhitespace(args)
1171         && consumeNumberRaw(args, x2)
1172         && x2 >= 0 && x2 <= 1
1173         && consumeCommaIncludingWhitespace(args)
1174         && consumeNumberRaw(args, y2)
1175         && args.atEnd()) {
1176         range = rangeCopy;
1177         return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2);
1178     }
1179
1180     return nullptr;
1181 }
1182
1183 static RefPtr<CSSValue> consumeAnimationTimingFunction(CSSParserTokenRange& range)
1184 {
1185     CSSValueID id = range.peek().id();
1186     if (id == CSSValueEase || id == CSSValueLinear || id == CSSValueEaseIn
1187         || id == CSSValueEaseOut || id == CSSValueEaseInOut || id == CSSValueStepStart || id == CSSValueStepEnd)
1188         return consumeIdent(range);
1189
1190     CSSValueID function = range.peek().functionId();
1191     if (function == CSSValueCubicBezier)
1192         return consumeCubicBezier(range);
1193     if (function == CSSValueSteps)
1194         return consumeSteps(range);
1195     return nullptr;
1196 }
1197
1198 static RefPtr<CSSValue> consumeAnimationValue(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
1199 {
1200     switch (property) {
1201     case CSSPropertyAnimationDelay:
1202     case CSSPropertyTransitionDelay:
1203         return consumeTime(range, context.mode, ValueRangeAll, UnitlessQuirk::Forbid);
1204     case CSSPropertyAnimationDirection:
1205         return consumeIdent<CSSValueNormal, CSSValueAlternate, CSSValueReverse, CSSValueAlternateReverse>(range);
1206     case CSSPropertyAnimationDuration:
1207     case CSSPropertyTransitionDuration:
1208         return consumeTime(range, context.mode, ValueRangeNonNegative, UnitlessQuirk::Forbid);
1209     case CSSPropertyAnimationFillMode:
1210         return consumeIdent<CSSValueNone, CSSValueForwards, CSSValueBackwards, CSSValueBoth>(range);
1211     case CSSPropertyAnimationIterationCount:
1212         return consumeAnimationIterationCount(range);
1213     case CSSPropertyAnimationName:
1214         return consumeAnimationName(range);
1215     case CSSPropertyAnimationPlayState:
1216         return consumeIdent<CSSValueRunning, CSSValuePaused>(range);
1217     case CSSPropertyTransitionProperty:
1218         return consumeTransitionProperty(range);
1219     case CSSPropertyAnimationTimingFunction:
1220     case CSSPropertyTransitionTimingFunction:
1221         return consumeAnimationTimingFunction(range);
1222     default:
1223         ASSERT_NOT_REACHED();
1224         return nullptr;
1225     }
1226 }
1227
1228 static bool isValidAnimationPropertyList(CSSPropertyID property, const CSSValueList& valueList)
1229 {
1230     if (property != CSSPropertyTransitionProperty || valueList.length() < 2)
1231         return true;
1232     for (auto& value : valueList) {
1233         if (value->isPrimitiveValue() && downcast<CSSPrimitiveValue>(value.get()).isValueID()
1234             && downcast<CSSPrimitiveValue>(value.get()).valueID() == CSSValueNone)
1235             return false;
1236     }
1237     return true;
1238 }
1239
1240 static RefPtr<CSSValueList> consumeAnimationPropertyList(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
1241 {
1242     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
1243     do {
1244         RefPtr<CSSValue> value = consumeAnimationValue(property, range, context);
1245         if (!value)
1246             return nullptr;
1247         list->append(value.releaseNonNull());
1248     } while (consumeCommaIncludingWhitespace(range));
1249     if (!isValidAnimationPropertyList(property, *list))
1250         return nullptr;
1251     ASSERT(list->length());
1252     return list;
1253 }
1254
1255 bool CSSPropertyParser::consumeAnimationShorthand(const StylePropertyShorthand& shorthand, bool important)
1256 {
1257     const unsigned longhandCount = shorthand.length();
1258     RefPtr<CSSValueList> longhands[8];
1259     ASSERT(longhandCount <= 8);
1260     for (size_t i = 0; i < longhandCount; ++i)
1261         longhands[i] = CSSValueList::createCommaSeparated();
1262
1263     do {
1264         bool parsedLonghand[8] = { false };
1265         do {
1266             bool foundProperty = false;
1267             for (size_t i = 0; i < longhandCount; ++i) {
1268                 if (parsedLonghand[i])
1269                     continue;
1270
1271                 if (RefPtr<CSSValue> value = consumeAnimationValue(shorthand.properties()[i], m_range, m_context)) {
1272                     parsedLonghand[i] = true;
1273                     foundProperty = true;
1274                     longhands[i]->append(*value);
1275                     break;
1276                 }
1277             }
1278             if (!foundProperty)
1279                 return false;
1280         } while (!m_range.atEnd() && m_range.peek().type() != CommaToken);
1281
1282         // FIXME: This will make invalid longhands, see crbug.com/386459
1283         for (size_t i = 0; i < longhandCount; ++i) {
1284             if (!parsedLonghand[i])
1285                 longhands[i]->append(CSSValuePool::singleton().createImplicitInitialValue());
1286             parsedLonghand[i] = false;
1287         }
1288     } while (consumeCommaIncludingWhitespace(m_range));
1289
1290     for (size_t i = 0; i < longhandCount; ++i) {
1291         if (!isValidAnimationPropertyList(shorthand.properties()[i], *longhands[i]))
1292             return false;
1293     }
1294
1295     for (size_t i = 0; i < longhandCount; ++i)
1296         addProperty(shorthand.properties()[i], shorthand.id(), *longhands[i], important);
1297
1298     return m_range.atEnd();
1299 }
1300
1301 static RefPtr<CSSValue> consumeZIndex(CSSParserTokenRange& range)
1302 {
1303     if (range.peek().id() == CSSValueAuto)
1304         return consumeIdent(range);
1305     return consumeInteger(range);
1306 }
1307
1308 static RefPtr<CSSShadowValue> parseSingleShadow(CSSParserTokenRange& range, CSSParserMode cssParserMode, bool allowInset, bool allowSpread)
1309 {
1310     RefPtr<CSSPrimitiveValue> style;
1311     RefPtr<CSSPrimitiveValue> color;
1312
1313     if (range.atEnd())
1314         return nullptr;
1315     if (range.peek().id() == CSSValueInset) {
1316         if (!allowInset)
1317             return nullptr;
1318         style = consumeIdent(range);
1319     }
1320     color = consumeColor(range, cssParserMode);
1321
1322     RefPtr<CSSPrimitiveValue> horizontalOffset = consumeLength(range, cssParserMode, ValueRangeAll);
1323     if (!horizontalOffset)
1324         return nullptr;
1325
1326     RefPtr<CSSPrimitiveValue> verticalOffset = consumeLength(range, cssParserMode, ValueRangeAll);
1327     if (!verticalOffset)
1328         return nullptr;
1329
1330     RefPtr<CSSPrimitiveValue> blurRadius = consumeLength(range, cssParserMode, ValueRangeAll);
1331     RefPtr<CSSPrimitiveValue> spreadDistance;
1332     if (blurRadius) {
1333         // Blur radius must be non-negative.
1334         if (blurRadius->doubleValue() < 0)
1335             return nullptr;
1336         if (allowSpread)
1337             spreadDistance = consumeLength(range, cssParserMode, ValueRangeAll);
1338     }
1339
1340     if (!range.atEnd()) {
1341         if (!color)
1342             color = consumeColor(range, cssParserMode);
1343         if (range.peek().id() == CSSValueInset) {
1344             if (!allowInset || style)
1345                 return nullptr;
1346             style = consumeIdent(range);
1347         }
1348     }
1349     
1350     // We pass RefPtrs, since they can actually be null.
1351     return CSSShadowValue::create(WTFMove(horizontalOffset), WTFMove(verticalOffset), WTFMove(blurRadius), WTFMove(spreadDistance), WTFMove(style), WTFMove(color));
1352 }
1353
1354 static RefPtr<CSSValue> consumeShadow(CSSParserTokenRange& range, CSSParserMode cssParserMode, bool isBoxShadowProperty)
1355 {
1356     if (range.peek().id() == CSSValueNone)
1357         return consumeIdent(range);
1358
1359     RefPtr<CSSValueList> shadowValueList = CSSValueList::createCommaSeparated();
1360     do {
1361         if (RefPtr<CSSShadowValue> shadowValue = parseSingleShadow(range, cssParserMode, isBoxShadowProperty, isBoxShadowProperty))
1362             shadowValueList->append(*shadowValue);
1363         else
1364             return nullptr;
1365     } while (consumeCommaIncludingWhitespace(range));
1366     return shadowValueList;
1367 }
1368
1369 static RefPtr<CSSFunctionValue> consumeFilterFunction(CSSParserTokenRange& range, const CSSParserContext& context)
1370 {
1371     CSSValueID filterType = range.peek().functionId();
1372     if (filterType < CSSValueInvert || filterType > CSSValueDropShadow)
1373         return nullptr;
1374     CSSParserTokenRange args = consumeFunction(range);
1375     RefPtr<CSSFunctionValue>filterValue = CSSFunctionValue::create(filterType);
1376     RefPtr<CSSValue> parsedValue;
1377
1378     if (filterType == CSSValueDropShadow)
1379         parsedValue = parseSingleShadow(args, context.mode, false, false);
1380     else {
1381         if (args.atEnd())
1382             return filterValue;
1383         if (filterType == CSSValueBrightness) {
1384             // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
1385             parsedValue = consumePercent(args, ValueRangeAll);
1386             if (!parsedValue)
1387                 parsedValue = consumeNumber(args, ValueRangeAll);
1388         } else if (filterType == CSSValueHueRotate)
1389             parsedValue = consumeAngle(args, context.mode, UnitlessQuirk::Forbid);
1390         else if (filterType == CSSValueBlur) {
1391             parsedValue = consumeLength(args, HTMLStandardMode, ValueRangeNonNegative);
1392         } else {
1393             // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5)
1394             parsedValue = consumePercent(args, ValueRangeNonNegative);
1395             if (!parsedValue)
1396                 parsedValue = consumeNumber(args, ValueRangeNonNegative);
1397             if (parsedValue && filterType != CSSValueSaturate && filterType != CSSValueContrast) {
1398                 bool isPercentage = downcast<CSSPrimitiveValue>(*parsedValue).isPercentage();
1399                 double maxAllowed = isPercentage ? 100.0 : 1.0;
1400                 if (downcast<CSSPrimitiveValue>(*parsedValue).doubleValue() > maxAllowed) {
1401                     parsedValue = CSSPrimitiveValue::create(maxAllowed, isPercentage ? CSSPrimitiveValue::UnitTypes::CSS_PERCENTAGE : CSSPrimitiveValue::UnitTypes::CSS_NUMBER);
1402                 }
1403             }
1404         }
1405     }
1406     if (!parsedValue || !args.atEnd())
1407         return nullptr;
1408     filterValue->append(*parsedValue);
1409     return filterValue;
1410 }
1411
1412 static RefPtr<CSSValue> consumeFilter(CSSParserTokenRange& range, const CSSParserContext& context)
1413 {
1414     if (range.peek().id() == CSSValueNone)
1415         return consumeIdent(range);
1416
1417     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1418     do {
1419         RefPtr<CSSValue> filterValue = consumeUrl(range);
1420         if (!filterValue) {
1421             filterValue = consumeFilterFunction(range, context);
1422             if (!filterValue)
1423                 return nullptr;
1424         }
1425         list->append(filterValue.releaseNonNull());
1426     } while (!range.atEnd());
1427     return list;
1428 }
1429
1430 static RefPtr<CSSValue> consumeTextDecorationLine(CSSParserTokenRange& range)
1431 {
1432     CSSValueID id = range.peek().id();
1433     if (id == CSSValueNone)
1434         return consumeIdent(range);
1435
1436     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1437     while (true) {
1438         RefPtr<CSSPrimitiveValue> ident = consumeIdent<CSSValueBlink, CSSValueUnderline, CSSValueOverline, CSSValueLineThrough>(range);
1439         if (!ident)
1440             break;
1441         if (list->hasValue(ident.get()))
1442             return nullptr;
1443         list->append(ident.releaseNonNull());
1444     }
1445
1446     if (!list->length())
1447         return nullptr;
1448     return list;
1449 }
1450
1451 static RefPtr<CSSValue> consumeTextEmphasisStyle(CSSParserTokenRange& range)
1452 {
1453     CSSValueID id = range.peek().id();
1454     if (id == CSSValueNone)
1455         return consumeIdent(range);
1456
1457     if (RefPtr<CSSValue> textEmphasisStyle = consumeString(range))
1458         return textEmphasisStyle;
1459
1460     RefPtr<CSSPrimitiveValue> fill = consumeIdent<CSSValueFilled, CSSValueOpen>(range);
1461     RefPtr<CSSPrimitiveValue> shape = consumeIdent<CSSValueDot, CSSValueCircle, CSSValueDoubleCircle, CSSValueTriangle, CSSValueSesame>(range);
1462     if (!fill)
1463         fill = consumeIdent<CSSValueFilled, CSSValueOpen>(range);
1464     if (fill && shape) {
1465         RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
1466         parsedValues->append(fill.releaseNonNull());
1467         parsedValues->append(shape.releaseNonNull());
1468         return parsedValues;
1469     }
1470     if (fill)
1471         return fill;
1472     if (shape)
1473         return shape;
1474     return nullptr;
1475 }
1476
1477 static RefPtr<CSSValue> consumeOutlineColor(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1478 {
1479     // Allow the special focus color even in HTML Standard parsing mode.
1480     if (range.peek().id() == CSSValueWebkitFocusRingColor)
1481         return consumeIdent(range);
1482     return consumeColor(range, cssParserMode);
1483 }
1484
1485 static RefPtr<CSSPrimitiveValue> consumeLineWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
1486 {
1487     CSSValueID id = range.peek().id();
1488     if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
1489         return consumeIdent(range);
1490     return consumeLength(range, cssParserMode, ValueRangeNonNegative, unitless);
1491 }
1492
1493 static RefPtr<CSSPrimitiveValue> consumeBorderWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
1494 {
1495     return consumeLineWidth(range, cssParserMode, unitless);
1496 }
1497
1498 static RefPtr<CSSPrimitiveValue> consumeTextStrokeWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1499 {
1500     return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid);
1501 }
1502
1503 static RefPtr<CSSPrimitiveValue> consumeColumnRuleWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1504 {
1505     return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid);
1506 }
1507
1508 static bool consumeTranslate3d(CSSParserTokenRange& args, CSSParserMode cssParserMode, RefPtr<WebKitCSSTransformValue>& transformValue)
1509 {
1510     unsigned numberOfArguments = 2;
1511     RefPtr<CSSValue> parsedValue;
1512     do {
1513         parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
1514         if (!parsedValue)
1515             return false;
1516         transformValue->append(*parsedValue);
1517         if (!consumeCommaIncludingWhitespace(args))
1518             return false;
1519     } while (--numberOfArguments);
1520     parsedValue = consumeLength(args, cssParserMode, ValueRangeAll);
1521     if (!parsedValue)
1522         return false;
1523     transformValue->append(*parsedValue);
1524     return true;
1525 }
1526
1527 static bool consumeNumbers(CSSParserTokenRange& args, RefPtr<WebKitCSSTransformValue>& transformValue, unsigned numberOfArguments)
1528 {
1529     do {
1530         RefPtr<CSSPrimitiveValue> parsedValue = consumeNumber(args, ValueRangeAll);
1531         if (!parsedValue)
1532             return false;
1533         transformValue->append(parsedValue.releaseNonNull());
1534         if (--numberOfArguments && !consumeCommaIncludingWhitespace(args))
1535             return false;
1536     } while (numberOfArguments);
1537     return true;
1538 }
1539
1540 static bool consumePerspective(CSSParserTokenRange& args, CSSParserMode cssParserMode, RefPtr<WebKitCSSTransformValue>& transformValue)
1541 {
1542     RefPtr<CSSPrimitiveValue> parsedValue = consumeLength(args, cssParserMode, ValueRangeNonNegative);
1543     if (!parsedValue) {
1544         double perspective;
1545         if (!consumeNumberRaw(args, perspective) || perspective < 0)
1546             return false;
1547         parsedValue = CSSPrimitiveValue::create(perspective, CSSPrimitiveValue::UnitTypes::CSS_PX);
1548     }
1549     if (!parsedValue)
1550         return false;
1551     transformValue->append(parsedValue.releaseNonNull());
1552     return true;
1553 }
1554
1555 // FIXME-NEWPARSER: This has no reason to exist once we eliminate WebkitCSSTransformValue in favor
1556 // of CSSFunctionValue.
1557 static WebKitCSSTransformValue::TransformOperationType transformOperationForCSSValueID(CSSValueID functionId)
1558 {
1559     switch (functionId) {
1560     case CSSValueRotate:
1561         return WebKitCSSTransformValue::RotateTransformOperation;
1562     case CSSValueRotatex:
1563         return WebKitCSSTransformValue::RotateXTransformOperation;
1564     case CSSValueRotatey:
1565         return WebKitCSSTransformValue::RotateYTransformOperation;
1566     case CSSValueRotatez:
1567         return WebKitCSSTransformValue::RotateZTransformOperation;
1568     case CSSValueSkewx:
1569         return WebKitCSSTransformValue::SkewXTransformOperation;
1570     case CSSValueSkewy:
1571         return WebKitCSSTransformValue::SkewYTransformOperation;
1572     case CSSValueSkew:
1573         return WebKitCSSTransformValue::SkewTransformOperation;
1574     case CSSValueScalex:
1575         return WebKitCSSTransformValue::ScaleXTransformOperation;
1576     case CSSValueScaley:
1577         return WebKitCSSTransformValue::ScaleYTransformOperation;
1578     case CSSValueScalez:
1579         return WebKitCSSTransformValue::ScaleZTransformOperation;
1580     case CSSValueScale:
1581         return WebKitCSSTransformValue::ScaleTransformOperation;
1582     case CSSValuePerspective:
1583         return WebKitCSSTransformValue::PerspectiveTransformOperation;
1584     case CSSValueTranslatex:
1585         return WebKitCSSTransformValue::TranslateXTransformOperation;
1586     case CSSValueTranslatey:
1587         return WebKitCSSTransformValue::TranslateYTransformOperation;
1588     case CSSValueTranslate:
1589         return WebKitCSSTransformValue::TranslateTransformOperation;
1590     case CSSValueTranslatez:
1591         return WebKitCSSTransformValue::TranslateZTransformOperation;
1592     case CSSValueMatrix:
1593         return WebKitCSSTransformValue::MatrixTransformOperation;
1594     case CSSValueMatrix3d:
1595         return WebKitCSSTransformValue::Matrix3DTransformOperation;
1596     case CSSValueScale3d:
1597         return WebKitCSSTransformValue::Scale3DTransformOperation;
1598     case CSSValueRotate3d:
1599         return WebKitCSSTransformValue::Rotate3DTransformOperation;
1600     case CSSValueTranslate3d:
1601         return WebKitCSSTransformValue::Translate3DTransformOperation;
1602     default:
1603         return WebKitCSSTransformValue::UnknownTransformOperation;
1604     }
1605 }
1606
1607 static RefPtr<CSSValue> consumeTransformValue(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1608 {
1609     CSSValueID functionId = range.peek().functionId();
1610     if (functionId == CSSValueInvalid)
1611         return nullptr;
1612     CSSParserTokenRange args = consumeFunction(range);
1613     if (args.atEnd())
1614         return nullptr;
1615     
1616     // FIXME-NEWPARSER: Do we really need WebkitCSSTransformValue? A CSSFunctionValue is good
1617     // enough and has the CSSValueID as the operation type. Blink has eliminated it.
1618     RefPtr<WebKitCSSTransformValue> transformValue = WebKitCSSTransformValue::create(transformOperationForCSSValueID(functionId));
1619     RefPtr<CSSValue> parsedValue;
1620     switch (functionId) {
1621     case CSSValueRotate:
1622     case CSSValueRotatex:
1623     case CSSValueRotatey:
1624     case CSSValueRotatez:
1625     case CSSValueSkewx:
1626     case CSSValueSkewy:
1627     case CSSValueSkew:
1628         parsedValue = consumeAngle(args, cssParserMode, UnitlessQuirk::Forbid);
1629         if (!parsedValue)
1630             return nullptr;
1631         if (functionId == CSSValueSkew && consumeCommaIncludingWhitespace(args)) {
1632             transformValue->append(*parsedValue);
1633             parsedValue = consumeAngle(args, cssParserMode, UnitlessQuirk::Forbid);
1634             if (!parsedValue)
1635                 return nullptr;
1636         }
1637         break;
1638     case CSSValueScalex:
1639     case CSSValueScaley:
1640     case CSSValueScalez:
1641     case CSSValueScale:
1642         parsedValue = consumeNumber(args, ValueRangeAll);
1643         if (!parsedValue)
1644             return nullptr;
1645         if (functionId == CSSValueScale && consumeCommaIncludingWhitespace(args)) {
1646             transformValue->append(*parsedValue);
1647             parsedValue = consumeNumber(args, ValueRangeAll);
1648             if (!parsedValue)
1649                 return nullptr;
1650         }
1651         break;
1652     case CSSValuePerspective:
1653         if (!consumePerspective(args, cssParserMode, transformValue))
1654             return nullptr;
1655         break;
1656     case CSSValueTranslatex:
1657     case CSSValueTranslatey:
1658     case CSSValueTranslate:
1659         parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
1660         if (!parsedValue)
1661             return nullptr;
1662         if (functionId == CSSValueTranslate && consumeCommaIncludingWhitespace(args)) {
1663             transformValue->append(*parsedValue);
1664             parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
1665             if (!parsedValue)
1666                 return nullptr;
1667         }
1668         break;
1669     case CSSValueTranslatez:
1670         parsedValue = consumeLength(args, cssParserMode, ValueRangeAll);
1671         break;
1672     case CSSValueMatrix:
1673     case CSSValueMatrix3d:
1674         if (!consumeNumbers(args, transformValue, (functionId == CSSValueMatrix3d) ? 16 : 6))
1675             return nullptr;
1676         break;
1677     case CSSValueScale3d:
1678         if (!consumeNumbers(args, transformValue, 3))
1679             return nullptr;
1680         break;
1681     case CSSValueRotate3d:
1682         if (!consumeNumbers(args, transformValue, 3) || !consumeCommaIncludingWhitespace(args))
1683             return nullptr;
1684         parsedValue = consumeAngle(args, cssParserMode, UnitlessQuirk::Forbid);
1685         if (!parsedValue)
1686             return nullptr;
1687         break;
1688     case CSSValueTranslate3d:
1689         if (!consumeTranslate3d(args, cssParserMode, transformValue))
1690             return nullptr;
1691         break;
1692     default:
1693         return nullptr;
1694     }
1695     if (parsedValue)
1696         transformValue->append(*parsedValue);
1697     if (!args.atEnd())
1698         return nullptr;
1699     return transformValue;
1700 }
1701
1702 static RefPtr<CSSValue> consumeTransform(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1703 {
1704     if (range.peek().id() == CSSValueNone)
1705         return consumeIdent(range);
1706
1707     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
1708     do {
1709         RefPtr<CSSValue> parsedTransformValue = consumeTransformValue(range, cssParserMode);
1710         if (!parsedTransformValue)
1711             return nullptr;
1712         list->append(parsedTransformValue.releaseNonNull());
1713     } while (!range.atEnd());
1714
1715     return list;
1716 }
1717
1718 template <CSSValueID start, CSSValueID end>
1719 static RefPtr<CSSValue> consumePositionLonghand(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1720 {
1721     if (range.peek().type() == IdentToken) {
1722         CSSValueID id = range.peek().id();
1723         int percent;
1724         if (id == start)
1725             percent = 0;
1726         else if (id == CSSValueCenter)
1727             percent = 50;
1728         else if (id == end)
1729             percent = 100;
1730         else
1731             return nullptr;
1732         range.consumeIncludingWhitespace();
1733         return CSSPrimitiveValue::create(percent, CSSPrimitiveValue::UnitTypes::CSS_PERCENTAGE);
1734     }
1735     return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
1736 }
1737
1738 static RefPtr<CSSValue> consumePositionX(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1739 {
1740     return consumePositionLonghand<CSSValueLeft, CSSValueRight>(range, cssParserMode);
1741 }
1742
1743 static RefPtr<CSSValue> consumePositionY(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1744 {
1745     return consumePositionLonghand<CSSValueTop, CSSValueBottom>(range, cssParserMode);
1746 }
1747
1748 static RefPtr<CSSValue> consumePaintStroke(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1749 {
1750     if (range.peek().id() == CSSValueNone)
1751         return consumeIdent(range);
1752     RefPtr<CSSPrimitiveValue> url = consumeUrl(range);
1753     if (url) {
1754         RefPtr<CSSValue> parsedValue;
1755         if (range.peek().id() == CSSValueNone)
1756             parsedValue = consumeIdent(range);
1757         else
1758             parsedValue = consumeColor(range, cssParserMode);
1759         if (parsedValue) {
1760             RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
1761             values->append(url.releaseNonNull());
1762             values->append(parsedValue.releaseNonNull());
1763             return values;
1764         }
1765         return url;
1766     }
1767     return consumeColor(range, cssParserMode);
1768 }
1769
1770 static RefPtr<CSSValue> consumePaintOrder(CSSParserTokenRange& range)
1771 {
1772     if (range.peek().id() == CSSValueNormal)
1773         return consumeIdent(range);
1774
1775     Vector<CSSValueID, 3> paintTypeList;
1776     RefPtr<CSSPrimitiveValue> fill;
1777     RefPtr<CSSPrimitiveValue> stroke;
1778     RefPtr<CSSPrimitiveValue> markers;
1779     do {
1780         CSSValueID id = range.peek().id();
1781         if (id == CSSValueFill && !fill)
1782             fill = consumeIdent(range);
1783         else if (id == CSSValueStroke && !stroke)
1784             stroke = consumeIdent(range);
1785         else if (id == CSSValueMarkers && !markers)
1786             markers = consumeIdent(range);
1787         else
1788             return nullptr;
1789         paintTypeList.append(id);
1790     } while (!range.atEnd());
1791
1792     // After parsing we serialize the paint-order list. Since it is not possible to
1793     // pop a last list items from CSSValueList without bigger cost, we create the
1794     // list after parsing.
1795     CSSValueID firstPaintOrderType = paintTypeList.at(0);
1796     RefPtr<CSSValueList> paintOrderList = CSSValueList::createSpaceSeparated();
1797     switch (firstPaintOrderType) {
1798     case CSSValueFill:
1799     case CSSValueStroke:
1800         paintOrderList->append(firstPaintOrderType == CSSValueFill ? fill.releaseNonNull() : stroke.releaseNonNull());
1801         if (paintTypeList.size() > 1) {
1802             if (paintTypeList.at(1) == CSSValueMarkers)
1803                 paintOrderList->append(markers.releaseNonNull());
1804         }
1805         break;
1806     case CSSValueMarkers:
1807         paintOrderList->append(markers.releaseNonNull());
1808         if (paintTypeList.size() > 1) {
1809             if (paintTypeList.at(1) == CSSValueStroke)
1810                 paintOrderList->append(stroke.releaseNonNull());
1811         }
1812         break;
1813     default:
1814         ASSERT_NOT_REACHED();
1815     }
1816
1817     return paintOrderList;
1818 }
1819
1820 static RefPtr<CSSValue> consumeNoneOrURI(CSSParserTokenRange& range)
1821 {
1822     if (range.peek().id() == CSSValueNone)
1823         return consumeIdent(range);
1824     return consumeUrl(range);
1825 }
1826
1827 static RefPtr<CSSValue> consumeFlexBasis(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1828 {
1829     // FIXME: Support intrinsic dimensions too.
1830     if (range.peek().id() == CSSValueAuto)
1831         return consumeIdent(range);
1832     return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
1833 }
1834
1835 static RefPtr<CSSValue> consumeStrokeDasharray(CSSParserTokenRange& range)
1836 {
1837     CSSValueID id = range.peek().id();
1838     if (id == CSSValueNone)
1839         return consumeIdent(range);
1840
1841     RefPtr<CSSValueList> dashes = CSSValueList::createCommaSeparated();
1842     do {
1843         RefPtr<CSSPrimitiveValue> dash = consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeNonNegative);
1844         if (!dash || (consumeCommaIncludingWhitespace(range) && range.atEnd()))
1845             return nullptr;
1846         dashes->append(dash.releaseNonNull());
1847     } while (!range.atEnd());
1848     return dashes;
1849 }
1850
1851 static RefPtr<CSSPrimitiveValue> consumeBaselineShift(CSSParserTokenRange& range)
1852 {
1853     CSSValueID id = range.peek().id();
1854     if (id == CSSValueBaseline || id == CSSValueSub || id == CSSValueSuper)
1855         return consumeIdent(range);
1856     return consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeAll);
1857 }
1858
1859 static RefPtr<CSSPrimitiveValue> consumeRxOrRy(CSSParserTokenRange& range)
1860 {
1861     if (range.peek().id() == CSSValueAuto)
1862         return consumeIdent(range);
1863     return consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
1864 }
1865
1866 static RefPtr<CSSValue> consumeCursor(CSSParserTokenRange& range, const CSSParserContext& context, bool inQuirksMode)
1867 {
1868     RefPtr<CSSValueList> list;
1869     while (RefPtr<CSSValue> image = consumeImage(range, context, ConsumeGeneratedImage::Forbid)) {
1870         double num;
1871         IntPoint hotSpot(-1, -1);
1872         bool hotSpotSpecified = false;
1873         if (consumeNumberRaw(range, num)) {
1874             hotSpot.setX(int(num));
1875             if (!consumeNumberRaw(range, num))
1876                 return nullptr;
1877             hotSpot.setY(int(num));
1878             hotSpotSpecified = true;
1879         }
1880
1881         if (!list)
1882             list = CSSValueList::createCommaSeparated();
1883
1884         list->append(CSSCursorImageValue::create(image.releaseNonNull(), hotSpotSpecified, hotSpot));
1885         if (!consumeCommaIncludingWhitespace(range))
1886             return nullptr;
1887     }
1888
1889     CSSValueID id = range.peek().id();
1890     RefPtr<CSSValue> cursorType;
1891     if (id == CSSValueHand) {
1892         if (!inQuirksMode) // Non-standard behavior
1893             return nullptr;
1894         cursorType = CSSValuePool::singleton().createIdentifierValue(CSSValuePointer);
1895         range.consumeIncludingWhitespace();
1896     } else if ((id >= CSSValueAuto && id <= CSSValueWebkitZoomOut) || id == CSSValueCopy || id == CSSValueNone) {
1897         cursorType = consumeIdent(range);
1898     } else {
1899         return nullptr;
1900     }
1901
1902     if (!list)
1903         return cursorType;
1904     list->append(cursorType.releaseNonNull());
1905     return list;
1906 }
1907
1908 static RefPtr<CSSValue> consumeAttr(CSSParserTokenRange args, CSSParserContext context)
1909 {
1910     if (args.peek().type() != IdentToken)
1911         return nullptr;
1912     
1913     StringView stringView = args.consumeIncludingWhitespace().value();
1914     if (context.isHTMLDocument)
1915         convertToASCIILowercaseInPlace(stringView);
1916
1917     String attrName = stringView.toString();
1918     if (!args.atEnd())
1919         return nullptr;
1920
1921     RefPtr<CSSFunctionValue> attrValue = CSSFunctionValue::create(CSSValueAttr);
1922     attrValue->append(CSSCustomIdentValue::create(attrName));
1923     return attrValue;
1924 }
1925
1926 static RefPtr<CSSValue> consumeCounterContent(CSSParserTokenRange args, bool counters)
1927 {
1928     RefPtr<CSSPrimitiveValue> identifier = consumeCustomIdent(args);
1929     if (!identifier)
1930         return nullptr;
1931
1932     RefPtr<CSSPrimitiveValue> separator;
1933     if (!counters)
1934         separator = CSSPrimitiveValue::create(String(), CSSPrimitiveValue::UnitTypes::CSS_STRING);
1935     else {
1936         if (!consumeCommaIncludingWhitespace(args) || args.peek().type() != StringToken)
1937             return nullptr;
1938         separator = CSSPrimitiveValue::create(args.consumeIncludingWhitespace().value().toString(), CSSPrimitiveValue::UnitTypes::CSS_STRING);
1939     }
1940
1941     RefPtr<CSSPrimitiveValue> listStyle;
1942     if (consumeCommaIncludingWhitespace(args)) {
1943         CSSValueID id = args.peek().id();
1944         if ((id != CSSValueNone && (id < CSSValueDisc || id > CSSValueKatakanaIroha)))
1945             return nullptr;
1946         listStyle = consumeIdent(args);
1947     } else
1948         listStyle = CSSValuePool::singleton().createIdentifierValue(CSSValueDecimal);
1949
1950     if (!args.atEnd())
1951         return nullptr;
1952     
1953     // FIXME-NEWPARSER: Should just have a CSSCounterValue.
1954     return CSSValuePool::singleton().createValue(Counter::create(identifier.releaseNonNull(), listStyle.releaseNonNull(), separator.releaseNonNull()));
1955 }
1956
1957 static RefPtr<CSSValue> consumeContent(CSSParserTokenRange& range, CSSParserContext context)
1958 {
1959     if (identMatches<CSSValueNone, CSSValueNormal>(range.peek().id()))
1960         return consumeIdent(range);
1961
1962     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
1963
1964     do {
1965         RefPtr<CSSValue> parsedValue = consumeImage(range, context);
1966         if (!parsedValue)
1967             parsedValue = consumeIdent<CSSValueOpenQuote, CSSValueCloseQuote, CSSValueNoOpenQuote, CSSValueNoCloseQuote>(range);
1968         if (!parsedValue)
1969             parsedValue = consumeString(range);
1970         if (!parsedValue) {
1971             if (range.peek().functionId() == CSSValueAttr)
1972                 parsedValue = consumeAttr(consumeFunction(range), context);
1973             else if (range.peek().functionId() == CSSValueCounter)
1974                 parsedValue = consumeCounterContent(consumeFunction(range), false);
1975             else if (range.peek().functionId() == CSSValueCounters)
1976                 parsedValue = consumeCounterContent(consumeFunction(range), true);
1977             if (!parsedValue)
1978                 return nullptr;
1979         }
1980         values->append(parsedValue.releaseNonNull());
1981     } while (!range.atEnd());
1982
1983     return values;
1984 }
1985
1986 static RefPtr<CSSPrimitiveValue> consumePerspective(CSSParserTokenRange& range, CSSParserMode cssParserMode)
1987 {
1988     if (range.peek().id() == CSSValueNone)
1989         return consumeIdent(range);
1990     RefPtr<CSSPrimitiveValue> parsedValue = consumeLength(range, cssParserMode, ValueRangeAll);
1991     if (!parsedValue) {
1992         // FIXME: Make this quirk only apply to the webkit prefixed version of the property.
1993         double perspective;
1994         if (!consumeNumberRaw(range, perspective))
1995             return nullptr;
1996         parsedValue = CSSPrimitiveValue::create(perspective, CSSPrimitiveValue::UnitTypes::CSS_PX);
1997     }
1998     if (parsedValue && (parsedValue->isCalculated() || parsedValue->doubleValue() > 0))
1999         return parsedValue;
2000     return nullptr;
2001 }
2002
2003 #if ENABLE(CSS_SCROLL_SNAP)
2004
2005 static RefPtr<CSSValueList> consumePositionList(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2006 {
2007     RefPtr<CSSValueList> positions = CSSValueList::createCommaSeparated();
2008     do {
2009         RefPtr<CSSValue> position = consumePosition(range, cssParserMode, UnitlessQuirk::Forbid);
2010         if (!position)
2011             return nullptr;
2012         positions->append(position.releaseNonNull());
2013     } while (consumeCommaIncludingWhitespace(range));
2014     return positions;
2015 }
2016
2017 static RefPtr<CSSValue> consumeScrollSnapCoordinate(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2018 {
2019     if (range.peek().id() == CSSValueNone)
2020         return consumeIdent(range);
2021     return consumePositionList(range, cssParserMode);
2022 }
2023
2024 static RefPtr<CSSValue> consumeScrollSnapPoints(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2025 {
2026     if (range.peek().id() == CSSValueNone)
2027         return consumeIdent(range);
2028     if (range.peek().functionId() == CSSValueRepeat) {
2029         CSSParserTokenRange args = consumeFunction(range);
2030         RefPtr<CSSPrimitiveValue> parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeNonNegative);
2031         if (args.atEnd() && parsedValue && (parsedValue->isCalculated() || parsedValue->doubleValue() > 0)) {
2032             RefPtr<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueRepeat);
2033             result->append(parsedValue.releaseNonNull());
2034             return result;
2035         }
2036     }
2037     return nullptr;
2038 }
2039
2040 #endif
2041
2042 static RefPtr<CSSValue> consumeBorderRadiusCorner(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2043 {
2044     RefPtr<CSSPrimitiveValue> parsedValue1 = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
2045     if (!parsedValue1)
2046         return nullptr;
2047     RefPtr<CSSPrimitiveValue> parsedValue2 = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
2048     if (!parsedValue2)
2049         parsedValue2 = parsedValue1;
2050     return createPrimitiveValuePair(parsedValue1.releaseNonNull(), parsedValue2.releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce);
2051 }
2052
2053 static RefPtr<CSSPrimitiveValue> consumeVerticalAlign(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2054 {
2055     RefPtr<CSSPrimitiveValue> parsedValue = consumeIdentRange(range, CSSValueBaseline, CSSValueWebkitBaselineMiddle);
2056     if (!parsedValue)
2057         parsedValue = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
2058     return parsedValue;
2059 }
2060
2061 static RefPtr<CSSPrimitiveValue> consumeShapeRadius(CSSParserTokenRange& args, CSSParserMode cssParserMode)
2062 {
2063     if (identMatches<CSSValueClosestSide, CSSValueFarthestSide>(args.peek().id()))
2064         return consumeIdent(args);
2065     return consumeLengthOrPercent(args, cssParserMode, ValueRangeNonNegative);
2066 }
2067
2068 static RefPtr<CSSBasicShapeCircle> consumeBasicShapeCircle(CSSParserTokenRange& args, const CSSParserContext& context)
2069 {
2070     // spec: https://drafts.csswg.org/css-shapes/#supported-basic-shapes
2071     // circle( [<shape-radius>]? [at <position>]? )
2072     RefPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create();
2073     if (RefPtr<CSSPrimitiveValue> radius = consumeShapeRadius(args, context.mode))
2074         shape->setRadius(radius.releaseNonNull());
2075     if (consumeIdent<CSSValueAt>(args)) {
2076         RefPtr<CSSPrimitiveValue> centerX;
2077         RefPtr<CSSPrimitiveValue> centerY;
2078         if (!consumePosition(args, context.mode, UnitlessQuirk::Forbid, centerX, centerY))
2079             return nullptr;
2080         shape->setCenterX(centerX.releaseNonNull());
2081         shape->setCenterY(centerY.releaseNonNull());
2082     }
2083     return shape;
2084 }
2085
2086 static RefPtr<CSSBasicShapeEllipse> consumeBasicShapeEllipse(CSSParserTokenRange& args, const CSSParserContext& context)
2087 {
2088     // spec: https://drafts.csswg.org/css-shapes/#supported-basic-shapes
2089     // ellipse( [<shape-radius>{2}]? [at <position>]? )
2090     RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create();
2091     if (RefPtr<CSSPrimitiveValue> radiusX = consumeShapeRadius(args, context.mode)) {
2092         shape->setRadiusX(radiusX.releaseNonNull());
2093         if (RefPtr<CSSPrimitiveValue> radiusY = consumeShapeRadius(args, context.mode))
2094             shape->setRadiusY(radiusY.releaseNonNull());
2095     }
2096     if (consumeIdent<CSSValueAt>(args)) {
2097         RefPtr<CSSPrimitiveValue> centerX;
2098         RefPtr<CSSPrimitiveValue> centerY;
2099         if (!consumePosition(args, context.mode, UnitlessQuirk::Forbid, centerX, centerY))
2100             return nullptr;
2101         shape->setCenterX(centerX.releaseNonNull());
2102         shape->setCenterY(centerY.releaseNonNull());
2103     }
2104     return shape;
2105 }
2106
2107 static RefPtr<CSSBasicShapePolygon> consumeBasicShapePolygon(CSSParserTokenRange& args, const CSSParserContext& context)
2108 {
2109     RefPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create();
2110     if (identMatches<CSSValueEvenodd, CSSValueNonzero>(args.peek().id())) {
2111         shape->setWindRule(args.consumeIncludingWhitespace().id() == CSSValueEvenodd ? RULE_EVENODD : RULE_NONZERO);
2112         if (!consumeCommaIncludingWhitespace(args))
2113             return nullptr;
2114     }
2115
2116     do {
2117         RefPtr<CSSPrimitiveValue> xLength = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2118         if (!xLength)
2119             return nullptr;
2120         RefPtr<CSSPrimitiveValue> yLength = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2121         if (!yLength)
2122             return nullptr;
2123         shape->appendPoint(xLength.releaseNonNull(), yLength.releaseNonNull());
2124     } while (consumeCommaIncludingWhitespace(args));
2125     return shape;
2126 }
2127
2128 static void complete4Sides(RefPtr<CSSPrimitiveValue> side[4])
2129 {
2130     if (side[3])
2131         return;
2132     if (!side[2]) {
2133         if (!side[1])
2134             side[1] = side[0];
2135         side[2] = side[0];
2136     }
2137     side[3] = side[1];
2138 }
2139
2140 static bool consumeRadii(RefPtr<CSSPrimitiveValue> horizontalRadii[4], RefPtr<CSSPrimitiveValue> verticalRadii[4], CSSParserTokenRange& range, CSSParserMode cssParserMode, bool useLegacyParsing)
2141 {
2142     unsigned i = 0;
2143     for (; i < 4 && !range.atEnd() && range.peek().type() != DelimiterToken; ++i) {
2144         horizontalRadii[i] = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
2145         if (!horizontalRadii[i])
2146             return false;
2147     }
2148     if (!horizontalRadii[0])
2149         return false;
2150     if (range.atEnd()) {
2151         // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to border-radius: l1 / l2;
2152         if (useLegacyParsing && i == 2) {
2153             verticalRadii[0] = horizontalRadii[1];
2154             horizontalRadii[1] = nullptr;
2155         } else {
2156             complete4Sides(horizontalRadii);
2157             for (unsigned i = 0; i < 4; ++i)
2158                 verticalRadii[i] = horizontalRadii[i];
2159             return true;
2160         }
2161     } else {
2162         if (!consumeSlashIncludingWhitespace(range))
2163             return false;
2164         for (i = 0; i < 4 && !range.atEnd(); ++i) {
2165             verticalRadii[i] = consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
2166             if (!verticalRadii[i])
2167                 return false;
2168         }
2169         if (!verticalRadii[0] || !range.atEnd())
2170             return false;
2171     }
2172     complete4Sides(horizontalRadii);
2173     complete4Sides(verticalRadii);
2174     return true;
2175 }
2176
2177 static RefPtr<CSSBasicShapeInset> consumeBasicShapeInset(CSSParserTokenRange& args, const CSSParserContext& context)
2178 {
2179     RefPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create();
2180     RefPtr<CSSPrimitiveValue> top = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2181     if (!top)
2182         return nullptr;
2183     RefPtr<CSSPrimitiveValue> right = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2184     RefPtr<CSSPrimitiveValue> bottom;
2185     RefPtr<CSSPrimitiveValue> left;
2186     if (right) {
2187         bottom = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2188         if (bottom)
2189             left = consumeLengthOrPercent(args, context.mode, ValueRangeAll);
2190     }
2191     if (left)
2192         shape->updateShapeSize4Values(top.releaseNonNull(), right.releaseNonNull(), bottom.releaseNonNull(), left.releaseNonNull());
2193     else if (bottom)
2194         shape->updateShapeSize3Values(top.releaseNonNull(), right.releaseNonNull(), bottom.releaseNonNull());
2195     else if (right)
2196         shape->updateShapeSize2Values(top.releaseNonNull(), right.releaseNonNull());
2197     else
2198         shape->updateShapeSize1Value(top.releaseNonNull());
2199
2200     if (consumeIdent<CSSValueRound>(args)) {
2201         RefPtr<CSSPrimitiveValue> horizontalRadii[4] = { 0 };
2202         RefPtr<CSSPrimitiveValue> verticalRadii[4] = { 0 };
2203         if (!consumeRadii(horizontalRadii, verticalRadii, args, context.mode, false))
2204             return nullptr;
2205         shape->setTopLeftRadius(createPrimitiveValuePair(horizontalRadii[0].releaseNonNull(), verticalRadii[0].releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce));
2206         shape->setTopRightRadius(createPrimitiveValuePair(horizontalRadii[1].releaseNonNull(), verticalRadii[1].releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce));
2207         shape->setBottomRightRadius(createPrimitiveValuePair(horizontalRadii[2].releaseNonNull(), verticalRadii[2].releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce));
2208         shape->setBottomLeftRadius(createPrimitiveValuePair(horizontalRadii[3].releaseNonNull(), verticalRadii[3].releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce));
2209     }
2210     return shape;
2211 }
2212
2213 static RefPtr<CSSValue> consumeBasicShape(CSSParserTokenRange& range, const CSSParserContext& context)
2214 {
2215     RefPtr<CSSValue> result;
2216     if (range.peek().type() != FunctionToken)
2217         return nullptr;
2218     CSSValueID id = range.peek().functionId();
2219     CSSParserTokenRange rangeCopy = range;
2220     CSSParserTokenRange args = consumeFunction(rangeCopy);
2221     
2222     // FIXME-NEWPARSER: CSSBasicShape should be a CSSValue, and shapes should not be primitive values.
2223     RefPtr<CSSBasicShape> shape;
2224     if (id == CSSValueCircle)
2225         shape = consumeBasicShapeCircle(args, context);
2226     else if (id == CSSValueEllipse)
2227         shape = consumeBasicShapeEllipse(args, context);
2228     else if (id == CSSValuePolygon)
2229         shape = consumeBasicShapePolygon(args, context);
2230     else if (id == CSSValueInset)
2231         shape = consumeBasicShapeInset(args, context);
2232     if (!shape)
2233         return nullptr;
2234     range = rangeCopy;
2235     
2236     return CSSValuePool::singleton().createValue(shape.releaseNonNull());
2237 }
2238
2239 static RefPtr<CSSValue> consumeBasicShapeOrBox(CSSParserTokenRange& range, const CSSParserContext& context)
2240 {
2241     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
2242     bool shapeFound = false;
2243     bool boxFound = false;
2244     while (!range.atEnd() && !(shapeFound && boxFound)) {
2245         RefPtr<CSSValue> componentValue;
2246         if (range.peek().type() == FunctionToken && !shapeFound) {
2247             componentValue = consumeBasicShape(range, context);
2248             shapeFound = true;
2249         } else if (range.peek().type() == IdentToken && !boxFound) {
2250             componentValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueFill, CSSValueStroke, CSSValueViewBox>(range);
2251             boxFound = true;
2252         }
2253         if (!componentValue)
2254             return nullptr;
2255         list->append(componentValue.releaseNonNull());
2256     }
2257     
2258     if (!range.atEnd())
2259         return nullptr;
2260     
2261     return list;
2262 }
2263     
2264 static RefPtr<CSSValue> consumeWebkitClipPath(CSSParserTokenRange& range, const CSSParserContext& context)
2265 {
2266     if (range.peek().id() == CSSValueNone)
2267         return consumeIdent(range);
2268     if (RefPtr<CSSPrimitiveValue> url = consumeUrl(range))
2269         return url;
2270     return consumeBasicShapeOrBox(range, context);
2271 }
2272
2273 static RefPtr<CSSValue> consumeShapeOutside(CSSParserTokenRange& range, const CSSParserContext& context)
2274 {
2275     if (RefPtr<CSSValue> imageValue = consumeImageOrNone(range, context))
2276         return imageValue;
2277     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
2278     if (RefPtr<CSSValue> boxValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox>(range))
2279         list->append(boxValue.releaseNonNull());
2280     if (RefPtr<CSSValue> shapeValue = consumeBasicShape(range, context)) {
2281         list->append(shapeValue.releaseNonNull());
2282         if (list->length() < 2) {
2283             if (RefPtr<CSSValue> boxValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox>(range))
2284                 list->append(boxValue.releaseNonNull());
2285         }
2286     }
2287     if (!list->length())
2288         return nullptr;
2289     return list;
2290 }
2291
2292 static RefPtr<CSSValue> consumeContentDistributionOverflowPosition(CSSParserTokenRange& range)
2293 {
2294     if (identMatches<CSSValueNormal, CSSValueBaseline, CSSValueLastBaseline>(range.peek().id()))
2295         return CSSContentDistributionValue::create(CSSValueInvalid, range.consumeIncludingWhitespace().id(), CSSValueInvalid);
2296
2297     CSSValueID distribution = CSSValueInvalid;
2298     CSSValueID position = CSSValueInvalid;
2299     CSSValueID overflow = CSSValueInvalid;
2300     do {
2301         CSSValueID id = range.peek().id();
2302         if (identMatches<CSSValueSpaceBetween, CSSValueSpaceAround, CSSValueSpaceEvenly, CSSValueStretch>(id)) {
2303             if (distribution != CSSValueInvalid)
2304                 return nullptr;
2305             distribution = id;
2306         } else if (identMatches<CSSValueStart, CSSValueEnd, CSSValueCenter, CSSValueFlexStart, CSSValueFlexEnd, CSSValueLeft, CSSValueRight>(id)) {
2307             if (position != CSSValueInvalid)
2308                 return nullptr;
2309             position = id;
2310         } else if (identMatches<CSSValueUnsafe, CSSValueSafe>(id)) {
2311             if (overflow != CSSValueInvalid)
2312                 return nullptr;
2313             overflow = id;
2314         } else {
2315             return nullptr;
2316         }
2317         range.consumeIncludingWhitespace();
2318     } while (!range.atEnd());
2319
2320     // The grammar states that we should have at least <content-distribution> or <content-position>.
2321     if (position == CSSValueInvalid && distribution == CSSValueInvalid)
2322         return nullptr;
2323
2324     // The grammar states that <overflow-position> must be associated to <content-position>.
2325     if (overflow != CSSValueInvalid && position == CSSValueInvalid)
2326         return nullptr;
2327
2328     return CSSContentDistributionValue::create(distribution, position, overflow);
2329 }
2330
2331 static RefPtr<CSSPrimitiveValue> consumeBorderImageRepeatKeyword(CSSParserTokenRange& range)
2332 {
2333     return consumeIdent<CSSValueStretch, CSSValueRepeat, CSSValueSpace, CSSValueRound>(range);
2334 }
2335
2336 static RefPtr<CSSValue> consumeBorderImageRepeat(CSSParserTokenRange& range)
2337 {
2338     RefPtr<CSSPrimitiveValue> horizontal = consumeBorderImageRepeatKeyword(range);
2339     if (!horizontal)
2340         return nullptr;
2341     RefPtr<CSSPrimitiveValue> vertical = consumeBorderImageRepeatKeyword(range);
2342     if (!vertical)
2343         vertical = horizontal;
2344     return createPrimitiveValuePair(horizontal.releaseNonNull(), vertical.releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce);
2345 }
2346
2347 static RefPtr<CSSValue> consumeBorderImageSlice(CSSPropertyID property, CSSParserTokenRange& range)
2348 {
2349     bool fill = consumeIdent<CSSValueFill>(range);
2350     RefPtr<CSSPrimitiveValue> slices[4] = { 0 };
2351
2352     for (size_t index = 0; index < 4; ++index) {
2353         RefPtr<CSSPrimitiveValue> value = consumePercent(range, ValueRangeNonNegative);
2354         if (!value)
2355             value = consumeNumber(range, ValueRangeNonNegative);
2356         if (!value)
2357             break;
2358         slices[index] = value;
2359     }
2360     if (!slices[0])
2361         return nullptr;
2362     if (consumeIdent<CSSValueFill>(range)) {
2363         if (fill)
2364             return nullptr;
2365         fill = true;
2366     }
2367     complete4Sides(slices);
2368     // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
2369     // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
2370     if (property == CSSPropertyWebkitBorderImage || property == CSSPropertyWebkitMaskBoxImage || property == CSSPropertyWebkitBoxReflect)
2371         fill = true;
2372     
2373     // Now build a rect value to hold all four of our primitive values.
2374     // FIXME-NEWPARSER: Should just have a CSSQuadValue.
2375     auto quad = Quad::create();
2376     quad->setTop(slices[0].releaseNonNull());
2377     quad->setRight(slices[1].releaseNonNull());
2378     quad->setBottom(slices[2].releaseNonNull());
2379     quad->setLeft(slices[3].releaseNonNull());
2380     
2381     // Make our new border image value now.
2382     return CSSBorderImageSliceValue::create(CSSValuePool::singleton().createValue(WTFMove(quad)), fill);
2383 }
2384
2385 static RefPtr<CSSValue> consumeBorderImageOutset(CSSParserTokenRange& range)
2386 {
2387     RefPtr<CSSPrimitiveValue> outsets[4] = { 0 };
2388
2389     RefPtr<CSSPrimitiveValue> value;
2390     for (size_t index = 0; index < 4; ++index) {
2391         value = consumeNumber(range, ValueRangeNonNegative);
2392         if (!value)
2393             value = consumeLength(range, HTMLStandardMode, ValueRangeNonNegative);
2394         if (!value)
2395             break;
2396         outsets[index] = value;
2397     }
2398     if (!outsets[0])
2399         return nullptr;
2400     complete4Sides(outsets);
2401     
2402     // FIXME-NEWPARSER: Should just have a CSSQuadValue.
2403     auto quad = Quad::create();
2404     quad->setTop(outsets[0].releaseNonNull());
2405     quad->setRight(outsets[1].releaseNonNull());
2406     quad->setBottom(outsets[2].releaseNonNull());
2407     quad->setLeft(outsets[3].releaseNonNull());
2408     
2409     return CSSValuePool::singleton().createValue(WTFMove(quad));
2410 }
2411
2412 static RefPtr<CSSValue> consumeBorderImageWidth(CSSParserTokenRange& range)
2413 {
2414     RefPtr<CSSPrimitiveValue> widths[4];
2415
2416     RefPtr<CSSPrimitiveValue> value;
2417     for (size_t index = 0; index < 4; ++index) {
2418         value = consumeNumber(range, ValueRangeNonNegative);
2419         if (!value)
2420             value = consumeLengthOrPercent(range, HTMLStandardMode, ValueRangeNonNegative, UnitlessQuirk::Forbid);
2421         if (!value)
2422             value = consumeIdent<CSSValueAuto>(range);
2423         if (!value)
2424             break;
2425         widths[index] = value;
2426     }
2427     if (!widths[0])
2428         return nullptr;
2429     complete4Sides(widths);
2430     
2431     // FIXME-NEWPARSER: Should just have a CSSQuadValue.
2432     auto quad = Quad::create();
2433     quad->setTop(widths[0].releaseNonNull());
2434     quad->setRight(widths[1].releaseNonNull());
2435     quad->setBottom(widths[2].releaseNonNull());
2436     quad->setLeft(widths[3].releaseNonNull());
2437     
2438     return CSSValuePool::singleton().createValue(WTFMove(quad));
2439 }
2440
2441 static bool consumeBorderImageComponents(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context, RefPtr<CSSValue>& source,
2442     RefPtr<CSSValue>& slice, RefPtr<CSSValue>& width, RefPtr<CSSValue>& outset, RefPtr<CSSValue>& repeat)
2443 {
2444     do {
2445         if (!source) {
2446             source = consumeImageOrNone(range, context);
2447             if (source)
2448                 continue;
2449         }
2450         if (!repeat) {
2451             repeat = consumeBorderImageRepeat(range);
2452             if (repeat)
2453                 continue;
2454         }
2455         if (!slice) {
2456             slice = consumeBorderImageSlice(property, range);
2457             if (slice) {
2458                 ASSERT(!width && !outset);
2459                 if (consumeSlashIncludingWhitespace(range)) {
2460                     width = consumeBorderImageWidth(range);
2461                     if (consumeSlashIncludingWhitespace(range)) {
2462                         outset = consumeBorderImageOutset(range);
2463                         if (!outset)
2464                             return false;
2465                     } else if (!width) {
2466                         return false;
2467                     }
2468                 }
2469             } else {
2470                 return false;
2471             }
2472         } else {
2473             return false;
2474         }
2475     } while (!range.atEnd());
2476     return true;
2477 }
2478
2479 static RefPtr<CSSValue> consumeWebkitBorderImage(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
2480 {
2481     RefPtr<CSSValue> source;
2482     RefPtr<CSSValue> slice;
2483     RefPtr<CSSValue> width;
2484     RefPtr<CSSValue> outset;
2485     RefPtr<CSSValue> repeat;
2486     if (consumeBorderImageComponents(property, range, context, source, slice, width, outset, repeat))
2487         return createBorderImageValue(WTFMove(source), WTFMove(slice), WTFMove(width), WTFMove(outset), WTFMove(repeat));
2488     return nullptr;
2489 }
2490
2491 static RefPtr<CSSValue> consumeReflect(CSSParserTokenRange& range, const CSSParserContext& context)
2492 {
2493     RefPtr<CSSPrimitiveValue> direction = consumeIdent<CSSValueAbove, CSSValueBelow, CSSValueLeft, CSSValueRight>(range);
2494     if (!direction)
2495         return nullptr;
2496
2497     RefPtr<CSSPrimitiveValue> offset;
2498     if (range.atEnd())
2499         offset = CSSValuePool::singleton().createValue(0, CSSPrimitiveValue::UnitTypes::CSS_PX);
2500     else {
2501         offset = consumeLengthOrPercent(range, context.mode, ValueRangeAll, UnitlessQuirk::Forbid);
2502         if (!offset)
2503             return nullptr;
2504     }
2505
2506     RefPtr<CSSValue> mask;
2507     if (!range.atEnd()) {
2508         mask = consumeWebkitBorderImage(CSSPropertyWebkitBoxReflect, range, context);
2509         if (!mask)
2510             return nullptr;
2511     }
2512     return CSSReflectValue::create(direction.releaseNonNull(), offset.releaseNonNull(), WTFMove(mask));
2513 }
2514
2515 #if ENABLE(CSS_IMAGE_ORIENTATION)
2516 static RefPtr<CSSValue> consumeImageOrientation(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless = UnitlessQuirk::Forbid)
2517 {
2518     if (range.peek().type() != NumberToken) {
2519         RefPtr<CSSPrimitiveValue> angle = consumeAngle(range, cssParserMode, unitless);
2520         if (angle && angle->doubleValue() == 0)
2521             return angle;
2522     }
2523     return nullptr;
2524 }
2525 #endif
2526
2527 static RefPtr<CSSPrimitiveValue> consumeBackgroundBlendMode(CSSParserTokenRange& range)
2528 {
2529     CSSValueID id = range.peek().id();
2530     if (id == CSSValueNormal || id == CSSValueOverlay || (id >= CSSValueMultiply && id <= CSSValueLuminosity))
2531         return consumeIdent(range);
2532     return nullptr;
2533 }
2534
2535 static RefPtr<CSSPrimitiveValue> consumeBackgroundAttachment(CSSParserTokenRange& range)
2536 {
2537     return consumeIdent<CSSValueScroll, CSSValueFixed, CSSValueLocal>(range);
2538 }
2539
2540 static RefPtr<CSSPrimitiveValue> consumeBackgroundBox(CSSParserTokenRange& range)
2541 {
2542     return consumeIdent<CSSValueBorderBox, CSSValuePaddingBox, CSSValueContentBox, CSSValueWebkitText>(range);
2543 }
2544
2545 static RefPtr<CSSPrimitiveValue> consumeBackgroundComposite(CSSParserTokenRange& range)
2546 {
2547     return consumeIdentRange(range, CSSValueClear, CSSValuePlusLighter);
2548 }
2549
2550 static RefPtr<CSSPrimitiveValue> consumePrefixedBackgroundBox(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& /*context*/)
2551 {
2552     // The values 'border', 'padding' and 'content' are deprecated and do not apply to the version of the property that has the -webkit- prefix removed.
2553     if (RefPtr<CSSPrimitiveValue> value = consumeIdentRange(range, CSSValueBorder, CSSValuePaddingBox))
2554         return value;
2555     if (range.peek().id() == CSSValueWebkitText || ((property == CSSPropertyWebkitBackgroundClip || property == CSSPropertyWebkitMaskClip) && range.peek().id() == CSSValueText))
2556         return consumeIdent(range);
2557     return nullptr;
2558 }
2559
2560 static RefPtr<CSSPrimitiveValue> consumeBackgroundSize(CSSPropertyID property, CSSParserTokenRange& range, CSSParserMode cssParserMode)
2561 {
2562     if (identMatches<CSSValueContain, CSSValueCover>(range.peek().id()))
2563         return consumeIdent(range);
2564
2565     RefPtr<CSSPrimitiveValue> horizontal = consumeIdent<CSSValueAuto>(range);
2566     if (!horizontal)
2567         horizontal = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Forbid);
2568
2569     RefPtr<CSSPrimitiveValue> vertical;
2570     if (!range.atEnd()) {
2571         if (range.peek().id() == CSSValueAuto) // `auto' is the default
2572             range.consumeIncludingWhitespace();
2573         else
2574             vertical = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Forbid);
2575     } else if (!vertical && property == CSSPropertyWebkitBackgroundSize) {
2576         // Legacy syntax: "-webkit-background-size: 10px" is equivalent to "background-size: 10px 10px".
2577         vertical = horizontal;
2578     }
2579     if (!vertical)
2580         return horizontal;
2581     return createPrimitiveValuePair(horizontal.releaseNonNull(), vertical.releaseNonNull(), Pair::IdenticalValueEncoding::DoNotCoalesce);
2582 }
2583
2584 static RefPtr<CSSValueList> consumeGridAutoFlow(CSSParserTokenRange& range)
2585 {
2586     RefPtr<CSSPrimitiveValue> rowOrColumnValue = consumeIdent<CSSValueRow, CSSValueColumn>(range);
2587     RefPtr<CSSPrimitiveValue> denseAlgorithm = consumeIdent<CSSValueDense>(range);
2588     if (!rowOrColumnValue) {
2589         rowOrColumnValue = consumeIdent<CSSValueRow, CSSValueColumn>(range);
2590         if (!rowOrColumnValue && !denseAlgorithm)
2591             return nullptr;
2592     }
2593     RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
2594     if (rowOrColumnValue)
2595         parsedValues->append(rowOrColumnValue.releaseNonNull());
2596     if (denseAlgorithm)
2597         parsedValues->append(denseAlgorithm.releaseNonNull());
2598     return parsedValues;
2599 }
2600
2601 static RefPtr<CSSValue> consumeBackgroundComponent(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
2602 {
2603     switch (property) {
2604     case CSSPropertyBackgroundClip:
2605         return consumeBackgroundBox(range);
2606     case CSSPropertyBackgroundBlendMode:
2607         return consumeBackgroundBlendMode(range);
2608     case CSSPropertyBackgroundAttachment:
2609         return consumeBackgroundAttachment(range);
2610     case CSSPropertyBackgroundOrigin:
2611         return consumeBackgroundBox(range);
2612     case CSSPropertyWebkitMaskComposite:
2613     case CSSPropertyWebkitBackgroundComposite:
2614         return consumeBackgroundComposite(range);
2615     case CSSPropertyWebkitBackgroundClip:
2616     case CSSPropertyWebkitBackgroundOrigin:
2617     case CSSPropertyWebkitMaskClip:
2618     case CSSPropertyWebkitMaskOrigin:
2619         return consumePrefixedBackgroundBox(property, range, context);
2620     case CSSPropertyBackgroundImage:
2621     case CSSPropertyWebkitMaskImage:
2622         return consumeImageOrNone(range, context);
2623     case CSSPropertyBackgroundPositionX:
2624     case CSSPropertyWebkitMaskPositionX:
2625         return consumePositionX(range, context.mode);
2626     case CSSPropertyBackgroundPositionY:
2627     case CSSPropertyWebkitMaskPositionY:
2628         return consumePositionY(range, context.mode);
2629     case CSSPropertyBackgroundSize:
2630     case CSSPropertyWebkitBackgroundSize:
2631     case CSSPropertyWebkitMaskSize:
2632         return consumeBackgroundSize(property, range, context.mode);
2633     case CSSPropertyBackgroundColor:
2634         return consumeColor(range, context.mode);
2635     default:
2636         break;
2637     };
2638     return nullptr;
2639 }
2640
2641 static void addBackgroundValue(RefPtr<CSSValue>& list, Ref<CSSValue>&& value)
2642 {
2643     if (list) {
2644         if (!list->isBaseValueList()) {
2645             RefPtr<CSSValue> firstValue = list;
2646             list = CSSValueList::createCommaSeparated();
2647             downcast<CSSValueList>(*list).append(firstValue.releaseNonNull());
2648         }
2649         downcast<CSSValueList>(*list).append(WTFMove(value));
2650     } else {
2651         // To conserve memory we don't actually wrap a single value in a list.
2652         list = WTFMove(value);
2653     }
2654 }
2655
2656 static RefPtr<CSSValue> consumeCommaSeparatedBackgroundComponent(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
2657 {
2658     RefPtr<CSSValue> result;
2659     do {
2660         RefPtr<CSSValue> value = consumeBackgroundComponent(property, range, context);
2661         if (!value)
2662             return nullptr;
2663         addBackgroundValue(result, value.releaseNonNull());
2664     } while (consumeCommaIncludingWhitespace(range));
2665     return result;
2666 }
2667
2668 static RefPtr<CSSPrimitiveValue> consumeSelfPositionKeyword(CSSParserTokenRange& range)
2669 {
2670     CSSValueID id = range.peek().id();
2671     if (id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
2672         || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
2673         || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight)
2674         return consumeIdent(range);
2675     return nullptr;
2676 }
2677
2678 static RefPtr<CSSValue> consumeSelfPositionOverflowPosition(CSSParserTokenRange& range)
2679 {
2680     if (identMatches<CSSValueAuto, CSSValueNormal, CSSValueStretch, CSSValueBaseline, CSSValueLastBaseline>(range.peek().id()))
2681         return consumeIdent(range);
2682
2683     RefPtr<CSSPrimitiveValue> overflowPosition = consumeIdent<CSSValueUnsafe, CSSValueSafe>(range);
2684     RefPtr<CSSPrimitiveValue> selfPosition = consumeSelfPositionKeyword(range);
2685     if (!selfPosition)
2686         return nullptr;
2687     if (!overflowPosition)
2688         overflowPosition = consumeIdent<CSSValueUnsafe, CSSValueSafe>(range);
2689     if (overflowPosition)
2690         return createPrimitiveValuePair(selfPosition.releaseNonNull(), overflowPosition.releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce);
2691     return selfPosition;
2692 }
2693
2694 static RefPtr<CSSValue> consumeAlignItems(CSSParserTokenRange& range)
2695 {
2696     // align-items property does not allow the 'auto' value.
2697     if (identMatches<CSSValueAuto>(range.peek().id()))
2698         return nullptr;
2699     return consumeSelfPositionOverflowPosition(range);
2700 }
2701
2702 static RefPtr<CSSValue> consumeJustifyItems(CSSParserTokenRange& range)
2703 {
2704     CSSParserTokenRange rangeCopy = range;
2705     RefPtr<CSSPrimitiveValue> legacy = consumeIdent<CSSValueLegacy>(rangeCopy);
2706     RefPtr<CSSPrimitiveValue> positionKeyword = consumeIdent<CSSValueCenter, CSSValueLeft, CSSValueRight>(rangeCopy);
2707     if (!legacy)
2708         legacy = consumeIdent<CSSValueLegacy>(rangeCopy);
2709     if (legacy && positionKeyword) {
2710         range = rangeCopy;
2711         return createPrimitiveValuePair(legacy.releaseNonNull(), positionKeyword.releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce);
2712     }
2713     return consumeSelfPositionOverflowPosition(range);
2714 }
2715
2716 static RefPtr<CSSValue> consumeFitContent(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2717 {
2718     CSSParserTokenRange rangeCopy = range;
2719     CSSParserTokenRange args = consumeFunction(rangeCopy);
2720     RefPtr<CSSPrimitiveValue> length = consumeLengthOrPercent(args, cssParserMode, ValueRangeNonNegative, UnitlessQuirk::Allow);
2721     if (!length || !args.atEnd())
2722         return nullptr;
2723     range = rangeCopy;
2724     RefPtr<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueWebkitFitContent);
2725     result->append(length.releaseNonNull());
2726     return result;
2727 }
2728
2729 static RefPtr<CSSPrimitiveValue> consumeCustomIdentForGridLine(CSSParserTokenRange& range)
2730 {
2731     if (range.peek().id() == CSSValueAuto || range.peek().id() == CSSValueSpan)
2732         return nullptr;
2733     return consumeCustomIdent(range);
2734 }
2735
2736 static RefPtr<CSSValue> consumeGridLine(CSSParserTokenRange& range)
2737 {
2738     if (range.peek().id() == CSSValueAuto)
2739         return consumeIdent(range);
2740
2741     RefPtr<CSSPrimitiveValue> spanValue;
2742     RefPtr<CSSPrimitiveValue> gridLineName;
2743     RefPtr<CSSPrimitiveValue> numericValue = consumeInteger(range);
2744     if (numericValue) {
2745         gridLineName = consumeCustomIdentForGridLine(range);
2746         spanValue = consumeIdent<CSSValueSpan>(range);
2747     } else {
2748         spanValue = consumeIdent<CSSValueSpan>(range);
2749         if (spanValue) {
2750             numericValue = consumeInteger(range);
2751             gridLineName = consumeCustomIdentForGridLine(range);
2752             if (!numericValue)
2753                 numericValue = consumeInteger(range);
2754         } else {
2755             gridLineName = consumeCustomIdentForGridLine(range);
2756             if (gridLineName) {
2757                 numericValue = consumeInteger(range);
2758                 spanValue = consumeIdent<CSSValueSpan>(range);
2759                 if (!spanValue && !numericValue)
2760                     return gridLineName;
2761             } else {
2762                 return nullptr;
2763             }
2764         }
2765     }
2766
2767     if (spanValue && !numericValue && !gridLineName)
2768         return nullptr; // "span" keyword alone is invalid.
2769     if (spanValue && numericValue && numericValue->intValue() < 0)
2770         return nullptr; // Negative numbers are not allowed for span.
2771     if (numericValue && numericValue->intValue() == 0)
2772         return nullptr; // An <integer> value of zero makes the declaration invalid.
2773
2774     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
2775     if (spanValue)
2776         values->append(spanValue.releaseNonNull());
2777     if (numericValue)
2778         values->append(numericValue.releaseNonNull());
2779     if (gridLineName)
2780         values->append(gridLineName.releaseNonNull());
2781     ASSERT(values->length());
2782     return values;
2783 }
2784
2785 static bool isGridTrackFixedSized(const CSSPrimitiveValue& primitiveValue)
2786 {
2787     CSSValueID valueID = primitiveValue.valueID();
2788     if (valueID == CSSValueWebkitMinContent || valueID == CSSValueWebkitMaxContent || valueID == CSSValueAuto || primitiveValue.isFlex())
2789         return false;
2790
2791     return true;
2792 }
2793
2794 static bool isGridTrackFixedSized(const CSSValue& value)
2795 {
2796     if (value.isPrimitiveValue())
2797         return isGridTrackFixedSized(downcast<CSSPrimitiveValue>(value));
2798
2799     ASSERT(value.isFunctionValue());
2800     auto& function = downcast<CSSFunctionValue>(value);
2801     if (function.name() == CSSValueWebkitFitContent || function.arguments() == nullptr || function.arguments()->length() < 2)
2802         return false;
2803
2804     CSSValue* minPrimitiveValue = downcast<CSSPrimitiveValue>(function.arguments()->item(0));
2805     CSSValue* maxPrimitiveValue = downcast<CSSPrimitiveValue>(function.arguments()->item(1));
2806     return isGridTrackFixedSized(*minPrimitiveValue) || isGridTrackFixedSized(*maxPrimitiveValue);
2807 }
2808
2809 static Vector<String> parseGridTemplateAreasColumnNames(const String& gridRowNames)
2810 {
2811     ASSERT(!gridRowNames.isEmpty());
2812     Vector<String> columnNames;
2813     // Using StringImpl to avoid checks and indirection in every call to String::operator[].
2814     StringImpl& text = *gridRowNames.impl();
2815
2816     StringBuilder areaName;
2817     for (unsigned i = 0; i < text.length(); ++i) {
2818         if (isCSSSpace(text[i])) {
2819             if (!areaName.isEmpty()) {
2820                 columnNames.append(areaName.toString());
2821                 areaName.clear();
2822             }
2823             continue;
2824         }
2825         if (text[i] == '.') {
2826             if (areaName == ".")
2827                 continue;
2828             if (!areaName.isEmpty()) {
2829                 columnNames.append(areaName.toString());
2830                 areaName.clear();
2831             }
2832         } else {
2833             if (!isNameCodePoint(text[i]))
2834                 return Vector<String>();
2835             if (areaName == ".") {
2836                 columnNames.append(areaName.toString());
2837                 areaName.clear();
2838             }
2839         }
2840
2841         areaName.append(text[i]);
2842     }
2843
2844     if (!areaName.isEmpty())
2845         columnNames.append(areaName.toString());
2846
2847     return columnNames;
2848 }
2849
2850 static bool parseGridTemplateAreasRow(const String& gridRowNames, NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount)
2851 {
2852     if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace())
2853         return false;
2854
2855     Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames);
2856     if (rowCount == 0) {
2857         columnCount = columnNames.size();
2858         if (columnCount == 0)
2859             return false;
2860     } else if (columnCount != columnNames.size()) {
2861         // The declaration is invalid if all the rows don't have the number of columns.
2862         return false;
2863     }
2864
2865     for (size_t currentColumn = 0; currentColumn < columnCount; ++currentColumn) {
2866         const String& gridAreaName = columnNames[currentColumn];
2867
2868         // Unamed areas are always valid (we consider them to be 1x1).
2869         if (gridAreaName == ".")
2870             continue;
2871
2872         size_t lookAheadColumn = currentColumn + 1;
2873         while (lookAheadColumn < columnCount && columnNames[lookAheadColumn] == gridAreaName)
2874             lookAheadColumn++;
2875
2876         NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
2877         if (gridAreaIt == gridAreaMap.end()) {
2878             gridAreaMap.add(gridAreaName, GridArea(GridSpan::translatedDefiniteGridSpan(rowCount, rowCount + 1), GridSpan::translatedDefiniteGridSpan(currentColumn, lookAheadColumn)));
2879         } else {
2880             GridArea& gridArea = gridAreaIt->value;
2881
2882             // The following checks test that the grid area is a single filled-in rectangle.
2883             // 1. The new row is adjacent to the previously parsed row.
2884             if (rowCount != gridArea.rows.endLine())
2885                 return false;
2886
2887             // 2. The new area starts at the same position as the previously parsed area.
2888             if (currentColumn != gridArea.columns.startLine())
2889                 return false;
2890
2891             // 3. The new area ends at the same position as the previously parsed area.
2892             if (lookAheadColumn != gridArea.columns.endLine())
2893                 return false;
2894
2895             gridArea.rows = GridSpan::translatedDefiniteGridSpan(gridArea.rows.startLine(), gridArea.rows.endLine() + 1);
2896         }
2897         currentColumn = lookAheadColumn - 1;
2898     }
2899
2900     return true;
2901 }
2902
2903 static RefPtr<CSSPrimitiveValue> consumeGridBreadth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2904 {
2905     const CSSParserToken& token = range.peek();
2906     if (identMatches<CSSValueWebkitMinContent, CSSValueWebkitMaxContent, CSSValueAuto>(token.id()))
2907         return consumeIdent(range);
2908     if (token.type() == DimensionToken && token.unitType() == CSSPrimitiveValue::UnitTypes::CSS_FR) {
2909         if (range.peek().numericValue() < 0)
2910             return nullptr;
2911         return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitTypes::CSS_FR);
2912     }
2913     return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative, UnitlessQuirk::Allow);
2914 }
2915
2916 static RefPtr<CSSValue> consumeGridTrackSize(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2917 {
2918     const CSSParserToken& token = range.peek();
2919     if (identMatches<CSSValueAuto>(token.id()))
2920         return consumeIdent(range);
2921
2922     if (token.functionId() == CSSValueMinmax) {
2923         CSSParserTokenRange rangeCopy = range;
2924         CSSParserTokenRange args = consumeFunction(rangeCopy);
2925         RefPtr<CSSPrimitiveValue> minTrackBreadth = consumeGridBreadth(args, cssParserMode);
2926         if (!minTrackBreadth || minTrackBreadth->isFlex() || !consumeCommaIncludingWhitespace(args))
2927             return nullptr;
2928         RefPtr<CSSPrimitiveValue> maxTrackBreadth = consumeGridBreadth(args, cssParserMode);
2929         if (!maxTrackBreadth || !args.atEnd())
2930             return nullptr;
2931         range = rangeCopy;
2932         RefPtr<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueMinmax);
2933         result->append(minTrackBreadth.releaseNonNull());
2934         result->append(maxTrackBreadth.releaseNonNull());
2935         return result;
2936     }
2937
2938     if (token.functionId() == CSSValueWebkitFitContent)
2939         return consumeFitContent(range, cssParserMode);
2940
2941     return consumeGridBreadth(range, cssParserMode);
2942 }
2943
2944 // Appends to the passed in CSSGridLineNamesValue if any, otherwise creates a new one.
2945 static RefPtr<CSSGridLineNamesValue> consumeGridLineNames(CSSParserTokenRange& range, CSSGridLineNamesValue* lineNames = nullptr)
2946 {
2947     CSSParserTokenRange rangeCopy = range;
2948     if (rangeCopy.consumeIncludingWhitespace().type() != LeftBracketToken)
2949         return nullptr;
2950     
2951     RefPtr<CSSGridLineNamesValue> result = lineNames;
2952     if (!result)
2953         result = CSSGridLineNamesValue::create();
2954     while (RefPtr<CSSPrimitiveValue> lineName = consumeCustomIdentForGridLine(rangeCopy))
2955         result->append(lineName.releaseNonNull());
2956     if (rangeCopy.consumeIncludingWhitespace().type() != RightBracketToken)
2957         return nullptr;
2958     range = rangeCopy;
2959     return result;
2960 }
2961
2962 static bool consumeGridTrackRepeatFunction(CSSParserTokenRange& range, CSSParserMode cssParserMode, CSSValueList& list, bool& isAutoRepeat, bool& allTracksAreFixedSized)
2963 {
2964     CSSParserTokenRange args = consumeFunction(range);
2965     // The number of repetitions for <auto-repeat> is not important at parsing level
2966     // because it will be computed later, let's set it to 1.
2967     size_t repetitions = 1;
2968     isAutoRepeat = identMatches<CSSValueAutoFill, CSSValueAutoFit>(args.peek().id());
2969     RefPtr<CSSValueList> repeatedValues;
2970     if (isAutoRepeat)
2971         repeatedValues = CSSGridAutoRepeatValue::create(args.consumeIncludingWhitespace().id());
2972     else {
2973         // FIXME: a consumeIntegerRaw would be more efficient here.
2974         RefPtr<CSSPrimitiveValue> repetition = consumePositiveInteger(args);
2975         if (!repetition)
2976             return false;
2977         repetitions = clampTo<size_t>(repetition->doubleValue(), 0, kGridMaxTracks);
2978         repeatedValues = CSSValueList::createSpaceSeparated();
2979     }
2980     if (!consumeCommaIncludingWhitespace(args))
2981         return false;
2982     RefPtr<CSSGridLineNamesValue> lineNames = consumeGridLineNames(args);
2983     if (lineNames)
2984         repeatedValues->append(lineNames.releaseNonNull());
2985
2986     size_t numberOfTracks = 0;
2987     while (!args.atEnd()) {
2988         RefPtr<CSSValue> trackSize = consumeGridTrackSize(args, cssParserMode);
2989         if (!trackSize)
2990             return false;
2991         if (allTracksAreFixedSized)
2992             allTracksAreFixedSized = isGridTrackFixedSized(*trackSize);
2993         repeatedValues->append(*trackSize);
2994         ++numberOfTracks;
2995         lineNames = consumeGridLineNames(args);
2996         if (lineNames)
2997             repeatedValues->append(lineNames.releaseNonNull());
2998     }
2999     // We should have found at least one <track-size> or else it is not a valid <track-list>.
3000     if (!numberOfTracks)
3001         return false;
3002
3003     if (isAutoRepeat)
3004         list.append(repeatedValues.releaseNonNull());
3005     else {
3006         // We clamp the repetitions to a multiple of the repeat() track list's size, while staying below the max grid size.
3007         repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks);
3008         for (size_t i = 0; i < repetitions; ++i) {
3009             for (size_t j = 0; j < repeatedValues->length(); ++j)
3010                 list.append(adoptRef(*repeatedValues->item(j)));
3011         }
3012     }
3013     return true;
3014 }
3015
3016 enum TrackListType { GridTemplate, GridTemplateNoRepeat, GridAuto };
3017
3018 static RefPtr<CSSValue> consumeGridTrackList(CSSParserTokenRange& range, CSSParserMode cssParserMode, TrackListType trackListType)
3019 {
3020     bool allowGridLineNames = trackListType != GridAuto;
3021     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
3022     RefPtr<CSSGridLineNamesValue> lineNames = consumeGridLineNames(range);
3023     if (lineNames) {
3024         if (!allowGridLineNames)
3025             return nullptr;
3026         values->append(lineNames.releaseNonNull());
3027     }
3028
3029     bool allowRepeat = trackListType == GridTemplate;
3030     bool seenAutoRepeat = false;
3031     bool allTracksAreFixedSized = true;
3032     do {
3033         bool isAutoRepeat;
3034         if (range.peek().functionId() == CSSValueRepeat) {
3035             if (!allowRepeat)
3036                 return nullptr;
3037             if (!consumeGridTrackRepeatFunction(range, cssParserMode, *values, isAutoRepeat, allTracksAreFixedSized))
3038                 return nullptr;
3039             if (isAutoRepeat && seenAutoRepeat)
3040                 return nullptr;
3041             seenAutoRepeat = seenAutoRepeat || isAutoRepeat;
3042         } else if (RefPtr<CSSValue> value = consumeGridTrackSize(range, cssParserMode)) {
3043             if (allTracksAreFixedSized)
3044                 allTracksAreFixedSized = isGridTrackFixedSized(*value);
3045             values->append(value.releaseNonNull());
3046         } else {
3047             return nullptr;
3048         }
3049         if (seenAutoRepeat && !allTracksAreFixedSized)
3050             return nullptr;
3051         lineNames = consumeGridLineNames(range);
3052         if (lineNames) {
3053             if (!allowGridLineNames)
3054                 return nullptr;
3055             values->append(*lineNames);
3056         }
3057     } while (!range.atEnd() && range.peek().type() != DelimiterToken);
3058     return values;
3059 }
3060
3061 static RefPtr<CSSValue> consumeGridTemplatesRowsOrColumns(CSSParserTokenRange& range, CSSParserMode cssParserMode)
3062 {
3063     if (range.peek().id() == CSSValueNone)
3064         return consumeIdent(range);
3065     return consumeGridTrackList(range, cssParserMode, GridTemplate);
3066 }
3067
3068 static RefPtr<CSSValue> consumeGridTemplateAreas(CSSParserTokenRange& range)
3069 {
3070     if (range.peek().id() == CSSValueNone)
3071         return consumeIdent(range);
3072
3073     NamedGridAreaMap gridAreaMap;
3074     size_t rowCount = 0;
3075     size_t columnCount = 0;
3076
3077     while (range.peek().type() == StringToken) {
3078         if (!parseGridTemplateAreasRow(range.consumeIncludingWhitespace().value().toString(), gridAreaMap, rowCount, columnCount))
3079             return nullptr;
3080         ++rowCount;
3081     }
3082
3083     if (rowCount == 0)
3084         return nullptr;
3085     ASSERT(columnCount);
3086     return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
3087 }
3088
3089 #if ENABLE(CSS_REGIONS)
3090 static RefPtr<CSSValue> consumeFlowProperty(CSSParserTokenRange& range)
3091 {
3092     RefPtr<CSSValue> result;
3093     if (range.peek().id() == CSSValueNone)
3094         result = consumeIdent(range);
3095     else
3096         result = consumeCustomIdent(range);
3097     return result;
3098 }
3099 #endif
3100
3101 static RefPtr<CSSValue> consumeLineBoxContain(CSSParserTokenRange& range)
3102 {
3103     if (range.peek().id() == CSSValueNone)
3104         return consumeIdent(range);
3105
3106     LineBoxContain lineBoxContain = LineBoxContainNone;
3107     
3108     while (range.peek().type() == IdentToken) {
3109         auto id = range.peek().id();
3110         if (id == CSSValueBlock) {
3111             if (lineBoxContain & LineBoxContainBlock)
3112                 return nullptr;
3113             lineBoxContain |= LineBoxContainBlock;
3114         } else if (id == CSSValueInline) {
3115             if (lineBoxContain & LineBoxContainInline)
3116                 return nullptr;
3117             lineBoxContain |= LineBoxContainInline;
3118         } else if (id == CSSValueFont) {
3119             if (lineBoxContain & LineBoxContainFont)
3120                 return nullptr;
3121             lineBoxContain |= LineBoxContainFont;
3122         } else if (id == CSSValueGlyphs) {
3123             if (lineBoxContain & LineBoxContainGlyphs)
3124                 return nullptr;
3125             lineBoxContain |= LineBoxContainGlyphs;
3126         } else if (id == CSSValueReplaced) {
3127             if (lineBoxContain & LineBoxContainReplaced)
3128                 return nullptr;
3129             lineBoxContain |= LineBoxContainReplaced;
3130         } else if (id == CSSValueInlineBox) {
3131             if (lineBoxContain & LineBoxContainInlineBox)
3132                 return nullptr;
3133             lineBoxContain |= LineBoxContainInlineBox;
3134         } else if (id == CSSValueInitialLetter) {
3135             if (lineBoxContain & LineBoxContainInitialLetter)
3136                 return nullptr;
3137             lineBoxContain |= LineBoxContainInitialLetter;
3138         } else
3139             return nullptr;
3140         range.consumeIncludingWhitespace();
3141     }
3142     
3143     if (!lineBoxContain)
3144         return nullptr;
3145     
3146     return CSSLineBoxContainValue::create(lineBoxContain);
3147 }
3148
3149 static RefPtr<CSSValue> consumeLineGrid(CSSParserTokenRange& range)
3150 {
3151     if (range.peek().id() == CSSValueNone)
3152         return consumeIdent(range);
3153     return consumeCustomIdent(range);
3154 }
3155
3156 static RefPtr<CSSValue> consumeInitialLetter(CSSParserTokenRange& range)
3157 {
3158     RefPtr<CSSValue> ident = consumeIdent<CSSValueNormal>(range);
3159     if (ident)
3160         return ident;
3161     
3162     RefPtr<CSSPrimitiveValue> height = consumeNumber(range, ValueRangeNonNegative);
3163     if (!height)
3164         return nullptr;
3165     
3166     RefPtr<CSSPrimitiveValue> position;
3167     if (!range.atEnd()) {
3168         position = consumeNumber(range, ValueRangeNonNegative);
3169         if (!position || !range.atEnd())
3170             return nullptr;
3171     } else
3172         position = height.copyRef();
3173     
3174     return createPrimitiveValuePair(position.releaseNonNull(), WTFMove(height));
3175 }
3176
3177 static RefPtr<CSSValue> consumeHangingPunctuation(CSSParserTokenRange& range)
3178 {
3179     if (range.peek().id() == CSSValueNone)
3180         return consumeIdent(range);
3181     
3182     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
3183     std::bitset<numCSSValueKeywords> seenValues;
3184
3185     bool seenForceEnd = false;
3186     bool seenAllowEnd = false;
3187     bool seenFirst = false;
3188     bool seenLast = false;
3189
3190     while (!range.atEnd()) {
3191         CSSValueID valueID = range.peek().id();
3192         if ((valueID == CSSValueFirst && seenFirst)
3193             || (valueID == CSSValueLast && seenLast)
3194             || (valueID == CSSValueAllowEnd && (seenAllowEnd || seenForceEnd))
3195             || (valueID == CSSValueForceEnd && (seenAllowEnd || seenForceEnd)))
3196             return nullptr;
3197         RefPtr<CSSValue> ident = consumeIdent<CSSValueAllowEnd, CSSValueForceEnd, CSSValueFirst, CSSValueLast>(range);
3198         if (!ident)
3199             return nullptr;
3200         switch (valueID) {
3201         case CSSValueAllowEnd:
3202             seenAllowEnd = true;
3203             break;
3204         case CSSValueForceEnd:
3205             seenForceEnd = true;
3206             break;
3207         case CSSValueFirst:
3208             seenFirst = true;
3209             break;
3210         case CSSValueLast:
3211             seenLast = true;
3212             break;
3213         default:
3214             break;
3215         }
3216         list->append(ident.releaseNonNull());
3217     }
3218     
3219     return list->length() ? list : nullptr;
3220 }
3221
3222 static RefPtr<CSSValue> consumeWebkitMarqueeIncrement(CSSParserTokenRange& range, CSSParserMode cssParserMode)
3223 {
3224     if (range.peek().type() == IdentToken)
3225         return consumeIdent<CSSValueSmall, CSSValueMedium, CSSValueLarge>(range);
3226     return consumeLengthOrPercent(range, cssParserMode, ValueRangeAll);
3227 }
3228
3229 static RefPtr<CSSValue> consumeWebkitMarqueeRepetition(CSSParserTokenRange& range)
3230 {
3231     if (range.peek().type() == IdentToken)
3232         return consumeIdent<CSSValueInfinite>(range);
3233     return consumeNumber(range, ValueRangeNonNegative);
3234 }
3235
3236 static RefPtr<CSSValue> consumeWebkitMarqueeSpeed(CSSParserTokenRange& range, CSSParserMode cssParserMode)
3237 {
3238     if (range.peek().type() == IdentToken)
3239         return consumeIdent<CSSValueSlow, CSSValueNormal, CSSValueFast>(range);
3240     return consumeTime(range, cssParserMode, ValueRangeNonNegative, UnitlessQuirk::Allow);
3241 }
3242
3243 static RefPtr<CSSValue> consumeAlt(CSSParserTokenRange& range, const CSSParserContext& context)
3244 {
3245     if (range.peek().type() == StringToken)
3246         return consumeString(range);
3247     
3248     if (range.peek().functionId() != CSSValueAttr)
3249         return nullptr;
3250     
3251     return consumeAttr(consumeFunction(range), context);
3252 }
3253
3254 static RefPtr<CSSValue> consumeWebkitAspectRatio(CSSParserTokenRange& range)
3255 {
3256     if (range.peek().type() == IdentToken)
3257         return consumeIdent<CSSValueAuto, CSSValueFromDimensions, CSSValueFromIntrinsic>(range);
3258     
3259     RefPtr<CSSPrimitiveValue> leftValue = consumeNumber(range, ValueRangeNonNegative);
3260     if (!leftValue || range.atEnd() || !consumeSlashIncludingWhitespace(range))
3261         return nullptr;
3262     RefPtr<CSSPrimitiveValue> rightValue = consumeNumber(range, ValueRangeNonNegative);
3263     if (!rightValue)
3264         return nullptr;
3265     
3266     return CSSAspectRatioValue::create(leftValue->floatValue(), rightValue->floatValue());
3267 }
3268
3269 static RefPtr<CSSValue> consumeTextEmphasisPosition(CSSParserTokenRange& range)
3270 {
3271     bool foundOverOrUnder = false;
3272     CSSValueID overUnderValueID = CSSValueOver;
3273     bool foundLeftOrRight = false;
3274     CSSValueID leftRightValueID = CSSValueRight;
3275     while (!range.atEnd()) {
3276         switch (range.peek().id()) {
3277         case CSSValueOver:
3278             if (foundOverOrUnder)
3279                 return nullptr;
3280             foundOverOrUnder = true;
3281             overUnderValueID = CSSValueOver;
3282             break;
3283         case CSSValueUnder:
3284             if (foundOverOrUnder)
3285                 return nullptr;
3286             foundOverOrUnder = true;
3287             overUnderValueID = CSSValueUnder;
3288             break;
3289         case CSSValueLeft:
3290             if (foundLeftOrRight)
3291                 return nullptr;
3292             foundLeftOrRight = true;
3293             leftRightValueID = CSSValueLeft;
3294             break;
3295         case CSSValueRight:
3296             if (foundLeftOrRight)
3297                 return nullptr;
3298             foundLeftOrRight = true;
3299             leftRightValueID = CSSValueRight;
3300             break;
3301         default:
3302             return nullptr;
3303         }
3304         
3305         range.consumeIncludingWhitespace();
3306     }
3307     if (!foundOverOrUnder)
3308         return nullptr;
3309     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
3310     list->append(CSSValuePool::singleton().createIdentifierValue(overUnderValueID));
3311     if (foundLeftOrRight)
3312         list->append(CSSValuePool::singleton().createIdentifierValue(leftRightValueID));
3313     return list;
3314 }
3315     
3316 RefPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID property, CSSPropertyID currentShorthand)
3317 {
3318     if (CSSParserFastPaths::isKeywordPropertyID(property)) {
3319         if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(property, m_range.peek().id(), m_context.mode))
3320             return nullptr;
3321         return consumeIdent(m_range);
3322     }
3323     switch (property) {
3324     case CSSPropertyWillChange:
3325         return consumeWillChange(m_range);
3326     case CSSPropertyPage:
3327         return consumePage(m_range);
3328     case CSSPropertyQuotes:
3329         return consumeQuotes(m_range);
3330     case CSSPropertyFontVariantCaps:
3331         return consumeFontVariantCaps(m_range);
3332     case CSSPropertyFontVariantLigatures:
3333         return consumeFontVariantLigatures(m_range);
3334     case CSSPropertyFontVariantNumeric:
3335         return consumeFontVariantNumeric(m_range);
3336     case CSSPropertyFontFeatureSettings:
3337         return consumeFontFeatureSettings(m_range);
3338     case CSSPropertyFontFamily:
3339         return consumeFontFamily(m_range);
3340     case CSSPropertyFontWeight:
3341         return consumeFontWeight(m_range);
3342     case CSSPropertyLetterSpacing:
3343     case CSSPropertyWordSpacing:
3344         return consumeSpacing(m_range, m_context.mode);
3345     case CSSPropertyTabSize:
3346         return consumeTabSize(m_range, m_context.mode);
3347 #if ENABLE(TEXT_AUTOSIZING)
3348     case CSSPropertyWebkitTextSizeAdjust:
3349         // FIXME: Support toggling the validation of this property via a runtime setting that is independent of
3350         // whether isTextAutosizingEnabled() is true. We want to enable this property on iOS, when simulating
3351         // a iOS device in Safari's responsive design mode and when optionally enabled in DRT/WTR. Otherwise,
3352         // this property should be disabled by default.
3353 #if !PLATFORM(IOS)
3354         if (!m_context.textAutosizingEnabled)
3355             return nullptr;
3356 #endif
3357         return consumeTextSizeAdjust(m_range, m_context.mode);
3358 #endif
3359     case CSSPropertyFontSize:
3360         return consumeFontSize(m_range, m_context.mode, UnitlessQuirk::Allow);
3361     case CSSPropertyLineHeight:
3362         return consumeLineHeight(m_range, m_context.mode);
3363     case CSSPropertyWebkitBorderHorizontalSpacing:
3364     case CSSPropertyWebkitBorderVerticalSpacing:
3365         return consumeLength(m_range, m_context.mode, ValueRangeNonNegative);
3366     case CSSPropertyCounterIncrement:
3367     case CSSPropertyCounterReset:
3368         return consumeCounter(m_range, property == CSSPropertyCounterIncrement ? 1 : 0);
3369     case CSSPropertySize:
3370         return consumeSize(m_range, m_context.mode);
3371     case CSSPropertyTextIndent:
3372         return consumeTextIndent(m_range, m_context.mode);
3373     case CSSPropertyMaxWidth:
3374     case CSSPropertyMaxHeight:
3375         return consumeMaxWidthOrHeight(m_range, m_context, UnitlessQuirk::Allow);
3376     case CSSPropertyWebkitMaxLogicalWidth:
3377     case CSSPropertyWebkitMaxLogicalHeight:
3378         return consumeMaxWidthOrHeight(m_range, m_context);
3379     case CSSPropertyMinWidth:
3380     case CSSPropertyMinHeight:
3381     case CSSPropertyWidth:
3382     case CSSPropertyHeight:
3383         return consumeWidthOrHeight(m_range, m_context, UnitlessQuirk::Allow);
3384     case CSSPropertyWebkitMinLogicalWidth:
3385     case CSSPropertyWebkitMinLogicalHeight:
3386     case CSSPropertyWebkitLogicalWidth:
3387     case CSSPropertyWebkitLogicalHeight:
3388         return consumeWidthOrHeight(m_range, m_context);
3389     case CSSPropertyMarginTop:
3390     case CSSPropertyMarginRight:
3391     case CSSPropertyMarginBottom:
3392     case CSSPropertyMarginLeft:
3393     case CSSPropertyBottom:
3394     case CSSPropertyLeft:
3395     case CSSPropertyRight:
3396     case CSSPropertyTop:
3397         return consumeMarginOrOffset(m_range, m_context.mode, UnitlessQuirk::Allow);
3398     case CSSPropertyWebkitMarginStart:
3399     case CSSPropertyWebkitMarginEnd:
3400     case CSSPropertyWebkitMarginBefore:
3401     case CSSPropertyWebkitMarginAfter:
3402         return consumeMarginOrOffset(m_range, m_context.mode, UnitlessQuirk::Forbid);
3403     case CSSPropertyPaddingTop:
3404     case CSSPropertyPaddingRight:
3405     case CSSPropertyPaddingBottom:
3406     case CSSPropertyPaddingLeft:
3407         return consumeLengthOrPercent(m_range, m_context.mode, ValueRangeNonNegative, UnitlessQuirk::Allow);
3408     case CSSPropertyWebkitPaddingStart:
3409     case CSSPropertyWebkitPaddingEnd:
3410     case CSSPropertyWebkitPaddingBefore:
3411     case CSSPropertyWebkitPaddingAfter:
3412         return consumeLengthOrPercent(m_range, m_context.mode, ValueRangeNonNegative, UnitlessQuirk::Forbid);
3413     case CSSPropertyClip:
3414         return consumeClip(m_range, m_context.mode);
3415 #if ENABLE(TOUCH_EVENTS)
3416     case CSSPropertyTouchAction:
3417         return consumeTouchAction(m_range);
3418 #endif
3419     case CSSPropertyObjectPosition:
3420         return consumePosition(m_range, m_context.mode, UnitlessQuirk::Forbid);
3421     case CSSPropertyWebkitLineClamp:
3422         return consumeLineClamp(m_range);
3423     case CSSPropertyWebkitFontSizeDelta:
3424         return consumeLength(m_range, m_context.mode, ValueRangeAll, UnitlessQuirk::Allow);
3425     case CSSPropertyWebkitHyphenateCharacter:
3426     case CSSPropertyWebkitLocale:
3427         return consumeLocale(m_range);
3428     case CSSPropertyWebkitHyphenateLimitBefore:
3429     case CSSPropertyWebkitHyphenateLimitAfter:
3430         return consumeHyphenateLimit(m_range, CSSValueAuto);
3431     case CSSPropertyWebkitHyphenateLimitLines:
3432         return consumeHyphenateLimit(m_range, CSSValueNoLimit);
3433     case CSSPropertyColumnWidth:
3434         return consumeColumnWidth(m_range);
3435     case CSSPropertyColumnCount:
3436         return consumeColumnCount(m_range);
3437     case CSSPropertyColumnGap:
3438         return consumeColumnGap(m_range, m_context.mode);
3439     case CSSPropertyColumnSpan:
3440         return consumeColumnSpan(m_range);
3441     case CSSPropertyZoom:
3442         return consumeZoom(m_range, m_context);
3443     case CSSPropertyAnimationDelay:
3444     case CSSPropertyTransitionDelay:
3445     case CSSPropertyAnimationDirection:
3446     case CSSPropertyAnimationDuration:
3447     case CSSPropertyTransitionDuration:
3448     case CSSPropertyAnimationFillMode:
3449     case CSSPropertyAnimationIterationCount:
3450     case CSSPropertyAnimationName:
3451     case CSSPropertyAnimationPlayState:
3452     case CSSPropertyTransitionProperty:
3453     case CSSPropertyAnimationTimingFunction:
3454     case CSSPropertyTransitionTimingFunction:
3455         return consumeAnimationPropertyList(property, m_range, m_context);
3456     case CSSPropertyGridColumnGap:
3457     case CSSPropertyGridRowGap:
3458         return consumeLength(m_range, m_context.mode, ValueRangeNonNegative);
3459     case CSSPropertyShapeMargin:
3460         return consumeLengthOrPercent(m_range, m_context.mode, ValueRangeNonNegative);
3461     case CSSPropertyShapeImageThreshold:
3462         return consumeNumber(m_range, ValueRangeAll);
3463     case CSSPropertyWebkitBoxOrdinalGroup:
3464     case CSSPropertyOrphans:
3465     case CSSPropertyWidows:
3466         return consumePositiveInteger(m_range);
3467     case CSSPropertyWebkitTextDecorationColor:
3468         return consumeColor(m_range, m_context.mode);
3469     case CSSPropertyWebkitTextStrokeWidth:
3470         return consumeTextStrokeWidth(m_range, m_context.mode);
3471     case CSSPropertyWebkitTextFillColor:
3472 #if ENABLE(TOUCH_EVENTS)
3473     case CSSPropertyWebkitTapHighlightColor:
3474 #endif
3475     case CSSPropertyWebkitTextEmphasisColor:
3476     case CSSPropertyWebkitBorderStartColor:
3477     case CSSPropertyWebkitBorderEndColor:
3478     case CSSPropertyWebkitBorderBeforeColor:
3479     case CSSPropertyWebkitBorderAfterColor:
3480     case CSSPropertyWebkitTextStrokeColor:
3481     case CSSPropertyStopColor:
3482     case CSSPropertyFloodColor:
3483     case CSSPropertyLightingColor:
3484     case CSSPropertyColumnRuleColor:
3485         return consumeColor(m_range, m_context.mode);
3486     case CSSPropertyColor:
3487     case CSSPropertyBackgroundColor:
3488         return consumeColor(m_range, m_context.mode, inQuirksMode());
3489     case CSSPropertyWebkitBorderStartWidth:
3490     case CSSPropertyWebkitBorderEndWidth:
3491     case CSSPropertyWebkitBorderBeforeWidth:
3492     case CSSPropertyWebkitBorderAfterWidth:
3493         return consumeBorderWidth(m_range, m_context.mode, UnitlessQuirk::Forbid);
3494     case CSSPropertyBorderBottomColor:
3495     case CSSPropertyBorderLeftColor:
3496     case CSSPropertyBorderRightColor:
3497     case CSSPropertyBorderTopColor: {
3498         bool allowQuirkyColors = inQuirksMode()
3499             && (currentShorthand == CSSPropertyInvalid || currentShorthand == CSSPropertyBorderColor);
3500         return consumeColor(m_range, m_context.mode, allowQuirkyColors);
3501     }
3502     case CSSPropertyBorderBottomWidth:
3503     case CSSPropertyBorderLeftWidth:
3504     case CSSPropertyBorderRightWidth:
3505     case CSSPropertyBorderTopWidth: {
3506         bool allowQuirkyLengths = inQuirksMode()
3507             && (currentShorthand == CSSPropertyInvalid || currentShorthand == CSSPropertyBorderWidth);
3508         UnitlessQuirk unitless = allowQuirkyLengths ? UnitlessQuirk::Allow : UnitlessQuirk::Forbid;
3509         return consumeBorderWidth(m_range, m_context.mode, unitless);
3510     }
3511     case CSSPropertyZIndex:
3512         return consumeZIndex(m_range);
3513     case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
3514     case CSSPropertyBoxShadow:
3515         return consumeShadow(m_range, m_context.mode, property == CSSPropertyBoxShadow);
3516     case CSSPropertyFilter:
3517 #if ENABLE(FILTERS_LEVEL_2)
3518     case CSSPropertyWebkitBackdropFilter:
3519 #endif
3520         return consumeFilter(m_range, m_context);
3521     case CSSPropertyTextDecoration:
3522     case CSSPropertyWebkitTextDecorationsInEffect:
3523     case CSSPropertyWebkitTextDecorationLine:
3524         return consumeTextDecorationLine(m_range);
3525     case CSSPropertyWebkitTextEmphasisStyle:
3526         return consumeTextEmphasisStyle(m_range);
3527     case CSSPropertyOutlineColor:
3528         return consumeOutlineColor(m_range, m_context.mode);
3529     case CSSPropertyOutlineOffset:
3530         return consumeLength(m_range, m_context.mode, ValueRangeAll);
3531     case CSSPropertyOutlineWidth:
3532         return consumeLineWidth(m_range, m_context.mode, UnitlessQuirk::Forbid);
3533     case CSSPropertyTransform:
3534         return consumeTransform(m_range, m_context.mode);
3535     case CSSPropertyTransformOriginX:
3536     case CSSPropertyPerspectiveOriginX:
3537         return consumePositionX(m_range, m_context.mode);
3538     case CSSPropertyTransformOriginY:
3539     case CSSPropertyPerspectiveOriginY:
3540         return consumePositionY(m_range, m_context.mode);
3541     case CSSPropertyTransformOriginZ:
3542         return consumeLength(m_range, m_context.mode, ValueRangeAll);
3543     case CSSPropertyFill:
3544     case CSSPropertyStroke:
3545         return consumePaintStroke(m_range, m_context.mode);
3546     case CSSPropertyPaintOrder:
3547         return consumePaintOrder(m_range);
3548     case CSSPropertyMarkerStart:
3549     case CSSPropertyMarkerMid:
3550     case CSSPropertyMarkerEnd:
3551     case CSSPropertyClipPath:
3552     case CSSPropertyMask:
3553         return consumeNoneOrURI(m_range);
3554     case CSSPropertyFlexBasis:
3555         return consumeFlexBasis(m_range, m_context.mode);
3556     case CSSPropertyFlexGrow:
3557     case CSSPropertyFlexShrink:
3558         return consumeNumber(m_range, ValueRangeNonNegative);
3559     case CSSPropertyStrokeDasharray:
3560         return consumeStrokeDasharray(m_range);
3561     case CSSPropertyColumnRuleWidth:
3562         return consumeColumnRuleWidth(m_range, m_context.mode);
3563     case CSSPropertyStrokeOpacity:
3564     case CSSPropertyFillOpacity:
3565     case CSSPropertyStopOpacity:
3566     case CSSPropertyFloodOpacity:
3567     case CSSPropertyOpacity:
3568     case CSSPropertyWebkitBoxFlex:
3569         return consumeNumber(m_range, ValueRangeAll);
3570     case CSSPropertyBaselineShift:
3571         return consumeBaselineShift(m_range);
3572     case CSSPropertyStrokeMiterlimit:
3573         return consumeNumber(m_range, ValueRangeNonNegative);
3574     case CSSPropertyStrokeWidth:
3575     case CSSPropertyStrokeDashoffset:
3576     case CSSPropertyCx:
3577     case CSSPropertyCy:
3578     case CSSPropertyX:
3579     case CSSPropertyY:
3580     case CSSPropertyR:
3581         return consumeLengthOrPercent(m_range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
3582     case CSSPropertyRx:
3583     case CSSPropertyRy:
3584         return consumeRxOrRy(m_range);
3585     case CSSPropertyCursor:
3586         return consumeCursor(m_range, m_context, inQuirksMode());
3587     case CSSPropertyContent:
3588         return consumeContent(m_range, m_context);
3589     case CSSPropertyListStyleImage:
3590     case CSSPropertyBorderImageSource:
3591     case CSSPropertyWebkitMaskBoxImageSource:
3592         return consumeImageOrNone(m_range, m_context);
3593     case CSSPropertyPerspective:
3594         return consumePerspective(m_range, m_context.mode);
3595 #if ENABLE(CSS_SCROLL_SNAP)
3596     case CSSPropertyWebkitScrollSnapCoordinate:
3597         return consumeScrollSnapCoordinate(m_range, m_context.mode);
3598     case CSSPropertyWebkitScrollSnapPointsX:
3599     case CSSPropertyWebkitScrollSnapPointsY:
3600         return consumeScrollSnapPoints(m_range, m_context.mode);
3601 #endif
3602     case CSSPropertyBorderTopRightRadius:
3603     case CSSPropertyBorderTopLeftRadius:
3604     case CSSPropertyBorderBottomLeftRadius:
3605     case CSSPropertyBorderBottomRightRadius:
3606         return consumeBorderRadiusCorner(m_range, m_context.mode);
3607     case CSSPropertyWebkitBoxFlexGroup:
3608         return consumeInteger(m_range, 0);
3609     case CSSPropertyOrder:
3610         return consumeInteger(m_range);
3611     case CSSPropertyWebkitTextUnderlinePosition:
3612         // auto | [ under || [ left | right ] ], but we only support auto | under for now
3613         return consumeIdent<CSSValueAuto, CSSValueUnder>(m_range);
3614     case CSSPropertyVerticalAlign:
3615         return consumeVerticalAlign(m_range, m_context.mode);
3616     case CSSPropertyShapeOutside:
3617         return consumeShapeOutside(m_range, m_context);
3618     case CSSPropertyWebkitClipPath:
3619         return consumeWebkitClipPath(m_range, m_context);
3620     case CSSPropertyJustifyContent:
3621     case CSSPropertyAlignContent:
3622         return consumeContentDistributionOverflowPosition(m_range);
3623     case CSSPropertyBorderImageRepeat:
3624     case CSSPropertyWebkitMaskBoxImageRepeat:
3625         return consumeBorderImageRepeat(m_range);
3626     case CSSPropertyBorderImageSlice:
3627     case CSSPropertyWebkitMaskBoxImageSlice:
3628         return consumeBorderImageSlice(property, m_range);
3629     case CSSPropertyBorderImageOutset:
3630     case CSSPropertyWebkitMaskBoxImageOutset:
3631         return consumeBorderImageOutset(m_range);
3632     case CSSPropertyBorderImageWidth:
3633     case CSSPropertyWebkitMaskBoxImageWidth:
3634         return consumeBorderImageWidth(m_range);
3635     case CSSPropertyWebkitBorderImage:
3636     case CSSPropertyWebkitMaskBoxImage:
3637         return consumeWebkitBorderImage(property, m_range, m_context);
3638     case CSSPropertyWebkitBoxReflect:
3639         return consumeReflect(m_range, m_context);
3640     case CSSPropertyWebkitLineBoxContain:
3641         return consumeLineBoxContain(m_range);
3642 #if ENABLE(CSS_IMAGE_ORIENTATION)
3643     case CSSPropertyImageOrientation:
3644         return consumeImageOrientation(m_range, m_context.mode);
3645 #endif
3646     case CSSPropertyBackgroundAttachment:
3647     case CSSPropertyBackgroundBlendMode:
3648     case CSSPropertyBackgroundClip:
3649     case CSSPropertyBackgroundImage:
3650     case CSSPropertyBackgroundOrigin:
3651     case CSSPropertyBackgroundPositionX:
3652     case CSSPropertyBackgroundPositionY:
3653     case CSSPropertyBackgroundSize:
3654     case CSSPropertyWebkitBackgroundClip:
3655     case CSSPropertyWebkitBackgroundOrigin:
3656     case CSSPropertyWebkitBackgroundComposite:
3657     case CSSPropertyWebkitMaskClip:
3658     case CSSPropertyWebkitMaskComposite:
3659     case CSSPropertyWebkitMaskImage:
3660     case CSSPropertyWebkitMaskOrigin:
3661     case CSSPropertyWebkitMaskPositionX:
3662     case CSSPropertyWebkitMaskPositionY:
3663     case CSSPropertyWebkitMaskSize:
3664         return consumeCommaSeparatedBackgroundComponent(property, m_range, m_context);
3665     case CSSPropertyWebkitMaskRepeatX:
3666     case CSSPropertyWebkitMaskRepeatY:
3667         return nullptr;
3668     case CSSPropertyAlignItems:
3669         return consumeAlignItems(m_range);
3670     case CSSPropertyJustifySelf:
3671     case CSSPropertyAlignSelf:
3672         return consumeSelfPositionOverflowPosition(m_range);
3673     case CSSPropertyJustifyItems:
3674         return consumeJustifyItems(m_range);
3675     case CSSPropertyGridColumnEnd:
3676     case CSSPropertyGridColumnStart:
3677     case CSSPropertyGridRowEnd:
3678     case CSSPropertyGridRowStart:
3679         return consumeGridLine(m_range);
3680     case CSSPropertyGridAutoColumns:
3681     case CSSPropertyGridAutoRows:
3682         return consumeGridTrackList(m_range, m_context.mode, GridAuto);
3683     case CSSPropertyGridTemplateColumns:
3684     case CSSPropertyGridTemplateRows:
3685         return consumeGridTemplatesRowsOrColumns(m_range, m_context.mode);
3686     case CSSPropertyGridTemplateAreas:
3687         return consumeGridTemplateAreas(m_range);
3688     case CSSPropertyGridAutoFlow:
3689         return consumeGridAutoFlow(m_range);
3690 #if ENABLE(CSS_REGIONS)
3691     case CSSPropertyWebkitFlowInto:
3692     case CSSPropertyWebkitFlowFrom:
3693         return consumeFlowProperty(m_range);
3694 #endif
3695     case CSSPropertyWebkitLineGrid:
3696         return consumeLineGrid(m_range);
3697     case CSSPropertyWebkitInitialLetter:
3698         return consumeInitialLetter(m_range);
3699     case CSSPropertyHangingPunctuation:
3700         return consumeHangingPunctuation(m_range);
3701     case CSSPropertyWebkitMarqueeIncrement:
3702         return consumeWebkitMarqueeIncrement(m_range, m_context.mode);
3703     case CSSPropertyWebkitMarqueeRepetition:
3704         return consumeWebkitMarqueeRepetition(m_range);
3705     case CSSPropertyWebkitMarqueeSpeed:
3706         return consumeWebkitMarqueeSpeed(m_range, m_context.mode);
3707     case CSSPropertyAlt:
3708         return consumeAlt(m_range, m_context);
3709     case CSSPropertyWebkitAspectRatio:
3710         return consumeWebkitAspectRatio(m_range);
3711     case CSSPropertyWebkitTextEmphasisPosition:
3712         return consumeTextEmphasisPosition(m_range);
3713     default:
3714         return nullptr;
3715     }
3716 }
3717
3718 static RefPtr<CSSValueList> consumeFontFaceUnicodeRange(CSSParserTokenRange& range)
3719 {
3720     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3721
3722     do {
3723         const CSSParserToken& token = range.consumeIncludingWhitespace();
3724         if (token.type() != UnicodeRangeToken)
3725             return nullptr;
3726
3727         UChar32 start = token.unicodeRangeStart();
3728         UChar32 end = token.unicodeRangeEnd();
3729         if (start > end)
3730             return nullptr;
3731         values->append(CSSUnicodeRangeValue::create(start, end));
3732     } while (consumeCommaIncludingWhitespace(range));
3733
3734     return values;
3735 }
3736
3737 static RefPtr<CSSValue> consumeFontFaceSrcURI(CSSParserTokenRange& range, const CSSParserContext& context)
3738 {
3739     String url = consumeUrlAsStringView(range).toString();
3740     if (url.isNull())
3741         return nullptr;
3742     
3743     RefPtr<CSSFontFaceSrcValue> uriValue = CSSFontFaceSrcValue::create(context.completeURL(url));
3744
3745     if (range.peek().functionId() != CSSValueFormat)
3746         return uriValue;
3747
3748     // FIXME: https://drafts.csswg.org/css-fonts says that format() contains a comma-separated list of strings,
3749     // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
3750     // FIXME: We're allowing the format to be an identifier as well as a string, because the old
3751     // parser did. It's not clear if we need to continue to support this behavior, but we have lots of
3752     // layout tests that rely on it.
3753     CSSParserTokenRange args = consumeFunction(range);
3754     const CSSParserToken& arg = args.consumeIncludingWhitespace();
3755     if ((arg.type() != StringToken && arg.type() != IdentToken) || !args.atEnd())
3756         return nullptr;
3757     uriValue->setFormat(arg.value().toString());
3758     return uriValue;
3759 }
3760
3761 static RefPtr<CSSValue> consumeFontFaceSrcLocal(CSSParserTokenRange& range)
3762 {
3763     CSSParserTokenRange args = consumeFunction(range);
3764     if (args.peek().type() == StringToken) {
3765         const CSSParserToken& arg = args.consumeIncludingWhitespace();
3766         if (!args.atEnd())
3767             return nullptr;
3768         return CSSFontFaceSrcValue::createLocal(arg.value().toString());
3769     }
3770     if (args.peek().type() == IdentToken) {
3771         String familyName = concatenateFamilyName(args);
3772         if (!args.atEnd())
3773             return nullptr;
3774         return CSSFontFaceSrcValue::createLocal(familyName);
3775     }
3776     return nullptr;
3777 }
3778
3779 static RefPtr<CSSValueList> consumeFontFaceSrc(CSSParserTokenRange& range, const CSSParserContext& context)
3780 {
3781     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3782
3783     do {
3784         const CSSParserToken& token = range.peek();
3785         RefPtr<CSSValue> parsedValue;
3786         if (token.functionId() == CSSValueLocal)
3787             parsedValue = consumeFontFaceSrcLocal(range);
3788         else
3789             parsedValue = consumeFontFaceSrcURI(range, context);
3790         if (!parsedValue)
3791             return nullptr;
3792         values->append(parsedValue.releaseNonNull());
3793     } while (consumeCommaIncludingWhitespace(range));
3794     return values;
3795 }
3796
3797 bool CSSPropertyParser::parseFontFaceDescriptor(CSSPropertyID propId)
3798 {
3799     RefPtr<CSSValue> parsedValue;
3800     switch (propId) {
3801     case CSSPropertyFontFamily:
3802         parsedValue = consumeFontFamily(m_range);
3803         break;
3804     case CSSPropertySrc: // This is a list of urls or local references.
3805         parsedValue = consumeFontFaceSrc(m_range, m_context);
3806         break;
3807     case CSSPropertyUnicodeRange:
3808         parsedValue = consumeFontFaceUnicodeRange(m_range);
3809         break;
3810     case CSSPropertyFontStretch:
3811     case CSSPropertyFontStyle: {
3812         CSSValueID id = m_range.consumeIncludingWhitespace().id();
3813         if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id, m_context.mode))
3814             return false;
3815         parsedValue = CSSValuePool::singleton().createIdentifierValue(id);
3816         break;
3817     }
3818     case CSSPropertyFontVariant:
3819         parsedValue = consumeFontVariantList(m_range);
3820         break;
3821     case CSSPropertyFontWeight:
3822         parsedValue = consumeFontWeight(m_range);
3823         break;
3824     case CSSPropertyFontFeatureSettings:
3825         parsedValue = consumeFontFeatureSettings(m_range);
3826         break;
3827     default:
3828         break;
3829     }
3830
3831     if (!parsedValue || !m_range.atEnd())
3832         return false;
3833
3834     addProperty(propId, CSSPropertyInvalid, *parsedValue, false);
3835     return true;
3836 }
3837
3838 bool CSSPropertyParser::consumeSystemFont(bool important)
3839 {
3840     CSSValueID systemFontID = m_range.consumeIncludingWhitespace().id();
3841     ASSERT(systemFontID >= CSSValueCaption && systemFontID <= CSSValueStatusBar);
3842     if (!m_range.atEnd())
3843         return false;
3844     
3845     FontCascadeDescription fontDescription;
3846     RenderTheme::defaultTheme()->systemFont(systemFontID, fontDescription);
3847     if (!fontDescription.isAbsoluteSize())
3848         return false;
3849     
3850