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