Chromium Code Reviews| Index: sdk/lib/html/scripts/htmldartgenerator.py |
| diff --git a/sdk/lib/html/scripts/htmldartgenerator.py b/sdk/lib/html/scripts/htmldartgenerator.py |
| index a199963ba72c5cd4febeca4549ec093c7f990f7f..9fe04a2260be21e3a775edfbd953f71b1acd4f36 100644 |
| --- a/sdk/lib/html/scripts/htmldartgenerator.py |
| +++ b/sdk/lib/html/scripts/htmldartgenerator.py |
| @@ -6,11 +6,27 @@ |
| """This module provides shared functionality for the system to generate |
| dart:html APIs from the IDL database.""" |
| -from generator import DartDomNameOfAttribute |
| +from generator import AnalyzeOperation, ConstantOutputOrder, \ |
| + DartDomNameOfAttribute, FindMatchingAttribute, IsDartCollectionType, \ |
| + IsPureInterface |
| + |
| +# Types that are accessible cross-frame in a limited fashion. |
| +# In these cases, the base type (e.g., Window) provides restricted access |
| +# while the subtype (e.g., LocalWindow) provides full access to the |
| +# corresponding objects if there are from the same frame. |
| +_secure_base_types = { |
| + 'LocalWindow': 'Window', |
| + 'LocalLocation': 'Location', |
| + 'LocalHistory': 'History', |
| +} |
| class HtmlDartGenerator(object): |
| def __init__(self, interface, options): |
| + self._database = options.database |
| self._interface = interface |
| + self._type_registry = options.type_registry |
| + self._interface_type_info = self._type_registry.TypeInfo(self._interface.id) |
| + self._renamer = options.renamer |
| def EmitAttributeDocumentation(self, attribute): |
| dom_name = DartDomNameOfAttribute(attribute) |
| @@ -23,6 +39,126 @@ class HtmlDartGenerator(object): |
| DOMINTERFACE=operation.overloads[0].doc_js_interface_name, |
| DOMNAME=operation.name) |
| + def EmitEventGetter(self, events_class_name): |
| + self._members_emitter.Emit( |
| + '\n /**' |
| + '\n * @domName EventTarget.addEventListener, ' |
| + 'EventTarget.removeEventListener, EventTarget.dispatchEvent' |
| + '\n */' |
| + '\n $TYPE get on =>\n new $TYPE(this);\n', |
| + TYPE=events_class_name) |
| + |
| + def AddMembers(self, interface, declare_only=False): |
|
vsm
2012/11/07 22:31:28
Is declare_only ever True now?
blois
2012/11/08 00:08:34
Yes, this is used for merged classes in Dartium.
|
| + for const in sorted(interface.constants, ConstantOutputOrder): |
| + self.AddConstant(const) |
| + |
| + for attr in sorted(interface.attributes, ConstantOutputOrder): |
| + if attr.type.id != 'EventListener': |
| + self.AddAttribute(attr, declare_only) |
| + |
| + # The implementation should define an indexer if the interface directly |
| + # extends List. |
| + element_type = None |
| + requires_indexer = False |
| + if self._interface_type_info.list_item_type(): |
| + self.AddIndexer(self._interface_type_info.list_item_type()) |
| + else: |
| + for parent in self._database.Hierarchy(self._interface): |
| + if parent == self._interface: |
| + continue |
| + parent_type_info = self._type_registry.TypeInfo(parent.id) |
| + if parent_type_info.list_item_type(): |
| + self.AmendIndexer(parent_type_info.list_item_type()) |
| + break |
| + |
| + # Group overloaded operations by id |
| + operationsById = {} |
| + for operation in interface.operations: |
| + if operation.id not in operationsById: |
| + operationsById[operation.id] = [] |
| + operationsById[operation.id].append(operation) |
| + |
| + # Generate operations |
| + for id in sorted(operationsById.keys()): |
| + operations = operationsById[id] |
| + info = AnalyzeOperation(interface, operations) |
| + self.AddOperation(info, declare_only) |
| + |
| + def AddSecondaryMembers(self, interface): |
| + # With multiple inheritance, attributes and operations of non-first |
| + # interfaces need to be added. Sometimes the attribute or operation is |
| + # defined in the current interface as well as a parent. In that case we |
| + # avoid making a duplicate definition and pray that the signatures match. |
| + secondary_parents = self._TransitiveSecondaryParents(interface) |
| + for parent_interface in sorted(secondary_parents): |
| + if isinstance(parent_interface, str): # IsDartCollectionType(parent_interface) |
|
vsm
2012/11/07 22:31:28
nit: line length
blois
2012/11/08 00:08:34
Done.
|
| + continue |
| + for attr in sorted(parent_interface.attributes, ConstantOutputOrder): |
| + if not FindMatchingAttribute(interface, attr): |
| + self.SecondaryContext(parent_interface) |
| + self.AddAttribute(attr) |
| + |
| + # Group overloaded operations by id |
| + operationsById = {} |
| + for operation in parent_interface.operations: |
| + if operation.id not in operationsById: |
| + operationsById[operation.id] = [] |
| + operationsById[operation.id].append(operation) |
| + |
| + # Generate operations |
| + for id in sorted(operationsById.keys()): |
| + if not any(op.id == id for op in interface.operations): |
| + operations = operationsById[id] |
| + info = AnalyzeOperation(interface, operations) |
| + self.SecondaryContext(parent_interface) |
| + self.AddOperation(info) |
| + |
| + def AddAttribute(self, attribute, declare_only=False): |
| + dom_name = DartDomNameOfAttribute(attribute) |
| + html_name = self._renamer.RenameMember( |
| + self._interface.id, attribute, dom_name, 'get:') |
| + if not html_name or self._IsPrivate(html_name): |
| + return |
| + |
| + html_setter_name = self._renamer.RenameMember( |
| + self._interface.id, attribute, dom_name, 'set:') |
| + read_only = (attribute.is_read_only or 'Replaceable' in attribute.ext_attrs |
| + or not html_setter_name) |
| + |
| + # We don't yet handle inconsistent renames of the getter and setter yet. |
| + assert(not html_setter_name or html_name == html_setter_name) |
| + |
| + if declare_only: |
| + self.DeclareAttribute(attribute, |
| + self.SecureOutputType(attribute.type.id), html_name, read_only) |
| + else: |
| + self.EmitAttribute(attribute, html_name, read_only) |
| + |
| + def AddOperation(self, info, declare_only=False): |
| + """ |
| + Arguments: |
| + operations - contains the overloads, one or more operations with the same |
| + name. |
| + """ |
| + # FIXME: When we pass in operations[0] below, we're assuming all |
| + # overloaded operations have the same security attributes. This |
| + # is currently true, but we should consider filtering earlier or |
| + # merging the relevant data into info itself. |
| + html_name = self._renamer.RenameMember(self._interface.id, |
| + info.operations[0], |
| + info.name) |
| + if not html_name: |
| + if info.name == 'item': |
| + # FIXME: item should be renamed to operator[], not removed. |
| + self.EmitOperation(info, '_item') |
| + return |
| + |
| + if declare_only: |
| + self.DeclareOperation(info, |
| + self.SecureOutputType(info.type_name), html_name) |
| + else: |
| + self.EmitOperation(info, html_name) |
| + |
| def AdditionalImplementedInterfaces(self): |
| # TODO: Include all implemented interfaces, including other Lists. |
| implements = [] |
| @@ -86,3 +222,54 @@ class HtmlDartGenerator(object): |
| TYPE=type_name, |
| NAME=html_name, |
| PARAMS=operation.ParametersDeclaration(self._DartType)) |
| + |
| + def SecureOutputType(self, type_name, is_dart_type=False): |
| + if is_dart_type: |
| + dart_name = type_name |
| + else: |
| + dart_name = self._DartType(type_name) |
| + # We only need to secure Window. Only local History and Location are returned |
|
vsm
2012/11/07 22:31:28
nit: line len
blois
2012/11/08 00:08:34
Done.
|
| + # in generated code. |
| + if dart_name == 'LocalWindow': |
| + return _secure_base_types[dart_name] |
| + return dart_name |
| + |
| + def SecureBaseName(self, type_name): |
| + if type_name in _secure_base_types: |
| + return _secure_base_types[type_name] |
| + |
| + def _TransitiveSecondaryParents(self, interface): |
| + """Returns a list of all non-primary parents. |
| + |
| + The list contains the interface objects for interfaces defined in the |
| + database, and the name for undefined interfaces. |
| + """ |
| + def walk(parents): |
| + for parent in parents: |
| + parent_name = parent.type.id |
| + if parent_name == 'EventTarget': |
| + # Currently EventTarget is implemented as a mixin, not a proper |
| + # super interface---ignore its members. |
| + continue |
| + if IsDartCollectionType(parent_name): |
| + result.append(parent_name) |
| + continue |
| + if self._database.HasInterface(parent_name): |
| + parent_interface = self._database.GetInterface(parent_name) |
| + result.append(parent_interface) |
| + walk(parent_interface.parents) |
| + |
| + result = [] |
| + if interface.parents: |
| + parent = interface.parents[0] |
| + if IsPureInterface(parent.type.id): |
| + walk(interface.parents) |
| + else: |
| + walk(interface.parents[1:]) |
| + return result |
| + |
| + def _DartType(self, type_name): |
| + return self._type_registry.DartType(type_name) |
| + |
| + def _IsPrivate(self, name): |
| + return name.startswith('_') |