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