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