Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(614)

Unified Diff: client/dom/scripts/systemhtml.py

Issue 9537001: Generate dart:html bindings for Dartium as well as Frog. All unittests now pass (or are disabled fo… (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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)

Powered by Google App Engine
This is Rietveld 408576698