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