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