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

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

Powered by Google App Engine
This is Rietveld 408576698