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..230a7b26965224b430387c2dddcde7e6041403ac |
--- /dev/null |
+++ b/Source/core/css/parser/CSSVariableParser.cpp |
@@ -0,0 +1,214 @@ |
+// 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/CSSCustomVariableValue.h" |
+#include "core/css/parser/CSSParserTokenRange.h" |
+#include "core/css/parser/CSSParserValues.h" |
+ |
+namespace blink { |
+ |
+static bool isValidVariableName(const CSSParserToken& token) |
+{ |
Timothy Loh
2015/08/25 09:21:10
Probably a good idea to check the token type is an
|
+ CSSParserString value = token.value(); |
+ return value.length() >= 2 && value[0] == '-' && value[0] == value[1]; |
Timothy Loh
2015/08/25 09:21:11
err.. value[1] == '-'?
|
+} |
+ |
+static bool isValidVariableReference(CSSParserTokenRange& range) |
Timothy Loh
2015/08/25 09:21:10
Use consumeBlock in the calling function and make
|
+{ |
+ bool foundVariableIdentToken = false; |
+ bool foundComma = false; |
+ bool contentAfterComma = false; |
+ |
+ // TODO(leviw): Use CSSParserToken::BlockType signals instead of checking for these directly. |
+ int parenthesisCount = 0; |
+ int braceCount = 0; |
+ int bracketCount = 0; |
+ while (!range.atEnd()) { |
+ const CSSParserToken& token = range.consume(); |
+ |
+ if (!foundVariableIdentToken) { |
Timothy Loh
2015/08/25 09:21:10
This would be easier without the state machine loo
|
+ if (token.type() == IdentToken) { |
+ if (!isValidVariableName(token)) |
+ return false; |
+ foundVariableIdentToken = true; |
+ } else if (token.type() != WhitespaceToken) { |
+ return false; |
+ } |
+ continue; |
+ } |
+ |
+ if (!foundComma) { |
+ if (token.type() == CommaToken) |
+ foundComma = true; |
+ else if (token.type() == RightParenthesisToken) |
+ return true; |
+ else if (token.type() != WhitespaceToken) |
+ return false; |
+ continue; |
+ } |
+ |
+ if (!contentAfterComma) { |
+ if (token.type() == RightParenthesisToken) |
+ return false; |
+ contentAfterComma = true; |
+ } |
+ |
+ switch (token.type()) { |
+ case DelimiterToken: |
+ if (token.delimiter() == '!' && !parenthesisCount && !bracketCount && !braceCount) |
+ return false; |
+ break; |
+ case FunctionToken: |
+ case LeftParenthesisToken: |
+ parenthesisCount++; |
+ break; |
+ case RightParenthesisToken: |
+ if (!parenthesisCount) |
+ return true; |
+ parenthesisCount--; |
+ break; |
+ case RightBraceToken: |
+ if (!braceCount) |
+ return false; |
+ braceCount--; |
+ break; |
+ case LeftBraceToken: |
+ braceCount++; |
+ break; |
+ case RightBracketToken: |
+ if (!bracketCount) |
+ return false; |
+ bracketCount--; |
+ break; |
+ case LeftBracketToken: |
+ bracketCount++; |
+ break; |
+ case BadStringToken: |
+ case BadUrlToken: |
+ return false; |
+ case CommentToken: |
+ case EOFToken: |
+ ASSERT_NOT_REACHED(); |
+ case SemicolonToken: |
+ if (!parenthesisCount && !bracketCount && !braceCount) |
+ return false; |
+ break; |
+ default: |
+ break; |
+ } |
+ } |
+ return foundVariableIdentToken && (!foundComma || contentAfterComma); |
+} |
+ |
+static CSSValueID classifyVariableRange(CSSParserTokenRange& originalRange, bool& hasReferences) |
Timothy Loh
2015/08/25 09:21:11
CSSParserTokenRange& originalRange -> CSSParserTok
|
+{ |
+ hasReferences = false; |
+ CSSParserTokenRange range = originalRange; |
+ |
+ int parenthesisCount = 0; |
+ int braceCount = 0; |
+ int bracketCount = 0; |
+ |
+ range.consumeWhitespace(); |
+ if (range.peek().type() == IdentToken) { |
+ const CSSParserToken& ident = range.consumeIncludingWhitespace(); |
+ if (range.atEnd()) { |
+ if (ident.valueEqualsIgnoringCase("inherit")) |
+ return CSSValueInherit; |
+ if (ident.valueEqualsIgnoringCase("initial")) |
+ return CSSValueInitial; |
+ if (ident.valueEqualsIgnoringCase("unset")) |
+ return CSSValueUnset; |
+ } |
+ } |
+ |
+ // TODO(leviw): Use consumeBlock to keep track of nesting instead of doing it directly here. |
+ while (!range.atEnd()) { |
+ const CSSParserToken& token = range.consume(); |
+ switch (token.type()) { |
+ case FunctionToken: |
+ if (token.valueEqualsIgnoringCase("var")) { |
+ if (!isValidVariableReference(range)) |
+ return CSSValueInvalid; // Bail if any references are invalid |
+ hasReferences = true; |
+ } else { |
+ parenthesisCount++; |
+ } |
+ break; |
+ case CommentToken: |
+ case EOFToken: |
+ ASSERT_NOT_REACHED(); |
+ case DelimiterToken: { |
+ if (token.delimiter() == '!' && !parenthesisCount && !bracketCount && !braceCount) |
+ return CSSValueInvalid; |
+ break; |
+ } |
+ case RightParenthesisToken: |
+ if (!parenthesisCount) |
+ return CSSValueInvalid; |
+ parenthesisCount--; |
+ break; |
+ case LeftParenthesisToken: |
+ parenthesisCount++; |
+ break; |
+ case RightBraceToken: |
+ if (!braceCount) |
+ return CSSValueInvalid; |
+ braceCount--; |
+ break; |
+ case LeftBraceToken: |
+ braceCount++; |
+ break; |
+ case RightBracketToken: |
+ if (!bracketCount) |
+ return CSSValueInvalid; |
+ bracketCount--; |
+ break; |
+ case LeftBracketToken: |
+ bracketCount++; |
+ break; |
+ case BadStringToken: |
+ case BadUrlToken: |
+ return CSSValueInvalid; |
+ case WhitespaceToken: |
+ break; |
+ case SemicolonToken: |
+ if (!parenthesisCount && !bracketCount && !braceCount) |
+ return CSSValueInvalid; |
+ default: |
+ break; |
+ } |
+ } |
+ if (parenthesisCount) |
+ return CSSValueInvalid; |
+ return CSSValueInternalVariableValue; |
+} |
+ |
+bool CSSVariableParser::containsValidVariableReferences(const CSSParserTokenRange& originalRange) |
Timothy Loh
2015/08/25 09:21:10
CSSParserTokenRange& originalRange -> CSSParserTok
|
+{ |
+ CSSParserTokenRange range = originalRange; |
+ bool hasReferences; |
+ CSSValueID type = classifyVariableRange(range, hasReferences); |
+ return type == CSSValueInternalVariableValue && hasReferences; |
+} |
+ |
+PassRefPtrWillBeRawPtr<CSSCustomVariableValue> CSSVariableParser::parseDeclarationValue(const AtomicString& variableName, CSSParserTokenRange& originalRange) |
Timothy Loh
2015/08/25 09:21:11
CSSParserTokenRange& originalRange -> CSSParserTok
|
+{ |
+ if (originalRange.atEnd()) |
+ return nullptr; |
+ |
+ bool hasReferences; |
+ CSSValueID type = classifyVariableRange(originalRange, hasReferences); |
+ |
+ if (type == CSSValueInvalid) |
+ return nullptr; |
+ if (type == CSSValueInternalVariableValue) |
+ return CSSCustomVariableValue::create(variableName, CSSVariableData::create(originalRange, hasReferences)); |
+ return CSSCustomVariableValue::create(variableName, type); |
+} |
+ |
+} // namespace blink |