source: webkit/trunk/Source/WebCore/css/parser/CSSParserFastPaths.cpp

Last change on this file was 295625, checked in by [email protected], 3 years ago

Fix styling of th elements when explicitly specifiying text-align:inherit
https://bugs.webkit.org/show_bug.cgi?id=138577

Patch by Ryan Reno <[email protected]> on 2022-06-16
Reviewed by Tim Nguyen.

<th> elements were being incorrectly centered when specifying
text-align: inherit. This fixes that bug by adding a new internal CSS
value for use in the UA stylesheet. This also removes a non-inherited
flag that was meant to be used for detecting this special case but ultimately didn't
work due to conflicts with the all property.

  • Source/WebCore/css/CSSValueKeywords.in:
  • Source/WebCore/css/html.css:

(th):

  • Source/WebCore/css/parser/CSSParserFastPaths.cpp:

(WebCore::CSSParserFastPaths::isValidKeywordPropertyAndValue):

  • Source/WebCore/css/parser/CSSParserIdioms.cpp:

(WebCore::isValueAllowedInMode):

  • Source/WebCore/rendering/style/RenderStyle.cpp:

(WebCore::RenderStyle::RenderStyle):

  • Source/WebCore/rendering/style/RenderStyle.h:

(WebCore::RenderStyle::NonInheritedFlags::operator== const):
(WebCore::RenderStyle::hasExplicitlySetTextAlign const): Deleted.
(WebCore::RenderStyle::setHasExplicitlySetTextAlign): Deleted.

  • Source/WebCore/style/StyleAdjuster.cpp:

(WebCore::Style::Adjuster::adjust const):

  • Source/WebCore/style/StyleBuilderConverter.h:

(WebCore::Style::BuilderConverter::convertTextAlign):

  • Source/WebCore/css/CSSProperties.json:
  • Source/WebCore/style/StyleBuilderCustom.h:

(WebCore::Style::BuilderCustom::applyInitialTextAlign): Deleted.
(WebCore::Style::BuilderCustom::applyValueTextAlign): Deleted.

  • LayoutTests/fast/css/internal-th-center-ua-only-expected.txt: Added.
  • LayoutTests/fast/css/internal-th-center-ua-only.html: Added.
  • LayoutTests/fast/table/center-th-when-parent-has-initial-text-align-expected.html:
  • LayoutTests/fast/table/center-th-when-parent-has-initial-text-align.html:

Canonical link: https://commits.webkit.org/251630@main

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