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