Flutter Engine
The Flutter Engine
systemhtml.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
5"""This module provides shared functionality for the system to generate
6Dart:html APIs from the IDL database."""
7
8import emitter
9import logging
10import monitored
11import os
12import re
13from collections import OrderedDict
14from generator import *
15from htmldartgenerator import *
16from htmlrenamer import generateCallbackInterface
17
18_logger = logging.getLogger('systemhtml')
19
20
21def CanUseStaticExtensions(interface, should):
22 if not should:
23 return False
24 static_extension_interfaces = [] # Classes to be migrated
25 return interface in static_extension_interfaces
26
27
28HTML_LIBRARY_NAMES = [
29 'html', 'indexed_db', 'svg', 'web_audio', 'web_gl', 'web_sql'
30]
31
32_safe_to_ignore_shadowing_members = monitored.Set(
33 'systemhtml._safe_to_ignore_shadowing_members', [
34 'SVGElement.tabIndex',
35 'SVGStyleElement.title',
36 ])
37
38_js_custom_members = monitored.Set(
39 'systemhtml._js_custom_members',
40 [
41 'AudioContext.createGain',
42 'AudioContext.createScriptProcessor',
43 'CanvasRenderingContext2D.drawImage',
44 'CanvasRenderingContext2D.fillText',
45 'CanvasRenderingContext2D.lineDashOffset',
46 'CanvasRenderingContext2D.setLineDash',
47 'Console.memory',
48 'ConsoleBase.assertCondition',
49 'ConsoleBase.clear',
50 'ConsoleBase.count',
51 'ConsoleBase.countReset',
52 'ConsoleBase.debug',
53 'ConsoleBase.dir',
54 'ConsoleBase.dirxml',
55 'ConsoleBase.error',
56 'ConsoleBase.group',
57 'ConsoleBase.groupCollapsed',
58 'ConsoleBase.groupEnd',
59 'ConsoleBase.info',
60 'ConsoleBase.log',
61 'ConsoleBase.markTimeline',
62 'ConsoleBase.profile',
63 'ConsoleBase.profileEnd',
64 'ConsoleBase.table',
65 'ConsoleBase.time',
66 'ConsoleBase.timeEnd',
67 'ConsoleBase.timeStamp',
68 'ConsoleBase.trace',
69 'ConsoleBase.warn',
70 'WebKitCSSKeyframesRule.insertRule',
71 'CSSStyleDeclaration.setProperty',
72 'CSSStyleDeclaration.__propertyQuery__',
73 'Document.createNodeIterator',
74 'Document.createTreeWalker',
75 'DOMException.name',
76 'DOMException.toString',
77 # ListMixin already provides this method although the implementation
78 # is slower. As this class is obsolete anyway, we ignore the slowdown in
79 # DOMStringList performance.
80 'DOMStringList.contains',
81 'Element.animate',
82 'Element.createShadowRoot',
83 'Element.insertAdjacentElement',
84 'Element.insertAdjacentHTML',
85 'Element.insertAdjacentText',
86 'Element.remove',
87 'Element.shadowRoot',
88 'Element.matches',
89 'ElementEvents.mouseWheel',
90 'ElementEvents.transitionEnd',
91 'FileReader.result',
92 'HTMLAnchorElement.toString',
93 'HTMLAreaElement.toString',
94 'HTMLTableElement.createTBody',
95 'IDBCursor.next',
96 'IDBDatabase.transaction',
97 'IDBDatabase.transactionList',
98 'IDBDatabase.transactionStore',
99 'IDBDatabase.transactionStores',
100 'KeyboardEvent.initKeyboardEvent',
101 'Location.origin',
102 'Location.toString',
103 'MouseEvent.offsetX',
104 'MouseEvent.offsetY',
105 'Navigator.language',
106 'Navigator.webkitGetUserMedia',
107 'ScriptProcessorNode._setEventListener',
108 'URL.createObjectURL',
109 'URL.createObjectUrlFromSource',
110 'URL.createObjectUrlFromStream',
111 'URL.createObjectUrlFromBlob',
112 'URL.revokeObjectURL',
113 'URL.toString',
114 'WheelEvent.deltaMode',
115 'Window.cancelAnimationFrame',
116 'Window.console',
117 'Window.document',
118 'Window.indexedDB',
119 'Window.location',
120 'Window.open',
121 'Window.requestAnimationFrame',
122 'Window.scrollX',
123 'Window.scrollY'
124 # 'WorkerContext.indexedDB', # Workers
125 ],
126 dart2jsOnly=True)
127
128_js_custom_constructors = monitored.Set(
129 'systemhtml._js_custom_constructors', [
130 'AudioContext',
131 'Blob',
132 'Comment',
133 'MutationObserver',
134 'PaymentRequest',
135 'RTCIceCandidate',
136 'RTCPeerConnection',
137 'RTCSessionDescription',
138 'SpeechRecognition',
139 ],
140 dart2jsOnly=True)
141
142# Classes that offer only static methods, and therefore we should suppress
143# constructor creation.
144_static_classes = set(['Url'])
145
146# Callback typedefs with generic List (List<nnn>) convert to List
147_callback_list_generics_mapping = monitored.Set(
148 'systemhtml._callback_list_generics_mapping', [
149 'List<Entry>',
150 'List<IntersectionObserverEntry>',
151 'List<MutationRecord>',
152 'List<_Report>',
153 'List<ResizeObserverEntry>',
154 ])
155
156
157# Information for generating element constructors.
158#
159# TODO(sra): maybe remove all the argument complexity and use cascades.
160#
161# var c = new CanvasElement(width: 100, height: 70);
162# var c = new CanvasElement()..width = 100..height = 70;
163#
165
166 def __init__(self,
167 name=None,
168 tag=None,
169 params=[],
170 opt_params=[],
171 factory_provider_name='document'):
172 self.name = name # The constructor name 'h1' in 'HeadingElement.h1'
173 self.tag = tag or name # The HTML or SVG tag
174 self.params = params
175 self.opt_params = opt_params
176 self.factory_provider_name = factory_provider_name
177
178 def ConstructorInfo(self, interface_name):
179 info = OperationInfo()
180 info.overloads = None
181 info.declared_name = interface_name
182 info.name = interface_name
183 info.constructor_name = self.name
184 info.js_name = None
185 info.type_name = interface_name
186 # optional parameters are always nullable
187 info.param_infos = [
188 ParamInfo(name=tXn[1],
189 type_id=tXn[0],
190 is_optional=True,
191 is_nullable=True,
192 default_value=None,
193 default_value_is_null=False) for tXn in self.opt_params
194 ]
195 info.requires_named_arguments = True
196 info.factory_parameters = ['"%s"' % self.tag]
197 info.pure_dart_constructor = True
198 return info
199
200
201_html_element_constructors = monitored.Dict(
202 'systemhtml._html_element_constructors',
203 {
204 'HTMLAnchorElement':
205 ElementConstructorInfo(tag='a', opt_params=[('DOMString', 'href')]),
206 'HTMLAreaElement':
207 'area',
208 'HTMLButtonElement':
209 'button',
210 'HTMLBRElement':
211 'br',
212 'HTMLBaseElement':
213 'base',
214 'HTMLBodyElement':
215 'body',
216 'HTMLButtonElement':
217 'button',
218 'HTMLCanvasElement':
220 tag='canvas', opt_params=[('int', 'width'), ('int', 'height')]),
221 'HTMLContentElement':
222 'content',
223 'HTMLDataListElement':
224 'datalist',
225 'HTMLDListElement':
226 'dl',
227 'HTMLDetailsElement':
228 'details',
229 'HTMLDivElement':
230 'div',
231 'HTMLEmbedElement':
232 'embed',
233 'HTMLFieldSetElement':
234 'fieldset',
235 'HTMLFormElement':
236 'form',
237 'HTMLHRElement':
238 'hr',
239 'HTMLHeadElement':
240 'head',
241 'HTMLHeadingElement': [
248 ],
249 'HTMLHtmlElement':
250 'html',
251 'HTMLIFrameElement':
252 'iframe',
253 'HTMLImageElement':
255 tag='img',
256 opt_params=[('DOMString', 'src'), ('int', 'width'),
257 ('int', 'height')]),
258 'HTMLKeygenElement':
259 'keygen',
260 'HTMLLIElement':
261 'li',
262 'HTMLLabelElement':
263 'label',
264 'HTMLLegendElement':
265 'legend',
266 'HTMLLinkElement':
267 'link',
268 'HTMLMapElement':
269 'map',
270 'HTMLMenuElement':
271 'menu',
272 'HTMLMetaElement':
273 'meta',
274 'HTMLMeterElement':
275 'meter',
276 'HTMLOListElement':
277 'ol',
278 'HTMLObjectElement':
279 'object',
280 'HTMLOptGroupElement':
281 'optgroup',
282 'HTMLOutputElement':
283 'output',
284 'HTMLParagraphElement':
285 'p',
286 'HTMLParamElement':
287 'param',
288 'HTMLPreElement':
289 'pre',
290 'HTMLProgressElement':
291 'progress',
292 'HTMLQuoteElement':
293 'q',
294 'HTMLScriptElement':
295 'script',
296 'HTMLSelectElement':
297 'select',
298 'HTMLShadowElement':
299 'shadow',
300 'HTMLSourceElement':
301 'source',
302 'HTMLSpanElement':
303 'span',
304 'HTMLStyleElement':
305 'style',
306 'HTMLTableCaptionElement':
307 'caption',
308 'HTMLTableCellElement':
309 'td',
310 'HTMLTableColElement':
311 'col',
312 'HTMLTableElement':
313 'table',
314 'HTMLTableRowElement':
315 'tr',
316 #'HTMLTableSectionElement' <thead> <tbody> <tfoot>
317 'HTMLTemplateElement':
318 'template',
319 'HTMLTextAreaElement':
320 'textarea',
321 'HTMLTitleElement':
322 'title',
323 'HTMLTrackElement':
324 'track',
325 'HTMLUListElement':
326 'ul',
327 'HTMLVideoElement':
328 'video'
329 })
330
331_svg_element_constructors = monitored.Dict(
332 'systemhtml._svg_element_constructors', {
333 'SVGAElement': 'a',
334 'SVGAltGlyphElement': 'altGlyph',
335 'SVGAnimateElement': 'animate',
336 'SVGAnimateMotionElement': 'animateMotion',
337 'SVGAnimateTransformElement': 'animateTransform',
338 'SVGAnimationElement': 'animation',
339 'SVGCircleElement': 'circle',
340 'SVGClipPathElement': 'clipPath',
341 'SVGCursorElement': 'cursor',
342 'SVGDefsElement': 'defs',
343 'SVGDescElement': 'desc',
344 'SVGEllipseElement': 'ellipse',
345 'SVGFEBlendElement': 'feBlend',
346 'SVGFEColorMatrixElement': 'feColorMatrix',
347 'SVGFEComponentTransferElement': 'feComponentTransfer',
348 'SVGFEConvolveMatrixElement': 'feConvolveMatrix',
349 'SVGFEDiffuseLightingElement': 'feDiffuseLighting',
350 'SVGFEDisplacementMapElement': 'feDisplacementMap',
351 'SVGFEDistantLightElement': 'feDistantLight',
352 'SVGFEFloodElement': 'feFlood',
353 'SVGFEFuncAElement': 'feFuncA',
354 'SVGFEFuncBElement': 'feFuncB',
355 'SVGFEFuncGElement': 'feFuncG',
356 'SVGFEFuncRElement': 'feFuncR',
357 'SVGFEGaussianBlurElement': 'feGaussianBlur',
358 'SVGFEImageElement': 'feImage',
359 'SVGFEMergeElement': 'feMerge',
360 'SVGFEMergeNodeElement': 'feMergeNode',
361 'SVGFEMorphology': 'feMorphology',
362 'SVGFEOffsetElement': 'feOffset',
363 'SVGFEPointLightElement': 'fePointLight',
364 'SVGFESpecularLightingElement': 'feSpecularLighting',
365 'SVGFESpotLightElement': 'feSpotLight',
366 'SVGFETileElement': 'feTile',
367 'SVGFETurbulenceElement': 'feTurbulence',
368 'SVGFilterElement': 'filter',
369 'SVGForeignObjectElement': 'foreignObject',
370 'SVGGlyphElement': 'glyph',
371 'SVGGElement': 'g',
372 'SVGHKernElement': 'hkern',
373 'SVGImageElement': 'image',
374 'SVGLinearGradientElement': 'linearGradient',
375 'SVGLineElement': 'line',
376 'SVGMarkerElement': 'marker',
377 'SVGMaskElement': 'mask',
378 'SVGMPathElement': 'mpath',
379 'SVGPathElement': 'path',
380 'SVGPatternElement': 'pattern',
381 'SVGPolygonElement': 'polygon',
382 'SVGPolylineElement': 'polyline',
383 'SVGRadialGradientElement': 'radialGradient',
384 'SVGRectElement': 'rect',
385 'SVGScriptElement': 'script',
386 'SVGSetElement': 'set',
387 'SVGStopElement': 'stop',
388 'SVGStyleElement': 'style',
389 'SVGSwitchElement': 'switch',
390 'SVGSymbolElement': 'symbol',
391 'SVGTextElement': 'text',
392 'SVGTitleElement': 'title',
393 'SVGTRefElement': 'tref',
394 'SVGTSpanElement': 'tspan',
395 'SVGUseElement': 'use',
396 'SVGViewElement': 'view',
397 'SVGVKernElement': 'vkern',
398 })
399
400_element_constructors = {
401 'html': _html_element_constructors,
402 'indexed_db': {},
403 'svg': _svg_element_constructors,
404 'typed_data': {},
405 'web_audio': {},
406 'web_gl': {},
407 'web_sql': {},
408}
409
410_factory_ctr_strings = {
411 'html': {
412 'provider_name': 'document',
413 'constructor_name': 'createElement'
414 },
415 'indexed_db': {
416 'provider_name': 'document',
417 'constructor_name': 'createElement'
418 },
419 'svg': {
420 'provider_name': '_SvgElementFactoryProvider',
421 'constructor_name': 'createSvgElement_tag',
422 },
423 'typed_data': {
424 'provider_name': 'document',
425 'constructor_name': 'createElement'
426 },
427 'web_audio': {
428 'provider_name': 'document',
429 'constructor_name': 'createElement'
430 },
431 'web_gl': {
432 'provider_name': 'document',
433 'constructor_name': 'createElement'
434 },
435 'web_sql': {
436 'provider_name': 'document',
437 'constructor_name': 'createElement'
438 },
439}
440
441
443 element_constructors,
444 factory_provider_name='_Elements'):
445 """Returns list of ElementConstructorInfos about the convenience constructors
446 for an Element or SvgElement."""
447 # TODO(sra): Handle multiple and named constructors.
448 if typename not in element_constructors:
449 return []
450 infos = element_constructors[typename]
451 if isinstance(infos, str):
453 tag=infos, factory_provider_name=factory_provider_name)
454 if not isinstance(infos, list):
455 infos = [infos]
456 return infos
457
458
459# ------------------------------------------------------------------------------
460def SvgSupportStr(tagName):
461 return 'Svg%s' % ElemSupportStr(tagName)
462
463
464def ElemSupportStr(tagName):
465 return "Element.isTagSupported('%s')" % tagName
466
467
468_js_support_checks_basic_element_with_constructors = [
469 'HTMLContentElement',
470 'HTMLDataListElement',
471 'HTMLDetailsElement',
472 'HTMLEmbedElement',
473 'HTMLMeterElement',
474 'HTMLObjectElement',
475 'HTMLOutputElement',
476 'HTMLProgressElement',
477 'HTMLTemplateElement',
478 'HTMLTrackElement',
479]
480
481_js_support_checks_additional_element = [
482 # IE creates keygen as Block elements
483 'HTMLKeygenElement',
484 'SVGAltGlyphElement',
485 'SVGAnimateElement',
486 'SVGAnimateMotionElement',
487 'SVGAnimateTransformElement',
488 'SVGCursorElement',
489 'SVGFEBlendElement',
490 'SVGFEColorMatrixElement',
491 'SVGFEComponentTransferElement',
492 'SVGFEConvolveMatrixElement',
493 'SVGFEDiffuseLightingElement',
494 'SVGFEDisplacementMapElement',
495 'SVGFEDistantLightElement',
496 'SVGFEFloodElement',
497 'SVGFEFuncAElement',
498 'SVGFEFuncBElement',
499 'SVGFEFuncGElement',
500 'SVGFEFuncRElement',
501 'SVGFEGaussianBlurElement',
502 'SVGFEImageElement',
503 'SVGFEMergeElement',
504 'SVGFEMergeNodeElement',
505 'SVGFEMorphology',
506 'SVGFEOffsetElement',
507 'SVGFEPointLightElement',
508 'SVGFESpecularLightingElement',
509 'SVGFESpotLightElement',
510 'SVGFETileElement',
511 'SVGFETurbulenceElement',
512 'SVGFilterElement',
513 'SVGForeignObjectElement',
514 'SVGSetElement',
515]
516
517js_support_checks = dict(
518 list({
519 'Animation':
520 "JS('bool', '!!(document.body.animate)')",
521 'AudioContext':
522 "JS('bool', '!!(window.AudioContext ||"
523 " window.webkitAudioContext)')",
524 'Crypto':
525 "JS('bool', '!!(window.crypto && window.crypto.getRandomValues)')",
526 'Database':
527 "JS('bool', '!!(window.openDatabase)')",
528 'DOMPoint':
529 "JS('bool', '!!(window.DOMPoint) || !!(window.WebKitPoint)')",
530 'ApplicationCache':
531 "JS('bool', '!!(window.applicationCache)')",
532 'DOMFileSystem':
533 "JS('bool', '!!(window.webkitRequestFileSystem)')",
534 'FormData':
535 "JS('bool', '!!(window.FormData)')",
536 'HashChangeEvent':
537 "Device.isEventTypeSupported('HashChangeEvent')",
538 'HTMLShadowElement':
539 ElemSupportStr('shadow'),
540 'HTMLTemplateElement':
541 ElemSupportStr('template'),
542 'MediaStreamEvent':
543 "Device.isEventTypeSupported('MediaStreamEvent')",
544 'MediaStreamTrackEvent':
545 "Device.isEventTypeSupported('MediaStreamTrackEvent')",
546 'MediaSource':
547 "JS('bool', '!!(window.MediaSource)')",
548 'Notification':
549 "JS('bool', '!!(window.Notification)')",
550 'Performance':
551 "JS('bool', '!!(window.performance)')",
552 'SpeechRecognition':
553 "JS('bool', '!!(window.SpeechRecognition || "
554 "window.webkitSpeechRecognition)')",
555 'SVGExternalResourcesRequired':
556 ('supported(SvgElement element)',
557 "JS('bool', '#.externalResourcesRequired !== undefined && "
558 "#.externalResourcesRequired.animVal !== undefined', "
559 "element, element)"),
560 'SVGLangSpace':
561 ('supported(SvgElement element)',
562 "JS('bool', '#.xmlspace !== undefined && #.xmllang !== undefined', "
563 "element, element)"),
564 'TouchList':
565 "JS('bool', '!!document.createTouchList')",
566 'WebGLRenderingContext':
567 "JS('bool', '!!(window.WebGLRenderingContext)')",
568 'WebSocket':
569 "JS('bool', 'typeof window.WebSocket != \"undefined\"')",
570 'Worker':
571 "JS('bool', '(typeof window.Worker != \"undefined\")')",
572 'XSLTProcessor':
573 "JS('bool', '!!(window.XSLTProcessor)')",
574 }.items()) + list(
575 dict((key,
576 SvgSupportStr(_svg_element_constructors[key]) if key.startswith(
577 'SVG') else ElemSupportStr(_html_element_constructors[key]))
578 for key in _js_support_checks_basic_element_with_constructors +
579 _js_support_checks_additional_element).items()))
580
581# JavaScript element class names of elements for which createElement does not
582# always return exactly the right element, either because it might not be
583# supported, or some browser does something weird.
584_js_unreliable_element_factories = set(
585 _js_support_checks_basic_element_with_constructors +
586 _js_support_checks_additional_element + [
587 'HTMLEmbedElement',
588 'HTMLObjectElement',
589 'HTMLShadowElement',
590 'HTMLTemplateElement',
591 ])
592
593# ------------------------------------------------------------------------------
594
595
597 """Generates dart interface and implementation for the DOM IDL interface."""
598
599 def __init__(self, options, library_emitter, event_generator,
600 prototype_event_generator, interface, backend):
601 self._renamer = options.renamer
602 self._database = options.database
603 self._template_loader = options.templates
604 self._type_registry = options.type_registry
605 self._options = options
606 self._library_emitter = library_emitter
607 self._event_generator = event_generator
608 self._prototype_event_generator = prototype_event_generator
609 self._interface = interface
610 self._backend = backend
611 self._interface_type_info = self._type_registry.TypeInfo(
612 self._interface.id)
613 self._library_name = self._renamer.GetLibraryName(self._interface)
614 self._metadata = options.metadata
615
616 def Generate(self):
617 if IsCustomType(self._interface.id):
618 pass
619 elif 'Callback' in self._interface.ext_attrs:
620 if len(GetCallbackHandlers(self._interface)) > 0:
621 self.GenerateCallback()
622 elif generateCallbackInterface(self._interface.id):
623 self.GenerateInterface()
624 else:
625 return
626 else:
627 self.GenerateInterface()
628
630 """Generates a typedef for the callback interface."""
631 typedef_name = self._renamer.RenameInterface(self._interface)
632 if not typedef_name:
633 return
634
635 info = GetCallbackInfo(self._interface)
636 code = self._library_emitter.FileEmitter(self._interface.id,
637 self._library_name)
638 code.Emit(self._template_loader.Load('callback.darttemplate'))
639
640 annotations = self._metadata.GetFormattedMetadata(
641 self._library_name, self._interface)
642
643 params = info.ParametersAsDeclaration(self._DartType)
644
645 types = params.split()
646 if len(types) > 0:
647 mapType = types[0] in _callback_list_generics_mapping
648 if mapType is True:
649 types[0] = 'List'
650 params = " ".join(types)
651
652 code.Emit(
653 '$(ANNOTATIONS)typedef void $NAME($PARAMS);\n',
654 ANNOTATIONS=annotations,
655 NAME=typedef_name,
656 PARAMS=params)
657 self._backend.GenerateCallback(info)
658
660 interface_name = self._interface_type_info.interface_name()
661
662 implementation_name = self._interface_type_info.implementation_name()
663 self._library_emitter.AddTypeEntry(
664 self._library_name, self._interface.id, implementation_name)
665
666 factory_provider = None
667 if interface_name in interface_factories:
668 factory_provider = interface_factories[interface_name]
669 factory_constructor_name = None
670
671 constructors = []
672 if interface_name in _static_classes:
673 constructor_info = None
674 else:
675 constructor_info = AnalyzeConstructor(self._interface)
676 if constructor_info:
677 constructors.append(constructor_info)
678 # TODO(antonm): consider removing it later.
679 factory_provider = interface_name
680
681 # HTML Elements and SVG Elements have convenience constructors.
683 self._interface.id,
684 _element_constructors[self._library_name],
685 factory_provider_name=_factory_ctr_strings[self._library_name]
686 ['provider_name'])
687
688 if infos:
689 factory_constructor_name = _factory_ctr_strings[
690 self._library_name]['constructor_name']
691
692 for info in infos:
693 constructors.append(info.ConstructorInfo(self._interface.id))
694 if factory_provider and factory_provider != info.factory_provider_name:
695 _logger.warn('Conflicting factory provider names: %s != %s' %
696 (factory_provider, info.factory_provider_name))
697 factory_provider = info.factory_provider_name
698
699 implementation_emitter = self._ImplementationEmitter()
700
701 base_type_info = None
702 if self._interface.parents:
703 supertype = self._interface.parents[0].type.id
704 if not IsDartCollectionType(supertype) and not IsPureInterface(
705 supertype, self._database):
706 base_type_info = self._type_registry.TypeInfo(supertype)
707
708 if base_type_info:
709 base_class = base_type_info.implementation_name()
710 else:
711 base_class = self._backend.RootClassName()
712
713 implements = self._backend.AdditionalImplementedInterfaces()
714 for parent in self._interface.parents:
715 parent_type_info = self._type_registry.TypeInfo(parent.type.id)
716 if parent_type_info.interface_name() != base_class and \
717 parent_type_info != base_type_info:
718 implements.append(parent_type_info.interface_name())
719
720 secure_base_name = self._backend.SecureBaseName(interface_name)
721 if secure_base_name:
722 implements.append(secure_base_name)
723
724 implements_str = ''
725 if implements:
726 # Get rid of duplicates using OrderedDict.
727 implements = list(OrderedDict([(i, None) for i in implements]))
728 implements_str = ' implements ' + ', '.join(implements)
729
730 mixins = self._backend.Mixins()
731
732 mixins_str = ''
733 if mixins:
734 mixins_str = ' with ' + ', '.join(mixins)
735 if not base_class:
736 base_class = 'JavaScriptObject'
737 elif (base_class == 'NativeFieldWrapperClass2' and
738 self._options.dart_js_interop and
739 not (isinstance(self._backend, Dart2JSBackend))):
740 base_class = 'DartHtmlDomObject'
741
742 annotations = self._metadata.GetFormattedMetadata(
743 self._library_name, self._interface, None, '')
744
745 class_modifiers = ''
746 if (self._renamer.ShouldSuppressInterface(self._interface) or
747 IsPureInterface(self._interface.id, self._database)):
748 # XMLHttpRequestProgressEvent can't be abstract we need to instantiate
749 # for JsInterop.
750 if (not (isinstance(self._backend, Dart2JSBackend)) and
751 (self._interface.id == 'XMLHttpRequestProgressEvent' or
752 self._interface.id == 'DOMStringMap')):
753 # Suppress abstract for XMLHttpRequestProgressEvent and DOMStringMap
754 # for Dartium. Need to be able to instantiate the class; can't be abstract.
755 class_modifiers = ''
756 else:
757 # For Dartium w/ JsInterop these suppressed interfaces are needed to
758 # instantiate the internal classes.
759 if (self._renamer.ShouldSuppressInterface(self._interface) and
760 not (isinstance(self._backend, Dart2JSBackend)) and
761 self._options.dart_js_interop):
762 class_modifiers = ''
763 else:
764 class_modifiers = 'abstract '
765
766 native_spec = ''
767 if not IsPureInterface(self._interface.id, self._database):
768 native_spec = self._backend.NativeSpec()
769
770 class_name = self._interface_type_info.implementation_name()
771
772 js_interop_wrapper = '''
773
774 @Deprecated("Internal Use Only")
775 external static Type get instanceRuntimeType;
776
777 @Deprecated("Internal Use Only")
778 {0}.internal_() : super.internal_();
779
780'''.format(class_name)
781 if base_class == 'NativeFieldWrapperClass2' or base_class == 'DartHtmlDomObject':
782 js_interop_wrapper = '''
783
784 @Deprecated("Internal Use Only")
785 external static Type get instanceRuntimeType;
786
787 @Deprecated("Internal Use Only")
788 {0}.internal_() {{ }}
789'''.format(class_name)
790 # Change to use the synthesized class so we can construct with a mixin
791 # classes prefixed with name of NativeFieldWrapperClass2 don't have a
792 # default constructor so classes with mixins can't be new'd.
793 if (self._options.templates._conditions['DARTIUM'] and
794 self._options.dart_js_interop and
795 (self._interface.id == 'NamedNodeMap' or
796 self._interface.id == 'CSSStyleDeclaration')):
797 base_class = 'DartHtmlDomObject'
798
799 maplikeKeyType = ''
800 maplikeValueType = ''
801 if self._interface.isMaplike:
802 maplikeKeyType = self._type_registry.\
803 _TypeInfo(self._interface.maplike_key_value[0].id).dart_type()
804 maplikeValueType = 'dynamic'
805 mixins_str = " with MapMixin<%s, %s>" % (maplikeKeyType,
806 maplikeValueType)
807
808 implementation_members_emitter = implementation_emitter.Emit(
809 self._backend.ImplementationTemplate(),
810 LIBRARYNAME='dart.dom.%s' % self._library_name,
811 ANNOTATIONS=annotations,
812 CLASS_MODIFIERS=class_modifiers,
813 CLASSNAME=class_name,
814 EXTENDS=' extends %s' % base_class if base_class else '',
815 IMPLEMENTS=implements_str,
816 MIXINS=mixins_str,
817 DOMNAME=self._interface.doc_js_name,
818 NATIVESPEC=native_spec,
819 KEYTYPE=maplikeKeyType,
820 VALUETYPE=maplikeValueType,
821 NULLABLE='?',
822 NULLSAFECAST=True,
823 NULLASSERT='!')
824 if self._interface.doc_js_name is 'RadioNodeList':
825 print(self._backend.ImplementationTemplate())
826 print(implementation_members_emitter)
827 stream_getter_signatures_emitter = None
828 element_stream_getters_emitter = None
829 class_members_emitter = None
830 if type(implementation_members_emitter) == tuple:
831 # We add event stream getters for both Element and ElementList, so in
832 # impl_Element.darttemplate, we have two additional "holes" for emitters
833 # to fill in, with small variations. These store these specialized
834 # emitters.
835 if (len(implementation_members_emitter) == 3):
836 stream_getter_signatures_emitter = \
837 implementation_members_emitter[0]
838 element_stream_getters_emitter = implementation_members_emitter[
839 1]
840 implementation_members_emitter = \
841 implementation_members_emitter[2]
842
843 # We add special emitters for classes migrated to static type extensions
844 elif (len(implementation_members_emitter) == 2):
845 class_members_emitter = \
846 implementation_members_emitter[0]
847 implementation_members_emitter = \
848 implementation_members_emitter[1]
849 self._backend.StartInterface(implementation_members_emitter)
850 self._backend.EmitHelpers(base_class, class_members_emitter)
851 self._event_generator.EmitStreamProviders(
852 self._interface, self._backend.CustomJSMembers(),
853 implementation_members_emitter, self._library_name)
854 self._prototype_event_generator.CollectStreamProviders(
855 self._interface, self._backend.CustomJSMembers(),
856 self._library_name)
857 self._backend.AddConstructors(constructors, factory_provider,
858 factory_constructor_name,
859 class_members_emitter)
860
861 isElement = False
862 for parent in self._database.Hierarchy(self._interface):
863 if parent.id == 'Element':
864 isElement = True
865
866 # Write out the JsInterop code.
867 if (implementation_members_emitter and
868 self._options.templates._conditions['DARTIUM'] and
869 self._options.dart_js_interop and
870 not IsPureInterface(self._interface.id, self._database)):
871 implementation_members_emitter.Emit(js_interop_wrapper)
872
873 if isElement and self._interface.id != 'Element':
874 implementation_members_emitter.Emit(
875 ' /**\n'
876 ' * Constructor instantiated by the DOM when a custom element has been created.\n'
877 ' *\n'
878 ' * This can only be called by subclasses from their created constructor.\n'
879 ' */\n'
880 ' $CLASSNAME.created() : super.created();\n',
881 CLASSNAME=self._interface_type_info.implementation_name())
882
883 self._backend.EmitSupportCheck()
884
885 merged_interface = self._interface_type_info.merged_interface()
886 if merged_interface:
887 self._backend.AddMembers(
888 self._database.GetInterface(merged_interface),
889 not self._backend.ImplementsMergedMembers())
890
891 self._backend.AddMembers(self._interface, False,
892 self._options.dart_js_interop)
893 self._backend.AddSecondaryMembers(self._interface)
894 self._event_generator.EmitStreamGetters(
895 self._interface, [], implementation_members_emitter,
896 self._library_name, stream_getter_signatures_emitter,
897 element_stream_getters_emitter)
898 self._prototype_event_generator.CollectStreamGetters(
899 self._interface, [], self._library_name)
900 self._backend.FinishInterface()
901
902 def _ImplementationEmitter(self):
903 basename = self._interface_type_info.implementation_name()
904 if (self._interface_type_info.merged_into() and
905 self._backend.ImplementsMergedMembers()):
906 # Merged members are implemented in target interface implementation.
907 return emitter.Emitter()
908 return self._library_emitter.FileEmitter(basename, self._library_name)
909
910 def _DartType(self, type_name):
911 return self._type_registry.DartType(type_name)
912
913
914# ------------------------------------------------------------------------------
915''' TODO(terry): Current idl_parser (Chrome) doesn't keep the Promise type e.g.,
916 Promise<T> in the AST so there is no way to pull this out. Need
917 to investigate getting the Chrome folks to fix. However, they
918 don't use this in the C++ code generation and don't have a need
919 for this feature. For now I have a table that maps to the
920 parameterized Promise type.
921'''
922promise_attributes = monitored.Dict(
923 'systemhtml.promise_attr_type', {
924 "Animation.finished": {
925 "type": "Animation",
926 "creates": "Animation"
927 },
928 "Animation.ready": {
929 "type": "Animation",
930 "creates": "Animation"
931 },
932 "BeforeInstallPromptEvent.userChoice": {
933 "type": "dictionary"
934 },
935 "FontFace.loaded": {
936 "type": "FontFace",
937 "creates": "FontFace"
938 },
939 "FontFaceSet.ready": {
940 "type": "FontFaceSet",
941 "creates": "FontFaceSet"
942 },
943 "MediaKeySession.closed": {
944 "type": "void"
945 },
946 "PresentationReceiver.connectionList": {
947 "type": "PresentationConnectionList",
948 "creates": "PresentationConnectionList"
949 },
950 "ServiceWorkerContainer.ready": {
951 "type": "ServiceWorkerRegistration",
952 "creates": "ServiceWorkerRegistration"
953 },
954 })
955
956promise_operations = monitored.Dict(
957 'systemhtml.promise_oper_type', {
958 "Clipboard.read": {
959 "type": "DataTransfer",
960 "creates": "DataTransfer"
961 },
962 "Clipboard.readText": {
963 "type": "String"
964 },
965 "FontFace.load": {
966 "type": "FontFace",
967 "creates": "FontFace"
968 },
969 "FontFaceSet.load": {
970 "type": "List<dynamic>"
971 },
972 "OffscreenCanvas.load": {
973 "type": "Blob",
974 "creates": "Blob"
975 },
976 "BackgroundFetchManager.fetch": {
977 "type": "BackgroundFetchRegistration",
978 "creates": "BackgroundFetchRegistration"
979 },
980 "BackgroundFetchManager.get": {
981 "type": "BackgroundFetchRegistration",
982 "creates": "BackgroundFetchRegistration"
983 },
984 "BackgroundFetchManager.getIds": {
985 "type": "List<dynamic>"
986 },
987 "BackgroundFetchRegistration.abort": {
988 "type": "bool"
989 },
990 "SyncManager.getTags": {
991 "type": "List<dynamic>"
992 },
993 "BudgetService.getCost": {
994 "type": "double"
995 },
996 "BudgetService.getBudget": {
997 "type": "BudgetState",
998 "creates": "BudgetState"
999 },
1000 "BudgetService.reserve": {
1001 "type": "bool"
1002 },
1003 "Body.blob": {
1004 "type": "Blob",
1005 "creates": "Blob"
1006 },
1007 "Body.formData": {
1008 "type": "FormData",
1009 "creates": "FormData"
1010 },
1011 "Body.text": {
1012 "type": "String"
1013 },
1014 "ImageCapture.getPhotoCapabilities": {
1015 "type": "PhotoCapabilities",
1016 "creates": "PhotoCapabilities"
1017 },
1018 "ImageCapture.getPhotoSettings": {
1019 "type": "dictionary"
1020 },
1021 "ImageCapture.takePhoto": {
1022 "type": "Blob",
1023 "creates": "Blob"
1024 },
1025 "ImageCapture.grabFrame": {
1026 "type": "ImageBitmap",
1027 "creates": "ImageBitmap"
1028 },
1029 "Navigator.getInstalledRelatedApps": {
1030 "type": "RelatedApplication",
1031 "creates": "RelatedApplication"
1032 },
1033 "OffscreenCanvas.convertToBlob": {
1034 "type": "Blob",
1035 "creates": "Blob"
1036 },
1037 "MediaCapabilities.decodingInfo": {
1038 "type": "MediaCapabilitiesInfo",
1039 "creates": "MediaCapabilitiesInfo"
1040 },
1041 "MediaCapabilities.encodingInfo": {
1042 "type": "MediaCapabilitiesInfo",
1043 "creates": "MediaCapabilitiesInfo"
1044 },
1045 "MediaDevices.enumerateDevices": {
1046 "type": "List<dynamic>"
1047 },
1048 "MediaDevices.getUserMedia": {
1049 "type": "MediaStream",
1050 "creates": "MediaStream"
1051 },
1052 "ServiceWorkerRegistration.getNotifications": {
1053 "type": "List<dynamic>"
1054 },
1055 "PaymentInstruments.delete": {
1056 "type": "bool"
1057 },
1058 "PaymentInstruments.get": {
1059 "type": "dictionary"
1060 },
1061 "PaymentInstruments.keys": {
1062 "type": "List<dynamic>"
1063 },
1064 "PaymentInstrumentshas.": {
1065 "type": "bool"
1066 },
1067 "PaymentRequest.show": {
1068 "type": "PaymentResponse",
1069 "creates": "PaymentResponse"
1070 },
1071 "PaymentRequest.canMakePayment": {
1072 "type": "bool"
1073 },
1074 "PaymentRequestEvent.openWindow": {
1075 "type": "WindowClient",
1076 "creates": "WindowClient"
1077 },
1078 "RTCPeerConnection.createOffer": {
1079 "type": "RtcSessionDescription",
1080 "creates": "RtcSessionDescription"
1081 },
1082 "RTCPeerConnection.createAnswer": {
1083 "type": "RtcSessionDescription",
1084 "creates": "RtcSessionDescription"
1085 },
1086 "RTCPeerConnection.getStats": {
1087 "type": "RtcStatsReport",
1088 "maplike": "RTCStatsReport",
1089 "creates": "RtcStatsReport"
1090 },
1091 "RTCPeerConnection.generateCertificate": {
1092 "type": "RtcCertificate",
1093 "creates": "RtcCertificate"
1094 },
1095 "Permissions.query": {
1096 "type": "PermissionStatus",
1097 "creates": "PermissionStatus"
1098 },
1099 "Permissions.request": {
1100 "type": "PermissionStatus",
1101 "creates": "PermissionStatus"
1102 },
1103 "Permissions.revoke": {
1104 "type": "PermissionStatus",
1105 "creates": "PermissionStatus"
1106 },
1107 "Permissions.requestAll": {
1108 "type": "PermissionStatus",
1109 "creates": "PermissionStatus"
1110 },
1111 "PresentationRequest.start": {
1112 "type": "PresentationConnection",
1113 "creates": "PresentationConnection"
1114 },
1115 "PresentationRequest.reconnect": {
1116 "type": "PresentationConnection",
1117 "creates": "PresentationConnection"
1118 },
1119 "PresentationRequest.getAvailability": {
1120 "type": "PresentationAvailability",
1121 "creates": "PresentationAvailability"
1122 },
1123 "PushManager.subscribe": {
1124 "type": "PushSubscription",
1125 "creates": "PushSubscription"
1126 },
1127 "PushManager.getSubscription": {
1128 "type": "PushSubscription",
1129 "creates": "PushSubscription"
1130 },
1131 "PushSubscription.unsubscribe": {
1132 "type": "bool"
1133 },
1134 "StorageManager.persisted": {
1135 "type": "bool"
1136 },
1137 "StorageManager.persist": {
1138 "type": "bool"
1139 },
1140 "StorageManager.estimate": {
1141 "type": "dictionary"
1142 },
1143 "RemotePlayback.watchAvailability": {
1144 "type": "int"
1145 },
1146 "Clients.matchAll": {
1147 "type": "List<dynamic>"
1148 },
1149 "Clients.openWindow": {
1150 "type": "WindowClient",
1151 "creates": "WindowClient"
1152 },
1153 "NavigationPreloadManager.getState": {
1154 "type": "dictionary"
1155 },
1156 "ServiceWorkerContainer.register": {
1157 "type": "ServiceWorkerRegistration",
1158 "creates": "ServiceWorkerRegistration"
1159 },
1160 "ServiceWorkerContainer.getRegistration": {
1161 "type": "ServiceWorkerRegistration",
1162 "creates": "ServiceWorkerRegistration"
1163 },
1164 "ServiceWorkerContainer.getRegistrations": {
1165 "type": "List<dynamic>"
1166 },
1167 "ServiceWorkerGlobalScope.fetch": {
1168 "creates": "_Response"
1169 },
1170 "ServiceWorkerRegistration.unregister": {
1171 "type": "bool"
1172 },
1173 "WindowClient.focus": {
1174 "type": "WindowClient",
1175 "creates": "WindowClient"
1176 },
1177 "WindowClient.navigate": {
1178 "type": "WindowClient",
1179 "creates": "WindowClient"
1180 },
1181 "BarcodeDetector.detect": {
1182 "type": "List<dynamic>"
1183 },
1184 "FaceDetector.detect": {
1185 "type": "List<dynamic>"
1186 },
1187 "TextDetector.detect": {
1188 "type": "List<dynamic>"
1189 },
1190 "BaseAudioContext.decodeAudioData": {
1191 "type": "AudioBuffer",
1192 "creates": "AudioBuffer"
1193 },
1194 "OfflineAudioContext.startRendering": {
1195 "type": "AudioBuffer",
1196 "creates": "AudioBuffer"
1197 },
1198 "CacheStorage.match": {
1199 "creates": "_Response"
1200 },
1201 "CacheStorage.open": {
1202 "creates": "_Cache"
1203 },
1204 "CredentialsContainer.create": {
1205 "creates": "Credential"
1206 },
1207 "CredentialsContainer.get": {
1208 "creates": "Credential"
1209 },
1210 "CredentialsContainer.store": {
1211 "creates": "Credential"
1212 },
1213 "FetchEvent.preloadResponse": {
1214 "creates": "_Response"
1215 },
1216 "MediaKeySystemAccess.createMediaKeys": {
1217 "creates": "MediaKeys"
1218 },
1219 "Navigator.getVRDisplays": {
1220 "creates": "VRDisplay"
1221 },
1222 "Navigator.requestMediaKeySystemAccess": {
1223 "creates": "MediaKeySystemAccess"
1224 },
1225 "VRSession.requestFrameOfReference": {
1226 "creates": "VRFrameOfReference"
1227 },
1228 "Window.fetch": {
1229 "creates": "_Response"
1230 },
1231 "WorkerGlobalScope.fetch": {
1232 "creates": "_Response"
1233 },
1234 })
1235
1236promise_generateCall = monitored.Set('systemhtml.promise_generateCall', [
1237 "Navigator.requestKeyboardLock",
1238])
1239
1240
1241def _IsPromiseOperationGenerateCall(interface_operation):
1242 return interface_operation in promise_generateCall
1243
1244
1245def _GetPromiseOperationType(interface_operation):
1246 if interface_operation in promise_operations:
1247 return promise_operations[interface_operation]
1248 return None
1249
1250
1251def _GetPromiseAttributeType(interface_operation):
1252 if interface_operation in promise_attributes:
1253 return promise_attributes[interface_operation]
1254 return None
1255
1256# Compatibility is used to help determine attribute nullability i.e. if the
1257# attribute is not compatible across all browsers, the getter/setter is marked
1258# as nullable. There are cases where the attribute belongs to a class that
1259# implements an interface whose methods are not in the IDL, however.
1260# Since attribute getters need to match their overridden method declaration,
1261# there are conflicts when the overriding method is not compatible, the
1262# overriding method is, and they're not already nullable. This dict marks the
1263# attributes where there is a conflict that cannot be resolved with code
1264# generation or within src/template files.
1265compat_conflicts = {
1266 # These interfaces implement Rectangle, which is a Dart interface. In order
1267 # to match the interface of Rectangle, they must be marked as non-nullable.
1268 'DOMRectReadOnly': ['bottom', 'height', 'left', 'right', 'top', 'width'],
1269 'DOMRect': ['height', 'width'],
1270}
1271
1272
1274 """Generates a dart2js class for the dart:html library from a DOM IDL
1275 interface.
1276 """
1277
1278 def __init__(self,
1279 interface,
1280 options,
1281 logging_level=logging.WARNING,
1282 generate_static_extensions=False):
1283 super(Dart2JSBackend, self).__init__(interface, options, False, _logger)
1284
1285 self._generate_static_extensions = generate_static_extensions
1286 self._database_database = options.database
1287 self._template_loader = options.templates
1288 self._type_registry_type_registry = options.type_registry
1289 self._renamer_renamer = options.renamer
1290 self._metadata_metadata = options.metadata
1292 self._interface.id)
1294 self._current_secondary_parent = None
1295 self._library_name_library_name = self._renamer_renamer.GetLibraryName(self._interface)
1296 # Global constants for all WebGLRenderingContextBase, WebGL2RenderingContextBase, WebGLDrawBuffers
1297 self._gl_constants = []
1298 _logger.setLevel(logging_level)
1299
1301 return True
1302
1303 def GenerateCallback(self, info):
1304 pass
1305
1307 implements = super(Dart2JSBackend,
1309 if self._interface_type_info.list_item_type() and self.HasIndexedGetter(
1310 ):
1311 item_type = self._type_registry.TypeInfo(
1312 self._interface_type_info.list_item_type()).dart_type()
1313 if self._interface_type_info.list_item_type_nullable():
1314 item_type += '?'
1315 implements.append('JavaScriptIndexingBehavior<%s>' % item_type)
1316 return implements
1317
1318 def NativeSpec(self):
1319 native_spec = MakeNativeSpec(self._interface.javascript_binding_name)
1320 return '@Native("%s")\n' % native_spec
1321
1323 template_file = ('impl_%s.darttemplate' % self._interface.doc_js_name)
1324 template_file_content = self._template_loader.TryLoad(template_file)
1325 if not (template_file_content):
1326 if self._interface.isMaplike and self._interface.isMaplike_ro:
1327 # TODO(terry): There are no mutable maplikes yet.
1328 template_file_content = self._template_loader.Load(
1329 'dart2js_maplike_impl.darttemplate')
1330
1331 else:
1334 template_file_content = self._template_loader.Load(
1335 'dart2js_static_extension_impl.darttemplate')
1336 else:
1337 template_file_content = self._template_loader.Load(
1338 'dart2js_impl.darttemplate')
1339 return template_file_content
1340
1341 def StartInterface(self, members_emitter):
1342 self._members_emitter = members_emitter
1343
1345 pass
1346
1348 return self._interface.doc_js_name in js_support_checks
1349
1351 """Return a tuple of the support check function signature and the support
1352 test itself. If no parameters are supplied, we assume the default."""
1353 if self._interface.doc_js_name in _js_support_checks_additional_element:
1354 if self._interface.doc_js_name in _svg_element_constructors:
1355 lib_prefix = 'Svg'
1356 constructors = _svg_element_constructors
1357 else:
1358 lib_prefix = ''
1359 constructors = _html_element_constructors
1360 return (js_support_checks.get(self._interface.doc_js_name) +
1361 " && (new %sElement.tag('%s') is %s)" %
1362 (lib_prefix, constructors[self._interface.doc_js_name],
1363 self._renamer_renamer.RenameInterface(self._interface)))
1364 return js_support_checks.get(self._interface.doc_js_name)
1365
1366 def GenerateCustomFactory(self, constructor_info):
1367 # Custom factory will be taken from the template.
1368 return self._interface.doc_js_name in _js_custom_constructors
1369
1370 def MakeFactoryCall(self, factory, method, arguments, constructor_info):
1371 if factory is 'document' and method is 'createElement' \
1372 and not ',' in arguments \
1373 and not self._HasUnreliableFactoryConstructor():
1374 return emitter.Format(
1375 "JS$CAST("
1376 "'returns:$INTERFACE_NAME;creates:$INTERFACE_NAME;new:true',"
1377 " '#.$METHOD(#)', $FACTORY, $ARGUMENTS)",
1378 CAST='<' + self._interface_type_info_interface_type_info.interface_name() + '>',
1379 INTERFACE_NAME=self._interface_type_info_interface_type_info.interface_name(),
1380 FACTORY=factory,
1381 METHOD=method,
1382 ARGUMENTS=arguments)
1383 return emitter.Format('$FACTORY.$METHOD($ARGUMENTS)$CAST',
1384 FACTORY=factory,
1385 METHOD=method,
1386 ARGUMENTS=arguments,
1387 CAST=' as ' +
1388 self._interface_type_info_interface_type_info.interface_name())
1389
1390 def _HasUnreliableFactoryConstructor(self):
1391 return self._interface.doc_js_name in _js_unreliable_element_factories
1392
1394 return argument.optional
1395
1396 def EmitStaticFactoryOverload(self, constructor_info, name, arguments,
1397 emitter):
1398 if self._interface_type_info_interface_type_info.has_generated_interface():
1399 # Use dart_type name, we're generating.
1400 interface_name = self._interface_type_info_interface_type_info.interface_name()
1401 else:
1402 # Use the implementation name the interface is suppressed.
1403 interface_name = self._interface_type_info_interface_type_info.implementation_name()
1404
1405 index = len(arguments)
1406 arguments = constructor_info.ParametersAsArgumentList(index)
1407 if arguments:
1408 arguments = ', ' + arguments
1409 (emitter if (emitter != None) else self._members_emitter).Emit(
1410 " static $INTERFACE_NAME $NAME($PARAMETERS) => "
1411 "JS('$INTERFACE_NAME', 'new $CTOR_NAME($PLACEHOLDERS)'$ARGUMENTS);\n",
1412 INTERFACE_NAME=interface_name,
1413 NAME=name,
1414 # TODO(antonm): add types to parameters.
1415 PARAMETERS=constructor_info.ParametersAsArgumentList(index),
1416 CTOR_NAME=constructor_info.name or self._interface.doc_js_name,
1417 PLACEHOLDERS=','.join(['#'] * index),
1418 ARGUMENTS=arguments)
1419
1420 def SecondaryContext(self, interface):
1421 if interface is not self._current_secondary_parent:
1422 self._current_secondary_parent = interface
1423 self._members_emitter.Emit(
1424 '\n // From $WHERE\n', WHERE=interface.id)
1425
1427 ext_attrs = self._interface.ext_attrs
1428 has_indexed_getter = 'CustomIndexedGetter' in ext_attrs
1429 for operation in self._interface.operations:
1430 if operation.id == 'item' and 'getter' in operation.specials \
1431 and not self._OperationRequiresConversions(operation):
1432 has_indexed_getter = True
1433 break
1434 if operation.id == '__getter__' and 'getter' in operation.specials \
1435 and not self._OperationRequiresConversions(operation):
1436 has_indexed_getter = True
1437 break
1438 return has_indexed_getter
1439
1440 def AddIndexer(self, element_type, nullable):
1441 """Adds all the methods required to complete implementation of List."""
1442 # We would like to simply inherit the implementation of everything except
1443 # length, [], and maybe []=. It is possible to extend from a base
1444 # array implementation class only when there is no other implementation
1445 # inheritance. There might be no implementation inheritance other than
1446 # DOMBaseWrapper for many classes, but there might be some where the
1447 # array-ness is introduced by a non-root interface:
1448 #
1449 # interface Y extends X, List<T> ...
1450 #
1451 # In the non-root case we have to choose between:
1452 #
1453 # class YImpl extends XImpl { add List<T> methods; }
1454 #
1455 # and
1456 #
1457 # class YImpl extends ListBase<T> { copies of transitive XImpl methods; }
1458 #
1459
1460 has_indexed_getter = self.HasIndexedGetter()
1461
1462 indexed_getter = False
1463 indexed_getter_nullable = nullable
1464 if has_indexed_getter:
1465 indexed_getter = ('JS("%s%s", "#[#]", this, index)' %
1466 (self.SecureOutputType(element_type),
1467 "|Null" if nullable else ""))
1468 else:
1469 for op in self._interface.operations:
1470 if op.id == 'getItem':
1471 indexed_getter = 'this.getItem(index)'
1472 indexed_getter_nullable = OperationTypeIsNullable(op)
1473 break
1474 if not indexed_getter:
1475 for op in self._interface.operations:
1476 if op.id == 'item':
1477 indexed_getter = 'this.item(index)'
1478 indexed_getter_nullable = OperationTypeIsNullable(op)
1479 break
1480
1481 if indexed_getter:
1482 self._members_emitter.Emit(
1483 '\n'
1484 ' $TYPE operator[](int index) {\n'
1485 ' if (JS("bool", "# >>> 0 !== # || # >= #", index,\n'
1486 ' index, index, length))\n'
1487 ' throw new IndexError.withLength(index, length, indexable: this);\n'
1488 ' return $INDEXED_GETTER$NULLASSERT;\n'
1489 ' }',
1490 INDEXED_GETTER=indexed_getter,
1491 TYPE=self.SecureOutputType(element_type,
1492 is_dart_type=False,
1493 can_narrow_type=True,
1494 nullable=nullable),
1495 # If the type of the operation is not nullable but the getter
1496 # is, we must assert non-null.
1497 NULLASSERT='!' if not nullable and indexed_getter_nullable \
1498 else '')
1499
1500 if 'CustomIndexedSetter' in self._interface.ext_attrs:
1501 self._members_emitter.Emit(
1502 '\n'
1503 ' void operator[]=(int index, $TYPE$NULLABLE value) {'
1504 ' JS("void", "#[#] = #", this, index, value); }',
1505 TYPE=self._NarrowInputType(element_type),
1506 NULLABLE='?' if nullable else '')
1507 else:
1508 theType = self._NarrowInputType(element_type)
1509 if theType == 'DomRectList':
1510 theType = ''
1511
1512 self._members_emitter.Emit(
1513 '\n'
1514 ' void operator[]=(int index, $TYPE$NULLABLE value) {\n'
1515 ' throw new UnsupportedError("Cannot assign element of immutable List.");\n'
1516 ' }\n',
1517 TYPE=theType,
1518 NULLABLE='?' if nullable else '')
1519
1520 self.EmitListMixin(self._DartType(element_type), nullable)
1521
1522 def EmitAttribute(self, attribute, html_name, read_only):
1523 if self._HasCustomImplementation(attribute.id):
1524 return
1525
1526 if IsPureInterface(self._interface.id, self._database_database):
1527 self._AddAttributeUsingProperties(attribute, html_name, read_only)
1528 return
1529
1530 output_type = self.SecureOutputType(attribute.type.id,
1531 can_narrow_type=read_only,
1532 nullable=attribute.type.nullable)
1533
1534 rename = self._RenamingAnnotation(attribute.id, html_name)
1535 metadata = self._Metadata(attribute.type.id, attribute.id, output_type,
1536 attribute.type.nullable)
1537
1538 is_compat = self._mdn_reader.is_compatible(attribute)
1539
1540 # If the attribute is shadowing, we can't generate a shadowing
1541 # getter or setter (Issue 1633).
1542 # TODO(sra): _FindShadowedAttribute does not take into account the html
1543 # renaming. We should be looking for another attribute that has the
1544 # same html_name. Two attributes with the same IDL name might not match
1545 # if one is renamed.
1546 # TODO(srujzs): Determine if logic behind shadowing is still true here
1547 # and below with the transition to natives.
1548 (super_attribute,
1549 super_attribute_interface) = self._FindShadowedAttribute(attribute)
1550
1551 if super_attribute:
1552 if is_compat is None:
1553 # If there is no compatibility info on this attribute, we use
1554 # the parent attribute's compatibility info.
1555 is_compat = self._mdn_reader.is_compatible(super_attribute)
1556 self._mdn_reader.set_compatible(attribute, is_compat)
1557 if read_only or self._SafeToIgnoreShadowingMember(html_name):
1558 if attribute.type.id == super_attribute.type.id:
1559 # Compatible attribute, use the superclass property. This
1560 # works because JavaScript will do its own dynamic dispatch.
1561
1562 # Nullability is determined by attribute compatibility.
1563 nullable = not is_compat or attribute.type.nullable
1564 self._members_emitter.Emit(
1565 '\n'
1566 ' // Use implementation from $SUPER.\n'
1567 ' // $GET_TYPE get $NAME native;\n'
1568 ' // void set $NAME($SET_TYPE value) native;\n',
1569 SUPER=super_attribute_interface,
1570 NAME=html_name,
1571 GET_TYPE=self.SecureOutputType(attribute.type.id,
1572 can_narrow_type=read_only,
1573 nullable=nullable),
1574 SET_TYPE=self.SecureOutputType(attribute.type.id,
1575 can_narrow_type=read_only,
1576 nullable=nullable or \
1577 'TreatNullAs' in attribute.ext_attrs))
1578 return
1579 self._members_emitter.Emit('\n // Shadowing definition.')
1580 self._AddAttributeUsingProperties(attribute, html_name, read_only,
1581 rename, metadata)
1582 return
1583
1584 # If the attribute is shadowed incompatibly in a subclass then we also
1585 # can't just generate it as a getter/setter. In particular, this happens
1586 # with DomMatrixReadOnly and its subclass DomMatrix. Force the
1587 # superclass to generate getters. Hardcoding the known problem classes
1588 # for now.
1589 # TODO(alanknight): Fix this more generally.
1590 if (self._interface.id == 'DOMMatrixReadOnly' or
1591 self._interface.id == 'DOMPointReadOnly' or
1592 self._interface.id == 'DOMRectReadOnly'):
1593 self._AddAttributeUsingProperties(attribute, html_name, read_only,
1594 rename, metadata)
1595 return
1596
1597 # If the type has a conversion we need a getter or setter to contain the
1598 # conversion code.
1599 if (self._OutputConversion(attribute.type.id, attribute.id) or
1600 self._InputConversion(attribute.type.id, attribute.id)):
1601 self._AddAttributeUsingProperties(attribute, html_name, read_only,
1602 rename, metadata)
1603 return
1604
1605 input_type = self._NarrowInputType(attribute.type.id)
1606 if attribute.type.nullable or not is_compat:
1607 input_type += '?'
1608 if not read_only:
1609 if attribute.type.id == 'Promise':
1610 _logger.warn('R/W member is a Promise: %s.%s' %
1611 (self._interface.id, html_name))
1612 self._AddAttributeUsingProperties(attribute, html_name, read_only,
1613 rename, metadata)
1614 else:
1615 if attribute.type.id == 'Promise':
1616 lookupOp = "%s.%s" % (self._interface.id, html_name)
1617 promiseFound = _GetPromiseAttributeType(lookupOp)
1618 promiseType = 'Future'
1619 promiseCall = 'promiseToFuture'
1620 type_description = ''
1621 if promiseFound is not (None):
1622 paramType = promiseFound.get('type')
1623 if 'maplike' in promiseFound:
1624 promiseCall = 'promiseToFuture<dynamic>'
1625 promiseType = 'Future'
1626 elif paramType == 'dictionary':
1627 # It's a dictionary so return as a Map.
1628 promiseCall = 'promiseToFutureAsMap'
1629 output_conversion = self._OutputConversion("Dictionary",
1630 None)
1631 nullability = '?' if output_conversion.nullable_output \
1632 else ''
1633 promiseType = 'Future<Map<String, dynamic>' + \
1634 nullability + '>'
1635 elif paramType:
1636 promiseCall = 'promiseToFuture<%s>' % paramType
1637 promiseType = 'Future<%s>' % paramType
1638
1639 if 'creates' in promiseFound:
1640 createsType = promiseFound['creates']
1641 type_description = 'creates:%s;' % createsType
1642
1643 if attribute.type.nullable:
1644 promiseType += '?'
1645
1646 template = '\n $RENAME$(ANNOTATIONS)$TYPE get $NAME => '\
1647 '$PROMISE_CALL(JS("$TYPE_DESC", "#.$NAME", this));\n'
1648
1649 self._members_emitter.Emit(
1650 template,
1651 RENAME=rename,
1652 ANNOTATIONS=metadata,
1653 TYPE=promiseType,
1654 PROMISE_CALL=promiseCall,
1655 TYPE_DESC=type_description,
1656 NAME=html_name,)
1657 else:
1658 # Need to use a getter for list.length properties so we can
1659 # add a setter which throws an exception, satisfying List
1660 # API.
1661 if self._interface_type_info_interface_type_info.list_item_type() and \
1662 html_name == 'length':
1663 template = (
1664 '\n $RENAME$(ANNOTATIONS)$TYPE get $NAME => ' +
1665 'JS("$TYPE", "#.$NAME", this);\n')
1666 self._members_emitter.Emit(
1667 template,
1668 RENAME=rename,
1669 ANNOTATIONS=metadata,
1670 NAME=html_name,
1671 TYPE=input_type
1672 if output_type == 'double' else output_type)
1673 else:
1674 # Transform to native getters/setters.
1675 # TODO(srujzs): Should the logic for types and doubles from
1676 # above and before stay the same here?
1677 self._AddAttributeUsingProperties(attribute, html_name,
1678 read_only, rename, metadata)
1679
1680 def _IsACompatibilityConflict(self, interface, attr):
1681 if interface in compat_conflicts and attr.id in compat_conflicts[
1682 interface]:
1683 is_compat = self._mdn_reader.is_compatible(attr)
1684 if is_compat or attr.type.nullable:
1685 # Only attributes that are not compatible and not nullable
1686 # belong in this list.
1687 raise ValueError(
1688 interface + '.' + attr.id +
1689 ' has no conflict between compatibility and nullability.')
1690 else:
1691 return True
1692 return False
1693
1694 def _AddAttributeUsingProperties(self, attribute, html_name, read_only,
1695 rename=None, metadata=None):
1696 self._AddRenamingGetter(attribute, html_name, rename, metadata)
1697 if not read_only:
1698 # No metadata for setters.
1699 self._AddRenamingSetter(attribute, html_name, rename)
1700
1701 def _AddRenamingGetter(self, attr, html_name, rename, metadata):
1702 conversion = self._OutputConversion(attr.type.id, attr.id)
1703 if conversion:
1704 return self._AddConvertingGetter(attr, html_name, conversion)
1705 # If the attribute is incompatible, it must be marked nullable.
1706 is_compat = self._mdn_reader.is_compatible(attr)
1707 return_type = self.SecureOutputType(attr.type.id,
1708 nullable=(not is_compat) or
1709 attr.type.nullable)
1710 native_type = self._NarrowToImplementationType(attr.type.id)
1711 non_null_return_type = self.SecureOutputType(attr.type.id,
1712 nullable=False)
1713 if self._IsACompatibilityConflict(self._interface.id, attr):
1714 if not rename:
1715 rename = '@JSName(\'%s\')' % html_name
1716 template = """\n
1717 // The following getter is incompatible with some browsers but
1718 // must be made non-nullable to match the overridden method.
1719 \n $RENAME
1720 \n $METADATA
1721 \n $STATIC $TYPE get _$HTML_NAME native;
1722 \n
1723 \n $STATIC $NONNULLTYPE get $HTML_NAME => _$HTML_NAME$NULLASSERT;"""
1724 else:
1727 template = """\n $RENAME
1728 \n $METADATA
1729 \n $STATIC $TYPE get $HTML_NAME => js_util.getProperty(this, '$JSNAME');
1730 \n"""
1731 else:
1732 template = """\n $RENAME
1733 \n $METADATA
1734 \n $STATIC $TYPE get $HTML_NAME native;
1735 \n"""
1736 self._members_emitter.Emit(template,
1737 RENAME=rename if rename else '',
1738 METADATA=metadata if metadata else '',
1739 HTML_NAME=html_name,
1740 STATIC='static' if attr.is_static else '',
1741 TYPE=return_type,
1742 NULLASSERT='!',
1743 NONNULLTYPE=non_null_return_type,
1744 JSNAME=rename if rename else html_name)
1745
1746 def _AddRenamingSetter(self, attr, html_name, rename):
1747 conversion = self._InputConversion(attr.type.id, attr.id)
1748 if conversion:
1749 return self._AddConvertingSetter(attr, html_name, conversion)
1750 nullable_type = attr.type.nullable or 'TreatNullAs' in attr.ext_attrs
1751 # If this attr has an output conversion, it is possible that there is a
1752 # converting getter. We need to make sure the setter type matches the
1753 # getter type.
1754 conversion = self._OutputConversion(attr.type.id, attr.id)
1755 # If the attribute is incompatible, it must be marked nullable.
1756 is_compat = self._mdn_reader.is_compatible(attr)
1757 if (conversion and conversion.nullable_output) or not is_compat:
1758 nullable_type = True
1759 if self._IsACompatibilityConflict(self._interface.id, attr):
1760 # Force non-nullable if it's a manual conflict.
1761 nullable_type = False
1764 template = """\n $RENAME
1765 \n $STATIC set $HTML_NAME($TYPE value)
1766 => js_util.setProperty(this, '$JSNAME', value);
1767 \n"""
1768 else:
1769 template = """\n $RENAME
1770 \n $STATIC set $HTML_NAME($TYPE value) native;
1771 \n"""
1772 self._members_emitter.Emit(template,
1773 RENAME=rename if rename else '',
1774 HTML_NAME=html_name,
1775 STATIC='static ' if attr.is_static else '',
1776 TYPE=self.SecureOutputType(
1777 attr.type.id, nullable=nullable_type),
1778 JSNAME=rename if rename else html_name)
1779
1780 def _AddConvertingGetter(self, attr, html_name, conversion):
1781 # dynamic should not be marked with ?
1782 nullable_out = conversion.nullable_output and \
1783 not conversion.output_type == 'dynamic'
1784 # Nullability is determined by attribute compatibility.
1785 is_compat = self._mdn_reader.is_compatible(attr)
1786 nullable_in = (not is_compat or attr.type.nullable) and \
1787 not conversion.input_type == 'dynamic'
1788 self._members_emitter.Emit(
1789 '\n $(METADATA)$RETURN_TYPE$NULLABLE_OUT get $HTML_NAME => '
1790 '$CONVERT(this._get_$(HTML_NAME)$NULLASSERT);'
1791 "\n @JSName('$NAME')"
1792 '\n $(JS_METADATA)$NATIVE_TYPE$NULLABLE_IN get _get_$HTML_NAME native;'
1793 '\n',
1794 METADATA=self._metadata_metadata.GetFormattedMetadata(
1795 self._library_name_library_name, self._interface, html_name, ' '),
1796 JS_METADATA=self._Metadata(attr.type.id, html_name,
1797 conversion.input_type,
1798 conversion.nullable_output),
1799 CONVERT=conversion.function_name,
1800 HTML_NAME=html_name,
1801 NAME=attr.id,
1802 RETURN_TYPE=conversion.output_type,
1803 NULLABLE_OUT='?' if nullable_out else '',
1804 NATIVE_TYPE=conversion.input_type,
1805 NULLABLE_IN='?' if nullable_in else '',
1806 NULLASSERT='!' if nullable_in and \
1807 not conversion.nullable_input else '')
1808
1809 def _AddConvertingSetter(self, attr, html_name, conversion):
1810 # If the attribute is incompatible, it must be marked nullable.
1811 is_compat = self._mdn_reader.is_compatible(attr)
1812 # If the attribute is nullable, the setter should be nullable.
1813 nullable_in = ((attr.type.nullable or 'TreatNullAs' in attr.ext_attrs) \
1814 and not conversion.input_type == 'dynamic') or not is_compat
1815 nullable_out = conversion.nullable_output and \
1816 not conversion.output_type == 'dynamic'
1817 self._members_emitter.Emit(
1818 # TODO(sra): Use metadata to provide native name.
1819 '\n set $HTML_NAME($INPUT_TYPE$NULLABLE_IN value) {'
1820 '\n this._set_$HTML_NAME = $CONVERT(value$NULLASSERT);'
1821 '\n }'
1822 '\n set _set_$HTML_NAME(/*$NATIVE_TYPE$NULLABLE_OUT*/ value) {'
1823 '\n JS("void", "#.$NAME = #", this, value);'
1824 '\n }'
1825 '\n',
1826 CONVERT=conversion.function_name,
1827 HTML_NAME=html_name,
1828 NAME=attr.id,
1829 INPUT_TYPE=conversion.input_type,
1830 NULLABLE_IN='?' if nullable_in else '',
1831 NATIVE_TYPE=conversion.output_type,
1832 NULLABLE_OUT='?' if nullable_out else '',
1833 NULLASSERT='!' if nullable_in and \
1834 not conversion.nullable_input else '')
1835
1836 def AmendIndexer(self, element_type):
1837 pass
1838
1839 def RootClassName(self):
1840 return 'JavaScriptObject'
1841
1843 return True
1844
1845 def EmitOperation(self, info, html_name, dart_js_interop=False):
1846 """
1847 Arguments:
1848 info: An OperationInfo object.
1849 """
1850 if self._HasCustomImplementation(info.name):
1851 return
1852
1853 if IsPureInterface(self._interface.id, self._database_database):
1854 self._AddInterfaceOperation(info, html_name)
1855 elif info.callback_args:
1856 self._AddFutureifiedOperation(info, html_name)
1857 else:
1858 if any(
1860 for op in info.overloads):
1861 lookupOp = "%s.%s" % (self._interface.id, html_name)
1862 if (_GetPromiseOperationType(lookupOp) or info.type_name == 'Promise') and \
1863 not _IsPromiseOperationGenerateCall(lookupOp):
1864 self._AddDirectNativeOperation(info, html_name)
1865 else:
1866 # Any conversions needed?
1867 self._AddOperationWithConversions(info, html_name)
1868 else:
1869 self._AddDirectNativeOperation(info, html_name)
1870
1871 def _computeResultType(self, checkType):
1872 # TODO(terry): Work around bug in dart2js compiler e.g.,
1873 # typedef void CustomElementConstructor();
1874 # CustomElementConstructor registerElement(String type, [Map options])
1875 # Needs to become:
1876 # Function registerElement(String type, [Map options])
1877 resultType = checkType
1878 if self._database_database.HasInterface(resultType):
1879 resultInterface = self._database_database.GetInterface(resultType)
1880 if 'Callback' in resultInterface.ext_attrs:
1881 resultType = 'Function'
1882 return resultType
1883
1884 def _zeroArgs(self, argsNames):
1885 return 'JS("$TYPE_DESC", "#.$JSNAME()", this)'
1886
1887 def _manyArgs(self, numberArgs, argsNames):
1888 argsPound = "#" if numberArgs == 1 else ("#, " * numberArgs)[:-2]
1889 template = ' JS("$TYPE_DESC", "#.$JSNAME(%s)", this, %s)'
1890 return template % (argsPound, argsNames)
1891
1892 """ If argument conversionsMapToDictionary is a list first entry is argument
1893 name and second entry signals if argument is optional (True). """
1894
1895 def _promiseToFutureCode(self, argsNames, conversionsMapToDictionary=None):
1896 numberArgs = argsNames.count(',') + 1
1897 jsCall = self._zeroArgs(argsNames) if len(argsNames) == 0 else \
1898 self._manyArgs(numberArgs, argsNames)
1899
1900 futureTemplate = []
1901 if conversionsMapToDictionary is None:
1902 futureTemplate = [
1903 '\n'
1904 ' $RENAME$METADATA$MODIFIERS $TYPE $NAME($PARAMS) => $PROMISE_CALL(',
1905 jsCall, ');\n'
1906 ]
1907 else:
1908 mapArg = conversionsMapToDictionary[0]
1909 tempVariable = '%s_dict' % mapArg
1910 mapArgOptional = conversionsMapToDictionary[1]
1911
1912 if argsNames.endswith('%s' % mapArg):
1913 argsNames = '%s_dict' % argsNames
1914 jsCall = self._zeroArgs(argsNames) if len(argsNames) == 0 else \
1915 self._manyArgs(numberArgs, argsNames)
1916 if mapArgOptional:
1917 futureTemplate = [
1918 # We will need to convert the Map argument to a Dictionary, test if mapArg is there (optional) then convert.
1919 '\n'
1920 ' $RENAME$METADATA$MODIFIERS $TYPE $NAME($PARAMS) {\n',
1921 ' var ',
1922 tempVariable,
1923 ' = null;\n',
1924 ' if (',
1925 mapArg,
1926 ' != null) {\n',
1927 ' ',
1928 tempVariable,
1929 ' = convertDartToNative_Dictionary(',
1930 mapArg,
1931 ');\n',
1932 ' }\n',
1933 ' return $PROMISE_CALL(',
1934 jsCall,
1935 ');\n',
1936 ' }\n'
1937 ]
1938 else:
1939 futureTemplate = [
1940 # We will need to convert the Map argument to a Dictionary, the Map argument is not optional.
1941 '\n'
1942 ' $RENAME$METADATA$MODIFIERS $TYPE $NAME($PARAMS) {\n',
1943 ' var ',
1944 tempVariable,
1945 ' = convertDartToNative_Dictionary(',
1946 mapArg,
1947 ');\n',
1948 ' return $PROMISE_CALL(',
1949 jsCall,
1950 ');\n',
1951 ' }\n'
1952 ]
1953
1954 return "".join(futureTemplate)
1955
1956 def _AddDirectNativeOperation(self, info, html_name):
1957 force_optional = True if html_name.startswith('_') else False
1958 resultType = self._computeResultType(info.type_name)
1959
1960 if info.type_name == 'Promise' and not (force_optional):
1961 lookupOp = "%s.%s" % (self._interface.id, html_name)
1962 promiseFound = _GetPromiseOperationType(lookupOp)
1963 promiseType = 'Future'
1964 promiseCall = 'promiseToFuture'
1965 type_description = ''
1966 if promiseFound is not (None):
1967 paramType = promiseFound.get('type')
1968 if 'maplike' in promiseFound:
1969 if paramType == 'dictionary':
1970 promiseCall = 'promiseToFuture<dynamic>'
1971 promiseType = 'Future'
1972 elif paramType:
1973 promiseCall = 'promiseToFuture<%s>' % paramType
1974 promiseType = 'Future<%s>' % paramType
1975 elif paramType == 'dictionary':
1976 # It's a dictionary so return as a Map.
1977 promiseCall = 'promiseToFutureAsMap'
1978 output_conversion = self._OutputConversion("Dictionary",
1979 None)
1980 nullability = '?' if output_conversion.nullable_output \
1981 else ''
1982 promiseType = 'Future<Map<String, dynamic>' + \
1983 nullability + '>'
1984 elif paramType:
1985 promiseCall = 'promiseToFuture<%s>' % paramType
1986 promiseType = 'Future<%s>' % paramType
1987
1988 if 'creates' in promiseFound:
1989 createsType = promiseFound['creates']
1990 type_description = 'creates:%s;' % createsType
1991
1992 argsNames = info.ParametersAsArgumentList()
1993 dictionary_argument = info.dictionaryArgumentName()
1994 codeTemplate = self._promiseToFutureCode(argsNames,
1995 dictionary_argument)
1996 if info.type_nullable:
1997 promiseType += '?'
1998 self._members_emitter.Emit(
1999 codeTemplate,
2000 RENAME=self._RenamingAnnotation(info.declared_name, html_name),
2001 METADATA=self._Metadata(info.type_name, info.declared_name,
2002 self.SecureOutputType(info.type_name,
2003 nullable=info.type_nullable),
2004 info.type_nullable),
2005 MODIFIERS='static ' if info.IsStatic() else '',
2006 TYPE=promiseType,
2007 PROMISE_CALL=promiseCall,
2008 NAME=html_name,
2009 TYPE_DESC=type_description,
2010 JSNAME=info.declared_name,
2011 PARAMS=info.ParametersAsDeclaration(self._NarrowInputType,
2012 force_optional))
2013 else:
2014 self._members_emitter.Emit(
2015 '\n'
2016 ' $RENAME$METADATA$MODIFIERS$TYPE $NAME($PARAMS) => '\
2017 'js_util.callMethod(this, \'$JSNAME\', [$ARGS]);\n'
2019 '\n $RENAME$METADATA$MODIFIERS$TYPE $NAME($PARAMS) native;\n',
2020 RENAME=self._RenamingAnnotation(info.declared_name, html_name),
2021 METADATA=self._Metadata(
2022 info.type_name, info.declared_name,
2023 self.SecureOutputType(info.type_name,
2024 nullable=info.type_nullable),
2025 info.type_nullable),
2026 MODIFIERS='static ' if info.IsStatic() else '',
2027 TYPE=self.SecureOutputType(resultType,
2028 can_narrow_type=True,
2029 nullable=info.type_nullable),
2030 NAME=html_name,
2031 PARAMS=info.ParametersAsDeclaration(self._NarrowInputType,
2032 force_optional),
2033 ARGS=info.ParametersAsArgumentList(),
2034 JSNAME=info.declared_name if info.declared_name != html_name else html_name)
2035
2036 def _AddOperationWithConversions(self, info, html_name):
2037 # Assert all operations have same return type.
2038 assert len(set([op.type.id for op in info.operations])) == 1
2039
2040 resultType = self._computeResultType(info.type_name)
2041
2042 output_conversion = self._OutputConversion(resultType,
2043 info.declared_name)
2044 if output_conversion:
2045 return_type = output_conversion.output_type
2046 native_return_type = output_conversion.input_type
2047 else:
2048 return_type = resultType if resultType == 'Function' else self._NarrowInputType(
2049 resultType)
2050 native_return_type = return_type
2051
2052 parameter_names = [param_info.name for param_info in info.param_infos]
2053 parameter_types = [
2054 self._InputType(param_info.type_id, info)
2055 for param_info in info.param_infos
2056 ]
2057 operations = info.operations
2058
2059 def InputType(type_name):
2060 return self._InputType(type_name, info)
2061
2062 def GenerateCall(stmts_emitter, call_emitter, version, operation,
2063 argument_count):
2064 target = '_%s_%d' % (html_name[1:] if html_name.startswith('_') else
2065 html_name, version)
2066
2067 (target_parameters, arguments,
2068 calling_params) = self._ConvertArgumentTypes(
2069 stmts_emitter, operation.arguments, argument_count, info)
2070
2071 argument_list = ', '.join(arguments)
2072 # TODO(sra): If the native method has zero type checks, we can 'inline' is
2073 # and call it directly with a JS-expression.
2074 call = '%s(%s)' % (target, argument_list)
2075
2076 if output_conversion:
2077 call = '%s(%s)' % (output_conversion.function_name, call)
2078 if output_conversion.nullable_output and not info.type_nullable:
2079 # Return type of operation is not nullable while conversion
2080 # is, so we need to assert non-null.
2081 call += '!'
2082
2083 call_emitter.Emit(call)
2084
2085 if (native_return_type == 'Future'):
2086 hashArgs = ''
2087 if argument_count > 0:
2088 if argument_count < 20:
2089 hashArgs = '#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#' [:
2090 argument_count
2091 *
2092 2
2093 -
2094 1]
2095 else:
2096 print(
2097 "ERROR: Arguments exceede 20 - please fix Python code to handle more."
2098 )
2099 self._members_emitter.Emit(
2100 ' $RENAME$METADATA$MODIFIERS$TYPE$TARGET($PARAMS) =>\n'
2101 ' promiseToFuture(JS("", "#.$JSNAME($HASH_STR)"'\
2102 ', this$CALLING_PARAMS));\n',
2103 RENAME=self._RenamingAnnotation(info.declared_name, target),
2104 METADATA=self._Metadata(info.type_name, info.declared_name,
2105 None, info.type_nullable),
2106 MODIFIERS='static ' if info.IsStatic() else '',
2107 TYPE=TypeOrNothing(native_return_type,
2108 nullable=info.type_nullable),
2109 TARGET=target,
2110 PARAMS=', '.join(target_parameters),
2111 JSNAME=operation.id,
2112 HASH_STR=hashArgs,
2113 CALLING_PARAMS=calling_params)
2114 else:
2115 self._members_emitter.Emit(
2116 ' $RENAME$METADATA$MODIFIERS$TYPE$TARGET($PARAMS) native;\n',
2117 RENAME=self._RenamingAnnotation(info.declared_name, target),
2118 METADATA=self._Metadata(info.type_name, info.declared_name,
2119 None, info.type_nullable),
2120 MODIFIERS='static ' if info.IsStatic() else '',
2121 TYPE=TypeOrNothing(native_return_type,
2122 nullable=info.type_nullable),
2123 TARGET=target,
2124 PARAMS=', '.join(target_parameters))
2125
2126 # private methods don't need named arguments.
2127 full_name = '%s.%s' % (self._interface.id, info.declared_name)
2128 force_optional = False if hasNamedFormals(full_name) and not (
2129 html_name.startswith('_')) else True
2130
2131 nullsafe_return_type = return_type;
2132 if info.type_nullable:
2133 nullsafe_return_type += '?'
2134
2135 declaration = '%s%s%s %s(%s)' % (
2136 self._Metadata(info.type_name, info.declared_name, return_type,
2137 info.type_nullable),
2138 'static ' if info.IsStatic() else '', nullsafe_return_type,
2139 html_name, info.ParametersAsDeclaration(InputType, force_optional))
2141 info,
2142 operations,
2143 declaration,
2144 GenerateCall,
2145 IsOptional,
2146 can_omit_type_check=lambda type, pos: type == parameter_types[pos])
2147
2148 def _AddInterfaceOperation(self, info, html_name):
2149 self._members_emitter.Emit(
2150 '\n'
2151 ' $TYPE $NAME($PARAMS);\n',
2152 TYPE=self.SecureOutputType(info.type_name, can_narrow_type=True,
2153 nullable=info.type_nullable),
2154 NAME=html_name,
2155 PARAMS=info.ParametersAsDeclaration(self._NarrowInputType))
2156
2157 def _OperationRequiresConversions(self, operation):
2158 return (self._OperationRequiresOutputConversion(operation) or
2159 self._OperationRequiresInputConversions(operation))
2160
2161 def _OperationRequiresOutputConversion(self, operation):
2162 return self._OutputConversion(operation.type.id, operation.id)
2163
2164 def _OperationRequiresInputConversions(self, operation):
2165 return any(
2166 self._InputConversion(arg.type.id, operation.id)
2167 for arg in operation.arguments)
2168
2169 def _OutputConversion(self, idl_type, member):
2170 return FindConversion(idl_type, 'get', self._interface.id, member)
2171
2172 def _InputConversion(self, idl_type, member):
2173 return FindConversion(idl_type, 'set', self._interface.id, member)
2174
2175 def _HasCustomImplementation(self, member_name):
2176 member_name = '%s.%s' % (self._interface.doc_js_name, member_name)
2177 return member_name in _js_custom_members
2178
2179 def _SafeToIgnoreShadowingMember(self, member_name):
2180 member_name = '%s.%s' % (self._interface.doc_js_name, member_name)
2181 return member_name in _safe_to_ignore_shadowing_members
2182
2183 def _RenamingAnnotation(self, idl_name, member_name):
2184 if member_name != idl_name:
2185 return "@JSName('%s')\n " % idl_name
2186 return ''
2187
2188 def _Metadata(self, idl_type, idl_member_name, dart_type, nullable,
2189 indent=' '):
2190 anns = self._metadata_metadata.GetDart2JSMetadata(
2191 idl_type, self._library_name_library_name, self._interface, idl_member_name)
2192
2193 if not self._metadata_metadata.AnyConversionAnnotations(
2194 idl_type, self._interface.id, idl_member_name):
2195 return_type = self.SecureOutputType(idl_type)
2196 native_type = self._NarrowToImplementationType(idl_type)
2197
2198 null_union = '' if not nullable else '|Null'
2199 if native_type != return_type:
2200 anns = anns + [
2201 "@Returns('%s%s')" % (native_type, null_union),
2202 "@Creates('%s')" % native_type,
2203 ]
2204 if dart_type == 'dynamic' or dart_type == 'Object?':
2205 # We emit non-nullable Object annotations but exclude nullable
2206 # Object annotations since that's the default.
2207
2208 def js_type_annotation(ann):
2209 return re.search('^@.*Returns', ann) or re.search(
2210 '^@.*Creates', ann)
2211
2212 if not list(filter(js_type_annotation, anns)):
2213 _logger.warn('Member with wildcard native type: %s.%s' %
2214 (self._interface.id, idl_member_name))
2215
2216 return self._metadata_metadata.FormatMetadata(anns, indent)
2217
2219 return _js_custom_members
2220
2221 def _FindShadowedAttribute(self, attr):
2222 """Returns (attribute, superinterface) or (None, None)."""
2223
2224 def FindInParent(interface):
2225 """Returns matching attribute in parent, or None."""
2226 if interface.parents:
2227 parent = interface.parents[0]
2228 if IsDartCollectionType(parent.type.id):
2229 return (None, None)
2230 if IsPureInterface(parent.type.id, self._database_database):
2231 return (None, None)
2232 if self._database_database.HasInterface(parent.type.id):
2233 interfaces_to_search_in = []
2234 parent_interface_name = parent.type.id
2235 interfaces_to_search_in.append(parent_interface_name)
2236 parent_type_info = self._type_registry_type_registry.TypeInfo(
2237 parent_interface_name)
2238 if parent_type_info.merged_into():
2239 # IDL parent was merged into another interface, which became a
2240 # parent interface in Dart.
2241 parent_interface_name = parent_type_info.merged_into()
2242 interfaces_to_search_in.append(parent_interface_name)
2243 elif parent_type_info.merged_interface():
2244 # IDL parent has another interface that was merged into it.
2245 interfaces_to_search_in.append(
2246 parent_type_info.merged_interface())
2247
2248 for interface_name in interfaces_to_search_in:
2249 interface = self._database_database.GetInterface(interface_name)
2250 attr2 = FindMatchingAttribute(interface, attr)
2251 if attr2:
2252 return (attr2, parent_interface_name)
2253
2254 return FindInParent(
2255 self._database_database.GetInterface(parent_interface_name))
2256 return (None, None)
2257
2258 return FindInParent(self._interface) if attr else (None, None)
2259
2260
2261# ------------------------------------------------------------------------------
2262
2263
2265
2266 def __init__(self, multiemitter, dart_sources_dir, dart_libraries):
2267 self._multiemitter = multiemitter
2268 self._dart_sources_dir = dart_sources_dir
2269 self._path_to_emitter = {}
2270 self._dart_libraries = dart_libraries
2271
2272 def FileEmitter(self, basename, library_name, template=None):
2273 aux_dir = os.path.join(self._dart_sources_dir, library_name)
2274 path = os.path.join(aux_dir, '%s.dart' % basename)
2275 if not path in self._path_to_emitter:
2276 emitter = self._multiemitter.FileEmitter(path)
2277 if not template is None:
2278 emitter = emitter.Emit(template)
2279 self._path_to_emitter[path] = emitter
2280
2281 self._dart_libraries.AddFile(basename, library_name, path)
2282 return self._path_to_emitter[path]
2283
2284 def AddTypeEntry(self, basename, idl_name, dart_name):
2285 self._dart_libraries.AddTypeEntry(basename, idl_name, dart_name)
2286
2287 def EmitLibraries(self, auxiliary_dir, dart_js_interop):
2288 self._dart_libraries.Emit(self._multiemitter, auxiliary_dir)
2289
2290
2291# ------------------------------------------------------------------------------
2293
2294 def __init__(self, name, template_loader, library_type, output_dir,
2295 dart_js_interop):
2296 self._template = template_loader.Load(
2297 '%s_%s.darttemplate' % (name, library_type))
2298 self._dart_path = os.path.join(output_dir,
2299 '%s_%s.dart' % (name, library_type))
2300 self._paths = []
2301 self._typeMap = {}
2302 self._dart_js_interop = dart_js_interop
2303
2304 def AddFile(self, path):
2305 self._paths.append(path)
2306
2307 def AddTypeEntry(self, idl_name, dart_name):
2308 self._typeMap[idl_name] = dart_name
2309
2310 def Emit(self, emitter, auxiliary_dir):
2311
2312 def massage_path(path):
2313 # The most robust way to emit path separators is to use / always.
2314 return path.replace('\\', '/')
2315
2316 library_emitter = emitter.FileEmitter(self._dart_path)
2317 library_file_dir = os.path.dirname(self._dart_path)
2318 auxiliary_dir = os.path.relpath(auxiliary_dir, library_file_dir)
2319 emitters = library_emitter.Emit(
2320 self._template,
2321 AUXILIARY_DIR=massage_path(auxiliary_dir),
2322 NULLABLE='?')
2323 if isinstance(emitters, tuple):
2324 imports_emitter, map_emitter = emitters
2325 else:
2326 imports_emitter, map_emitter = emitters, None
2327
2328 for path in sorted(self._paths):
2329 relpath = os.path.relpath(path, library_file_dir)
2330 imports_emitter.Emit("part '$PATH';\n", PATH=massage_path(relpath))
2331
2332 # Emit the $!TYPE_MAP
2333 if map_emitter:
2334 items = list(self._typeMap.items())
2335 items.sort()
2336 for (idl_name, dart_name) in items:
2337 map_emitter.Emit(
2338 " '$IDL_NAME': () => $DART_NAME.instanceRuntimeType,\n",
2339 IDL_NAME=idl_name,
2340 DART_NAME=dart_name)
2341
2342
2343# ------------------------------------------------------------------------------
2344
2345
2347
2348 def __init__(self, libraries, template_loader, library_type, output_dir,
2349 dart_js_interop):
2350 self._libraries = {}
2351 for library_name in libraries:
2352 self._libraries[library_name] = DartLibrary(
2353 library_name, template_loader, library_type, output_dir,
2354 dart_js_interop)
2355
2356 def AddFile(self, basename, library_name, path):
2357 self._libraries[library_name].AddFile(path)
2358
2359 def AddTypeEntry(self, library_name, idl_name, dart_name):
2360 self._libraries[library_name].AddTypeEntry(idl_name, dart_name)
2361
2362 def Emit(self, emitter, auxiliary_dir):
2363 for lib in self._libraries.values():
2364 lib.Emit(emitter, auxiliary_dir)
static bool is_compatible(const GrSurfaceCharacterization &gsc, const GrBackendTexture &backendTex)
GLenum type
def SecureOutputType(self, type_name, is_dart_type=False, can_narrow_type=False, nullable=False)
def _GenerateDispatcherBody(self, info, operations, declaration, generate_call, is_optional, can_omit_type_check=lambda type, False pos)
def EmitListMixin(self, element_name, nullable)
def _ConvertArgumentTypes(self, stmts_emitter, arguments, argument_count, info)
def _AddFutureifiedOperation(self, info, html_name)
def _OperationRequiresConversions(self, operation)
Definition: systemhtml.py:2157
def SecondaryContext(self, interface)
Definition: systemhtml.py:1420
def _OperationRequiresInputConversions(self, operation)
Definition: systemhtml.py:2164
def __init__(self, interface, options, logging_level=logging.WARNING, generate_static_extensions=False)
Definition: systemhtml.py:1282
def GenerateCustomFactory(self, constructor_info)
Definition: systemhtml.py:1366
def AmendIndexer(self, element_type)
Definition: systemhtml.py:1836
def _HasCustomImplementation(self, member_name)
Definition: systemhtml.py:2175
def AddIndexer(self, element_type, nullable)
Definition: systemhtml.py:1440
def _FindShadowedAttribute(self, attr)
Definition: systemhtml.py:2221
def EmitAttribute(self, attribute, html_name, read_only)
Definition: systemhtml.py:1522
def _computeResultType(self, checkType)
Definition: systemhtml.py:1871
def _AddOperationWithConversions(self, info, html_name)
Definition: systemhtml.py:2036
def _AddRenamingGetter(self, attr, html_name, rename, metadata)
Definition: systemhtml.py:1701
def _OperationRequiresOutputConversion(self, operation)
Definition: systemhtml.py:2161
def _AddConvertingGetter(self, attr, html_name, conversion)
Definition: systemhtml.py:1780
def _Metadata(self, idl_type, idl_member_name, dart_type, nullable, indent=' ')
Definition: systemhtml.py:2189
def _AddRenamingSetter(self, attr, html_name, rename)
Definition: systemhtml.py:1746
def _IsACompatibilityConflict(self, interface, attr)
Definition: systemhtml.py:1680
def _RenamingAnnotation(self, idl_name, member_name)
Definition: systemhtml.py:2183
def MakeFactoryCall(self, factory, method, arguments, constructor_info)
Definition: systemhtml.py:1370
def _AddDirectNativeOperation(self, info, html_name)
Definition: systemhtml.py:1956
def IsConstructorArgumentOptional(self, argument)
Definition: systemhtml.py:1393
def EmitOperation(self, info, html_name, dart_js_interop=False)
Definition: systemhtml.py:1845
def _AddAttributeUsingProperties(self, attribute, html_name, read_only, rename=None, metadata=None)
Definition: systemhtml.py:1695
def StartInterface(self, members_emitter)
Definition: systemhtml.py:1341
def _zeroArgs(self, argsNames)
Definition: systemhtml.py:1884
def _SafeToIgnoreShadowingMember(self, member_name)
Definition: systemhtml.py:2179
def _OutputConversion(self, idl_type, member)
Definition: systemhtml.py:2169
def _InputConversion(self, idl_type, member)
Definition: systemhtml.py:2172
def _AddConvertingSetter(self, attr, html_name, conversion)
Definition: systemhtml.py:1809
def EmitStaticFactoryOverload(self, constructor_info, name, arguments, emitter)
Definition: systemhtml.py:1397
def _AddInterfaceOperation(self, info, html_name)
Definition: systemhtml.py:2148
def _promiseToFutureCode(self, argsNames, conversionsMapToDictionary=None)
Definition: systemhtml.py:1895
def _manyArgs(self, numberArgs, argsNames)
Definition: systemhtml.py:1887
def Emit(self, emitter, auxiliary_dir)
Definition: systemhtml.py:2362
def __init__(self, libraries, template_loader, library_type, output_dir, dart_js_interop)
Definition: systemhtml.py:2349
def AddTypeEntry(self, library_name, idl_name, dart_name)
Definition: systemhtml.py:2359
def AddFile(self, basename, library_name, path)
Definition: systemhtml.py:2356
def FileEmitter(self, basename, library_name, template=None)
Definition: systemhtml.py:2272
def EmitLibraries(self, auxiliary_dir, dart_js_interop)
Definition: systemhtml.py:2287
def AddTypeEntry(self, basename, idl_name, dart_name)
Definition: systemhtml.py:2284
def __init__(self, multiemitter, dart_sources_dir, dart_libraries)
Definition: systemhtml.py:2266
def __init__(self, name, template_loader, library_type, output_dir, dart_js_interop)
Definition: systemhtml.py:2295
def AddTypeEntry(self, idl_name, dart_name)
Definition: systemhtml.py:2307
def Emit(self, emitter, auxiliary_dir)
Definition: systemhtml.py:2310
def __init__(self, name=None, tag=None, params=[], opt_params=[], factory_provider_name='document')
Definition: systemhtml.py:171
def ConstructorInfo(self, interface_name)
Definition: systemhtml.py:178
def __init__(self, options, library_emitter, event_generator, prototype_event_generator, interface, backend)
Definition: systemhtml.py:600
static void append(char **dst, size_t *count, const char *src, size_t n)
Definition: editor.cpp:211
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition: switches.h:76
def print(*args, **kwargs)
Definition: run_tests.py:49
def ElemSupportStr(tagName)
Definition: systemhtml.py:464
def SvgSupportStr(tagName)
Definition: systemhtml.py:460
def ElementConstructorInfos(typename, element_constructors, factory_provider_name='_Elements')
Definition: systemhtml.py:444
def CanUseStaticExtensions(interface, should)
Definition: systemhtml.py:21
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741