Index: Source/core/css/parser/CSSParserValues.cpp |
diff --git a/Source/core/css/parser/CSSParserValues.cpp b/Source/core/css/parser/CSSParserValues.cpp |
index 039e70bc66c8316a9d6b117e5f21abdc72476df7..3392bc709aea306138dc2fa08862c1ca52ac17fa 100644 |
--- a/Source/core/css/parser/CSSParserValues.cpp |
+++ b/Source/core/css/parser/CSSParserValues.cpp |
@@ -23,19 +23,48 @@ |
#include "core/css/CSSFunctionValue.h" |
#include "core/css/CSSSelectorList.h" |
+#include "core/css/CSSVariableData.h" |
#include "core/css/parser/CSSParserToken.h" |
#include "core/css/parser/CSSParserTokenRange.h" |
#include "core/css/parser/CSSPropertyParser.h" |
+#include "core/css/parser/CSSTokenizer.h" |
+#include "core/css/parser/CSSVariableParser.h" |
#include "core/html/parser/HTMLParserIdioms.h" |
+#include "wtf/text/StringBuilder.h" |
namespace blink { |
using namespace WTF; |
+struct SameSizeAsCSSParserValue { |
+ CSSValueID id; |
+ CSSParserString valueUnion; |
+ int unit; |
+}; |
+ |
+static_assert(sizeof(CSSParserValue) == sizeof(SameSizeAsCSSParserValue), "CSSParserValue should stay small"); |
+ |
CSSParserValueList::CSSParserValueList(CSSParserTokenRange range, bool& usesRemUnits) |
: m_current(0) |
{ |
+ init(range, usesRemUnits); |
+} |
+ |
+CSSParserValueList::CSSParserValueList(CSSParserTokenRange range, const String& string, bool& usesRemUnits, bool& usesVariables) |
+: m_current(0) |
+{ |
+ init(range, usesRemUnits, &usesVariables, &string); |
+} |
+ |
+void CSSParserValueList::init(CSSParserTokenRange range, bool& usesRemUnits, bool* usesVariables, const String* string) |
+{ |
+ CSSParserTokenRange originalRangeForVariables = range; |
+ |
usesRemUnits = false; |
+ if (usesVariables) { |
+ ASSERT(string); |
+ *usesVariables = false; |
+ } |
Vector<CSSParserValueList*> stack; |
Vector<int> bracketCounts; |
stack.append(this); |
@@ -51,7 +80,8 @@ CSSParserValueList::CSSParserValueList(CSSParserTokenRange range, bool& usesRemU |
if (token.valueEqualsIgnoringCase("url")) { |
const CSSParserToken& next = range.consumeIncludingWhitespace(); |
if (next.type() == BadStringToken || range.consume().type() != RightParenthesisToken) { |
- destroyAndClear(); |
+ if (usesVariables) |
+ checkForVariableReferencesOrDestroyAndClear(originalRangeForVariables, *string); |
return; |
} |
ASSERT(next.type() == StringToken); |
@@ -60,6 +90,10 @@ CSSParserValueList::CSSParserValueList(CSSParserTokenRange range, bool& usesRemU |
value.unit = CSSPrimitiveValue::CSS_URI; |
value.string = next.value(); |
break; |
+ } else if (token.valueEqualsIgnoringCase("var")) { |
+ if (usesVariables) |
+ checkForVariableReferencesOrDestroyAndClear(originalRangeForVariables, *string); |
+ return; |
} |
CSSParserFunction* function = new CSSParserFunction; |
@@ -76,6 +110,8 @@ CSSParserValueList::CSSParserValueList(CSSParserTokenRange range, bool& usesRemU |
stack.append(list); |
bracketCounts.append(0); |
calcDepth += (function->id == CSSValueCalc || function->id == CSSValueWebkitCalc); |
+ if (function->id == CSSValueVar && usesVariables) |
+ *usesVariables = true; |
continue; |
} |
case LeftParenthesisToken: { |
@@ -96,7 +132,8 @@ CSSParserValueList::CSSParserValueList(CSSParserTokenRange range, bool& usesRemU |
stack.removeLast(); |
bracketCounts.removeLast(); |
if (bracketCounts.isEmpty()) { |
- destroyAndClear(); |
+ if (usesVariables) |
+ checkForVariableReferencesOrDestroyAndClear(originalRangeForVariables, *string); |
return; |
} |
CSSParserValueList* currentList = stack.last(); |
@@ -181,7 +218,8 @@ CSSParserValueList::CSSParserValueList(CSSParserTokenRange range, bool& usesRemU |
value.setFromOperator(token.delimiter()); |
if (calcDepth && token.delimiter() == '+' && (&token - 1)->type() != WhitespaceToken) { |
// calc(1px+ 2px) is invalid |
- destroyAndClear(); |
+ if (usesVariables) |
+ checkForVariableReferencesOrDestroyAndClear(originalRangeForVariables, *string); |
return; |
} |
break; |
@@ -245,9 +283,30 @@ static void destroy(Vector<CSSParserValue, 4>& values) |
else if (values[i].unit == CSSParserValue::ValueList |
|| values[i].unit == CSSParserValue::DimensionList) |
delete values[i].valueList; |
+ else if (values[i].unit == CSSParserValue::VariableValue) |
+ values[i].variableData->deref(); |
} |
} |
+void CSSParserValueList::checkForVariableReferencesOrDestroyAndClear(const CSSParserTokenRange& originalRange, const String& string) |
+{ |
+ // We have to clear any state that may have been previously loaded |
+ destroyAndClear(); |
+ if (CSSVariableParser::containsValidVariableReferences(originalRange)) |
+ consumeVariableValue(originalRange, string); |
+} |
+ |
+void CSSParserValueList::consumeVariableValue(const CSSParserTokenRange& originalRange, const String& string) |
+{ |
+ ASSERT(m_values.isEmpty()); |
+ CSSParserValue variableValue; |
+ variableValue.id = CSSValueInternalVariableValue; |
+ variableValue.isInt = false; |
+ variableValue.unit = CSSParserValue::VariableValue; |
+ variableValue.variableData = CSSVariableData::create(originalRange, string).leakRef(); |
+ addValue(variableValue); |
+} |
+ |
void CSSParserValueList::destroyAndClear() |
{ |
destroy(m_values); |