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

Unified Diff: third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp

Issue 1192983003: CSS Custom Properties (Variables) (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Remove reftest.list :( Created 5 years, 2 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: third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
diff --git a/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..68e6ebe293d8d74e0e3a98ee26e7b209fa885116
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/resolver/CSSVariableResolver.cpp
@@ -0,0 +1,181 @@
+// 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/resolver/CSSVariableResolver.h"
+
+#include "core/CSSPropertyNames.h"
+#include "core/CSSValueKeywords.h"
+#include "core/StyleBuilderFunctions.h"
+#include "core/css/CSSVariableData.h"
+#include "core/css/CSSVariableReferenceValue.h"
+#include "core/css/parser/CSSParserToken.h"
+#include "core/css/parser/CSSParserTokenRange.h"
+#include "core/css/parser/CSSParserValues.h"
+#include "core/css/parser/CSSPropertyParser.h"
+#include "core/css/resolver/StyleBuilder.h"
+#include "core/css/resolver/StyleResolverState.h"
+#include "core/style/StyleVariableData.h"
+#include "wtf/Vector.h"
+
+namespace blink {
+
+// TODO(leviw): This should take a CSSParserTokenRange
+static void findEndOfVariableReference(const Vector<CSSParserToken>& resolvedTokens, unsigned startOffset, unsigned& end, unsigned& commaLocation)
Timothy Loh 2015/10/28 05:12:41 Maybe startIndex, endIndex, commaIndex (as well as
leviw_travelin_and_unemployed 2015/10/30 21:41:16 Done.
+{
+ end = 0;
+ commaLocation = 0;
+ unsigned bracketCount = 0;
Timothy Loh 2015/10/28 05:12:41 imo, the logic below would be slightly clearer if
leviw_travelin_and_unemployed 2015/10/30 21:41:16 Done.
+ for (unsigned i = startOffset; i < resolvedTokens.size(); ++i) {
+ CSSParserTokenType type = resolvedTokens[i].type();
+
+ if (type == CommaToken && !commaLocation) {
+ commaLocation = i;
+ } else if (type == LeftParenthesisToken || type == FunctionToken) {
+ bracketCount++;
+ } else if (type == RightParenthesisToken) {
+ if (bracketCount) {
+ bracketCount--;
+ } else {
+ end = i;
+ break;
+ }
+ }
+ }
+ if (!end)
+ end = resolvedTokens.size() - 1;
+}
+
+unsigned CSSVariableResolver::resolveVariableTokensRecursive(Vector<CSSParserToken>& resolvedTokens, unsigned startOffset)
+{
+ ASSERT(startOffset);
+
+ unsigned commaLocation, end;
Timothy Loh 2015/10/28 05:12:41 I think Blink style is to have multiple variable d
leviw_travelin_and_unemployed 2015/10/30 21:41:16 Done.
+
+ // Find the variable location
+ unsigned variableLocation = 0;
Timothy Loh 2015/10/28 05:12:41 How about (we definitely have an ident, right?):
leviw_travelin_and_unemployed 2015/10/30 21:41:16 Done.
+ for (unsigned i = startOffset; i < resolvedTokens.size(); ++i) {
+ if (resolvedTokens[i].type() == IdentToken) {
+ variableLocation = i;
+ break;
+ }
+ }
+
+ // Find default value and match braces
+ findEndOfVariableReference(resolvedTokens, variableLocation + 1, end, commaLocation);
+
+ unsigned length = end - startOffset + 2;
Timothy Loh 2015/10/28 05:12:42 All the +1s and -1s are a bit hard to follow. This
leviw_travelin_and_unemployed 2015/10/30 21:41:16 Addressed.
+ unsigned varFunctionPosition = startOffset - 1;
+
+ AtomicString variableName = resolvedTokens[variableLocation].value();
+
+ if (m_variablesSeen.contains(variableName)) {
+ m_cycleDetected = true;
+ resolvedTokens.clear();
+ return 0;
+ }
+
+ CSSVariableData* variableData = m_styleVariableData ? m_styleVariableData->getVariable(variableName) : nullptr;
+ if (variableData) {
+ Vector<CSSParserToken> tokens(variableData->tokens());
+ if (variableData->needsVariableResolution()) {
+ m_variablesSeen.add(variableName);
+ resolveVariableReferencesFromTokens(tokens);
+ m_variablesSeen.remove(variableName);
+
+ m_styleVariableData->setVariable(variableName, CSSVariableData::createResolved(tokens));
+ }
+ if (tokens.size()) {
+ resolvedTokens.remove(startOffset - 1, length);
+ resolvedTokens.insert(startOffset - 1, tokens);
+ return tokens.size();
+ }
+ }
+
+ // Fallback on default value if present
+ if (!commaLocation || m_cycleDetected) {
+ resolvedTokens.clear();
+ return 0;
+ }
+
+ // Move the tokens to the beginning of the variable reference
+ unsigned defaultValueOffset = commaLocation + 1;
Timothy Loh 2015/10/28 05:12:41 defaultValueStart?
leviw_travelin_and_unemployed 2015/10/30 21:41:16 Sure :)
+ unsigned defaultValueLength = end - commaLocation - 1;
Timothy Loh 2015/10/28 05:12:42 end - defaultValueStart
+ for (unsigned i = 0; i < defaultValueLength; ++i)
+ resolvedTokens[varFunctionPosition + i] = resolvedTokens[defaultValueOffset + i];
+ resolvedTokens.remove(varFunctionPosition + defaultValueLength, length - defaultValueLength);
+
+ resolveVariableReferencesFromTokens(resolvedTokens);
+
+ return resolvedTokens.size();
+}
+
+void CSSVariableResolver::resolveVariableReferencesFromTokens(Vector<CSSParserToken>& tokens)
+{
+ for (unsigned i = 0; i < tokens.size(); ++i) {
+ if (tokens[i].functionId() == CSSValueVar) {
+ unsigned validTokens = resolveVariableTokensRecursive(tokens, i + 1);
+ if (validTokens < 1 || m_cycleDetected) {
+ tokens.clear();
+ break;
+ }
+ i += validTokens - 1;
+ }
+ }
+}
+
+void CSSVariableResolver::resolveAndApplyVariableReferences(StyleResolverState& state, CSSPropertyID id, const CSSVariableReferenceValue& value)
+{
+ // TODO(leviw): This should be a stack
+ Vector<CSSParserToken> tokens = value.variableDataValue()->tokens();
+
+ CSSVariableResolver resolver(state.style()->variables());
+
+ resolver.resolveVariableReferencesFromTokens(tokens);
+
+ if (!tokens.size())
+ return;
+
+ CSSParserContext context(HTMLStandardMode, 0);
+
+ WillBeHeapVector<CSSProperty, 256> parsedProperties;
+
+ CSSPropertyParser::parseValue(id, false, CSSParserTokenRange(tokens), context, parsedProperties, StyleRule::Type::Style);
+
+ unsigned parsedPropertiesCount = parsedProperties.size();
+ for (unsigned i = 0; i < parsedPropertiesCount; ++i)
+ StyleBuilder::applyProperty(parsedProperties[i].id(), state, parsedProperties[i].value());
+}
+
+void CSSVariableResolver::resolveVariableDefinitions(StyleVariableData* variables)
+{
+ if (!variables)
+ return;
+
+ for (auto& variable : variables->m_data) {
+ if (!variable.value->needsVariableResolution())
+ continue;
+ Vector<CSSParserToken> resolvedTokens(variable.value->tokens());
+
+ CSSVariableResolver resolver(variables, variable.key);
+ resolver.resolveVariableReferencesFromTokens(resolvedTokens);
+
+ variable.value = CSSVariableData::createResolved(resolvedTokens);
+ }
+}
+
+CSSVariableResolver::CSSVariableResolver(StyleVariableData* styleVariableData)
+ : m_styleVariableData(styleVariableData)
+ , m_cycleDetected(false)
+{
+}
+
+CSSVariableResolver::CSSVariableResolver(StyleVariableData* styleVariableData, AtomicString& variable)
+ : m_styleVariableData(styleVariableData)
+ , m_cycleDetected(false)
+{
+ m_variablesSeen.add(variable);
+}
+
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698