[CSS Parser] The page-break-* properties are only keyword props for old parser.
[WebKit-https.git] / Source / WebCore / css / parser / CSSParserFastPaths.cpp
1 // Copyright 2014 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 "CSSParserFastPaths.h"
32
33 #include "CSSFunctionValue.h"
34 #include "CSSInheritedValue.h"
35 #include "CSSInitialValue.h"
36 #include "CSSParserIdioms.h"
37 #include "CSSPrimitiveValue.h"
38 #include "CSSPropertyParser.h"
39 #include "CSSValueList.h"
40 #include "CSSValuePool.h"
41 #include "HTMLParserIdioms.h"
42 #include "RuntimeEnabledFeatures.h"
43 #include "StyleColor.h"
44 #include "StylePropertyShorthand.h"
45 #include "StyleSheetContents.h"
46
47 namespace WebCore {
48
49 static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
50 {
51     switch (propertyId) {
52     case CSSPropertyFontSize:
53 #if ENABLE(CSS_GRID_LAYOUT)
54     case CSSPropertyGridColumnGap:
55     case CSSPropertyGridRowGap:
56 #endif
57     case CSSPropertyHeight:
58     case CSSPropertyWidth:
59     case CSSPropertyMinHeight:
60     case CSSPropertyMinWidth:
61     case CSSPropertyPaddingBottom:
62     case CSSPropertyPaddingLeft:
63     case CSSPropertyPaddingRight:
64     case CSSPropertyPaddingTop:
65     case CSSPropertyWebkitLogicalWidth:
66     case CSSPropertyWebkitLogicalHeight:
67     case CSSPropertyWebkitMinLogicalWidth:
68     case CSSPropertyWebkitMinLogicalHeight:
69     case CSSPropertyWebkitPaddingAfter:
70     case CSSPropertyWebkitPaddingBefore:
71     case CSSPropertyWebkitPaddingEnd:
72     case CSSPropertyWebkitPaddingStart:
73     case CSSPropertyShapeMargin:
74     case CSSPropertyR:
75     case CSSPropertyRx:
76     case CSSPropertyRy:
77         acceptsNegativeNumbers = false;
78         return true;
79     case CSSPropertyBottom:
80     case CSSPropertyCx:
81     case CSSPropertyCy:
82     case CSSPropertyLeft:
83     case CSSPropertyMarginBottom:
84     case CSSPropertyMarginLeft:
85     case CSSPropertyMarginRight:
86     case CSSPropertyMarginTop:
87     case CSSPropertyRight:
88     case CSSPropertyTop:
89     case CSSPropertyWebkitMarginAfter:
90     case CSSPropertyWebkitMarginBefore:
91     case CSSPropertyWebkitMarginEnd:
92     case CSSPropertyWebkitMarginStart:
93     case CSSPropertyX:
94     case CSSPropertyY:
95         acceptsNegativeNumbers = true;
96         return true;
97     default:
98         return false;
99     }
100 }
101
102 template <typename CharacterType>
103 static inline bool parseSimpleLength(const CharacterType* characters, unsigned length, CSSPrimitiveValue::UnitTypes& unit, double& number)
104 {
105     if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
106         length -= 2;
107         unit = CSSPrimitiveValue::UnitTypes::CSS_PX;
108     } else if (length > 1 && characters[length - 1] == '%') {
109         length -= 1;
110         unit = CSSPrimitiveValue::UnitTypes::CSS_PERCENTAGE;
111     }
112
113     // We rely on charactersToDouble for validation as well. The function
114     // will set "ok" to "false" if the entire passed-in character range does
115     // not represent a double.
116     bool ok;
117     number = charactersToDouble(characters, length, &ok);
118     if (!ok)
119         return false;
120     number = clampTo<double>(number, -std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
121     return true;
122 }
123
124 static RefPtr<CSSValue> parseSimpleLengthValue(CSSPropertyID propertyId, const String& string, CSSParserMode cssParserMode)
125 {
126     ASSERT(!string.isEmpty());
127     bool acceptsNegativeNumbers = false;
128
129     // In @viewport, width and height are shorthands, not simple length values.
130     if (isCSSViewportParsingEnabledForMode(cssParserMode) || !isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
131         return nullptr;
132
133     unsigned length = string.length();
134     double number;
135     CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::UnitTypes::CSS_NUMBER;
136
137     if (string.is8Bit()) {
138         if (!parseSimpleLength(string.characters8(), length, unit, number))
139             return nullptr;
140     } else {
141         if (!parseSimpleLength(string.characters16(), length, unit, number))
142             return nullptr;
143     }
144
145     if (unit == CSSPrimitiveValue::UnitTypes::CSS_NUMBER) {
146         if (number && cssParserMode != SVGAttributeMode)
147             return nullptr;
148         unit = CSSPrimitiveValue::UnitTypes::CSS_PX;
149     }
150
151     if (number < 0 && !acceptsNegativeNumbers)
152         return nullptr;
153
154     return CSSPrimitiveValue::create(number, unit);
155 }
156
157 static inline bool isColorPropertyID(CSSPropertyID propertyId)
158 {
159     switch (propertyId) {
160     case CSSPropertyColor:
161     case CSSPropertyBackgroundColor:
162     case CSSPropertyBorderBottomColor:
163     case CSSPropertyBorderLeftColor:
164     case CSSPropertyBorderRightColor:
165     case CSSPropertyBorderTopColor:
166     case CSSPropertyFill:
167     case CSSPropertyFloodColor:
168     case CSSPropertyLightingColor:
169     case CSSPropertyOutlineColor:
170     case CSSPropertyStopColor:
171     case CSSPropertyStroke:
172     case CSSPropertyWebkitBorderAfterColor:
173     case CSSPropertyWebkitBorderBeforeColor:
174     case CSSPropertyWebkitBorderEndColor:
175     case CSSPropertyWebkitBorderStartColor:
176     case CSSPropertyColumnRuleColor:
177     case CSSPropertyWebkitTextEmphasisColor:
178     case CSSPropertyWebkitTextFillColor:
179     case CSSPropertyWebkitTextStrokeColor:
180     case CSSPropertyWebkitTextDecorationColor:
181         return true;
182     default:
183         return false;
184     }
185 }
186
187 // Returns the number of characters which form a valid double
188 // and are terminated by the given terminator character
189 template <typename CharacterType>
190 static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
191 {
192     int length = end - string;
193     if (length < 1)
194         return 0;
195
196     bool decimalMarkSeen = false;
197     int processedLength = 0;
198
199     for (int i = 0; i < length; ++i) {
200         if (string[i] == terminator) {
201             processedLength = i;
202             break;
203         }
204         if (!isASCIIDigit(string[i])) {
205             if (!decimalMarkSeen && string[i] == '.')
206                 decimalMarkSeen = true;
207             else
208                 return 0;
209         }
210     }
211
212     if (decimalMarkSeen && processedLength == 1)
213         return 0;
214
215     return processedLength;
216 }
217
218 // Returns the number of characters consumed for parsing a valid double
219 // terminated by the given terminator character
220 template <typename CharacterType>
221 static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
222 {
223     int length = checkForValidDouble(string, end, terminator);
224     if (!length)
225         return 0;
226
227     int position = 0;
228     double localValue = 0;
229
230     // The consumed characters here are guaranteed to be
231     // ASCII digits with or without a decimal mark
232     for (; position < length; ++position) {
233         if (string[position] == '.')
234             break;
235         localValue = localValue * 10 + string[position] - '0';
236     }
237
238     if (++position == length) {
239         value = localValue;
240         return length;
241     }
242
243     double fraction = 0;
244     double scale = 1;
245
246     const double maxScale = 1000000;
247     while (position < length && scale < maxScale) {
248         fraction = fraction * 10 + string[position++] - '0';
249         scale *= 10;
250     }
251
252     value = localValue + fraction / scale;
253     return length;
254 }
255
256 template <typename CharacterType>
257 static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value)
258 {
259     const CharacterType* current = string;
260     double localValue = 0;
261     bool negative = false;
262     while (current != end && isHTMLSpace<CharacterType>(*current))
263         current++;
264     if (current != end && *current == '-') {
265         negative = true;
266         current++;
267     }
268     if (current == end || !isASCIIDigit(*current))
269         return false;
270     while (current != end && isASCIIDigit(*current)) {
271         double newValue = localValue * 10 + *current++ - '0';
272         if (newValue >= 255) {
273             // Clamp values at 255.
274             localValue = 255;
275             while (current != end && isASCIIDigit(*current))
276                 ++current;
277             break;
278         }
279         localValue = newValue;
280     }
281
282     if (current == end)
283         return false;
284
285     if (expect == CSSPrimitiveValue::UnitTypes::CSS_NUMBER && (*current == '.' || *current == '%'))
286         return false;
287
288     if (*current == '.') {
289         // We already parsed the integral part, try to parse
290         // the fraction part of the percentage value.
291         double percentage = 0;
292         int numCharactersParsed = parseDouble(current, end, '%', percentage);
293         if (!numCharactersParsed)
294             return false;
295         current += numCharactersParsed;
296         if (*current != '%')
297             return false;
298         localValue += percentage;
299     }
300
301     if (expect == CSSPrimitiveValue::UnitTypes::CSS_PERCENTAGE && *current != '%')
302         return false;
303
304     if (*current == '%') {
305         expect = CSSPrimitiveValue::UnitTypes::CSS_PERCENTAGE;
306         localValue = localValue / 100.0 * 256.0;
307         // Clamp values at 255 for percentages over 100%
308         if (localValue > 255)
309             localValue = 255;
310         current++;
311     } else {
312         expect = CSSPrimitiveValue::UnitTypes::CSS_NUMBER;
313     }
314
315     while (current != end && isHTMLSpace<CharacterType>(*current))
316         current++;
317     if (current == end || *current++ != terminator)
318         return false;
319     // Clamp negative values at zero.
320     value = negative ? 0 : static_cast<int>(localValue);
321     string = current;
322     return true;
323 }
324
325 template <typename CharacterType>
326 static inline bool isTenthAlpha(const CharacterType* string, const int length)
327 {
328     // "0.X"
329     if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
330         return true;
331
332     // ".X"
333     if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
334         return true;
335
336     return false;
337 }
338
339 template <typename CharacterType>
340 static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
341 {
342     while (string != end && isHTMLSpace<CharacterType>(*string))
343         string++;
344
345     bool negative = false;
346
347     if (string != end && *string == '-') {
348         negative = true;
349         string++;
350     }
351
352     value = 0;
353
354     int length = end - string;
355     if (length < 2)
356         return false;
357
358     if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
359         return false;
360
361     if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
362         if (checkForValidDouble(string, end, terminator)) {
363             value = negative ? 0 : 255;
364             string = end;
365             return true;
366         }
367         return false;
368     }
369
370     if (length == 2 && string[0] != '.') {
371         value = !negative && string[0] == '1' ? 255 : 0;
372         string = end;
373         return true;
374     }
375
376     if (isTenthAlpha(string, length - 1)) {
377         static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
378         value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
379         string = end;
380         return true;
381     }
382
383     double alpha = 0;
384     if (!parseDouble(string, end, terminator, alpha))
385         return false;
386     value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
387     string = end;
388     return true;
389 }
390
391 template <typename CharacterType>
392 static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
393 {
394     if (length < 5)
395         return false;
396     return characters[4] == '('
397         && isASCIIAlphaCaselessEqual(characters[0], 'r')
398         && isASCIIAlphaCaselessEqual(characters[1], 'g')
399         && isASCIIAlphaCaselessEqual(characters[2], 'b')
400         && isASCIIAlphaCaselessEqual(characters[3], 'a');
401 }
402
403 template <typename CharacterType>
404 static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
405 {
406     if (length < 4)
407         return false;
408     return characters[3] == '('
409         && isASCIIAlphaCaselessEqual(characters[0], 'r')
410         && isASCIIAlphaCaselessEqual(characters[1], 'g')
411         && isASCIIAlphaCaselessEqual(characters[2], 'b');
412 }
413
414 template <typename CharacterType>
415 static Color fastParseColorInternal(const CharacterType* characters, unsigned length, bool quirksMode)
416 {
417     CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::UnitTypes::CSS_UNKNOWN;
418
419     if (length >= 4 && characters[0] == '#') {
420         // FIXME: Why doesn't this check if the parse worked? Is the fallback black?
421         RGBA32 rgb;
422         Color::parseHexColor(characters + 1, length - 1, rgb);
423         return Color(rgb);
424     }
425
426     if (quirksMode && (length == 3 || length == 6)) {
427         RGBA32 rgb;
428         if (Color::parseHexColor(characters, length, rgb))
429             return Color(rgb);
430     }
431
432     // Try rgba() syntax.
433     if (mightBeRGBA(characters, length)) {
434         const CharacterType* current = characters + 5;
435         const CharacterType* end = characters + length;
436         int red;
437         int green;
438         int blue;
439         int alpha;
440
441         if (!parseColorIntOrPercentage(current, end, ',', expect, red))
442             return Color();
443         if (!parseColorIntOrPercentage(current, end, ',', expect, green))
444             return Color();
445         if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
446             return Color();
447         if (!parseAlphaValue(current, end, ')', alpha))
448             return Color();
449         if (current != end)
450             return Color();
451         return Color(makeRGBA(red, green, blue, alpha));
452     }
453
454     // Try rgb() syntax.
455     if (mightBeRGB(characters, length)) {
456         const CharacterType* current = characters + 4;
457         const CharacterType* end = characters + length;
458         int red;
459         int green;
460         int blue;
461         if (!parseColorIntOrPercentage(current, end, ',', expect, red))
462             return Color();
463         if (!parseColorIntOrPercentage(current, end, ',', expect, green))
464             return Color();
465         if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
466             return Color();
467         if (current != end)
468             return Color();
469         return Color(makeRGB(red, green, blue));
470     }
471
472     return Color();
473 }
474
475 RefPtr<CSSValue> CSSParserFastPaths::parseColor(const String& string, CSSParserMode parserMode)
476 {
477     ASSERT(!string.isEmpty());
478     CSSValueID valueID = cssValueKeywordID(string);
479     if (StyleColor::isColorKeyword(valueID)) {
480         if (!isValueAllowedInMode(valueID, parserMode))
481             return nullptr;
482         return CSSValuePool::singleton().createIdentifierValue(valueID);
483     }
484
485     bool quirksMode = isQuirksModeBehavior(parserMode);
486
487     // Fast path for hex colors and rgb()/rgba() colors
488     Color color;
489     if (string.is8Bit())
490         color = fastParseColorInternal(string.characters8(), string.length(), quirksMode);
491     else
492         color = fastParseColorInternal(string.characters16(), string.length(), quirksMode);
493     if (!color.isValid())
494         return nullptr;
495     return CSSValuePool::singleton().createColorValue(color);
496 }
497
498 bool CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyID propertyId, CSSValueID valueID, CSSParserMode parserMode, StyleSheetContents* styleSheetContents)
499 {
500     if (valueID == CSSValueInvalid || !isValueAllowedInMode(valueID, parserMode))
501         return false;
502
503     switch (propertyId) {
504     case CSSPropertyAlignmentBaseline:
505         // auto | baseline | before-edge | text-before-edge | middle |
506         // central | after-edge | text-after-edge | ideographic | alphabetic |
507         // hanging | mathematical
508         return valueID == CSSValueAuto || valueID == CSSValueAlphabetic || valueID == CSSValueBaseline
509             || valueID == CSSValueMiddle || (valueID >= CSSValueBeforeEdge && valueID <= CSSValueMathematical);
510     case CSSPropertyAll:
511         return false; // Only accepts css-wide keywords
512     case CSSPropertyBackgroundRepeatX: // repeat | no-repeat
513     case CSSPropertyBackgroundRepeatY: // repeat | no-repeat
514         return valueID == CSSValueRepeat || valueID == CSSValueNoRepeat;
515     case CSSPropertyBorderCollapse: // collapse | separate
516         return valueID == CSSValueCollapse || valueID == CSSValueSeparate;
517     case CSSPropertyBorderTopStyle: // <border-style>
518     case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
519     case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
520     case CSSPropertyBorderLeftStyle:
521     case CSSPropertyWebkitBorderAfterStyle:
522     case CSSPropertyWebkitBorderBeforeStyle:
523     case CSSPropertyWebkitBorderEndStyle:
524     case CSSPropertyWebkitBorderStartStyle:
525     case CSSPropertyColumnRuleStyle:
526         return valueID >= CSSValueNone && valueID <= CSSValueDouble;
527     case CSSPropertyBoxSizing:
528         return valueID == CSSValueBorderBox || valueID == CSSValueContentBox;
529     case CSSPropertyBufferedRendering:
530         return valueID == CSSValueAuto || valueID == CSSValueDynamic || valueID == CSSValueStatic;
531     case CSSPropertyCaptionSide: // top | bottom | left | right
532         return valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom;
533     case CSSPropertyClear: // none | left | right | both
534         return valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth;
535     case CSSPropertyClipRule:
536     case CSSPropertyFillRule:
537         return valueID == CSSValueNonzero || valueID == CSSValueEvenodd;
538     case CSSPropertyColorInterpolation:
539     case CSSPropertyColorInterpolationFilters:
540         return valueID == CSSValueAuto || valueID == CSSValueSrgb || valueID == CSSValueLinearrgb;
541     case CSSPropertyColorRendering:
542         return valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizequality;
543     case CSSPropertyDirection: // ltr | rtl
544         return valueID == CSSValueLtr || valueID == CSSValueRtl;
545     case CSSPropertyDisplay:
546         // inline | block | list-item | inline-block | table |
547         // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
548         // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none
549         // flex | inline-flex | -webkit-flex | -webkit-inline-flex | grid | inline-grid
550         return (valueID >= CSSValueInline && valueID <= CSSValueContents) || valueID == CSSValueNone
551 #if ENABLE(CSS_GRID_LAYOUT)
552             || (RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled() && (valueID == CSSValueGrid || valueID == CSSValueInlineGrid))
553 #endif
554         ;
555     case CSSPropertyDominantBaseline:
556         // auto | use-script | no-change | reset-size | ideographic |
557         // alphabetic | hanging | mathematical | central | middle |
558         // text-after-edge | text-before-edge
559         return valueID == CSSValueAuto || valueID == CSSValueAlphabetic || valueID == CSSValueMiddle
560             || (valueID >= CSSValueUseScript && valueID <= CSSValueResetSize)
561             || (valueID >= CSSValueCentral && valueID <= CSSValueMathematical);
562     case CSSPropertyEmptyCells: // show | hide
563         return valueID == CSSValueShow || valueID == CSSValueHide;
564     case CSSPropertyFloat: // left | right | none
565         return valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone;
566     case CSSPropertyFontStyle: // normal | italic | oblique
567         return valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique;
568     case CSSPropertyFontStretch: // normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded
569         return valueID == CSSValueNormal || (valueID >= CSSValueUltraCondensed && valueID <= CSSValueUltraExpanded);
570     case CSSPropertyImageRendering: // auto | optimizeContrast | pixelated | optimizeSpeed | crispEdges | optimizeQuality | webkit-crispEdges
571         return valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizequality || valueID == CSSValueWebkitCrispEdges || valueID == CSSValueWebkitOptimizeContrast || valueID == CSSValueCrispEdges || valueID == CSSValuePixelated;
572 #if ENABLE(CSS_COMPOSITING)
573     case CSSPropertyIsolation: // auto | isolate
574         return valueID == CSSValueAuto || valueID == CSSValueIsolate;
575 #endif
576     case CSSPropertyListStylePosition: // inside | outside
577         return valueID == CSSValueInside || valueID == CSSValueOutside;
578     case CSSPropertyListStyleType:
579         // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
580         // for the list of supported list-style-types.
581         return (valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone;
582     case CSSPropertyMaskType:
583         return valueID == CSSValueLuminance || valueID == CSSValueAlpha;
584     case CSSPropertyObjectFit:
585         return valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown;
586     case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto
587         return valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble);
588     // FIXME-NEWPARSER: Support?
589     // case CSSPropertyOverflowAnchor:
590     //    return valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAuto;
591     case CSSPropertyOverflowWrap: // normal | break-word
592     case CSSPropertyWordWrap:
593         return valueID == CSSValueNormal || valueID == CSSValueBreakWord;
594     case CSSPropertyOverflowX: // visible | hidden | scroll | auto | overlay
595         return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay;
596     case CSSPropertyOverflowY: // visible | hidden | scroll | auto | overlay | -webkit-paged-x | -webkit-paged-y
597         return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY;
598     case CSSPropertyBreakAfter:
599     case CSSPropertyBreakBefore:
600         return valueID == CSSValueAuto || valueID == CSSValueAvoid || valueID == CSSValueAvoidPage || valueID == CSSValuePage || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueRecto || valueID == CSSValueVerso || valueID == CSSValueAvoidColumn || valueID == CSSValueColumn
601 #if ENABLE(CSS_REGIONS)
602             || valueID == CSSValueRegion || valueID == CSSValueAvoidRegion
603 #endif
604         ;
605     case CSSPropertyBreakInside:
606         return valueID == CSSValueAuto || valueID == CSSValueAvoid || valueID == CSSValueAvoidPage || valueID == CSSValueAvoidColumn
607 #if ENABLE(CSS_REGIONS)
608             || valueID == CSSValueAvoidRegion
609 #endif
610         ;
611     case CSSPropertyPointerEvents:
612         // none | visiblePainted | visibleFill | visibleStroke | visible |
613         // painted | fill | stroke | auto | all | bounding-box
614         return valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueStroke);
615     case CSSPropertyPosition: // static | relative | absolute | fixed | sticky
616         return valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed || valueID == CSSValueWebkitSticky;
617     case CSSPropertyResize: // none | both | horizontal | vertical | auto
618         return valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto;
619     // FIXME-NEWPARSER: Investigate this property.
620     // case CSSPropertyScrollBehavior: // auto | smooth
621     //     ASSERT(RuntimeEnabledFeatures::cssomSmoothScrollEnabled());
622     //   return valueID == CSSValueAuto || valueID == CSSValueSmooth;
623     case CSSPropertyShapeRendering:
624         return valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueCrispEdges || valueID == CSSValueGeometricprecision;
625     case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation
626         return valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation;
627     case CSSPropertyStrokeLinejoin:
628         return valueID == CSSValueMiter || valueID == CSSValueRound || valueID == CSSValueBevel;
629     case CSSPropertyStrokeLinecap:
630         return valueID == CSSValueButt || valueID == CSSValueRound || valueID == CSSValueSquare;
631     case CSSPropertyTableLayout: // auto | fixed
632         return valueID == CSSValueAuto || valueID == CSSValueFixed;
633     case CSSPropertyTextAlign:
634         return (valueID >= CSSValueWebkitAuto && valueID <= CSSValueWebkitMatchParent) || valueID == CSSValueStart || valueID == CSSValueEnd;
635 #if ENABLE(CSS3_TEXT)
636     case CSSPropertyWebkitTextAlignLast:
637         // auto | start | end | left | right | center | justify
638         return (valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto;
639 #endif
640     case CSSPropertyTextAnchor:
641         return valueID == CSSValueStart || valueID == CSSValueMiddle || valueID == CSSValueEnd;
642 // FIXME-NEWPARSER: Support
643 //    case CSSPropertyTextCombineUpright:
644 //        return valueID == CSSValueNone || valueID == CSSValueAll;
645     case CSSPropertyWebkitTextDecorationStyle:
646         // solid | double | dotted | dashed | wavy
647         return valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDotted || valueID == CSSValueDashed || valueID == CSSValueWavy;
648 #if ENABLE(CSS3_TEXT)
649     case CSSPropertyWebkitTextJustify:
650         // auto | none | inter-word | distribute
651         return valueID == CSSValueInterWord || valueID == CSSValueDistribute || valueID == CSSValueAuto || valueID == CSSValueNone;
652 #endif
653     case CSSPropertyWebkitTextOrientation: // mixed | upright | sideways | sideways-right
654         return valueID == CSSValueMixed || valueID == CSSValueUpright || valueID == CSSValueSideways || valueID == CSSValueSidewaysRight;
655     case CSSPropertyTextOverflow: // clip | ellipsis
656         return valueID == CSSValueClip || valueID == CSSValueEllipsis;
657     case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
658         return valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision;
659     case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none
660         return (valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone;
661     case CSSPropertyUnicodeBidi:
662         return valueID == CSSValueNormal || valueID == CSSValueEmbed
663             || valueID == CSSValueBidiOverride || valueID == CSSValueWebkitIsolate
664             || valueID == CSSValueWebkitIsolateOverride || valueID == CSSValueWebkitPlaintext;
665     case CSSPropertyVectorEffect:
666         return valueID == CSSValueNone || valueID == CSSValueNonScalingStroke;
667     case CSSPropertyVisibility: // visible | hidden | collapse
668         return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse;
669     case CSSPropertyWebkitAppearance:
670         return (valueID >= CSSValueCheckbox && valueID <= CSSValueCapsLockIndicator) || valueID == CSSValueNone;
671     case CSSPropertyWebkitBackfaceVisibility:
672         return valueID == CSSValueVisible || valueID == CSSValueHidden;
673 #if ENABLE(CSS_COMPOSITING)
674     case CSSPropertyMixBlendMode:
675         return valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen || valueID == CSSValueOverlay
676             || valueID == CSSValueDarken || valueID == CSSValueLighten || valueID == CSSValueColorDodge || valueID == CSSValueColorBurn
677             || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference || valueID == CSSValueExclusion
678             || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor || valueID == CSSValueLuminosity || valueID == CSSValuePlusDarker || valueID == CSSValuePlusLighter;
679 #endif
680     case CSSPropertyWebkitBoxAlign:
681         return valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline;
682 #if ENABLE(CSS_BOX_DECORATION_BREAK)
683     case CSSPropertyWebkitBoxDecorationBreak:
684         return valueID == CSSValueClone || valueID == CSSValueSlice;
685     case CSSPropertyWebkitBoxDirection:
686         return valueID == CSSValueNormal || valueID == CSSValueReverse;
687 #endif
688     case CSSPropertyWebkitBoxLines:
689         return valueID == CSSValueSingle || valueID == CSSValueMultiple;
690     case CSSPropertyWebkitBoxOrient:
691         return valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis;
692     case CSSPropertyWebkitBoxPack:
693         return valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify;
694     case CSSPropertyColumnFill:
695         return valueID == CSSValueAuto || valueID == CSSValueBalance;
696     case CSSPropertyWebkitColumnAxis:
697         return valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto;
698     case CSSPropertyWebkitColumnProgression:
699         return valueID == CSSValueNormal || valueID == CSSValueReverse;
700     case CSSPropertyAlignContent:
701         // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
702         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch;
703     case CSSPropertyAlignItems:
704         // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
705         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
706     case CSSPropertyAlignSelf:
707         // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
708         return valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
709     case CSSPropertyFlexDirection:
710         return valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse;
711     case CSSPropertyFlexWrap:
712         return valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse;
713     case CSSPropertyWebkitHyphens:
714         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueManual;
715     case CSSPropertyJustifyContent:
716         // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
717         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround;
718     case CSSPropertyWebkitFontKerning:
719         return valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone;
720     case CSSPropertyWebkitFontSmoothing:
721         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased;
722     case CSSPropertyWebkitLineAlign:
723         return valueID == CSSValueNone || valueID == CSSValueEdges;
724     case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
725         return valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace;
726     case CSSPropertyWebkitLineSnap:
727         return valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain;
728     case CSSPropertyWebkitMarginAfterCollapse:
729     case CSSPropertyWebkitMarginBeforeCollapse:
730     case CSSPropertyWebkitMarginBottomCollapse:
731     case CSSPropertyWebkitMarginTopCollapse:
732         return valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard;
733     case CSSPropertyWebkitPrintColorAdjust:
734         return valueID == CSSValueExact || valueID == CSSValueEconomy;
735     case CSSPropertyWebkitRtlOrdering:
736         return valueID == CSSValueLogical || valueID == CSSValueVisual;
737     case CSSPropertyWebkitRubyPosition:
738         return valueID == CSSValueBefore || valueID == CSSValueAfter || valueID == CSSValueInterCharacter;
739     case CSSPropertyWebkitTextCombine:
740         return valueID == CSSValueNone || valueID == CSSValueHorizontal;
741     case CSSPropertyWebkitTextSecurity: // disc | circle | square | none
742         return valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone;
743     case CSSPropertyTransformStyle:
744     case CSSPropertyWebkitTransformStyle:
745         return valueID == CSSValueFlat || valueID == CSSValuePreserve3d;
746     case CSSPropertyWebkitUserDrag: // auto | none | element
747         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement;
748     case CSSPropertyWebkitUserModify: // read-only | read-write
749         if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly) {
750             if (styleSheetContents)
751                 styleSheetContents->parserSetUsesStyleBasedEditability();
752             return true;
753         }
754         return false;
755     case CSSPropertyWebkitUserSelect: // auto | none | text | all
756         if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText)
757             return true;
758         if (valueID == CSSValueAll) {
759             if (styleSheetContents)
760                 styleSheetContents->parserSetUsesStyleBasedEditability();
761             return true;
762         }
763         return false;
764     case CSSPropertyWritingMode:
765         // Note that horizontal-bt is not supported by the unprefixed version of
766         // the property, only by the -webkit- version.
767         return (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
768             || valueID == CSSValueLrTb || valueID == CSSValueRlTb || valueID == CSSValueTbRl
769             || valueID == CSSValueLr || valueID == CSSValueRl || valueID == CSSValueTb;
770     case CSSPropertyWhiteSpace: // normal | pre | nowrap
771         return valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap;
772     case CSSPropertyWordBreak: // normal | break-all | keep-all | break-word (this is a custom extension)
773         return valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueKeepAll || valueID == CSSValueBreakWord;
774     case CSSPropertyWebkitBorderFit:
775         return valueID == CSSValueBorder || valueID == CSSValueLines;
776 #if ENABLE(CSS_REGIONS)
777     case CSSPropertyWebkitRegionFragment:
778         return valueID == CSSValueAuto || valueID == CSSValueBreak;
779 #endif
780 #if ENABLE(CSS_SCROLL_SNAP)
781     case CSSPropertyWebkitScrollSnapType: // none | mandatory | proximity
782         return valueID == CSSValueNone || valueID == CSSValueMandatory || valueID == CSSValueProximity;
783 #endif
784 #if ENABLE(TOUCH_EVENTS)
785     case CSSPropertyTouchAction: // auto | manipulation
786         return valueID == CSSValueAuto || valueID == CSSValueManipulation;
787 #endif
788 #if ENABLE(CSS_TRAILING_WORD)
789     case CSSPropertyAppleTrailingWord: // auto | -apple-partially-balanced
790         return valueID == CSSValueAuto || valueID == CSSValueWebkitPartiallyBalanced;
791 #endif
792 #if ENABLE(APPLE_PAY)
793     case CSSPropertyApplePayButtonStyle: // white | white-outline | black
794         return valueID == CSSValueWhite || valueID == CSSValueWhiteOutline || valueID == CSSValueBlack;
795     case CSSPropertyApplePayButtonType: // plain | buy | set-up | donate
796         return valueID == CSSValuePlain || valueID == CSSValueBuy || valueID == CSSValueSetUp || valueID == CSSValueDonate;
797 #endif
798     case CSSPropertyWebkitNbspMode: // normal | space
799         return valueID == CSSValueNormal || valueID == CSSValueSpace;
800     case CSSPropertyWebkitTextZoom:
801         return valueID == CSSValueNormal || valueID == CSSValueReset;
802 #if PLATFORM(IOS)
803     // Apple specific property. These will never be standardized and is purely to
804     // support custom WebKit-based Apple applications.
805     case CSSPropertyWebkitTouchCallout:
806         return valueID == CSSValueDefault || valueID == CSSValueNone;
807 #endif
808     case CSSPropertyWebkitMarqueeDirection:
809         return valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
810             || valueID == CSSValueUp || valueID == CSSValueAuto;
811     case CSSPropertyWebkitMarqueeStyle:
812         return valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate;
813     case CSSPropertyFontVariantPosition: // normal | sub | super
814         return valueID == CSSValueNormal || valueID == CSSValueSub || valueID == CSSValueSuper;
815     case CSSPropertyFontVariantCaps: // normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps
816         return valueID == CSSValueNormal || valueID == CSSValueSmallCaps || valueID == CSSValueAllSmallCaps || valueID == CSSValuePetiteCaps || valueID == CSSValueAllPetiteCaps || valueID == CSSValueUnicase || valueID == CSSValueTitlingCaps;
817     case CSSPropertyFontVariantAlternates: // We only support the normal and historical-forms values.
818         return valueID == CSSValueNormal || valueID == CSSValueHistoricalForms;
819 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
820     case CSSPropertyWebkitOverflowScrolling:
821         return valueID == CSSValueAuto || valueID == CSSValueTouch;
822 #endif
823     default:
824         ASSERT_NOT_REACHED();
825         return false;
826     }
827 }
828
829 bool CSSParserFastPaths::isKeywordPropertyID(CSSPropertyID propertyId)
830 {
831     switch (propertyId) {
832     case CSSPropertyBorderBottomStyle:
833     case CSSPropertyBorderCollapse:
834     case CSSPropertyBorderLeftStyle:
835     case CSSPropertyBorderRightStyle:
836     case CSSPropertyBorderTopStyle:
837     case CSSPropertyBoxSizing:
838     case CSSPropertyBreakAfter:
839     case CSSPropertyBreakBefore:
840     case CSSPropertyBreakInside:
841     case CSSPropertyCaptionSide:
842     case CSSPropertyClear:
843     case CSSPropertyColumnFill:
844     case CSSPropertyWebkitColumnProgression:
845     case CSSPropertyColumnRuleStyle:
846     case CSSPropertyDirection:
847     case CSSPropertyDisplay:
848     case CSSPropertyEmptyCells:
849     case CSSPropertyFlexDirection:
850     case CSSPropertyFlexWrap:
851     case CSSPropertyFloat:
852     case CSSPropertyFontStretch:
853     case CSSPropertyFontStyle:
854     case CSSPropertyFontVariantAlternates:
855     case CSSPropertyFontVariantCaps:
856     case CSSPropertyFontVariantPosition:
857     case CSSPropertyImageRendering:
858     case CSSPropertyListStylePosition:
859     case CSSPropertyListStyleType:
860     case CSSPropertyObjectFit:
861     case CSSPropertyOutlineStyle:
862     case CSSPropertyOverflowWrap:
863     case CSSPropertyOverflowX:
864     case CSSPropertyOverflowY:
865     case CSSPropertyPointerEvents:
866     case CSSPropertyPosition:
867     case CSSPropertyResize:
868     case CSSPropertySpeak:
869     case CSSPropertyTableLayout:
870     case CSSPropertyTextAlign:
871     case CSSPropertyTextLineThroughMode:
872     case CSSPropertyTextLineThroughStyle:
873     case CSSPropertyTextOverflow:
874     case CSSPropertyTextOverlineMode:
875     case CSSPropertyTextOverlineStyle:
876     case CSSPropertyTextRendering:
877     case CSSPropertyTextTransform:
878     case CSSPropertyTextUnderlineMode:
879     case CSSPropertyTextUnderlineStyle:
880     case CSSPropertyTransformStyle:
881     case CSSPropertyUnicodeBidi:
882     case CSSPropertyVisibility:
883     case CSSPropertyWebkitAppearance:
884     case CSSPropertyWebkitBackfaceVisibility:
885     case CSSPropertyWebkitBorderAfterStyle:
886     case CSSPropertyWebkitBorderBeforeStyle:
887     case CSSPropertyWebkitBorderEndStyle:
888     case CSSPropertyWebkitBorderFit:
889     case CSSPropertyWebkitBorderStartStyle:
890     case CSSPropertyWebkitBoxAlign:
891     case CSSPropertyWebkitBoxDirection:
892     case CSSPropertyWebkitBoxLines:
893     case CSSPropertyWebkitBoxOrient:
894     case CSSPropertyWebkitBoxPack:
895     case CSSPropertyWebkitColumnAxis:
896     case CSSPropertyWebkitFontKerning:
897     case CSSPropertyWebkitFontSmoothing:
898     case CSSPropertyWebkitHyphens:
899     case CSSPropertyWebkitLineAlign:
900     case CSSPropertyWebkitLineBreak:
901     case CSSPropertyWebkitLineSnap:
902     case CSSPropertyWebkitMarginAfterCollapse:
903     case CSSPropertyWebkitMarginBeforeCollapse:
904     case CSSPropertyWebkitMarginBottomCollapse:
905     case CSSPropertyWebkitMarginTopCollapse:
906     case CSSPropertyWebkitMarqueeDirection:
907     case CSSPropertyWebkitMarqueeStyle:
908     case CSSPropertyWebkitNbspMode:
909     case CSSPropertyWebkitPrintColorAdjust:
910     case CSSPropertyWebkitRtlOrdering:
911     case CSSPropertyWebkitRubyPosition:
912     case CSSPropertyWebkitTextCombine:
913     case CSSPropertyWebkitTextDecorationStyle:
914     case CSSPropertyWebkitTextOrientation:
915     case CSSPropertyWebkitTextSecurity:
916     case CSSPropertyWebkitTextZoom:
917     case CSSPropertyWebkitTransformStyle:
918     case CSSPropertyWebkitUserDrag:
919     case CSSPropertyWebkitUserModify:
920     case CSSPropertyWebkitUserSelect:
921     case CSSPropertyWhiteSpace:
922     case CSSPropertyWordBreak:
923     case CSSPropertyWordWrap:
924
925     // SVG CSS properties from SVG 1.1, Appendix N: Property Index.
926     case CSSPropertyAlignmentBaseline:
927     case CSSPropertyBufferedRendering:
928     case CSSPropertyClipRule:
929     case CSSPropertyColorInterpolation:
930     case CSSPropertyColorInterpolationFilters:
931     case CSSPropertyColorRendering:
932     case CSSPropertyDominantBaseline:
933     case CSSPropertyFillRule:
934     case CSSPropertyMaskType:
935     case CSSPropertyShapeRendering:
936     case CSSPropertyStrokeLinecap:
937     case CSSPropertyStrokeLinejoin:
938     case CSSPropertyTextAnchor:
939     case CSSPropertyVectorEffect:
940     case CSSPropertyWritingMode:
941
942     // FIXME-NEWPARSER: Treat all as a keyword property.
943     // case CSSPropertyAll:
944
945     // FIXME-NEWPARSER: Treat the following properties as keyword properties:
946     // case CSSPropertyBackgroundRepeatX:
947     // case CSSPropertyBackgroundRepeatY:
948
949     // FIXME-NEWPARSER: Add the following unprefixed properties:
950     // case CSSPropertyBackfaceVisibility:
951     // case CSSPropertyFontKerning:
952     // case CSSPropertyHyphens:
953     // case CSSPropertyOverflowAnchor:
954     // case CSSPropertyScrollBehavior:
955     // case CSSPropertyScrollSnapType:
956     // case CSSPropertyTextAlignLast:
957     // case CSSPropertyTextCombineUpright:
958     // case CSSPropertyTextDecorationStyle:
959     // case CSSPropertyTextJustify:
960     // case CSSPropertyTextOrientation:
961     // case CSSPropertyUserSelect:
962 #if ENABLE(CSS_TRAILING_WORD)
963     case CSSPropertyAppleTrailingWord:
964 #endif
965 #if ENABLE(CSS_COMPOSITING)
966     case CSSPropertyIsolation:
967     case CSSPropertyMixBlendMode:
968 #endif
969 #if ENABLE(TOUCH_EVENTS)
970     case CSSPropertyTouchAction:
971 #endif
972 #if ENABLE(CSS_BOX_DECORATION_BREAK)
973     case CSSPropertyWebkitBoxDecorationBreak:
974 #endif
975 #if ENABLE(CURSOR_VISIBILITY)
976     case CSSPropertyWebkitCursorVisibility:
977 #endif
978 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
979     case CSSPropertyWebkitOverflowScrolling:
980 #endif
981 #if ENABLE(CSS_REGIONS)
982     case CSSPropertyWebkitRegionFragment:
983 #endif
984 #if ENABLE(CSS3_TEXT)
985     case CSSPropertyWebkitTextAlignLast:
986     case CSSPropertyWebkitTextJustify:
987 #endif
988 #if PLATFORM(IOS)
989     // Apple specific property. This will never be standardized and is purely to
990     // support custom WebKit-based Apple applications.
991     case CSSPropertyWebkitTouchCallout:
992 #endif
993 #if ENABLE(CSS_SCROLL_SNAP)
994     case CSSPropertyWebkitScrollSnapType:
995 #endif
996 #if ENABLE(APPLE_PAY)
997     case CSSPropertyApplePayButtonStyle:
998     case CSSPropertyApplePayButtonType:
999 #endif
1000         return true;
1001     case CSSPropertyJustifyContent:
1002     case CSSPropertyAlignContent:
1003     case CSSPropertyAlignItems:
1004     case CSSPropertyAlignSelf:
1005 #if ENABLE(CSS_GRID_LAYOUT)
1006         return !RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled();
1007 #else
1008         return true;
1009 #endif
1010     default:
1011         return false;
1012     }
1013 }
1014
1015 static bool isUniversalKeyword(const String& string)
1016 {
1017     // These keywords can be used for all properties.
1018     return equalLettersIgnoringASCIICase(string, "initial")
1019     || equalLettersIgnoringASCIICase(string, "inherit")
1020     || equalLettersIgnoringASCIICase(string, "unset")
1021     || equalLettersIgnoringASCIICase(string, "revert");
1022 }
1023
1024 static RefPtr<CSSValue> parseKeywordValue(CSSPropertyID propertyId, const String& string, CSSParserMode parserMode, StyleSheetContents* styleSheetContents)
1025 {
1026     ASSERT(!string.isEmpty());
1027
1028     if (!CSSParserFastPaths::isKeywordPropertyID(propertyId)) {
1029         // All properties accept the values of "initial" and "inherit".
1030         if (!isUniversalKeyword(string))
1031             return nullptr;
1032
1033         // Parse initial/inherit shorthands using the CSSPropertyParser.
1034         if (shorthandForProperty(propertyId).length())
1035             return nullptr;
1036
1037         // Descriptors do not support css wide keywords.
1038         if (CSSProperty::isDescriptorOnly(propertyId))
1039             return nullptr;
1040     }
1041
1042     CSSValueID valueID = cssValueKeywordID(string);
1043
1044     if (!valueID)
1045         return nullptr;
1046
1047     if (valueID == CSSValueInherit)
1048         return CSSValuePool::singleton().createInheritedValue();
1049     if (valueID == CSSValueInitial)
1050         return CSSValuePool::singleton().createExplicitInitialValue();
1051     if (valueID == CSSValueUnset)
1052         return CSSValuePool::singleton().createUnsetValue();
1053     if (valueID == CSSValueRevert)
1054         return CSSValuePool::singleton().createRevertValue();
1055     
1056     if (CSSParserFastPaths::isValidKeywordPropertyAndValue(propertyId, valueID, parserMode, styleSheetContents))
1057         return CSSPrimitiveValue::createIdentifier(valueID);
1058     return nullptr;
1059 }
1060
1061 template <typename CharType>
1062 static bool parseTransformTranslateArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSFunctionValue* transformValue)
1063 {
1064     while (expectedCount) {
1065         size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
1066         if (delimiter == notFound)
1067             return false;
1068         unsigned argumentLength = static_cast<unsigned>(delimiter);
1069         CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::UnitTypes::CSS_NUMBER;
1070         double number;
1071         if (!parseSimpleLength(pos, argumentLength, unit, number))
1072             return false;
1073         if (unit != CSSPrimitiveValue::UnitTypes::CSS_PX && (number || unit != CSSPrimitiveValue::UnitTypes::CSS_NUMBER))
1074             return false;
1075         transformValue->append(CSSPrimitiveValue::create(number, CSSPrimitiveValue::UnitTypes::CSS_PX));
1076         pos += argumentLength + 1;
1077         --expectedCount;
1078     }
1079     return true;
1080 }
1081
1082 template <typename CharType>
1083 static bool parseTransformNumberArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSFunctionValue* transformValue)
1084 {
1085     while (expectedCount) {
1086         size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
1087         if (delimiter == notFound)
1088             return false;
1089         unsigned argumentLength = static_cast<unsigned>(delimiter);
1090         bool ok;
1091         double number = charactersToDouble(pos, argumentLength, &ok);
1092         if (!ok)
1093             return false;
1094         transformValue->append(CSSPrimitiveValue::create(number, CSSPrimitiveValue::UnitTypes::CSS_NUMBER));
1095         pos += argumentLength + 1;
1096         --expectedCount;
1097     }
1098     return true;
1099 }
1100
1101 static const int kShortestValidTransformStringLength = 12;
1102
1103 template <typename CharType>
1104 static RefPtr<CSSFunctionValue> parseSimpleTransformValue(CharType*& pos, CharType* end)
1105 {
1106     if (end - pos < kShortestValidTransformStringLength)
1107         return nullptr;
1108
1109     const bool isTranslate = toASCIILower(pos[0]) == 't'
1110         && toASCIILower(pos[1]) == 'r'
1111         && toASCIILower(pos[2]) == 'a'
1112         && toASCIILower(pos[3]) == 'n'
1113         && toASCIILower(pos[4]) == 's'
1114         && toASCIILower(pos[5]) == 'l'
1115         && toASCIILower(pos[6]) == 'a'
1116         && toASCIILower(pos[7]) == 't'
1117         && toASCIILower(pos[8]) == 'e';
1118
1119     if (isTranslate) {
1120         CSSValueID transformType;
1121         unsigned expectedArgumentCount = 1;
1122         unsigned argumentStart = 11;
1123         CharType c9 = toASCIILower(pos[9]);
1124         if (c9 == 'x' && pos[10] == '(') {
1125             transformType = CSSValueTranslatex;
1126         } else if (c9 == 'y' && pos[10] == '(') {
1127             transformType = CSSValueTranslatey;
1128         } else if (c9 == 'z' && pos[10] == '(') {
1129             transformType = CSSValueTranslatez;
1130         } else if (c9 == '(') {
1131             transformType = CSSValueTranslate;
1132             expectedArgumentCount = 2;
1133             argumentStart = 10;
1134         } else if (c9 == '3' && toASCIILower(pos[10]) == 'd' && pos[11] == '(') {
1135             transformType = CSSValueTranslate3d;
1136             expectedArgumentCount = 3;
1137             argumentStart = 12;
1138         } else {
1139             return nullptr;
1140         }
1141         pos += argumentStart;
1142         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(transformType);
1143         if (!parseTransformTranslateArguments(pos, end, expectedArgumentCount, transformValue.get()))
1144             return nullptr;
1145         return transformValue;
1146     }
1147
1148     const bool isMatrix3d = toASCIILower(pos[0]) == 'm'
1149         && toASCIILower(pos[1]) == 'a'
1150         && toASCIILower(pos[2]) == 't'
1151         && toASCIILower(pos[3]) == 'r'
1152         && toASCIILower(pos[4]) == 'i'
1153         && toASCIILower(pos[5]) == 'x'
1154         && pos[6] == '3'
1155         && toASCIILower(pos[7]) == 'd'
1156         && pos[8] == '(';
1157
1158     if (isMatrix3d) {
1159         pos += 9;
1160         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(CSSValueMatrix3d);
1161         if (!parseTransformNumberArguments(pos, end, 16, transformValue.get()))
1162             return nullptr;
1163         return transformValue;
1164     }
1165
1166     const bool isScale3d = toASCIILower(pos[0]) == 's'
1167         && toASCIILower(pos[1]) == 'c'
1168         && toASCIILower(pos[2]) == 'a'
1169         && toASCIILower(pos[3]) == 'l'
1170         && toASCIILower(pos[4]) == 'e'
1171         && pos[5] == '3'
1172         && toASCIILower(pos[6]) == 'd'
1173         && pos[7] == '(';
1174
1175     if (isScale3d) {
1176         pos += 8;
1177         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(CSSValueScale3d);
1178         if (!parseTransformNumberArguments(pos, end, 3, transformValue.get()))
1179             return nullptr;
1180         return transformValue;
1181     }
1182
1183     return nullptr;
1184 }
1185
1186 template <typename CharType>
1187 static bool transformCanLikelyUseFastPath(const CharType* chars, unsigned length)
1188 {
1189     // Very fast scan that attempts to reject most transforms that couldn't
1190     // take the fast path. This avoids doing the malloc and string->double
1191     // conversions in parseSimpleTransformValue only to discard them when we
1192     // run into a transform component we don't understand.
1193     unsigned i = 0;
1194     while (i < length) {
1195         if (isCSSSpace(chars[i])) {
1196             ++i;
1197             continue;
1198         }
1199         if (length - i < kShortestValidTransformStringLength)
1200             return false;
1201         switch (toASCIILower(chars[i])) {
1202         case 't':
1203             // translate, translateX, translateY, translateZ, translate3d.
1204             if (toASCIILower(chars[i + 8]) != 'e')
1205                 return false;
1206             i += 9;
1207             break;
1208         case 'm':
1209             // matrix3d.
1210             if (toASCIILower(chars[i + 7]) != 'd')
1211                 return false;
1212             i += 8;
1213             break;
1214         case 's':
1215             // scale3d.
1216             if (toASCIILower(chars[i + 6]) != 'd')
1217                 return false;
1218             i += 7;
1219             break;
1220         default:
1221             // All other things, ex. rotate.
1222             return false;
1223         }
1224         size_t argumentsEnd = WTF::find(chars, length, ')', i);
1225         if (argumentsEnd == notFound)
1226             return false;
1227         // Advance to the end of the arguments.
1228         i = argumentsEnd + 1;
1229     }
1230     return i == length;
1231 }
1232
1233 template <typename CharType>
1234 static RefPtr<CSSValueList> parseSimpleTransformList(const CharType* chars, unsigned length)
1235 {
1236     if (!transformCanLikelyUseFastPath(chars, length))
1237         return nullptr;
1238     const CharType*& pos = chars;
1239     const CharType* end = chars + length;
1240     RefPtr<CSSValueList> transformList;
1241     while (pos < end) {
1242         while (pos < end && isCSSSpace(*pos))
1243             ++pos;
1244         if (pos >= end)
1245             break;
1246         RefPtr<CSSFunctionValue> transformValue = parseSimpleTransformValue(pos, end);
1247         if (!transformValue)
1248             return nullptr;
1249         if (!transformList)
1250             transformList = CSSValueList::createSpaceSeparated();
1251         transformList->append(*transformValue);
1252     }
1253     return transformList;
1254 }
1255
1256 static RefPtr<CSSValue> parseSimpleTransform(CSSPropertyID propertyID, const String& string)
1257 {
1258     ASSERT(!string.isEmpty());
1259
1260     if (propertyID != CSSPropertyTransform)
1261         return nullptr;
1262     if (string.is8Bit())
1263         return parseSimpleTransformList(string.characters8(), string.length());
1264     return parseSimpleTransformList(string.characters16(), string.length());
1265 }
1266
1267 RefPtr<CSSValue> CSSParserFastPaths::maybeParseValue(CSSPropertyID propertyID, const String& string, CSSParserMode parserMode, StyleSheetContents* styleSheetContents)
1268 {
1269     RefPtr<CSSValue> result = parseSimpleLengthValue(propertyID, string, parserMode);
1270     if (result)
1271         return result;
1272     if (isColorPropertyID(propertyID))
1273         return parseColor(string, parserMode);
1274     result = parseKeywordValue(propertyID, string, parserMode, styleSheetContents);
1275     if (result)
1276         return result;
1277     result = parseSimpleTransform(propertyID, string);
1278     if (result)
1279         return result;
1280     return nullptr;
1281 }
1282
1283 } // namespace WebCore