Chromium Code Reviews| Index: tools/dom/scripts/css_code_generator.py |
| diff --git a/tools/dom/scripts/css_code_generator.py b/tools/dom/scripts/css_code_generator.py |
| index 11bf7bcbf63ab04d2a66e2c3307fbbbe35bcd465..c2bd17df9a9e7885e0d9e06d0619ba9d3ca01580 100644 |
| --- a/tools/dom/scripts/css_code_generator.py |
| +++ b/tools/dom/scripts/css_code_generator.py |
| @@ -1,28 +1,28 @@ |
| -#!/usr/bin/python2.6 |
| +#!/usr/bin/python |
| # |
| -# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| +# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| # for details. All rights reserved. Use of this source code is governed by a |
| # BSD-style license that can be found in the LICENSE file. |
| -"""Generates CSSStyleDeclaration from css property definitions defined in WebKit.""" |
| +"""Generates CSSStyleDeclaration template file from css property definitions |
| +defined in WebKit.""" |
| import tempfile, os |
| COMMENT_LINE_PREFIX = ' * ' |
| -SOURCE_PATH = 'Source/WebCore/css/CSSPropertyNames.in' |
| -INPUT_URL = 'http://trac.webkit.org/export/latest/trunk/%s' % SOURCE_PATH |
| -INTERFACE_FILE = '../../html/src/CSSStyleDeclaration.dart' |
| -CLASS_FILE = '../../html/src/CSSStyleDeclarationWrappingImplementation.dart' |
| - |
| -def main(): |
| - _, css_names_file = tempfile.mkstemp('.CSSPropertyNames.in') |
| - try: |
| - if os.system('wget %s -O %s' % (INPUT_URL, css_names_file)): |
| - return 1 |
| - generate_code(css_names_file) |
| - print 'Successfully generated %s and %s' % (INTERFACE_FILE, CLASS_FILE) |
| - finally: |
| - os.remove(css_names_file) |
| +# TODO(efortuna): Pull from DEPS so that we have latest css *in sync* with our |
| +# Dartium. Then remove the checked in CSSPropertyNames.in. |
| +SOURCE_PATH = 'CSSPropertyNames.in' |
|
Emily Fortuna
2014/08/05 22:14:13
I will remove this TODO and the commented out SOUR
|
| +#SOURCE_PATH = 'Source/WebCore/css/CSSPropertyNames.in' |
| +TEMPLATE_FILE = '../templates/html/impl/impl_CSSStyleDeclaration.darttemplate' |
| + |
| +# Supported annotations for any specific CSS properties. |
| +annotated = { |
| + 'transition': '''@SupportedBrowser(SupportedBrowser.CHROME) |
| + @SupportedBrowser(SupportedBrowser.FIREFOX) |
| + @SupportedBrowser(SupportedBrowser.IE, '10') |
| + @SupportedBrowser(SupportedBrowser.SAFARI)''' |
| +} |
| def camelCaseName(name): |
| """Convert a CSS property name to a lowerCamelCase name.""" |
| @@ -35,165 +35,196 @@ def camelCaseName(name): |
| words.append(word) |
| return ''.join(words) |
| -def generate_code(input_path): |
| - data = open(input_path).readlines() |
| +def GenerateCssTemplateFile(): |
| + data = open(SOURCE_PATH).readlines() |
| # filter CSSPropertyNames.in to only the properties |
| + # TODO(efortuna): do we also want CSSPropertyNames.in? |
| data = [d[:-1] for d in data |
| if len(d) > 1 |
| and not d.startswith('#') |
| and not d.startswith('//') |
| and not '=' in d] |
| - interface_file = open(INTERFACE_FILE, 'w') |
| - class_file = open(CLASS_FILE, 'w') |
| - |
| - interface_file.write(""" |
| -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| -// for details. All rights reserved. Use of this source code is governed by a |
| -// BSD-style license that can be found in the LICENSE file. |
| - |
| -// WARNING: Do not edit. |
| -// This file was generated by html/scripts/css_code_generator.py |
| - |
| -// Source of CSS properties: |
| -// %s |
| - |
| -// TODO(jacobr): add versions that take numeric values in px, miliseconds, etc. |
| - |
| -interface CSSStyleDeclaration { |
| - |
| - String get cssText; |
| - |
| - void set cssText(String value); |
| - |
| - int get length; |
| - |
| - CSSRule get parentRule; |
| - |
| - CSSValue getPropertyCSSValue(String propertyName); |
| - |
| - String getPropertyPriority(String propertyName); |
| - |
| - String getPropertyShorthand(String propertyName); |
| - |
| - String getPropertyValue(String propertyName); |
| - |
| - bool isPropertyImplicit(String propertyName); |
| - |
| - String item(int index); |
| - |
| - String removeProperty(String propertyName); |
| - |
| - void setProperty(String propertyName, String value, [String priority]); |
| - |
| -""".lstrip() % SOURCE_PATH) |
| - |
| + class_file = open(TEMPLATE_FILE, 'w') |
| class_file.write(""" |
| -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| -// WARNING: Do not edit. |
| -// This file was generated by html/scripts/css_code_generator.py |
| +// WARNING: DO NOT EDIT THIS TEMPLATE FILE. |
| +// The template file was generated by scripts/css_code_generator.py |
| // Source of CSS properties: |
| // %s |
| -// TODO(jacobr): add versions that take numeric values in px, miliseconds, etc. |
| - |
| -class CSSStyleDeclarationWrappingImplementation extends DOMWrapperBase implements CSSStyleDeclaration { |
| - static String _cachedBrowserPrefix; |
| +part of $LIBRARYNAME; |
| - CSSStyleDeclarationWrappingImplementation._wrap(ptr) : super._wrap(ptr) {} |
| +$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS) class $CLASSNAME $EXTENDS with |
| + $(CLASSNAME)Base $IMPLEMENTS { |
| + factory $CLASSNAME() => new CssStyleDeclaration.css(''); |
| - static String get _browserPrefix { |
| - if (_cachedBrowserPrefix == null) { |
| - if (_Device.isFirefox) { |
| - _cachedBrowserPrefix = '-moz-'; |
| - } else { |
| - _cachedBrowserPrefix = '-webkit-'; |
| - } |
| - // TODO(jacobr): support IE 9.0 and Opera as well. |
| - } |
| - return _cachedBrowserPrefix; |
| + factory $CLASSNAME.css(String css) { |
| + final style = new Element.tag('div').style; |
| + style.cssText = css; |
| + return style; |
| } |
| - String get cssText { return _ptr.cssText; } |
| - |
| - void set cssText(String value) { _ptr.cssText = value; } |
| - |
| - int get length { return _ptr.length; } |
| - |
| - CSSRule get parentRule { return LevelDom.wrapCSSRule(_ptr.parentRule); } |
| - |
| - CSSValue getPropertyCSSValue(String propertyName) { |
| - return LevelDom.wrapCSSValue(_ptr.getPropertyCSSValue(propertyName)); |
| + String getPropertyValue(String propertyName) { |
| + var propValue = _getPropertyValueHelper(propertyName); |
| + return propValue != null ? propValue : ''; |
| } |
| - String getPropertyPriority(String propertyName) { |
| - return _ptr.getPropertyPriority(propertyName); |
| + String _getPropertyValueHelper(String propertyName) { |
| + if (_supportsProperty(_camelCase(propertyName))) { |
| + return _getPropertyValue(propertyName); |
| + } else { |
| + return _getPropertyValue(Device.cssPrefix + propertyName); |
| + } |
| } |
| - String getPropertyShorthand(String propertyName) { |
| - return _ptr.getPropertyShorthand(propertyName); |
| + /** |
| + * Returns true if the provided *CSS* property name is supported on this |
| + * element. |
| + * |
| + * Please note the property name camelCase, not-hyphens. This |
| + * method returns true if the property is accessible via an unprefixed _or_ |
| + * prefixed property. |
| + */ |
| + bool supportsProperty(String propertyName) { |
| + return _supportsProperty(propertyName) || |
| + _supportsProperty(_camelCase(Device.cssPrefix + propertyName)); |
| } |
| - String getPropertyValue(String propertyName) { |
| - return _ptr.getPropertyValue(propertyName); |
| + bool _supportsProperty(String propertyName) { |
| +$if DART2JS |
| + return JS('bool', '# in #', propertyName, this); |
| +$else |
| + // You can't just check the value of a property, because there is no way |
| + // to distinguish between property not being present in the browser and |
| + // not having a value at all. (Ultimately we'll want the native method to |
| + // return null if the property doesn't exist and empty string if it's |
| + // defined but just doesn't have a value. |
| + return _hasProperty(propertyName); |
| +$endif |
| + } |
| +$if DARTIUM |
| + |
| + bool _hasProperty(String propertyName) => |
| + _blink.BlinkCSSStyleDeclaration.$__getter___Callback(this, propertyName); |
| +$endif |
| + |
| + @DomName('CSSStyleDeclaration.setProperty') |
| + void setProperty(String propertyName, String value, [String priority]) { |
| + if (_supportsProperty(_camelCase(propertyName))) { |
| + return _setPropertyHelper(propertyName, value, priority); |
| + } else { |
| + return _setPropertyHelper(Device.cssPrefix + propertyName, value, |
| + priority); |
| + } |
| } |
| - bool isPropertyImplicit(String propertyName) { |
| - return _ptr.isPropertyImplicit(propertyName); |
| + String _camelCase(String hyphenated) { |
| + bool firstWord = true; |
| + return hyphenated.splitMapJoin('-', onMatch : (_) => '', |
| + onNonMatch : (String word) { |
| + if (word.length > 0) { |
| + if (firstWord) { |
| + firstWord = false; |
| + return word; |
| + } |
| + return word[0].toUpperCase() + word.substring(1); |
| + } |
| + return ''; |
| + }); |
| } |
| - String item(int index) { |
| - return _ptr.item(index); |
| +$if DART2JS |
| + void _setPropertyHelper(String propertyName, String value, [String priority]) { |
| + // try/catch for IE9 which throws on unsupported values. |
| + try { |
| + if (value == null) value = ''; |
| + if (priority == null) { |
| + priority = ''; |
| + } |
| + JS('void', '#.setProperty(#, #, #)', this, propertyName, value, priority); |
| + // Bug #2772, IE9 requires a poke to actually apply the value. |
| + if (JS('bool', '!!#.setAttribute', this)) { |
| + JS('void', '#.setAttribute(#, #)', this, propertyName, value); |
| + } |
| + } catch (e) {} |
| } |
| - String removeProperty(String propertyName) { |
| - return _ptr.removeProperty(propertyName); |
| + /** |
| + * Checks to see if CSS Transitions are supported. |
| + */ |
| + static bool get supportsTransitions { |
| + return supportsProperty('transition'); |
| + } |
| +$else |
| + void _setPropertyHelper(String propertyName, String value, [String priority]) { |
| + if (priority == null) { |
| + priority = ''; |
| + } |
| + _setProperty(propertyName, value, priority); |
| } |
| - void setProperty(String propertyName, String value, [String priority = '']) { |
| - _ptr.setProperty(propertyName, value, priority); |
| + /** |
| + * Checks to see if CSS Transitions are supported. |
| + */ |
| + static bool get supportsTransitions => true; |
| +$endif |
| +$!MEMBERS |
| +} |
| + |
| +class _CssStyleDeclarationSet extends Object with CssStyleDeclarationBase { |
| + final Iterable<Element> _elementIterable; |
| + Iterable<CssStyleDeclaration> _elementCssStyleDeclarationSetIterable; |
| + |
| + _CssStyleDeclarationSet(this._elementIterable) { |
| + _elementCssStyleDeclarationSetIterable = new List.from( |
| + _elementIterable).map((e) => e.style); |
| } |
| - String get typeName { return "CSSStyleDeclaration"; } |
| + String getPropertyValue(String propertyName) => |
| + _elementCssStyleDeclarationSetIterable.first.getPropertyValue( |
| + propertyName); |
| -""".lstrip() % SOURCE_PATH) |
| + void setProperty(String propertyName, String value, [String priority]) { |
| + _elementCssStyleDeclarationSetIterable.forEach((e) => |
| + e.setProperty(propertyName, value, priority)); |
| + } |
| + // Important note: CssStyleDeclarationSet does NOT implement every method |
| + // available in CssStyleDeclaration. Some of the methods don't make so much |
| + // sense in terms of having a resonable value to return when you're |
| + // considering a list of Elements. You will need to manually add any of the |
| + // items in the MEMBERS set if you want that functionality. |
| +} |
| + |
| +abstract class CssStyleDeclarationBase { |
| + String getPropertyValue(String propertyName); |
| + void setProperty(String propertyName, String value, [String priority]); |
| +""" % SOURCE_PATH) |
| - interface_lines = []; |
| class_lines = []; |
| seen = set() |
| for prop in sorted(data, key=lambda p: camelCaseName(p)): |
| camel_case_name = camelCaseName(prop) |
| upper_camel_case_name = camel_case_name[0].upper() + camel_case_name[1:]; |
| - css_name = prop.replace('-webkit-', '${_browserPrefix}') |
| + css_name = prop.replace('-webkit-', '') |
| base_css_name = prop.replace('-webkit-', '') |
| - if base_css_name in seen: |
| + if base_css_name in seen or base_css_name.startswith('-internal'): |
| continue |
| seen.add(base_css_name) |
| comment = ' /** %s the value of "' + base_css_name + '" */' |
| - |
| - interface_lines.append(comment % 'Gets') |
| - interface_lines.append(""" |
| - String get %s; |
| - |
| -""" % camel_case_name) |
| - |
| - interface_lines.append(comment % 'Sets') |
| - interface_lines.append(""" |
| - void set %s(String value); |
| - |
| -""" % camel_case_name) |
| - |
| class_lines.append('\n'); |
| class_lines.append(comment % 'Gets') |
| + if base_css_name in annotated: |
| + class_lines.append(annotated[base_css_name]) |
| class_lines.append(""" |
| String get %s => |
| getPropertyValue('%s'); |
| @@ -201,19 +232,14 @@ class CSSStyleDeclarationWrappingImplementation extends DOMWrapperBase implement |
| """ % (camel_case_name, css_name)) |
| class_lines.append(comment % 'Sets') |
| + if base_css_name in annotated: |
| + class_lines.append(annotated[base_css_name]) |
| class_lines.append(""" |
| void set %s(String value) { |
| setProperty('%s', value, ''); |
| } |
| """ % (camel_case_name, css_name)) |
| - interface_file.write(''.join(interface_lines)); |
| - interface_file.write('}\n') |
| - interface_file.close() |
| - |
| class_file.write(''.join(class_lines)); |
| class_file.write('}\n') |
| class_file.close() |
| - |
| -if __name__ == '__main__': |
| - main() |