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