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