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

Side by Side 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: s/FAST_ALLOCATED/FAST_MALLOC/ Created 5 years, 1 month 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "core/css/resolver/CSSVariableResolver.h"
7
8 #include "core/CSSPropertyNames.h"
9 #include "core/CSSValueKeywords.h"
10 #include "core/StyleBuilderFunctions.h"
11 #include "core/css/CSSVariableData.h"
12 #include "core/css/CSSVariableReferenceValue.h"
13 #include "core/css/parser/CSSParserToken.h"
14 #include "core/css/parser/CSSParserTokenRange.h"
15 #include "core/css/parser/CSSParserValues.h"
16 #include "core/css/parser/CSSPropertyParser.h"
17 #include "core/css/resolver/StyleBuilder.h"
18 #include "core/css/resolver/StyleResolverState.h"
19 #include "core/style/StyleVariableData.h"
20 #include "wtf/Vector.h"
21
22 namespace blink {
23
24 // TODO(leviw): This should take a CSSParserTokenRange
25 static void findendIndexOfVariableReference(const Vector<CSSParserToken>& resolv edTokens, unsigned startIndex, unsigned& endIndex, unsigned& commaIndex, bool& h asClosingBracket)
Timothy Loh 2015/11/02 07:28:48 err.. findend -> findEnd?
26 {
27 endIndex = 0;
28 commaIndex = 0;
29 unsigned bracketCount = 1;
30 for (unsigned i = startIndex; i < resolvedTokens.size(); ++i) {
31 CSSParserTokenType type = resolvedTokens[i].type();
32
33 if (type == CommaToken && !commaIndex) {
34 commaIndex = i;
35 } else if (type == LeftParenthesisToken || type == FunctionToken) {
36 bracketCount++;
37 } else if (type == RightParenthesisToken) {
38 if (bracketCount == 1) {
39 hasClosingBracket = true;
40 endIndex = i;
41 break;
Timothy Loh 2015/11/02 07:28:48 probably just return here and remove the if check
42 }
43 bracketCount--;
44 }
45 }
46 if (!endIndex) {
47 hasClosingBracket = false;
48 endIndex = resolvedTokens.size() - 1;
49 }
50 }
51
52 unsigned CSSVariableResolver::resolveVariableTokensRecursive(Vector<CSSParserTok en>& resolvedTokens, unsigned startIndex)
53 {
54 unsigned variableLocation = startIndex;
55 while (resolvedTokens[variableLocation].type() != IdentToken)
56 variableLocation++;
57
58 unsigned commaIndex;
59 unsigned endIndex;
60 bool hasClosingBracket;
61 // Find default value and match braces
62 findendIndexOfVariableReference(resolvedTokens, variableLocation + 1, endInd ex, commaIndex, hasClosingBracket);
63
64 unsigned length = endIndex - startIndex + 1;
65 unsigned varFunctionPosition = startIndex;
66
67 AtomicString variableName = resolvedTokens[variableLocation].value();
68
69 if (m_variablesSeen.contains(variableName)) {
70 m_cycleDetected = true;
71 resolvedTokens.clear();
72 return 0;
73 }
74
75 CSSVariableData* variableData = m_styleVariableData ? m_styleVariableData->g etVariable(variableName) : nullptr;
76 if (variableData) {
77 Vector<CSSParserToken> tokens(variableData->tokens());
78 if (variableData->needsVariableResolution()) {
79 m_variablesSeen.add(variableName);
80 resolveVariableReferencesFromTokens(tokens);
81 m_variablesSeen.remove(variableName);
82
83 // The old variable data holds onto the backing string the new resol ved CSSVariableData
84 // relies on. Ensure it will live beyond us overwriting the RefPtr i n StyleVariableData.
85 ASSERT(variableData->refCount() > 1);
86
87 m_styleVariableData->setVariable(variableName, CSSVariableData::crea teResolved(tokens));
88 }
89 if (tokens.size()) {
90 resolvedTokens.remove(startIndex, length);
91 resolvedTokens.insert(startIndex, tokens);
92 return tokens.size();
93 }
94 }
95
96 // Fallback on default value if present
97 if (!commaIndex || m_cycleDetected) {
98 resolvedTokens.clear();
99 return 0;
100 }
101
102 // Move the tokens to the beginning of the variable reference
103 unsigned defaultValueStart = commaIndex + 1;
104 unsigned defaultValueLength = endIndex - commaIndex - (hasClosingBracket ? 1 : 0);
105 for (unsigned i = 0; i < defaultValueLength; ++i)
106 resolvedTokens[varFunctionPosition + i] = resolvedTokens[defaultValueSta rt + i];
107 resolvedTokens.remove(varFunctionPosition + defaultValueLength, length - def aultValueLength);
108
109 resolveVariableReferencesFromTokens(resolvedTokens);
110
111 return resolvedTokens.size();
112 }
113
114 void CSSVariableResolver::resolveVariableReferencesFromTokens(Vector<CSSParserTo ken>& tokens)
115 {
116 for (unsigned i = 0; i < tokens.size(); ++i) {
117 if (tokens[i].functionId() == CSSValueVar) {
118 unsigned validTokens = resolveVariableTokensRecursive(tokens, i);
119 if (validTokens < 1 || m_cycleDetected) {
120 tokens.clear();
121 break;
122 }
123 i += validTokens - 1;
124 }
125 }
126 }
127
128 void CSSVariableResolver::resolveAndApplyVariableReferences(StyleResolverState& state, CSSPropertyID id, const CSSVariableReferenceValue& value)
129 {
130 // TODO(leviw): This should be a stack
131 Vector<CSSParserToken> tokens = value.variableDataValue()->tokens();
132
133 CSSVariableResolver resolver(state.style()->variables());
134
135 resolver.resolveVariableReferencesFromTokens(tokens);
136
137 if (!tokens.size())
138 return;
139
140 CSSParserContext context(HTMLStandardMode, 0);
141
142 WillBeHeapVector<CSSProperty, 256> parsedProperties;
143
144 CSSPropertyParser::parseValue(id, false, CSSParserTokenRange(tokens), contex t, parsedProperties, StyleRule::Type::Style);
145
146 unsigned parsedPropertiesCount = parsedProperties.size();
147 for (unsigned i = 0; i < parsedPropertiesCount; ++i)
148 StyleBuilder::applyProperty(parsedProperties[i].id(), state, parsedPrope rties[i].value());
149 }
150
151 void CSSVariableResolver::resolveVariableDefinitions(StyleVariableData* variable s)
152 {
153 if (!variables)
154 return;
155
156 for (auto& variable : variables->m_data) {
157 if (!variable.value->needsVariableResolution())
158 continue;
159 Vector<CSSParserToken> resolvedTokens(variable.value->tokens());
160
161 CSSVariableResolver resolver(variables, variable.key);
162 resolver.resolveVariableReferencesFromTokens(resolvedTokens);
163
164 variable.value = CSSVariableData::createResolved(resolvedTokens);
165 }
166 }
167
168 CSSVariableResolver::CSSVariableResolver(StyleVariableData* styleVariableData)
169 : m_styleVariableData(styleVariableData)
170 , m_cycleDetected(false)
171 {
172 }
173
174 CSSVariableResolver::CSSVariableResolver(StyleVariableData* styleVariableData, A tomicString& variable)
175 : m_styleVariableData(styleVariableData)
176 , m_cycleDetected(false)
177 {
178 m_variablesSeen.add(variable);
179 }
180
181 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698