Flutter Engine
The Flutter Engine
css_code_generator.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2#
3# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
4# for details. All rights reserved. Use of this source code is governed by a
5# BSD-style license that can be found in the LICENSE file.
6"""Generates CSSStyleDeclaration template file from css property definitions
7defined in WebKit."""
8
9import tempfile, os, re
10
11COMMENT_LINE_PREFIX = ' * '
12# TODO(efortuna): Pull from DEPS so that we have latest css *in sync* with our
13# Dartium. Then remove the checked in CSSPropertyNames.in.
14SOURCE_PATH = 'CSSPropertyNames.in'
15#SOURCE_PATH = 'Source/WebCore/css/CSSPropertyNames.in'
16TEMPLATE_FILE = '../templates/html/impl/impl_CSSStyleDeclaration.darttemplate'
17
18# These are the properties that are supported on all Dart project supported
19# browsers as camelCased names on the CssStyleDeclaration.
20# Note that we do not use the MDN for compatibility info here.
21BROWSER_PATHS = [
22 'cssProperties.CSS21.txt', # Remove when we have samples from all browsers.
23 'cssProperties.ie9.txt',
24 'cssProperties.ie10.txt',
25 'cssProperties.ie11.txt',
26 'cssProperties.ff36.txt',
27 'cssProperties.chrome40.txt',
28 'cssProperties.safari-7.1.3.txt',
29 'cssProperties.mobileSafari-8.2.txt',
30 'cssProperties.iPad4Air.onGoogleSites.txt',
31]
32
33# Supported annotations for any specific CSS properties.
34annotated = {
35 'transition':
36 '''@SupportedBrowser(SupportedBrowser.CHROME)
37 @SupportedBrowser(SupportedBrowser.FIREFOX)
38 @SupportedBrowser(SupportedBrowser.IE, '10')
39 @SupportedBrowser(SupportedBrowser.SAFARI)'''
40}
41
42
43class Error:
44
45 def __init__(self, message):
46 self.message = message
47
48 def __repr__(self):
49 return self.message
50
51
52def camelCaseName(name):
53 """Convert a CSS property name to a lowerCamelCase name."""
54 name = name.replace('-webkit-', '')
55 words = []
56 for word in name.split('-'):
57 if words:
58 words.append(word.title())
59 else:
60 words.append(word)
61 return ''.join(words)
62
63
64def dashifyName(camelName):
65
66 def fix(match):
67 return '-' + match.group(0).lower()
68
69 return re.sub(r'[A-Z]', fix, camelName)
70
71
72def isCommentLine(line):
73 return line.strip() == '' or line.startswith('#') or line.startswith('//')
74
75
76def readCssProperties(filename):
77 data = open(filename).readlines()
78 data = sorted([d.strip() for d in set(data) if not isCommentLine(d)])
79 return data
80
81
83 data = open(SOURCE_PATH).readlines()
84
85 # filter CSSPropertyNames.in to only the properties
86 # TODO(efortuna): do we also want CSSPropertyNames.in?
87 data = [d.strip() for d in data if not isCommentLine(d) and not '=' in d]
88
89 browser_props = [set(readCssProperties(file)) for file in BROWSER_PATHS]
90 universal_properties = set.intersection(*browser_props)
91 universal_properties = universal_properties.difference(['cssText'])
92 universal_properties = universal_properties.intersection(
93 list(map(camelCaseName, data)))
94
95 class_file = open(TEMPLATE_FILE, 'w')
96
97 class_file.write("""
98// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
99// for details. All rights reserved. Use of this source code is governed by a
100// BSD-style license that can be found in the LICENSE file.
101
102// WARNING: DO NOT EDIT THIS TEMPLATE FILE.
103// The template file was generated by scripts/css_code_generator.py
104
105// Source of CSS properties:
106// %s
107
108part of $LIBRARYNAME;
109""" % SOURCE_PATH)
110
111 class_file.write("""
112$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME $EXTENDS with
113 $(CLASSNAME)Base $IMPLEMENTS {
114 factory $CLASSNAME() => new CssStyleDeclaration.css('');
115
116 factory $CLASSNAME.css(String css) {
117 final style = new DivElement().style;
118 style.cssText = css;
119 return style;
120 }
121
122 /// Returns the value of the property if the provided *CSS* property
123 /// name is supported on this element and if the value is set. Otherwise
124 /// returns an empty string.
125 ///
126 /// Please note the property name uses camelCase, not-hyphens.
127 String getPropertyValue(String propertyName) {
128 return _getPropertyValueHelper(propertyName);
129 }
130
131 String _getPropertyValueHelper(String propertyName) {
132 return _getPropertyValue(_browserPropertyName(propertyName));
133 }
134
135 /**
136 * Returns true if the provided *CSS* property name is supported on this
137 * element.
138 *
139 * Please note the property name camelCase, not-hyphens. This
140 * method returns true if the property is accessible via an unprefixed _or_
141 * prefixed property.
142 */
143 bool supportsProperty(String propertyName) {
144 return _supportsProperty(propertyName) ||
145 _supportsProperty(_camelCase("${Device.cssPrefix}$propertyName"));
146 }
147
148 bool _supportsProperty(String propertyName) {
149 return JS('bool', '# in #', propertyName, this);
150 }
151
152
153 void setProperty(String propertyName, String$NULLABLE value,
154 [String$NULLABLE priority]) {
155 return _setPropertyHelper(_browserPropertyName(propertyName),
156 value, priority);
157 }
158
159 String _browserPropertyName(String propertyName) {
160 String$NULLABLE name = _readCache(propertyName);
161 if (name is String) return name;
162 name = _supportedBrowserPropertyName(propertyName);
163 _writeCache(propertyName, name);
164 return name;
165 }
166
167 String _supportedBrowserPropertyName(String propertyName) {
168 if (_supportsProperty(_camelCase(propertyName))) {
169 return propertyName;
170 }
171 var prefixed = "${Device.cssPrefix}$propertyName";
172 if (_supportsProperty(prefixed)) {
173 return prefixed;
174 }
175 // May be a CSS variable, just use it as provided.
176 return propertyName;
177 }
178
179 static final _propertyCache = JS('', '{}');
180 static String$NULLABLE _readCache(String key) =>
181 JS('String|Null', '#[#]', _propertyCache, key);
182 static void _writeCache(String key, String value) {
183 JS('void', '#[#] = #', _propertyCache, key, value);
184 }
185
186 static String _camelCase(String hyphenated) {
187 var replacedMs = JS('String', r'#.replace(/^-ms-/, "ms-")', hyphenated);
188 return JS(
189 'String',
190 r'#.replace(/-([\da-z])/ig,'
191 r'function(_, letter) { return letter.toUpperCase();})',
192 replacedMs);
193 }
194
195 void _setPropertyHelper(String propertyName, String$NULLABLE value,
196 [String$NULLABLE priority]) {
197 if (value == null) value = '';
198 if (priority == null) priority = '';
199 JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority);
200 }
201
202 /**
203 * Checks to see if CSS Transitions are supported.
204 */
205 static bool get supportsTransitions {
206 return document.body$NULLASSERT.style.supportsProperty('transition');
207 }
208$!MEMBERS
209""")
210
211 for camelName in sorted(universal_properties):
212 property = dashifyName(camelName)
213 class_file.write("""
214 /** Gets the value of "%s" */
215 String get %s => this._%s;
216
217 /** Sets the value of "%s" */
218 set %s(String$NULLABLE value) {
219 _%s = value == null ? '' : value;
220 }
221 @Returns('String')
222 @JSName('%s')
223 String get _%s native;
224
225 @JSName('%s')
226 set _%s(String value) native;
227 """ % (property, camelName, camelName, property, camelName, camelName,
228 camelName, camelName, camelName, camelName))
229
230 class_file.write("""
231}
232
233class _CssStyleDeclarationSet extends Object with CssStyleDeclarationBase {
234 final Iterable<Element> _elementIterable;
235 Iterable<CssStyleDeclaration> _elementCssStyleDeclarationSetIterable;
236
237 _CssStyleDeclarationSet(this._elementIterable)
238 : _elementCssStyleDeclarationSetIterable =
239 new List.of(_elementIterable).map((e) => e.style);
240
241 String getPropertyValue(String propertyName) =>
242 _elementCssStyleDeclarationSetIterable.first.getPropertyValue(
243 propertyName);
244
245 void setProperty(String propertyName, String$NULLABLE value,
246 [String$NULLABLE priority]) {
247 _elementCssStyleDeclarationSetIterable.forEach((e) =>
248 e.setProperty(propertyName, value, priority));
249 }
250
251""")
252
253 class_file.write("""
254 void _setAll(String propertyName, String$NULLABLE value) {
255 value = value == null ? '' : value;
256 for (Element element in _elementIterable) {
257 JS('void', '#.style[#] = #', element, propertyName, value);
258 }
259 }
260""")
261
262 for camelName in sorted(universal_properties):
263 property = dashifyName(camelName)
264 class_file.write("""
265 /** Sets the value of "%s" */
266 set %s(String value) {
267 _setAll('%s', value);
268 }
269 """ % (property, camelName, camelName))
270
271 class_file.write("""
272
273 // Important note: CssStyleDeclarationSet does NOT implement every method
274 // available in CssStyleDeclaration. Some of the methods don't make so much
275 // sense in terms of having a reasonable value to return when you're
276 // considering a list of Elements. You will need to manually add any of the
277 // items in the MEMBERS set if you want that functionality.
278}
279
280abstract mixin class CssStyleDeclarationBase {
281 String getPropertyValue(String propertyName);
282 void setProperty(String propertyName, String$NULLABLE value,
283 [String$NULLABLE priority]);
284""")
285
286 class_lines = []
287
288 seen = set()
289 for prop in sorted(data, key=camelCaseName):
290 camel_case_name = camelCaseName(prop)
291 upper_camel_case_name = camel_case_name[0].upper() + camel_case_name[1:]
292 css_name = prop.replace('-webkit-', '')
293 base_css_name = prop.replace('-webkit-', '')
294
295 if base_css_name in seen or base_css_name.startswith('-internal'):
296 continue
297 seen.add(base_css_name)
298
299 comment = ' /** %s the value of "' + base_css_name + '" */'
300 class_lines.append('\n')
301 class_lines.append(comment % 'Gets')
302 if base_css_name in annotated:
303 class_lines.append(annotated[base_css_name])
304 class_lines.append("""
305 String get %s =>
306 getPropertyValue('%s');
307
308""" % (camel_case_name, css_name))
309
310 class_lines.append(comment % 'Sets')
311 if base_css_name in annotated:
312 class_lines.append(annotated[base_css_name])
313 class_lines.append("""
314 set %s(String value) {
315 setProperty('%s', value, '');
316 }
317""" % (camel_case_name, css_name))
318
319 class_file.write(''.join(class_lines))
320 class_file.write('}\n')
321 class_file.close()
static void readlines(const void *data, size_t size, F f)
Definition: editor.cpp:30
struct MyStruct s
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
Definition: SkVx.h:680
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741