Chromium Code Reviews| Index: client/dom/scripts/dartgenerator.py |
| diff --git a/client/dom/scripts/dartgenerator.py b/client/dom/scripts/dartgenerator.py |
| index 76084e92062b99ab2d0f39675ccf798a332080cd..aa23d9746aebe9f9a8301c544c9e5eeab1c21689 100755 |
| --- a/client/dom/scripts/dartgenerator.py |
| +++ b/client/dom/scripts/dartgenerator.py |
| @@ -58,6 +58,348 @@ _idl_to_dart_type_conversions = { |
| _dart_to_idl_type_conversions = dict((v,k) for k, v in |
| _idl_to_dart_type_conversions.iteritems()) |
| +_private_html_properties = { |
|
sra1
2012/02/16 04:43:28
For each of these tables, add a comment saying wha
Jacob
2012/02/17 00:44:23
Done.
|
| + 'Element': set(['clientLeft', 'clientTop', 'clientWidth', 'clientHeight', |
| + 'offsetLeft', 'offsetTop', 'offsetWidth', 'offsetHeight', |
| + 'scrollLeft', 'scrollTop', 'scrollWidth', 'scrollHeight', |
| + 'childElementCount', 'firstElementChild', 'hasAttribute', |
| + 'getAttribute', 'removeAttribute', 'setAttribute', 'className', |
| + 'children']), |
| + 'Node' : set(['appendChild', 'removeChild', 'replaceChild', 'attributes', |
| + 'childNodes']), |
| + # TODO(jacobr): other direct translate methods on node such as |
| + # textContext->text |
| + 'Document': set(['createElement', 'createEvent']), |
| + 'Window': set(['getComputedStyle']), |
| + 'EventTarget': set(['removeEventListener', 'addEventListener', |
| + 'dispatchEvent']), |
| + 'Event': set(['initEvent', 'target', 'srcElement', 'currentTarget']) |
| +} |
| + |
| +html_library_renames = { |
| + 'Document.createTextNode': 'Text.Text', |
| + 'Document.get:defaultView': 'Document.get:window', |
| + 'DocumentFragment.querySelector': 'Element.query', |
| + 'Element.querySelector': 'Element.query', |
| + 'Document.querySelector': 'Element.query', |
| + 'DocumentFragment.querySelectorAll': 'Element.queryAll', |
| + 'DocumentFragment.querySelectorAll': 'Element.queryAll', |
| + 'Element.querySelectorAll': 'Element.queryAll', |
| + 'Element.scrollIntoViewIfNeeded': 'Element.scrollIntoView', |
| + 'Node.cloneNode': 'Node.clone', |
| + 'Node.get:nextSibling': 'Node.get:nextNode', |
| + 'Node.get:ownerDocument': 'Node.get:document', |
| + 'Node.get:parentNode': 'Node.get:parent', |
| + 'Node.get:previousSibling': 'Node.get:previousNode', |
| +} |
| + |
| +# TODO(jacobr): cleanup and augment this list. |
| +_html_library_remove = set([ |
|
sra1
2012/02/16 04:43:28
These tables are pretty huge.
Could you get a smal
Jacob
2012/02/17 00:44:23
Done.
|
| + 'Window.get:document', # Removed as we have a custom implementation. |
| + 'NodeList.item', |
| + "Attr.*", |
|
sra1
2012/02/16 04:43:28
Does this work?
Jacob
2012/02/17 00:44:23
Added a TODO. only parts of this table of stuff g
|
| +# "BarProp.*", |
| +# "BarInfo.*", |
| +# "Blob.webkitSlice", |
| +# "CDATASection.*", |
| +# "Comment.*", |
| +# "DOMImplementation.*", |
| + # TODO(jacobr): listing title here is a temporary hack due to a frog bug |
| + # involving when an interface inherits from another interface and defines |
| + # the same field. |
|
sra1
2012/02/16 04:43:28
This should be fixed - can you try it?
Jacob
2012/02/17 00:44:23
listed the bug# in the TODO
|
| + "Document.get:title", |
| + "Document.set:title", |
| + "Element.get:title", |
| + "Element.set:title", |
| + "Document.get:documentElement", |
| + "Document.get:forms", |
| +# "Document.get:selectedStylesheetSet", |
| +# "Document.set:selectedStylesheetSet", |
| +# "Document.get:preferredStylesheetSet", |
| + "Document.get:links", |
| + "Document.getElementsByTagName", |
| + "Document.set:domain", |
| + "Document.get:implementation", |
| + "Document.createAttributeNS", |
| + "Document.get:inputEncoding", |
| + "Document.getElementsByClassName", |
| + "Document.get:compatMode", |
| + "Document.importNode", |
| + "Document.evaluate", |
| + "Document.get:images", |
| + "Document.querySelector", |
| + "Document.createExpression", |
| + "Document.getOverrideStyle", |
| + "Document.get:xmlStandalone", |
| + "Document.set:xmlStandalone", |
| + "Document.createComment", |
| + "Document.adoptNode", |
| + "Document.get:characterSet", |
| + "Document.createAttribute", |
| + "Document.querySelectorAll", |
| + "Document.get:URL", |
| + "Document.createElementNS", |
| + "Document.createEntityReference", |
| + "Document.get:documentURI", |
| + "Document.set:documentURI", |
| + "Document.createNodeIterator", |
| + "Document.createProcessingInstruction", |
| + "Document.get:doctype", |
| + "Document.getElementsByName", |
| + "Document.createTreeWalker", |
| + "Document.get:location", |
| + "Document.set:location", |
| + "Document.createNSResolver", |
| + "Document.get:xmlEncoding", |
| + "Document.get:defaultCharset", |
| + "Document.get:applets", |
| + "Document.getSelection", |
| + "Document.get:xmlVersion", |
| + "Document.set:xmlVersion", |
| + "Document.get:anchors", |
| + "Document.getElementsByTagNameNS", |
| + "DocumentType.*", |
| + "Element.hasAttributeNS", |
| + "Element.getAttributeNS", |
| + "Element.setAttributeNode", |
| + "Element.getAttributeNode", |
| + "Element.removeAttributeNode", |
| + "Element.removeAttributeNS", |
| + "Element.setAttributeNodeNS", |
| + "Element.getAttributeNodeNS", |
| + "Element.setAttributeNS", |
| +# "EventSource.get:url", |
| +# TODO(jacobr): should these be removed? |
| + "Document.close", |
| + "Document.hasFocus", |
| + |
| + "Document.get:vlinkColor", |
| + "Document.set:vlinkColor", |
| + "Document.captureEvents", |
| + "Document.releaseEvents", |
| + "Document.get:compatMode", |
| + "Document.get:designMode", |
| + "Document.set:designMode", |
| + "Document.get:dir", |
| + "Document.set:dir", |
| + "Document.get:all", |
| + "Document.set:all", |
| + "Document.write", |
| + "Document.get:fgColor", |
| + "Document.set:fgColor", |
| + "Document.get:bgColor", |
| + "Document.set:bgColor", |
| + "Document.get:plugins", |
| + "Document.get:alinkColor", |
| + "Document.set:alinkColor", |
| + "Document.get:embeds", |
| + "Document.open", |
| + "Document.clear", |
| + "Document.get:scripts", |
| + "Document.writeln", |
| + "Document.get:linkColor", |
| + "Document.set:linkColor", |
| + "Element.get:itemRef", |
| + "Element.set:className", |
| + "Element.get:outerText", |
| + "Element.set:outerText", |
| + "Element.get:accessKey", |
| + "Element.set:accessKey", |
| + "Element.get:itemType", |
| + "Element.get:innerText", |
| + "Element.set:innerText", |
| + "Element.set:outerHTML", |
| + "Element.get:itemScope", |
| + "Element.set:itemScope", |
| + "Element.get:itemValue", |
| + "Element.set:itemValue", |
| + "Element.get:itemId", |
| + "Element.set:itemId", |
| + "Element.get:itemProp", |
| + "EmbedElement.getSVGDocument", |
| + "FormElement.get:elements", |
| + "HTMLFrameElement.*", |
| + "HTMLFrameSetElement.*", |
| + "HTMLHtmlElement.get:version", |
| + "HTMLHtmlElement.set:version", |
| +# "IFrameElement.getSVGDocument", #TODO(jacobr): should this be removed |
| + "InputElement.get:dirName", |
| + "InputElement.set:dirName", |
| + "HTMLIsIndexElement.*", |
| + "ObjectElement.getSVGDocument", |
| + "HTMLOptionsCollection.*", |
| + "HTMLPropertiesCollection.*", |
| + "SelectElement.remove", |
| + "TextAreaElement.get:dirName", |
| + "TextAreaElement.set:dirName", |
| + "NamedNodeMap.*", |
| + "Node.isEqualNode", |
| + "Node.get:TEXT_NODE", |
| + "Node.hasAttributes", |
| + "Node.get:DOCUMENT_TYPE_NODE", |
| + "Node.get:DOCUMENT_POSITION_FOLLOWING", |
| + "Node.get:childNodes", |
| + "Node.lookupNamespaceURI", |
| + "Node.get:ELEMENT_NODE", |
| + "Node.get:namespaceURI", |
| + "Node.get:DOCUMENT_FRAGMENT_NODE", |
| + "Node.get:localName", |
| + "Node.dispatchEvent", |
| + "Node.isDefaultNamespace", |
| + "Node.compareDocumentPosition", |
| + "Node.get:baseURI", |
| + "Node.isSameNode", |
| + "Node.get:DOCUMENT_POSITION_DISCONNECTED", |
| + "Node.get:DOCUMENT_NODE", |
| + "Node.get:DOCUMENT_POSITION_CONTAINS", |
| + "Node.get:COMMENT_NODE", |
| + "Node.get:ENTITY_REFERENCE_NODE", |
| + "Node.isSupported", |
| + "Node.get:firstChild", |
| + "Node.get:DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC", |
| + "Node.get:lastChild", |
| + "Node.get:attributes", |
| + "Node.get:NOTATION_NODE", |
| + "Node.normalize", |
| + "Node.get:parentElement", |
| + "Node.get:ATTRIBUTE_NODE", |
| + "Node.get:ENTITY_NODE", |
| + "Node.get:DOCUMENT_POSITION_CONTAINED_BY", |
| + "Node.get:prefix", |
| + "Node.set:prefix", |
| + "Node.get:DOCUMENT_POSITION_PRECEDING", |
| + "Node.get:nodeType", |
| + "Node.removeEventListener", |
| + "Node.get:nodeValue", |
| + "Node.set:nodeValue", |
| + "Node.get:CDATA_SECTION_NODE", |
| + "Node.get:nodeName", |
| + "Node.addEventListener", |
| + "Node.lookupPrefix", |
| + "Node.get:PROCESSING_INSTRUCTION_NODE", |
| + "Notification.dispatchEvent", |
| + "Notification.addEventListener", |
| + "Notification.removeEventListener"]) |
| + |
| +# Events without onEventName attributes in the IDL we want to support. |
| +_html_manual_events = { |
| + 'Element': ['touchleave', 'webkitTransitionEnd'], |
| + 'Window': ['DOMContentLoaded'] |
| +} |
| + |
| +# Sadly these event names must be camel case when attaching event listeners |
| +# using addEventListener even though the onEventName properties in the DOM for |
| +# them are not camel case. |
| +_on_attribute_to_event_name_mapping = { |
| + 'webkitanimationend': 'webkitAnimationEnd', |
| + 'webkitanimationiteration': 'webkitAnimationIteration', |
| + 'webkitanimationstart': 'webkitAnimationStart', |
| + 'webkitfullscreenchange': 'webkitFullScreenChange', |
| + 'webkitfullscreenerror': 'webkitFullScreenError', |
| + 'webkitspeechchange': 'webkitSpeechChange', |
| + 'webkittransitionend': 'webkitTransitionEnd', |
| +} |
| + |
| +_html_event_names = { |
| + 'DOMContentLoaded': 'contentLoaded', |
| + 'touchleave': 'touchLeave', |
| + 'abort': 'abort', |
| + 'beforecopy': 'beforeCopy', |
| + 'beforecut': 'beforeCut', |
| + 'beforepaste': 'beforePaste', |
| + 'beforeunload': 'beforeUnload', |
| + 'blur': 'blur', |
| + 'cached': 'cached', |
| + 'canplay': 'canPlay', |
| + 'canplaythrough': 'canPlayThrough', |
| + 'change': 'change', |
| + 'checking': 'checking', |
| + 'click': 'click', |
| + 'close': 'close', |
| + 'contextmenu': 'contextMenu', |
| + 'copy': 'copy', |
| + 'cut': 'cut', |
| + 'dblclick': 'doubleClick', |
| + 'devicemotion': 'deviceMotion', |
| + 'deviceorientation': 'deviceOrientation', |
| + 'display': 'display', |
| + 'downloading': 'downloading', |
| + 'drag': 'drag', |
| + 'dragend': 'dragEnd', |
| + 'dragenter': 'dragEnter', |
| + 'dragleave': 'dragLeave', |
| + 'dragover': 'dragOver', |
| + 'dragstart': 'dragStart', |
| + 'drop': 'drop', |
| + 'durationchange': 'durationChange', |
| + 'emptied': 'emptied', |
| + 'ended': 'ended', |
| + 'error': 'error', |
| + 'focus': 'focus', |
| + 'hashchange': 'hashChange', |
| + 'input': 'input', |
| + 'invalid': 'invalid', |
| + 'keydown': 'keyDown', |
| + 'keypress': 'keyPress', |
| + 'keyup': 'keyUp', |
| + 'load': 'load', |
| + 'loadeddata': 'loadedData', |
| + 'loadedmetadata': 'loadedMetadata', |
| + 'loadend': 'loadEnd', |
| + 'loadstart': 'loadStart', |
| + 'message': 'message', |
| + 'mousedown': 'mouseDown', |
| + 'mousemove': 'mouseMove', |
| + 'mouseout': 'mouseOut', |
| + 'mouseover': 'mouseOver', |
| + 'mouseup': 'mouseUp', |
| + 'mousewheel': 'mouseWheel', |
| + 'noupdate': 'noUpdate', |
| + 'obsolete': 'obsolete', |
| + 'offline': 'offline', |
| + 'online': 'online', |
| + 'open': 'open', |
| + 'pagehide': 'pageHide', |
| + 'pageshow': 'pageShow', |
| + 'paste': 'paste', |
| + 'pause': 'pause', |
| + 'play': 'play', |
| + 'playing': 'playing', |
| + 'popstate': 'popState', |
| + 'progress': 'progress', |
| + 'ratechange': 'rateChange', |
| + 'readystatechange': 'readyStateChange', |
| + 'reset': 'reset', |
| + 'resize': 'resize', |
| + 'scroll': 'scroll', |
| + 'search': 'search', |
| + 'seeked': 'seeked', |
| + 'seeking': 'seeking', |
| + 'select': 'select', |
| + 'selectionchange': 'selectionChange', |
| + 'selectstart': 'selectStart', |
| + 'show': 'show', |
| + 'stalled': 'stalled', |
| + 'storage': 'storage', |
| + 'submit': 'submit', |
| + 'suspend': 'suspend', |
| + 'timeupdate': 'timeUpdate', |
| + 'touchcancel': 'touchCancel', |
| + 'touchend': 'touchEnd', |
| + 'touchmove': 'touchMove', |
| + 'touchstart': 'touchStart', |
| + 'unload': 'unload', |
| + 'updateready': 'updateReady', |
| + 'volumechange': 'volumeChange', |
| + 'waiting': 'waiting', |
| + 'webkitAnimationEnd': 'animationEnd', |
| + 'webkitAnimationIteration': 'animationIteration', |
| + 'webkitAnimationStart': 'animationStart', |
| + 'webkitFullScreenChange': 'fullScreenChange', |
| + 'webkitFullScreenError': 'fullScreenError', |
| + 'webkitSpeechChange': 'speechChange', |
| + 'webkitTransitionEnd': 'transitionEnd' |
| +} |
| # |
| # Identifiers that are used in the IDL than need to be treated specially because |
| @@ -125,6 +467,12 @@ _alternate_methods = { |
| ('WheelEvent', 'initWheelEvent'): ['initWebKitWheelEvent', 'initWheelEvent'] |
| } |
| +def _OnAttributeToEventName(on_method): |
| + event_name = on_method.id[2:] |
| + if event_name in _on_attribute_to_event_name_mapping: |
| + return _on_attribute_to_event_name_mapping[event_name] |
| + else: |
| + return event_name |
| def _MatchSourceFilter(filter, thing): |
| if not filter: |
| @@ -203,7 +551,7 @@ class DartGenerator(object): |
| self._auxiliary_files[name] = os.path.join(dirname, name) |
| os.path.walk(self._auxiliary_dir, Visitor, None) |
| - def RenameTypes(self, database, conversion_table=None): |
| + def RenameTypes(self, database, conversion_table, rename_native_names): |
| """Renames interfaces using the given conversion table. |
| References through all interfaces will be renamed as well. |
| @@ -215,18 +563,23 @@ class DartGenerator(object): |
| if conversion_table is None: |
| conversion_table = {} |
| - |
| + |
| # Rename interfaces: |
| for old_name, new_name in conversion_table.items(): |
| if database.HasInterface(old_name): |
| - _logger.info('renaming interface %s to %s' % |
| - (old_name, new_name)) |
| + _logger.info('renaming interface %s to %s' % (old_name, new_name)) |
| interface = database.GetInterface(old_name) |
| database.DeleteInterface(old_name) |
| if not database.HasInterface(new_name): |
| interface.id = new_name |
| database.AddInterface(interface) |
| - |
| + else: |
| + new_interface = database.GetInterface(new_name) |
| + new_interface.merge(interface) |
| + |
| + interface.native_name = (old_name if rename_native_names |
| + else new_name) |
| + |
| # Fix references: |
| for interface in database.GetInterfaces(): |
| for idl_type in interface.all(idlnode.IDLType): |
| @@ -349,7 +702,8 @@ class DartGenerator(object): |
| def Generate(self, database, output_dir, |
| module_source_preference=[], source_filter=None, |
| super_database=None, common_prefix=None, super_map={}, |
| - lib_dir=None, systems=[]): |
| + html_map={}, lib_dir=None, systems=[], |
| + generate_html_systems=False): |
|
sra1
2012/02/16 04:43:28
We are passing 'systems' and 'generate_html_system
Jacob
2012/02/17 00:44:23
done
|
| """Generates Dart and JS files for the loaded interfaces. |
| Args: |
| @@ -377,14 +731,15 @@ class DartGenerator(object): |
| self._systems = [] |
| # TODO(jmesserly): only create these if needed |
| - interface_system = InterfacesSystem( |
| - TemplateLoader(self._template_dir, ['dom/interface', 'dom', '']), |
| - self._database, self._emitters, self._output_dir) |
| - self._systems.append(interface_system) |
| + if not generate_html_systems: |
| + interface_system = InterfacesSystem( |
| + TemplateLoader(self._template_dir, ['dom/interface', 'dom', '']), |
| + self._database, self._emitters, self._output_dir) |
| + self._systems.append(interface_system) |
| html_interface_system = HtmlInterfacesSystem( |
|
sra1
2012/02/16 04:43:28
Is this needed when 'not generate_html_systems' is
Jacob
2012/02/17 00:44:23
Nope. Done.
|
| TemplateLoader(self._template_dir, ['html/interface', 'html', '']), |
| - self._database, self._emitters, self._output_dir) |
| + self._database, self._emitters, self._output_dir, self) |
| self._systems.append(html_interface_system) |
| if 'native' in systems: |
| @@ -426,7 +781,7 @@ class DartGenerator(object): |
| if 'htmlfrog' in systems: |
| html_system = HtmlFrogSystem( |
| TemplateLoader(self._template_dir, ['html/frog', 'html', '']), |
| - self._database, self._emitters, self._output_dir) |
| + self._database, self._emitters, self._output_dir, self) |
| html_system._interface_system = html_interface_system |
| self._systems.append(html_system) |
| @@ -434,12 +789,11 @@ class DartGenerator(object): |
| if 'htmldartium' in systems: |
| html_system = HtmlDartiumSystem( |
| TemplateLoader(self._template_dir, ['html/dartium', 'html', '']), |
| - self._database, self._emitters, self._output_dir) |
| + self._database, self._emitters, self._output_dir, self) |
| html_system._interface_system = html_interface_system |
| self._systems.append(html_system) |
| - |
| # Collect interfaces |
| interfaces = [] |
| for interface in database.GetInterfaces(): |
| @@ -539,8 +893,15 @@ class DartGenerator(object): |
| for generator in generators: |
| generator.AddAttribute(getter, setter) |
| - events = _PairUpAttributes([attr for attr in interface.attributes |
| + events = set([_OnAttributeToEventName(attr) for attr in interface.attributes |
| if self._IsEventAttribute(interface, attr)]) |
| + |
| + if interface.id in _html_manual_events: |
| + for manual_event_name in _html_manual_events[interface.id]: |
|
sra1
2012/02/16 04:43:28
Move this _html specific code into the generator.
Jacob
2012/02/17 00:44:23
Done.
|
| + events.add(manual_event_name) |
| + |
| + events = sorted(events, key=lambda name: _html_event_names[name]) |
| + |
| if events: |
| for generator in generators: |
| generator.AddEventAttributes(events) |
| @@ -551,7 +912,6 @@ class DartGenerator(object): |
| if element_type: |
| for generator in generators: |
| generator.AddIndexer(element_type) |
| - |
| # Group overloaded operations by id |
| operationsById = {} |
| for operation in interface.operations: |
| @@ -602,10 +962,8 @@ class DartGenerator(object): |
| def _IsEventAttribute(self, interface, attr): |
| # Remove EventListener attributes like 'onclick' when addEventListener |
| # is available. |
| - if attr.type.id == 'EventListener': |
| - if 'EventTarget' in self._AllImplementedInterfaces(interface): |
| - return True |
| - return False |
| + return (attr.type.id == 'EventListener' and |
| + 'EventTarget' in self._AllImplementedInterfaces(interface)) |
| def _TransitiveSecondaryParents(self, interface): |
| """Returns a list of all non-primary parents. |
| @@ -790,6 +1148,13 @@ class OperationInfo(object): |
| for (name, type, default) in args] |
| return self._FormatArgs(args, False) |
| + def ParametersNameDeclaration(self): |
|
sra1
2012/02/16 04:43:28
This is generating an argument list, no?
Then call
Jacob
2012/02/17 00:44:23
Done.
|
| + """Returns a formatted string declaring the parameters names. |
| + """ |
| + # TODO(jacobr) use lambda syntax. |
| + def FormatArg(arg_info): |
| + return arg_info[0] |
| + return ', '.join(map(FormatArg, self.arg_infos)) |
| def _FormatArgs(self, args, is_interface): |
| def FormatArg(arg_info): |
| @@ -1059,11 +1424,67 @@ class InterfacesSystem(System): |
| # ------------------------------------------------------------------------------ |
| -class HtmlInterfacesSystem(System): |
| +class HtmlSystem(System): |
| - def __init__(self, templates, database, emitters, output_dir): |
| - super(HtmlInterfacesSystem, self).__init__( |
| + def __init__(self, templates, database, emitters, output_dir, generator): |
| + super(HtmlSystem, self).__init__( |
| templates, database, emitters, output_dir) |
| + self._event_classes = set() |
| + self._seen_event_names = {} |
| + self._generator = generator |
| + |
| + def _AllowInHtmlLibrary(self, interface, member): |
| + if self._PrivateInHtmlLibrary(interface, member): |
| + return False |
| + for interface_name in ([interface.id] + |
| + self._generator._AllImplementedInterfaces(interface)): |
| + if interface.id + '.' + member in _html_library_remove: |
| + return False |
| + return True |
| + |
| + def _PrivateInHtmlLibrary(self, interface, member): |
| + for interface_name in ([interface.id] + |
| + self._generator._AllImplementedInterfaces(interface)): |
| + if (interface_name in _private_html_properties and |
| + member in _private_html_properties[interface_name]): |
| + return True |
| + return False |
| + |
| + # TODO(jacobr): this already exists |
| + def _TraverseParents(self, interface, callback): |
| + for parent in interface.parents: |
| + parent_id = parent.type.id |
| + if self._database.HasInterface(parent_id): |
| + parent_interface = self._database.GetInterface(parent_id) |
| + callback(parent_interface) |
| + self._TraverseParents(parent_interface, callback) |
| + |
| + # TODO(jacobr): this isn't quite right.... |
| + def _GetParentsEventsClasses(self, interface): |
| + # Ugly hack as we don't specify that Document inherits from Element |
| + # in our IDL. |
| + if interface.id == 'Document': |
| + return ['ElementEvents'] |
| + |
| + interfaces_with_events = set() |
| + def visit(parent): |
| + if parent.id in self._event_classes: |
| + interfaces_with_events.add(parent) |
| + |
| + self._TraverseParents(interface, visit) |
| + if len(interfaces_with_events) == 0: |
| + return ['Events'] |
| + else: |
| + names = [] |
| + for interface in interfaces_with_events: |
| + names.append(interface.id + 'Events') |
| + return names |
| + |
| +class HtmlInterfacesSystem(HtmlSystem): |
| + |
| + def __init__(self, templates, database, emitters, output_dir, generator): |
| + super(HtmlInterfacesSystem, self).__init__( |
| + templates, database, emitters, output_dir, generator) |
| self._dart_interface_file_paths = [] |
| def InterfaceGenerator(self, |
| @@ -1088,7 +1509,7 @@ class HtmlInterfacesSystem(System): |
| interface, dart_interface_code, |
| template, |
| common_prefix, super_interface_name, |
| - source_filter) |
| + source_filter, self) |
| def ProcessCallback(self, interface, info): |
| """Generates a typedef for the callback interface.""" |
| @@ -1243,13 +1664,14 @@ class FrogSystem(System): |
| # ------------------------------------------------------------------------------ |
| -class HtmlFrogSystem(System): |
| +class HtmlFrogSystem(HtmlSystem): |
| - def __init__(self, templates, database, emitters, output_dir): |
| + def __init__(self, templates, database, emitters, output_dir, generator): |
| super(HtmlFrogSystem, self).__init__( |
| - templates, database, emitters, output_dir) |
| + templates, database, emitters, output_dir, generator) |
| self._dart_frog_file_paths = [] |
| + |
| def InterfaceGenerator(self, |
| interface, |
| common_prefix, |
| @@ -1265,7 +1687,7 @@ class HtmlFrogSystem(System): |
| template = self._templates.Load('frog_impl.darttemplate') |
| dart_code = self._emitters.FileEmitter(dart_frog_file_path) |
| - return HtmlFrogInterfaceGenerator(self, interface, template, |
| + return HtmlFrogClassGenerator(self, interface, template, |
| super_interface_name, dart_code) |
| def GenerateLibraries(self, lib_dir): |
| @@ -1318,12 +1740,6 @@ class DartInterfaceGenerator(object): |
| else: |
| typename = self._interface.id |
| - # TODO(vsm): Add appropriate package / namespace syntax. |
| - (extends_emitter, |
| - self._members_emitter, |
| - self._top_level_emitter) = self._emitter.Emit( |
| - self._template + '$!TOP_LEVEL', |
| - ID=typename) |
| extends = [] |
| suppressed_extends = [] |
| @@ -1342,16 +1758,22 @@ class DartInterfaceGenerator(object): |
| (self._common_prefix, parent.type.id)) |
| comment = ' extends' |
| + extends_str = '' |
| if extends: |
| - extends_emitter.Emit(' extends $SUPERS', SUPERS=', '.join(extends)) |
| + extends_str += ' extends ' + ', '.join(extends) |
| comment = ',' |
| if suppressed_extends: |
| - extends_emitter.Emit(' /*$COMMENT $SUPERS */', |
| - COMMENT=comment, |
| - SUPERS=', '.join(suppressed_extends)) |
| + extends_str += ' /*%s %s */' % (comment, ', '.join(suppressed_extends)) |
| if typename in _interface_factories: |
| - extends_emitter.Emit(' default $F', F=_interface_factories[typename]) |
| + extends_str += ' default ' + _interface_factories[typename] |
| + |
| + # TODO(vsm): Add appropriate package / namespace syntax. |
| + (self._members_emitter, |
| + self._top_level_emitter) = self._emitter.Emit( |
| + self._template + '$!TOP_LEVEL', |
| + ID=typename, |
| + EXTENDS=extends_str) |
| element_type = MaybeTypedArrayElementType(self._interface) |
| if element_type: |
| @@ -1444,22 +1866,114 @@ class HtmlDartInterfaceGenerator(DartInterfaceGenerator): |
| """Generates Dart Interface definition for one DOM IDL interface.""" |
| def __init__(self, interface, emitter, template, |
| - common_prefix, super_interface, source_filter): |
| + common_prefix, super_interface, source_filter, system): |
| super(HtmlDartInterfaceGenerator, self).__init__(interface, |
| emitter, template, common_prefix, super_interface, source_filter) |
| + self._system = system |
| + |
| + def StartInterface(self): |
| + typename = self._interface.id |
| + |
| + extends = [] |
| + suppressed_extends = [] |
| + |
| + for parent in self._interface.parents: |
| + # TODO(vsm): Remove source_filter. |
| + if _MatchSourceFilter(self._source_filter, parent): |
| + # Parent is a DOM type. |
| + extends.append(parent.type.id) |
| + elif '<' in parent.type.id: |
| + # Parent is a Dart collection type. |
| + # TODO(vsm): Make this check more robust. |
| + extends.append(parent.type.id) |
| + else: |
| + suppressed_extends.append('%s.%s' % |
| + (self._common_prefix, parent.type.id)) |
| + |
| + comment = ' extends' |
| + extends_str = '' |
| + if extends: |
| + extends_str += ' extends ' + ', '.join(extends) |
| + comment = ',' |
| + if suppressed_extends: |
| + extends_str += ' /*%s %s */' % (comment, ', '.join(suppressed_extends)) |
| + |
| + if typename in _interface_factories: |
| + extends_str += ' default ' + _interface_factories[typename] |
| + |
| + # TODO(vsm): Add appropriate package / namespace syntax. |
| + (self._members_emitter, |
| + self._top_level_emitter) = self._emitter.Emit( |
| + self._template + '$!TOP_LEVEL', |
| + ID=typename, |
| + EXTENDS=extends_str) |
| + |
| + element_type = MaybeTypedArrayElementType(self._interface) |
| + if element_type: |
| + self._members_emitter.Emit( |
| + '\n' |
| + ' $CTOR(int length);\n' |
| + '\n' |
| + ' $CTOR.fromList(List<$TYPE> list);\n' |
| + '\n' |
| + ' $CTOR.fromBuffer(ArrayBuffer buffer);\n', |
| + CTOR=self._interface.id, |
| + TYPE=element_type) |
| + |
| + def AddAttribute(self, getter, setter): |
| + if getter and not self._system._AllowInHtmlLibrary(self._interface, 'get:' + getter.id): |
|
sra1
2012/02/16 04:43:28
Line length
Jacob
2012/02/17 00:44:23
Done.
|
| + getter = None |
| + if setter and not self._system._AllowInHtmlLibrary(self._interface, 'set:' + setter.id): |
| + setter = None |
| + if not getter and not setter: |
| + return |
| + if getter and setter and getter.type.id == setter.type.id: |
| + self._members_emitter.Emit('\n $TYPE $NAME;\n', |
| + NAME=getter.id, TYPE=getter.type.id); |
| + return |
| + if getter and not setter: |
| + self._members_emitter.Emit('\n final $TYPE $NAME;\n', |
| + NAME=getter.id, TYPE=getter.type.id); |
| + return |
| + raise Exception('Unexpected getter/setter combination %s %s' % |
| + (getter, setter)) |
| + |
| + def AddOperation(self, info): |
| + """ |
| + Arguments: |
| + operations - contains the overloads, one or more operations with the same |
| + name. |
| + """ |
| + if self._system._AllowInHtmlLibrary(self._interface, info.name): |
| + self._members_emitter.Emit('\n' |
| + ' $TYPE $NAME($PARAMS);\n', |
| + TYPE=info.type_name, |
| + NAME=info.name, |
| + PARAMS=info.ParametersInterfaceDeclaration()) |
| + |
| + def FinishInterface(self): |
| + pass |
| + |
| + def AddConstant(self, constant): |
| + self._EmitConstant(self._members_emitter, constant) |
| def AddEventAttributes(self, event_attrs): |
| + self._system._event_classes.add(self._interface.id) |
| events_interface = self._interface.id + 'Events' |
| self._members_emitter.Emit('\n $TYPE get on();\n', |
| TYPE=events_interface) |
| events_members = self._emitter.Emit( |
| - '\ninterface $INTERFACE {\n$!MEMBERS}\n', |
| - INTERFACE=events_interface) |
| - |
| - for getter, setter in event_attrs: |
| - event = getter or setter |
| - events_members.Emit('\n EventListenerList get $NAME();\n', NAME=event.id) |
| - |
| + '\ninterface $INTERFACE extends $PARENTS {\n$!MEMBERS}\n', |
| + INTERFACE=events_interface, |
| + PARENTS=', '.join( |
| + self._system._GetParentsEventsClasses(self._interface))) |
| + |
| + for event_name in event_attrs: |
| + if event_name in _html_event_names: |
| + events_members.Emit('\n EventListenerList get $NAME();\n', |
| + NAME=_html_event_names[event_name]) |
| + else: |
| + raise Exception('No known html even name for event: ' + event_name) |
| # ------------------------------------------------------------------------------ |
| @@ -1987,7 +2501,7 @@ class FrogInterfaceGenerator(object): |
| def StartInterface(self): |
| interface = self._interface |
| interface_name = interface.id |
| - |
| + native_name = interface.native_name |
|
sra1
2012/02/16 04:43:28
Rather than 'rename' the interface.native_name, ca
Jacob
2012/02/17 00:44:23
discussed offline. this is needed.
changed name to
|
| self._class_name = self._ImplClassName(interface_name) |
| base = None |
| @@ -1999,8 +2513,8 @@ class FrogInterfaceGenerator(object): |
| else: |
| base = self._ImplClassName(supertype) |
| - if interface_name in _frog_dom_custom_native_specs: |
| - native_spec = _frog_dom_custom_native_specs[interface_name] |
| + if native_name in _frog_dom_custom_native_specs: |
| + native_spec = _frog_dom_custom_native_specs[native_name] |
| else: |
| # Make the class 'hidden' so it is dynamically patched at runtime. This |
| # is useful not only for browser compat, but to allow code that links |
| @@ -2241,36 +2755,220 @@ class FrogInterfaceGenerator(object): |
| # TODO(jmesserly): inheritance is probably not the right way to factor this long |
| # term, but it makes merging better for now. |
| -class HtmlFrogInterfaceGenerator(FrogInterfaceGenerator): |
| +class HtmlFrogClassGenerator(FrogInterfaceGenerator): |
| """Generates a Frog class for the dart:html library from a DOM IDL |
| interface. |
| """ |
| def __init__(self, system, interface, template, super_interface, dart_code): |
| - super(HtmlFrogInterfaceGenerator, self).__init__( |
| + super(HtmlFrogClassGenerator, self).__init__( |
| system, interface, template, super_interface, dart_code) |
| + |
| + def StartInterface(self): |
| + interface = self._interface |
| + interface_name = interface.id |
| + native_interface_name = interface.native_name |
| + |
| + self._class_name = self._ImplClassName(interface_name) |
| + |
| + base = None |
| + if interface.parents: |
| + supertype = interface.parents[0].type.id |
| + # FIXME: We're currently injecting List<..> and EventTarget as |
| + # supertypes in dart.idl. We should annotate/preserve as |
| + # attributes instead. For now, this hack lets the interfaces |
| + # inherit, but not the classes. |
| + if (not _IsDartListType(supertype) and |
| + not supertype == 'EventTarget'): |
| + base = self._ImplClassName(supertype) |
| + if _IsDartCollectionType(supertype): |
| + # List methods are injected in AddIndexer. |
| + pass |
| + elif supertype == 'EventTarget': |
| + # Most implementors of EventTarget specify the EventListener operations |
| + # again. If the operations are not specified, try to inherit from the |
| + # EventTarget implementation. |
| + # |
| + # Applies to MessagePort. |
| + if not [op for op in interface.operations if op.id == 'addEventListener']: |
| + base = self._ImplClassName(supertype) |
| + else: |
| + base = self._ImplClassName(supertype) |
| + |
| + if native_interface_name in _frog_dom_custom_native_specs: |
| + native_spec = _frog_dom_custom_native_specs[native_interface_name] |
| + else: |
| + # Make the class 'hidden' so it is dynamically patched at runtime. This |
| + # is useful not only for browser compat, but to allow code that links |
| + # against dart:dom to load in a worker isolate. |
| + native_spec = '*' + native_interface_name |
| + |
| + extends = ' extends ' + base if base else '' |
| + |
| + # TODO: Include all implemented interfaces, including other Lists. |
| + implements = [interface_name] |
| + element_type = MaybeTypedArrayElementType(self._interface) |
| + if element_type: |
| + implements.append('List<' + element_type + '>') |
| + |
| + self._members_emitter = self._dart_code.Emit( |
| + self._template, |
| + #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { |
| + #$!MEMBERS |
| + #} |
| + CLASSNAME=self._class_name, |
| + EXTENDS=extends, |
| + IMPLEMENTS=' implements ' + ', '.join(implements), |
| + NATIVESPEC=' native "' + native_spec + '"') |
| + |
| + element_type = MaybeTypedArrayElementType(interface) |
| + if element_type: |
| + self.AddTypedArrayConstructors(element_type) |
| + |
| + def AddAttribute(self, getter, setter): |
| + |
| + if self._system._PrivateInHtmlLibrary(self._interface, getter.id): |
| + if getter: |
| + self._AddGetter(getter, True) |
| + if setter: |
| + self._AddSetter(setter, True) |
|
sra1
2012/02/16 04:43:28
If you return after these two ifs you can drop the
Jacob
2012/02/17 00:44:23
Done
|
| + else: |
| + if getter and not self._system._AllowInHtmlLibrary(self._interface, 'get:' + getter.id): |
|
sra1
2012/02/16 04:43:28
Line length.
Jacob
2012/02/17 00:44:23
Done.
|
| + getter = None |
| + if setter and not self._system._AllowInHtmlLibrary(self._interface, 'set:' + setter.id): |
| + setter = None |
| + if not getter and not setter: |
| + return |
| + # If the (getter, setter) pair is shadowing, we can't generate a shadowing |
| + # field (Issue 1633). |
| + (super_getter, super_getter_interface) = self._FindShadowedAttribute(getter) |
| + (super_setter, super_setter_interface) = self._FindShadowedAttribute(setter) |
| + if super_getter or super_setter: |
| + if getter and not setter and super_getter and not super_setter: |
| + if getter.type.id == super_getter.type.id: |
| + # Compatible getter, use the superclass property. This works because |
| + # JavaScript will do its own dynamic dispatch. |
| + output_type = getter and self._NarrowOutputType(getter.type.id) |
| + self._members_emitter.Emit( |
| + '\n' |
| + ' // Use implementation from $SUPER.\n' |
| + ' // final $TYPE $NAME;\n', |
| + SUPER=super_getter_interface.id, |
| + NAME=getter.id, TYPE=output_type) |
| + return |
| + |
| + self._members_emitter.Emit('\n // Shadowing definition.') |
| + if getter: |
|
sra1
2012/02/16 04:43:28
I've seen this before.
Copy _AddAttributeUsingProp
Jacob
2012/02/17 00:44:23
Done.
|
| + self._AddGetter(getter, False) |
| + if setter: |
| + self._AddSetter(setter, False) |
| + return |
| + |
| + if self._interface.id != 'Document': |
| + output_type = getter and self._NarrowOutputType(getter.type.id) |
| + input_type = setter and self._NarrowInputType(setter.type.id) |
| + if getter and setter and input_type == output_type: |
| + self._members_emitter.Emit( |
| + '\n $TYPE $NAME;\n', |
| + NAME=getter.id, TYPE=output_type) |
| + return |
| + if getter and not setter: |
| + self._members_emitter.Emit( |
| + '\n final $TYPE $NAME;\n', |
| + NAME=getter.id, TYPE=output_type) |
| + return |
| + if getter: |
| + self._AddGetter(getter, False) |
| + if setter: |
| + self._AddSetter(setter, False) |
| + |
| + def _AddGetter(self, attr, private): |
| + # TODO(sra): Remove native body when Issue 829 fixed. |
| + self._members_emitter.Emit( |
| + '\n $TYPE get $PRIVATE$NAME() native "return $THIS.$NAME;";\n', |
| + NAME=attr.id, TYPE=self._NarrowOutputType(attr.type.id), |
| + PRIVATE='_' if private else '', |
| + THIS='this.parentNode' if self._interface.id == 'Document' else 'this' |
| + ) |
| + |
| + def _AddSetter(self, attr, private): |
| + # TODO(sra): Remove native body when Issue 829 fixed. |
| + self._members_emitter.Emit( |
| + '\n void set $PRIVATE$NAME($TYPE value) native "$THIS.$NAME = value;";\n', |
| + NAME=attr.id, TYPE=self._NarrowInputType(attr.type.id), |
| + PRIVATE='_' if private else '', |
| + THIS='this.parentNode' if self._interface.id == 'Document' else 'this') |
| + |
| + def AddOperation(self, info): |
| + """ |
| + Arguments: |
| + info: An OperationInfo object. |
| + """ |
| + private_in_html = self._system._PrivateInHtmlLibrary(self._interface, info.name) |
| + if private_in_html or self._interface.id == 'Document': |
| + # TODO(vsm): Handle overloads. |
| + # TODO(jacobr): handle document more efficiently for cases where any |
| + # document is fine. For example: use window.document instead of |
| + # this.parentNode. |
| + return_type = self._NarrowOutputType(info.type_name) |
| + self._members_emitter.Emit( |
| + '\n' |
| + ' $TYPE $PRIVATE$NAME($PARAMS) native "$(RETURN)$(THIS).$NAME($PARAMNAMES);";\n', |
|
sra1
2012/02/16 04:43:28
Line length.
Jacob
2012/02/17 00:44:23
Done.
|
| + TYPE=return_type, |
| + RETURN='' if return_type == 'void' else 'return ', |
| + NAME=info.name, |
| + PRIVATE='_' if private_in_html else '', |
| + THIS='this.parentNode' if self._interface.id == 'Document' else 'this', |
| + PARAMNAMES=info.ParametersNameDeclaration(), |
|
sra1
2012/02/16 04:43:28
ARGUMENTS=info.ParemetersAsArguments(),
Jacob
2012/02/17 00:44:23
Done.
|
| + PARAMS=info.ParametersImplementationDeclaration( |
| + lambda type_name: self._NarrowInputType(type_name))) |
| + elif self._system._AllowInHtmlLibrary(self._interface, info.name): |
| + # TODO(jacobr): this is duplicated from the parent class. |
| + self._members_emitter.Emit( |
| + '\n' |
| + ' $TYPE $NAME($PARAMS) native;\n', |
| + TYPE=self._NarrowOutputType(info.type_name), |
| + NAME=info.name, |
| + PARAMS=info.ParametersImplementationDeclaration( |
| + lambda type_name: self._NarrowInputType(type_name))) |
| + |
| def AddEventAttributes(self, event_attrs): |
| - events_class = self._interface.id + 'EventsImpl' |
| + events_class = '_' + self._interface.id + 'EventsImpl' |
| events_interface = self._interface.id + 'Events' |
| - self._members_emitter.Emit('\n $TYPE get on() =>\n new $TYPE(this);\n', |
| - TYPE=events_class) |
| + self._members_emitter.Emit('\n $TYPE get on() =>\n new $TYPE($EVENTTARGET);\n', |
|
sra1
2012/02/16 04:43:28
Line length. Break like so:
.....Emit(
Jacob
2012/02/17 00:44:23
Done.
|
| + TYPE=events_class, |
| + EVENTTARGET='_jsDocument' if self._interface.id == 'Document' else 'this') |
| + self._system._event_classes.add(self._interface.id) |
| + |
| + parent_event_classes = self._system._GetParentsEventsClasses( |
| + self._interface) |
| + if len(parent_event_classes) != 1: |
| + raise Exception('Only one parent event class allowed ' |
| + + self._interface.id) |
| + |
| + # TODO(jacobr): specify the type of _ptr as EventTarget |
| events_members = self._dart_code.Emit( |
| '\n' |
| - 'class $CLASSNAME extends EventsImplementation ' |
| + 'class $CLASSNAME extends $SUPER ' |
| 'implements $INTERFACE {\n' |
|
sra1
2012/02/16 04:43:28
Does this fit on above line?
Jacob
2012/02/17 00:44:23
Done.
|
| - ' $CLASSNAME(_ptr) : super._wrap(_ptr);\n' |
| + ' $CLASSNAME(_ptr) : super(_ptr);\n' |
| '$!MEMBERS}\n', |
| + TARGETCLASS=self._NarrowOutputType(self._interface.id), |
| CLASSNAME=events_class, |
| - INTERFACE=events_interface) |
| - |
| - for getter, setter in event_attrs: |
| - event = getter or setter |
| - events_members.Emit( |
| - "\n" |
| - "EventListenerList get $NAME() => _get('$NAME');\n", |
| - NAME=event.id) |
| + INTERFACE=events_interface, |
| + SUPER='_' + parent_event_classes[0] + 'Impl') |
| + |
| + for event_name in event_attrs: |
| + if event_name in _html_event_names: |
| + events_members.Emit( |
| + "\n" |
| + " EventListenerList get $NAME() => _get('$RAWNAME');\n", |
| + RAWNAME=event_name, |
| + NAME=_html_event_names[event_name]) |
| + else: |
| + raise Exception('No known html even name for event: ' + event_name) |
| # ------------------------------------------------------------------------------ |