Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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