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