[CSS Parser] Fix crash when parsing -webkit-margin-collapse
[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 "CSSParserFastPaths.h"
48 #include "CSSParserIdioms.h"
49 #include "CSSPendingSubstitutionValue.h"
50 #include "CSSPrimitiveValueMappings.h"
51 #include "CSSPropertyParserHelpers.h"
52 #include "CSSReflectValue.h"
53 #include "CSSRevertValue.h"
54 #include "CSSShadowValue.h"
55 #include "CSSTimingFunctionValue.h"
56 #include "CSSUnicodeRangeValue.h"
57 #include "CSSUnsetValue.h"
58 #include "CSSVariableParser.h"
59 #include "CSSVariableReferenceValue.h"
60 #include "Counter.h"
61 #include "FontFace.h"
62 #include "HashTools.h"
63 // FIXME-NEWPARSER: Replace Pair and Rect with actual CSSValue subclasses (CSSValuePair and CSSQuadValue).
64 #include "Pair.h"
65 #include "Rect.h"
66 #include "RenderTheme.h"
67 #include "RuntimeEnabledFeatures.h"
68 #include "SVGPathUtilities.h"
69 #include "StylePropertyShorthand.h"
70 #include "StylePropertyShorthandFunctions.h"
71 #include "WebKitCSSTransformValue.h"
72 #include <memory>
73 #include <wtf/text/StringBuilder.h>
74
75 using namespace WTF;
76
77 namespace WebCore {
78
79 static bool hasPrefix(const char* string, unsigned length, const char* prefix)
80 {
81     for (unsigned i = 0; i < length; ++i) {
82         if (!prefix[i])
83             return true;
84         if (string[i] != prefix[i])
85             return false;
86     }
87     return false;
88 }
89
90 #if PLATFORM(IOS)
91 static void cssPropertyNameIOSAliasing(const char* propertyName, const char*& propertyNameAlias, unsigned& newLength)
92 {
93     if (!strcmp(propertyName, "-webkit-hyphenate-locale")) {
94         // Worked in iOS 4.2.
95         static const char webkitLocale[] = "-webkit-locale";
96         propertyNameAlias = webkitLocale;
97         newLength = strlen(webkitLocale);
98     }
99 }
100 #endif
101
102 template <typename CharacterType>
103 static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length)
104 {
105     char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
106     
107     for (unsigned i = 0; i != length; ++i) {
108         CharacterType c = propertyName[i];
109         if (!c || c >= 0x7F)
110             return CSSPropertyInvalid; // illegal character
111         buffer[i] = toASCIILower(c);
112     }
113     buffer[length] = '\0';
114     
115     const char* name = buffer;
116     if (buffer[0] == '-') {
117 #if ENABLE(LEGACY_CSS_VENDOR_PREFIXES)
118         // If the prefix is -apple- or -khtml-, change it to -webkit-.
119         // This makes the string one character longer.
120         if (RuntimeEnabledFeatures::sharedFeatures().legacyCSSVendorPrefixesEnabled()
121             && (hasPrefix(buffer, length, "-apple-") || hasPrefix(buffer, length, "-khtml-"))) {
122             memmove(buffer + 7, buffer + 6, length + 1 - 6);
123             memcpy(buffer, "-webkit", 7);
124             ++length;
125         }
126 #endif
127 #if PLATFORM(IOS)
128         cssPropertyNameIOSAliasing(buffer, name, length);
129 #endif
130     }
131     
132     const Property* hashTableEntry = findProperty(name, length);
133     return hashTableEntry ? static_cast<CSSPropertyID>(hashTableEntry->id) : CSSPropertyInvalid;
134 }
135
136 static bool isAppleLegacyCssValueKeyword(const char* valueKeyword, unsigned length)
137 {
138     static const char applePrefix[] = "-apple-";
139     static const char appleSystemPrefix[] = "-apple-system";
140     static const char* appleWirelessPlaybackTargetActive = getValueName(CSSValueAppleWirelessPlaybackTargetActive);
141     
142     return hasPrefix(valueKeyword, length, applePrefix)
143     && !hasPrefix(valueKeyword, length, appleSystemPrefix)
144     && !WTF::equal(reinterpret_cast<const LChar*>(valueKeyword), reinterpret_cast<const LChar*>(appleWirelessPlaybackTargetActive), length);
145 }
146
147 template <typename CharacterType>
148 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length)
149 {
150     char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character
151     
152     for (unsigned i = 0; i != length; ++i) {
153         CharacterType c = valueKeyword[i];
154         if (!c || c >= 0x7F)
155             return CSSValueInvalid; // illegal keyword.
156         buffer[i] = WTF::toASCIILower(c);
157     }
158     buffer[length] = '\0';
159     
160     if (buffer[0] == '-') {
161         // If the prefix is -apple- or -khtml-, change it to -webkit-.
162         // This makes the string one character longer.
163         // On iOS we don't want to change values starting with -apple-system to -webkit-system.
164         // FIXME: Remove this mangling without breaking the web.
165         if (isAppleLegacyCssValueKeyword(buffer, length) || hasPrefix(buffer, length, "-khtml-")) {
166             memmove(buffer + 7, buffer + 6, length + 1 - 6);
167             memcpy(buffer, "-webkit", 7);
168             ++length;
169         }
170     }
171     
172     const Value* hashTableEntry = findValue(buffer, length);
173     return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSValueInvalid;
174 }
175
176 CSSValueID cssValueKeywordID(StringView string)
177 {
178     unsigned length = string.length();
179     if (!length)
180         return CSSValueInvalid;
181     if (length > maxCSSValueKeywordLength)
182         return CSSValueInvalid;
183     
184     return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
185 }
186
187 CSSPropertyID cssPropertyID(StringView string)
188 {
189     unsigned length = string.length();
190     
191     if (!length)
192         return CSSPropertyInvalid;
193     if (length > maxCSSPropertyNameLength)
194         return CSSPropertyInvalid;
195     
196     return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length);
197 }
198     
199 using namespace CSSPropertyParserHelpers;
200
201 CSSPropertyParser::CSSPropertyParser(const CSSParserTokenRange& range,
202     const CSSParserContext& context, Vector<CSSProperty, 256>* parsedProperties)
203     : m_range(range)
204     , m_context(context)
205     , m_parsedProperties(parsedProperties)
206 {
207     m_range.consumeWhitespace();
208 }
209
210 void CSSPropertyParser::addProperty(CSSPropertyID property, CSSPropertyID currentShorthand, Ref<CSSValue>&& value, bool important, bool implicit)
211 {
212     int shorthandIndex = 0;
213     bool setFromShorthand = false;
214
215     if (currentShorthand) {
216         auto shorthands = matchingShorthandsForLonghand(property);
217         setFromShorthand = true;
218         if (shorthands.size() > 1)
219             shorthandIndex = indexOfShorthandForLonghand(currentShorthand, shorthands);
220     }
221
222     m_parsedProperties->append(CSSProperty(property, WTFMove(value), important, setFromShorthand, shorthandIndex, implicit));
223 }
224
225 void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID property, Ref<CSSValue>&& value, bool important)
226 {
227     const StylePropertyShorthand& shorthand = shorthandForProperty(property);
228     unsigned shorthandLength = shorthand.length();
229     ASSERT(shorthandLength);
230     const CSSPropertyID* longhands = shorthand.properties();
231     for (unsigned i = 0; i < shorthandLength; ++i)
232         addProperty(longhands[i], property, value.copyRef(), important);
233 }
234     
235 bool CSSPropertyParser::parseValue(CSSPropertyID propertyID, bool important,
236     const CSSParserTokenRange& range, const CSSParserContext& context,
237     ParsedPropertyVector& parsedProperties, StyleRule::Type ruleType)
238 {
239     int parsedPropertiesSize = parsedProperties.size();
240
241     CSSPropertyParser parser(range, context, &parsedProperties);
242     bool parseSuccess;
243
244 #if ENABLE(CSS_DEVICE_ADAPTATION)
245     if (ruleType == StyleRule::Viewport)
246         parseSuccess = parser.parseViewportDescriptor(propertyID, important);
247     else
248 #endif
249     if (ruleType == StyleRule::FontFace)
250         parseSuccess = parser.parseFontFaceDescriptor(propertyID);
251     else
252         parseSuccess = parser.parseValueStart(propertyID, important);
253
254     if (!parseSuccess)
255         parsedProperties.shrink(parsedPropertiesSize);
256
257     return parseSuccess;
258 }
259
260 RefPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID property, const CSSParserTokenRange& range, const CSSParserContext& context)
261 {
262     CSSPropertyParser parser(range, context, nullptr);
263     RefPtr<CSSValue> value = parser.parseSingleValue(property);
264     if (!value || !parser.m_range.atEnd())
265         return nullptr;
266     return value;
267 }
268
269 static bool isLegacyBreakProperty(CSSPropertyID propertyID)
270 {
271     switch (propertyID) {
272     case CSSPropertyPageBreakAfter:
273     case CSSPropertyPageBreakBefore:
274     case CSSPropertyPageBreakInside:
275     case CSSPropertyWebkitColumnBreakAfter:
276     case CSSPropertyWebkitColumnBreakBefore:
277     case CSSPropertyWebkitColumnBreakInside:
278 #if ENABLE(CSS_REGIONS)
279     case CSSPropertyWebkitRegionBreakAfter:
280     case CSSPropertyWebkitRegionBreakBefore:
281     case CSSPropertyWebkitRegionBreakInside:
282 #endif
283         return true;
284     default:
285         break;
286     }
287     return false;
288 }
289
290 bool CSSPropertyParser::parseValueStart(CSSPropertyID propertyID, bool important)
291 {
292     if (consumeCSSWideKeyword(propertyID, important))
293         return true;
294
295     CSSParserTokenRange originalRange = m_range;
296     bool isShorthand = isShorthandCSSProperty(propertyID);
297
298     if (isShorthand) {
299         // Variable references will fail to parse here and will fall out to the variable ref parser below.
300         if (parseShorthand(propertyID, important))
301             return true;
302     } else if (isLegacyBreakProperty(propertyID)) {
303         // FIXME-NEWPARSER: Can turn this into a shorthand once old parser is gone, and then
304         // we don't need the special case.
305         if (consumeLegacyBreakProperty(propertyID, important))
306             return true;
307     } else {
308         RefPtr<CSSValue> parsedValue = parseSingleValue(propertyID);
309         if (parsedValue && m_range.atEnd()) {
310             addProperty(propertyID, CSSPropertyInvalid, *parsedValue, important);
311             return true;
312         }
313     }
314
315     if (CSSVariableParser::containsValidVariableReferences(originalRange)) {
316         RefPtr<CSSVariableReferenceValue> variable = CSSVariableReferenceValue::create(CSSVariableData::create(originalRange));
317
318         if (isShorthand) {
319             RefPtr<CSSPendingSubstitutionValue> pendingValue = CSSPendingSubstitutionValue::create(propertyID, variable.releaseNonNull());
320             addExpandedPropertyForValue(propertyID, pendingValue.releaseNonNull(), important);
321         } else
322             addProperty(propertyID, CSSPropertyInvalid, variable.releaseNonNull(), important);
323         return true;
324     }
325
326     return false;
327 }
328  
329 bool CSSPropertyParser::consumeCSSWideKeyword(CSSPropertyID propertyID, bool important)
330 {
331     CSSParserTokenRange rangeCopy = m_range;
332     CSSValueID valueID = rangeCopy.consumeIncludingWhitespace().id();
333     if (!rangeCopy.atEnd())
334         return false;
335
336     RefPtr<CSSValue> value;
337     if (valueID == CSSValueInherit)
338         value = CSSValuePool::singleton().createInheritedValue();
339     else if (valueID == CSSValueInitial)
340         value = CSSValuePool::singleton().createExplicitInitialValue();
341     else if (valueID == CSSValueUnset)
342         value = CSSValuePool::singleton().createUnsetValue();
343     else if (valueID == CSSValueRevert)
344         value = CSSValuePool::singleton().createRevertValue();
345     else
346         return false;
347     
348     const StylePropertyShorthand& shorthand = shorthandForProperty(propertyID);
349     if (!shorthand.length()) {
350         if (CSSProperty::isDescriptorOnly(propertyID))
351             return false;
352         addProperty(propertyID, CSSPropertyInvalid, value.releaseNonNull(), important);
353     } else
354         addExpandedPropertyForValue(propertyID, value.releaseNonNull(), important);
355     m_range = rangeCopy;
356     return true;
357 }
358
359 static RefPtr<CSSValueList> consumeTransformOrigin(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless)
360 {
361     RefPtr<CSSPrimitiveValue> resultX;
362     RefPtr<CSSPrimitiveValue> resultY;
363     if (consumeOneOrTwoValuedPosition(range, cssParserMode, unitless, resultX, resultY)) {
364         RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
365         list->append(resultX.releaseNonNull());
366         list->append(resultY.releaseNonNull());
367         RefPtr<CSSPrimitiveValue> resultZ = consumeLength(range, cssParserMode, ValueRangeAll);
368         if (!resultZ)
369             resultZ = CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitTypes::CSS_PX);
370         list->append(resultZ.releaseNonNull());
371         return list;
372     }
373     return nullptr;
374 }
375
376 // Methods for consuming non-shorthand properties starts here.
377 static RefPtr<CSSValue> consumeWillChange(CSSParserTokenRange& range)
378 {
379     if (range.peek().id() == CSSValueAuto)
380         return consumeIdent(range);
381
382     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
383     // Every comma-separated list of identifiers is a valid will-change value,
384     // unless the list includes an explicitly disallowed identifier.
385     while (true) {
386         if (range.peek().type() != IdentToken)
387             return nullptr;
388         CSSPropertyID propertyID = cssPropertyID(range.peek().value());
389         if (propertyID != CSSPropertyInvalid) {
390             // Now "all" is used by both CSSValue and CSSPropertyValue.
391             // Need to return nullptr when currentValue is CSSPropertyAll.
392             if (propertyID == CSSPropertyWillChange || propertyID == CSSPropertyAll)
393                 return nullptr;
394             values->append(CSSCustomIdentValue::create(propertyID));
395             range.consumeIncludingWhitespace();
396         } else {
397             switch (range.peek().id()) {
398             case CSSValueNone:
399             case CSSValueAll:
400             case CSSValueAuto:
401             case CSSValueDefault:
402             case CSSValueInitial:
403             case CSSValueInherit:
404                 return nullptr;
405             case CSSValueContents:
406             case CSSValueScrollPosition:
407                 values->append(consumeIdent(range).releaseNonNull());
408                 break;
409             default:
410                 range.consumeIncludingWhitespace();
411                 break;
412             }
413         }
414
415         if (range.atEnd())
416             break;
417         if (!consumeCommaIncludingWhitespace(range))
418             return nullptr;
419     }
420
421     return values;
422 }
423
424 static RefPtr<CSSFontFeatureValue> consumeFontFeatureTag(CSSParserTokenRange& range)
425 {
426     // Feature tag name consists of 4-letter characters.
427     static const unsigned tagNameLength = 4;
428
429     const CSSParserToken& token = range.consumeIncludingWhitespace();
430     // Feature tag name comes first
431     if (token.type() != StringToken)
432         return nullptr;
433     if (token.value().length() != tagNameLength)
434         return nullptr;
435     
436     FontTag tag;
437     for (unsigned i = 0; i < tag.size(); ++i) {
438         // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification.
439         UChar character = token.value()[i];
440         if (character < 0x20 || character > 0x7E)
441             return nullptr;
442         tag[i] = toASCIILower(character);
443     }
444
445     int tagValue = 1;
446     // Feature tag values could follow: <integer> | on | off
447     if (range.peek().type() == NumberToken && range.peek().numericValueType() == IntegerValueType && range.peek().numericValue() >= 0) {
448         tagValue = clampTo<int>(range.consumeIncludingWhitespace().numericValue());
449         if (tagValue < 0)
450             return nullptr;
451     } else if (range.peek().id() == CSSValueOn || range.peek().id() == CSSValueOff) {
452         tagValue = range.consumeIncludingWhitespace().id() == CSSValueOn;
453     }
454     return CSSFontFeatureValue::create(WTFMove(tag), tagValue);
455 }
456
457 static RefPtr<CSSValue> consumeFontFeatureSettings(CSSParserTokenRange& range)
458 {
459     if (range.peek().id() == CSSValueNormal)
460         return consumeIdent(range);
461     RefPtr<CSSValueList> settings = CSSValueList::createCommaSeparated();
462     do {
463         RefPtr<CSSFontFeatureValue> fontFeatureValue = consumeFontFeatureTag(range);
464         if (!fontFeatureValue)
465             return nullptr;
466         settings->append(fontFeatureValue.releaseNonNull());
467     } while (consumeCommaIncludingWhitespace(range));
468     return settings;
469 }
470
471 static RefPtr<CSSValue> consumePage(CSSParserTokenRange& range)
472 {
473     if (range.peek().id() == CSSValueAuto)
474         return consumeIdent(range);
475     return consumeCustomIdent(range);
476 }
477
478 static RefPtr<CSSValue> consumeQuotes(CSSParserTokenRange& range)
479 {
480     if (range.peek().id() == CSSValueNone)
481         return consumeIdent(range);
482     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
483     while (!range.atEnd()) {
484         RefPtr<CSSPrimitiveValue> parsedValue = consumeString(range);
485         if (!parsedValue)
486             return nullptr;
487         values->append(parsedValue.releaseNonNull());
488     }
489     if (values->length() && values->length() % 2 == 0)
490         return values;
491     return nullptr;
492 }
493
494 class FontVariantLigaturesParser {
495 public:
496     FontVariantLigaturesParser()
497         : m_sawCommonLigaturesValue(false)
498         , m_sawDiscretionaryLigaturesValue(false)
499         , m_sawHistoricalLigaturesValue(false)
500         , m_sawContextualLigaturesValue(false)
501         , m_result(CSSValueList::createSpaceSeparated())
502     {
503     }
504
505     enum class ParseResult {
506         ConsumedValue,
507         DisallowedValue,
508         UnknownValue
509     };
510
511     ParseResult consumeLigature(CSSParserTokenRange& range)
512     {
513         CSSValueID valueID = range.peek().id();
514         switch (valueID) {
515         case CSSValueNoCommonLigatures:
516         case CSSValueCommonLigatures:
517             if (m_sawCommonLigaturesValue)
518                 return ParseResult::DisallowedValue;
519             m_sawCommonLigaturesValue = true;
520             break;
521         case CSSValueNoDiscretionaryLigatures:
522         case CSSValueDiscretionaryLigatures:
523             if (m_sawDiscretionaryLigaturesValue)
524                 return ParseResult::DisallowedValue;
525             m_sawDiscretionaryLigaturesValue = true;
526             break;
527         case CSSValueNoHistoricalLigatures:
528         case CSSValueHistoricalLigatures:
529             if (m_sawHistoricalLigaturesValue)
530                 return ParseResult::DisallowedValue;
531             m_sawHistoricalLigaturesValue = true;
532             break;
533         case CSSValueNoContextual:
534         case CSSValueContextual:
535             if (m_sawContextualLigaturesValue)
536                 return ParseResult::DisallowedValue;
537             m_sawContextualLigaturesValue = true;
538             break;
539         default:
540             return ParseResult::UnknownValue;
541         }
542         m_result->append(consumeIdent(range).releaseNonNull());
543         return ParseResult::ConsumedValue;
544     }
545
546     RefPtr<CSSValue> finalizeValue()
547     {
548         if (!m_result->length())
549             return CSSValuePool::singleton().createIdentifierValue(CSSValueNormal);
550         return m_result.release();
551     }
552
553 private:
554     bool m_sawCommonLigaturesValue;
555     bool m_sawDiscretionaryLigaturesValue;
556     bool m_sawHistoricalLigaturesValue;
557     bool m_sawContextualLigaturesValue;
558     RefPtr<CSSValueList> m_result;
559 };
560
561 static RefPtr<CSSValue> consumeFontVariantLigatures(CSSParserTokenRange& range)
562 {
563     if (range.peek().id() == CSSValueNormal || range.peek().id() == CSSValueNone)
564         return consumeIdent(range);
565
566     FontVariantLigaturesParser ligaturesParser;
567     do {
568         if (ligaturesParser.consumeLigature(range) !=
569             FontVariantLigaturesParser::ParseResult::ConsumedValue)
570             return nullptr;
571     } while (!range.atEnd());
572
573     return ligaturesParser.finalizeValue();
574 }
575
576 static RefPtr<CSSPrimitiveValue> consumeFontVariantCaps(CSSParserTokenRange& range)
577 {
578     return consumeIdent<CSSValueNormal, CSSValueSmallCaps, CSSValueAllSmallCaps,
579         CSSValuePetiteCaps, CSSValueAllPetiteCaps,
580         CSSValueUnicase, CSSValueTitlingCaps>(range);
581 }
582
583 class FontVariantNumericParser {
584 public:
585     FontVariantNumericParser()
586         : m_sawNumericFigureValue(false)
587         , m_sawNumericSpacingValue(false)
588         , m_sawNumericFractionValue(false)
589         , m_sawOrdinalValue(false)
590         , m_sawSlashedZeroValue(false)
591         , m_result(CSSValueList::createSpaceSeparated())
592     {
593     }
594
595     enum class ParseResult {
596         ConsumedValue,
597         DisallowedValue,
598         UnknownValue
599     };
600
601     ParseResult consumeNumeric(CSSParserTokenRange& range)
602     {
603         CSSValueID valueID = range.peek().id();
604         switch (valueID) {
605         case CSSValueLiningNums:
606         case CSSValueOldstyleNums:
607             if (m_sawNumericFigureValue)
608                 return ParseResult::DisallowedValue;
609             m_sawNumericFigureValue = true;
610             break;
611         case CSSValueProportionalNums:
612         case CSSValueTabularNums:
613             if (m_sawNumericSpacingValue)
614                 return ParseResult::DisallowedValue;
615             m_sawNumericSpacingValue = true;
616             break;
617         case CSSValueDiagonalFractions:
618         case CSSValueStackedFractions:
619             if (m_sawNumericFractionValue)
620                 return ParseResult::DisallowedValue;
621             m_sawNumericFractionValue = true;
622             break;
623         case CSSValueOrdinal:
624             if (m_sawOrdinalValue)
625                 return ParseResult::DisallowedValue;
626             m_sawOrdinalValue = true;
627             break;
628         case CSSValueSlashedZero:
629             if (m_sawSlashedZeroValue)
630                 return ParseResult::DisallowedValue;
631             m_sawSlashedZeroValue = true;
632             break;
633         default:
634             return ParseResult::UnknownValue;
635         }
636         m_result->append(consumeIdent(range).releaseNonNull());
637         return ParseResult::ConsumedValue;
638     }
639
640     RefPtr<CSSValue> finalizeValue()
641     {
642         if (!m_result->length())
643             return CSSValuePool::singleton().createIdentifierValue(CSSValueNormal);
644         return m_result.release();
645     }
646
647
648 private:
649     bool m_sawNumericFigureValue;
650     bool m_sawNumericSpacingValue;
651     bool m_sawNumericFractionValue;
652     bool m_sawOrdinalValue;
653     bool m_sawSlashedZeroValue;
654     RefPtr<CSSValueList> m_result;
655 };
656
657 static RefPtr<CSSValue> consumeFontVariantNumeric(CSSParserTokenRange& range)
658 {
659     if (range.peek().id() == CSSValueNormal)
660         return consumeIdent(range);
661
662     FontVariantNumericParser numericParser;
663     do {
664         if (numericParser.consumeNumeric(range) !=
665             FontVariantNumericParser::ParseResult::ConsumedValue)
666             return nullptr;
667     } while (!range.atEnd());
668
669     return numericParser.finalizeValue();
670 }
671
672 static RefPtr<CSSPrimitiveValue> consumeFontVariantCSS21(CSSParserTokenRange& range)
673 {
674     return consumeIdent<CSSValueNormal, CSSValueSmallCaps>(range);
675 }
676
677 static RefPtr<CSSValue> consumeFontVariantList(CSSParserTokenRange& range)
678 {
679     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
680     do {
681         if (range.peek().id() == CSSValueAll) {
682             // FIXME: CSSPropertyParser::parseFontVariant() implements
683             // the old css3 draft:
684             // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#font-variant
685             // 'all' is only allowed in @font-face and with no other values.
686             if (values->length())
687                 return nullptr;
688             return consumeIdent(range);
689         }
690         RefPtr<CSSPrimitiveValue> fontVariant = consumeFontVariantCSS21(range);
691         if (fontVariant)
692             values->append(fontVariant.releaseNonNull());
693     } while (consumeCommaIncludingWhitespace(range));
694
695     if (values->length())
696         return values;
697
698     return nullptr;
699 }
700
701 static RefPtr<CSSPrimitiveValue> consumeFontWeight(CSSParserTokenRange& range)
702 {
703     const CSSParserToken& token = range.peek();
704     if (token.id() >= CSSValueNormal && token.id() <= CSSValueLighter)
705         return consumeIdent(range);
706     if (token.type() != NumberToken || token.numericValueType() != IntegerValueType)
707         return nullptr;
708     int weight = static_cast<int>(token.numericValue());
709     if ((weight % 100) || weight < 100 || weight > 900)
710         return nullptr;
711     range.consumeIncludingWhitespace();
712     return CSSValuePool::singleton().createIdentifierValue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1));
713 }
714
715 static String concatenateFamilyName(CSSParserTokenRange& range)
716 {
717     StringBuilder builder;
718     bool addedSpace = false;
719     const CSSParserToken& firstToken = range.peek();
720     while (range.peek().type() == IdentToken) {
721         if (!builder.isEmpty()) {
722             builder.append(' ');
723             addedSpace = true;
724         }
725         builder.append(range.consumeIncludingWhitespace().value());
726     }
727     if (!addedSpace && isCSSWideKeyword(firstToken.id()))
728         return String();
729     return builder.toString();
730 }
731
732 static RefPtr<CSSValue> consumeFamilyName(CSSParserTokenRange& range)
733 {
734     if (range.peek().type() == StringToken)
735         return CSSValuePool::singleton().createFontFamilyValue(range.consumeIncludingWhitespace().value().toString());
736     if (range.peek().type() != IdentToken)
737         return nullptr;
738     String familyName = concatenateFamilyName(range);
739     if (familyName.isNull())
740         return nullptr;
741     return CSSValuePool::singleton().createFontFamilyValue(familyName);
742 }
743
744 static RefPtr<CSSValue> consumeGenericFamily(CSSParserTokenRange& range)
745 {
746     return consumeIdentRange(range, CSSValueSerif, CSSValueWebkitBody);
747 }
748
749 static RefPtr<CSSValueList> consumeFontFamily(CSSParserTokenRange& range)
750 {
751     RefPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
752     do {
753         RefPtr<CSSValue> parsedValue = consumeGenericFamily(range);
754         if (parsedValue) {
755             list->append(parsedValue.releaseNonNull());
756         } else {
757             parsedValue = consumeFamilyName(range);
758             if (parsedValue) {
759                 list->append(parsedValue.releaseNonNull());
760             } else {
761                 return nullptr;
762             }
763         }
764     } while (consumeCommaIncludingWhitespace(range));
765     return list;
766 }
767
768 static RefPtr<CSSValue> consumeSpacing(CSSParserTokenRange& range, CSSParserMode cssParserMode)
769 {
770     if (range.peek().id() == CSSValueNormal)
771         return consumeIdent(range);
772     // FIXME: allow <percentage>s in word-spacing.
773     return consumeLength(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow);
774 }
775
776 static RefPtr<CSSValue> consumeTabSize(CSSParserTokenRange& range, CSSParserMode cssParserMode)
777 {
778     RefPtr<CSSPrimitiveValue> parsedValue = consumeInteger(range, 0);
779     if (parsedValue)
780         return parsedValue;
781     return consumeLength(range, cssParserMode, ValueRangeNonNegative);
782 }
783
784 #if ENABLE(TEXT_AUTOSIZING)
785 static RefPtr<CSSValue> consumeTextSizeAdjust(CSSParserTokenRange& range, CSSParserMode /* cssParserMode */)
786 {
787     if (range.peek().id() == CSSValueAuto)
788         return consumeIdent(range);
789     if (range.peek().id() == CSSValueNone)
790         return consumeIdent(range);
791     return consumePercent(range, ValueRangeNonNegative);
792 }
793 #endif
794
795 static RefPtr<CSSValue> consumeFontSize(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless = UnitlessQuirk::Forbid)
796 {
797     if (range.peek().id() >= CSSValueXxSmall && range.peek().id() <= CSSValueLarger)
798         return consumeIdent(range);
799     return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative, unitless);
800 }
801
802 static RefPtr<CSSPrimitiveValue> consumeLineHeight(CSSParserTokenRange& range, CSSParserMode cssParserMode)
803 {
804     if (range.peek().id() == CSSValueNormal)
805         return consumeIdent(range);
806
807     RefPtr<CSSPrimitiveValue> lineHeight = consumeNumber(range, ValueRangeNonNegative);
808     if (lineHeight)
809         return lineHeight;
810     return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
811 }
812
813 template<typename... Args>
814 static Ref<CSSPrimitiveValue> createPrimitiveValuePair(Args&&... args)
815 {
816     return CSSValuePool::singleton().createValue(Pair::create(std::forward<Args>(args)...));
817 }
818
819 static RefPtr<CSSValue> consumeCounter(CSSParserTokenRange& range, int defaultValue)
820 {
821     if (range.peek().id() == CSSValueNone)
822         return consumeIdent(range);
823
824     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
825     do {
826         RefPtr<CSSPrimitiveValue> counterName = consumeCustomIdent(range);
827         if (!counterName)
828             return nullptr;
829         int i = defaultValue;
830         if (RefPtr<CSSPrimitiveValue> counterValue = consumeInteger(range))
831             i = counterValue->intValue();
832         list->append(createPrimitiveValuePair(counterName.releaseNonNull(), CSSPrimitiveValue::create(i, CSSPrimitiveValue::UnitTypes::CSS_NUMBER), Pair::IdenticalValueEncoding::Coalesce));
833     } while (!range.atEnd());
834     return list;
835 }
836
837 static RefPtr<CSSValue> consumePageSize(CSSParserTokenRange& range)
838 {
839     return consumeIdent<CSSValueA3, CSSValueA4, CSSValueA5, CSSValueB4, CSSValueB5, CSSValueLedger, CSSValueLegal, CSSValueLetter>(range);
840 }
841
842 static RefPtr<CSSValueList> consumeSize(CSSParserTokenRange& range, CSSParserMode cssParserMode)
843 {
844     RefPtr<CSSValueList> result = CSSValueList::createSpaceSeparated();
845
846     if (range.peek().id() == CSSValueAuto) {
847         result->append(consumeIdent(range).releaseNonNull());
848         return result;
849     }
850
851     if (RefPtr<CSSValue> width = consumeLength(range, cssParserMode, ValueRangeNonNegative)) {
852         RefPtr<CSSValue> height = consumeLength(range, cssParserMode, ValueRangeNonNegative);
853         result->append(width.releaseNonNull());
854         if (height)
855             result->append(height.releaseNonNull());
856         return result;
857     }
858
859     RefPtr<CSSValue> pageSize = consumePageSize(range);
860     RefPtr<CSSValue> orientation = consumeIdent<CSSValuePortrait, CSSValueLandscape>(range);
861     if (!pageSize)
862         pageSize = consumePageSize(range);
863
864     if (!orientation && !pageSize)
865         return nullptr;
866     if (pageSize)
867         result->append(pageSize.releaseNonNull());
868     if (orientation)
869         result->append(orientation.releaseNonNull());
870     return result;
871 }
872
873 static RefPtr<CSSValue> consumeTextIndent(CSSParserTokenRange& range, CSSParserMode cssParserMode)
874 {
875     // [ <length> | <percentage> ] && hanging? && each-line?
876     // Keywords only allowed when css3Text is enabled.
877     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
878
879     bool hasLengthOrPercentage = false;
880 //    bool hasEachLine = false;
881     bool hasHanging = false;
882
883     do {
884         if (!hasLengthOrPercentage) {
885             if (RefPtr<CSSValue> textIndent = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Allow)) {
886                 list->append(*textIndent);
887                 hasLengthOrPercentage = true;
888                 continue;
889             }
890         }
891
892         CSSValueID id = range.peek().id();
893  /* FIXME-NEWPARSER: We don't support this yet.
894         if (!hasEachLine && id == CSSValueEachLine) {
895             list->append(*consumeIdent(range));
896             hasEachLine = true;
897             continue;
898         }
899 */
900         
901         if (!hasHanging && id == CSSValueHanging) {
902             list->append(consumeIdent(range).releaseNonNull());
903             hasHanging = true;
904             continue;
905         }
906         
907         return nullptr;
908     } while (!range.atEnd());
909
910     if (!hasLengthOrPercentage)
911         return nullptr;
912
913     return list;
914 }
915
916 // FIXME-NEWPARSER: Drop the prefix on min-content, max-content and fit-content.
917 static bool validWidthOrHeightKeyword(CSSValueID id, const CSSParserContext& /*context*/)
918 {
919     if (id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent
920         || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || 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 || !args.atEnd())
2206         return nullptr;
2207     range = rangeCopy;
2208     
2209     return CSSValuePool::singleton().createValue(shape.releaseNonNull());
2210 }
2211
2212 static RefPtr<CSSValue> consumeWebkitClipPath(CSSParserTokenRange& range, const CSSParserContext& context)
2213 {
2214     if (range.peek().id() == CSSValueNone)
2215         return consumeIdent(range);
2216     if (RefPtr<CSSPrimitiveValue> url = consumeUrl(range))
2217         return url;
2218     return consumeBasicShape(range, context);
2219 }
2220
2221 static RefPtr<CSSValue> consumeShapeOutside(CSSParserTokenRange& range, const CSSParserContext& context)
2222 {
2223     if (RefPtr<CSSValue> imageValue = consumeImageOrNone(range, context))
2224         return imageValue;
2225     RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
2226     if (RefPtr<CSSValue> boxValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox>(range))
2227         list->append(boxValue.releaseNonNull());
2228     if (RefPtr<CSSValue> shapeValue = consumeBasicShape(range, context)) {
2229         list->append(shapeValue.releaseNonNull());
2230         if (list->length() < 2) {
2231             if (RefPtr<CSSValue> boxValue = consumeIdent<CSSValueContentBox, CSSValuePaddingBox, CSSValueBorderBox, CSSValueMarginBox>(range))
2232                 list->append(boxValue.releaseNonNull());
2233         }
2234     }
2235     if (!list->length())
2236         return nullptr;
2237     return list;
2238 }
2239
2240 static RefPtr<CSSValue> consumeContentDistributionOverflowPosition(CSSParserTokenRange& range)
2241 {
2242     if (identMatches<CSSValueNormal, CSSValueBaseline, CSSValueLastBaseline>(range.peek().id()))
2243         return CSSContentDistributionValue::create(CSSValueInvalid, range.consumeIncludingWhitespace().id(), CSSValueInvalid);
2244
2245     CSSValueID distribution = CSSValueInvalid;
2246     CSSValueID position = CSSValueInvalid;
2247     CSSValueID overflow = CSSValueInvalid;
2248     do {
2249         CSSValueID id = range.peek().id();
2250         if (identMatches<CSSValueSpaceBetween, CSSValueSpaceAround, CSSValueSpaceEvenly, CSSValueStretch>(id)) {
2251             if (distribution != CSSValueInvalid)
2252                 return nullptr;
2253             distribution = id;
2254         } else if (identMatches<CSSValueStart, CSSValueEnd, CSSValueCenter, CSSValueFlexStart, CSSValueFlexEnd, CSSValueLeft, CSSValueRight>(id)) {
2255             if (position != CSSValueInvalid)
2256                 return nullptr;
2257             position = id;
2258         } else if (identMatches<CSSValueUnsafe, CSSValueSafe>(id)) {
2259             if (overflow != CSSValueInvalid)
2260                 return nullptr;
2261             overflow = id;
2262         } else {
2263             return nullptr;
2264         }
2265         range.consumeIncludingWhitespace();
2266     } while (!range.atEnd());
2267
2268     // The grammar states that we should have at least <content-distribution> or <content-position>.
2269     if (position == CSSValueInvalid && distribution == CSSValueInvalid)
2270         return nullptr;
2271
2272     // The grammar states that <overflow-position> must be associated to <content-position>.
2273     if (overflow != CSSValueInvalid && position == CSSValueInvalid)
2274         return nullptr;
2275
2276     return CSSContentDistributionValue::create(distribution, position, overflow);
2277 }
2278
2279 static RefPtr<CSSPrimitiveValue> consumeBorderImageRepeatKeyword(CSSParserTokenRange& range)
2280 {
2281     return consumeIdent<CSSValueStretch, CSSValueRepeat, CSSValueSpace, CSSValueRound>(range);
2282 }
2283
2284 static RefPtr<CSSValue> consumeBorderImageRepeat(CSSParserTokenRange& range)
2285 {
2286     RefPtr<CSSPrimitiveValue> horizontal = consumeBorderImageRepeatKeyword(range);
2287     if (!horizontal)
2288         return nullptr;
2289     RefPtr<CSSPrimitiveValue> vertical = consumeBorderImageRepeatKeyword(range);
2290     if (!vertical)
2291         vertical = horizontal;
2292     return createPrimitiveValuePair(horizontal.releaseNonNull(), vertical.releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce);
2293 }
2294
2295 static RefPtr<CSSValue> consumeBorderImageSlice(CSSPropertyID property, CSSParserTokenRange& range)
2296 {
2297     bool fill = consumeIdent<CSSValueFill>(range);
2298     RefPtr<CSSPrimitiveValue> slices[4] = { 0 };
2299
2300     for (size_t index = 0; index < 4; ++index) {
2301         RefPtr<CSSPrimitiveValue> value = consumePercent(range, ValueRangeNonNegative);
2302         if (!value)
2303             value = consumeNumber(range, ValueRangeNonNegative);
2304         if (!value)
2305             break;
2306         slices[index] = value;
2307     }
2308     if (!slices[0])
2309         return nullptr;
2310     if (consumeIdent<CSSValueFill>(range)) {
2311         if (fill)
2312             return nullptr;
2313         fill = true;
2314     }
2315     complete4Sides(slices);
2316     // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mask-box-image and -webkit-box-reflect have to do a fill by default.
2317     // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-image? Probably just have to leave them filling...
2318     if (property == CSSPropertyWebkitBorderImage || property == CSSPropertyWebkitMaskBoxImage || property == CSSPropertyWebkitBoxReflect)
2319         fill = true;
2320     
2321     // Now build a rect value to hold all four of our primitive values.
2322     // FIXME-NEWPARSER: Should just have a CSSQuadValue.
2323     auto quad = Quad::create();
2324     quad->setTop(slices[0].releaseNonNull());
2325     quad->setRight(slices[1].releaseNonNull());
2326     quad->setBottom(slices[2].releaseNonNull());
2327     quad->setLeft(slices[3].releaseNonNull());
2328     
2329     // Make our new border image value now.
2330     return CSSBorderImageSliceValue::create(CSSValuePool::singleton().createValue(WTFMove(quad)), fill);
2331 }
2332
2333 static RefPtr<CSSValue> consumeBorderImageOutset(CSSParserTokenRange& range)
2334 {
2335     RefPtr<CSSPrimitiveValue> outsets[4] = { 0 };
2336
2337     RefPtr<CSSPrimitiveValue> value;
2338     for (size_t index = 0; index < 4; ++index) {
2339         value = consumeNumber(range, ValueRangeNonNegative);
2340         if (!value)
2341             value = consumeLength(range, HTMLStandardMode, ValueRangeNonNegative);
2342         if (!value)
2343             break;
2344         outsets[index] = value;
2345     }
2346     if (!outsets[0])
2347         return nullptr;
2348     complete4Sides(outsets);
2349     
2350     // FIXME-NEWPARSER: Should just have a CSSQuadValue.
2351     auto quad = Quad::create();
2352     quad->setTop(outsets[0].releaseNonNull());
2353     quad->setRight(outsets[1].releaseNonNull());
2354     quad->setBottom(outsets[2].releaseNonNull());
2355     quad->setLeft(outsets[3].releaseNonNull());
2356     
2357     return CSSValuePool::singleton().createValue(WTFMove(quad));
2358 }
2359
2360 static RefPtr<CSSValue> consumeBorderImageWidth(CSSParserTokenRange& range)
2361 {
2362     RefPtr<CSSPrimitiveValue> widths[4];
2363
2364     RefPtr<CSSPrimitiveValue> value;
2365     for (size_t index = 0; index < 4; ++index) {
2366         value = consumeNumber(range, ValueRangeNonNegative);
2367         if (!value)
2368             value = consumeLengthOrPercent(range, HTMLStandardMode, ValueRangeNonNegative, UnitlessQuirk::Forbid);
2369         if (!value)
2370             value = consumeIdent<CSSValueAuto>(range);
2371         if (!value)
2372             break;
2373         widths[index] = value;
2374     }
2375     if (!widths[0])
2376         return nullptr;
2377     complete4Sides(widths);
2378     
2379     // FIXME-NEWPARSER: Should just have a CSSQuadValue.
2380     auto quad = Quad::create();
2381     quad->setTop(widths[0].releaseNonNull());
2382     quad->setRight(widths[1].releaseNonNull());
2383     quad->setBottom(widths[2].releaseNonNull());
2384     quad->setLeft(widths[3].releaseNonNull());
2385     
2386     return CSSValuePool::singleton().createValue(WTFMove(quad));
2387 }
2388
2389 static bool consumeBorderImageComponents(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context, RefPtr<CSSValue>& source,
2390     RefPtr<CSSValue>& slice, RefPtr<CSSValue>& width, RefPtr<CSSValue>& outset, RefPtr<CSSValue>& repeat)
2391 {
2392     do {
2393         if (!source) {
2394             source = consumeImageOrNone(range, context);
2395             if (source)
2396                 continue;
2397         }
2398         if (!repeat) {
2399             repeat = consumeBorderImageRepeat(range);
2400             if (repeat)
2401                 continue;
2402         }
2403         if (!slice) {
2404             slice = consumeBorderImageSlice(property, range);
2405             if (slice) {
2406                 ASSERT(!width && !outset);
2407                 if (consumeSlashIncludingWhitespace(range)) {
2408                     width = consumeBorderImageWidth(range);
2409                     if (consumeSlashIncludingWhitespace(range)) {
2410                         outset = consumeBorderImageOutset(range);
2411                         if (!outset)
2412                             return false;
2413                     } else if (!width) {
2414                         return false;
2415                     }
2416                 }
2417             } else {
2418                 return false;
2419             }
2420         } else {
2421             return false;
2422         }
2423     } while (!range.atEnd());
2424     return true;
2425 }
2426
2427 static RefPtr<CSSValue> consumeWebkitBorderImage(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
2428 {
2429     RefPtr<CSSValue> source;
2430     RefPtr<CSSValue> slice;
2431     RefPtr<CSSValue> width;
2432     RefPtr<CSSValue> outset;
2433     RefPtr<CSSValue> repeat;
2434     if (consumeBorderImageComponents(property, range, context, source, slice, width, outset, repeat))
2435         return createBorderImageValue(WTFMove(source), WTFMove(slice), WTFMove(width), WTFMove(outset), WTFMove(repeat));
2436     return nullptr;
2437 }
2438
2439 static RefPtr<CSSValue> consumeReflect(CSSParserTokenRange& range, const CSSParserContext& context)
2440 {
2441     RefPtr<CSSPrimitiveValue> direction = consumeIdent<CSSValueAbove, CSSValueBelow, CSSValueLeft, CSSValueRight>(range);
2442     if (!direction)
2443         return nullptr;
2444
2445     RefPtr<CSSPrimitiveValue> offset;
2446     if (range.atEnd())
2447         offset = CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitTypes::CSS_PX);
2448     else {
2449         offset = consumeLengthOrPercent(range, context.mode, ValueRangeAll, UnitlessQuirk::Forbid);
2450         if (!offset)
2451             return nullptr;
2452     }
2453
2454     RefPtr<CSSValue> mask;
2455     if (!range.atEnd()) {
2456         mask = consumeWebkitBorderImage(CSSPropertyWebkitBoxReflect, range, context);
2457         if (!mask)
2458             return nullptr;
2459     }
2460     return CSSReflectValue::create(direction.releaseNonNull(), offset.releaseNonNull(), mask.releaseNonNull());
2461 }
2462
2463 #if ENABLE(CSS_IMAGE_ORIENTATION)
2464 static RefPtr<CSSValue> consumeImageOrientation(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless = UnitlessQuirk::Forbid)
2465 {
2466     if (range.peek().type() != NumberToken) {
2467         RefPtr<CSSPrimitiveValue> angle = consumeAngle(range, cssParserMode, unitless);
2468         if (angle && angle->doubleValue() == 0)
2469             return angle;
2470     }
2471     return nullptr;
2472 }
2473 #endif
2474
2475 static RefPtr<CSSPrimitiveValue> consumeBackgroundBlendMode(CSSParserTokenRange& range)
2476 {
2477     CSSValueID id = range.peek().id();
2478     if (id == CSSValueNormal || id == CSSValueOverlay || (id >= CSSValueMultiply && id <= CSSValueLuminosity))
2479         return consumeIdent(range);
2480     return nullptr;
2481 }
2482
2483 static RefPtr<CSSPrimitiveValue> consumeBackgroundAttachment(CSSParserTokenRange& range)
2484 {
2485     return consumeIdent<CSSValueScroll, CSSValueFixed, CSSValueLocal>(range);
2486 }
2487
2488 static RefPtr<CSSPrimitiveValue> consumeBackgroundBox(CSSParserTokenRange& range)
2489 {
2490     return consumeIdent<CSSValueBorderBox, CSSValuePaddingBox, CSSValueContentBox>(range);
2491 }
2492
2493 static RefPtr<CSSPrimitiveValue> consumeBackgroundComposite(CSSParserTokenRange& range)
2494 {
2495     return consumeIdentRange(range, CSSValueClear, CSSValuePlusLighter);
2496 }
2497
2498 static RefPtr<CSSPrimitiveValue> consumePrefixedBackgroundBox(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& /*context*/)
2499 {
2500     // The values 'border', 'padding' and 'content' are deprecated and do not apply to the version of the property that has the -webkit- prefix removed.
2501     if (RefPtr<CSSPrimitiveValue> value = consumeIdentRange(range, CSSValueBorder, CSSValuePaddingBox))
2502         return value;
2503     if ((property == CSSPropertyWebkitBackgroundClip || property == CSSPropertyWebkitMaskClip) && range.peek().id() == CSSValueText)
2504         return consumeIdent(range);
2505     return nullptr;
2506 }
2507
2508 static RefPtr<CSSPrimitiveValue> consumeBackgroundSize(CSSPropertyID property, CSSParserTokenRange& range, CSSParserMode cssParserMode)
2509 {
2510     if (identMatches<CSSValueContain, CSSValueCover>(range.peek().id()))
2511         return consumeIdent(range);
2512
2513     RefPtr<CSSPrimitiveValue> horizontal = consumeIdent<CSSValueAuto>(range);
2514     if (!horizontal)
2515         horizontal = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Forbid);
2516
2517     RefPtr<CSSPrimitiveValue> vertical;
2518     if (!range.atEnd()) {
2519         if (range.peek().id() == CSSValueAuto) // `auto' is the default
2520             range.consumeIncludingWhitespace();
2521         else
2522             vertical = consumeLengthOrPercent(range, cssParserMode, ValueRangeAll, UnitlessQuirk::Forbid);
2523     } else if (!vertical && property == CSSPropertyWebkitBackgroundSize) {
2524         // Legacy syntax: "-webkit-background-size: 10px" is equivalent to "background-size: 10px 10px".
2525         vertical = horizontal;
2526     }
2527     if (!vertical)
2528         return horizontal;
2529     return createPrimitiveValuePair(horizontal.releaseNonNull(), vertical.releaseNonNull(), Pair::IdenticalValueEncoding::DoNotCoalesce);
2530 }
2531
2532 static RefPtr<CSSValueList> consumeGridAutoFlow(CSSParserTokenRange& range)
2533 {
2534     RefPtr<CSSPrimitiveValue> rowOrColumnValue = consumeIdent<CSSValueRow, CSSValueColumn>(range);
2535     RefPtr<CSSPrimitiveValue> denseAlgorithm = consumeIdent<CSSValueDense>(range);
2536     if (!rowOrColumnValue) {
2537         rowOrColumnValue = consumeIdent<CSSValueRow, CSSValueColumn>(range);
2538         if (!rowOrColumnValue && !denseAlgorithm)
2539             return nullptr;
2540     }
2541     RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
2542     if (rowOrColumnValue)
2543         parsedValues->append(rowOrColumnValue.releaseNonNull());
2544     if (denseAlgorithm)
2545         parsedValues->append(denseAlgorithm.releaseNonNull());
2546     return parsedValues;
2547 }
2548
2549 static RefPtr<CSSValue> consumeBackgroundComponent(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
2550 {
2551     switch (property) {
2552     case CSSPropertyBackgroundClip:
2553         return consumeBackgroundBox(range);
2554     case CSSPropertyBackgroundBlendMode:
2555         return consumeBackgroundBlendMode(range);
2556     case CSSPropertyBackgroundAttachment:
2557         return consumeBackgroundAttachment(range);
2558     case CSSPropertyBackgroundOrigin:
2559         return consumeBackgroundBox(range);
2560     case CSSPropertyWebkitMaskComposite:
2561         return consumeBackgroundComposite(range);
2562     case CSSPropertyWebkitBackgroundClip:
2563     case CSSPropertyWebkitBackgroundOrigin:
2564     case CSSPropertyWebkitMaskClip:
2565     case CSSPropertyWebkitMaskOrigin:
2566         return consumePrefixedBackgroundBox(property, range, context);
2567     case CSSPropertyBackgroundImage:
2568     case CSSPropertyWebkitMaskImage:
2569         return consumeImageOrNone(range, context);
2570     case CSSPropertyBackgroundPositionX:
2571     case CSSPropertyWebkitMaskPositionX:
2572         return consumePositionX(range, context.mode);
2573     case CSSPropertyBackgroundPositionY:
2574     case CSSPropertyWebkitMaskPositionY:
2575         return consumePositionY(range, context.mode);
2576     case CSSPropertyBackgroundSize:
2577     case CSSPropertyWebkitBackgroundSize:
2578     case CSSPropertyWebkitMaskSize:
2579         return consumeBackgroundSize(property, range, context.mode);
2580     case CSSPropertyBackgroundColor:
2581         return consumeColor(range, context.mode);
2582     default:
2583         break;
2584     };
2585     return nullptr;
2586 }
2587
2588 static void addBackgroundValue(RefPtr<CSSValue>& list, Ref<CSSValue>&& value)
2589 {
2590     if (list) {
2591         if (!list->isBaseValueList()) {
2592             RefPtr<CSSValue> firstValue = list;
2593             list = CSSValueList::createCommaSeparated();
2594             downcast<CSSValueList>(*list).append(firstValue.releaseNonNull());
2595         }
2596         downcast<CSSValueList>(*list).append(WTFMove(value));
2597     } else {
2598         // To conserve memory we don't actually wrap a single value in a list.
2599         list = WTFMove(value);
2600     }
2601 }
2602
2603 static RefPtr<CSSValue> consumeCommaSeparatedBackgroundComponent(CSSPropertyID property, CSSParserTokenRange& range, const CSSParserContext& context)
2604 {
2605     RefPtr<CSSValue> result;
2606     do {
2607         RefPtr<CSSValue> value = consumeBackgroundComponent(property, range, context);
2608         if (!value)
2609             return nullptr;
2610         addBackgroundValue(result, value.releaseNonNull());
2611     } while (consumeCommaIncludingWhitespace(range));
2612     return result;
2613 }
2614
2615 static RefPtr<CSSPrimitiveValue> consumeSelfPositionKeyword(CSSParserTokenRange& range)
2616 {
2617     CSSValueID id = range.peek().id();
2618     if (id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
2619         || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFlexStart
2620         || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight)
2621         return consumeIdent(range);
2622     return nullptr;
2623 }
2624
2625 static RefPtr<CSSValue> consumeSelfPositionOverflowPosition(CSSParserTokenRange& range)
2626 {
2627     if (identMatches<CSSValueAuto, CSSValueNormal, CSSValueStretch, CSSValueBaseline, CSSValueLastBaseline>(range.peek().id()))
2628         return consumeIdent(range);
2629
2630     RefPtr<CSSPrimitiveValue> overflowPosition = consumeIdent<CSSValueUnsafe, CSSValueSafe>(range);
2631     RefPtr<CSSPrimitiveValue> selfPosition = consumeSelfPositionKeyword(range);
2632     if (!selfPosition)
2633         return nullptr;
2634     if (!overflowPosition)
2635         overflowPosition = consumeIdent<CSSValueUnsafe, CSSValueSafe>(range);
2636     if (overflowPosition)
2637         return createPrimitiveValuePair(selfPosition.releaseNonNull(), overflowPosition.releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce);
2638     return selfPosition;
2639 }
2640
2641 static RefPtr<CSSValue> consumeAlignItems(CSSParserTokenRange& range)
2642 {
2643     // align-items property does not allow the 'auto' value.
2644     if (identMatches<CSSValueAuto>(range.peek().id()))
2645         return nullptr;
2646     return consumeSelfPositionOverflowPosition(range);
2647 }
2648
2649 static RefPtr<CSSValue> consumeJustifyItems(CSSParserTokenRange& range)
2650 {
2651     CSSParserTokenRange rangeCopy = range;
2652     RefPtr<CSSPrimitiveValue> legacy = consumeIdent<CSSValueLegacy>(rangeCopy);
2653     RefPtr<CSSPrimitiveValue> positionKeyword = consumeIdent<CSSValueCenter, CSSValueLeft, CSSValueRight>(rangeCopy);
2654     if (!legacy)
2655         legacy = consumeIdent<CSSValueLegacy>(rangeCopy);
2656     if (legacy && positionKeyword) {
2657         range = rangeCopy;
2658         return createPrimitiveValuePair(legacy.releaseNonNull(), positionKeyword.releaseNonNull(), Pair::IdenticalValueEncoding::Coalesce);
2659     }
2660     return consumeSelfPositionOverflowPosition(range);
2661 }
2662
2663 static RefPtr<CSSValue> consumeFitContent(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2664 {
2665     CSSParserTokenRange rangeCopy = range;
2666     CSSParserTokenRange args = consumeFunction(rangeCopy);
2667     RefPtr<CSSPrimitiveValue> length = consumeLengthOrPercent(args, cssParserMode, ValueRangeNonNegative, UnitlessQuirk::Allow);
2668     if (!length || !args.atEnd())
2669         return nullptr;
2670     range = rangeCopy;
2671     RefPtr<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueWebkitFitContent);
2672     result->append(length.releaseNonNull());
2673     return result;
2674 }
2675
2676 static RefPtr<CSSPrimitiveValue> consumeCustomIdentForGridLine(CSSParserTokenRange& range)
2677 {
2678     if (range.peek().id() == CSSValueAuto || range.peek().id() == CSSValueSpan)
2679         return nullptr;
2680     return consumeCustomIdent(range);
2681 }
2682
2683 static RefPtr<CSSValue> consumeGridLine(CSSParserTokenRange& range)
2684 {
2685     if (range.peek().id() == CSSValueAuto)
2686         return consumeIdent(range);
2687
2688     RefPtr<CSSPrimitiveValue> spanValue;
2689     RefPtr<CSSPrimitiveValue> gridLineName;
2690     RefPtr<CSSPrimitiveValue> numericValue = consumeInteger(range);
2691     if (numericValue) {
2692         gridLineName = consumeCustomIdentForGridLine(range);
2693         spanValue = consumeIdent<CSSValueSpan>(range);
2694     } else {
2695         spanValue = consumeIdent<CSSValueSpan>(range);
2696         if (spanValue) {
2697             numericValue = consumeInteger(range);
2698             gridLineName = consumeCustomIdentForGridLine(range);
2699             if (!numericValue)
2700                 numericValue = consumeInteger(range);
2701         } else {
2702             gridLineName = consumeCustomIdentForGridLine(range);
2703             if (gridLineName) {
2704                 numericValue = consumeInteger(range);
2705                 spanValue = consumeIdent<CSSValueSpan>(range);
2706                 if (!spanValue && !numericValue)
2707                     return gridLineName;
2708             } else {
2709                 return nullptr;
2710             }
2711         }
2712     }
2713
2714     if (spanValue && !numericValue && !gridLineName)
2715         return nullptr; // "span" keyword alone is invalid.
2716     if (spanValue && numericValue && numericValue->intValue() < 0)
2717         return nullptr; // Negative numbers are not allowed for span.
2718     if (numericValue && numericValue->intValue() == 0)
2719         return nullptr; // An <integer> value of zero makes the declaration invalid.
2720
2721     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
2722     if (spanValue)
2723         values->append(spanValue.releaseNonNull());
2724     if (numericValue)
2725         values->append(numericValue.releaseNonNull());
2726     if (gridLineName)
2727         values->append(gridLineName.releaseNonNull());
2728     ASSERT(values->length());
2729     return values;
2730 }
2731
2732 static bool isGridTrackFixedSized(const CSSPrimitiveValue& primitiveValue)
2733 {
2734     CSSValueID valueID = primitiveValue.valueID();
2735     if (valueID == CSSValueWebkitMinContent || valueID == CSSValueWebkitMaxContent || valueID == CSSValueAuto || primitiveValue.isFlex())
2736         return false;
2737
2738     return true;
2739 }
2740
2741 static bool isGridTrackFixedSized(const CSSValue& value)
2742 {
2743     if (value.isPrimitiveValue())
2744         return isGridTrackFixedSized(downcast<CSSPrimitiveValue>(value));
2745
2746     ASSERT(value.isFunctionValue());
2747     auto& function = downcast<CSSFunctionValue>(value);
2748     if (function.name() == CSSValueWebkitFitContent || function.arguments() == nullptr || function.arguments()->length() < 2)
2749         return false;
2750
2751     CSSValue* minPrimitiveValue = downcast<CSSPrimitiveValue>(function.arguments()->item(0));
2752     CSSValue* maxPrimitiveValue = downcast<CSSPrimitiveValue>(function.arguments()->item(1));
2753     return isGridTrackFixedSized(*minPrimitiveValue) || isGridTrackFixedSized(*maxPrimitiveValue);
2754 }
2755
2756 static Vector<String> parseGridTemplateAreasColumnNames(const String& gridRowNames)
2757 {
2758     ASSERT(!gridRowNames.isEmpty());
2759     Vector<String> columnNames;
2760     // Using StringImpl to avoid checks and indirection in every call to String::operator[].
2761     StringImpl& text = *gridRowNames.impl();
2762
2763     StringBuilder areaName;
2764     for (unsigned i = 0; i < text.length(); ++i) {
2765         if (isCSSSpace(text[i])) {
2766             if (!areaName.isEmpty()) {
2767                 columnNames.append(areaName.toString());
2768                 areaName.clear();
2769             }
2770             continue;
2771         }
2772         if (text[i] == '.') {
2773             if (areaName == ".")
2774                 continue;
2775             if (!areaName.isEmpty()) {
2776                 columnNames.append(areaName.toString());
2777                 areaName.clear();
2778             }
2779         } else {
2780             if (!isNameCodePoint(text[i]))
2781                 return Vector<String>();
2782             if (areaName == ".") {
2783                 columnNames.append(areaName.toString());
2784                 areaName.clear();
2785             }
2786         }
2787
2788         areaName.append(text[i]);
2789     }
2790
2791     if (!areaName.isEmpty())
2792         columnNames.append(areaName.toString());
2793
2794     return columnNames;
2795 }
2796
2797 static bool parseGridTemplateAreasRow(const String& gridRowNames, NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount)
2798 {
2799     if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace())
2800         return false;
2801
2802     Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames);
2803     if (rowCount == 0) {
2804         columnCount = columnNames.size();
2805         if (columnCount == 0)
2806             return false;
2807     } else if (columnCount != columnNames.size()) {
2808         // The declaration is invalid if all the rows don't have the number of columns.
2809         return false;
2810     }
2811
2812     for (size_t currentColumn = 0; currentColumn < columnCount; ++currentColumn) {
2813         const String& gridAreaName = columnNames[currentColumn];
2814
2815         // Unamed areas are always valid (we consider them to be 1x1).
2816         if (gridAreaName == ".")
2817             continue;
2818
2819         size_t lookAheadColumn = currentColumn + 1;
2820         while (lookAheadColumn < columnCount && columnNames[lookAheadColumn] == gridAreaName)
2821             lookAheadColumn++;
2822
2823         NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName);
2824         if (gridAreaIt == gridAreaMap.end()) {
2825             gridAreaMap.add(gridAreaName, GridArea(GridSpan::translatedDefiniteGridSpan(rowCount, rowCount + 1), GridSpan::translatedDefiniteGridSpan(currentColumn, lookAheadColumn)));
2826         } else {
2827             GridArea& gridArea = gridAreaIt->value;
2828
2829             // The following checks test that the grid area is a single filled-in rectangle.
2830             // 1. The new row is adjacent to the previously parsed row.
2831             if (rowCount != gridArea.rows.endLine())
2832                 return false;
2833
2834             // 2. The new area starts at the same position as the previously parsed area.
2835             if (currentColumn != gridArea.columns.startLine())
2836                 return false;
2837
2838             // 3. The new area ends at the same position as the previously parsed area.
2839             if (lookAheadColumn != gridArea.columns.endLine())
2840                 return false;
2841
2842             gridArea.rows = GridSpan::translatedDefiniteGridSpan(gridArea.rows.startLine(), gridArea.rows.endLine() + 1);
2843         }
2844         currentColumn = lookAheadColumn - 1;
2845     }
2846
2847     return true;
2848 }
2849
2850 static RefPtr<CSSPrimitiveValue> consumeGridBreadth(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2851 {
2852     const CSSParserToken& token = range.peek();
2853     if (identMatches<CSSValueWebkitMinContent, CSSValueWebkitMaxContent, CSSValueAuto>(token.id()))
2854         return consumeIdent(range);
2855     if (token.type() == DimensionToken && token.unitType() == CSSPrimitiveValue::UnitTypes::CSS_FR) {
2856         if (range.peek().numericValue() < 0)
2857             return nullptr;
2858         return CSSPrimitiveValue::create(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitTypes::CSS_FR);
2859     }
2860     return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative, UnitlessQuirk::Allow);
2861 }
2862
2863 static RefPtr<CSSValue> consumeGridTrackSize(CSSParserTokenRange& range, CSSParserMode cssParserMode)
2864 {
2865     const CSSParserToken& token = range.peek();
2866     if (identMatches<CSSValueAuto>(token.id()))
2867         return consumeIdent(range);
2868
2869     if (token.functionId() == CSSValueMinmax) {
2870         CSSParserTokenRange rangeCopy = range;
2871         CSSParserTokenRange args = consumeFunction(rangeCopy);
2872         RefPtr<CSSPrimitiveValue> minTrackBreadth = consumeGridBreadth(args, cssParserMode);
2873         if (!minTrackBreadth || minTrackBreadth->isFlex() || !consumeCommaIncludingWhitespace(args))
2874             return nullptr;
2875         RefPtr<CSSPrimitiveValue> maxTrackBreadth = consumeGridBreadth(args, cssParserMode);
2876         if (!maxTrackBreadth || !args.atEnd())
2877             return nullptr;
2878         range = rangeCopy;
2879         RefPtr<CSSFunctionValue> result = CSSFunctionValue::create(CSSValueMinmax);
2880         result->append(minTrackBreadth.releaseNonNull());
2881         result->append(maxTrackBreadth.releaseNonNull());
2882         return result;
2883     }
2884
2885     if (token.functionId() == CSSValueWebkitFitContent)
2886         return consumeFitContent(range, cssParserMode);
2887
2888     return consumeGridBreadth(range, cssParserMode);
2889 }
2890
2891 // Appends to the passed in CSSGridLineNamesValue if any, otherwise creates a new one.
2892 static RefPtr<CSSGridLineNamesValue> consumeGridLineNames(CSSParserTokenRange& range, CSSGridLineNamesValue* lineNames = nullptr)
2893 {
2894     CSSParserTokenRange rangeCopy = range;
2895     if (rangeCopy.consumeIncludingWhitespace().type() != LeftBracketToken)
2896         return nullptr;
2897     
2898     RefPtr<CSSGridLineNamesValue> result = lineNames;
2899     if (!result)
2900         result = CSSGridLineNamesValue::create();
2901     while (RefPtr<CSSPrimitiveValue> lineName = consumeCustomIdentForGridLine(rangeCopy))
2902         result->append(lineName.releaseNonNull());
2903     if (rangeCopy.consumeIncludingWhitespace().type() != RightBracketToken)
2904         return nullptr;
2905     range = rangeCopy;
2906     return result;
2907 }
2908
2909 static bool consumeGridTrackRepeatFunction(CSSParserTokenRange& range, CSSParserMode cssParserMode, CSSValueList& list, bool& isAutoRepeat, bool& allTracksAreFixedSized)
2910 {
2911     CSSParserTokenRange args = consumeFunction(range);
2912     // The number of repetitions for <auto-repeat> is not important at parsing level
2913     // because it will be computed later, let's set it to 1.
2914     size_t repetitions = 1;
2915     isAutoRepeat = identMatches<CSSValueAutoFill, CSSValueAutoFit>(args.peek().id());
2916     RefPtr<CSSValueList> repeatedValues;
2917     if (isAutoRepeat)
2918         repeatedValues = CSSGridAutoRepeatValue::create(args.consumeIncludingWhitespace().id());
2919     else {
2920         // FIXME: a consumeIntegerRaw would be more efficient here.
2921         RefPtr<CSSPrimitiveValue> repetition = consumePositiveInteger(args);
2922         if (!repetition)
2923             return false;
2924         repetitions = clampTo<size_t>(repetition->doubleValue(), 0, kGridMaxTracks);
2925         repeatedValues = CSSValueList::createSpaceSeparated();
2926     }
2927     if (!consumeCommaIncludingWhitespace(args))
2928         return false;
2929     RefPtr<CSSGridLineNamesValue> lineNames = consumeGridLineNames(args);
2930     if (lineNames)
2931         repeatedValues->append(lineNames.releaseNonNull());
2932
2933     size_t numberOfTracks = 0;
2934     while (!args.atEnd()) {
2935         RefPtr<CSSValue> trackSize = consumeGridTrackSize(args, cssParserMode);
2936         if (!trackSize)
2937             return false;
2938         if (allTracksAreFixedSized)
2939             allTracksAreFixedSized = isGridTrackFixedSized(*trackSize);
2940         repeatedValues->append(*trackSize);
2941         ++numberOfTracks;
2942         lineNames = consumeGridLineNames(args);
2943         if (lineNames)
2944             repeatedValues->append(lineNames.releaseNonNull());
2945     }
2946     // We should have found at least one <track-size> or else it is not a valid <track-list>.
2947     if (!numberOfTracks)
2948         return false;
2949
2950     if (isAutoRepeat)
2951         list.append(repeatedValues.releaseNonNull());
2952     else {
2953         // We clamp the repetitions to a multiple of the repeat() track list's size, while staying below the max grid size.
2954         repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks);
2955         for (size_t i = 0; i < repetitions; ++i) {
2956             for (size_t j = 0; j < repeatedValues->length(); ++j)
2957                 list.append(adoptRef(*repeatedValues->item(j)));
2958         }
2959     }
2960     return true;
2961 }
2962
2963 enum TrackListType { GridTemplate, GridTemplateNoRepeat, GridAuto };
2964
2965 static RefPtr<CSSValue> consumeGridTrackList(CSSParserTokenRange& range, CSSParserMode cssParserMode, TrackListType trackListType)
2966 {
2967     bool allowGridLineNames = trackListType != GridAuto;
2968     RefPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
2969     RefPtr<CSSGridLineNamesValue> lineNames = consumeGridLineNames(range);
2970     if (lineNames) {
2971         if (!allowGridLineNames)
2972             return nullptr;
2973         values->append(lineNames.releaseNonNull());
2974     }
2975
2976     bool allowRepeat = trackListType == GridTemplate;
2977     bool seenAutoRepeat = false;
2978     bool allTracksAreFixedSized = true;
2979     do {
2980         bool isAutoRepeat;
2981         if (range.peek().functionId() == CSSValueRepeat) {
2982             if (!allowRepeat)
2983                 return nullptr;
2984             if (!consumeGridTrackRepeatFunction(range, cssParserMode, *values, isAutoRepeat, allTracksAreFixedSized))
2985                 return nullptr;
2986             if (isAutoRepeat && seenAutoRepeat)
2987                 return nullptr;
2988             seenAutoRepeat = seenAutoRepeat || isAutoRepeat;
2989         } else if (RefPtr<CSSValue> value = consumeGridTrackSize(range, cssParserMode)) {
2990             if (allTracksAreFixedSized)
2991                 allTracksAreFixedSized = isGridTrackFixedSized(*value);
2992             values->append(value.releaseNonNull());
2993         } else {
2994             return nullptr;
2995         }
2996         if (seenAutoRepeat && !allTracksAreFixedSized)
2997             return nullptr;
2998         lineNames = consumeGridLineNames(range);
2999         if (lineNames) {
3000             if (!allowGridLineNames)
3001                 return nullptr;
3002             values->append(*lineNames);
3003         }
3004     } while (!range.atEnd() && range.peek().type() != DelimiterToken);
3005     return values;
3006 }
3007
3008 static RefPtr<CSSValue> consumeGridTemplatesRowsOrColumns(CSSParserTokenRange& range, CSSParserMode cssParserMode)
3009 {
3010     if (range.peek().id() == CSSValueNone)
3011         return consumeIdent(range);
3012     return consumeGridTrackList(range, cssParserMode, GridTemplate);
3013 }
3014
3015 static RefPtr<CSSValue> consumeGridTemplateAreas(CSSParserTokenRange& range)
3016 {
3017     if (range.peek().id() == CSSValueNone)
3018         return consumeIdent(range);
3019
3020     NamedGridAreaMap gridAreaMap;
3021     size_t rowCount = 0;
3022     size_t columnCount = 0;
3023
3024     while (range.peek().type() == StringToken) {
3025         if (!parseGridTemplateAreasRow(range.consumeIncludingWhitespace().value().toString(), gridAreaMap, rowCount, columnCount))
3026             return nullptr;
3027         ++rowCount;
3028     }
3029
3030     if (rowCount == 0)
3031         return nullptr;
3032     ASSERT(columnCount);
3033     return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount);
3034 }
3035
3036 #if ENABLE(CSS_REGIONS)
3037 static RefPtr<CSSValue> consumeFlowProperty(CSSParserTokenRange& range)
3038 {
3039     RefPtr<CSSValue> result;
3040     if (range.peek().id() == CSSValueNone)
3041         result = consumeIdent(range);
3042     else
3043         result = consumeCustomIdent(range);
3044     return result;
3045 }
3046 #endif
3047
3048 RefPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID property, CSSPropertyID currentShorthand)
3049 {
3050     if (CSSParserFastPaths::isKeywordPropertyID(property)) {
3051         if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(property, m_range.peek().id(), m_context.mode))
3052             return nullptr;
3053         return consumeIdent(m_range);
3054     }
3055     switch (property) {
3056     case CSSPropertyWillChange:
3057         return consumeWillChange(m_range);
3058     case CSSPropertyPage:
3059         return consumePage(m_range);
3060     case CSSPropertyQuotes:
3061         return consumeQuotes(m_range);
3062     case CSSPropertyFontVariantCaps:
3063         return consumeFontVariantCaps(m_range);
3064     case CSSPropertyFontVariantLigatures:
3065         return consumeFontVariantLigatures(m_range);
3066     case CSSPropertyFontVariantNumeric:
3067         return consumeFontVariantNumeric(m_range);
3068     case CSSPropertyFontFeatureSettings:
3069         return consumeFontFeatureSettings(m_range);
3070     case CSSPropertyFontFamily:
3071         return consumeFontFamily(m_range);
3072     case CSSPropertyFontWeight:
3073         return consumeFontWeight(m_range);
3074     case CSSPropertyLetterSpacing:
3075     case CSSPropertyWordSpacing:
3076         return consumeSpacing(m_range, m_context.mode);
3077     case CSSPropertyTabSize:
3078         return consumeTabSize(m_range, m_context.mode);
3079 #if ENABLE(TEXT_AUTOSIZING)
3080     case CSSPropertyWebkitTextSizeAdjust:
3081         return consumeTextSizeAdjust(m_range, m_context.mode);
3082 #endif
3083     case CSSPropertyFontSize:
3084         return consumeFontSize(m_range, m_context.mode, UnitlessQuirk::Allow);
3085     case CSSPropertyLineHeight:
3086         return consumeLineHeight(m_range, m_context.mode);
3087     case CSSPropertyWebkitBorderHorizontalSpacing:
3088     case CSSPropertyWebkitBorderVerticalSpacing:
3089         return consumeLength(m_range, m_context.mode, ValueRangeNonNegative);
3090     case CSSPropertyCounterIncrement:
3091     case CSSPropertyCounterReset:
3092         return consumeCounter(m_range, property == CSSPropertyCounterIncrement ? 1 : 0);
3093     case CSSPropertySize:
3094         return consumeSize(m_range, m_context.mode);
3095     case CSSPropertyTextIndent:
3096         return consumeTextIndent(m_range, m_context.mode);
3097     case CSSPropertyMaxWidth:
3098     case CSSPropertyMaxHeight:
3099         return consumeMaxWidthOrHeight(m_range, m_context, UnitlessQuirk::Allow);
3100     case CSSPropertyWebkitMaxLogicalWidth:
3101     case CSSPropertyWebkitMaxLogicalHeight:
3102         return consumeMaxWidthOrHeight(m_range, m_context);
3103     case CSSPropertyMinWidth:
3104     case CSSPropertyMinHeight:
3105     case CSSPropertyWidth:
3106     case CSSPropertyHeight:
3107         return consumeWidthOrHeight(m_range, m_context, UnitlessQuirk::Allow);
3108     case CSSPropertyWebkitMinLogicalWidth:
3109     case CSSPropertyWebkitMinLogicalHeight:
3110     case CSSPropertyWebkitLogicalWidth:
3111     case CSSPropertyWebkitLogicalHeight:
3112         return consumeWidthOrHeight(m_range, m_context);
3113     case CSSPropertyMarginTop:
3114     case CSSPropertyMarginRight:
3115     case CSSPropertyMarginBottom:
3116     case CSSPropertyMarginLeft:
3117     case CSSPropertyBottom:
3118     case CSSPropertyLeft:
3119     case CSSPropertyRight:
3120     case CSSPropertyTop:
3121         return consumeMarginOrOffset(m_range, m_context.mode, UnitlessQuirk::Allow);
3122     case CSSPropertyWebkitMarginStart:
3123     case CSSPropertyWebkitMarginEnd:
3124     case CSSPropertyWebkitMarginBefore:
3125     case CSSPropertyWebkitMarginAfter:
3126         return consumeMarginOrOffset(m_range, m_context.mode, UnitlessQuirk::Forbid);
3127     case CSSPropertyPaddingTop:
3128     case CSSPropertyPaddingRight:
3129     case CSSPropertyPaddingBottom:
3130     case CSSPropertyPaddingLeft:
3131         return consumeLengthOrPercent(m_range, m_context.mode, ValueRangeNonNegative, UnitlessQuirk::Allow);
3132     case CSSPropertyWebkitPaddingStart:
3133     case CSSPropertyWebkitPaddingEnd:
3134     case CSSPropertyWebkitPaddingBefore:
3135     case CSSPropertyWebkitPaddingAfter:
3136         return consumeLengthOrPercent(m_range, m_context.mode, ValueRangeNonNegative, UnitlessQuirk::Forbid);
3137     case CSSPropertyClip:
3138         return consumeClip(m_range, m_context.mode);
3139 #if ENABLE(TOUCH_EVENTS)
3140     case CSSPropertyTouchAction:
3141         return consumeTouchAction(m_range);
3142 #endif
3143     case CSSPropertyObjectPosition:
3144     case CSSPropertyPerspectiveOrigin:
3145         return consumePosition(m_range, m_context.mode, UnitlessQuirk::Forbid);
3146     case CSSPropertyWebkitLineClamp:
3147         return consumeLineClamp(m_range);
3148     case CSSPropertyWebkitFontSizeDelta:
3149         return consumeLength(m_range, m_context.mode, ValueRangeAll, UnitlessQuirk::Allow);
3150     case CSSPropertyWebkitHyphenateCharacter:
3151     case CSSPropertyWebkitLocale:
3152         return consumeLocale(m_range);
3153     case CSSPropertyColumnWidth:
3154         return consumeColumnWidth(m_range);
3155     case CSSPropertyColumnCount:
3156         return consumeColumnCount(m_range);
3157     case CSSPropertyColumnGap:
3158         return consumeColumnGap(m_range, m_context.mode);
3159     case CSSPropertyColumnSpan:
3160         return consumeColumnSpan(m_range);
3161     case CSSPropertyZoom:
3162         return consumeZoom(m_range, m_context);
3163     case CSSPropertyAnimationDelay:
3164     case CSSPropertyTransitionDelay:
3165     case CSSPropertyAnimationDirection:
3166     case CSSPropertyAnimationDuration:
3167     case CSSPropertyTransitionDuration:
3168     case CSSPropertyAnimationFillMode:
3169     case CSSPropertyAnimationIterationCount:
3170     case CSSPropertyAnimationName:
3171     case CSSPropertyAnimationPlayState:
3172     case CSSPropertyTransitionProperty:
3173     case CSSPropertyAnimationTimingFunction:
3174     case CSSPropertyTransitionTimingFunction:
3175         return consumeAnimationPropertyList(property, m_range, m_context);
3176     case CSSPropertyGridColumnGap:
3177     case CSSPropertyGridRowGap:
3178         return consumeLength(m_range, m_context.mode, ValueRangeNonNegative);
3179     case CSSPropertyShapeMargin:
3180         return consumeLengthOrPercent(m_range, m_context.mode, ValueRangeNonNegative);
3181     case CSSPropertyShapeImageThreshold:
3182         return consumeNumber(m_range, ValueRangeAll);
3183     case CSSPropertyWebkitBoxOrdinalGroup:
3184     case CSSPropertyOrphans:
3185     case CSSPropertyWidows:
3186         return consumePositiveInteger(m_range);
3187     case CSSPropertyWebkitTextDecorationColor:
3188         return consumeColor(m_range, m_context.mode);
3189     case CSSPropertyWebkitTextStrokeWidth:
3190         return consumeTextStrokeWidth(m_range, m_context.mode);
3191     case CSSPropertyWebkitTextFillColor:
3192 #if ENABLE(TOUCH_EVENTS)
3193     case CSSPropertyWebkitTapHighlightColor:
3194 #endif
3195     case CSSPropertyWebkitTextEmphasisColor:
3196     case CSSPropertyWebkitBorderStartColor:
3197     case CSSPropertyWebkitBorderEndColor:
3198     case CSSPropertyWebkitBorderBeforeColor:
3199     case CSSPropertyWebkitBorderAfterColor:
3200     case CSSPropertyWebkitTextStrokeColor:
3201     case CSSPropertyStopColor:
3202     case CSSPropertyFloodColor:
3203     case CSSPropertyLightingColor:
3204     case CSSPropertyColumnRuleColor:
3205         return consumeColor(m_range, m_context.mode);
3206     case CSSPropertyColor:
3207     case CSSPropertyBackgroundColor:
3208         return consumeColor(m_range, m_context.mode, inQuirksMode());
3209     case CSSPropertyWebkitBorderStartWidth:
3210     case CSSPropertyWebkitBorderEndWidth:
3211     case CSSPropertyWebkitBorderBeforeWidth:
3212     case CSSPropertyWebkitBorderAfterWidth:
3213         return consumeBorderWidth(m_range, m_context.mode, UnitlessQuirk::Forbid);
3214     case CSSPropertyBorderBottomColor:
3215     case CSSPropertyBorderLeftColor:
3216     case CSSPropertyBorderRightColor:
3217     case CSSPropertyBorderTopColor: {
3218         bool allowQuirkyColors = inQuirksMode()
3219             && (currentShorthand == CSSPropertyInvalid || currentShorthand == CSSPropertyBorderColor);
3220         return consumeColor(m_range, m_context.mode, allowQuirkyColors);
3221     }
3222     case CSSPropertyBorderBottomWidth:
3223     case CSSPropertyBorderLeftWidth:
3224     case CSSPropertyBorderRightWidth:
3225     case CSSPropertyBorderTopWidth: {
3226         bool allowQuirkyLengths = inQuirksMode()
3227             && (currentShorthand == CSSPropertyInvalid || currentShorthand == CSSPropertyBorderWidth);
3228         UnitlessQuirk unitless = allowQuirkyLengths ? UnitlessQuirk::Allow : UnitlessQuirk::Forbid;
3229         return consumeBorderWidth(m_range, m_context.mode, unitless);
3230     }
3231     case CSSPropertyZIndex:
3232         return consumeZIndex(m_range);
3233     case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
3234     case CSSPropertyBoxShadow:
3235         return consumeShadow(m_range, m_context.mode, property == CSSPropertyBoxShadow);
3236     case CSSPropertyFilter:
3237 #if ENABLE(FILTERS_LEVEL_2)
3238     case CSSPropertyWebkitBackdropFilter:
3239 #endif
3240         return consumeFilter(m_range, m_context);
3241     case CSSPropertyTextDecoration:
3242     case CSSPropertyWebkitTextDecorationsInEffect:
3243     case CSSPropertyWebkitTextDecorationLine:
3244         return consumeTextDecorationLine(m_range);
3245     case CSSPropertyWebkitTextEmphasisStyle:
3246         return consumeTextEmphasisStyle(m_range);
3247     case CSSPropertyOutlineColor:
3248         return consumeOutlineColor(m_range, m_context.mode);
3249     case CSSPropertyOutlineOffset:
3250         return consumeLength(m_range, m_context.mode, ValueRangeAll);
3251     case CSSPropertyOutlineWidth:
3252         return consumeLineWidth(m_range, m_context.mode, UnitlessQuirk::Forbid);
3253     case CSSPropertyTransform:
3254         return consumeTransform(m_range, m_context.mode);
3255     case CSSPropertyTransformOriginX:
3256     case CSSPropertyPerspectiveOriginX:
3257         return consumePositionX(m_range, m_context.mode);
3258     case CSSPropertyTransformOriginY:
3259     case CSSPropertyPerspectiveOriginY:
3260         return consumePositionY(m_range, m_context.mode);
3261     case CSSPropertyTransformOriginZ:
3262         return consumeLength(m_range, m_context.mode, ValueRangeAll);
3263     case CSSPropertyFill:
3264     case CSSPropertyStroke:
3265         return consumePaintStroke(m_range, m_context.mode);
3266     case CSSPropertyPaintOrder:
3267         return consumePaintOrder(m_range);
3268     case CSSPropertyMarkerStart:
3269     case CSSPropertyMarkerMid:
3270     case CSSPropertyMarkerEnd:
3271     case CSSPropertyClipPath:
3272     case CSSPropertyMask:
3273         return consumeNoneOrURI(m_range);
3274     case CSSPropertyFlexBasis:
3275         return consumeFlexBasis(m_range, m_context.mode);
3276     case CSSPropertyFlexGrow:
3277     case CSSPropertyFlexShrink:
3278         return consumeNumber(m_range, ValueRangeNonNegative);
3279     case CSSPropertyStrokeDasharray:
3280         return consumeStrokeDasharray(m_range);
3281     case CSSPropertyColumnRuleWidth:
3282         return consumeColumnRuleWidth(m_range, m_context.mode);
3283     case CSSPropertyStrokeOpacity:
3284     case CSSPropertyFillOpacity:
3285     case CSSPropertyStopOpacity:
3286     case CSSPropertyFloodOpacity:
3287     case CSSPropertyOpacity:
3288     case CSSPropertyWebkitBoxFlex:
3289         return consumeNumber(m_range, ValueRangeAll);
3290     case CSSPropertyBaselineShift:
3291         return consumeBaselineShift(m_range);
3292     case CSSPropertyStrokeMiterlimit:
3293         return consumeNumber(m_range, ValueRangeNonNegative);
3294     case CSSPropertyStrokeWidth:
3295     case CSSPropertyStrokeDashoffset:
3296     case CSSPropertyCx:
3297     case CSSPropertyCy:
3298     case CSSPropertyX:
3299     case CSSPropertyY:
3300     case CSSPropertyR:
3301         return consumeLengthOrPercent(m_range, SVGAttributeMode, ValueRangeAll, UnitlessQuirk::Forbid);
3302     case CSSPropertyRx:
3303     case CSSPropertyRy:
3304         return consumeRxOrRy(m_range);
3305     case CSSPropertyCursor:
3306         return consumeCursor(m_range, m_context, inQuirksMode());
3307     case CSSPropertyTransformOrigin:
3308         return consumeTransformOrigin(m_range, m_context.mode, UnitlessQuirk::Forbid);
3309     case CSSPropertyContent:
3310         return consumeContent(m_range, m_context);
3311     case CSSPropertyListStyleImage:
3312     case CSSPropertyBorderImageSource:
3313     case CSSPropertyWebkitMaskBoxImageSource:
3314         return consumeImageOrNone(m_range, m_context);
3315     case CSSPropertyPerspective:
3316         return consumePerspective(m_range, m_context.mode);
3317 #if ENABLE(CSS_SCROLL_SNAP)
3318     case CSSPropertyWebkitScrollSnapCoordinate:
3319         return consumeScrollSnapCoordinate(m_range, m_context.mode);
3320     case CSSPropertyWebkitScrollSnapPointsX:
3321     case CSSPropertyWebkitScrollSnapPointsY:
3322         return consumeScrollSnapPoints(m_range, m_context.mode);
3323 #endif
3324     case CSSPropertyBorderTopRightRadius:
3325     case CSSPropertyBorderTopLeftRadius:
3326     case CSSPropertyBorderBottomLeftRadius:
3327     case CSSPropertyBorderBottomRightRadius:
3328         return consumeBorderRadiusCorner(m_range, m_context.mode);
3329     case CSSPropertyWebkitBoxFlexGroup:
3330         return consumeInteger(m_range, 0);
3331     case CSSPropertyOrder:
3332         return consumeInteger(m_range);
3333     case CSSPropertyWebkitTextUnderlinePosition:
3334         // auto | [ under || [ left | right ] ], but we only support auto | under for now
3335         return consumeIdent<CSSValueAuto, CSSValueUnder>(m_range);
3336     case CSSPropertyVerticalAlign:
3337         return consumeVerticalAlign(m_range, m_context.mode);
3338     case CSSPropertyShapeOutside:
3339         return consumeShapeOutside(m_range, m_context);
3340     case CSSPropertyWebkitClipPath:
3341         return consumeWebkitClipPath(m_range, m_context);
3342     case CSSPropertyJustifyContent:
3343     case CSSPropertyAlignContent:
3344         return consumeContentDistributionOverflowPosition(m_range);
3345     case CSSPropertyBorderImageRepeat:
3346     case CSSPropertyWebkitMaskBoxImageRepeat:
3347         return consumeBorderImageRepeat(m_range);
3348     case CSSPropertyBorderImageSlice:
3349     case CSSPropertyWebkitMaskBoxImageSlice:
3350         return consumeBorderImageSlice(property, m_range);
3351     case CSSPropertyBorderImageOutset:
3352     case CSSPropertyWebkitMaskBoxImageOutset:
3353         return consumeBorderImageOutset(m_range);
3354     case CSSPropertyBorderImageWidth:
3355     case CSSPropertyWebkitMaskBoxImageWidth:
3356         return consumeBorderImageWidth(m_range);
3357     case CSSPropertyWebkitBorderImage:
3358     case CSSPropertyWebkitMaskBoxImage:
3359         return consumeWebkitBorderImage(property, m_range, m_context);
3360     case CSSPropertyWebkitBoxReflect:
3361         return consumeReflect(m_range, m_context);
3362 #if ENABLE(CSS_IMAGE_ORIENTATION)
3363     case CSSPropertyImageOrientation:
3364         return consumeImageOrientation(m_range, m_context.mode);
3365 #endif
3366     case CSSPropertyBackgroundAttachment:
3367     case CSSPropertyBackgroundBlendMode:
3368     case CSSPropertyBackgroundClip:
3369     case CSSPropertyBackgroundImage:
3370     case CSSPropertyBackgroundOrigin:
3371     case CSSPropertyBackgroundPositionX:
3372     case CSSPropertyBackgroundPositionY:
3373     case CSSPropertyBackgroundSize:
3374     case CSSPropertyWebkitBackgroundClip:
3375     case CSSPropertyWebkitBackgroundOrigin:
3376     case CSSPropertyWebkitMaskClip:
3377     case CSSPropertyWebkitMaskComposite:
3378     case CSSPropertyWebkitMaskImage:
3379     case CSSPropertyWebkitMaskOrigin:
3380     case CSSPropertyWebkitMaskPositionX:
3381     case CSSPropertyWebkitMaskPositionY:
3382     case CSSPropertyWebkitMaskSize:
3383         return consumeCommaSeparatedBackgroundComponent(property, m_range, m_context);
3384     case CSSPropertyWebkitMaskRepeatX:
3385     case CSSPropertyWebkitMaskRepeatY:
3386         return nullptr;
3387     case CSSPropertyAlignItems:
3388         return consumeAlignItems(m_range);
3389     case CSSPropertyJustifySelf:
3390     case CSSPropertyAlignSelf:
3391         return consumeSelfPositionOverflowPosition(m_range);
3392     case CSSPropertyJustifyItems:
3393         return consumeJustifyItems(m_range);
3394     case CSSPropertyGridColumnEnd:
3395     case CSSPropertyGridColumnStart:
3396     case CSSPropertyGridRowEnd:
3397     case CSSPropertyGridRowStart:
3398         return consumeGridLine(m_range);
3399     case CSSPropertyGridAutoColumns:
3400     case CSSPropertyGridAutoRows:
3401         return consumeGridTrackList(m_range, m_context.mode, GridAuto);
3402     case CSSPropertyGridTemplateColumns:
3403     case CSSPropertyGridTemplateRows:
3404         return consumeGridTemplatesRowsOrColumns(m_range, m_context.mode);
3405     case CSSPropertyGridTemplateAreas:
3406         return consumeGridTemplateAreas(m_range);
3407     case CSSPropertyGridAutoFlow:
3408         return consumeGridAutoFlow(m_range);
3409 #if ENABLE(CSS_REGIONS)
3410     case CSSPropertyWebkitFlowInto:
3411     case CSSPropertyWebkitFlowFrom:
3412         return consumeFlowProperty(m_range);
3413 #endif
3414     default:
3415         return nullptr;
3416     }
3417 }
3418
3419 static RefPtr<CSSValueList> consumeFontFaceUnicodeRange(CSSParserTokenRange& range)
3420 {
3421     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3422
3423     do {
3424         const CSSParserToken& token = range.consumeIncludingWhitespace();
3425         if (token.type() != UnicodeRangeToken)
3426             return nullptr;
3427
3428         UChar32 start = token.unicodeRangeStart();
3429         UChar32 end = token.unicodeRangeEnd();
3430         if (start > end)
3431             return nullptr;
3432         values->append(CSSUnicodeRangeValue::create(start, end));
3433     } while (consumeCommaIncludingWhitespace(range));
3434
3435     return values;
3436 }
3437
3438 static RefPtr<CSSValue> consumeFontFaceSrcURI(CSSParserTokenRange& range, const CSSParserContext& context)
3439 {
3440     String url = consumeUrlAsStringView(range).toString();
3441     if (url.isNull())
3442         return nullptr;
3443     
3444     RefPtr<CSSFontFaceSrcValue> uriValue = CSSFontFaceSrcValue::create(context.completeURL(url));
3445
3446     if (range.peek().functionId() != CSSValueFormat)
3447         return uriValue;
3448
3449     // FIXME: https://drafts.csswg.org/css-fonts says that format() contains a comma-separated list of strings,
3450     // but CSSFontFaceSrcValue stores only one format. Allowing one format for now.
3451     CSSParserTokenRange args = consumeFunction(range);
3452     const CSSParserToken& arg = args.consumeIncludingWhitespace();
3453     if ((arg.type() != StringToken) || !args.atEnd())
3454         return nullptr;
3455     uriValue->setFormat(arg.value().toString());
3456     return uriValue;
3457 }
3458
3459 static RefPtr<CSSValue> consumeFontFaceSrcLocal(CSSParserTokenRange& range)
3460 {
3461     CSSParserTokenRange args = consumeFunction(range);
3462     if (args.peek().type() == StringToken) {
3463         const CSSParserToken& arg = args.consumeIncludingWhitespace();
3464         if (!args.atEnd())
3465             return nullptr;
3466         return CSSFontFaceSrcValue::createLocal(arg.value().toString());
3467     }
3468     if (args.peek().type() == IdentToken) {
3469         String familyName = concatenateFamilyName(args);
3470         if (!args.atEnd())
3471             return nullptr;
3472         return CSSFontFaceSrcValue::createLocal(familyName);
3473     }
3474     return nullptr;
3475 }
3476
3477 static RefPtr<CSSValueList> consumeFontFaceSrc(CSSParserTokenRange& range, const CSSParserContext& context)
3478 {
3479     RefPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
3480
3481     do {
3482         const CSSParserToken& token = range.peek();
3483         RefPtr<CSSValue> parsedValue;
3484         if (token.functionId() == CSSValueLocal)
3485             parsedValue = consumeFontFaceSrcLocal(range);
3486         else
3487             parsedValue = consumeFontFaceSrcURI(range, context);
3488         if (!parsedValue)
3489             return nullptr;
3490         values->append(parsedValue.releaseNonNull());
3491     } while (consumeCommaIncludingWhitespace(range));
3492     return values;
3493 }
3494
3495 bool CSSPropertyParser::parseFontFaceDescriptor(CSSPropertyID propId)
3496 {
3497     RefPtr<CSSValue> parsedValue;
3498     switch (propId) {
3499     case CSSPropertyFontFamily:
3500         if (consumeGenericFamily(m_range))
3501             return false;
3502         parsedValue = consumeFamilyName(m_range);
3503         break;
3504     case CSSPropertySrc: // This is a list of urls or local references.
3505         parsedValue = consumeFontFaceSrc(m_range, m_context);
3506         break;
3507     case CSSPropertyUnicodeRange:
3508         parsedValue = consumeFontFaceUnicodeRange(m_range);
3509         break;
3510     case CSSPropertyFontStretch:
3511     case CSSPropertyFontStyle: {
3512         CSSValueID id = m_range.consumeIncludingWhitespace().id();
3513         if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id, m_context.mode))
3514             return false;
3515         parsedValue = CSSValuePool::singleton().createIdentifierValue(id);
3516         break;
3517     }
3518     case CSSPropertyFontVariant:
3519         parsedValue = consumeFontVariantList(m_range);
3520         break;
3521     case CSSPropertyFontWeight:
3522         parsedValue = consumeFontWeight(m_range);
3523         break;
3524     case CSSPropertyFontFeatureSettings:
3525         parsedValue = consumeFontFeatureSettings(m_range);
3526         break;
3527     default:
3528         break;
3529     }
3530
3531     if (!parsedValue || !m_range.atEnd())
3532         return false;
3533
3534     addProperty(propId, CSSPropertyInvalid, *parsedValue, false);
3535     return true;
3536 }
3537
3538 bool CSSPropertyParser::consumeSystemFont(bool important)
3539 {
3540     CSSValueID systemFontID = m_range.consumeIncludingWhitespace().id();
3541     ASSERT(systemFontID >= CSSValueCaption && systemFontID <= CSSValueStatusBar);
3542     if (!m_range.atEnd())
3543         return false;
3544     
3545     FontCascadeDescription fontDescription;
3546     RenderTheme::defaultTheme()->systemFont(systemFontID, fontDescription);
3547     if (!fontDescription.isAbsoluteSize())
3548         return false;
3549     
3550     addProperty(CSSPropertyFontStyle, CSSPropertyFont, CSSValuePool::singleton().createIdentifierValue(fontDescription.italic() == FontItalicOn ? CSSValueItalic : CSSValueNormal), important);
3551     addProperty(CSSPropertyFontWeight, CSSPropertyFont, CSSValuePool::singleton().createValue(fontDescription.weight()), important);
3552     addProperty(CSSPropertyFontSize, CSSPropertyFont, CSSValuePool::singleton().createValue(fontDescription.specifiedSize(), CSSPrimitiveValue::CSS_PX), important);
3553     Ref<CSSValueList> fontFamilyList = CSSValueList::createCommaSeparated();
3554     fontFamilyList->append(CSSValuePool::singleton().createFontFamilyValue(fontDescription.familyAt(0), FromSystemFontID::Yes));
3555     addProperty(CSSPropertyFontFamily, CSSPropertyFont, WTFMove(fontFamilyList), important);
3556     addProperty(CSSPropertyFontVariantCaps, CSSPropertyFont, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important);
3557     addProperty(CSSPropertyLineHeight, CSSPropertyFont, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important);
3558
3559     // FIXME_NEWPARSER: What about FontVariantNumeric and FontVariantLigatures?
3560
3561     return true;
3562 }
3563
3564 bool CSSPropertyParser::consumeFont(bool important)
3565 {
3566     // Let's check if there is an inherit or initial somewhere in the shorthand.
3567     CSSParserTokenRange range = m_range;
3568     while (!range.atEnd()) {
3569         CSSValueID id = range.consumeIncludingWhitespace().id();
3570         if (id == CSSValueInherit || id == CSSValueInitial)
3571             return false;
3572     }
3573     // Optional font-style, font-variant, font-stretch and font-weight.
3574     RefPtr<CSSPrimitiveValue> fontStyle;
3575     RefPtr<CSSPrimitiveValue> fontVariantCaps;
3576     RefPtr<CSSPrimitiveValue> fontWeight;
3577     // FIXME-NEWPARSER: Implement. RefPtr<CSSPrimitiveValue> fontStretch;
3578     while (!m_range.atEnd()) {
3579         CSSValueID id = m_range.peek().id();
3580         if (!fontStyle && CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyFontStyle, id, m_context.mode)) {
3581             fontStyle = consumeIdent(m_range);
3582             continue;
3583         }
3584         if (!fontVariantCaps && (id == CSSValueNormal || id == CSSValueSmallCaps)) {
3585             // Font variant in the shorthand is particular, it only accepts normal or small-caps.
3586             // See https://drafts.csswg.org/css-fonts/#propdef-font
3587             fontVariantCaps = consumeFontVariantCSS21(m_range);
3588             if (fontVariantCaps)
3589                 continue;
3590         }
3591         if (!fontWeight) {
3592             fontWeight = consumeFontWeight(m_range);
3593             if (fontWeight)
3594                 continue;
3595         }
3596         /* FIXME-NEWPARSER: Implement
3597          if (!fontStretch && CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyFontStretch, id, m_context.mode))
3598             fontStretch = consumeIdent(m_range);
3599         else*/
3600         break;
3601     }
3602
3603     if (m_range.atEnd())
3604         return false;
3605
3606     addProperty(CSSPropertyFontStyle, CSSPropertyFont, fontStyle ? fontStyle.releaseNonNull() : CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important);
3607     addProperty(CSSPropertyFontVariantCaps, CSSPropertyFont, fontVariantCaps ? fontVariantCaps.releaseNonNull() : CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important);
3608 /*  
3609     // FIXME-NEWPARSER: What do we do with these? They aren't part of our fontShorthand().
3610     addProperty(CSSPropertyFontVariantLigatures, CSSPropertyFont, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important);
3611     addProperty(CSSPropertyFontVariantNumeric, CSSPropertyFont, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important);
3612 */
3613     
3614     addProperty(CSSPropertyFontWeight, CSSPropertyFont, fontWeight ? fontWeight.releaseNonNull() : CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important);
3615     /* FIXME-NEWPARSER: Implement.
3616     addProperty(CSSPropertyFontStretch, CSSPropertyFont, fontStretch ? fontStretch.releaseNonNull() : CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important);
3617     */
3618
3619     // Now a font size _must_ come.
3620     RefPtr<CSSValue> fontSize = consumeFontSize(m_range, m_context.mode);
3621     if (!fontSize || m_range.atEnd())
3622         return false;
3623
3624     addProperty(CSSPropertyFontSize, CSSPropertyFont, *fontSize, important);
3625
3626     if (consumeSlashIncludingWhitespace(m_range)) {
3627         RefPtr<CSSPrimitiveValue> lineHeight = consumeLineHeight(m_range, m_context.mode);
3628         if (!lineHeight)
3629             return false;
3630         addProperty(CSSPropertyLineHeight, CSSPropertyFont, lineHeight.releaseNonNull(), important);
3631     } else {
3632         addProperty(CSSPropertyLineHeight, CSSPropertyFont, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important);
3633     }
3634
3635     // Font family must come now.
3636     RefPtr<CSSValue> parsedFamilyValue = consumeFontFamily(m_range);
3637     if (!parsedFamilyValue)
3638         return false;
3639
3640     addProperty(CSSPropertyFontFamily, CSSPropertyFont, parsedFamilyValue.releaseNonNull(), important);
3641
3642     // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requires that
3643     // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values
3644     // but we don't seem to support them at the moment. They should also be added here once implemented.
3645     return m_range.atEnd();
3646 }
3647
3648 bool CSSPropertyParser::consumeFontVariantShorthand(bool important)
3649 {
3650     if (identMatches<CSSValueNormal, CSSValueNone>(m_range.peek().id())) {
3651         addProperty(CSSPropertyFontVariantLigatures, CSSPropertyFontVariant, consumeIdent(m_range).releaseNonNull(), important);
3652         addProperty(CSSPropertyFontVariantCaps, CSSPropertyFontVariant, CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important);
3653         return m_range.atEnd();
3654     }
3655
3656     RefPtr<CSSPrimitiveValue> capsValue;
3657     FontVariantLigaturesParser ligaturesParser;
3658     FontVariantNumericParser numericParser;
3659     do {
3660         FontVariantLigaturesParser::ParseResult ligaturesParseResult = ligaturesParser.consumeLigature(m_range);
3661         FontVariantNumericParser::ParseResult numericParseResult = numericParser.consumeNumeric(m_range);
3662         if (ligaturesParseResult == FontVariantLigaturesParser::ParseResult::ConsumedValue
3663             || numericParseResult == FontVariantNumericParser::ParseResult::ConsumedValue)
3664             continue;
3665
3666         if (ligaturesParseResult == FontVariantLigaturesParser::ParseResult::DisallowedValue
3667             || numericParseResult == FontVariantNumericParser::ParseResult::DisallowedValue)
3668             return false;
3669
3670         CSSValueID id = m_range.peek().id();
3671         switch (id) {
3672         case CSSValueSmallCaps:
3673         case CSSValueAllSmallCaps:
3674         case CSSValuePetiteCaps:
3675         case CSSValueAllPetiteCaps:
3676         case CSSValueUnicase:
3677         case CSSValueTitlingCaps:
3678             // Only one caps value permitted in font-variant grammar.
3679             if (capsValue)
3680                 return false;
3681             capsValue = consumeIdent(m_range);
3682             break;
3683         default:
3684             return false;
3685         }
3686     } while (!m_range.atEnd());
3687
3688     addProperty(CSSPropertyFontVariantLigatures, CSSPropertyFontVariant, ligaturesParser.finalizeValue().releaseNonNull(), important);
3689     addProperty(CSSPropertyFontVariantNumeric, CSSPropertyFontVariant, numericParser.finalizeValue().releaseNonNull(), important);
3690     addProperty(CSSPropertyFontVariantCaps, CSSPropertyFontVariant, capsValue ? capsValue.releaseNonNull() : CSSValuePool::singleton().createIdentifierValue(CSSValueNormal), important);
3691     return true;
3692 }
3693
3694 bool CSSPropertyParser::consumeBorderSpacing(bool important)
3695 {
3696     RefPtr<CSSValue> horizontalSpacing = consumeLength(m_range, m_context.mode, ValueRangeNonNegative, UnitlessQuirk::Allow);
3697     if (!horizontalSpacing)
3698         return false;
3699     RefPtr<CSSValue> verticalSpacing = horizontalSpacing;
3700     if (!m_range.atEnd())
3701         verticalSpacing = consumeLength(m_range, m_context.mode, ValueRangeNonNegative, UnitlessQuirk::Allow);
3702     if (!verticalSpacing || !m_range.atEnd())
3703         return false;
3704     addProperty(CSSPropertyWebkitBorderHorizontalSpacing, CSSPropertyBorderSpacing, horizontalSpacing.releaseNonNull(), important);
3705     addProperty(CSSPropertyWebkitBorderVerticalSpacing, CSSPropertyBorderSpacing, verticalSpacing.releaseNonNull(), important);
3706     return true;
3707 }
3708
3709 #if ENABLE(CSS_DEVICE_ADAPTATION)
3710
3711 static RefPtr<CSSValue> consumeSingleViewportDescriptor(CSSParserTokenRange& range, CSSPropertyID propId, CSSParserMode cssParserMode)
3712 {
3713     CSSValueID id = range.peek().id();
3714     switch (propId) {
3715     case CSSPropertyMinWidth:
3716     case CSSPropertyMaxWidth:
3717     case CSSPropertyMinHeight:
3718     case CSSPropertyMaxHeight:
3719         if (id == CSSValueAuto)
3720             return consumeIdent(range);
3721         return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
3722     case CSSPropertyMinZoom:
3723     case CSSPropertyMaxZoom:
3724     case CSSPropertyZoom: {
3725         if (id == CSSValueAuto)
3726             return consumeIdent(range);
3727         RefPtr<CSSValue> parsedValue = consumeNumber(range, ValueRangeNonNegative);
3728         if (parsedValue)
3729             return parsedValue;
3730         return consumePercent(range, ValueRangeNonNegative);
3731     }
3732     case CSSPropertyUserZoom:
3733         return consumeIdent<CSSValueZoom, CSSValueFixed>(range);
3734     case CSSPropertyOrientation:
3735         return consumeIdent<CSSValueAuto, CSSValuePortrait, CSSValueLandscape>(range);
3736     default:
3737         ASSERT_NOT_REACHED();
3738         break;
3739     }
3740
3741     ASSERT_NOT_REACHED();
3742     return nullptr;
3743 }
3744
3745 bool CSSPropertyParser::parseViewportDescriptor(CSSPropertyID propId, bool important)
3746 {
3747     switch (propId) {
3748     case CSSPropertyWidth: {
3749         RefPtr<CSSValue> minWidth = consumeSingleViewportDescriptor(m_range, CSSPropertyMinWidth, m_context.mode);
3750         if (!minWidth)
3751             return false;
3752         RefPtr<CSSValue> maxWidth = minWidth;
3753         if (!m_range.atEnd())
3754             maxWidth = consumeSingleViewportDescriptor(m_range, CSSPropertyMaxWidth, m_context.mode);
3755         if (!maxWidth || !m_range.atEnd())
3756             return false;
3757         addProperty(CSSPropertyMinWidth, CSSPropertyInvalid, *minWidth, important);
3758         addProperty(CSSPropertyMaxWidth, CSSPropertyInvalid, *maxWidth, important);
3759         return true;
3760     }
3761     case CSSPropertyHeight: {
3762         RefPtr<CSSValue> minHeight = consumeSingleViewportDescriptor(m_range, CSSPropertyMinHeight, m_context.mode);
3763         if (!minHeight)
3764             return false;
3765         RefPtr<CSSValue> maxHeight = minHeight;
3766         if (!m_range.atEnd())
3767             maxHeight = consumeSingleViewportDescriptor(m_range, CSSPropertyMaxHeight, m_context.mode);
3768         if (!maxHeight || !m_range.atEnd())
3769             return false;
3770         addProperty(CSSPropertyMinHeight, CSSPropertyInvalid, *minHeight, important);
3771         addProperty(CSSPropertyMaxHeight, CSSPropertyInvalid, *maxHeight, important);
3772         return true;
3773     }
3774     case CSSPropertyMinWidth:
3775     case CSSPropertyMaxWidth:
3776     case CSSPropertyMinHeight:
3777     case CSSPropertyMaxHeight:
3778     case CSSPropertyMinZoom:
3779     case CSSPropertyMaxZoom:
3780     case CSSPropertyZoom:
3781     case CSSPropertyUserZoom:
3782     case CSSPropertyOrientation: {
3783         RefPtr<CSSValue> parsedValue = consumeSingleViewportDescriptor(m_range, propId, m_context.mode);
3784         if (!parsedValue || !m_range.atEnd())
3785             return false;
3786         addProperty(propId, CSSPropertyInvalid, parsedValue.releaseNonNull(), important);
3787         return true;
3788     }
3789     default:
3790         return false;
3791     }
3792 }
3793
3794 #endif
3795
3796 static bool consumeColumnWidthOrCount(CSSParserTokenRange& range, RefPtr<CSSValue>& columnWidth, RefPtr<CSSValue>& columnCount)
3797 {
3798     if (range.peek().id() == CSSValueAuto) {
3799         consumeIdent(range);
3800         return true;
3801     }
3802     if (!columnWidth) {
3803         columnWidth = consumeColumnWidth(range);
3804         if (columnWidth)
3805             return true;
3806     }
3807     if (!columnCount)
3808         columnCount = consumeColumnCount(range);
3809     return columnCount;
3810 }
3811
3812 bool CSSPropertyParser::consumeColumns(bool important)
3813 {
3814     RefPtr<CSSValue> columnWidth;
3815     RefPtr<CSSValue> columnCount;
3816     if (!consumeColumnWidthOrCount(m_range, columnWidth, columnCount))
3817         return false;
3818     consumeColumnWidthOrCount(m_range, columnWidth, columnCount);
3819     if (!m_range.atEnd())
3820         return false;
3821     if (!columnWidth)
3822         columnWidth = CSSValuePool::singleton().createIdentifierValue(CSSValueAuto);
3823     if (!columnCount)
3824         columnCount = CSSValuePool::singleton().createIdentifierValue(CSSValueAuto);
3825     addProperty(CSSPropertyColumnWidth, CSSPropertyInvalid, columnWidth.releaseNonNull(), important);
3826     addProperty(CSSPropertyColumnCount, CSSPropertyInvalid, columnCount.releaseNonNull(), important);
3827     return true;
3828 }
3829
3830 bool CSSPropertyParser::consumeShorthandGreedily(const StylePropertyShorthand& shorthand, bool important)
3831 {
3832     ASSERT(shorthand.length() <= 6); // Existing shorthands have at most 6 longhands.
3833     RefPtr<CSSValue> longhands[6];
3834     const CSSPropertyID* shorthandProperties = shorthand.properties();
3835     do {
3836         bool foundLonghand = false;
3837         for (size_t i = 0; !foundLonghand && i < shorthand.length(); ++i) {
3838             if (longhands[i])
3839                 continue;
3840             longhands[i] = parseSingleValue(shorthandProperties[i], shorthand.id());
3841             if (longhands[i])
3842                 foundLonghand = true;
3843         }
3844         if (!foundLonghand)
3845             return false;