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