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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: Source/core/css/parser/CSSParserFastPaths.cpp
diff --git a/Source/core/css/parser/CSSParserFastPaths.cpp b/Source/core/css/parser/CSSParserFastPaths.cpp
index 85143c11097a2e08d49ada99964fea49d4d9bfc8..caa105f12a68d330a705e923159308a5a1dc6585 100644
--- a/Source/core/css/parser/CSSParserFastPaths.cpp
+++ b/Source/core/css/parser/CSSParserFastPaths.cpp
@@ -11,6 +11,7 @@
#include "core/css/parser/CSSParserIdioms.h"
#include "core/css/parser/CSSParserValues.h"
#include "core/css/parser/CSSPropertyParser.h"
+#include "core/html/parser/HTMLParserIdioms.h"
#include "platform/RuntimeEnabledFeatures.h"
namespace blink {
@@ -142,30 +143,328 @@ static inline bool isColorPropertyID(CSSPropertyID propertyId)
}
}
-static PassRefPtrWillBeRawPtr<CSSValue> parseColorValue(CSSPropertyID propertyId, const String& string, CSSParserMode cssParserMode)
+// Returns the number of characters which form a valid double
+// and are terminated by the given terminator character
+template <typename CharacterType>
+static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator)
+{
+ int length = end - string;
+ if (length < 1)
+ return 0;
+
+ bool decimalMarkSeen = false;
+ int processedLength = 0;
+
+ for (int i = 0; i < length; ++i) {
+ if (string[i] == terminator) {
+ processedLength = i;
+ break;
+ }
+ if (!isASCIIDigit(string[i])) {
+ if (!decimalMarkSeen && string[i] == '.')
+ decimalMarkSeen = true;
+ else
+ return 0;
+ }
+ }
+
+ if (decimalMarkSeen && processedLength == 1)
+ return 0;
+
+ return processedLength;
+}
+
+// Returns the number of characters consumed for parsing a valid double
+// terminated by the given terminator character
+template <typename CharacterType>
+static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value)
+{
+ int length = checkForValidDouble(string, end, terminator);
+ if (!length)
+ return 0;
+
+ int position = 0;
+ double localValue = 0;
+
+ // The consumed characters here are guaranteed to be
+ // ASCII digits with or without a decimal mark
+ for (; position < length; ++position) {
+ if (string[position] == '.')
+ break;
+ localValue = localValue * 10 + string[position] - '0';
+ }
+
+ if (++position == length) {
+ value = localValue;
+ return length;
+ }
+
+ double fraction = 0;
+ double scale = 1;
+
+ const double maxScale = 1000000;
+ while (position < length && scale < maxScale) {
+ fraction = fraction * 10 + string[position++] - '0';
+ scale *= 10;
+ }
+
+ value = localValue + fraction / scale;
+ return length;
+}
+
+template <typename CharacterType>
+static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitType& expect, int& value)
+{
+ const CharacterType* current = string;
+ double localValue = 0;
+ bool negative = false;
+ while (current != end && isHTMLSpace<CharacterType>(*current))
+ current++;
+ if (current != end && *current == '-') {
+ negative = true;
+ current++;
+ }
+ if (current == end || !isASCIIDigit(*current))
+ return false;
+ while (current != end && isASCIIDigit(*current)) {
+ double newValue = localValue * 10 + *current++ - '0';
+ if (newValue >= 255) {
+ // Clamp values at 255.
+ localValue = 255;
+ while (current != end && isASCIIDigit(*current))
+ ++current;
+ break;
+ }
+ localValue = newValue;
+ }
+
+ if (current == end)
+ return false;
+
+ if (expect == CSSPrimitiveValue::CSS_NUMBER && (*current == '.' || *current == '%'))
+ return false;
+
+ if (*current == '.') {
+ // We already parsed the integral part, try to parse
+ // the fraction part of the percentage value.
+ double percentage = 0;
+ int numCharactersParsed = parseDouble(current, end, '%', percentage);
+ if (!numCharactersParsed)
+ return false;
+ current += numCharactersParsed;
+ if (*current != '%')
+ return false;
+ localValue += percentage;
+ }
+
+ if (expect == CSSPrimitiveValue::CSS_PERCENTAGE && *current != '%')
+ return false;
+
+ if (*current == '%') {
+ expect = CSSPrimitiveValue::CSS_PERCENTAGE;
+ localValue = localValue / 100.0 * 256.0;
+ // Clamp values at 255 for percentages over 100%
+ if (localValue > 255)
+ localValue = 255;
+ current++;
+ } else {
+ expect = CSSPrimitiveValue::CSS_NUMBER;
+ }
+
+ while (current != end && isHTMLSpace<CharacterType>(*current))
+ current++;
+ if (current == end || *current++ != terminator)
+ return false;
+ // Clamp negative values at zero.
+ value = negative ? 0 : static_cast<int>(localValue);
+ string = current;
+ return true;
+}
+
+template <typename CharacterType>
+static inline bool isTenthAlpha(const CharacterType* string, const int length)
+{
+ // "0.X"
+ if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2]))
+ return true;
+
+ // ".X"
+ if (length == 2 && string[0] == '.' && isASCIIDigit(string[1]))
+ return true;
+
+ return false;
+}
+
+template <typename CharacterType>
+static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value)
+{
+ while (string != end && isHTMLSpace<CharacterType>(*string))
+ string++;
+
+ bool negative = false;
+
+ if (string != end && *string == '-') {
+ negative = true;
+ string++;
+ }
+
+ value = 0;
+
+ int length = end - string;
+ if (length < 2)
+ return false;
+
+ if (string[length - 1] != terminator || !isASCIIDigit(string[length - 2]))
+ return false;
+
+ if (string[0] != '0' && string[0] != '1' && string[0] != '.') {
+ if (checkForValidDouble(string, end, terminator)) {
+ value = negative ? 0 : 255;
+ string = end;
+ return true;
+ }
+ return false;
+ }
+
+ if (length == 2 && string[0] != '.') {
+ value = !negative && string[0] == '1' ? 255 : 0;
+ string = end;
+ return true;
+ }
+
+ if (isTenthAlpha(string, length - 1)) {
+ static const int tenthAlphaValues[] = { 0, 25, 51, 76, 102, 127, 153, 179, 204, 230 };
+ value = negative ? 0 : tenthAlphaValues[string[length - 2] - '0'];
+ string = end;
+ return true;
+ }
+
+ double alpha = 0;
+ if (!parseDouble(string, end, terminator, alpha))
+ return false;
+ value = negative ? 0 : static_cast<int>(alpha * nextafter(256.0, 0.0));
+ string = end;
+ return true;
+}
+
+template <typename CharacterType>
+static inline bool mightBeRGBA(const CharacterType* characters, unsigned length)
+{
+ if (length < 5)
+ return false;
+ return characters[4] == '('
+ && isASCIIAlphaCaselessEqual(characters[0], 'r')
+ && isASCIIAlphaCaselessEqual(characters[1], 'g')
+ && isASCIIAlphaCaselessEqual(characters[2], 'b')
+ && isASCIIAlphaCaselessEqual(characters[3], 'a');
+}
+
+template <typename CharacterType>
+static inline bool mightBeRGB(const CharacterType* characters, unsigned length)
+{
+ if (length < 4)
+ return false;
+ return characters[3] == '('
+ && isASCIIAlphaCaselessEqual(characters[0], 'r')
+ && isASCIIAlphaCaselessEqual(characters[1], 'g')
+ && isASCIIAlphaCaselessEqual(characters[2], 'b');
+}
+
+template <typename CharacterType>
+static bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length, bool quirksMode)
alancutter (OOO until 2018) 2015/06/10 00:31:20 parseRGBA32Internal()?
+{
+ CSSPrimitiveValue::UnitType expect = CSSPrimitiveValue::CSS_UNKNOWN;
+
+ if (length >= 4 && characters[0] == '#')
+ return Color::parseHexColor(characters + 1, length - 1, rgb);
+
+ if (quirksMode && length >= 3) {
+ if (Color::parseHexColor(characters, length, rgb))
+ return true;
+ }
+
+ // Try rgba() syntax.
+ if (mightBeRGBA(characters, length)) {
+ const CharacterType* current = characters + 5;
+ const CharacterType* end = characters + length;
+ int red;
+ int green;
+ int blue;
+ int alpha;
+
+ if (!parseColorIntOrPercentage(current, end, ',', expect, red))
+ return false;
+ if (!parseColorIntOrPercentage(current, end, ',', expect, green))
+ return false;
+ if (!parseColorIntOrPercentage(current, end, ',', expect, blue))
+ return false;
+ if (!parseAlphaValue(current, end, ')', alpha))
+ return false;
+ if (current != end)
+ return false;
+ rgb = makeRGBA(red, green, blue, alpha);
+ return true;
+ }
+
+ // Try rgb() syntax.
+ if (mightBeRGB(characters, length)) {
+ const CharacterType* current = characters + 4;
+ const CharacterType* end = characters + length;
+ int red;
+ int green;
+ int blue;
+ if (!parseColorIntOrPercentage(current, end, ',', expect, red))
+ return false;
+ if (!parseColorIntOrPercentage(current, end, ',', expect, green))
+ return false;
+ if (!parseColorIntOrPercentage(current, end, ')', expect, blue))
+ return false;
+ if (current != end)
+ return false;
+ rgb = makeRGB(red, green, blue);
+ return true;
+ }
+
+ return false;
+}
+
+bool CSSParserFastPaths::parseColorAsRGBA32(RGBA32& rgb, const String& name, bool quirksMode)
+{
+ unsigned length = name.length();
+ bool parseResult;
+
+ if (!length)
+ return false;
+
+ if (name.is8Bit())
+ parseResult = fastParseColorInternal(rgb, name.characters8(), length, quirksMode);
+ else
+ parseResult = fastParseColorInternal(rgb, name.characters16(), length, quirksMode);
+
+ if (parseResult)
+ return true;
+
+ // Try named colors.
+ Color tc;
+ if (!tc.setNamedColor(name))
+ return false;
+ rgb = tc.rgb();
+ return true;
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> parseColor(const String& string, bool quirksMode)
{
ASSERT(!string.isEmpty());
- bool quirksMode = isQuirksModeBehavior(cssParserMode);
- if (!isColorPropertyID(propertyId))
- return nullptr;
CSSParserString cssString;
cssString.init(string);
CSSValueID valueID = cssValueKeywordID(cssString);
- bool validPrimitive = false;
- if (valueID == CSSValueWebkitText) {
- validPrimitive = true;
- } else if (valueID == CSSValueCurrentcolor) {
- validPrimitive = true;
- } else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
- || (quirksMode && valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText)) {
- validPrimitive = true;
- }
-
- if (validPrimitive)
+ if (valueID == CSSValueWebkitText || valueID == CSSValueCurrentcolor
+ || (valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
+ || (quirksMode && valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText))
return cssValuePool().createIdentifierValue(valueID);
RGBA32 color;
- if (!CSSPropertyParser::fastParseColor(color, string, !quirksMode && string[0] != '#'))
+ if (!CSSParserFastPaths::parseColorAsRGBA32(color, string, quirksMode))
return nullptr;
return cssValuePool().createColorValue(color);
}
@@ -660,8 +959,8 @@ PassRefPtrWillBeRawPtr<CSSValue> CSSParserFastPaths::maybeParseValue(CSSProperty
{
if (RefPtrWillBeRawPtr<CSSValue> length = parseSimpleLengthValue(propertyID, string, parserMode))
return length.release();
- if (RefPtrWillBeRawPtr<CSSValue> color = parseColorValue(propertyID, string, parserMode))
- return color.release();
+ if (isColorPropertyID(propertyID))
+ return parseColor(string, isQuirksModeBehavior(parserMode));
if (RefPtrWillBeRawPtr<CSSValue> keyword = parseKeywordValue(propertyID, string))
return keyword.release();
if (RefPtrWillBeRawPtr<CSSValue> transform = parseSimpleTransform(propertyID, string))

Powered by Google App Engine
This is Rietveld 408576698