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 |
|
---|
47 | namespace WebCore {
|
---|
48 |
|
---|
49 | static 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 |
|
---|
102 | template<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 |
|
---|
115 | template <typename CharacterType>
|
---|
116 | static 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 |
|
---|
131 | template <typename CharacterType>
|
---|
132 | static 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 |
|
---|
152 | static 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
|
---|
189 | template <typename CharacterType>
|
---|
190 | static 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
|
---|
220 | template <typename CharacterType>
|
---|
221 | static 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 |
|
---|
256 | template <typename CharacterType>
|
---|
257 | static 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 |
|
---|
325 | template <typename CharacterType>
|
---|
326 | static 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 |
|
---|
339 | template <typename CharacterType>
|
---|
340 | static 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 |
|
---|
388 | template <typename CharacterType>
|
---|
389 | static 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 |
|
---|
400 | template <typename CharacterType>
|
---|
401 | static 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 |
|
---|
411 | static 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 |
|
---|
442 | template<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 |
|
---|
457 | template<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 |
|
---|
513 | static 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 |
|
---|
521 | static 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 |
|
---|
535 | static 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 |
|
---|
544 | template<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 |
|
---|
558 | template<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 |
|
---|
565 | std::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 |
|
---|
572 | std::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 |
|
---|
579 | std::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 |
|
---|
586 | bool 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 |
|
---|
912 | bool 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 |
|
---|
1060 | bool CSSParserFastPaths::isPartialKeywordPropertyID(CSSPropertyID propertyId)
|
---|
1061 | {
|
---|
1062 | switch (propertyId) {
|
---|
1063 | case CSSPropertyListStyleType:
|
---|
1064 | return true;
|
---|
1065 | default:
|
---|
1066 | return false;
|
---|
1067 | }
|
---|
1068 | }
|
---|
1069 |
|
---|
1070 | static 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 |
|
---|
1080 | static 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 |
|
---|
1115 | template <typename CharType>
|
---|
1116 | static 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 |
|
---|
1138 | template <typename CharType>
|
---|
1139 | static 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 |
|
---|
1159 | template <typename CharType>
|
---|
1160 | static 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 |
|
---|
1177 | static const int kShortestValidTransformStringLength = 9; // "rotate(0)"
|
---|
1178 |
|
---|
1179 | template <typename CharType>
|
---|
1180 | static 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 |
|
---|
1288 | template <typename CharType>
|
---|
1289 | static 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 |
|
---|
1346 | template <typename CharType>
|
---|
1347 | static 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 |
|
---|
1369 | static 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 |
|
---|
1379 | static 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 |
|
---|
1387 | RefPtr<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
|
---|