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