Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: Source/core/css/parser/CSSParserFastPaths.cpp

Issue 1169983004: Move fast-path color parsing from CSSPropertyParser to CSSParserFastPaths (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "config.h" 5 #include "config.h"
6 #include "core/css/parser/CSSParserFastPaths.h" 6 #include "core/css/parser/CSSParserFastPaths.h"
7 7
8 #include "core/StylePropertyShorthand.h" 8 #include "core/StylePropertyShorthand.h"
9 #include "core/css/CSSFunctionValue.h" 9 #include "core/css/CSSFunctionValue.h"
10 #include "core/css/CSSValuePool.h" 10 #include "core/css/CSSValuePool.h"
11 #include "core/css/parser/CSSParserIdioms.h" 11 #include "core/css/parser/CSSParserIdioms.h"
12 #include "core/css/parser/CSSParserValues.h" 12 #include "core/css/parser/CSSParserValues.h"
13 #include "core/css/parser/CSSPropertyParser.h" 13 #include "core/css/parser/CSSPropertyParser.h"
14 #include "core/html/parser/HTMLParserIdioms.h"
14 #include "platform/RuntimeEnabledFeatures.h" 15 #include "platform/RuntimeEnabledFeatures.h"
15 16
16 namespace blink { 17 namespace blink {
17 18
18 static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acce ptsNegativeNumbers) 19 static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acce ptsNegativeNumbers)
19 { 20 {
20 switch (propertyId) { 21 switch (propertyId) {
21 case CSSPropertyFontSize: 22 case CSSPropertyFontSize:
22 case CSSPropertyHeight: 23 case CSSPropertyHeight:
23 case CSSPropertyWidth: 24 case CSSPropertyWidth:
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 case CSSPropertyWebkitTextEmphasisColor: 136 case CSSPropertyWebkitTextEmphasisColor:
136 case CSSPropertyWebkitTextFillColor: 137 case CSSPropertyWebkitTextFillColor:
137 case CSSPropertyWebkitTextStrokeColor: 138 case CSSPropertyWebkitTextStrokeColor:
138 case CSSPropertyTextDecorationColor: 139 case CSSPropertyTextDecorationColor:
139 return true; 140 return true;
140 default: 141 default:
141 return false; 142 return false;
142 } 143 }
143 } 144 }
144 145
145 static PassRefPtrWillBeRawPtr<CSSValue> parseColorValue(CSSPropertyID propertyId , const String& string, CSSParserMode cssParserMode) 146 // Returns the number of characters which form a valid double
147 // and are terminated by the given terminator character
148 template <typename CharacterType>
149 static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
150 {
151 int length = end - string;
152 if (length < 1)
153 return 0;
154
155 bool decimalMarkSeen = false;
156 int processedLength = 0;
157
158 for (int i = 0; i < length; ++i) {
159 if (string[i] == terminator) {
160 processedLength = i;
161 break;
162 }
163 if (!isASCIIDigit(string[i])) {
164 if (!decimalMarkSeen && string[i] == '.')
165 decimalMarkSeen = true;
166 else
167 return 0;
168 }
169 }
170
171 if (decimalMarkSeen && processedLength == 1)
172 return 0;
173
174 return processedLength;
175 }
176
177 // Returns the number of characters consumed for parsing a valid double
178 // terminated by the given terminator character
179 template <typename CharacterType>
180 static int parseDouble(const CharacterType* string, const CharacterType* end, co nst char terminator, double& value)
181 {
182 int length = checkForValidDouble(string, end, terminator);
183 if (!length)
184 return 0;
185
186 int position = 0;
187 double localValue = 0;
188
189 // The consumed characters here are guaranteed to be
190 // ASCII digits with or without a decimal mark
191 for (; position < length; ++position) {
192 if (string[position] == '.')
193 break;
194 localValue = localValue * 10 + string[position] - '0';
195 }
196
197 if (++position == length) {
198 value = localValue;
199 return length;
200 }
201
202 double fraction = 0;
203 double scale = 1;
204
205 const double maxScale = 1000000;
206 while (position < length && scale < maxScale) {
207 fraction = fraction * 10 + string[position++] - '0';
208 scale *= 10;
209 }
210
211 value = localValue + fraction / scale;
212 return length;
213 }
214
215 template <typename CharacterType>
216 static bool parseColorIntOrPercentage(const CharacterType*& string, const Charac terType* end, const char terminator, CSSPrimitiveValue::UnitType& expect, int& v alue)
217 {
218 const CharacterType* current = string;
219 double localValue = 0;
220 bool negative = false;
221 while (current != end && isHTMLSpace<CharacterType>(*current))
222 current++;
223 if (current != end && *current == '-') {
224 negative = true;
225 current++;
226 }
227 if (current == end || !isASCIIDigit(*current))
228 return false;
229 while (current != end && isASCIIDigit(*current)) {
230 double newValue = localValue * 10 + *current++ - '0';
231 if (newValue >= 255) {
232 // Clamp values at 255.
233 localValue = 255;
234 while (current != end && isASCIIDigit(*current))
235 ++current;
236 break;
237 }
238 localValue = newValue;
239 }
240
241 if (current == end)
242 return false;
243
244 if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
245 return false;
246
247 if (*current == '.') {
248 // We already parsed the integral part, try to parse
249 // the fraction part of the percentage value.
250 double percentage = 0;
251 int numCharactersParsed = parseDouble(current, end, '%', percentage);
252 if (!numCharactersParsed)
253 return false;
254 current += numCharactersParsed;
255 if (*current != '%')
256 return false;
257 localValue += percentage;
258 }
259
260 if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
261 return false;
262
263 if (*current == '%') {
264 expect = CSSPrimitiveValue::CSS_PERCENTAGE;
265 localValue = localValue / 100.0 * 256.0;
266 // Clamp values at 255 for percentages over 100%
267 if (localValue > 255)
268 localValue = 255;
269 current++;
270 } else {
271 expect = CSSPrimitiveValue::CSS_NUMBER;
272 }
273
274 while (current != end && isHTMLSpace<CharacterType>(*current))
275 current++;
276 if (current == end || *current++ != terminator)
277 return false;
278 // Clamp negative values at zero.
279 value = negative ? 0 : static_cast<int>(localValue);
280 string = current;
281 return true;
282 }
283
284 template <typename CharacterType>
285 static inline bool isTenthAlpha(const CharacterType* string, const int length)
286 {
287 // "0.X"
288 if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(stri ng[2]))
289 return true;
290
291 // ".X"
292 if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
293 return true;
294
295 return false;
296 }
297
298 template <typename CharacterType>
299 static inline bool parseAlphaValue(const CharacterType*& string, const Character Type* end, const char terminator, int& value)
300 {
301 while (string != end && isHTMLSpace<CharacterType>(*string))
302 string++;
303
304 bool negative = false;
305
306 if (string != end && *string == '-') {
307 negative = true;
308 string++;
309 }
310
311 value = 0;
312
313 int length = end - string;
314 if (length < 2)
315 return false;
316
317 if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
318 return false;
319
320 if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
321 if (checkForValidDouble(string, end, terminator)) {
322 value = negative ? 0 : 255;
323 string = end;
324 return true;
325 }
326 return false;
327 }
328
329 if (length == 2 && string[0] != '.') {
330 value = !negative && string[0] == '1' ? 255 : 0;
331 string = end;
332 return true;
333 }
334
335 if (isTenthAlpha(string, length - 1)) {
336 static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 17 9, 204, 230 };
337 value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
338 string = end;
339 return true;
340 }
341
342 double alpha = 0;
343 if (!parseDouble(string, end, terminator, alpha))
344 return false;
345 value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
346 string = end;
347 return true;
348 }
349
350 template <typename CharacterType>
351 static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
352 {
353 if (length < 5)
354 return false;
355 return characters[4] == '('
356 && isASCIIAlphaCaselessEqual(characters[0], 'r')
357 && isASCIIAlphaCaselessEqual(characters[1], 'g')
358 && isASCIIAlphaCaselessEqual(characters[2], 'b')
359 && isASCIIAlphaCaselessEqual(characters[3], 'a');
360 }
361
362 template <typename CharacterType>
363 static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
364 {
365 if (length < 4)
366 return false;
367 return characters[3] == '('
368 && isASCIIAlphaCaselessEqual(characters[0], 'r')
369 && isASCIIAlphaCaselessEqual(characters[1], 'g')
370 && isASCIIAlphaCaselessEqual(characters[2], 'b');
371 }
372
373 template <typename CharacterType>
374 static bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length, bool quirksMode)
alancutter (OOO until 2018) 2015/06/10 00:31:20 parseRGBA32Internal()?
375 {
376 CSSPrimitiveValue::UnitType expect = CSSPrimitiveValue::CSS_UNKNOWN;
377
378 if (length >= 4 && characters[0] == '#')
379 return Color::parseHexColor(characters + 1, length - 1, rgb);
380
381 if (quirksMode && length >= 3) {
382 if (Color::parseHexColor(characters, length, rgb))
383 return true;
384 }
385
386 // Try rgba() syntax.
387 if (mightBeRGBA(characters, length)) {
388 const CharacterType* current = characters + 5;
389 const CharacterType* end = characters + length;
390 int red;
391 int green;
392 int blue;
393 int alpha;
394
395 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
396 return false;
397 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
398 return false;
399 if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
400 return false;
401 if (!parseAlphaValue(current, end, ')', alpha))
402 return false;
403 if (current != end)
404 return false;
405 rgb = makeRGBA(red, green, blue, alpha);
406 return true;
407 }
408
409 // Try rgb() syntax.
410 if (mightBeRGB(characters, length)) {
411 const CharacterType* current = characters + 4;
412 const CharacterType* end = characters + length;
413 int red;
414 int green;
415 int blue;
416 if (!parseColorIntOrPercentage(current, end, ',', expect, red))
417 return false;
418 if (!parseColorIntOrPercentage(current, end, ',', expect, green))
419 return false;
420 if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
421 return false;
422 if (current != end)
423 return false;
424 rgb = makeRGB(red, green, blue);
425 return true;
426 }
427
428 return false;
429 }
430
431 bool CSSParserFastPaths::parseColorAsRGBA32(RGBA32& rgb, const String& name, boo l quirksMode)
432 {
433 unsigned length = name.length();
434 bool parseResult;
435
436 if (!length)
437 return false;
438
439 if (name.is8Bit())
440 parseResult = fastParseColorInternal(rgb, name.characters8(), length, qu irksMode);
441 else
442 parseResult = fastParseColorInternal(rgb, name.characters16(), length, q uirksMode);
443
444 if (parseResult)
445 return true;
446
447 // Try named colors.
448 Color tc;
449 if (!tc.setNamedColor(name))
450 return false;
451 rgb = tc.rgb();
452 return true;
453 }
454
455 static PassRefPtrWillBeRawPtr<CSSValue> parseColor(const String& string, bool qu irksMode)
146 { 456 {
147 ASSERT(!string.isEmpty()); 457 ASSERT(!string.isEmpty());
148 bool quirksMode = isQuirksModeBehavior(cssParserMode);
149 if (!isColorPropertyID(propertyId))
150 return nullptr;
151 CSSParserString cssString; 458 CSSParserString cssString;
152 cssString.init(string); 459 cssString.init(string);
153 CSSValueID valueID = cssValueKeywordID(cssString); 460 CSSValueID valueID = cssValueKeywordID(cssString);
154 bool validPrimitive = false; 461 if (valueID == CSSValueWebkitText || valueID == CSSValueCurrentcolor
155 if (valueID == CSSValueWebkitText) { 462 || (valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
156 validPrimitive = true; 463 || (quirksMode && valueID >= CSSValueWebkitFocusRingColor && valueID < C SSValueWebkitText))
157 } else if (valueID == CSSValueCurrentcolor) {
158 validPrimitive = true;
159 } else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || val ueID == CSSValueMenu
160 || (quirksMode && valueID >= CSSValueWebkitFocusRingColor && valueID < C SSValueWebkitText)) {
161 validPrimitive = true;
162 }
163
164 if (validPrimitive)
165 return cssValuePool().createIdentifierValue(valueID); 464 return cssValuePool().createIdentifierValue(valueID);
166 465
167 RGBA32 color; 466 RGBA32 color;
168 if (!CSSPropertyParser::fastParseColor(color, string, !quirksMode && string[ 0] != '#')) 467 if (!CSSParserFastPaths::parseColorAsRGBA32(color, string, quirksMode))
169 return nullptr; 468 return nullptr;
170 return cssValuePool().createColorValue(color); 469 return cssValuePool().createColorValue(color);
171 } 470 }
172 471
173 bool CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyID propertyId , CSSValueID valueID) 472 bool CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyID propertyId , CSSValueID valueID)
174 { 473 {
175 if (valueID == CSSValueInvalid) 474 if (valueID == CSSValueInvalid)
176 return false; 475 return false;
177 476
178 switch (propertyId) { 477 switch (propertyId) {
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 } 952 }
654 const UChar* pos = string.characters16(); 953 const UChar* pos = string.characters16();
655 const UChar* end = pos + string.length(); 954 const UChar* end = pos + string.length();
656 return parseSimpleTransformList(pos, end); 955 return parseSimpleTransformList(pos, end);
657 } 956 }
658 957
659 PassRefPtrWillBeRawPtr<CSSValue> CSSParserFastPaths::maybeParseValue(CSSProperty ID propertyID, const String& string, CSSParserMode parserMode) 958 PassRefPtrWillBeRawPtr<CSSValue> CSSParserFastPaths::maybeParseValue(CSSProperty ID propertyID, const String& string, CSSParserMode parserMode)
660 { 959 {
661 if (RefPtrWillBeRawPtr<CSSValue> length = parseSimpleLengthValue(propertyID, string, parserMode)) 960 if (RefPtrWillBeRawPtr<CSSValue> length = parseSimpleLengthValue(propertyID, string, parserMode))
662 return length.release(); 961 return length.release();
663 if (RefPtrWillBeRawPtr<CSSValue> color = parseColorValue(propertyID, string, parserMode)) 962 if (isColorPropertyID(propertyID))
664 return color.release(); 963 return parseColor(string, isQuirksModeBehavior(parserMode));
665 if (RefPtrWillBeRawPtr<CSSValue> keyword = parseKeywordValue(propertyID, str ing)) 964 if (RefPtrWillBeRawPtr<CSSValue> keyword = parseKeywordValue(propertyID, str ing))
666 return keyword.release(); 965 return keyword.release();
667 if (RefPtrWillBeRawPtr<CSSValue> transform = parseSimpleTransform(propertyID , string)) 966 if (RefPtrWillBeRawPtr<CSSValue> transform = parseSimpleTransform(propertyID , string))
668 return transform.release(); 967 return transform.release();
669 return nullptr; 968 return nullptr;
670 } 969 }
671 970
672 } // namespace blink 971 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698