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