Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |