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