Index: Source/core/css/parser/CSSVariableParser.cpp |
diff --git a/Source/core/css/parser/CSSVariableParser.cpp b/Source/core/css/parser/CSSVariableParser.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..96f58449be8ef8ae71f93cde7fee4511774d40cc |
--- /dev/null |
+++ b/Source/core/css/parser/CSSVariableParser.cpp |
@@ -0,0 +1,186 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "config.h" |
+#include "core/css/parser/CSSVariableParser.h" |
+ |
+#include "core/css/parser/CSSParserTokenRange.h" |
+#include "core/css/parser/CSSParserValues.h" |
+ |
+namespace blink { |
+ |
+static bool isValidVariableName(const CSSParserToken& token) |
+{ |
+ CSSParserString value = token.value(); |
+ return value.length() >= 2 && value[0] == '-' && value[0] == value[1]; |
+} |
+ |
+static bool isValidVariableReference(CSSParserTokenRange& range) |
+{ |
+ bool foundVariableIdentToken = false; |
+ bool foundComma = false; |
+ bool contentAfterComma = false; |
+ unsigned bracketCount = 0; |
+ while (!range.atEnd()) { |
+ const CSSParserToken& token = range.consume(); |
+ switch (token.type()) { |
+ case WhitespaceToken: |
+ if (foundComma) |
+ contentAfterComma = true; |
+ break; |
+ case IdentToken: |
+ if (foundComma) { |
+ contentAfterComma = true; |
+ } else if (!foundVariableIdentToken) { |
+ if (!isValidVariableName(token)) |
+ return false; |
+ foundVariableIdentToken = true; |
+ } else { |
+ return false; |
+ } |
+ break; |
+ case FunctionToken: |
+ case LeftParenthesisToken: |
+ if (!foundComma) |
+ return false; |
+ bracketCount++; |
+ break; |
+ case RightParenthesisToken: |
+ if (!foundVariableIdentToken) |
+ return false; |
+ if (!bracketCount) |
+ return foundVariableIdentToken && (!foundComma || contentAfterComma); |
+ bracketCount--; |
+ break; |
+ case CommaToken: |
+ if (!foundVariableIdentToken) |
+ return false; |
+ foundComma = true; |
+ break; |
+ case CommentToken: |
+ case EOFToken: |
+ ASSERT_NOT_REACHED(); |
+ case SemicolonToken: |
+ return false; |
+ case CDOToken: |
+ case CDCToken: |
+ case AtKeywordToken: |
+ case IncludeMatchToken: |
+ case DashMatchToken: |
+ case PrefixMatchToken: |
+ case SuffixMatchToken: |
+ case SubstringMatchToken: |
+ case ColumnToken: |
+ case BadStringToken: |
+ case BadUrlToken: |
+ case ColonToken: |
+ // TODO(leviw): Need to match CDO/CDC tokens |
+ if (!foundComma) |
+ return false; |
+ break; |
+ default: |
+ if (!foundComma) |
+ return false; |
+ break; |
+ } |
+ } |
+ return false; |
+} |
+ |
+static CSSVariableParser::DefinitionType classifyVariableRange(const CSSParserTokenRange& originalRange, bool& important) |
+{ |
+ CSSParserTokenRange range = originalRange; |
+ CSSVariableParser::DefinitionType type = CSSVariableParser::Variable; |
+ bool lastTokenWasExclamation = false; |
+ |
+ // TODO(leviw): this needs to be a stack. |
+ bool foundImportant = false; |
+ |
+ int bracketCount = 0; |
+ |
Timothy Loh
2015/07/23 08:11:47
Probably something like:
range.consumeWhitespace(
|
+ while (!range.atEnd()) { |
+ const CSSParserToken& token = range.consume(); |
+ switch (token.type()) { |
+ case FunctionToken: |
+ if (token.valueEqualsIgnoringCase("var")) { |
+ if (!isValidVariableReference(range)) |
+ return CSSVariableParser::Invalid; // Bail if any references are invalid |
+ type = CSSVariableParser::VariableWithReferences; |
+ } else { |
+ bracketCount++; |
+ } |
+ lastTokenWasExclamation = false; |
+ break; |
+ case CommentToken: |
+ case EOFToken: |
+ ASSERT_NOT_REACHED(); |
+ case IdentToken: |
+ // TODO(leviw): This isn't correct. |
+ if (token.valueEqualsIgnoringCase("inherit")) { |
+ type = CSSVariableParser::Inherit; |
+ } else if (token.valueEqualsIgnoringCase("initial")) { |
+ type = CSSVariableParser::Initial; |
+ } else if (token.valueEqualsIgnoringCase("unset")) { |
+ type = CSSVariableParser::Unset; |
+ } else if (lastTokenWasExclamation && token.valueEqualsIgnoringCase("important")) { |
Timothy Loh
2015/07/23 08:11:47
Why does this need to handle !important when consu
|
+ if (foundImportant) |
+ return CSSVariableParser::Invalid; |
+ foundImportant = true; |
+ important = true; |
+ } |
+ lastTokenWasExclamation = false; |
+ break; |
+ case DelimiterToken: |
+ lastTokenWasExclamation = token.delimiter() == '!'; |
+ break; |
+ case RightParenthesisToken: |
+ if (!bracketCount) |
+ return CSSVariableParser::Invalid; |
+ bracketCount--; |
+ break; |
+ case LeftParenthesisToken: |
+ bracketCount++; |
+ break; |
+ case SemicolonToken: |
+ return CSSVariableParser::Invalid; |
+ case CDOToken: |
Timothy Loh
2015/07/23 08:11:47
The spec doesn't say these are invalid
|
+ case CDCToken: |
+ case AtKeywordToken: |
+ case IncludeMatchToken: |
+ case DashMatchToken: |
+ case PrefixMatchToken: |
+ case SuffixMatchToken: |
+ case SubstringMatchToken: |
+ case ColumnToken: |
+ case BadStringToken: |
+ case BadUrlToken: |
+ case ColonToken: |
+ return CSSVariableParser::Invalid; |
+ case WhitespaceToken: |
+ break; |
+ default: |
+ lastTokenWasExclamation = false; |
+ break; |
+ } |
+ } |
+ if (bracketCount) |
+ return CSSVariableParser::Invalid; |
+ return type; |
+} |
+ |
+bool CSSVariableParser::containsValidVariableReferences(const CSSParserTokenRange& originalRange) |
+{ |
+ bool important; |
+ return VariableWithReferences == classifyVariableRange(originalRange, important); |
+} |
+ |
+CSSVariableParser::DefinitionType CSSVariableParser::parseVariableDefinition(const CSSParserTokenRange& originalRange, bool& important) |
+{ |
+ important = false; |
+ if (originalRange.atEnd()) |
+ return CSSVariableParser::Invalid; |
+ return classifyVariableRange(originalRange, important); |
+} |
+ |
+} // namespace blink |