[CSS Parser] Unprefix -webkit-writing-mode
[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             || valueID == CSSValueIsolate || 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 <= CSSValueTextarea) || 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;
679 #endif
680     case CSSPropertyWebkitBoxAlign:
681         return valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline;
682     case CSSPropertyWebkitBoxDecorationBreak:
683         return valueID == CSSValueClone || valueID == CSSValueSlice;
684     case CSSPropertyWebkitBoxDirection:
685         return valueID == CSSValueNormal || valueID == CSSValueReverse;
686     case CSSPropertyWebkitBoxLines:
687         return valueID == CSSValueSingle || valueID == CSSValueMultiple;
688     case CSSPropertyWebkitBoxOrient:
689         return valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis;
690     case CSSPropertyWebkitBoxPack:
691         return valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify;
692     case CSSPropertyColumnFill:
693         return valueID == CSSValueAuto || valueID == CSSValueBalance;
694     case CSSPropertyAlignContent:
695         // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
696         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch;
697     case CSSPropertyAlignItems:
698         // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
699         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
700     case CSSPropertyAlignSelf:
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 == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
703     case CSSPropertyFlexDirection:
704         return valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse;
705     case CSSPropertyFlexWrap:
706         return valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse;
707     case CSSPropertyWebkitHyphens:
708         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueManual;
709     case CSSPropertyJustifyContent:
710         // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
711         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround;
712     case CSSPropertyWebkitFontKerning:
713         return valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone;
714     case CSSPropertyWebkitFontSmoothing:
715         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased;
716     case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
717         return valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace;
718     case CSSPropertyWebkitMarginAfterCollapse:
719     case CSSPropertyWebkitMarginBeforeCollapse:
720     case CSSPropertyWebkitMarginBottomCollapse:
721     case CSSPropertyWebkitMarginTopCollapse:
722         return valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard;
723     case CSSPropertyWebkitPrintColorAdjust:
724         return valueID == CSSValueExact || valueID == CSSValueEconomy;
725     case CSSPropertyWebkitRtlOrdering:
726         return valueID == CSSValueLogical || valueID == CSSValueVisual;
727     case CSSPropertyWebkitRubyPosition:
728         return valueID == CSSValueBefore || valueID == CSSValueAfter;
729     case CSSPropertyWebkitTextCombine:
730         return valueID == CSSValueNone || valueID == CSSValueHorizontal;
731     case CSSPropertyWebkitTextEmphasisPosition:
732         return valueID == CSSValueOver || valueID == CSSValueUnder;
733     case CSSPropertyWebkitTextSecurity: // disc | circle | square | none
734         return valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone;
735     case CSSPropertyTransformStyle:
736     case CSSPropertyWebkitTransformStyle:
737         return valueID == CSSValueFlat || valueID == CSSValuePreserve3d;
738     case CSSPropertyWebkitUserDrag: // auto | none | element
739         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement;
740     case CSSPropertyWebkitUserModify: // read-only | read-write
741         return valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly;
742     case CSSPropertyWebkitUserSelect: // auto | none | text | all
743         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll;
744     case CSSPropertyWritingMode:
745         // Note that horizontal-bt is not supported by the unprefixed version of
746         // the property, only by the -webkit- version.
747         return (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
748             || valueID == CSSValueLrTb || valueID == CSSValueRlTb || valueID == CSSValueTbRl
749             || valueID == CSSValueLr || valueID == CSSValueRl || valueID == CSSValueTb;
750     case CSSPropertyWhiteSpace: // normal | pre | nowrap
751         return valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap;
752     case CSSPropertyWordBreak: // normal | break-all | keep-all | break-word (this is a custom extension)
753         return valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueKeepAll || valueID == CSSValueBreakWord;
754     case CSSPropertyWebkitBorderFit:
755         return valueID == CSSValueBorder || valueID == CSSValueLines;
756 #if ENABLE(CSS_REGIONS)
757     case CSSPropertyWebkitRegionFragment:
758         return valueID == CSSValueAuto || valueID == CSSValueBreak;
759 #endif
760 #if ENABLE(CSS_SCROLL_SNAP)
761     case CSSPropertyWebkitScrollSnapType: // none | mandatory | proximity
762         return valueID == CSSValueNone || valueID == CSSValueMandatory || valueID == CSSValueProximity;
763 #endif
764 #if ENABLE(TOUCH_EVENTS)
765     case CSSPropertyTouchAction: // auto | manipulation
766         return valueID == CSSValueAuto || valueID == CSSValueManipulation;
767 #endif
768 #if ENABLE(CSS_TRAILING_WORD)
769     case CSSPropertyAppleTrailingWord: // auto | -apple-partially-balanced
770         return valueID == CSSValueAuto || valueID == CSSValueWebkitPartiallyBalanced;
771 #endif
772 #if ENABLE(APPLE_PAY)
773     case CSSPropertyApplePayButtonStyle: // white | white-outline | black
774         return valueID == CSSValueWhite || valueID == CSSValueWhiteOutline || valueID == CSSValueBlack;
775     case CSSPropertyApplePayButtonType: // plain | buy | set-up
776         return valueID == CSSValuePlain || valueID == CSSValueBuy || valueID == CSSValueSetUp;
777 #endif
778     default:
779         ASSERT_NOT_REACHED();
780         return false;
781     }
782 }
783
784 bool CSSParserFastPaths::isKeywordPropertyID(CSSPropertyID propertyId)
785 {
786     switch (propertyId) {
787     case CSSPropertyBorderBottomStyle:
788     case CSSPropertyBorderCollapse:
789     case CSSPropertyBorderLeftStyle:
790     case CSSPropertyBorderRightStyle:
791     case CSSPropertyBorderTopStyle:
792     case CSSPropertyBoxSizing:
793     case CSSPropertyBreakAfter:
794     case CSSPropertyBreakBefore:
795     case CSSPropertyBreakInside:
796     case CSSPropertyCaptionSide:
797     case CSSPropertyClear:
798     case CSSPropertyColumnFill:
799     case CSSPropertyColumnProgression:
800     case CSSPropertyColumnRuleStyle:
801     case CSSPropertyDirection:
802     case CSSPropertyDisplay:
803     case CSSPropertyEmptyCells:
804     case CSSPropertyFlexDirection:
805     case CSSPropertyFlexWrap:
806     case CSSPropertyFloat:
807     case CSSPropertyFontStretch:
808     case CSSPropertyFontStyle:
809     case CSSPropertyFontVariantAlternates:
810     case CSSPropertyFontVariantCaps:
811     case CSSPropertyFontVariantPosition:
812     case CSSPropertyImageRendering:
813     case CSSPropertyListStylePosition:
814     case CSSPropertyListStyleType:
815     case CSSPropertyObjectFit:
816     case CSSPropertyOutlineStyle:
817     case CSSPropertyOverflowWrap:
818     case CSSPropertyOverflowX:
819     case CSSPropertyOverflowY:
820     case CSSPropertyPageBreakAfter:
821     case CSSPropertyPageBreakBefore:
822     case CSSPropertyPageBreakInside:
823     case CSSPropertyPointerEvents:
824     case CSSPropertyPosition:
825     case CSSPropertyResize:
826     case CSSPropertySpeak:
827     case CSSPropertyTableLayout:
828     case CSSPropertyTextAlign:
829     case CSSPropertyTextLineThroughMode:
830     case CSSPropertyTextLineThroughStyle:
831     case CSSPropertyTextOverflow:
832     case CSSPropertyTextOverlineMode:
833     case CSSPropertyTextOverlineStyle:
834     case CSSPropertyTextRendering:
835     case CSSPropertyTextTransform:
836     case CSSPropertyTextUnderlineMode:
837     case CSSPropertyTextUnderlineStyle:
838     case CSSPropertyTransformStyle:
839     case CSSPropertyUnicodeBidi:
840     case CSSPropertyVisibility:
841     case CSSPropertyWebkitAppearance:
842     case CSSPropertyWebkitBackfaceVisibility:
843     case CSSPropertyWebkitBorderAfterStyle:
844     case CSSPropertyWebkitBorderBeforeStyle:
845     case CSSPropertyWebkitBorderEndStyle:
846     case CSSPropertyWebkitBorderFit:
847     case CSSPropertyWebkitBorderStartStyle:
848     case CSSPropertyWebkitBoxAlign:
849     case CSSPropertyWebkitBoxDirection:
850     case CSSPropertyWebkitBoxLines:
851     case CSSPropertyWebkitBoxOrient:
852     case CSSPropertyWebkitBoxPack:
853     case CSSPropertyWebkitColumnAxis:
854     case CSSPropertyWebkitFontKerning:
855     case CSSPropertyWebkitFontSmoothing:
856     case CSSPropertyWebkitHyphens:
857     case CSSPropertyWebkitLineAlign:
858     case CSSPropertyWebkitLineBreak:
859     case CSSPropertyWebkitLineSnap:
860     case CSSPropertyWebkitMarginAfterCollapse:
861     case CSSPropertyWebkitMarginBeforeCollapse:
862     case CSSPropertyWebkitMarginBottomCollapse:
863     case CSSPropertyWebkitMarginTopCollapse:
864     case CSSPropertyWebkitMarqueeDirection:
865     case CSSPropertyWebkitMarqueeStyle:
866     case CSSPropertyWebkitNbspMode:
867     case CSSPropertyWebkitPrintColorAdjust:
868     case CSSPropertyWebkitRtlOrdering:
869     case CSSPropertyWebkitRubyPosition:
870     case CSSPropertyWebkitTextCombine:
871     case CSSPropertyWebkitTextDecorationStyle:
872     case CSSPropertyWebkitTextOrientation:
873     case CSSPropertyWebkitTextSecurity:
874     case CSSPropertyWebkitTextZoom:
875     case CSSPropertyWebkitTransformStyle:
876     case CSSPropertyWebkitUserDrag:
877     case CSSPropertyWebkitUserModify:
878     case CSSPropertyWebkitUserSelect:
879     case CSSPropertyWhiteSpace:
880     case CSSPropertyWordBreak:
881     case CSSPropertyWordWrap:
882
883     // SVG CSS properties from SVG 1.1, Appendix N: Property Index.
884     case CSSPropertyAlignmentBaseline:
885     case CSSPropertyBufferedRendering:
886     case CSSPropertyClipRule:
887     case CSSPropertyColorInterpolation:
888     case CSSPropertyColorInterpolationFilters:
889     case CSSPropertyColorRendering:
890     case CSSPropertyDominantBaseline:
891     case CSSPropertyFillRule:
892     case CSSPropertyMaskType:
893     case CSSPropertyShapeRendering:
894     case CSSPropertyStrokeLinecap:
895     case CSSPropertyStrokeLinejoin:
896     case CSSPropertyTextAnchor:
897     case CSSPropertyVectorEffect:
898     case CSSPropertyWritingMode:
899
900     // FIXME-NEWPARSER: Treat all as a keyword property.
901     // case CSSPropertyAll:
902
903     // FIXME-NEWPARSER: Treat the following properties as keyword properties:
904     // case CSSPropertyBackgroundRepeatX:
905     // case CSSPropertyBackgroundRepeatY:
906     // case CSSPropertyWebkitTextEmphasisPosition:
907
908     // FIXME-NEWPARSER: Add the following unprefixed properties:
909     // case CSSPropertyBackfaceVisibility:
910     // case CSSPropertyFontKerning:
911     // case CSSPropertyHyphens:
912     // case CSSPropertyOverflowAnchor:
913     // case CSSPropertyScrollBehavior:
914     // case CSSPropertyScrollSnapType:
915     // case CSSPropertyTextAlignLast:
916     // case CSSPropertyTextCombineUpright:
917     // case CSSPropertyTextDecorationStyle:
918     // case CSSPropertyTextJustify:
919     // case CSSPropertyTextOrientation:
920     // case CSSPropertyUserSelect:
921 #if ENABLE(CSS_TRAILING_WORD)
922     case CSSPropertyAppleTrailingWord:
923 #endif
924 #if ENABLE(CSS_COMPOSITING)
925     case CSSPropertyIsolation:
926     case CSSPropertyMixBlendMode:
927 #endif
928 #if ENABLE(TOUCH_EVENTS)
929     case CSSPropertyTouchAction:
930 #endif
931 #if ENABLE(CSS_BOX_DECORATION_BREAK)
932     case CSSPropertyWebkitBoxDecorationBreak:
933 #endif
934 #if ENABLE(CURSOR_VISIBILITY)
935     case CSSPropertyWebkitCursorVisibility:
936 #endif
937 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
938     case CSSPropertyWebkitOverflowScrolling:
939 #endif
940 #if ENABLE(CSS_REGIONS)
941     case CSSPropertyWebkitRegionFragment:
942 #endif
943 #if ENABLE(CSS3_TEXT)
944     case CSSPropertyWebkitTextAlignLast:
945     case CSSPropertyWebkitTextJustify:
946 #endif
947 #if PLATFORM(IOS)
948     // Apple specific property. This will never be standardized and is purely to
949     // support custom WebKit-based Apple applications.
950     case CSSPropertyWebkitTouchCallout:
951 #endif
952 #if ENABLE(CSS_SCROLL_SNAP)
953     case CSSPropertyWebkitScrollSnapType:
954 #endif
955 #if ENABLE(APPLE_PAY)
956     case CSSPropertyApplePayButtonStyle:
957     case CSSPropertyApplePayButtonType:
958 #endif
959         return true;
960     case CSSPropertyJustifyContent:
961     case CSSPropertyAlignContent:
962     case CSSPropertyAlignItems:
963     case CSSPropertyAlignSelf:
964 #if ENABLE(CSS_GRID_LAYOUT)
965         return !RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled();
966 #else
967         return true;
968 #endif
969     default:
970         return false;
971     }
972 }
973
974 static bool isUniversalKeyword(const String& string)
975 {
976     // These keywords can be used for all properties.
977     return equalLettersIgnoringASCIICase(string, "initial")
978     || equalLettersIgnoringASCIICase(string, "inherit")
979     || equalLettersIgnoringASCIICase(string, "unset")
980     || equalLettersIgnoringASCIICase(string, "revert");
981 }
982
983 static RefPtr<CSSValue> parseKeywordValue(CSSPropertyID propertyId, const String& string, CSSParserMode parserMode)
984 {
985     ASSERT(!string.isEmpty());
986
987     if (!CSSParserFastPaths::isKeywordPropertyID(propertyId)) {
988         // All properties accept the values of "initial" and "inherit".
989         if (!isUniversalKeyword(string))
990             return nullptr;
991
992         // Parse initial/inherit shorthands using the CSSPropertyParser.
993         if (shorthandForProperty(propertyId).length())
994             return nullptr;
995
996         // Descriptors do not support css wide keywords.
997         if (CSSProperty::isDescriptorOnly(propertyId))
998             return nullptr;
999     }
1000
1001     CSSValueID valueID = cssValueKeywordID(string);
1002
1003     if (!valueID)
1004         return nullptr;
1005
1006     if (valueID == CSSValueInherit)
1007         return CSSValuePool::singleton().createInheritedValue();
1008     if (valueID == CSSValueInitial)
1009         return CSSValuePool::singleton().createExplicitInitialValue();
1010     if (valueID == CSSValueUnset)
1011         return CSSValuePool::singleton().createUnsetValue();
1012     if (valueID == CSSValueRevert)
1013         return CSSValuePool::singleton().createRevertValue();
1014     
1015     if (CSSParserFastPaths::isValidKeywordPropertyAndValue(propertyId, valueID, parserMode))
1016         return CSSPrimitiveValue::createIdentifier(valueID);
1017     return nullptr;
1018 }
1019
1020 template <typename CharType>
1021 static bool parseTransformTranslateArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSFunctionValue* transformValue)
1022 {
1023     while (expectedCount) {
1024         size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
1025         if (delimiter == notFound)
1026             return false;
1027         unsigned argumentLength = static_cast<unsigned>(delimiter);
1028         CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::UnitTypes::CSS_NUMBER;
1029         double number;
1030         if (!parseSimpleLength(pos, argumentLength, unit, number))
1031             return false;
1032         if (unit != CSSPrimitiveValue::UnitTypes::CSS_PX && (number || unit != CSSPrimitiveValue::UnitTypes::CSS_NUMBER))
1033             return false;
1034         transformValue->append(CSSPrimitiveValue::create(number, CSSPrimitiveValue::UnitTypes::CSS_PX));
1035         pos += argumentLength + 1;
1036         --expectedCount;
1037     }
1038     return true;
1039 }
1040
1041 template <typename CharType>
1042 static bool parseTransformNumberArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSFunctionValue* transformValue)
1043 {
1044     while (expectedCount) {
1045         size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
1046         if (delimiter == notFound)
1047             return false;
1048         unsigned argumentLength = static_cast<unsigned>(delimiter);
1049         bool ok;
1050         double number = charactersToDouble(pos, argumentLength, &ok);
1051         if (!ok)
1052             return false;
1053         transformValue->append(CSSPrimitiveValue::create(number, CSSPrimitiveValue::UnitTypes::CSS_NUMBER));
1054         pos += argumentLength + 1;
1055         --expectedCount;
1056     }
1057     return true;
1058 }
1059
1060 static const int kShortestValidTransformStringLength = 12;
1061
1062 template <typename CharType>
1063 static RefPtr<CSSFunctionValue> parseSimpleTransformValue(CharType*& pos, CharType* end)
1064 {
1065     if (end - pos < kShortestValidTransformStringLength)
1066         return nullptr;
1067
1068     const bool isTranslate = toASCIILower(pos[0]) == 't'
1069         && toASCIILower(pos[1]) == 'r'
1070         && toASCIILower(pos[2]) == 'a'
1071         && toASCIILower(pos[3]) == 'n'
1072         && toASCIILower(pos[4]) == 's'
1073         && toASCIILower(pos[5]) == 'l'
1074         && toASCIILower(pos[6]) == 'a'
1075         && toASCIILower(pos[7]) == 't'
1076         && toASCIILower(pos[8]) == 'e';
1077
1078     if (isTranslate) {
1079         CSSValueID transformType;
1080         unsigned expectedArgumentCount = 1;
1081         unsigned argumentStart = 11;
1082         CharType c9 = toASCIILower(pos[9]);
1083         if (c9 == 'x' && pos[10] == '(') {
1084             transformType = CSSValueTranslatex;
1085         } else if (c9 == 'y' && pos[10] == '(') {
1086             transformType = CSSValueTranslatey;
1087         } else if (c9 == 'z' && pos[10] == '(') {
1088             transformType = CSSValueTranslatez;
1089         } else if (c9 == '(') {
1090             transformType = CSSValueTranslate;
1091             expectedArgumentCount = 2;
1092             argumentStart = 10;
1093         } else if (c9 == '3' && toASCIILower(pos[10]) == 'd' && pos[11] == '(') {
1094             transformType = CSSValueTranslate3d;
1095             expectedArgumentCount = 3;
1096             argumentStart = 12;
1097         } else {
1098             return nullptr;
1099         }
1100         pos += argumentStart;
1101         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(transformType);
1102         if (!parseTransformTranslateArguments(pos, end, expectedArgumentCount, transformValue.get()))
1103             return nullptr;
1104         return transformValue;
1105     }
1106
1107     const bool isMatrix3d = toASCIILower(pos[0]) == 'm'
1108         && toASCIILower(pos[1]) == 'a'
1109         && toASCIILower(pos[2]) == 't'
1110         && toASCIILower(pos[3]) == 'r'
1111         && toASCIILower(pos[4]) == 'i'
1112         && toASCIILower(pos[5]) == 'x'
1113         && pos[6] == '3'
1114         && toASCIILower(pos[7]) == 'd'
1115         && pos[8] == '(';
1116
1117     if (isMatrix3d) {
1118         pos += 9;
1119         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(CSSValueMatrix3d);
1120         if (!parseTransformNumberArguments(pos, end, 16, transformValue.get()))
1121             return nullptr;
1122         return transformValue;
1123     }
1124
1125     const bool isScale3d = toASCIILower(pos[0]) == 's'
1126         && toASCIILower(pos[1]) == 'c'
1127         && toASCIILower(pos[2]) == 'a'
1128         && toASCIILower(pos[3]) == 'l'
1129         && toASCIILower(pos[4]) == 'e'
1130         && pos[5] == '3'
1131         && toASCIILower(pos[6]) == 'd'
1132         && pos[7] == '(';
1133
1134     if (isScale3d) {
1135         pos += 8;
1136         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(CSSValueScale3d);
1137         if (!parseTransformNumberArguments(pos, end, 3, transformValue.get()))
1138             return nullptr;
1139         return transformValue;
1140     }
1141
1142     return nullptr;
1143 }
1144
1145 template <typename CharType>
1146 static bool transformCanLikelyUseFastPath(const CharType* chars, unsigned length)
1147 {
1148     // Very fast scan that attempts to reject most transforms that couldn't
1149     // take the fast path. This avoids doing the malloc and string->double
1150     // conversions in parseSimpleTransformValue only to discard them when we
1151     // run into a transform component we don't understand.
1152     unsigned i = 0;
1153     while (i < length) {
1154         if (isCSSSpace(chars[i])) {
1155             ++i;
1156             continue;
1157         }
1158         if (length - i < kShortestValidTransformStringLength)
1159             return false;
1160         switch (toASCIILower(chars[i])) {
1161         case 't':
1162             // translate, translateX, translateY, translateZ, translate3d.
1163             if (toASCIILower(chars[i + 8]) != 'e')
1164                 return false;
1165             i += 9;
1166             break;
1167         case 'm':
1168             // matrix3d.
1169             if (toASCIILower(chars[i + 7]) != 'd')
1170                 return false;
1171             i += 8;
1172             break;
1173         case 's':
1174             // scale3d.
1175             if (toASCIILower(chars[i + 6]) != 'd')
1176                 return false;
1177             i += 7;
1178             break;
1179         default:
1180             // All other things, ex. rotate.
1181             return false;
1182         }
1183         size_t argumentsEnd = WTF::find(chars, length, ')', i);
1184         if (argumentsEnd == notFound)
1185             return false;
1186         // Advance to the end of the arguments.
1187         i = argumentsEnd + 1;
1188     }
1189     return i == length;
1190 }
1191
1192 template <typename CharType>
1193 static RefPtr<CSSValueList> parseSimpleTransformList(const CharType* chars, unsigned length)
1194 {
1195     if (!transformCanLikelyUseFastPath(chars, length))
1196         return nullptr;
1197     const CharType*& pos = chars;
1198     const CharType* end = chars + length;
1199     RefPtr<CSSValueList> transformList;
1200     while (pos < end) {
1201         while (pos < end && isCSSSpace(*pos))
1202             ++pos;
1203         if (pos >= end)
1204             break;
1205         RefPtr<CSSFunctionValue> transformValue = parseSimpleTransformValue(pos, end);
1206         if (!transformValue)
1207             return nullptr;
1208         if (!transformList)
1209             transformList = CSSValueList::createSpaceSeparated();
1210         transformList->append(*transformValue);
1211     }
1212     return transformList;
1213 }
1214
1215 static RefPtr<CSSValue> parseSimpleTransform(CSSPropertyID propertyID, const String& string)
1216 {
1217     ASSERT(!string.isEmpty());
1218
1219     if (propertyID != CSSPropertyTransform)
1220         return nullptr;
1221     if (string.is8Bit())
1222         return parseSimpleTransformList(string.characters8(), string.length());
1223     return parseSimpleTransformList(string.characters16(), string.length());
1224 }
1225
1226 RefPtr<CSSValue> CSSParserFastPaths::maybeParseValue(CSSPropertyID propertyID, const String& string, CSSParserMode parserMode)
1227 {
1228     RefPtr<CSSValue> result = parseSimpleLengthValue(propertyID, string, parserMode);
1229     if (result)
1230         return result;
1231     if (isColorPropertyID(propertyID))
1232         return parseColor(string, parserMode);
1233     result = parseKeywordValue(propertyID, string, parserMode);
1234     if (result)
1235         return result;
1236     result = parseSimpleTransform(propertyID, string);
1237     if (result)
1238         return result;
1239     return nullptr;
1240 }
1241
1242 } // namespace WebCore