| Index: client/dom/scripts/systemhtml.py
|
| diff --git a/client/dom/scripts/systemhtml.py b/client/dom/scripts/systemhtml.py
|
| index ead46709a530734e861fd436b91ca866a2b9954b..2259626f8a575e9be6bbcfc8a7a2304232b18e29 100644
|
| --- a/client/dom/scripts/systemhtml.py
|
| +++ b/client/dom/scripts/systemhtml.py
|
| @@ -6,55 +6,84 @@
|
| """This module provides shared functionality for the system to generate
|
| Dart:html APIs from the IDL database."""
|
|
|
| -import os
|
| -from generator import *
|
| -from systembase import *
|
| from systemfrog import *
|
| from systeminterface import *
|
|
|
| # Members from the standard dom that should not be exposed publicly in dart:html
|
| # but need to be exposed internally to implement dart:html on top of a standard
|
| # browser.
|
| -_private_html_members = {
|
| - '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'])
|
| -}
|
| +_private_html_members = set([
|
| + 'Element.clientLeft',
|
| + 'Element.clientTop',
|
| + 'Element.clientWidth',
|
| + 'Element.clientHeight',
|
| + 'Element.offsetLeft',
|
| + 'Element.offsetTop',
|
| + 'Element.offsetWidth',
|
| + 'Element.offsetHeight',
|
| + 'Element.scrollLeft',
|
| + 'Element.scrollTop',
|
| + 'Element.scrollWidth',
|
| + 'Element.scrollHeight',
|
| + 'Element.childElementCount',
|
| + 'Element.firstElementChild',
|
| + 'Element.hasAttribute',
|
| + 'Element.getAttribute',
|
| + 'Element.removeAttribute',
|
| + 'Element.setAttribute',
|
| + 'Element.className',
|
| + 'Element.children',
|
| + 'Element.querySelectorAll',
|
| + 'Document.querySelectorAll',
|
| + 'Element.getBoundingClientRect',
|
| + 'Element.getClientRects',
|
| + 'Node.appendChild',
|
| + 'Node.removeChild',
|
| + 'Node.replaceChild',
|
| + 'Node.attributes',
|
| + 'Node.childNodes',
|
| + 'Document.createElement',
|
| + 'Document.createEvent',
|
| + 'Document.createTextNode',
|
| + 'Document.createTouchList',
|
| + 'Window.getComputedStyle',
|
| + 'EventTarget.removeEventListener',
|
| + 'EventTarget.addEventListener',
|
| + 'EventTarget.dispatchEvent',
|
| + 'Event.initEvent',
|
| + 'MouseEvent.initMouseEvent',
|
| +])
|
|
|
| # Members from the standard dom that exist in the dart:html library with
|
| # identical functionality but with cleaner names.
|
| -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',
|
| +_html_library_renames = {
|
| + 'Document.defaultView': 'window',
|
| + 'DocumentFragment.querySelector': 'query',
|
| + 'Element.querySelector': 'query',
|
| + 'Element.webkitMatchesSelector' : 'matchesSelector',
|
| + 'Element.scrollIntoViewIfNeeded': 'scrollIntoView',
|
| + 'Document.querySelector': 'query',
|
| + 'DocumentFragment.querySelectorAll': 'queryAll',
|
| + 'DocumentFragment.querySelectorAll': 'queryAll',
|
| + 'Node.cloneNode': 'clone',
|
| + 'Node.nextSibling': 'nextNode',
|
| + 'Node.ownerDocument': 'document',
|
| + 'Node.parentNode': 'parent',
|
| + 'Node.previousSibling': 'previousNode',
|
| + 'Node.textContent': 'text',
|
| }
|
|
|
| +#TODO(jacobr): inject annotations into the interfaces based on this table and
|
| +# on _html_library_renames.
|
| +_injected_doc_fragments = {
|
| + 'Element.query': ' /** @domName querySelector, Document.getElementById */',
|
| +}
|
| # Members and classes from the dom that should be removed completelly from
|
| # dart:html. These could be expressed in the IDL instead but expressing this
|
| # as a simple table instead is more concise.
|
| +# Syntax is: ClassName.(get\.|set\.)?MemberName
|
| +# Using get: and set: is optional and should only be used when a getter needs
|
| +# to be suppressed but not the setter, etc.
|
| # TODO(jacobr): cleanup and augment this list.
|
| _html_library_remove = set([
|
| 'Window.get:document', # Removed as we have a custom implementation.
|
| @@ -69,10 +98,8 @@ _html_library_remove = set([
|
| # 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. BUG(1633)
|
| - "Document.get:title",
|
| - "Document.set:title",
|
| - "Element.get:title",
|
| - "Element.set:title",
|
| + "Document.title",
|
| + "Element.title",
|
| "Document.get:documentElement",
|
| "Document.get:forms",
|
| # "Document.get:selectedStylesheetSet",
|
| @@ -84,7 +111,11 @@ _html_library_remove = set([
|
| "Document.get:implementation",
|
| "Document.createAttributeNS",
|
| "Document.get:inputEncoding",
|
| + "Document.getElementById",
|
| "Document.getElementsByClassName",
|
| + "Element.getElementsByClassName",
|
| + "Element.getElementsByTagNameNS",
|
| + "Element.getElementsByTagName",
|
| "Document.get:compatMode",
|
| "Document.importNode",
|
| "Document.evaluate",
|
| @@ -92,8 +123,7 @@ _html_library_remove = set([
|
| "Document.querySelector",
|
| "Document.createExpression",
|
| "Document.getOverrideStyle",
|
| - "Document.get:xmlStandalone",
|
| - "Document.set:xmlStandalone",
|
| + "Document.xmlStandalone",
|
| "Document.createComment",
|
| "Document.adoptNode",
|
| "Document.get:characterSet",
|
| @@ -109,15 +139,13 @@ _html_library_remove = set([
|
| "Document.get:doctype",
|
| "Document.getElementsByName",
|
| "Document.createTreeWalker",
|
| - "Document.get:location",
|
| - "Document.set:location",
|
| + "Document.location",
|
| "Document.createNSResolver",
|
| "Document.get:xmlEncoding",
|
| "Document.get:defaultCharset",
|
| "Document.get:applets",
|
| "Document.getSelection",
|
| - "Document.get:xmlVersion",
|
| - "Document.set:xmlVersion",
|
| + "Document.xmlVersion",
|
| "Document.get:anchors",
|
| "Document.getElementsByTagNameNS",
|
| "DocumentType.*",
|
| @@ -130,77 +158,64 @@ _html_library_remove = set([
|
| "Element.setAttributeNodeNS",
|
| "Element.getAttributeNodeNS",
|
| "Element.setAttributeNS",
|
| + "BodyElement.text",
|
| + "AnchorElement.text",
|
| + "OptionElement.text",
|
| + "ScriptElement.text",
|
| + "TitleElement.text",
|
| # "EventSource.get:url",
|
| # TODO(jacobr): should these be removed?
|
| "Document.close",
|
| "Document.hasFocus",
|
|
|
| - "Document.get:vlinkColor",
|
| - "Document.set:vlinkColor",
|
| + "Document.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.designMode",
|
| + "Document.dir",
|
| + "Document.all",
|
| "Document.write",
|
| - "Document.get:fgColor",
|
| - "Document.set:fgColor",
|
| - "Document.get:bgColor",
|
| - "Document.set:bgColor",
|
| + "Document.fgColor",
|
| + "Document.bgColor",
|
| "Document.get:plugins",
|
| - "Document.get:alinkColor",
|
| - "Document.set:alinkColor",
|
| + "Document.alinkColor",
|
| "Document.get:embeds",
|
| "Document.open",
|
| "Document.clear",
|
| "Document.get:scripts",
|
| "Document.writeln",
|
| - "Document.get:linkColor",
|
| - "Document.set:linkColor",
|
| + "Document.linkColor",
|
| "Element.get:itemRef",
|
| - "Element.set:className",
|
| - "Element.get:outerText",
|
| - "Element.set:outerText",
|
| - "Element.get:accessKey",
|
| - "Element.set:accessKey",
|
| + "Element.outerText",
|
| + "Element.accessKey",
|
| "Element.get:itemType",
|
| - "Element.get:innerText",
|
| - "Element.set:innerText",
|
| + "Element.innerText",
|
| "Element.set:outerHTML",
|
| - "Element.get:itemScope",
|
| - "Element.set:itemScope",
|
| - "Element.get:itemValue",
|
| - "Element.set:itemValue",
|
| - "Element.get:itemId",
|
| - "Element.set:itemId",
|
| + "Element.itemScope",
|
| + "Element.itemValue",
|
| + "Element.itemId",
|
| "Element.get:itemProp",
|
| + 'Element.scrollIntoView',
|
| "EmbedElement.getSVGDocument",
|
| "FormElement.get:elements",
|
| "HTMLFrameElement.*",
|
| "HTMLFrameSetElement.*",
|
| - "HTMLHtmlElement.get:version",
|
| - "HTMLHtmlElement.set:version",
|
| + "HTMLHtmlElement.version",
|
| # "IFrameElement.getSVGDocument", #TODO(jacobr): should this be removed
|
| - "InputElement.get:dirName",
|
| - "InputElement.set:dirName",
|
| + "InputElement.dirName",
|
| "HTMLIsIndexElement.*",
|
| "ObjectElement.getSVGDocument",
|
| "HTMLOptionsCollection.*",
|
| "HTMLPropertiesCollection.*",
|
| "SelectElement.remove",
|
| - "TextAreaElement.get:dirName",
|
| - "TextAreaElement.set:dirName",
|
| + "TextAreaElement.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",
|
| @@ -220,7 +235,6 @@ _html_library_remove = set([
|
| "Node.get:firstChild",
|
| "Node.get:DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC",
|
| "Node.get:lastChild",
|
| - "Node.get:attributes",
|
| "Node.get:NOTATION_NODE",
|
| "Node.normalize",
|
| "Node.get:parentElement",
|
| @@ -259,8 +273,6 @@ _on_attribute_to_event_name_mapping = {
|
| 'webkitanimationend': 'webkitAnimationEnd',
|
| 'webkitanimationiteration': 'webkitAnimationIteration',
|
| 'webkitanimationstart': 'webkitAnimationStart',
|
| - 'webkitfullscreenchange': 'webkitFullScreenChange',
|
| - 'webkitfullscreenerror': 'webkitFullScreenError',
|
| 'webkitspeechchange': 'webkitSpeechChange',
|
| 'webkittransitionend': 'webkitTransitionEnd',
|
| }
|
| @@ -363,8 +375,8 @@ _html_event_names = {
|
| 'webkitAnimationEnd': 'animationEnd',
|
| 'webkitAnimationIteration': 'animationIteration',
|
| 'webkitAnimationStart': 'animationStart',
|
| - 'webkitFullScreenChange': 'fullScreenChange',
|
| - 'webkitFullScreenError': 'fullScreenError',
|
| + 'webkitfullscreenchange': 'fullscreenChange',
|
| + 'webkitfullscreenerror': 'fullscreenError',
|
| 'webkitSpeechChange': 'speechChange',
|
| 'webkitTransitionEnd': 'transitionEnd'
|
| }
|
| @@ -385,33 +397,67 @@ def _DomToHtmlEvents(interface_id, events):
|
| return sorted(event_names, key=lambda name: _html_event_names[name])
|
|
|
| # ------------------------------------------------------------------------------
|
| +class HtmlSystemShared(object):
|
|
|
| -class HtmlSystem(System):
|
| -
|
| - def __init__(self, templates, database, emitters, output_dir, generator):
|
| - super(HtmlSystem, self).__init__(
|
| - templates, database, emitters, output_dir)
|
| + def __init__(self, database, generator):
|
| self._event_classes = set()
|
| self._seen_event_names = {}
|
| + self._database = database
|
| 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 _AllowInHtmlLibrary(self, interface, member, member_prefix):
|
| + return not self._Matches(interface, member, member_prefix,
|
| + _html_library_remove)
|
|
|
| - def _PrivateInHtmlLibrary(self, interface, member):
|
| + def _Matches(self, interface, member, member_prefix, candidates):
|
| for interface_name in ([interface.id] +
|
| self._generator._AllImplementedInterfaces(interface)):
|
| - if (interface_name in _private_html_members and
|
| - member in _private_html_members[interface_name]):
|
| + if (DartType(interface_name) + '.' + member in candidates or
|
| + DartType(interface_name) + '.' + member_prefix + member in candidates):
|
| return True
|
| return False
|
|
|
| + def MaybeReturnDocument(self, return_type):
|
| + """
|
| + To make it appear that there are not a distinct Document and
|
| + HTMLHtmlElement (document.documentElement) objects we always use
|
| + documentElement instead of the regular document object so must not
|
| + allow a regular document to leak out.
|
| + """
|
| + # TODO(jacobr): any method that returns a Node could also theoretically
|
| + # really return a Document but there are alot of methods that return nodes
|
| + # and they all appear to be safe. Consider the alternate strategy of
|
| + # whitelisting just the known safe methods that return Nodes.
|
| + return (DartType(return_type) == 'EventTarget' or
|
| + DartType(return_type) == 'Document')
|
| +
|
| + def RenameInHtmlLibrary(self, interface, member, member_prefix=''):
|
| + """
|
| + Returns the name of the member in the HTML library or None if the member is
|
| + suppressed in the HTML library
|
| + """
|
| + if not self._AllowInHtmlLibrary(interface, member, member_prefix):
|
| + return None
|
| +
|
| + for interface_name in ([interface.id] +
|
| + self._generator._AllImplementedInterfaces(interface)):
|
| + name = interface.id + '.' + member
|
| + if name in _html_library_renames:
|
| + return _html_library_renames[name]
|
| + name = interface.id + '.' + member_prefix + member
|
| + if name in _html_library_renames:
|
| + return _html_library_renames[name]
|
| +
|
| + if self._PrivateInHtmlLibrary(interface, member, member_prefix):
|
| + return '_' + member
|
| +
|
| + # No rename required
|
| + return member
|
| +
|
| + def _PrivateInHtmlLibrary(self, interface, member, member_prefix):
|
| + return self._Matches(interface, member, member_prefix,
|
| + _private_html_members)
|
| +
|
| # TODO(jacobr): this already exists
|
| def _TraverseParents(self, interface, callback):
|
| for parent in interface.parents:
|
| @@ -422,7 +468,7 @@ class HtmlSystem(System):
|
| self._TraverseParents(parent_interface, callback)
|
|
|
| # TODO(jacobr): this isn't quite right....
|
| - def _GetParentsEventsClasses(self, interface):
|
| + def GetParentsEventsClasses(self, interface):
|
| # Ugly hack as we don't specify that Document inherits from Element
|
| # in our IDL.
|
| if interface.id == 'Document':
|
| @@ -442,6 +488,16 @@ class HtmlSystem(System):
|
| names.append(interface.id + 'Events')
|
| return names
|
|
|
| + def _ImplClassName(self, type_name):
|
| + return '_' + type_name + 'Impl'
|
| +
|
| +class HtmlSystem(System):
|
| +
|
| + def __init__(self, templates, database, emitters, output_dir, generator):
|
| + super(HtmlSystem, self).__init__(
|
| + templates, database, emitters, output_dir)
|
| + self._shared = HtmlSystemShared(database, generator)
|
| +
|
| class HtmlInterfacesSystem(HtmlSystem):
|
|
|
| def __init__(self, templates, database, emitters, output_dir, generator):
|
| @@ -471,7 +527,7 @@ class HtmlInterfacesSystem(HtmlSystem):
|
| interface, dart_interface_code,
|
| template,
|
| common_prefix, super_interface_name,
|
| - source_filter, self)
|
| + source_filter, self, self._shared)
|
|
|
| def ProcessCallback(self, interface, info):
|
| """Generates a typedef for the callback interface."""
|
| @@ -497,10 +553,11 @@ class HtmlDartInterfaceGenerator(DartInterfaceGenerator):
|
| """Generates Dart Interface definition for one DOM IDL interface."""
|
|
|
| def __init__(self, interface, emitter, template,
|
| - common_prefix, super_interface, source_filter, system):
|
| + common_prefix, super_interface, source_filter, system, shared):
|
| super(HtmlDartInterfaceGenerator, self).__init__(interface,
|
| emitter, template, common_prefix, super_interface, source_filter)
|
| self._system = system
|
| + self._shared = shared
|
|
|
| def StartInterface(self):
|
| typename = self._interface.id
|
| @@ -516,10 +573,10 @@ class HtmlDartInterfaceGenerator(DartInterfaceGenerator):
|
| elif '<' in parent.type.id:
|
| # Parent is a Dart collection type.
|
| # TODO(vsm): Make this check more robust.
|
| - extends.append(parent.type.id)
|
| + extends.append(DartType(parent.type.id))
|
| else:
|
| suppressed_extends.append('%s.%s' %
|
| - (self._common_prefix, parent.type.id))
|
| + (self._common_prefix, DartType(parent.type.id)))
|
|
|
| comment = ' extends'
|
| extends_str = ''
|
| @@ -552,21 +609,31 @@ class HtmlDartInterfaceGenerator(DartInterfaceGenerator):
|
| TYPE=DartType(element_type))
|
|
|
| def AddAttribute(self, getter, setter):
|
| - if getter and not self._system._AllowInHtmlLibrary(self._interface,
|
| - 'get:' + getter.id):
|
| + html_getter_name = self._shared.RenameInHtmlLibrary(
|
| + self._interface, getter.id, 'get:')
|
| + html_setter_name = self._shared.RenameInHtmlLibrary(
|
| + self._interface, getter.id, 'set:')
|
| +
|
| + if not html_getter_name:
|
| getter = None
|
| - if setter and not self._system._AllowInHtmlLibrary(self._interface,
|
| - 'set:' + setter.id):
|
| + if not html_setter_name:
|
| setter = None
|
| if not getter and not setter:
|
| return
|
| - if getter and setter and DartType(getter.type.id) == DartType(setter.type.id):
|
| +
|
| + # We don't yet handle inconsistent renames of the getter and setter yet.
|
| + if html_getter_name and html_setter_name:
|
| + assert html_getter_name == html_setter_name
|
| + if (getter and setter and
|
| + DartType(getter.type.id) == DartType(setter.type.id)):
|
| self._members_emitter.Emit('\n $TYPE $NAME;\n',
|
| - NAME=getter.id, TYPE=DartType(getter.type.id));
|
| + NAME=html_getter_name,
|
| + TYPE=DartType(getter.type.id));
|
| return
|
| if getter and not setter:
|
| self._members_emitter.Emit('\n final $TYPE $NAME;\n',
|
| - NAME=getter.id, TYPE=DartType(getter.type.id));
|
| + NAME=html_getter_name,
|
| + TYPE=DartType(getter.type.id));
|
| return
|
| raise Exception('Unexpected getter/setter combination %s %s' %
|
| (getter, setter))
|
| @@ -577,11 +644,12 @@ class HtmlDartInterfaceGenerator(DartInterfaceGenerator):
|
| operations - contains the overloads, one or more operations with the same
|
| name.
|
| """
|
| - if self._system._AllowInHtmlLibrary(self._interface, info.name):
|
| + html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
|
| + if html_name:
|
| self._members_emitter.Emit('\n'
|
| ' $TYPE $NAME($PARAMS);\n',
|
| - TYPE=info.type_name,
|
| - NAME=info.name,
|
| + TYPE=info.type_name,
|
| + NAME=html_name,
|
| PARAMS=info.ParametersInterfaceDeclaration())
|
|
|
| def FinishInterface(self):
|
| @@ -592,7 +660,7 @@ class HtmlDartInterfaceGenerator(DartInterfaceGenerator):
|
|
|
| def AddEventAttributes(self, event_attrs):
|
| event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
|
| - self._system._event_classes.add(self._interface.id)
|
| + self._shared._event_classes.add(self._interface.id)
|
| events_interface = self._interface.id + 'Events'
|
| self._members_emitter.Emit('\n $TYPE get on();\n',
|
| TYPE=events_interface)
|
| @@ -600,7 +668,7 @@ class HtmlDartInterfaceGenerator(DartInterfaceGenerator):
|
| '\ninterface $INTERFACE extends $PARENTS {\n$!MEMBERS}\n',
|
| INTERFACE=events_interface,
|
| PARENTS=', '.join(
|
| - self._system._GetParentsEventsClasses(self._interface)))
|
| + self._shared.GetParentsEventsClasses(self._interface)))
|
|
|
| for event_name in event_attrs:
|
| if event_name in _html_event_names:
|
| @@ -618,10 +686,14 @@ class HtmlFrogClassGenerator(FrogInterfaceGenerator):
|
| interface.
|
| """
|
|
|
| - def __init__(self, system, interface, template, super_interface, dart_code):
|
| + def __init__(self, system, interface, template, super_interface, dart_code,
|
| + shared):
|
| super(HtmlFrogClassGenerator, self).__init__(
|
| system, interface, template, super_interface, dart_code)
|
| + self._shared = shared
|
|
|
| + def _ImplClassName(self, type_name):
|
| + return self._shared._ImplClassName(type_name)
|
|
|
| def StartInterface(self):
|
| interface = self._interface
|
| @@ -632,24 +704,9 @@ class HtmlFrogClassGenerator(FrogInterfaceGenerator):
|
| 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)
|
|
|
| @@ -673,33 +730,90 @@ class HtmlFrogClassGenerator(FrogInterfaceGenerator):
|
| IMPLEMENTS=' implements ' + ', '.join(implements),
|
| NATIVESPEC=' native "' + native_spec + '"')
|
|
|
| - element_type = MaybeTypedArrayElementType(interface)
|
| if element_type:
|
| self.AddTypedArrayConstructors(element_type)
|
|
|
| + def AddIndexer(self, element_type):
|
| + """Adds all the methods required to complete implementation of List."""
|
| + # We would like to simply inherit the implementation of everything except
|
| + # get length(), [], and maybe []=. It is possible to extend from a base
|
| + # array implementation class only when there is no other implementation
|
| + # inheritance. There might be no implementation inheritance other than
|
| + # DOMBaseWrapper for many classes, but there might be some where the
|
| + # array-ness is introduced by a non-root interface:
|
| + #
|
| + # interface Y extends X, List<T> ...
|
| + #
|
| + # In the non-root case we have to choose between:
|
| + #
|
| + # class YImpl extends XImpl { add List<T> methods; }
|
| + #
|
| + # and
|
| + #
|
| + # class YImpl extends ListBase<T> { copies of transitive XImpl methods; }
|
| + #
|
| + self._members_emitter.Emit(
|
| + '\n'
|
| + ' $TYPE operator[](int index) native "return this[index];";\n',
|
| + TYPE=self._NarrowOutputType(element_type))
|
| +
|
| + if 'CustomIndexedSetter' in self._interface.ext_attrs:
|
| + self._members_emitter.Emit(
|
| + '\n'
|
| + ' void operator[]=(int index, $TYPE value) native "this[index] = value";\n',
|
| + TYPE=self._NarrowInputType(element_type))
|
| + else:
|
| + # The HTML library implementation of NodeList has a custom indexed setter
|
| + # implementation that uses the parent node the NodeList is associated
|
| + # with if one is available.
|
| + if self._interface.id != 'NodeList':
|
| + self._members_emitter.Emit(
|
| + '\n'
|
| + ' void operator[]=(int index, $TYPE value) {\n'
|
| + ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
|
| + ' }\n',
|
| + TYPE=self._NarrowInputType(element_type))
|
| +
|
| + # TODO(sra): Use separate mixins for mutable implementations of List<T>.
|
| + # TODO(sra): Use separate mixins for typed array implementations of List<T>.
|
| + if self._interface.id != 'NodeList':
|
| + template_file = 'immutable_list_mixin.darttemplate'
|
| + template = self._system._templates.Load(template_file)
|
| + self._members_emitter.Emit(template, E=DartType(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)
|
| - return
|
| - if getter and not self._system._AllowInHtmlLibrary(self._interface,
|
| - 'get:' + getter.id):
|
| + html_getter_name = self._shared.RenameInHtmlLibrary(
|
| + self._interface, getter.id, 'get:')
|
| + html_setter_name = self._shared.RenameInHtmlLibrary(
|
| + self._interface, getter.id, 'set:')
|
| +
|
| + if not html_getter_name:
|
| getter = None
|
| - if setter and not self._system._AllowInHtmlLibrary(self._interface,
|
| - 'set:' + setter.id):
|
| + if not html_setter_name:
|
| setter = None
|
| +
|
| if not getter and not setter:
|
| return
|
| +
|
| + if ((getter and (html_getter_name != getter.id or
|
| + self._shared.MaybeReturnDocument(getter.type.id))) or
|
| + (setter and (html_setter_name != setter.id or
|
| + self._shared.MaybeReturnDocument(setter.type.id))) or
|
| + self._interface.id == 'Document'):
|
| + if getter:
|
| + self._AddRenamingGetter(getter, html_getter_name)
|
| + if setter:
|
| + self._AddRenamingSetter(setter, html_setter_name)
|
| + 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:
|
| + if DartType(getter.type.id) == DartType(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)
|
| @@ -708,53 +822,71 @@ class HtmlFrogClassGenerator(FrogInterfaceGenerator):
|
| ' // Use implementation from $SUPER.\n'
|
| ' // final $TYPE $NAME;\n',
|
| SUPER=super_getter_interface.id,
|
| - NAME=getter.id, TYPE=output_type)
|
| + NAME=getter.id,
|
| + TYPE=output_type)
|
| return
|
|
|
| self._members_emitter.Emit('\n // Shadowing definition.')
|
| - if getter:
|
| - self._AddGetter(getter, False)
|
| - if setter:
|
| - self._AddSetter(setter, False)
|
| + self._AddAttributeUsingProperties(getter, setter)
|
| 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
|
| - self._AddAttributeUsingProperties(getter, setter, False)
|
| + 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
|
| + self._AddAttributeUsingProperties(getter, setter)
|
|
|
| - def _AddAttributeUsingProperties(self, getter, setter, private):
|
| + def _AddAttributeUsingProperties(self, getter, setter):
|
| if getter:
|
| - self._AddGetter(getter, private)
|
| + self._AddGetter(getter)
|
| if setter:
|
| - self._AddSetter(setter, private)
|
| + self._AddSetter(setter)
|
| +
|
| + def _AddGetter(self, attr):
|
| + self._AddRenamingGetter(attr, attr.id)
|
| +
|
| + def _AddSetter(self, attr):
|
| + self._AddRenamingSetter(attr, attr.id)
|
| +
|
| + def _AddRenamingGetter(self, attr, html_name):
|
| + return_type = self._NarrowOutputType(attr.type.id)
|
| + if self._shared.MaybeReturnDocument(attr.type.id):
|
| + self._members_emitter.Emit(
|
| + '\n $TYPE get $(HTML_NAME)() => '
|
| + '_FixHtmlDocumentReference(_$(HTML_NAME));\n',
|
| + HTML_NAME=html_name,
|
| + NAME=attr.id,
|
| + TYPE=return_type)
|
| + html_name = '_' + html_name
|
| + # For correctness this needs to be the return type of the native helper
|
| + # method due to the fact that the real HTMLDocument object is not typed
|
| + # as a document. TODO(jacobr): we could simplify this.
|
| + return_type = '_EventTargetImpl'
|
|
|
| - 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.
|
| + '\n $TYPE get $(HTML_NAME)() native "return $(THIS).$NAME;";\n',
|
| + HTML_NAME=html_name,
|
| + NAME=attr.id,
|
| + TYPE=return_type,
|
| + THIS='this.parentNode' if self._interface.id == 'Document' else 'this')
|
| +
|
| + def _AddRenamingSetter(self, attr, html_name):
|
| 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 '',
|
| + '\n void set $HTML_NAME($TYPE value)'
|
| + ' native "$(THIS).$NAME = value;";\n',
|
| + HTML_NAME=html_name,
|
| + NAME=attr.id,
|
| + TYPE=self._NarrowInputType(attr.type.id),
|
| THIS='this.parentNode' if self._interface.id == 'Document' else 'this')
|
|
|
| def AddOperation(self, info):
|
| @@ -762,29 +894,45 @@ class HtmlFrogClassGenerator(FrogInterfaceGenerator):
|
| 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.
|
| + html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
|
| + if not html_name:
|
| + return
|
| +
|
| + maybe_return_document = self._shared.MaybeReturnDocument(info.type_name)
|
| +
|
| + # Do we need a native body?
|
| + if (self._interface.id == 'Document' or # Need alternate 'this'
|
| + html_name != info.name or # renamed operation
|
| + maybe_return_document): # need to wrap value
|
| + # For example: use window.document instead of his.parentNode.
|
| return_type = self._NarrowOutputType(info.type_name)
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' $TYPE $PRIVATE$NAME($PARAMS)'
|
| - ' native "$(RETURN)$(THIS).$NAME($PARAMNAMES);";\n',
|
| +
|
| + operation_emitter = self._members_emitter.Emit('$!SCOPE',
|
| + THIS=('this.parentNode' if self._interface.id == 'Document'
|
| + else 'this'),
|
| TYPE=return_type,
|
| - RETURN='' if return_type == 'void' else 'return ',
|
| + HTML_NAME=html_name,
|
| NAME=info.name,
|
| - PRIVATE='_' if private_in_html else '',
|
| - THIS='this.parentNode' if self._interface.id == 'Document'
|
| - else 'this',
|
| + RETURN='' if return_type == 'void' else 'return ',
|
| PARAMNAMES=info.ParametersAsArgumentList(),
|
| 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.
|
| +
|
| + if maybe_return_document:
|
| + assert len(info.overloads) == 1
|
| + operation_emitter.Emit(
|
| + '\n'
|
| + ' $TYPE $(HTML_NAME)($PARAMS) => '
|
| + '_FixHtmlDocumentReference(_$(HTML_NAME)($PARAMNAMES));\n'
|
| + '\n'
|
| + ' _EventTargetImpl _$(HTML_NAME)($PARAMS)'
|
| + ' native "return $(THIS).$NAME($PARAMNAMES);";\n')
|
| + else:
|
| + operation_emitter.Emit(
|
| + '\n'
|
| + ' $TYPE $(HTML_NAME)($PARAMS)'
|
| + ' native "$(RETURN)$(THIS).$NAME($PARAMNAMES);";\n')
|
| + else:
|
| self._members_emitter.Emit(
|
| '\n'
|
| ' $TYPE $NAME($PARAMS) native;\n',
|
| @@ -803,9 +951,9 @@ class HtmlFrogClassGenerator(FrogInterfaceGenerator):
|
| EVENTTARGET='_jsDocument' if self._interface.id == 'Document'
|
| else 'this')
|
|
|
| - self._system._event_classes.add(self._interface.id)
|
| + self._shared._event_classes.add(self._interface.id)
|
|
|
| - parent_event_classes = self._system._GetParentsEventsClasses(
|
| + parent_event_classes = self._shared.GetParentsEventsClasses(
|
| self._interface)
|
| if len(parent_event_classes) != 1:
|
| raise Exception('Only one parent event class allowed '
|
| @@ -817,7 +965,6 @@ class HtmlFrogClassGenerator(FrogInterfaceGenerator):
|
| 'class $CLASSNAME extends $SUPER implements $INTERFACE {\n'
|
| ' $CLASSNAME(_ptr) : super(_ptr);\n'
|
| '$!MEMBERS}\n',
|
| - TARGETCLASS=self._NarrowOutputType(self._interface.id),
|
| CLASSNAME=events_class,
|
| INTERFACE=events_interface,
|
| SUPER='_' + parent_event_classes[0] + 'Impl')
|
| @@ -858,7 +1005,7 @@ class HtmlFrogSystem(HtmlSystem):
|
|
|
| dart_code = self._emitters.FileEmitter(dart_frog_file_path)
|
| return HtmlFrogClassGenerator(self, interface, template,
|
| - super_interface_name, dart_code)
|
| + super_interface_name, dart_code, self._shared)
|
|
|
| def GenerateLibraries(self, lib_dir):
|
| self._GenerateLibFile(
|
| @@ -877,16 +1024,83 @@ class HtmlFrogSystem(HtmlSystem):
|
| return os.path.join(self._output_dir, 'html', 'frog',
|
| '%s.dart' % interface_name)
|
|
|
| +# -----------------------------------------------------------------------------
|
| +
|
| +class HtmlDartiumSystem(HtmlSystem):
|
| +
|
| + def __init__(self, templates, database, emitters, output_dir, generator):
|
| + """Prepared for generating wrapping implementation.
|
| +
|
| + - Creates emitter for Dart code.
|
| + """
|
| + super(HtmlDartiumSystem, self).__init__(
|
| + templates, database, emitters, output_dir, generator)
|
| + self._shared = HtmlSystemShared(database, generator)
|
| + self._dart_dartium_file_paths = []
|
| + self._wrap_cases = []
|
| +
|
| + def InterfaceGenerator(self,
|
| + interface,
|
| + common_prefix,
|
| + super_interface_name,
|
| + source_filter):
|
| + """."""
|
| + dart_dartium_file_path = self._FilePathForImpl(interface.id)
|
| + self._dart_dartium_file_paths.append(dart_dartium_file_path)
|
| +
|
| + template_file = 'impl_%s.darttemplate' % interface.id
|
| + template = self._templates.TryLoad(template_file)
|
| + # TODO(jacobr): change this name as it is confusing.
|
| + if not template:
|
| + template = self._templates.Load('frog_impl.darttemplate')
|
| +
|
| + dart_code = self._emitters.FileEmitter(dart_dartium_file_path)
|
| + return HtmlDartiumInterfaceGenerator(self, interface, template,
|
| + super_interface_name, dart_code, self._BaseDefines(interface),
|
| + self._shared)
|
| +
|
| + def _FilePathForImpl(self, interface_name):
|
| + """Returns the file path of the Frog implementation."""
|
| + # TODO(jmesserly): is this the right path
|
| + return os.path.join(self._output_dir, 'html', 'dartium',
|
| + '%s.dart' % interface_name)
|
| +
|
| + def ProcessCallback(self, interface, info):
|
| + pass
|
| +
|
| + def GenerateLibraries(self, lib_dir):
|
| + # Library generated for implementation.
|
| + self._GenerateLibFile(
|
| + 'html_dartium.darttemplate',
|
| + os.path.join(lib_dir, 'html_dartium.dart'),
|
| + (self._interface_system._dart_interface_file_paths +
|
| + self._interface_system._dart_callback_file_paths +
|
| + # FIXME: Move the implementation to a separate library.
|
| + self._dart_dartium_file_paths
|
| + ),
|
| + WRAPCASES='\n'.join(self._wrap_cases))
|
| +
|
| + def Finish(self):
|
| + pass
|
| +
|
| # ------------------------------------------------------------------------------
|
|
|
| -class WrappingInterfaceGenerator(object):
|
| - """Generates Dart and JS implementation for one DOM IDL interface."""
|
| +# TODO(jacobr): there is far too much duplicated code between these bindings
|
| +# and the Frog bindings. A larger scale refactoring needs to be performed to
|
| +# reduce the duplicated logic.
|
| +class HtmlDartiumInterfaceGenerator(object):
|
| + """Generates a wrapper based implementation fo the HTML library that works
|
| + on Dartium. This is not intended to be the final solution for implementing
|
| + dart:html on Dartium. Eventually we should generate direct wrapperless
|
| + dart:html bindings that work on dartium."""
|
|
|
| - def __init__(self, interface, super_interface, dart_code, base_members):
|
| - """Generates Dart and JS code for the given interface.
|
| + def __init__(self, system, interface, template, super_interface, dart_code,
|
| + base_members, shared):
|
| + """Generates Dart wrapper code for the given interface.
|
|
|
| Args:
|
| -
|
| + system: system that is executing this generator.
|
| + template: template that output is generated into.
|
| interface: an IDLInterface instance. It is assumed that all types have
|
| been converted to Dart types (e.g. int, String), unless they are in
|
| the same package as the interface.
|
| @@ -896,52 +1110,99 @@ class WrappingInterfaceGenerator(object):
|
| class.
|
| base_members: a set of names of members defined in a base class. This is
|
| used to avoid static member 'overriding' in the generated Dart code.
|
| + shared: functionaly shared across all Html generators.
|
| """
|
| + self._system = system
|
| self._interface = interface
|
| self._super_interface = super_interface
|
| self._dart_code = dart_code
|
| self._base_members = base_members
|
| self._current_secondary_parent = None
|
| + self._shared = shared
|
| + self._template = template
|
| +
|
| + def DomObjectName(self):
|
| + return '_documentPtr' if self._interface.id == 'Document' else '_ptr'
|
| +
|
| + # TODO(jacobr): these 3 methods are duplicated.
|
| + def _NarrowToImplementationType(self, type_name):
|
| + # TODO(sra): Move into the 'system' and cache the result.
|
| + if type_name == 'EventListener':
|
| + # Callbacks are typedef functions so don't have a class.
|
| + return type_name
|
| + if self._system._database.HasInterface(type_name):
|
| + interface = self._system._database.GetInterface(type_name)
|
| + if RecognizeCallback(interface):
|
| + # Callbacks are typedef functions so don't have a class.
|
| + return type_name
|
| + else:
|
| + return self._ImplClassName(type_name)
|
| + return type_name
|
| +
|
| + def _NarrowInputType(self, type_name):
|
| + return self._NarrowToImplementationType(type_name)
|
|
|
| + def _NarrowOutputType(self, type_name):
|
| + return self._NarrowToImplementationType(type_name)
|
|
|
| def StartInterface(self):
|
| +
|
| interface = self._interface
|
| interface_name = interface.id
|
| -
|
| self._class_name = self._ImplClassName(interface_name)
|
|
|
| - base = self._BaseClassName(interface)
|
| + base = None
|
| + if interface.parents:
|
| + supertype = interface.parents[0].type.id
|
| + if not IsDartListType(supertype):
|
| + base = self._ImplClassName(supertype)
|
| + if IsDartCollectionType(supertype):
|
| + # List methods are injected in AddIndexer.
|
| + pass
|
| + else:
|
| + base = self._ImplClassName(supertype)
|
| +
|
| + # TODO(jacobr): this is fragile. There isn't a guarantee that dart:dom
|
| + # will continue to exactly match the IDL names.
|
| + dom_name = interface.javascript_binding_name
|
| + # We hard code the cases for these classes
|
| + if dom_name != 'HTMLHtmlElement' and dom_name != 'Document':
|
| + self._system._wrap_cases.append(
|
| + ' case "%s": return new %s._wrap(domObject);' %
|
| + (dom_name, self._class_name))
|
| +
|
| + extends = ' extends ' + base if base else ' extends _DOMTypeBase'
|
| +
|
| + # TODO: Include all implemented interfaces, including other Lists.
|
| + implements = [interface_name]
|
| + element_type = MaybeTypedArrayElementType(self._interface)
|
| + if element_type:
|
| + implements.append('List<' + DartType(element_type) + '>')
|
| + implements_str = ', '.join(implements)
|
|
|
| (self._members_emitter,
|
| self._top_level_emitter) = self._dart_code.Emit(
|
| - '\n'
|
| - 'class $CLASS extends $BASE implements $INTERFACE {\n'
|
| - ' $CLASS() : super() {}\n'
|
| - '\n'
|
| - ' static create_$CLASS() native {\n'
|
| - ' return new $CLASS();\n'
|
| - ' }\n'
|
| - '$!MEMBERS'
|
| - '\n'
|
| - ' String get typeName() { return "$INTERFACE"; }\n'
|
| - '}\n'
|
| - '$!TOP_LEVEL',
|
| - CLASS=self._class_name, BASE=base, INTERFACE=interface_name)
|
| + self._template + '$!TOP_LEVEL',
|
| + #class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
|
| + #$!MEMBERS
|
| + #}
|
| + NATIVESPEC='', # hack to make reusing the same templates work.
|
| + CLASSNAME=self._class_name,
|
| + EXTENDS=extends,
|
| + IMPLEMENTS=' implements ' + implements_str)
|
|
|
| - def _ImplClassName(self, type_name):
|
| - return '_' + type_name + 'WrappingImplementation'
|
| + # Document requires a custom wrapper.
|
| + if dom_name != 'Document':
|
| + self._members_emitter.Emit(
|
| + ' $(CLASSNAME)._wrap(ptr) : super._wrap(ptr);\n',
|
| + CLASSNAME=self._class_name)
|
|
|
| def _BaseClassName(self, interface):
|
| if not interface.parents:
|
| - return 'DOMWrapperBase'
|
| + return '_DOMTypeBase'
|
|
|
| - supertype = interface.parents[0].type.id
|
| + supertype = DartType(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.
|
| - # List methods are injected in AddIndexer.
|
| if IsDartListType(supertype) or IsDartCollectionType(supertype):
|
| return 'DOMWrapperBase'
|
|
|
| @@ -957,6 +1218,9 @@ class WrappingInterfaceGenerator(object):
|
|
|
| return self._ImplClassName(supertype)
|
|
|
| + def _ImplClassName(self, type_name):
|
| + return self._shared._ImplClassName(type_name)
|
| +
|
| def FinishInterface(self):
|
| """."""
|
| pass
|
| @@ -972,30 +1236,43 @@ class WrappingInterfaceGenerator(object):
|
| return method_name
|
|
|
| def AddAttribute(self, getter, setter):
|
| - if getter:
|
| - self._AddGetter(getter)
|
| - if setter:
|
| - self._AddSetter(setter)
|
| -
|
| - def _AddGetter(self, attr):
|
| - # FIXME: Instead of injecting the interface name into the method when it is
|
| - # also implemented in the base class, suppress the method altogether if it
|
| - # has the same signature. I.e., let the JS do the virtual dispatch instead.
|
| - method_name = self._MethodName('_get_', attr.id)
|
| - self._members_emitter.Emit(
|
| + html_getter_name = self._shared.RenameInHtmlLibrary(
|
| + self._interface, getter.id, 'get:')
|
| + html_setter_name = self._shared.RenameInHtmlLibrary(
|
| + self._interface, getter.id, 'set:')
|
| +
|
| + if getter and html_getter_name:
|
| + self._AddGetter(getter, html_getter_name)
|
| + if setter and html_setter_name:
|
| + self._AddSetter(setter, html_setter_name)
|
| +
|
| + def _AddGetter(self, attr, html_name):
|
| + if self._shared.MaybeReturnDocument(attr.type.id):
|
| + self._members_emitter.Emit(
|
| + '\n'
|
| + ' $TYPE get $(HTML_NAME)() => '
|
| + '_FixHtmlDocumentReference(_wrap($(THIS).$NAME));\n',
|
| + NAME=attr.id,
|
| + HTML_NAME=html_name,
|
| + TYPE=DartType(attr.type.id),
|
| + THIS=self.DomObjectName())
|
| + else:
|
| + self._members_emitter.Emit(
|
| '\n'
|
| - ' $TYPE get $NAME() { return $METHOD(this); }\n'
|
| - ' static $TYPE $METHOD(var _this) native;\n',
|
| - NAME=attr.id, TYPE=attr.type.id, METHOD=method_name)
|
| + ' $TYPE get $(HTML_NAME)() => _wrap($(THIS).$NAME);\n',
|
| + NAME=attr.id,
|
| + HTML_NAME=html_name,
|
| + TYPE=DartType(attr.type.id),
|
| + THIS=self.DomObjectName())
|
|
|
| - def _AddSetter(self, attr):
|
| - # FIXME: See comment on getter.
|
| - method_name = self._MethodName('_set_', attr.id)
|
| + def _AddSetter(self, attr, html_name):
|
| self._members_emitter.Emit(
|
| '\n'
|
| - ' void set $NAME($TYPE value) { $METHOD(this, value); }\n'
|
| - ' static void $METHOD(var _this, $TYPE value) native;\n',
|
| - NAME=attr.id, TYPE=attr.type.id, METHOD=method_name)
|
| + ' void set $(HTML_NAME)($TYPE value) { $(THIS).$NAME = _unwrap(value); }\n',
|
| + NAME=attr.id,
|
| + HTML_NAME=html_name,
|
| + TYPE=DartType(attr.type.id),
|
| + THIS=self.DomObjectName())
|
|
|
| def AddSecondaryAttribute(self, interface, getter, setter):
|
| self._SecondaryContext(interface)
|
| @@ -1006,13 +1283,53 @@ class WrappingInterfaceGenerator(object):
|
| self.AddOperation(info)
|
|
|
| def AddEventAttributes(self, event_attrs):
|
| - pass
|
| + event_attrs = _DomToHtmlEvents(self._interface.id, event_attrs)
|
| + events_class = '_' + self._interface.id + 'EventsImpl'
|
| + events_interface = self._interface.id + 'Events'
|
| + self._members_emitter.Emit(
|
| + '\n'
|
| + ' $TYPE get on() {\n'
|
| + ' if (_on == null) _on = new $TYPE($EVENTTARGET);\n'
|
| + ' return _on;\n'
|
| + ' }\n',
|
| + TYPE=events_class,
|
| + EVENTTARGET='_wrappedDocumentPtr' if self._interface.id == 'Document'
|
| + else 'this')
|
| +
|
| + self._shared._event_classes.add(self._interface.id)
|
| +
|
| + parent_event_classes = self._shared.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 $SUPER implements $INTERFACE {\n'
|
| + ' $CLASSNAME(_ptr) : super(_ptr);\n'
|
| + '$!MEMBERS}\n',
|
| + CLASSNAME=events_class,
|
| + 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)
|
|
|
| def _SecondaryContext(self, interface):
|
| if interface is not self._current_secondary_parent:
|
| self._current_secondary_parent = interface
|
| self._members_emitter.Emit('\n // From $WHERE\n', WHERE=interface.id)
|
|
|
| + # TODO(jacobr): change this to more directly match the frog version.
|
| def AddIndexer(self, element_type):
|
| """Adds all the methods required to complete implementation of List."""
|
| # We would like to simply inherit the implementation of everything except
|
| @@ -1037,20 +1354,28 @@ class WrappingInterfaceGenerator(object):
|
| else:
|
| self._members_emitter.Emit(
|
| '\n'
|
| - ' $TYPE operator[](int index) {\n'
|
| - ' return item(index);\n'
|
| - ' }\n',
|
| + ' $TYPE operator[](int index) => _wrap($(THIS)[index]);\n'
|
| + '\n',
|
| + THIS=self.DomObjectName(),
|
| TYPE=DartType(element_type))
|
|
|
| if self._HasNativeIndexSetter(self._interface):
|
| self._EmitNativeIndexSetter(self._interface, element_type)
|
| else:
|
| - self._members_emitter.Emit(
|
| - '\n'
|
| - ' void operator[]=(int index, $TYPE value) {\n'
|
| - ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
|
| - ' }\n',
|
| - TYPE=element_type)
|
| + # The HTML library implementation of NodeList has a custom indexed setter
|
| + # implementation that uses the parent node the NodeList is associated
|
| + # with if one is available.
|
| + if self._interface.id != 'NodeList':
|
| + self._members_emitter.Emit(
|
| + '\n'
|
| + ' void operator[]=(int index, $TYPE value) {\n'
|
| + ' throw new UnsupportedOperationException("Cannot assign element of immutable List.");\n'
|
| + ' }\n',
|
| + TYPE=DartType(element_type))
|
| +
|
| + # The list interface for this class is manually generated.
|
| + if self._interface.id == 'NodeList':
|
| + return
|
|
|
| self._members_emitter.Emit(
|
| '\n'
|
| @@ -1139,7 +1464,7 @@ class WrappingInterfaceGenerator(object):
|
| ' Iterator<$TYPE> iterator() {\n'
|
| ' return new _FixedSizeListIterator<$TYPE>(this);\n'
|
| ' }\n',
|
| - TYPE=element_type)
|
| + TYPE=DartType(element_type))
|
|
|
| def _HasNativeIndexGetter(self, interface):
|
| return ('HasIndexGetter' in interface.ext_attrs or
|
| @@ -1148,10 +1473,10 @@ class WrappingInterfaceGenerator(object):
|
| def _EmitNativeIndexGetter(self, interface, element_type):
|
| method_name = '_index'
|
| self._members_emitter.Emit(
|
| - '\n'
|
| - ' $TYPE operator[](int index) { return $METHOD(this, index); }\n'
|
| - ' static $TYPE $METHOD(var _this, int index) native;\n',
|
| - TYPE=element_type, METHOD=method_name)
|
| + '\n $TYPE operator[](int index) => _wrap($(THIS)[index]);\n',
|
| + TYPE=DartType(element_type),
|
| + THIS=self.DomObjectName(),
|
| + METHOD=method_name)
|
|
|
| def _HasNativeIndexSetter(self, interface):
|
| return 'HasCustomIndexSetter' in interface.ext_attrs
|
| @@ -1161,23 +1486,29 @@ class WrappingInterfaceGenerator(object):
|
| self._members_emitter.Emit(
|
| '\n'
|
| ' void operator[]=(int index, $TYPE value) {\n'
|
| - ' return $METHOD(this, index, value);\n'
|
| - ' }\n'
|
| - ' static $METHOD(_this, index, value) native;\n',
|
| - TYPE=element_type, METHOD=method_name)
|
| + ' return $(THIS)[index] = _unwrap(value);\n'
|
| + ' }\n',
|
| + THIS=self.DomObjectName(),
|
| + TYPE=DartType(element_type),
|
| + METHOD=method_name)
|
|
|
| def AddOperation(self, info):
|
| """
|
| Arguments:
|
| info: An OperationInfo object.
|
| """
|
| + html_name = self._shared.RenameInHtmlLibrary(self._interface, info.name)
|
| +
|
| + if not html_name:
|
| + return
|
| +
|
| body = self._members_emitter.Emit(
|
| '\n'
|
| - ' $TYPE $NAME($PARAMS) {\n'
|
| + ' $TYPE $HTML_NAME($PARAMS) {\n'
|
| '$!BODY'
|
| ' }\n',
|
| TYPE=info.type_name,
|
| - NAME=info.name,
|
| + HTML_NAME=html_name,
|
| PARAMS=info.ParametersImplementationDeclaration())
|
|
|
| # Process in order of ascending number of arguments to ensure missing
|
| @@ -1202,7 +1533,7 @@ class WrappingInterfaceGenerator(object):
|
| # arguments from passing 'null' which is represented as 'undefined'?
|
| def UnwrapArgExpression(name, type):
|
| # TODO: Type specific unwrapping.
|
| - return '__dom_unwrap(%s)' % (name)
|
| + return '_unwrap(%s)' % (name)
|
|
|
| def ArgNameAndUnwrapper(arg_info, overload_arg):
|
| (name, type, value) = arg_info
|
| @@ -1211,32 +1542,34 @@ class WrappingInterfaceGenerator(object):
|
| names_and_unwrappers = [ArgNameAndUnwrapper(info.arg_infos[i], arg)
|
| for (i, arg) in enumerate(operation.arguments)]
|
| unwrap_args = [unwrap_arg for (_, unwrap_arg) in names_and_unwrappers]
|
| - arg_names = [name for (name, _) in names_and_unwrappers]
|
| -
|
| - self._native_version += 1
|
| - native_name = self._MethodName('_', info.name)
|
| - if self._native_version > 1:
|
| - native_name = '%s_%s' % (native_name, self._native_version)
|
| + arg_names = ['_unwrap(%s)' % name for (name, _) in names_and_unwrappers]
|
|
|
| - argument_expressions = ', '.join(['this'] + arg_names)
|
| + argument_expressions = ', '.join(arg_names)
|
| if info.type_name != 'void':
|
| - emitter.Emit('$(INDENT)return $NATIVENAME($ARGS);\n',
|
| - INDENT=indent,
|
| - NATIVENAME=native_name,
|
| - ARGS=argument_expressions)
|
| + # We could place the logic for handling Document directly in _wrap
|
| + # but we chose to place it here so that bugs in the wrapper and
|
| + # wrapperless implementations are more consistent.
|
| + if self._shared.MaybeReturnDocument(info.type_name):
|
| + emitter.Emit('$(INDENT)return _FixHtmlDocumentReference('
|
| + '_wrap($(THIS).$NAME($ARGS)));\n',
|
| + INDENT=indent,
|
| + THIS=self.DomObjectName(),
|
| + NAME=info.name,
|
| + ARGS=argument_expressions)
|
| + else:
|
| + emitter.Emit('$(INDENT)return _wrap($(THIS).$NAME($ARGS));\n',
|
| + INDENT=indent,
|
| + THIS=self.DomObjectName(),
|
| + NAME=info.name,
|
| + ARGS=argument_expressions)
|
| else:
|
| - emitter.Emit('$(INDENT)$NATIVENAME($ARGS);\n'
|
| + emitter.Emit('$(INDENT)$(THIS).$NAME($ARGS);\n'
|
| '$(INDENT)return;\n',
|
| INDENT=indent,
|
| - NATIVENAME=native_name,
|
| + THIS=self.DomObjectName(),
|
| + NAME=info.name,
|
| ARGS=argument_expressions)
|
|
|
| - self._members_emitter.Emit(' static $TYPE $NAME($PARAMS) native;\n',
|
| - NAME=native_name,
|
| - TYPE=info.type_name,
|
| - PARAMS=', '.join(['receiver'] + arg_names) )
|
| -
|
| -
|
| def GenerateDispatch(self, emitter, info, indent, position, overloads):
|
| """Generates a dispatch to one of the overloads.
|
|
|
| @@ -1279,9 +1612,10 @@ class WrappingInterfaceGenerator(object):
|
| # precise type than the first. E.g.,
|
| # void foo(Node x);
|
| # void foo(Element x);
|
| - type = first_overload.arguments[position].type.id
|
| + type = DartType(first_overload.arguments[position].type.id)
|
| test = TypeCheck(param_name, type)
|
| - pred = lambda op: len(op.arguments) > position and op.arguments[position].type.id == type
|
| + pred = lambda op: (len(op.arguments) > position and
|
| + DartType(op.arguments[position].type.id) == type)
|
| else:
|
| type = None
|
| test = NullCheck(param_name)
|
|
|