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

Side by Side Diff: Source/core/css/resolver/CSSVariableResolver.cpp

Issue 1192983003: CSS Custom Properties (Variables) (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Missing file :( Created 5 years, 4 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 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/parser/CSSParserToken.h"
13 #include "core/css/parser/CSSParserTokenRange.h"
14 #include "core/css/parser/CSSParserValues.h"
15 #include "core/css/parser/CSSPropertyParser.h"
16 #include "core/css/resolver/StyleResolverState.h"
17 #include "core/style/StyleVariableData.h"
18 #include "wtf/Vector.h"
19
20 namespace blink {
21
22 static bool isVariableReferenceToken(CSSParserToken& token)
23 {
24 return token.type() == FunctionToken && token.valueEqualsIgnoringCase("var") ;
25 }
26
27 static void findEndOfVariableReference(Vector<CSSParserToken>& resolvedTokens, u nsigned startOffset, unsigned& end, unsigned& commaLocation)
28 {
29 end = 0;
30 commaLocation = 0;
31 unsigned bracketCount = 0;
alancutter (OOO until 2018) 2015/08/05 08:01:43 If resolvedTokens was a CSSParserTokenRange you co
32 for (unsigned i = startOffset; i < resolvedTokens.size(); ++i) {
33 CSSParserTokenType type = resolvedTokens[i].type();
34
35 if (type == CommaToken && !commaLocation) {
36 commaLocation = i;
37 } else if (type == LeftParenthesisToken || type == FunctionToken) {
38 bracketCount++;
39 } else if (type == RightParenthesisToken) {
40 if (bracketCount) {
41 bracketCount--;
42 } else {
43 end = i;
44 break;
45 }
46 }
47 }
48 if (!end)
49 end = resolvedTokens.size() - 1;
50 }
51
52 unsigned CSSVariableResolver::resolveVariableTokensRecursive(Vector<CSSParserTok en>& resolvedTokens, unsigned startOffset)
53 {
54 ASSERT(startOffset);
55 // There should be at least 2 tokens after the start position: a the variabl e name and the close bracket
56 if (resolvedTokens.size() < startOffset + 1)
57 return -1;
58
59 unsigned commaLocation, end;
60
61 // Find the variable location
62 unsigned variableLocation = 0;
63 for (unsigned i = startOffset; i < resolvedTokens.size(); ++i) {
64 if (resolvedTokens[i].type() == IdentToken) {
65 variableLocation = i;
66 break;
67 }
68 if (resolvedTokens[i].type() != WhitespaceToken) {
69 findEndOfVariableReference(resolvedTokens, i, end, commaLocation);
70 unsigned length = end - startOffset + 2;
71 resolvedTokens.remove(startOffset - 1, length);
72 return -1;
73 }
74 }
75
76 // Find default value and match braces
77 findEndOfVariableReference(resolvedTokens, variableLocation + 1, end, commaL ocation);
78
79 unsigned length = end - startOffset + 2;
80 unsigned varFunctionPosition = startOffset - 1;
81
82 AtomicString variableName = resolvedTokens[variableLocation].value();
83
84 if (m_variablesSeen.contains(variableName)) {
85 m_cycleDetected = true;
86 resolvedTokens.clear();
87 return 0;
88 }
89
90 CSSVariableData* variableData = m_styleVariableData ? m_styleVariableData->g etVariable(variableName) : nullptr;
91 if (variableData) {
92 Vector<CSSParserToken>& tokens = variableData->tokens();
93 if (variableData->needsVariableResolution()) {
94 m_variablesSeen.add(variableName);
95 resolveVariableReferencesFromTokens(tokens);
96 m_variablesSeen.remove(variableName);
97 }
98 if (tokens.size()) {
99 resolvedTokens.remove(startOffset - 1, length);
100 resolvedTokens.insert(startOffset - 1, tokens);
101 return tokens.size();
102 }
103 }
104
105 // Fallback on default value if present
106 if (!commaLocation || m_cycleDetected) {
107 resolvedTokens.clear();
108 return 0;
109 }
110
111 // Move the tokens to the beginning of the variable reference
112 unsigned defaultValueOffset = commaLocation + 1;
113 unsigned defaultValueLength = end - commaLocation - 1;
114 for (unsigned i = 0; i < defaultValueLength; ++i)
115 resolvedTokens[varFunctionPosition + i] = resolvedTokens[defaultValueOff set + i];
116 resolvedTokens.remove(varFunctionPosition + defaultValueLength, length - def aultValueLength);
117
118 resolveVariableReferencesFromTokens(resolvedTokens);
119
120 return resolvedTokens.size();
121 }
122
123 void CSSVariableResolver::resolveVariableReferencesFromTokens(Vector<CSSParserTo ken>& tokens)
124 {
125 for (unsigned i = 0; i < tokens.size(); ++i) {
126 if (isVariableReferenceToken(tokens[i])) {
127 unsigned validTokens = resolveVariableTokensRecursive(tokens, i + 1) ;
128 if (validTokens < 1 || m_cycleDetected) {
129 tokens.clear();
130 break;
131 }
132 i += validTokens - 1;
133 }
134 }
135 }
136
137 void CSSVariableResolver::resolveAndApplyVariableReferences(StyleResolverState& state, CSSPropertyID id, CSSPrimitiveValue* value)
138 {
139 // TODO(leviw): This should be a stack
140 Vector<CSSParserToken> tokens = value->getVariableDataValue()->tokens();
141
142 CSSVariableResolver resolver(state.style()->variables());
143
144 resolver.resolveVariableReferencesFromTokens(tokens);
145
146 if (!tokens.size())
147 return;
148
149 CSSParserContext context(HTMLStandardMode, 0);
150
151 WillBeHeapVector<CSSProperty, 256> parsedProperties;
152
153 CSSParserValueList valueList = CSSParserValueList(CSSParserTokenRange(tokens ));
154
155 if (!valueList.size())
156 return;
157
158 CSSPropertyParser::parseValue(id, false, &valueList, context, parsedProperti es, StyleRule::Type::Style);
159
160 unsigned parsedPropertiesCount = parsedProperties.size();
161 for (unsigned i = 0; i < parsedPropertiesCount; ++i)
162 StyleBuilder::applyProperty(parsedProperties[i].id(), state, parsedPrope rties[i].value());
163 }
164
165 void CSSVariableResolver::resolveVariableDefinitions(StyleResolverState& state)
166 {
167 StyleVariableData* variables = state.style()->variables();
168 if (!variables)
169 return;
170
171 for (auto& variable : variables->m_data) {
172 if (!variable.value->needsVariableResolution())
173 continue;
174 Vector<CSSParserToken>& tokens = variable.value->tokens();
175
176 CSSVariableResolver resolver(variables, variable.key);
177 resolver.resolveVariableReferencesFromTokens(tokens);
178
179 variable.value->setNeedsVariableResolution(false);
alancutter (OOO until 2018) 2015/08/05 08:01:43 Isn't this mutating the original CSSCustomVariable
180 }
181 }
182
183 CSSVariableResolver::CSSVariableResolver(const StyleVariableData* styleVariableD ata)
184 : m_styleVariableData(styleVariableData)
185 , m_cycleDetected(false)
186 {
187 }
188
189 CSSVariableResolver::CSSVariableResolver(const StyleVariableData* styleVariableD ata, AtomicString& variable)
190 : m_styleVariableData(styleVariableData)
191 , m_cycleDetected(false)
192 {
193 m_variablesSeen.add(variable);
194 }
195
196 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698