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

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

Powered by Google App Engine
This is Rietveld 408576698