Expand font-weight and font-stretch to take any number
[WebKit.git] / Source / WebCore / css / parser / CSSParserFastPaths.cpp
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Copyright (C) 2016 Apple Inc. All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //    * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //    * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //    * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "config.h"
31 #include "CSSParserFastPaths.h"
32
33 #include "CSSFunctionValue.h"
34 #include "CSSInheritedValue.h"
35 #include "CSSInitialValue.h"
36 #include "CSSParserIdioms.h"
37 #include "CSSPrimitiveValue.h"
38 #include "CSSPropertyParser.h"
39 #include "CSSValueList.h"
40 #include "CSSValuePool.h"
41 #include "HTMLParserIdioms.h"
42 #include "RuntimeEnabledFeatures.h"
43 #include "StyleColor.h"
44 #include "StylePropertyShorthand.h"
45 #include "StyleSheetContents.h"
46
47 namespace WebCore {
48
49 static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
50 {
51     switch (propertyId) {
52     case CSSPropertyFontSize:
53     case CSSPropertyGridColumnGap:
54     case CSSPropertyGridRowGap:
55     case CSSPropertyHeight:
56     case CSSPropertyWidth:
57     case CSSPropertyMinHeight:
58     case CSSPropertyMinWidth:
59     case CSSPropertyPaddingBottom:
60     case CSSPropertyPaddingLeft:
61     case CSSPropertyPaddingRight:
62     case CSSPropertyPaddingTop:
63     case CSSPropertyWebkitLogicalWidth:
64     case CSSPropertyWebkitLogicalHeight:
65     case CSSPropertyWebkitMinLogicalWidth:
66     case CSSPropertyWebkitMinLogicalHeight:
67     case CSSPropertyWebkitPaddingAfter:
68     case CSSPropertyWebkitPaddingBefore:
69     case CSSPropertyWebkitPaddingEnd:
70     case CSSPropertyWebkitPaddingStart:
71     case CSSPropertyShapeMargin:
72         acceptsNegativeNumbers = false;
73         return true;
74     case CSSPropertyBottom:
75     case CSSPropertyCx:
76     case CSSPropertyCy:
77     case CSSPropertyLeft:
78     case CSSPropertyMarginBottom:
79     case CSSPropertyMarginLeft:
80     case CSSPropertyMarginRight:
81     case CSSPropertyMarginTop:
82     case CSSPropertyRight:
83     case CSSPropertyTop:
84     case CSSPropertyWebkitMarginAfter:
85     case CSSPropertyWebkitMarginBefore:
86     case CSSPropertyWebkitMarginEnd:
87     case CSSPropertyWebkitMarginStart:
88     case CSSPropertyX:
89     case CSSPropertyY:
90     case CSSPropertyR:
91     case CSSPropertyRx:
92     case CSSPropertyRy:
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::UnitType& unit, double& number)
102 {
103     if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
104         length -= 2;
105         unit = CSSPrimitiveValue::UnitType::CSS_PX;
106     } else if (length > 1 && characters[length - 1] == '%') {
107         length -= 1;
108         unit = CSSPrimitiveValue::UnitType::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     return true;
119 }
120
121 static RefPtr<CSSValue> parseSimpleLengthValue(CSSPropertyID propertyId, const String& string, CSSParserMode cssParserMode)
122 {
123     ASSERT(!string.isEmpty());
124     bool acceptsNegativeNumbers = false;
125
126     // In @viewport, width and height are shorthands, not simple length values.
127     if (isCSSViewportParsingEnabledForMode(cssParserMode) || !isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
128         return nullptr;
129
130     unsigned length = string.length();
131     double number;
132     CSSPrimitiveValue::UnitType unit = CSSPrimitiveValue::UnitType::CSS_NUMBER;
133
134     if (string.is8Bit()) {
135         if (!parseSimpleLength(string.characters8(), length, unit, number))
136             return nullptr;
137     } else {
138         if (!parseSimpleLength(string.characters16(), length, unit, number))
139             return nullptr;
140     }
141
142     if (unit == CSSPrimitiveValue::UnitType::CSS_NUMBER) {
143         if (number && cssParserMode != SVGAttributeMode)
144             return nullptr;
145         unit = CSSPrimitiveValue::UnitType::CSS_PX;
146     }
147
148     if (number < 0 && !acceptsNegativeNumbers)
149         return nullptr;
150     if (std::isinf(number))
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::UnitType& 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::UnitType::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::UnitType::CSS_PERCENTAGE && *current != '%')
301         return false;
302
303     if (*current == '%') {
304         expect = CSSPrimitiveValue::UnitType::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::UnitType::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::UnitType expect = CSSPrimitiveValue::UnitType::CSS_UNKNOWN;
417
418     if (length >= 4 && characters[0] == '#') {
419         RGBA32 rgb;
420         if (Color::parseHexColor(characters + 1, length - 1, rgb))
421             return Color(rgb);
422     }
423
424     if (quirksMode && (length == 3 || length == 6)) {
425         RGBA32 rgb;
426         if (Color::parseHexColor(characters, length, rgb))
427             return Color(rgb);
428     }
429
430     // Try rgba() syntax.
431     if (mightBeRGBA(characters, length)) {
432         const CharacterType* current = characters + 5;
433         const CharacterType* end = characters + length;
434         int red;
435         int green;
436         int blue;
437         int alpha;
438
439         if (!parseColorIntOrPercentage(current, end, ',', expect, red))
440             return Color();
441         if (!parseColorIntOrPercentage(current, end, ',', expect, green))
442             return Color();
443         if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
444             return Color();
445         if (!parseAlphaValue(current, end, ')', alpha))
446             return Color();
447         if (current != end)
448             return Color();
449         return Color(makeRGBA(red, green, blue, alpha));
450     }
451
452     // Try rgb() syntax.
453     if (mightBeRGB(characters, length)) {
454         const CharacterType* current = characters + 4;
455         const CharacterType* end = characters + length;
456         int red;
457         int green;
458         int blue;
459         if (!parseColorIntOrPercentage(current, end, ',', expect, red))
460             return Color();
461         if (!parseColorIntOrPercentage(current, end, ',', expect, green))
462             return Color();
463         if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
464             return Color();
465         if (current != end)
466             return Color();
467         return Color(makeRGB(red, green, blue));
468     }
469
470     return Color();
471 }
472
473 RefPtr<CSSValue> CSSParserFastPaths::parseColor(const String& string, CSSParserMode parserMode)
474 {
475     ASSERT(!string.isEmpty());
476     CSSValueID valueID = cssValueKeywordID(string);
477     if (StyleColor::isColorKeyword(valueID)) {
478         if (!isValueAllowedInMode(valueID, parserMode))
479             return nullptr;
480         return CSSValuePool::singleton().createIdentifierValue(valueID);
481     }
482
483     bool quirksMode = isQuirksModeBehavior(parserMode);
484
485     // Fast path for hex colors and rgb()/rgba() colors
486     Color color;
487     if (string.is8Bit())
488         color = fastParseColorInternal(string.characters8(), string.length(), quirksMode);
489     else
490         color = fastParseColorInternal(string.characters16(), string.length(), quirksMode);
491     if (!color.isValid())
492         return nullptr;
493     return CSSValuePool::singleton().createColorValue(color);
494 }
495
496 bool CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyID propertyId, CSSValueID valueID, CSSParserMode parserMode)
497 {
498     if (valueID == CSSValueInvalid || !isValueAllowedInMode(valueID, parserMode))
499         return false;
500
501     switch (propertyId) {
502     case CSSPropertyAlignmentBaseline:
503         // auto | baseline | before-edge | text-before-edge | middle |
504         // central | after-edge | text-after-edge | ideographic | alphabetic |
505         // hanging | mathematical
506         return valueID == CSSValueAuto || valueID == CSSValueAlphabetic || valueID == CSSValueBaseline
507             || valueID == CSSValueMiddle || (valueID >= CSSValueBeforeEdge && valueID <= CSSValueMathematical);
508     case CSSPropertyAll:
509         return false; // Only accepts css-wide keywords
510     case CSSPropertyBackgroundRepeatX: // repeat | no-repeat
511     case CSSPropertyBackgroundRepeatY: // repeat | no-repeat
512         return valueID == CSSValueRepeat || valueID == CSSValueNoRepeat;
513     case CSSPropertyBorderCollapse: // collapse | separate
514         return valueID == CSSValueCollapse || valueID == CSSValueSeparate;
515     case CSSPropertyBorderTopStyle: // <border-style>
516     case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
517     case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
518     case CSSPropertyBorderLeftStyle:
519     case CSSPropertyWebkitBorderAfterStyle:
520     case CSSPropertyWebkitBorderBeforeStyle:
521     case CSSPropertyWebkitBorderEndStyle:
522     case CSSPropertyWebkitBorderStartStyle:
523     case CSSPropertyColumnRuleStyle:
524         return valueID >= CSSValueNone && valueID <= CSSValueDouble;
525     case CSSPropertyBoxSizing:
526         return valueID == CSSValueBorderBox || valueID == CSSValueContentBox;
527     case CSSPropertyBufferedRendering:
528         return valueID == CSSValueAuto || valueID == CSSValueDynamic || valueID == CSSValueStatic;
529     case CSSPropertyCaptionSide: // top | bottom | left | right
530         return valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom;
531     case CSSPropertyClear: // none | left | right | both
532         return valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth;
533     case CSSPropertyClipRule:
534     case CSSPropertyFillRule:
535         return valueID == CSSValueNonzero || valueID == CSSValueEvenodd;
536     case CSSPropertyColorInterpolation:
537     case CSSPropertyColorInterpolationFilters:
538         return valueID == CSSValueAuto || valueID == CSSValueSRGB || valueID == CSSValueLinearRGB;
539     case CSSPropertyColorRendering:
540         return valueID == CSSValueAuto || valueID == CSSValueOptimizeSpeed || valueID == CSSValueOptimizeQuality;
541     case CSSPropertyDirection: // ltr | rtl
542         return valueID == CSSValueLtr || valueID == CSSValueRtl;
543     case CSSPropertyDisplay:
544         // inline | block | list-item | inline-block | table |
545         // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
546         // table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none
547         // flex | inline-flex | -webkit-flex | -webkit-inline-flex | grid | inline-grid
548         return (valueID >= CSSValueInline && valueID <= CSSValueContents) || valueID == CSSValueNone
549             || (RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled() && (valueID == CSSValueGrid || valueID == CSSValueInlineGrid))
550         ;
551     case CSSPropertyDominantBaseline:
552         // auto | use-script | no-change | reset-size | ideographic |
553         // alphabetic | hanging | mathematical | central | middle |
554         // text-after-edge | text-before-edge
555         return valueID == CSSValueAuto || valueID == CSSValueAlphabetic || valueID == CSSValueMiddle
556             || (valueID >= CSSValueUseScript && valueID <= CSSValueResetSize)
557             || (valueID >= CSSValueCentral && valueID <= CSSValueMathematical);
558     case CSSPropertyEmptyCells: // show | hide
559         return valueID == CSSValueShow || valueID == CSSValueHide;
560     case CSSPropertyFloat: // left | right | none
561         return valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone;
562     case CSSPropertyImageRendering: // auto | optimizeContrast | pixelated | optimizeSpeed | crispEdges | optimizeQuality | webkit-crispEdges
563         return valueID == CSSValueAuto || valueID == CSSValueOptimizeSpeed || valueID == CSSValueOptimizeQuality || valueID == CSSValueWebkitCrispEdges || valueID == CSSValueWebkitOptimizeContrast || valueID == CSSValueCrispEdges || valueID == CSSValuePixelated;
564 #if ENABLE(CSS_COMPOSITING)
565     case CSSPropertyIsolation: // auto | isolate
566         return valueID == CSSValueAuto || valueID == CSSValueIsolate;
567 #endif
568     case CSSPropertyListStylePosition: // inside | outside
569         return valueID == CSSValueInside || valueID == CSSValueOutside;
570     case CSSPropertyListStyleType:
571         // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
572         // for the list of supported list-style-types.
573         return (valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone;
574     case CSSPropertyMaskType:
575         return valueID == CSSValueLuminance || valueID == CSSValueAlpha;
576     case CSSPropertyObjectFit:
577         return valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown;
578     case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto
579         return valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble);
580     // FIXME-NEWPARSER: Support?
581     // case CSSPropertyOverflowAnchor:
582     //    return valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAuto;
583     case CSSPropertyOverflowWrap: // normal | break-word
584     case CSSPropertyWordWrap:
585         return valueID == CSSValueNormal || valueID == CSSValueBreakWord;
586     case CSSPropertyOverflowX: // visible | hidden | scroll | auto | overlay
587         return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay;
588     case CSSPropertyOverflowY: // visible | hidden | scroll | auto | overlay | -webkit-paged-x | -webkit-paged-y
589         return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY;
590     case CSSPropertyBreakAfter:
591     case CSSPropertyBreakBefore:
592         return valueID == CSSValueAuto || valueID == CSSValueAvoid || valueID == CSSValueAvoidPage || valueID == CSSValuePage || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueRecto || valueID == CSSValueVerso || valueID == CSSValueAvoidColumn || valueID == CSSValueColumn
593 #if ENABLE(CSS_REGIONS)
594             || valueID == CSSValueRegion || valueID == CSSValueAvoidRegion
595 #endif
596         ;
597     case CSSPropertyBreakInside:
598         return valueID == CSSValueAuto || valueID == CSSValueAvoid || valueID == CSSValueAvoidPage || valueID == CSSValueAvoidColumn
599 #if ENABLE(CSS_REGIONS)
600             || valueID == CSSValueAvoidRegion
601 #endif
602         ;
603     case CSSPropertyPointerEvents:
604         // none | visiblePainted | visibleFill | visibleStroke | visible |
605         // painted | fill | stroke | auto | all | bounding-box
606         return valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblePainted && valueID <= CSSValueStroke);
607     case CSSPropertyPosition: // static | relative | absolute | fixed | sticky
608         return valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed || valueID == CSSValueWebkitSticky;
609     case CSSPropertyResize: // none | both | horizontal | vertical | auto
610         return valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto;
611     // FIXME-NEWPARSER: Investigate this property.
612     // case CSSPropertyScrollBehavior: // auto | smooth
613     //     ASSERT(RuntimeEnabledFeatures::cssomSmoothScrollEnabled());
614     //   return valueID == CSSValueAuto || valueID == CSSValueSmooth;
615     case CSSPropertyShapeRendering:
616         return valueID == CSSValueAuto || valueID == CSSValueOptimizeSpeed || valueID == CSSValueCrispedges || valueID == CSSValueGeometricPrecision;
617     case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation
618         return valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation;
619     case CSSPropertyStrokeLinejoin:
620         return valueID == CSSValueMiter || valueID == CSSValueRound || valueID == CSSValueBevel;
621     case CSSPropertyStrokeLinecap:
622         return valueID == CSSValueButt || valueID == CSSValueRound || valueID == CSSValueSquare;
623     case CSSPropertyTableLayout: // auto | fixed
624         return valueID == CSSValueAuto || valueID == CSSValueFixed;
625     case CSSPropertyTextAlign:
626         return (valueID >= CSSValueWebkitAuto && valueID <= CSSValueWebkitMatchParent) || valueID == CSSValueStart || valueID == CSSValueEnd;
627 #if ENABLE(CSS3_TEXT)
628     case CSSPropertyWebkitTextAlignLast:
629         // auto | start | end | left | right | center | justify
630         return (valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto;
631 #endif
632     case CSSPropertyTextAnchor:
633         return valueID == CSSValueStart || valueID == CSSValueMiddle || valueID == CSSValueEnd;
634 // FIXME-NEWPARSER: Support
635 //    case CSSPropertyTextCombineUpright:
636 //        return valueID == CSSValueNone || valueID == CSSValueAll;
637     case CSSPropertyWebkitTextDecorationStyle:
638         // solid | double | dotted | dashed | wavy
639         return valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDotted || valueID == CSSValueDashed || valueID == CSSValueWavy;
640 #if ENABLE(CSS3_TEXT)
641     case CSSPropertyWebkitTextJustify:
642         // auto | none | inter-word | distribute
643         return valueID == CSSValueInterWord || valueID == CSSValueDistribute || valueID == CSSValueAuto || valueID == CSSValueNone;
644 #endif
645     case CSSPropertyWebkitTextOrientation: // mixed | upright | sideways | sideways-right
646         return valueID == CSSValueMixed || valueID == CSSValueUpright || valueID == CSSValueSideways || valueID == CSSValueSidewaysRight;
647     case CSSPropertyTextOverflow: // clip | ellipsis
648         return valueID == CSSValueClip || valueID == CSSValueEllipsis;
649     case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
650         return valueID == CSSValueAuto || valueID == CSSValueOptimizeSpeed || valueID == CSSValueOptimizeLegibility || valueID == CSSValueGeometricPrecision;
651     case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none
652         return (valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone;
653     case CSSPropertyUnicodeBidi:
654         return valueID == CSSValueNormal || valueID == CSSValueEmbed
655             || valueID == CSSValueBidiOverride || valueID == CSSValueWebkitIsolate
656             || valueID == CSSValueWebkitIsolateOverride || valueID == CSSValueWebkitPlaintext;
657     case CSSPropertyVectorEffect:
658         return valueID == CSSValueNone || valueID == CSSValueNonScalingStroke;
659     case CSSPropertyVisibility: // visible | hidden | collapse
660         return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse;
661     case CSSPropertyWebkitAppearance:
662         return (valueID >= CSSValueCheckbox && valueID <= CSSValueCapsLockIndicator) || valueID == CSSValueNone;
663     case CSSPropertyWebkitBackfaceVisibility:
664         return valueID == CSSValueVisible || valueID == CSSValueHidden;
665 #if ENABLE(CSS_COMPOSITING)
666     case CSSPropertyMixBlendMode:
667         return valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen || valueID == CSSValueOverlay
668             || valueID == CSSValueDarken || valueID == CSSValueLighten || valueID == CSSValueColorDodge || valueID == CSSValueColorBurn
669             || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference || valueID == CSSValueExclusion
670             || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor || valueID == CSSValueLuminosity || valueID == CSSValuePlusDarker || valueID == CSSValuePlusLighter;
671 #endif
672     case CSSPropertyWebkitBoxAlign:
673         return valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline;
674 #if ENABLE(CSS_BOX_DECORATION_BREAK)
675     case CSSPropertyWebkitBoxDecorationBreak:
676         return valueID == CSSValueClone || valueID == CSSValueSlice;
677     case CSSPropertyWebkitBoxDirection:
678         return valueID == CSSValueNormal || valueID == CSSValueReverse;
679 #endif
680     case CSSPropertyWebkitBoxLines:
681         return valueID == CSSValueSingle || valueID == CSSValueMultiple;
682     case CSSPropertyWebkitBoxOrient:
683         return valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis;
684     case CSSPropertyWebkitBoxPack:
685         return valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify;
686 #if ENABLE(CURSOR_VISIBILITY)
687     case CSSPropertyWebkitCursorVisibility:
688         return valueID == CSSValueAuto || valueID == CSSValueAutoHide;
689 #endif
690     case CSSPropertyColumnFill:
691         return valueID == CSSValueAuto || valueID == CSSValueBalance;
692     case CSSPropertyWebkitColumnAxis:
693         return valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto;
694     case CSSPropertyWebkitColumnProgression:
695         return valueID == CSSValueNormal || valueID == CSSValueReverse;
696     case CSSPropertyAlignContent:
697         // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
698         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch;
699     case CSSPropertyAlignItems:
700         // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
701         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
702     case CSSPropertyAlignSelf:
703         // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
704         return valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
705     case CSSPropertyFlexDirection:
706         return valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse;
707     case CSSPropertyFlexWrap:
708         return valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse;
709     case CSSPropertyWebkitHyphens:
710         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueManual;
711     case CSSPropertyJustifyContent:
712         // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
713         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround;
714     case CSSPropertyWebkitFontKerning:
715         return valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone;
716     case CSSPropertyWebkitFontSmoothing:
717         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased;
718     case CSSPropertyWebkitLineAlign:
719         return valueID == CSSValueNone || valueID == CSSValueEdges;
720     case CSSPropertyLineBreak: // auto | loose | normal | strict | after-white-space
721         return valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace;
722     case CSSPropertyWebkitLineSnap:
723         return valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain;
724     case CSSPropertyWebkitMarginAfterCollapse:
725     case CSSPropertyWebkitMarginBeforeCollapse:
726     case CSSPropertyWebkitMarginBottomCollapse:
727     case CSSPropertyWebkitMarginTopCollapse:
728         return valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard;
729     case CSSPropertyWebkitPrintColorAdjust:
730         return valueID == CSSValueExact || valueID == CSSValueEconomy;
731     case CSSPropertyWebkitRtlOrdering:
732         return valueID == CSSValueLogical || valueID == CSSValueVisual;
733     case CSSPropertyWebkitRubyPosition:
734         return valueID == CSSValueBefore || valueID == CSSValueAfter || valueID == CSSValueInterCharacter;
735     case CSSPropertyWebkitTextCombine:
736         return valueID == CSSValueNone || valueID == CSSValueHorizontal;
737     case CSSPropertyWebkitTextSecurity: // disc | circle | square | none
738         return valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone;
739     case CSSPropertyTransformStyle:
740     case CSSPropertyWebkitTransformStyle:
741         return valueID == CSSValueFlat || valueID == CSSValuePreserve3d;
742     case CSSPropertyWebkitUserDrag: // auto | none | element
743         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement;
744     case CSSPropertyWebkitUserModify: // read-only | read-write
745         return valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly;
746     case CSSPropertyWebkitUserSelect: // auto | none | text | all
747         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll;
748     case CSSPropertyWritingMode:
749         // Note that horizontal-bt is not supported by the unprefixed version of
750         // the property, only by the -webkit- version.
751         return (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
752             || valueID == CSSValueLrTb || valueID == CSSValueRlTb || valueID == CSSValueTbRl
753             || valueID == CSSValueLr || valueID == CSSValueRl || valueID == CSSValueTb;
754     case CSSPropertyWhiteSpace: // normal | pre | nowrap
755         return valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap;
756     case CSSPropertyWordBreak: // normal | break-all | keep-all | break-word (this is a custom extension)
757         return valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueKeepAll || valueID == CSSValueBreakWord;
758     case CSSPropertyWebkitBorderFit:
759         return valueID == CSSValueBorder || valueID == CSSValueLines;
760 #if ENABLE(CSS_REGIONS)
761     case CSSPropertyWebkitRegionFragment:
762         return valueID == CSSValueAuto || valueID == CSSValueBreak;
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 | donate
776         return valueID == CSSValuePlain || valueID == CSSValueBuy || valueID == CSSValueSetUp || valueID == CSSValueDonate;
777 #endif
778     case CSSPropertyWebkitNbspMode: // normal | space
779         return valueID == CSSValueNormal || valueID == CSSValueSpace;
780     case CSSPropertyWebkitTextZoom:
781         return valueID == CSSValueNormal || valueID == CSSValueReset;
782 #if PLATFORM(IOS)
783     // Apple specific property. These will never be standardized and is purely to
784     // support custom WebKit-based Apple applications.
785     case CSSPropertyWebkitTouchCallout:
786         return valueID == CSSValueDefault || valueID == CSSValueNone;
787 #endif
788     case CSSPropertyWebkitMarqueeDirection:
789         return valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
790             || valueID == CSSValueUp || valueID == CSSValueAuto;
791     case CSSPropertyWebkitMarqueeStyle:
792         return valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate;
793     case CSSPropertyFontVariantPosition: // normal | sub | super
794         return valueID == CSSValueNormal || valueID == CSSValueSub || valueID == CSSValueSuper;
795     case CSSPropertyFontVariantCaps: // normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps
796         return valueID == CSSValueNormal || valueID == CSSValueSmallCaps || valueID == CSSValueAllSmallCaps || valueID == CSSValuePetiteCaps || valueID == CSSValueAllPetiteCaps || valueID == CSSValueUnicase || valueID == CSSValueTitlingCaps;
797     case CSSPropertyFontVariantAlternates: // We only support the normal and historical-forms values.
798         return valueID == CSSValueNormal || valueID == CSSValueHistoricalForms;
799 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
800     case CSSPropertyWebkitOverflowScrolling:
801         return valueID == CSSValueAuto || valueID == CSSValueTouch;
802 #endif
803     default:
804         ASSERT_NOT_REACHED();
805         return false;
806     }
807 }
808
809 bool CSSParserFastPaths::isKeywordPropertyID(CSSPropertyID propertyId)
810 {
811     switch (propertyId) {
812     case CSSPropertyBorderBottomStyle:
813     case CSSPropertyBorderCollapse:
814     case CSSPropertyBorderLeftStyle:
815     case CSSPropertyBorderRightStyle:
816     case CSSPropertyBorderTopStyle:
817     case CSSPropertyBoxSizing:
818     case CSSPropertyBreakAfter:
819     case CSSPropertyBreakBefore:
820     case CSSPropertyBreakInside:
821     case CSSPropertyCaptionSide:
822     case CSSPropertyClear:
823     case CSSPropertyColumnFill:
824     case CSSPropertyWebkitColumnProgression:
825     case CSSPropertyColumnRuleStyle:
826     case CSSPropertyDirection:
827     case CSSPropertyDisplay:
828     case CSSPropertyEmptyCells:
829     case CSSPropertyFlexDirection:
830     case CSSPropertyFlexWrap:
831     case CSSPropertyFloat:
832     case CSSPropertyFontVariantAlternates:
833     case CSSPropertyFontVariantCaps:
834     case CSSPropertyFontVariantPosition:
835     case CSSPropertyImageRendering:
836     case CSSPropertyListStylePosition:
837     case CSSPropertyListStyleType:
838     case CSSPropertyObjectFit:
839     case CSSPropertyOutlineStyle:
840     case CSSPropertyOverflowWrap:
841     case CSSPropertyOverflowX:
842     case CSSPropertyOverflowY:
843     case CSSPropertyPointerEvents:
844     case CSSPropertyPosition:
845     case CSSPropertyResize:
846     case CSSPropertySpeak:
847     case CSSPropertyTableLayout:
848     case CSSPropertyTextAlign:
849     case CSSPropertyTextLineThroughMode:
850     case CSSPropertyTextLineThroughStyle:
851     case CSSPropertyTextOverflow:
852     case CSSPropertyTextOverlineMode:
853     case CSSPropertyTextOverlineStyle:
854     case CSSPropertyTextRendering:
855     case CSSPropertyTextTransform:
856     case CSSPropertyTextUnderlineMode:
857     case CSSPropertyTextUnderlineStyle:
858     case CSSPropertyTransformStyle:
859     case CSSPropertyUnicodeBidi:
860     case CSSPropertyVisibility:
861     case CSSPropertyWebkitAppearance:
862     case CSSPropertyWebkitBackfaceVisibility:
863     case CSSPropertyWebkitBorderAfterStyle:
864     case CSSPropertyWebkitBorderBeforeStyle:
865     case CSSPropertyWebkitBorderEndStyle:
866     case CSSPropertyWebkitBorderFit:
867     case CSSPropertyWebkitBorderStartStyle:
868     case CSSPropertyWebkitBoxAlign:
869     case CSSPropertyWebkitBoxDirection:
870     case CSSPropertyWebkitBoxLines:
871     case CSSPropertyWebkitBoxOrient:
872     case CSSPropertyWebkitBoxPack:
873     case CSSPropertyWebkitColumnAxis:
874     case CSSPropertyWebkitFontKerning:
875     case CSSPropertyWebkitFontSmoothing:
876     case CSSPropertyWebkitHyphens:
877     case CSSPropertyWebkitLineAlign:
878     case CSSPropertyLineBreak:
879     case CSSPropertyWebkitLineSnap:
880     case CSSPropertyWebkitMarginAfterCollapse:
881     case CSSPropertyWebkitMarginBeforeCollapse:
882     case CSSPropertyWebkitMarginBottomCollapse:
883     case CSSPropertyWebkitMarginTopCollapse:
884     case CSSPropertyWebkitMarqueeDirection:
885     case CSSPropertyWebkitMarqueeStyle:
886     case CSSPropertyWebkitNbspMode:
887     case CSSPropertyWebkitPrintColorAdjust:
888     case CSSPropertyWebkitRtlOrdering:
889     case CSSPropertyWebkitRubyPosition:
890     case CSSPropertyWebkitTextCombine:
891     case CSSPropertyWebkitTextDecorationStyle:
892     case CSSPropertyWebkitTextOrientation:
893     case CSSPropertyWebkitTextSecurity:
894     case CSSPropertyWebkitTextZoom:
895     case CSSPropertyWebkitTransformStyle:
896     case CSSPropertyWebkitUserDrag:
897     case CSSPropertyWebkitUserModify:
898     case CSSPropertyWebkitUserSelect:
899     case CSSPropertyWhiteSpace:
900     case CSSPropertyWordBreak:
901     case CSSPropertyWordWrap:
902
903     // SVG CSS properties from SVG 1.1, Appendix N: Property Index.
904     case CSSPropertyAlignmentBaseline:
905     case CSSPropertyBufferedRendering:
906     case CSSPropertyClipRule:
907     case CSSPropertyColorInterpolation:
908     case CSSPropertyColorInterpolationFilters:
909     case CSSPropertyColorRendering:
910     case CSSPropertyDominantBaseline:
911     case CSSPropertyFillRule:
912     case CSSPropertyMaskType:
913     case CSSPropertyShapeRendering:
914     case CSSPropertyStrokeLinecap:
915     case CSSPropertyStrokeLinejoin:
916     case CSSPropertyTextAnchor:
917     case CSSPropertyVectorEffect:
918     case CSSPropertyWritingMode:
919
920     // FIXME-NEWPARSER: Treat all as a keyword property.
921     // case CSSPropertyAll:
922
923     // FIXME-NEWPARSER: Add the following unprefixed properties:
924     // case CSSPropertyBackfaceVisibility:
925     // case CSSPropertyFontKerning:
926     // case CSSPropertyHyphens:
927     // case CSSPropertyOverflowAnchor:
928     // case CSSPropertyScrollBehavior:
929     // case CSSPropertyScrollSnapType:
930     // case CSSPropertyTextAlignLast:
931     // case CSSPropertyTextCombineUpright:
932     // case CSSPropertyTextDecorationStyle:
933     // case CSSPropertyTextJustify:
934     // case CSSPropertyTextOrientation:
935     // case CSSPropertyUserSelect:
936 #if ENABLE(CSS_TRAILING_WORD)
937     case CSSPropertyAppleTrailingWord:
938 #endif
939 #if ENABLE(CSS_COMPOSITING)
940     case CSSPropertyIsolation:
941     case CSSPropertyMixBlendMode:
942 #endif
943 #if ENABLE(TOUCH_EVENTS)
944     case CSSPropertyTouchAction:
945 #endif
946 #if ENABLE(CSS_BOX_DECORATION_BREAK)
947     case CSSPropertyWebkitBoxDecorationBreak:
948 #endif
949 #if ENABLE(CURSOR_VISIBILITY)
950     case CSSPropertyWebkitCursorVisibility:
951 #endif
952 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
953     case CSSPropertyWebkitOverflowScrolling:
954 #endif
955 #if ENABLE(CSS_REGIONS)
956     case CSSPropertyWebkitRegionFragment:
957 #endif
958 #if ENABLE(CSS3_TEXT)
959     case CSSPropertyWebkitTextAlignLast:
960     case CSSPropertyWebkitTextJustify:
961 #endif
962 #if PLATFORM(IOS)
963     // Apple specific property. This will never be standardized and is purely to
964     // support custom WebKit-based Apple applications.
965     case CSSPropertyWebkitTouchCallout:
966 #endif
967 #if ENABLE(APPLE_PAY)
968     case CSSPropertyApplePayButtonStyle:
969     case CSSPropertyApplePayButtonType:
970 #endif
971         return true;
972     case CSSPropertyJustifyContent:
973     case CSSPropertyAlignContent:
974     case CSSPropertyAlignItems:
975     case CSSPropertyAlignSelf:
976         return !RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled();
977     default:
978         return false;
979     }
980 }
981
982 static bool isUniversalKeyword(const String& string)
983 {
984     // These keywords can be used for all properties.
985     return equalLettersIgnoringASCIICase(string, "initial")
986     || equalLettersIgnoringASCIICase(string, "inherit")
987     || equalLettersIgnoringASCIICase(string, "unset")
988     || equalLettersIgnoringASCIICase(string, "revert");
989 }
990
991 static RefPtr<CSSValue> parseKeywordValue(CSSPropertyID propertyId, const String& string, CSSParserMode parserMode)
992 {
993     ASSERT(!string.isEmpty());
994
995     if (!CSSParserFastPaths::isKeywordPropertyID(propertyId)) {
996         // All properties accept the values of "initial" and "inherit".
997         if (!isUniversalKeyword(string))
998             return nullptr;
999
1000         // Parse initial/inherit shorthands using the CSSPropertyParser.
1001         if (shorthandForProperty(propertyId).length())
1002             return nullptr;
1003
1004         // Descriptors do not support css wide keywords.
1005         if (CSSProperty::isDescriptorOnly(propertyId))
1006             return nullptr;
1007     }
1008
1009     CSSValueID valueID = cssValueKeywordID(string);
1010
1011     if (!valueID)
1012         return nullptr;
1013
1014     if (valueID == CSSValueInherit)
1015         return CSSValuePool::singleton().createInheritedValue();
1016     if (valueID == CSSValueInitial)
1017         return CSSValuePool::singleton().createExplicitInitialValue();
1018     if (valueID == CSSValueUnset)
1019         return CSSValuePool::singleton().createUnsetValue();
1020     if (valueID == CSSValueRevert)
1021         return CSSValuePool::singleton().createRevertValue();
1022     
1023     if (CSSParserFastPaths::isValidKeywordPropertyAndValue(propertyId, valueID, parserMode))
1024         return CSSPrimitiveValue::createIdentifier(valueID);
1025     return nullptr;
1026 }
1027
1028 template <typename CharType>
1029 static bool parseTransformTranslateArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSFunctionValue* transformValue)
1030 {
1031     while (expectedCount) {
1032         size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
1033         if (delimiter == notFound)
1034             return false;
1035         unsigned argumentLength = static_cast<unsigned>(delimiter);
1036         CSSPrimitiveValue::UnitType unit = CSSPrimitiveValue::UnitType::CSS_NUMBER;
1037         double number;
1038         if (!parseSimpleLength(pos, argumentLength, unit, number))
1039             return false;
1040         if (!number && unit == CSSPrimitiveValue::CSS_NUMBER)
1041             unit = CSSPrimitiveValue::UnitType::CSS_PX;
1042         if (unit == CSSPrimitiveValue::UnitType::CSS_NUMBER || (unit == CSSPrimitiveValue::UnitType::CSS_PERCENTAGE && (transformValue->name() == CSSValueTranslateZ || (transformValue->name() == CSSValueTranslate3d && expectedCount == 1))))
1043             return false;
1044         transformValue->append(CSSPrimitiveValue::create(number, unit));
1045         pos += argumentLength + 1;
1046         --expectedCount;
1047     }
1048     return true;
1049 }
1050
1051 template <typename CharType>
1052 static bool parseTransformNumberArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSFunctionValue* transformValue)
1053 {
1054     while (expectedCount) {
1055         size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
1056         if (delimiter == notFound)
1057             return false;
1058         unsigned argumentLength = static_cast<unsigned>(delimiter);
1059         bool ok;
1060         double number = charactersToDouble(pos, argumentLength, &ok);
1061         if (!ok)
1062             return false;
1063         transformValue->append(CSSPrimitiveValue::create(number, CSSPrimitiveValue::UnitType::CSS_NUMBER));
1064         pos += argumentLength + 1;
1065         --expectedCount;
1066     }
1067     return true;
1068 }
1069
1070 static const int kShortestValidTransformStringLength = 12;
1071
1072 template <typename CharType>
1073 static RefPtr<CSSFunctionValue> parseSimpleTransformValue(CharType*& pos, CharType* end)
1074 {
1075     if (end - pos < kShortestValidTransformStringLength)
1076         return nullptr;
1077
1078     const bool isTranslate = toASCIILower(pos[0]) == 't'
1079         && toASCIILower(pos[1]) == 'r'
1080         && toASCIILower(pos[2]) == 'a'
1081         && toASCIILower(pos[3]) == 'n'
1082         && toASCIILower(pos[4]) == 's'
1083         && toASCIILower(pos[5]) == 'l'
1084         && toASCIILower(pos[6]) == 'a'
1085         && toASCIILower(pos[7]) == 't'
1086         && toASCIILower(pos[8]) == 'e';
1087
1088     if (isTranslate) {
1089         CSSValueID transformType;
1090         unsigned expectedArgumentCount = 1;
1091         unsigned argumentStart = 11;
1092         CharType c9 = toASCIILower(pos[9]);
1093         if (c9 == 'x' && pos[10] == '(') {
1094             transformType = CSSValueTranslateX;
1095         } else if (c9 == 'y' && pos[10] == '(') {
1096             transformType = CSSValueTranslateY;
1097         } else if (c9 == 'z' && pos[10] == '(') {
1098             transformType = CSSValueTranslateZ;
1099         } else if (c9 == '(') {
1100             transformType = CSSValueTranslate;
1101             expectedArgumentCount = 2;
1102             argumentStart = 10;
1103         } else if (c9 == '3' && toASCIILower(pos[10]) == 'd' && pos[11] == '(') {
1104             transformType = CSSValueTranslate3d;
1105             expectedArgumentCount = 3;
1106             argumentStart = 12;
1107         } else {
1108             return nullptr;
1109         }
1110         pos += argumentStart;
1111         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(transformType);
1112         if (!parseTransformTranslateArguments(pos, end, expectedArgumentCount, transformValue.get()))
1113             return nullptr;
1114         return transformValue;
1115     }
1116
1117     const bool isMatrix3d = toASCIILower(pos[0]) == 'm'
1118         && toASCIILower(pos[1]) == 'a'
1119         && toASCIILower(pos[2]) == 't'
1120         && toASCIILower(pos[3]) == 'r'
1121         && toASCIILower(pos[4]) == 'i'
1122         && toASCIILower(pos[5]) == 'x'
1123         && pos[6] == '3'
1124         && toASCIILower(pos[7]) == 'd'
1125         && pos[8] == '(';
1126
1127     if (isMatrix3d) {
1128         pos += 9;
1129         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(CSSValueMatrix3d);
1130         if (!parseTransformNumberArguments(pos, end, 16, transformValue.get()))
1131             return nullptr;
1132         return transformValue;
1133     }
1134
1135     const bool isScale3d = toASCIILower(pos[0]) == 's'
1136         && toASCIILower(pos[1]) == 'c'
1137         && toASCIILower(pos[2]) == 'a'
1138         && toASCIILower(pos[3]) == 'l'
1139         && toASCIILower(pos[4]) == 'e'
1140         && pos[5] == '3'
1141         && toASCIILower(pos[6]) == 'd'
1142         && pos[7] == '(';
1143
1144     if (isScale3d) {
1145         pos += 8;
1146         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(CSSValueScale3d);
1147         if (!parseTransformNumberArguments(pos, end, 3, transformValue.get()))
1148             return nullptr;
1149         return transformValue;
1150     }
1151
1152     return nullptr;
1153 }
1154
1155 template <typename CharType>
1156 static bool transformCanLikelyUseFastPath(const CharType* chars, unsigned length)
1157 {
1158     // Very fast scan that attempts to reject most transforms that couldn't
1159     // take the fast path. This avoids doing the malloc and string->double
1160     // conversions in parseSimpleTransformValue only to discard them when we
1161     // run into a transform component we don't understand.
1162     unsigned i = 0;
1163     while (i < length) {
1164         if (isCSSSpace(chars[i])) {
1165             ++i;
1166             continue;
1167         }
1168         if (length - i < kShortestValidTransformStringLength)
1169             return false;
1170         switch (toASCIILower(chars[i])) {
1171         case 't':
1172             // translate, translateX, translateY, translateZ, translate3d.
1173             if (toASCIILower(chars[i + 8]) != 'e')
1174                 return false;
1175             i += 9;
1176             break;
1177         case 'm':
1178             // matrix3d.
1179             if (toASCIILower(chars[i + 7]) != 'd')
1180                 return false;
1181             i += 8;
1182             break;
1183         case 's':
1184             // scale3d.
1185             if (toASCIILower(chars[i + 6]) != 'd')
1186                 return false;
1187             i += 7;
1188             break;
1189         default:
1190             // All other things, ex. rotate.
1191             return false;
1192         }
1193         size_t argumentsEnd = WTF::find(chars, length, ')', i);
1194         if (argumentsEnd == notFound)
1195             return false;
1196         // Advance to the end of the arguments.
1197         i = argumentsEnd + 1;
1198     }
1199     return i == length;
1200 }
1201
1202 template <typename CharType>
1203 static RefPtr<CSSValueList> parseSimpleTransformList(const CharType* chars, unsigned length)
1204 {
1205     if (!transformCanLikelyUseFastPath(chars, length))
1206         return nullptr;
1207     const CharType*& pos = chars;
1208     const CharType* end = chars + length;
1209     RefPtr<CSSValueList> transformList;
1210     while (pos < end) {
1211         while (pos < end && isCSSSpace(*pos))
1212             ++pos;
1213         if (pos >= end)
1214             break;
1215         RefPtr<CSSFunctionValue> transformValue = parseSimpleTransformValue(pos, end);
1216         if (!transformValue)
1217             return nullptr;
1218         if (!transformList)
1219             transformList = CSSValueList::createSpaceSeparated();
1220         transformList->append(*transformValue);
1221     }
1222     return transformList;
1223 }
1224
1225 static RefPtr<CSSValue> parseSimpleTransform(CSSPropertyID propertyID, const String& string)
1226 {
1227     ASSERT(!string.isEmpty());
1228
1229     if (propertyID != CSSPropertyTransform)
1230         return nullptr;
1231     if (string.is8Bit())
1232         return parseSimpleTransformList(string.characters8(), string.length());
1233     return parseSimpleTransformList(string.characters16(), string.length());
1234 }
1235
1236 RefPtr<CSSValue> CSSParserFastPaths::maybeParseValue(CSSPropertyID propertyID, const String& string, CSSParserMode parserMode)
1237 {
1238     RefPtr<CSSValue> result = parseSimpleLengthValue(propertyID, string, parserMode);
1239     if (result)
1240         return result;
1241     if (isColorPropertyID(propertyID))
1242         return parseColor(string, parserMode);
1243     result = parseKeywordValue(propertyID, string, parserMode);
1244     if (result)
1245         return result;
1246     result = parseSimpleTransform(propertyID, string);
1247     if (result)
1248         return result;
1249     return nullptr;
1250 }
1251
1252 } // namespace WebCore