#!/usr/bin/python # Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file # for details. All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. """This module provides shared functionality for the system to generate Dart:html APIs from the IDL database.""" import emitter import logging import monitored import os import re from generator import * from htmldartgenerator import * _logger = logging.getLogger('systemhtml') HTML_LIBRARY_NAMES = ['html', 'indexed_db', 'svg', 'web_audio', 'web_gl', 'web_sql'] # The following two sets let us avoid shadowing fields with properties. # This information could be derived from the IDL files but would require # a significant refactor to compute accurately. Instead we manually compute # these sets based on manual triage of strong mode errors. _force_property_members = monitored.Set('systemhtml._force_property_members', [ 'Element.outerHtml', 'Element.isContentEditable', 'AudioContext.createGain', 'AudioContext.createScriptProcessor', ]) _safe_to_ignore_shadowing_members = monitored.Set('systemhtml._safe_to_ignore_shadowing_members', [ 'SVGElement.tabIndex', 'SVGStyleElement.title', ]) _js_custom_members = monitored.Set('systemhtml._js_custom_members', [ 'AudioBufferSourceNode.start', 'AudioBufferSourceNode.stop', 'AudioContext.createGain', 'AudioContext.createScriptProcessor', 'CanvasRenderingContext2D.drawImage', 'CanvasRenderingContext2D.fill', 'CanvasRenderingContext2D.fillText', 'CanvasRenderingContext2D.lineDashOffset', 'CanvasRenderingContext2D.setLineDash', 'Console.memory', 'ConsoleBase.assertCondition', 'ConsoleBase.clear', 'ConsoleBase.count', 'ConsoleBase.debug', 'ConsoleBase.dir', 'ConsoleBase.dirxml', 'ConsoleBase.error', 'ConsoleBase.group', 'ConsoleBase.groupCollapsed', 'ConsoleBase.groupEnd', 'ConsoleBase.info', 'ConsoleBase.log', 'ConsoleBase.markTimeline', 'ConsoleBase.profile', 'ConsoleBase.profileEnd', 'ConsoleBase.table', 'ConsoleBase.time', 'ConsoleBase.timeEnd', 'ConsoleBase.timeStamp', 'ConsoleBase.trace', 'ConsoleBase.warn', 'WebKitCSSKeyframesRule.insertRule', 'CSSStyleDeclaration.setProperty', 'CSSStyleDeclaration.__propertyQuery__', 'Document.createNodeIterator', 'Document.createTreeWalker', 'DOMException.name', 'DOMException.toString', # ListMixin already provides this method although the implementation # is slower. As this class is obsolete anyway, we ignore the slowdown in # DOMStringList performance. 'DOMStringList.contains', 'Element.animate', 'Element.createShadowRoot', 'Element.insertAdjacentElement', 'Element.insertAdjacentHTML', 'Element.insertAdjacentText', 'Element.remove', 'Element.shadowRoot', 'Element.matches', 'ElementEvents.mouseWheel', 'ElementEvents.transitionEnd', 'FileReader.result', 'HTMLAnchorElement.toString', 'HTMLAreaElement.toString', 'HTMLTableElement.createTBody', 'IDBCursor.next', 'IDBDatabase.transaction', 'IDBDatabase.transactionList', 'IDBDatabase.transactionStore', 'IDBDatabase.transactionStores', 'KeyboardEvent.initKeyboardEvent', 'Location.origin', 'Location.toString', 'MouseEvent.offsetX', 'MouseEvent.offsetY', 'Navigator.language', 'Navigator.webkitGetUserMedia', 'ScriptProcessorNode._setEventListener', 'URL.createObjectURL', 'URL.createObjectUrlFromSource', 'URL.createObjectUrlFromStream', 'URL.createObjectUrlFromBlob', 'URL.revokeObjectURL', 'URL.toString', 'WheelEvent.deltaMode', 'Window.cancelAnimationFrame', 'Window.console', 'Window.document', 'Window.indexedDB', 'Window.location', 'Window.open', 'Window.requestAnimationFrame', 'Window.scrollX', 'Window.scrollY' # 'WorkerContext.indexedDB', # Workers ], dart2jsOnly=True) _js_custom_constructors = monitored.Set('systemhtml._js_custom_constructors', [ 'AudioContext', 'Blob', 'Comment', 'MutationObserver', 'RTCIceCandidate', 'RTCPeerConnection', 'RTCSessionDescription', 'SpeechRecognition', ], dart2jsOnly=True) # Classes that offer only static methods, and therefore we should suppress # constructor creation. _static_classes = set(['Url']) # Information for generating element constructors. # # TODO(sra): maybe remove all the argument complexity and use cascades. # # var c = new CanvasElement(width: 100, height: 70); # var c = new CanvasElement()..width = 100..height = 70; # class ElementConstructorInfo(object): def __init__(self, name=None, tag=None, params=[], opt_params=[], factory_provider_name='document'): self.name = name # The constructor name 'h1' in 'HeadingElement.h1' self.tag = tag or name # The HTML or SVG tag self.params = params self.opt_params = opt_params self.factory_provider_name = factory_provider_name def ConstructorInfo(self, interface_name): info = OperationInfo() info.overloads = None info.declared_name = interface_name info.name = interface_name info.constructor_name = self.name info.js_name = None info.type_name = interface_name info.param_infos = map(lambda tXn: ParamInfo(tXn[1], tXn[0], True), self.opt_params) info.requires_named_arguments = True info.factory_parameters = ['"%s"' % self.tag] info.pure_dart_constructor = True return info _html_element_constructors = monitored.Dict( 'systemhtml._html_element_constructors', { 'HTMLAnchorElement' : ElementConstructorInfo(tag='a', opt_params=[('DOMString', 'href')]), 'HTMLAreaElement': 'area', 'HTMLButtonElement': 'button', 'HTMLBRElement': 'br', 'HTMLBaseElement': 'base', 'HTMLBodyElement': 'body', 'HTMLButtonElement': 'button', 'HTMLCanvasElement': ElementConstructorInfo(tag='canvas', opt_params=[('int', 'width'), ('int', 'height')]), 'HTMLContentElement': 'content', 'HTMLDataListElement': 'datalist', 'HTMLDListElement': 'dl', 'HTMLDetailsElement': 'details', 'HTMLDivElement': 'div', 'HTMLEmbedElement': 'embed', 'HTMLFieldSetElement': 'fieldset', 'HTMLFormElement': 'form', 'HTMLHRElement': 'hr', 'HTMLHeadElement': 'head', 'HTMLHeadingElement': [ElementConstructorInfo('h1'), ElementConstructorInfo('h2'), ElementConstructorInfo('h3'), ElementConstructorInfo('h4'), ElementConstructorInfo('h5'), ElementConstructorInfo('h6')], 'HTMLHtmlElement': 'html', 'HTMLIFrameElement': 'iframe', 'HTMLImageElement': ElementConstructorInfo(tag='img', opt_params=[('DOMString', 'src'), ('int', 'width'), ('int', 'height')]), 'HTMLKeygenElement': 'keygen', 'HTMLLIElement': 'li', 'HTMLLabelElement': 'label', 'HTMLLegendElement': 'legend', 'HTMLLinkElement': 'link', 'HTMLMapElement': 'map', 'HTMLMenuElement': 'menu', 'HTMLMetaElement': 'meta', 'HTMLMeterElement': 'meter', 'HTMLOListElement': 'ol', 'HTMLObjectElement': 'object', 'HTMLOptGroupElement': 'optgroup', 'HTMLOutputElement': 'output', 'HTMLParagraphElement': 'p', 'HTMLParamElement': 'param', 'HTMLPreElement': 'pre', 'HTMLProgressElement': 'progress', 'HTMLQuoteElement': 'q', 'HTMLScriptElement': 'script', 'HTMLSelectElement': 'select', 'HTMLShadowElement': 'shadow', 'HTMLSourceElement': 'source', 'HTMLSpanElement': 'span', 'HTMLStyleElement': 'style', 'HTMLTableCaptionElement': 'caption', 'HTMLTableCellElement': 'td', 'HTMLTableColElement': 'col', 'HTMLTableElement': 'table', 'HTMLTableRowElement': 'tr', #'HTMLTableSectionElement'
'HTMLTemplateElement': 'template', 'HTMLTextAreaElement': 'textarea', 'HTMLTitleElement': 'title', 'HTMLTrackElement': 'track', 'HTMLUListElement': 'ul', 'HTMLVideoElement': 'video' }) _svg_element_constructors = monitored.Dict( 'systemhtml._svg_element_constructors', { 'SVGAElement': 'a', 'SVGAltGlyphElement': 'altGlyph', 'SVGAnimateElement': 'animate', 'SVGAnimateMotionElement': 'animateMotion', 'SVGAnimateTransformElement': 'animateTransform', 'SVGAnimationElement': 'animation', 'SVGCircleElement': 'circle', 'SVGClipPathElement': 'clipPath', 'SVGCursorElement': 'cursor', 'SVGDefsElement': 'defs', 'SVGDescElement': 'desc', 'SVGEllipseElement': 'ellipse', 'SVGFEBlendElement': 'feBlend', 'SVGFEColorMatrixElement': 'feColorMatrix', 'SVGFEComponentTransferElement': 'feComponentTransfer', 'SVGFEConvolveMatrixElement': 'feConvolveMatrix', 'SVGFEDiffuseLightingElement': 'feDiffuseLighting', 'SVGFEDisplacementMapElement': 'feDisplacementMap', 'SVGFEDistantLightElement': 'feDistantLight', 'SVGFEFloodElement': 'feFlood', 'SVGFEFuncAElement': 'feFuncA', 'SVGFEFuncBElement': 'feFuncB', 'SVGFEFuncGElement': 'feFuncG', 'SVGFEFuncRElement': 'feFuncR', 'SVGFEGaussianBlurElement': 'feGaussianBlur', 'SVGFEImageElement': 'feImage', 'SVGFEMergeElement': 'feMerge', 'SVGFEMergeNodeElement': 'feMergeNode', 'SVGFEMorphology': 'feMorphology', 'SVGFEOffsetElement': 'feOffset', 'SVGFEPointLightElement': 'fePointLight', 'SVGFESpecularLightingElement': 'feSpecularLighting', 'SVGFESpotLightElement': 'feSpotLight', 'SVGFETileElement': 'feTile', 'SVGFETurbulenceElement': 'feTurbulence', 'SVGFilterElement': 'filter', 'SVGForeignObjectElement': 'foreignObject', 'SVGGlyphElement': 'glyph', 'SVGGElement': 'g', 'SVGHKernElement': 'hkern', 'SVGImageElement': 'image', 'SVGLinearGradientElement': 'linearGradient', 'SVGLineElement': 'line', 'SVGMarkerElement': 'marker', 'SVGMaskElement': 'mask', 'SVGMPathElement': 'mpath', 'SVGPathElement': 'path', 'SVGPatternElement': 'pattern', 'SVGPolygonElement': 'polygon', 'SVGPolylineElement': 'polyline', 'SVGRadialGradientElement': 'radialGradient', 'SVGRectElement': 'rect', 'SVGScriptElement': 'script', 'SVGSetElement': 'set', 'SVGStopElement': 'stop', 'SVGStyleElement': 'style', 'SVGSwitchElement': 'switch', 'SVGSymbolElement': 'symbol', 'SVGTextElement': 'text', 'SVGTitleElement': 'title', 'SVGTRefElement': 'tref', 'SVGTSpanElement': 'tspan', 'SVGUseElement': 'use', 'SVGViewElement': 'view', 'SVGVKernElement': 'vkern', }) _element_constructors = { 'html': _html_element_constructors, 'indexed_db': {}, 'svg': _svg_element_constructors, 'typed_data': {}, 'web_audio': {}, 'web_gl': {}, 'web_sql': {}, } _factory_ctr_strings = { 'html': { 'provider_name': 'document', 'constructor_name': 'createElement' }, 'indexed_db': { 'provider_name': 'document', 'constructor_name': 'createElement' }, 'svg': { 'provider_name': '_SvgElementFactoryProvider', 'constructor_name': 'createSvgElement_tag', }, 'typed_data': { 'provider_name': 'document', 'constructor_name': 'createElement' }, 'web_audio': { 'provider_name': 'document', 'constructor_name': 'createElement' }, 'web_gl': { 'provider_name': 'document', 'constructor_name': 'createElement' }, 'web_sql': { 'provider_name': 'document', 'constructor_name': 'createElement' }, } def ElementConstructorInfos(typename, element_constructors, factory_provider_name='_Elements'): """Returns list of ElementConstructorInfos about the convenience constructors for an Element or SvgElement.""" # TODO(sra): Handle multiple and named constructors. if typename not in element_constructors: return [] infos = element_constructors[typename] if isinstance(infos, str): infos = ElementConstructorInfo(tag=infos, factory_provider_name=factory_provider_name) if not isinstance(infos, list): infos = [infos] return infos # ------------------------------------------------------------------------------ def SvgSupportStr(tagName): return 'Svg%s' % ElemSupportStr(tagName) def ElemSupportStr(tagName): return "Element.isTagSupported('%s')" % tagName _js_support_checks_basic_element_with_constructors = [ 'HTMLContentElement', 'HTMLDataListElement', 'HTMLDetailsElement', 'HTMLEmbedElement', 'HTMLMeterElement', 'HTMLObjectElement', 'HTMLOutputElement', 'HTMLProgressElement', 'HTMLTemplateElement', 'HTMLTrackElement', ] _js_support_checks_additional_element = [ # IE creates keygen as Block elements 'HTMLKeygenElement', 'SVGAltGlyphElement', 'SVGAnimateElement', 'SVGAnimateMotionElement', 'SVGAnimateTransformElement', 'SVGCursorElement', 'SVGFEBlendElement', 'SVGFEColorMatrixElement', 'SVGFEComponentTransferElement', 'SVGFEConvolveMatrixElement', 'SVGFEDiffuseLightingElement', 'SVGFEDisplacementMapElement', 'SVGFEDistantLightElement', 'SVGFEFloodElement', 'SVGFEFuncAElement', 'SVGFEFuncBElement', 'SVGFEFuncGElement', 'SVGFEFuncRElement', 'SVGFEGaussianBlurElement', 'SVGFEImageElement', 'SVGFEMergeElement', 'SVGFEMergeNodeElement', 'SVGFEMorphology', 'SVGFEOffsetElement', 'SVGFEPointLightElement', 'SVGFESpecularLightingElement', 'SVGFESpotLightElement', 'SVGFETileElement', 'SVGFETurbulenceElement', 'SVGFilterElement', 'SVGForeignObjectElement', 'SVGSetElement', ] js_support_checks = dict({ 'Animation': "JS('bool', '!!(document.body.animate)')", 'AudioContext': "JS('bool', '!!(window.AudioContext ||" " window.webkitAudioContext)')", 'Crypto': "JS('bool', '!!(window.crypto && window.crypto.getRandomValues)')", 'Database': "JS('bool', '!!(window.openDatabase)')", 'DOMPoint': "JS('bool', '!!(window.DOMPoint) || !!(window.WebKitPoint)')", 'ApplicationCache': "JS('bool', '!!(window.applicationCache)')", 'DOMFileSystem': "JS('bool', '!!(window.webkitRequestFileSystem)')", 'FormData': "JS('bool', '!!(window.FormData)')", 'HashChangeEvent': "Device.isEventTypeSupported('HashChangeEvent')", 'HTMLShadowElement': ElemSupportStr('shadow'), 'HTMLTemplateElement': ElemSupportStr('template'), 'MediaStreamEvent': "Device.isEventTypeSupported('MediaStreamEvent')", 'MediaStreamTrackEvent': "Device.isEventTypeSupported('MediaStreamTrackEvent')", 'MediaSource': "JS('bool', '!!(window.MediaSource)')", 'Notification': "JS('bool', '!!(window.Notification)')", 'Performance': "JS('bool', '!!(window.performance)')", 'SpeechRecognition': "JS('bool', '!!(window.SpeechRecognition || " "window.webkitSpeechRecognition)')", 'SVGExternalResourcesRequired': ('supported(SvgElement element)', "JS('bool', '#.externalResourcesRequired !== undefined && " "#.externalResourcesRequired.animVal !== undefined', " "element, element)"), 'SVGLangSpace': ('supported(SvgElement element)', "JS('bool', '#.xmlspace !== undefined && #.xmllang !== undefined', " "element, element)"), 'TouchList': "JS('bool', '!!document.createTouchList')", 'WebGLRenderingContext': "JS('bool', '!!(window.WebGLRenderingContext)')", 'WebSocket': "JS('bool', 'typeof window.WebSocket != \"undefined\"')", 'Worker': "JS('bool', '(typeof window.Worker != \"undefined\")')", 'XSLTProcessor': "JS('bool', '!!(window.XSLTProcessor)')", }.items() + dict((key, SvgSupportStr(_svg_element_constructors[key]) if key.startswith('SVG') else ElemSupportStr(_html_element_constructors[key])) for key in _js_support_checks_basic_element_with_constructors + _js_support_checks_additional_element).items()) # JavaScript element class names of elements for which createElement does not # always return exactly the right element, either because it might not be # supported, or some browser does something weird. _js_unreliable_element_factories = set( _js_support_checks_basic_element_with_constructors + _js_support_checks_additional_element + [ 'HTMLEmbedElement', 'HTMLObjectElement', 'HTMLShadowElement', 'HTMLTemplateElement', ]) # ------------------------------------------------------------------------------ class HtmlDartInterfaceGenerator(object): """Generates dart interface and implementation for the DOM IDL interface.""" def __init__(self, options, library_emitter, event_generator, interface, backend): self._renamer = options.renamer self._database = options.database self._template_loader = options.templates self._type_registry = options.type_registry self._options = options self._library_emitter = library_emitter self._event_generator = event_generator self._interface = interface self._backend = backend self._interface_type_info = self._type_registry.TypeInfo(self._interface.id) self._library_name = self._renamer.GetLibraryName(self._interface) self._metadata = options.metadata def Generate(self): if IsCustomType(self._interface.id): pass elif 'Callback' in self._interface.ext_attrs: self.GenerateCallback() else: self.GenerateInterface() def GenerateCallback(self): """Generates a typedef for the callback interface.""" typedef_name = self._renamer.RenameInterface(self._interface) if not typedef_name: return info = GetCallbackInfo(self._interface) code = self._library_emitter.FileEmitter(self._interface.id, self._library_name) code.Emit(self._template_loader.Load('callback.darttemplate')) annotations = self._metadata.GetFormattedMetadata(self._library_name, self._interface) code.Emit('$(ANNOTATIONS)typedef void $NAME($PARAMS);\n', ANNOTATIONS=annotations, NAME=typedef_name, PARAMS=info.ParametersAsDeclaration(self._DartType)) self._backend.GenerateCallback(info) def GenerateInterface(self): interface_name = self._interface_type_info.interface_name() implementation_name = self._interface_type_info.implementation_name() self._library_emitter.AddTypeEntry(self._library_name, self._interface.id, implementation_name) factory_provider = None if interface_name in interface_factories: factory_provider = interface_factories[interface_name] factory_constructor_name = None constructors = [] if interface_name in _static_classes: constructor_info = None else: constructor_info = AnalyzeConstructor(self._interface) if constructor_info: constructors.append(constructor_info) # TODO(antonm): consider removing it later. factory_provider = interface_name # HTML Elements and SVG Elements have convenience constructors. infos = ElementConstructorInfos(self._interface.id, _element_constructors[self._library_name], factory_provider_name= _factory_ctr_strings[self._library_name]['provider_name']) if infos: factory_constructor_name = _factory_ctr_strings[ self._library_name]['constructor_name'] for info in infos: constructors.append(info.ConstructorInfo(self._interface.id)) if factory_provider and factory_provider != info.factory_provider_name: _logger.warn('Conflicting factory provider names: %s != %s' % (factory_provider, info.factory_provider_name)) factory_provider = info.factory_provider_name implementation_emitter = self._ImplementationEmitter() base_type_info = None if self._interface.parents: supertype = self._interface.parents[0].type.id if not IsDartCollectionType(supertype) and not IsPureInterface(supertype, self._database): base_type_info = self._type_registry.TypeInfo(supertype) if base_type_info: base_class = base_type_info.implementation_name() else: base_class = self._backend.RootClassName() implements = self._backend.AdditionalImplementedInterfaces() for parent in self._interface.parents: parent_type_info = self._type_registry.TypeInfo(parent.type.id) if parent_type_info.interface_name() != base_class and \ parent_type_info != base_type_info: implements.append(parent_type_info.interface_name()) secure_base_name = self._backend.SecureBaseName(interface_name) if secure_base_name: implements.append(secure_base_name) implements_str = '' if implements: implements_str = ' implements ' + ', '.join(set(implements)) mixins = self._backend.Mixins() mixins_str = '' if mixins: mixins_str = ' with ' + ', '.join(mixins) if not base_class: base_class = 'Interceptor' elif (base_class == 'NativeFieldWrapperClass2' and self._options.dart_js_interop and not(isinstance(self._backend, Dart2JSBackend))): base_class = 'DartHtmlDomObject' annotations = self._metadata.GetFormattedMetadata( self._library_name, self._interface, None, '') class_modifiers = '' if (self._renamer.ShouldSuppressInterface(self._interface) or IsPureInterface(self._interface.id, self._database)): # XMLHttpRequestProgressEvent can't be abstract we need to instantiate # for JsInterop. if (not(isinstance(self._backend, Dart2JSBackend)) and (self._interface.id == 'XMLHttpRequestProgressEvent' or self._interface.id == 'DOMStringMap')): # Suppress abstract for XMLHttpRequestProgressEvent and DOMStringMap # for Dartium. Need to be able to instantiate the class; can't be abstract. class_modifiers = '' else: # For Dartium w/ JsInterop these suppressed interfaces are needed to # instanciate the internal classes. if (self._renamer.ShouldSuppressInterface(self._interface) and not(isinstance(self._backend, Dart2JSBackend)) and self._options.dart_js_interop): class_modifiers = '' else: class_modifiers = 'abstract ' native_spec = '' if not IsPureInterface(self._interface.id, self._database): native_spec = self._backend.NativeSpec() class_name = self._interface_type_info.implementation_name() js_interop_wrapper = ''' @Deprecated("Internal Use Only") external static Type get instanceRuntimeType; @Deprecated("Internal Use Only") {0}.internal_() : super.internal_(); '''.format(class_name) if base_class == 'NativeFieldWrapperClass2' or base_class == 'DartHtmlDomObject': js_interop_wrapper = ''' @Deprecated("Internal Use Only") external static Type get instanceRuntimeType; @Deprecated("Internal Use Only") {0}.internal_() {{ }} '''.format(class_name) # Change to use the synthesized class so we can construct with a mixin # classes prefixed with name of NativeFieldWrapperClass2 don't have a # default constructor so classes with mixins can't be new'd. if (self._options.templates._conditions['DARTIUM'] and self._options.dart_js_interop and (self._interface.id == 'NamedNodeMap' or self._interface.id == 'CSSStyleDeclaration')): base_class = 'DartHtmlDomObject' implementation_members_emitter = implementation_emitter.Emit( self._backend.ImplementationTemplate(), LIBRARYNAME='dart.dom.%s' % self._library_name, ANNOTATIONS=annotations, CLASS_MODIFIERS=class_modifiers, CLASSNAME=class_name, EXTENDS=' extends %s' % base_class if base_class else '', IMPLEMENTS=implements_str, MIXINS=mixins_str, DOMNAME=self._interface.doc_js_name, NATIVESPEC=native_spec) stream_getter_signatures_emitter = None element_stream_getters_emitter = None if type(implementation_members_emitter) == tuple: # We add event stream getters for both Element and ElementList, so in # impl_Element.darttemplate, we have two additional "holes" for emitters # to fill in, with small variations. These store these specialized # emitters. assert len(implementation_members_emitter) == 3; stream_getter_signatures_emitter = \ implementation_members_emitter[0] element_stream_getters_emitter = implementation_members_emitter[1] implementation_members_emitter = \ implementation_members_emitter[2] self._backend.StartInterface(implementation_members_emitter) self._backend.EmitHelpers(base_class) self._event_generator.EmitStreamProviders( self._interface, self._backend.CustomJSMembers(), implementation_members_emitter, self._library_name) self._backend.AddConstructors( constructors, factory_provider, factory_constructor_name) isElement = False for parent in self._database.Hierarchy(self._interface): if parent.id == 'Element': isElement = True # Write out the JsInterop code. if (implementation_members_emitter and self._options.templates._conditions['DARTIUM'] and self._options.dart_js_interop and not IsPureInterface(self._interface.id, self._database)): implementation_members_emitter.Emit(js_interop_wrapper) if isElement and self._interface.id != 'Element': implementation_members_emitter.Emit( ' /**\n' ' * Constructor instantiated by the DOM when a custom element has been created.\n' ' *\n' ' * This can only be called by subclasses from their created constructor.\n' ' */\n' ' $CLASSNAME.created() : super.created();\n', CLASSNAME=self._interface_type_info.implementation_name()) self._backend.EmitSupportCheck() merged_interface = self._interface_type_info.merged_interface() if merged_interface: self._backend.AddMembers(self._database.GetInterface(merged_interface), not self._backend.ImplementsMergedMembers()) self._backend.AddMembers(self._interface, False, self._options.dart_js_interop) self._backend.AddSecondaryMembers(self._interface) self._event_generator.EmitStreamGetters( self._interface, [], implementation_members_emitter, self._library_name, stream_getter_signatures_emitter, element_stream_getters_emitter) self._backend.FinishInterface() def _ImplementationEmitter(self): basename = self._interface_type_info.implementation_name() if (self._interface_type_info.merged_into() and self._backend.ImplementsMergedMembers()): # Merged members are implemented in target interface implementation. return emitter.Emitter() return self._library_emitter.FileEmitter(basename, self._library_name) def _DartType(self, type_name): return self._type_registry.DartType(type_name) # ------------------------------------------------------------------------------ class Dart2JSBackend(HtmlDartGenerator): """Generates a dart2js class for the dart:html library from a DOM IDL interface. """ def __init__(self, interface, options, logging_level=logging.WARNING): super(Dart2JSBackend, self).__init__(interface, options, False, _logger) self._database = options.database self._template_loader = options.templates self._type_registry = options.type_registry self._renamer = options.renamer self._metadata = options.metadata self._interface_type_info = self._type_registry.TypeInfo(self._interface.id) self._current_secondary_parent = None self._library_name = self._renamer.GetLibraryName(self._interface) _logger.setLevel(logging_level) def ImplementsMergedMembers(self): return True def GenerateCallback(self, info): pass def AdditionalImplementedInterfaces(self): implements = super(Dart2JSBackend, self).AdditionalImplementedInterfaces() if self._interface_type_info.list_item_type() and self.HasIndexedGetter(): item_type = self._type_registry.TypeInfo( self._interface_type_info.list_item_type()).dart_type() implements.append('JavaScriptIndexingBehavior<%s>' % item_type) return implements def NativeSpec(self): native_spec = MakeNativeSpec(self._interface.javascript_binding_name) return '@Native("%s")\n' % native_spec def ImplementationTemplate(self): template_file = ('impl_%s.darttemplate' % self._interface.doc_js_name) return (self._template_loader.TryLoad(template_file) or self._template_loader.Load('dart2js_impl.darttemplate')) def StartInterface(self, members_emitter): self._members_emitter = members_emitter def FinishInterface(self): pass def HasSupportCheck(self): return self._interface.doc_js_name in js_support_checks def GetSupportCheck(self): """Return a tuple of the support check function signature and the support test itself. If no parameters are supplied, we assume the default.""" if self._interface.doc_js_name in _js_support_checks_additional_element: if self._interface.doc_js_name in _svg_element_constructors: lib_prefix = 'Svg' constructors = _svg_element_constructors else: lib_prefix = '' constructors = _html_element_constructors return (js_support_checks.get(self._interface.doc_js_name) + " && (new %sElement.tag('%s') is %s)" % (lib_prefix, constructors[self._interface.doc_js_name], self._renamer.RenameInterface(self._interface))) return js_support_checks.get(self._interface.doc_js_name) def GenerateCustomFactory(self, constructor_info): # Custom factory will be taken from the template. return self._interface.doc_js_name in _js_custom_constructors def MakeFactoryCall(self, factory, method, arguments, constructor_info): if factory is 'document' and method is 'createElement' \ and not ',' in arguments \ and not self._HasUnreliableFactoryConstructor(): return emitter.Format( "JS('returns:$INTERFACE_NAME;creates:$INTERFACE_NAME;new:true'," " '#.$METHOD(#)', $FACTORY, $ARGUMENTS)", INTERFACE_NAME=self._interface_type_info.interface_name(), FACTORY=factory, METHOD=method, ARGUMENTS=arguments) return emitter.Format( '$FACTORY.$METHOD($ARGUMENTS)', FACTORY=factory, METHOD=method, ARGUMENTS=arguments) def _HasUnreliableFactoryConstructor(self): return self._interface.doc_js_name in _js_unreliable_element_factories def IsConstructorArgumentOptional(self, argument): return argument.optional def EmitStaticFactoryOverload(self, constructor_info, name, arguments): index = len(arguments) arguments = constructor_info.ParametersAsArgumentList(index) if arguments: arguments = ', ' + arguments self._members_emitter.Emit( " static $INTERFACE_NAME $NAME($PARAMETERS) => " "JS('$INTERFACE_NAME', 'new $CTOR_NAME($PLACEHOLDERS)'$ARGUMENTS);\n", INTERFACE_NAME=self._interface_type_info.interface_name(), NAME=name, # TODO(antonm): add types to parameters. PARAMETERS=constructor_info.ParametersAsArgumentList(index), CTOR_NAME=constructor_info.name or self._interface.doc_js_name, PLACEHOLDERS=','.join(['#'] * index), ARGUMENTS=arguments) 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) def HasIndexedGetter(self): ext_attrs = self._interface.ext_attrs has_indexed_getter = 'CustomIndexedGetter' in ext_attrs for operation in self._interface.operations: if operation.id == 'item' and 'getter' in operation.specials \ and not self._OperationRequiresConversions(operation): has_indexed_getter = True break return has_indexed_getter def AddIndexer(self, element_type, nullable): """Adds all the methods required to complete implementation of List.""" # We would like to simply inherit the implementation of everything except # 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