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

Side by Side Diff: pkg/csslib/lib/src/polyfill.dart

Issue 23868008: Added polyfill for var (moved from web_ui) (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 3 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 (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of csslib.parser;
6
7 /**
8 * CSS polyfill emits CSS to be understood by older parsers that which do not
9 * understand (var, calc, etc.).
10 */
11 class PolyFill {
12 final Messages _messages;
13 final bool _warningsAsErrors;
14
15 Set<StyleSheet> allStyleSheets = new Set<StyleSheet>();
16
17 /**
18 * [_pseudoElements] list of known pseudo attributes found in HTML, any
19 * CSS pseudo-elements 'name::custom-element' is mapped to the manged name
20 * associated with the pseudo-element key.
21 */
22 PolyFill(this._messages, this._warningsAsErrors);
23
24 /**
25 * Run the analyzer on every file that is a style sheet or any component that
26 * has a style tag.
27 */
28 void process(StyleSheet stylesheet) {
29 // TODO(terry): Process all imported stylesheets.
30
31 var styleSheets = processVars([stylesheet]);
32 allStyleSheets.addAll(styleSheets);
33
34 normalize();
35 }
36
37 void normalize() {
38 // Remove all var definitions for all style sheets analyzed.
39 for (var tree in allStyleSheets)
40 new _RemoveVarDefinitions().visitTree(tree);
41 }
42
43 List<StyleSheet> processVars(List<StyleSheet> styleSheets) {
44 // TODO(terry): Process all dependencies.
45 // Build list of all var definitions.
46 Map varDefs = new Map();
47 for (var tree in styleSheets) {
48 var allDefs = (new _VarDefinitions()..visitTree(tree)).found;
49 allDefs.forEach((key, value) {
50 varDefs[key] = value;
51 });
52 }
53
54 // Resolve all definitions to a non-VarUsage (terminal expression).
55 varDefs.forEach((key, value) {
56 for (var expr in (value.expression as Expressions).expressions) {
57 var def = _findTerminalVarDefinition(varDefs, value);
58 varDefs[key] = def;
59 }
60 });
61
62 // Resolve all var usages.
63 for (var tree in styleSheets) new _ResolveVarUsages(varDefs).visitTree(tree) ;
Siggi Cherem (dart-lang) 2013/09/09 19:53:38 style: 80 col and add { } (we only skip them for f
terry 2013/09/09 20:04:50 Done.
64
65 return styleSheets;
66 }
67 }
68
69 /**
70 * Find var- definitions in a style sheet.
71 * [found] list of known definitions.
72 */
73 class _VarDefinitions extends Visitor {
74 final Map<String, VarDefinition> found = new Map();
75
76 void visitTree(StyleSheet tree) {
77 visitStyleSheet(tree);
78 }
79
80 visitVarDefinition(VarDefinition node) {
81 // Replace with latest variable definition.
82 found[node.definedName] = node;
83 super.visitVarDefinition(node);
84 }
85
86 void visitVarDefinitionDirective(VarDefinitionDirective node) {
87 visitVarDefinition(node.def);
88 }
89 }
90
91 /**
92 * Resolve any CSS expression which contains a var() usage to the ultimate real
93 * CSS expression value e.g.,
94 *
95 * var-one: var(two);
96 * var-two: #ff00ff;
97 *
98 * .test {
99 * color: var(one);
100 * }
101 *
102 * then .test's color would be #ff00ff
103 */
104 class _ResolveVarUsages extends Visitor {
105 final Map<String, VarDefinition> varDefs;
106 bool inVarDefinition = false;
107 bool inUsage = false;
108 Expressions currentExpressions;
109
110 _ResolveVarUsages(this.varDefs);
111
112 void visitTree(StyleSheet tree) {
113 visitStyleSheet(tree);
114 }
115
116 void visitVarDefinition(VarDefinition varDef) {
117 inVarDefinition = true;
118 super.visitVarDefinition(varDef);
119 inVarDefinition = false;
120 }
121
122 void visitExpressions(Expressions node) {
123 currentExpressions = node;
124 super.visitExpressions(node);
125 currentExpressions = null;
126 }
127
128 void visitVarUsage(VarUsage node) {
129 // Don't process other var() inside of a varUsage. That implies that the
130 // default is a var() too. Also, don't process any var() inside of a
131 // varDefinition (they're just place holders until we've resolved all real
132 // usages.
133 if (!inUsage && !inVarDefinition && currentExpressions != null) {
134 var expressions = currentExpressions.expressions;
135 var index = expressions.indexOf(node);
136 assert(index >= 0);
137 var def = varDefs[node.name];
138 if (def != null) {
139 // Found a VarDefinition use it.
140 _resolveVarUsage(currentExpressions.expressions, index, def);
141 } else if (node.defaultValues.any((e) => e is VarUsage)) {
142 // Don't have a VarDefinition need to use default values resolve all
143 // default values.
144 var terminalDefaults = [];
145 for (var defaultValue in node.defaultValues) {
146 terminalDefaults.addAll(resolveUsageTerminal(defaultValue));
147 }
148 expressions.replaceRange(index, index + 1, terminalDefaults);
149 } else {
150 // No VarDefinition but default value is a terminal expression; use it.
151 expressions.replaceRange(index, index + 1, node.defaultValues);
152 }
153 }
154
155 inUsage = true;
156 super.visitVarUsage(node);
157 inUsage = false;
158 }
159
160 List<Expression> resolveUsageTerminal(VarUsage usage) {
161 var result = [];
162
163 var varDef = varDefs[usage.name];
164 var expressions;
165 if (varDef == null) {
166 // VarDefinition not found try the defaultValues.
167 expressions = usage.defaultValues;
168 } else {
169 // Use the VarDefinition found.
170 expressions = (varDef.expression as Expressions).expressions;
171 }
172
173 for (var expr in expressions) {
174 if (expr is VarUsage) {
175 // Get terminal value.
176 result.addAll(resolveUsageTerminal(expr));
177 }
178 }
179
180 // We're at a terminal just return the VarDefinition expression.
181 if (result.isEmpty && varDef != null) {
182 result = (varDef.expression as Expressions).expressions;
183 }
184
185 return result;
186 }
187
188 _resolveVarUsage(List<Expressions> expressions, int index,
189 VarDefinition def) {
190 var defExpressions = (def.expression as Expressions).expressions;
191 expressions.replaceRange(index, index + 1, defExpressions);
192 }
193 }
194
195 /** Remove all var definitions. */
196 class _RemoveVarDefinitions extends Visitor {
197 void visitTree(StyleSheet tree) {
198 visitStyleSheet(tree);
199 }
200
201 void visitStyleSheet(StyleSheet ss) {
202 ss.topLevels.removeWhere((e) => e is VarDefinitionDirective);
203 super.visitStyleSheet(ss);
204 }
205
206 void visitDeclarationGroup(DeclarationGroup node) {
207 node.declarations.removeWhere((e) => e is VarDefinition);
208 super.visitDeclarationGroup(node);
209 }
210 }
211
212 /** Find terminal definition (non VarUsage implies real CSS value). */
213 VarDefinition _findTerminalVarDefinition(Map<String, VarDefinition> varDefs,
214 VarDefinition varDef) {
Siggi Cherem (dart-lang) 2013/09/09 19:53:38 fix indentation: missing a space, or only indent +
terry 2013/09/09 20:04:50 +4 Done.
215 var expressions = varDef.expression as Expressions;
216 for (var expr in expressions.expressions) {
217 if (expr is VarUsage) {
218 var usageName = (expr as VarUsage).name;
219 var foundDef = varDefs[usageName];
220
221 // If foundDef is unknown check if defaultValues; if it exist then resolve
222 // to terminal value.
223 if (foundDef == null) {
224 // We're either a VarUsage or terminal definition if in varDefs;
225 // either way replace VarUsage with it's default value because the
226 // VarDefinition isn't found.
227 var defaultValues = (expr as VarUsage).defaultValues;
228 var replaceExprs = expressions.expressions;
229 assert(replaceExprs.length == 1);
230 replaceExprs.replaceRange(0, 1, defaultValues);
231 return varDef;
232 }
233 if (foundDef is VarDefinition) {
234 return _findTerminalVarDefinition(varDefs, foundDef);
235 }
236 } else {
237 // Return real CSS property.
238 return varDef;
239 }
240 }
241
242 // Didn't point to a var definition that existed.
243 return varDef;
244 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698