[css-grid] Remove compilation flag ENABLE_CSS_GRID_LAYOUT
[WebKit-https.git] / Source / WebCore / css / parser / CSSParserFastPaths.cpp
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Copyright (C) 2016 Apple Inc. All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //    * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //    * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //    * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "config.h"
31 #include "CSSParserFastPaths.h"
32
33 #include "CSSFunctionValue.h"
34 #include "CSSInheritedValue.h"
35 #include "CSSInitialValue.h"
36 #include "CSSParserIdioms.h"
37 #include "CSSPrimitiveValue.h"
38 #include "CSSPropertyParser.h"
39 #include "CSSValueList.h"
40 #include "CSSValuePool.h"
41 #include "HTMLParserIdioms.h"
42 #include "RuntimeEnabledFeatures.h"
43 #include "StyleColor.h"
44 #include "StylePropertyShorthand.h"
45 #include "StyleSheetContents.h"
46
47 namespace WebCore {
48
49 static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
50 {
51     switch (propertyId) {
52     case CSSPropertyFontSize:
53     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 CSSPropertyFontStyle: // normal | italic | oblique
563         return valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique;
564     case CSSPropertyFontStretch: // normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded
565         return valueID == CSSValueNormal || (valueID >= CSSValueUltraCondensed && valueID <= CSSValueUltraExpanded);
566     case CSSPropertyImageRendering: // auto | optimizeContrast | pixelated | optimizeSpeed | crispEdges | optimizeQuality | webkit-crispEdges
567         return valueID == CSSValueAuto || valueID == CSSValueOptimizeSpeed || valueID == CSSValueOptimizeQuality || valueID == CSSValueWebkitCrispEdges || valueID == CSSValueWebkitOptimizeContrast || valueID == CSSValueCrispEdges || valueID == CSSValuePixelated;
568 #if ENABLE(CSS_COMPOSITING)
569     case CSSPropertyIsolation: // auto | isolate
570         return valueID == CSSValueAuto || valueID == CSSValueIsolate;
571 #endif
572     case CSSPropertyListStylePosition: // inside | outside
573         return valueID == CSSValueInside || valueID == CSSValueOutside;
574     case CSSPropertyListStyleType:
575         // See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
576         // for the list of supported list-style-types.
577         return (valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone;
578     case CSSPropertyMaskType:
579         return valueID == CSSValueLuminance || valueID == CSSValueAlpha;
580     case CSSPropertyObjectFit:
581         return valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown;
582     case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto
583         return valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble);
584     // FIXME-NEWPARSER: Support?
585     // case CSSPropertyOverflowAnchor:
586     //    return valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAuto;
587     case CSSPropertyOverflowWrap: // normal | break-word
588     case CSSPropertyWordWrap:
589         return valueID == CSSValueNormal || valueID == CSSValueBreakWord;
590     case CSSPropertyOverflowX: // visible | hidden | scroll | auto | overlay
591         return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay;
592     case CSSPropertyOverflowY: // visible | hidden | scroll | auto | overlay | -webkit-paged-x | -webkit-paged-y
593         return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY;
594     case CSSPropertyBreakAfter:
595     case CSSPropertyBreakBefore:
596         return valueID == CSSValueAuto || valueID == CSSValueAvoid || valueID == CSSValueAvoidPage || valueID == CSSValuePage || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueRecto || valueID == CSSValueVerso || valueID == CSSValueAvoidColumn || valueID == CSSValueColumn
597 #if ENABLE(CSS_REGIONS)
598             || valueID == CSSValueRegion || valueID == CSSValueAvoidRegion
599 #endif
600         ;
601     case CSSPropertyBreakInside:
602         return valueID == CSSValueAuto || valueID == CSSValueAvoid || valueID == CSSValueAvoidPage || valueID == CSSValueAvoidColumn
603 #if ENABLE(CSS_REGIONS)
604             || valueID == CSSValueAvoidRegion
605 #endif
606         ;
607     case CSSPropertyPointerEvents:
608         // none | visiblePainted | visibleFill | visibleStroke | visible |
609         // painted | fill | stroke | auto | all | bounding-box
610         return valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblePainted && valueID <= CSSValueStroke);
611     case CSSPropertyPosition: // static | relative | absolute | fixed | sticky
612         return valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed || valueID == CSSValueWebkitSticky;
613     case CSSPropertyResize: // none | both | horizontal | vertical | auto
614         return valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto;
615     // FIXME-NEWPARSER: Investigate this property.
616     // case CSSPropertyScrollBehavior: // auto | smooth
617     //     ASSERT(RuntimeEnabledFeatures::cssomSmoothScrollEnabled());
618     //   return valueID == CSSValueAuto || valueID == CSSValueSmooth;
619     case CSSPropertyShapeRendering:
620         return valueID == CSSValueAuto || valueID == CSSValueOptimizeSpeed || valueID == CSSValueCrispedges || valueID == CSSValueGeometricPrecision;
621     case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation
622         return valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation;
623     case CSSPropertyStrokeLinejoin:
624         return valueID == CSSValueMiter || valueID == CSSValueRound || valueID == CSSValueBevel;
625     case CSSPropertyStrokeLinecap:
626         return valueID == CSSValueButt || valueID == CSSValueRound || valueID == CSSValueSquare;
627     case CSSPropertyTableLayout: // auto | fixed
628         return valueID == CSSValueAuto || valueID == CSSValueFixed;
629     case CSSPropertyTextAlign:
630         return (valueID >= CSSValueWebkitAuto && valueID <= CSSValueWebkitMatchParent) || valueID == CSSValueStart || valueID == CSSValueEnd;
631 #if ENABLE(CSS3_TEXT)
632     case CSSPropertyWebkitTextAlignLast:
633         // auto | start | end | left | right | center | justify
634         return (valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto;
635 #endif
636     case CSSPropertyTextAnchor:
637         return valueID == CSSValueStart || valueID == CSSValueMiddle || valueID == CSSValueEnd;
638 // FIXME-NEWPARSER: Support
639 //    case CSSPropertyTextCombineUpright:
640 //        return valueID == CSSValueNone || valueID == CSSValueAll;
641     case CSSPropertyWebkitTextDecorationStyle:
642         // solid | double | dotted | dashed | wavy
643         return valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDotted || valueID == CSSValueDashed || valueID == CSSValueWavy;
644 #if ENABLE(CSS3_TEXT)
645     case CSSPropertyWebkitTextJustify:
646         // auto | none | inter-word | distribute
647         return valueID == CSSValueInterWord || valueID == CSSValueDistribute || valueID == CSSValueAuto || valueID == CSSValueNone;
648 #endif
649     case CSSPropertyWebkitTextOrientation: // mixed | upright | sideways | sideways-right
650         return valueID == CSSValueMixed || valueID == CSSValueUpright || valueID == CSSValueSideways || valueID == CSSValueSidewaysRight;
651     case CSSPropertyTextOverflow: // clip | ellipsis
652         return valueID == CSSValueClip || valueID == CSSValueEllipsis;
653     case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
654         return valueID == CSSValueAuto || valueID == CSSValueOptimizeSpeed || valueID == CSSValueOptimizeLegibility || valueID == CSSValueGeometricPrecision;
655     case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none
656         return (valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone;
657     case CSSPropertyUnicodeBidi:
658         return valueID == CSSValueNormal || valueID == CSSValueEmbed
659             || valueID == CSSValueBidiOverride || valueID == CSSValueWebkitIsolate
660             || valueID == CSSValueWebkitIsolateOverride || valueID == CSSValueWebkitPlaintext;
661     case CSSPropertyVectorEffect:
662         return valueID == CSSValueNone || valueID == CSSValueNonScalingStroke;
663     case CSSPropertyVisibility: // visible | hidden | collapse
664         return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse;
665     case CSSPropertyWebkitAppearance:
666         return (valueID >= CSSValueCheckbox && valueID <= CSSValueCapsLockIndicator) || valueID == CSSValueNone;
667     case CSSPropertyWebkitBackfaceVisibility:
668         return valueID == CSSValueVisible || valueID == CSSValueHidden;
669 #if ENABLE(CSS_COMPOSITING)
670     case CSSPropertyMixBlendMode:
671         return valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen || valueID == CSSValueOverlay
672             || valueID == CSSValueDarken || valueID == CSSValueLighten || valueID == CSSValueColorDodge || valueID == CSSValueColorBurn
673             || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference || valueID == CSSValueExclusion
674             || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor || valueID == CSSValueLuminosity || valueID == CSSValuePlusDarker || valueID == CSSValuePlusLighter;
675 #endif
676     case CSSPropertyWebkitBoxAlign:
677         return valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline;
678 #if ENABLE(CSS_BOX_DECORATION_BREAK)
679     case CSSPropertyWebkitBoxDecorationBreak:
680         return valueID == CSSValueClone || valueID == CSSValueSlice;
681     case CSSPropertyWebkitBoxDirection:
682         return valueID == CSSValueNormal || valueID == CSSValueReverse;
683 #endif
684     case CSSPropertyWebkitBoxLines:
685         return valueID == CSSValueSingle || valueID == CSSValueMultiple;
686     case CSSPropertyWebkitBoxOrient:
687         return valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis;
688     case CSSPropertyWebkitBoxPack:
689         return valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify;
690 #if ENABLE(CURSOR_VISIBILITY)
691     case CSSPropertyWebkitCursorVisibility:
692         return valueID == CSSValueAuto || valueID == CSSValueAutoHide;
693 #endif
694     case CSSPropertyColumnFill:
695         return valueID == CSSValueAuto || valueID == CSSValueBalance;
696     case CSSPropertyWebkitColumnAxis:
697         return valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto;
698     case CSSPropertyWebkitColumnProgression:
699         return valueID == CSSValueNormal || valueID == CSSValueReverse;
700     case CSSPropertyAlignContent:
701         // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
702         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch;
703     case CSSPropertyAlignItems:
704         // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
705         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
706     case CSSPropertyAlignSelf:
707         // FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
708         return valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
709     case CSSPropertyFlexDirection:
710         return valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse;
711     case CSSPropertyFlexWrap:
712         return valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse;
713     case CSSPropertyWebkitHyphens:
714         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueManual;
715     case CSSPropertyJustifyContent:
716         // FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
717         return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround;
718     case CSSPropertyWebkitFontKerning:
719         return valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone;
720     case CSSPropertyWebkitFontSmoothing:
721         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased;
722     case CSSPropertyWebkitLineAlign:
723         return valueID == CSSValueNone || valueID == CSSValueEdges;
724     case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
725         return valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace;
726     case CSSPropertyWebkitLineSnap:
727         return valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain;
728     case CSSPropertyWebkitMarginAfterCollapse:
729     case CSSPropertyWebkitMarginBeforeCollapse:
730     case CSSPropertyWebkitMarginBottomCollapse:
731     case CSSPropertyWebkitMarginTopCollapse:
732         return valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard;
733     case CSSPropertyWebkitPrintColorAdjust:
734         return valueID == CSSValueExact || valueID == CSSValueEconomy;
735     case CSSPropertyWebkitRtlOrdering:
736         return valueID == CSSValueLogical || valueID == CSSValueVisual;
737     case CSSPropertyWebkitRubyPosition:
738         return valueID == CSSValueBefore || valueID == CSSValueAfter || valueID == CSSValueInterCharacter;
739     case CSSPropertyWebkitTextCombine:
740         return valueID == CSSValueNone || valueID == CSSValueHorizontal;
741     case CSSPropertyWebkitTextSecurity: // disc | circle | square | none
742         return valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone;
743     case CSSPropertyTransformStyle:
744     case CSSPropertyWebkitTransformStyle:
745         return valueID == CSSValueFlat || valueID == CSSValuePreserve3d;
746     case CSSPropertyWebkitUserDrag: // auto | none | element
747         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement;
748     case CSSPropertyWebkitUserModify: // read-only | read-write
749         return valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly;
750     case CSSPropertyWebkitUserSelect: // auto | none | text | all
751         return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll;
752     case CSSPropertyWritingMode:
753         // Note that horizontal-bt is not supported by the unprefixed version of
754         // the property, only by the -webkit- version.
755         return (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
756             || valueID == CSSValueLrTb || valueID == CSSValueRlTb || valueID == CSSValueTbRl
757             || valueID == CSSValueLr || valueID == CSSValueRl || valueID == CSSValueTb;
758     case CSSPropertyWhiteSpace: // normal | pre | nowrap
759         return valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap;
760     case CSSPropertyWordBreak: // normal | break-all | keep-all | break-word (this is a custom extension)
761         return valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueKeepAll || valueID == CSSValueBreakWord;
762     case CSSPropertyWebkitBorderFit:
763         return valueID == CSSValueBorder || valueID == CSSValueLines;
764 #if ENABLE(CSS_REGIONS)
765     case CSSPropertyWebkitRegionFragment:
766         return valueID == CSSValueAuto || valueID == CSSValueBreak;
767 #endif
768 #if ENABLE(TOUCH_EVENTS)
769     case CSSPropertyTouchAction: // auto | manipulation
770         return valueID == CSSValueAuto || valueID == CSSValueManipulation;
771 #endif
772 #if ENABLE(CSS_TRAILING_WORD)
773     case CSSPropertyAppleTrailingWord: // auto | -apple-partially-balanced
774         return valueID == CSSValueAuto || valueID == CSSValueWebkitPartiallyBalanced;
775 #endif
776 #if ENABLE(APPLE_PAY)
777     case CSSPropertyApplePayButtonStyle: // white | white-outline | black
778         return valueID == CSSValueWhite || valueID == CSSValueWhiteOutline || valueID == CSSValueBlack;
779     case CSSPropertyApplePayButtonType: // plain | buy | set-up | donate
780         return valueID == CSSValuePlain || valueID == CSSValueBuy || valueID == CSSValueSetUp || valueID == CSSValueDonate;
781 #endif
782     case CSSPropertyWebkitNbspMode: // normal | space
783         return valueID == CSSValueNormal || valueID == CSSValueSpace;
784     case CSSPropertyWebkitTextZoom:
785         return valueID == CSSValueNormal || valueID == CSSValueReset;
786 #if PLATFORM(IOS)
787     // Apple specific property. These will never be standardized and is purely to
788     // support custom WebKit-based Apple applications.
789     case CSSPropertyWebkitTouchCallout:
790         return valueID == CSSValueDefault || valueID == CSSValueNone;
791 #endif
792     case CSSPropertyWebkitMarqueeDirection:
793         return valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
794             || valueID == CSSValueUp || valueID == CSSValueAuto;
795     case CSSPropertyWebkitMarqueeStyle:
796         return valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate;
797     case CSSPropertyFontVariantPosition: // normal | sub | super
798         return valueID == CSSValueNormal || valueID == CSSValueSub || valueID == CSSValueSuper;
799     case CSSPropertyFontVariantCaps: // normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps
800         return valueID == CSSValueNormal || valueID == CSSValueSmallCaps || valueID == CSSValueAllSmallCaps || valueID == CSSValuePetiteCaps || valueID == CSSValueAllPetiteCaps || valueID == CSSValueUnicase || valueID == CSSValueTitlingCaps;
801     case CSSPropertyFontVariantAlternates: // We only support the normal and historical-forms values.
802         return valueID == CSSValueNormal || valueID == CSSValueHistoricalForms;
803 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
804     case CSSPropertyWebkitOverflowScrolling:
805         return valueID == CSSValueAuto || valueID == CSSValueTouch;
806 #endif
807     default:
808         ASSERT_NOT_REACHED();
809         return false;
810     }
811 }
812
813 bool CSSParserFastPaths::isKeywordPropertyID(CSSPropertyID propertyId)
814 {
815     switch (propertyId) {
816     case CSSPropertyBorderBottomStyle:
817     case CSSPropertyBorderCollapse:
818     case CSSPropertyBorderLeftStyle:
819     case CSSPropertyBorderRightStyle:
820     case CSSPropertyBorderTopStyle:
821     case CSSPropertyBoxSizing:
822     case CSSPropertyBreakAfter:
823     case CSSPropertyBreakBefore:
824     case CSSPropertyBreakInside:
825     case CSSPropertyCaptionSide:
826     case CSSPropertyClear:
827     case CSSPropertyColumnFill:
828     case CSSPropertyWebkitColumnProgression:
829     case CSSPropertyColumnRuleStyle:
830     case CSSPropertyDirection:
831     case CSSPropertyDisplay:
832     case CSSPropertyEmptyCells:
833     case CSSPropertyFlexDirection:
834     case CSSPropertyFlexWrap:
835     case CSSPropertyFloat:
836     case CSSPropertyFontStretch:
837     case CSSPropertyFontStyle:
838     case CSSPropertyFontVariantAlternates:
839     case CSSPropertyFontVariantCaps:
840     case CSSPropertyFontVariantPosition:
841     case CSSPropertyImageRendering:
842     case CSSPropertyListStylePosition:
843     case CSSPropertyListStyleType:
844     case CSSPropertyObjectFit:
845     case CSSPropertyOutlineStyle:
846     case CSSPropertyOverflowWrap:
847     case CSSPropertyOverflowX:
848     case CSSPropertyOverflowY:
849     case CSSPropertyPointerEvents:
850     case CSSPropertyPosition:
851     case CSSPropertyResize:
852     case CSSPropertySpeak:
853     case CSSPropertyTableLayout:
854     case CSSPropertyTextAlign:
855     case CSSPropertyTextLineThroughMode:
856     case CSSPropertyTextLineThroughStyle:
857     case CSSPropertyTextOverflow:
858     case CSSPropertyTextOverlineMode:
859     case CSSPropertyTextOverlineStyle:
860     case CSSPropertyTextRendering:
861     case CSSPropertyTextTransform:
862     case CSSPropertyTextUnderlineMode:
863     case CSSPropertyTextUnderlineStyle:
864     case CSSPropertyTransformStyle:
865     case CSSPropertyUnicodeBidi:
866     case CSSPropertyVisibility:
867     case CSSPropertyWebkitAppearance:
868     case CSSPropertyWebkitBackfaceVisibility:
869     case CSSPropertyWebkitBorderAfterStyle:
870     case CSSPropertyWebkitBorderBeforeStyle:
871     case CSSPropertyWebkitBorderEndStyle:
872     case CSSPropertyWebkitBorderFit:
873     case CSSPropertyWebkitBorderStartStyle:
874     case CSSPropertyWebkitBoxAlign:
875     case CSSPropertyWebkitBoxDirection:
876     case CSSPropertyWebkitBoxLines:
877     case CSSPropertyWebkitBoxOrient:
878     case CSSPropertyWebkitBoxPack:
879     case CSSPropertyWebkitColumnAxis:
880     case CSSPropertyWebkitFontKerning:
881     case CSSPropertyWebkitFontSmoothing:
882     case CSSPropertyWebkitHyphens:
883     case CSSPropertyWebkitLineAlign:
884     case CSSPropertyWebkitLineBreak:
885     case CSSPropertyWebkitLineSnap:
886     case CSSPropertyWebkitMarginAfterCollapse:
887     case CSSPropertyWebkitMarginBeforeCollapse:
888     case CSSPropertyWebkitMarginBottomCollapse:
889     case CSSPropertyWebkitMarginTopCollapse:
890     case CSSPropertyWebkitMarqueeDirection:
891     case CSSPropertyWebkitMarqueeStyle:
892     case CSSPropertyWebkitNbspMode:
893     case CSSPropertyWebkitPrintColorAdjust:
894     case CSSPropertyWebkitRtlOrdering:
895     case CSSPropertyWebkitRubyPosition:
896     case CSSPropertyWebkitTextCombine:
897     case CSSPropertyWebkitTextDecorationStyle:
898     case CSSPropertyWebkitTextOrientation:
899     case CSSPropertyWebkitTextSecurity:
900     case CSSPropertyWebkitTextZoom:
901     case CSSPropertyWebkitTransformStyle:
902     case CSSPropertyWebkitUserDrag:
903     case CSSPropertyWebkitUserModify:
904     case CSSPropertyWebkitUserSelect:
905     case CSSPropertyWhiteSpace:
906     case CSSPropertyWordBreak:
907     case CSSPropertyWordWrap:
908
909     // SVG CSS properties from SVG 1.1, Appendix N: Property Index.
910     case CSSPropertyAlignmentBaseline:
911     case CSSPropertyBufferedRendering:
912     case CSSPropertyClipRule:
913     case CSSPropertyColorInterpolation:
914     case CSSPropertyColorInterpolationFilters:
915     case CSSPropertyColorRendering:
916     case CSSPropertyDominantBaseline:
917     case CSSPropertyFillRule:
918     case CSSPropertyMaskType:
919     case CSSPropertyShapeRendering:
920     case CSSPropertyStrokeLinecap:
921     case CSSPropertyStrokeLinejoin:
922     case CSSPropertyTextAnchor:
923     case CSSPropertyVectorEffect:
924     case CSSPropertyWritingMode:
925
926     // FIXME-NEWPARSER: Treat all as a keyword property.
927     // case CSSPropertyAll:
928
929     // FIXME-NEWPARSER: Add the following unprefixed properties:
930     // case CSSPropertyBackfaceVisibility:
931     // case CSSPropertyFontKerning:
932     // case CSSPropertyHyphens:
933     // case CSSPropertyOverflowAnchor:
934     // case CSSPropertyScrollBehavior:
935     // case CSSPropertyScrollSnapType:
936     // case CSSPropertyTextAlignLast:
937     // case CSSPropertyTextCombineUpright:
938     // case CSSPropertyTextDecorationStyle:
939     // case CSSPropertyTextJustify:
940     // case CSSPropertyTextOrientation:
941     // case CSSPropertyUserSelect:
942 #if ENABLE(CSS_TRAILING_WORD)
943     case CSSPropertyAppleTrailingWord:
944 #endif
945 #if ENABLE(CSS_COMPOSITING)
946     case CSSPropertyIsolation:
947     case CSSPropertyMixBlendMode:
948 #endif
949 #if ENABLE(TOUCH_EVENTS)
950     case CSSPropertyTouchAction:
951 #endif
952 #if ENABLE(CSS_BOX_DECORATION_BREAK)
953     case CSSPropertyWebkitBoxDecorationBreak:
954 #endif
955 #if ENABLE(CURSOR_VISIBILITY)
956     case CSSPropertyWebkitCursorVisibility:
957 #endif
958 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
959     case CSSPropertyWebkitOverflowScrolling:
960 #endif
961 #if ENABLE(CSS_REGIONS)
962     case CSSPropertyWebkitRegionFragment:
963 #endif
964 #if ENABLE(CSS3_TEXT)
965     case CSSPropertyWebkitTextAlignLast:
966     case CSSPropertyWebkitTextJustify:
967 #endif
968 #if PLATFORM(IOS)
969     // Apple specific property. This will never be standardized and is purely to
970     // support custom WebKit-based Apple applications.
971     case CSSPropertyWebkitTouchCallout:
972 #endif
973 #if ENABLE(APPLE_PAY)
974     case CSSPropertyApplePayButtonStyle:
975     case CSSPropertyApplePayButtonType:
976 #endif
977         return true;
978     case CSSPropertyJustifyContent:
979     case CSSPropertyAlignContent:
980     case CSSPropertyAlignItems:
981     case CSSPropertyAlignSelf:
982         return !RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled();
983     default:
984         return false;
985     }
986 }
987
988 static bool isUniversalKeyword(const String& string)
989 {
990     // These keywords can be used for all properties.
991     return equalLettersIgnoringASCIICase(string, "initial")
992     || equalLettersIgnoringASCIICase(string, "inherit")
993     || equalLettersIgnoringASCIICase(string, "unset")
994     || equalLettersIgnoringASCIICase(string, "revert");
995 }
996
997 static RefPtr<CSSValue> parseKeywordValue(CSSPropertyID propertyId, const String& string, CSSParserMode parserMode)
998 {
999     ASSERT(!string.isEmpty());
1000
1001     if (!CSSParserFastPaths::isKeywordPropertyID(propertyId)) {
1002         // All properties accept the values of "initial" and "inherit".
1003         if (!isUniversalKeyword(string))
1004             return nullptr;
1005
1006         // Parse initial/inherit shorthands using the CSSPropertyParser.
1007         if (shorthandForProperty(propertyId).length())
1008             return nullptr;
1009
1010         // Descriptors do not support css wide keywords.
1011         if (CSSProperty::isDescriptorOnly(propertyId))
1012             return nullptr;
1013     }
1014
1015     CSSValueID valueID = cssValueKeywordID(string);
1016
1017     if (!valueID)
1018         return nullptr;
1019
1020     if (valueID == CSSValueInherit)
1021         return CSSValuePool::singleton().createInheritedValue();
1022     if (valueID == CSSValueInitial)
1023         return CSSValuePool::singleton().createExplicitInitialValue();
1024     if (valueID == CSSValueUnset)
1025         return CSSValuePool::singleton().createUnsetValue();
1026     if (valueID == CSSValueRevert)
1027         return CSSValuePool::singleton().createRevertValue();
1028     
1029     if (CSSParserFastPaths::isValidKeywordPropertyAndValue(propertyId, valueID, parserMode))
1030         return CSSPrimitiveValue::createIdentifier(valueID);
1031     return nullptr;
1032 }
1033
1034 template <typename CharType>
1035 static bool parseTransformTranslateArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSFunctionValue* transformValue)
1036 {
1037     while (expectedCount) {
1038         size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
1039         if (delimiter == notFound)
1040             return false;
1041         unsigned argumentLength = static_cast<unsigned>(delimiter);
1042         CSSPrimitiveValue::UnitType unit = CSSPrimitiveValue::UnitType::CSS_NUMBER;
1043         double number;
1044         if (!parseSimpleLength(pos, argumentLength, unit, number))
1045             return false;
1046         if (!number && unit == CSSPrimitiveValue::CSS_NUMBER)
1047             unit = CSSPrimitiveValue::UnitType::CSS_PX;
1048         if (unit == CSSPrimitiveValue::UnitType::CSS_NUMBER || (unit == CSSPrimitiveValue::UnitType::CSS_PERCENTAGE && (transformValue->name() == CSSValueTranslateZ || (transformValue->name() == CSSValueTranslate3d && expectedCount == 1))))
1049             return false;
1050         transformValue->append(CSSPrimitiveValue::create(number, unit));
1051         pos += argumentLength + 1;
1052         --expectedCount;
1053     }
1054     return true;
1055 }
1056
1057 template <typename CharType>
1058 static bool parseTransformNumberArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSFunctionValue* transformValue)
1059 {
1060     while (expectedCount) {
1061         size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
1062         if (delimiter == notFound)
1063             return false;
1064         unsigned argumentLength = static_cast<unsigned>(delimiter);
1065         bool ok;
1066         double number = charactersToDouble(pos, argumentLength, &ok);
1067         if (!ok)
1068             return false;
1069         transformValue->append(CSSPrimitiveValue::create(number, CSSPrimitiveValue::UnitType::CSS_NUMBER));
1070         pos += argumentLength + 1;
1071         --expectedCount;
1072     }
1073     return true;
1074 }
1075
1076 static const int kShortestValidTransformStringLength = 12;
1077
1078 template <typename CharType>
1079 static RefPtr<CSSFunctionValue> parseSimpleTransformValue(CharType*& pos, CharType* end)
1080 {
1081     if (end - pos < kShortestValidTransformStringLength)
1082         return nullptr;
1083
1084     const bool isTranslate = toASCIILower(pos[0]) == 't'
1085         && toASCIILower(pos[1]) == 'r'
1086         && toASCIILower(pos[2]) == 'a'
1087         && toASCIILower(pos[3]) == 'n'
1088         && toASCIILower(pos[4]) == 's'
1089         && toASCIILower(pos[5]) == 'l'
1090         && toASCIILower(pos[6]) == 'a'
1091         && toASCIILower(pos[7]) == 't'
1092         && toASCIILower(pos[8]) == 'e';
1093
1094     if (isTranslate) {
1095         CSSValueID transformType;
1096         unsigned expectedArgumentCount = 1;
1097         unsigned argumentStart = 11;
1098         CharType c9 = toASCIILower(pos[9]);
1099         if (c9 == 'x' && pos[10] == '(') {
1100             transformType = CSSValueTranslateX;
1101         } else if (c9 == 'y' && pos[10] == '(') {
1102             transformType = CSSValueTranslateY;
1103         } else if (c9 == 'z' && pos[10] == '(') {
1104             transformType = CSSValueTranslateZ;
1105         } else if (c9 == '(') {
1106             transformType = CSSValueTranslate;
1107             expectedArgumentCount = 2;
1108             argumentStart = 10;
1109         } else if (c9 == '3' && toASCIILower(pos[10]) == 'd' && pos[11] == '(') {
1110             transformType = CSSValueTranslate3d;
1111             expectedArgumentCount = 3;
1112             argumentStart = 12;
1113         } else {
1114             return nullptr;
1115         }
1116         pos += argumentStart;
1117         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(transformType);
1118         if (!parseTransformTranslateArguments(pos, end, expectedArgumentCount, transformValue.get()))
1119             return nullptr;
1120         return transformValue;
1121     }
1122
1123     const bool isMatrix3d = toASCIILower(pos[0]) == 'm'
1124         && toASCIILower(pos[1]) == 'a'
1125         && toASCIILower(pos[2]) == 't'
1126         && toASCIILower(pos[3]) == 'r'
1127         && toASCIILower(pos[4]) == 'i'
1128         && toASCIILower(pos[5]) == 'x'
1129         && pos[6] == '3'
1130         && toASCIILower(pos[7]) == 'd'
1131         && pos[8] == '(';
1132
1133     if (isMatrix3d) {
1134         pos += 9;
1135         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(CSSValueMatrix3d);
1136         if (!parseTransformNumberArguments(pos, end, 16, transformValue.get()))
1137             return nullptr;
1138         return transformValue;
1139     }
1140
1141     const bool isScale3d = toASCIILower(pos[0]) == 's'
1142         && toASCIILower(pos[1]) == 'c'
1143         && toASCIILower(pos[2]) == 'a'
1144         && toASCIILower(pos[3]) == 'l'
1145         && toASCIILower(pos[4]) == 'e'
1146         && pos[5] == '3'
1147         && toASCIILower(pos[6]) == 'd'
1148         && pos[7] == '(';
1149
1150     if (isScale3d) {
1151         pos += 8;
1152         RefPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(CSSValueScale3d);
1153         if (!parseTransformNumberArguments(pos, end, 3, transformValue.get()))
1154             return nullptr;
1155         return transformValue;
1156     }
1157
1158     return nullptr;
1159 }
1160
1161 template <typename CharType>
1162 static bool transformCanLikelyUseFastPath(const CharType* chars, unsigned length)
1163 {
1164     // Very fast scan that attempts to reject most transforms that couldn't
1165     // take the fast path. This avoids doing the malloc and string->double
1166     // conversions in parseSimpleTransformValue only to discard them when we
1167     // run into a transform component we don't understand.
1168     unsigned i = 0;
1169     while (i < length) {
1170         if (isCSSSpace(chars[i])) {
1171             ++i;
1172             continue;
1173         }
1174         if (length - i < kShortestValidTransformStringLength)
1175             return false;
1176         switch (toASCIILower(chars[i])) {
1177         case 't':
1178             // translate, translateX, translateY, translateZ, translate3d.
1179             if (toASCIILower(chars[i + 8]) != 'e')
1180                 return false;
1181             i += 9;
1182             break;
1183         case 'm':
1184             // matrix3d.
1185             if (toASCIILower(chars[i + 7]) != 'd')
1186                 return false;
1187             i += 8;
1188             break;
1189         case 's':
1190             // scale3d.
1191             if (toASCIILower(chars[i + 6]) != 'd')
1192                 return false;
1193             i += 7;
1194             break;
1195         default:
1196             // All other things, ex. rotate.
1197             return false;
1198         }
1199         size_t argumentsEnd = WTF::find(chars, length, ')', i);
1200         if (argumentsEnd == notFound)
1201             return false;
1202         // Advance to the end of the arguments.
1203         i = argumentsEnd + 1;
1204     }
1205     return i == length;
1206 }
1207
1208 template <typename CharType>
1209 static RefPtr<CSSValueList> parseSimpleTransformList(const CharType* chars, unsigned length)
1210 {
1211     if (!transformCanLikelyUseFastPath(chars, length))
1212         return nullptr;
1213     const CharType*& pos = chars;
1214     const CharType* end = chars + length;
1215     RefPtr<CSSValueList> transformList;
1216     while (pos < end) {
1217         while (pos < end && isCSSSpace(*pos))
1218             ++pos;
1219         if (pos >= end)
1220             break;
1221         RefPtr<CSSFunctionValue> transformValue = parseSimpleTransformValue(pos, end);
1222         if (!transformValue)
1223             return nullptr;
1224         if (!transformList)
1225             transformList = CSSValueList::createSpaceSeparated();
1226         transformList->append(*transformValue);
1227     }
1228     return transformList;
1229 }
1230
1231 static RefPtr<CSSValue> parseSimpleTransform(CSSPropertyID propertyID, const String& string)
1232 {
1233     ASSERT(!string.isEmpty());
1234
1235     if (propertyID != CSSPropertyTransform)
1236         return nullptr;
1237     if (string.is8Bit())
1238         return parseSimpleTransformList(string.characters8(), string.length());
1239     return parseSimpleTransformList(string.characters16(), string.length());
1240 }
1241
1242 RefPtr<CSSValue> CSSParserFastPaths::maybeParseValue(CSSPropertyID propertyID, const String& string, CSSParserMode parserMode)
1243 {
1244     RefPtr<CSSValue> result = parseSimpleLengthValue(propertyID, string, parserMode);
1245     if (result)
1246         return result;
1247     if (isColorPropertyID(propertyID))
1248         return parseColor(string, parserMode);
1249     result = parseKeywordValue(propertyID, string, parserMode);
1250     if (result)
1251         return result;
1252     result = parseSimpleTransform(propertyID, string);
1253     if (result)
1254         return result;
1255     return nullptr;
1256 }
1257
1258 } // namespace WebCore