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