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