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