Flutter Engine
The Flutter Engine
generate_blink_file.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2#
3# Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
4# for details. All rights reserved. Use of this source code is governed by a
5# BSD-style license that can be found in the LICENSE file.
6"""Generates sdk/lib/_blink/dartium/_blink_dartium.dart file."""
7
8import os
9from generator import AnalyzeOperation, AnalyzeConstructor, ConstantOutputOrder
10
11# This is list of all methods with native c++ implementations
12# If performing a dartium merge, the best practice is to comment out this list,
13# ensure everything runs, and then uncomment this list which might possibly
14# introduce breaking changes due to changes to these method signatures.
15_js_custom_members = set([
16 'Document.createElement',
17 'Element.id',
18 'Element.tagName',
19 'Element.className',
20 'Element.setAttribute',
21 'Element.getAttribute',
22 # Consider adding this method so there is a fast path to access only
23 # element children.
24 # 'NonDocumentTypeChildNode.nextElementSibling',
25 'Node.appendChild', # actually not removed, just native implementation.
26 'Node.cloneNode',
27 'Node.insertBefore',
28 'Node.lastChild',
29 'Node.firstChild',
30 'Node.parentElement',
31 'Node.parentNode',
32 'Node.childNodes',
33 'Node.removeChild',
34 'Node.contains',
35 'Node.nextSibling',
36 'Node.previousSibling',
37 'ChildNode.remove',
38 'Document.createTextNode',
39 'Window.location',
40 'Location.href',
41 'Location.hash',
42 'Node.querySelector',
43 'HTMLElement.hidden',
44 'HTMLElement.style',
45 'Element.attributes',
46 'Window.innerWidth',
47 'NodeList.length',
48 'NodeList.item',
49 'ParentNode.children',
50 'ParentNode.firstElementChild',
51 'ParentNode.lastElementChild',
52 'Event.target',
53 'MouseEvent.clientY',
54 'MouseEvent.clientX',
55 'Node.nodeType',
56 'Node.textContent',
57 'HTMLCollection.length',
58 'HTMLCollection.item',
59 'Node.lastElementChild',
60 'Node.firstElementChild',
61 'HTMLElement_tabIndex',
62 'Element.clientWidth',
63 'Element.clientHeight',
64 'Document.body',
65 'Element.removeAttribute',
66 'Element.getBoundingClientRect',
67 'CSSStyleDeclaration.getPropertyValue',
68 'CSSStyleDeclaration.setProperty',
69 'CSSStyleDeclaration.__propertyQuery__',
70
71 # TODO(jacobr): consider implementing these methods as well as they show
72 # up in benchmarks for some sample applications.
73 #'Document.createEvent',
74 #'Document.initEvent',
75 #'EventTarget.dispatchEvent',
76])
77
78# Uncomment out this line to short circuited native methods and run all of
79# dart:html through JS interop except for createElement which is slightly more
80# tightly natively wired.
81# _js_custom_members = set()
82
83# Expose built-in methods support by an instance that is not shown in the IDL.
84_additional_methods = {
85 # Support propertyIsEnumerable (available on all objects only needed by
86 # CSSStyleDeclaration decides if style property is supported (handling
87 # camelcase and inject hyphens between camelcase).
88 # Format of dictionary is 'operation name', arguments, returns value (True or False)
89 'CSSStyleDeclaration': ('propertyIsEnumerable', 1, True),
90}
91
92HEADER = """/* Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
93 * for details. All rights reserved. Use of this source code is governed by a
94 * BSD-style license that can be found in the LICENSE file.
95 *
96 * DO NOT EDIT
97 * Auto-generated _blink library.
98 */
99library dart.dom._blink;
100
101import 'dart:async';
102import 'dart:js' as js;
103import 'dart:html' show DomException;
104import 'dart:_internal' as internal;
105// This is a place to put custom renames if we need them.
106final resolverMap = {
107};
108
109dynamic resolver(String s) {
110"""
111
112END_RESOLVER = """
113 // Failed to find it, check for custom renames
114 dynamic obj = resolverMap[s];
115 if (obj != null) return obj;
116 throw("No such interface exposed in blink: ${s}");
117}
118
119"""
120
121BLINK_UTILS = """
122// _Utils native entry points
123class Blink_Utils {
124 static window() native "Utils_window";
125
126 static forwardingPrint(message) native "Utils_forwardingPrint";
127
128 static spawnDomUri(uri) native "Utils_spawnDomUri";
129
130 static void spawnDomHelper(Function f, int replyTo) native "Utils_spawnDomHelper";
131
132 static register(document, tag, customType, extendsTagName) native "Utils_register";
133
134 // Below code sets up VMLibraryHooks for resolvePackageUri.
135 static Uri resolvePackageUri(Uri packageUri) native "Utils_resolvePackageUri";
136 static Future<Uri> _resolvePackageUriFuture(Uri packageUri) async {
137 return resolvePackageUri(packageUri);
138 }
139 static void _setupHooks() {
140 internal.VMLibraryHooks.resolvePackageUriFuture = _resolvePackageUriFuture;
141 }
142
143 // Defines an interceptor if there is an appropriate JavaScript prototype to define it on.
144 // In any case, returns a typed JS wrapper compatible with dart:html and the new
145 // typed JS Interop.
146 static defineInterceptorCustomElement(jsObject, Type type) native "Utils_defineInterceptorCustomElement";
147 static defineInterceptor(jsObject, Type type) native "Utils_defineInterceptor";
148 static setInstanceInterceptor(o, Type type, {bool customElement: false}) native "Utils_setInstanceInterceptor";
149 static setInstanceInterceptorCustomUpgrade(o) native "Utils_setInstanceInterceptorCustomUpgrade";
150
151 // This method will throw if the element isn't actually a real Element.
152 static initializeCustomElement(element) native "Utils_initializeCustomElement";
153}
154
155class Blink_DOMStringMap {
156 // _DOMStringMap native entry points
157 static containsKey(_DOMStringMap, key) native "DOMStringMap_containsKey_Callback";
158
159 static item(_DOMStringMap, key) native "DOMStringMap_item_Callback";
160
161 static setItem(_DOMStringMap, key, value) native "DOMStringMap_setItem_Callback";
162
163 static remove(_DOMStringMap, key) native "DOMStringMap_remove_Callback";
164
165 static get_keys(_DOMStringMap) native "DOMStringMap_getKeys_Callback";
166}
167
168// Calls through JsNative but returns DomException instead of error strings.
169class Stats {
170 Stats(this.name) {
171 counts = new Map<String, int>();
172 }
173
174 String name;
175 Map<String, int> counts;
176 clear() {
177 counts.clear();
178 }
179
180 track(String v) {
181 counts[v] = counts.putIfAbsent(v, ()=> 0) + 1;
182 }
183 toString() {
184 StringBuffer sb = new StringBuffer();
185 sb.write('================');
186 sb.write('$name ${counts.length}');
187 var keys = counts.keys.toList();
188 keys.sort((a,b) => counts[b].compareTo(counts[a]));
189 for (var key in keys) {
190 print("$key => ${counts[key]}");
191 }
192 sb.write('---------------');
193 sb.write('================');
194 return sb;
195 }
196}
197
198bool TRACK_STATS = true;
199dumpStats() {
200 print("------------ STATS ----------------");
201 print(Blink_JsNative_DomException.getPropertyStats.toString());
202 print(Blink_JsNative_DomException.setPropertyStats.toString());
203 print(Blink_JsNative_DomException.callMethodStats.toString());
204 print(Blink_JsNative_DomException.constructorStats.toString());
205 print("-----------------------------------");
206}
207
208clearStats() {
209 Blink_JsNative_DomException.getPropertyStats.clear();
210 Blink_JsNative_DomException.setPropertyStats.clear();
211 Blink_JsNative_DomException.callMethodStats.clear();
212 Blink_JsNative_DomException.constructorStats.clear();
213}
214
215class Blink_JsNative_DomException {
216 static var getPropertyStats = new Stats('get property');
217 static var setPropertyStats = new Stats('set property');
218 static var callMethodStats = new Stats('call method');
219 static var constructorStats = new Stats('constructor');
220
221 static var constructors = new Map<String, dynamic>();
222
223 static getProperty(o, String name) {
224 try {
225 if (TRACK_STATS) getPropertyStats.track(name);
226 return js.JsNative.getProperty(o, name);
227 } catch (e) {
228 // Re-throw any errors (returned as a string) as a DomException.
229 throw new DomException.jsInterop(e);
230 }
231 }
232
233 static propertyQuery(o, String name) {
234 try {
235 if (TRACK_STATS) getPropertyStats.track('__propertyQuery__');
236 return js.JsNative.getProperty(o, name);
237 } catch (e) {
238 // Re-throw any errors (returned as a string) as a DomException.
239 throw new DomException.jsInterop(e);
240 }
241 }
242
243 static callConstructor0(String name) {
244 try {
245 if (TRACK_STATS) constructorStats.track(name);
246 var constructor = constructors.putIfAbsent(name, () => js.context[name]);
247 return js.JsNative.callConstructor0(constructor);
248 } catch (e) {
249 // Re-throw any errors (returned as a string) as a DomException.
250 throw new DomException.jsInterop(e);
251 }
252 }
253
254 static callConstructor(String name, List args) {
255 try {
256 if (TRACK_STATS) constructorStats.track(name);
257 var constructor = constructors.putIfAbsent(name, () => js.context[name]);
258 return js.JsNative.callConstructor(constructor, args);
259 } catch (e) {
260 // Re-throw any errors (returned as a string) as a DomException.
261 throw new DomException.jsInterop(e);
262 }
263 }
264
265 static setProperty(o, String name, value) {
266 try {
267 if (TRACK_STATS) setPropertyStats.track(name);
268 return js.JsNative.setProperty(o, name, value);
269 } catch (e) {
270 // Re-throw any errors (returned as a string) as a DomException.
271 throw new DomException.jsInterop(e);
272 }
273 }
274
275 static callMethod(o, String method, List args) {
276 try {
277 if (TRACK_STATS) callMethodStats.track(method);
278 return js.JsNative.callMethod(o, method, args);
279 } catch (e) {
280 // Re-throw any errors (returned as a string) as a DomException.
281 throw new DomException.jsInterop(e);
282 }
283 }
284}"""
285
286CLASS_DEFINITION = """class Blink%s {
287 static final instance = new Blink%s();
288
289"""
290
291CLASS_DEFINITION_EXTENDS = """class Blink%s extends Blink%s {
292 static final instance = new Blink%s();
293
294"""
295
296#(interface_name)
297
298#
299CONSTRUCTOR_0 = [
300 ' constructorCallback_0_()',
301 ' => Blink_JsNative_DomException.callConstructor0("%s");\n\n',
302 ' native "Blink_Constructor_%s";\n\n'
303]
304
305#(argument_count, arguments, interface_name, arguments)
306CONSTRUCTOR_ARGS = [
307 ' constructorCallback_%s_(%s)',
308 ' => Blink_JsNative_DomException.callConstructor("%s", [%s]);\n\n',
309 ' native "Blink_Constructor_Args_%s" /* %s */;\n\n'
310]
311
312#(attribute_name, attribute_name)
313ATTRIBUTE_GETTER = [
314 ' %s_Getter_(mthis)',
315 ' => Blink_JsNative_DomException.getProperty(mthis /* %s */, "%s");\n\n',
316 ' native "Blink_Getter_%s_%s";\n\n'
317]
318
319ATTRIBUTE_SETTER = [
320 ' %s_Setter_(mthis, __arg_0)',
321 ' => Blink_JsNative_DomException.setProperty(mthis /* %s */, "%s", __arg_0);\n\n',
322 ' native "Blink_Setter_%s_%s";\n\n'
323]
324
325#(operation_name, operationName)
326OPERATION_0 = [
327 ' %s_Callback_0_(mthis)',
328 ' => Blink_JsNative_DomException.callMethod(mthis /* %s */, "%s", []);\n\n',
329 ' native "Blink_Operation_0_%s_%s";\n\n'
330]
331
332# getter, setter, deleter, propertyQuery code, and propertyIsEnumerable
333OPERATION_1 = [
334 ' $%s_Callback_1_(mthis, __arg_0)',
335 ' => Blink_JsNative_DomException.callMethod(mthis /* %s */, "%s", [__arg_0]);\n\n',
336 ' native "Blink_Operation_1_%s_%s";\n\n'
337]
338
339OPERATION_2 = [
340 ' $%s_Callback_2_(mthis, __arg_0, __arg_1)',
341 ' => Blink_JsNative_DomException.callMethod(mthis /* %s */, "%s", [__arg_0, __arg_1]);\n\n',
342 ' native "Blink_Operation_2_%s_%s";\n\n'
343]
344
345OPERATION_PQ = [
346 ' $%s_Callback_1_(mthis, __arg_0)',
347 ' => Blink_JsNative_DomException.propertyQuery(mthis, __arg_0); /* %s */ \n\n',
348 ' native "Blink_Operation_PQ_%s";\n\n'
349]
350
351#(operation_name, argument_count, arguments, operation_name, arguments)
352ARGUMENT_NUM = "__arg_%s"
353OPERATION_ARGS = [
354 ' %s_Callback_%s_(mthis, %s)',
355 ' => Blink_JsNative_DomException.callMethod(mthis /* %s */, "%s", [%s]);\n\n',
356 ' native "Blink_Operation_%s_%s"; /* %s */\n\n'
357]
358
359# get class property to make static call.
360CLASS_STATIC = 'Blink_JsNative_DomException.getProperty(js.context, "%s")'
361
362# name, classname_getproperty, name
363STATIC_ATTRIBUTE_GETTER = [
364 ' %s_Getter_()',
365 ' => Blink_JsNative_DomException.getProperty(%s /* %s */, "%s");\n\n',
366 ' /* %s */ native "Blink_Static_getter_%s_%s"'
367]
368
369# name, classname_getproperty, name
370STATIC_OPERATION_0 = [
371 ' %s_Callback_0_()',
372 ' => Blink_JsNative_DomException.callMethod(%s /* %s */, "%s", []);\n\n',
373 ' /* %s */ native "Blink_Static_Operation_0_%s_%s'
374]
375
376# name, argsCount, args, classname_getproperty, name, args
377STATIC_OPERATION_ARGS = [
378 ' %s_Callback_%s_(%s)',
379 ' => Blink_JsNative_DomException.callMethod(%s /* %s */, "%s", [%s]);\n\n',
380 ' /* %s */ native "Blink_Static_Operations_%s_%s" /* %s */ \n\n'
381]
382
383CLASS_DEFINITION_END = """}
384
385"""
386
388 optional_default_args = 0
389 for argument in param_infos:
390 if argument.is_optional:
391 optional_default_args += 1
392
393 arg_count = len(param_infos)
394 min_arg_count = arg_count - optional_default_args
395 lb = min_arg_count - 2 if min_arg_count > 2 else 0
396 return (lb, arg_count + 1)
397
398
399constructor_renames = {
400 'RTCPeerConnection': 'webkitRTCPeerConnection',
401 'SpeechRecognition': 'webkitSpeechRecognition',
402}
403
404
406 return constructor_renames[name] if name in constructor_renames else name
407
408
409def _Find_Match(interface_id, member, member_prefix, candidates):
410 member_name = interface_id + '.' + member
411 if member_name in candidates:
412 return member_name
413 member_name = interface_id + '.' + member_prefix + member
414 if member_name in candidates:
415 return member_name
416 member_name = interface_id + '.*'
417 if member_name in candidates:
418 return member_name
419
420
421def _Is_Native(interface, member):
422 return _Find_Match(interface, member, '', _js_custom_members)
423
424
425def Select_Stub(template, is_native):
426 if is_native:
427 return template[0] + template[2]
428 else:
429 return template[0] + template[1]
430
431
432def Generate_Blink(output_dir, database, type_registry):
433 blink_filename = os.path.join(output_dir, '_blink_dartium.dart')
434 blink_file = open(blink_filename, 'w')
435
436 blink_file.write(HEADER)
437
438 interfaces = database.GetInterfaces()
439 for interface in interfaces:
440 name = interface.id
441 resolver_entry = ' if (s == "%s") return Blink%s.instance;\n' % (name,
442 name)
443 blink_file.write(resolver_entry)
444
445 blink_file.write(END_RESOLVER)
446
447 for interface in interfaces:
448 name = interface.id
449
450 if interface.parents and len(
451 interface.parents) > 0 and interface.parents[0].id:
452 extends = interface.parents[0].id
453 class_def = CLASS_DEFINITION_EXTENDS % (name, extends, name)
454 else:
455 class_def = CLASS_DEFINITION % (name, name)
456 blink_file.write(class_def)
457
458 analyzed_constructors = AnalyzeConstructor(interface)
459 if analyzed_constructors:
460 _Emit_Blink_Constructors(blink_file, analyzed_constructors)
461 elif 'Constructor' in interface.ext_attrs:
462 # Zero parameter constructor.
463 blink_file.write(
464 Select_Stub(CONSTRUCTOR_0, _Is_Native(name, 'constructor')) %
465 rename_constructor(name))
466
467 _Process_Attributes(blink_file, interface, interface.attributes)
468 _Process_Operations(blink_file, interface, interface.operations, True)
469
470 _Emit_Extra_Operations(blink_file, name)
471
472 secondary_parents = database.TransitiveSecondaryParents(
473 interface, False)
474 for secondary in secondary_parents:
475 _Process_Attributes(blink_file, secondary, secondary.attributes)
476 _Process_Operations(blink_file, secondary, secondary.operations,
477 False)
478
479 blink_file.write(CLASS_DEFINITION_END)
480
481 blink_file.write(BLINK_UTILS)
482
483 blink_file.close()
484
485
486def _Emit_Extra_Operations(blink_file, interface_name):
487 if (interface_name in _additional_methods):
488 (name, arg_count, return_value) = _additional_methods[interface_name]
489 exposed_name = ''.join(['__get', '___', name]) if return_value else name
490 blink_file.write(
491 Select_Stub(OPERATION_1, False) % (exposed_name, interface_name,
492 name))
493
494
495def _Emit_Blink_Constructors(blink_file, analyzed_constructors):
496 (arg_min_count, arg_max_count) = generate_parameter_entries(
497 analyzed_constructors.param_infos)
498 name = analyzed_constructors.js_name
499 if not (name):
500 name = analyzed_constructors.type_name
501
502 for callback_index in range(arg_min_count, arg_max_count):
503 if callback_index == 0:
504 blink_file.write(
505 Select_Stub(CONSTRUCTOR_0, _Is_Native(name, 'constructor')) %
506 (rename_constructor(name)))
507 else:
508 arguments = []
509 for i in range(0, callback_index):
510 arguments.append(ARGUMENT_NUM % i)
511 argument_list = ', '.join(arguments)
512 blink_file.write(
513 Select_Stub(CONSTRUCTOR_ARGS, _Is_Native(name, 'constructor')) %
514 (callback_index, argument_list, rename_constructor(name),
515 argument_list))
516
517
518def _Process_Attributes(blink_file, interface, attributes):
519 # Emit an interface's attributes and operations.
520 for attribute in sorted(attributes, key=ConstantOutputOrder):
521 name = attribute.id
522 is_native = _Is_Native(interface.id, name)
523 if attribute.is_read_only:
524 if attribute.is_static:
525 class_property = CLASS_STATIC % interface.id
526 blink_file.write(
527 Select_Stub(STATIC_ATTRIBUTE_GETTER, is_native) %
528 (name, class_property, interface.id, name))
529 else:
530 blink_file.write(
531 Select_Stub(ATTRIBUTE_GETTER, is_native) %
532 (name, interface.id, name))
533 else:
534 blink_file.write(
535 Select_Stub(ATTRIBUTE_GETTER, is_native) % (name, interface.id,
536 name))
537 blink_file.write(
538 Select_Stub(ATTRIBUTE_SETTER, is_native) % (name, interface.id,
539 name))
540
541
542def _Process_Operations(blink_file,
543 interface,
544 operations,
545 primary_interface=False):
546 analyzeOperations = []
547
548 for operation in sorted(operations, key=ConstantOutputOrder):
549 if len(analyzeOperations) == 0:
550 analyzeOperations.append(operation)
551 else:
552 if analyzeOperations[0].id == operation.id:
553 # Handle overloads
554 analyzeOperations.append(operation)
555 else:
556 _Emit_Blink_Operation(blink_file, interface, analyzeOperations,
557 primary_interface)
558 analyzeOperations = [operation]
559 if len(analyzeOperations) > 0:
560 _Emit_Blink_Operation(blink_file, interface, analyzeOperations,
561 primary_interface)
562
563
564# List of DartName operations to not emit (e.g., For now only WebGL2RenderingContextBase
565# has readPixels in both WebGLRenderingContextBase and WebGL2RenderingContextBase.
566# Furthermore, readPixels has the exact same number of arguments - in JavaScript
567# there is no typing so they're the same.
568suppressed_operations = {
569 'WebGL2RenderingContextBase': ['readPixels2', 'texImage2D2'],
570}
571
572
573def _Suppress_Secondary_Interface_Operation(interface, analyzed):
574 if interface.id in suppressed_operations:
575 # Should this DartName (name property) be suppressed on this interface?
576 return analyzed.name in suppressed_operations[interface.id]
577 return False
578
579
580def _Emit_Blink_Operation(blink_file, interface, analyzeOperations,
581 primary_interface):
582 analyzed = AnalyzeOperation(interface, analyzeOperations)
583
584 if not (primary_interface) and _Suppress_Secondary_Interface_Operation(
585 interface, analyzed):
586 return
587
588 (arg_min_count,
589 arg_max_count) = generate_parameter_entries(analyzed.param_infos)
590 name = analyzed.js_name
591
592 is_native = _Is_Native(interface.id, name)
593
594 operation = analyzeOperations[0]
595 if (name.startswith('__') and \
596 ('getter' in operation.specials or \
597 'setter' in operation.specials or \
598 'deleter' in operation.specials)):
599 if name == '__propertyQuery__':
600 blink_file.write(
601 Select_Stub(OPERATION_PQ, is_native) % (name, interface.id))
602 else:
603 arg_min_count = arg_max_count
604 if arg_max_count == 2:
605 blink_file.write(
606 Select_Stub(OPERATION_1, is_native) % (name, interface.id,
607 name))
608 elif arg_max_count == 3:
609 blink_file.write(
610 Select_Stub(OPERATION_2, is_native) % (name, interface.id,
611 name))
612 else:
613 print("FATAL ERROR: _blink emitter operator %s.%s" %
614 (interface.id, name))
615 exit
616
617 return
618
619 for callback_index in range(arg_min_count, arg_max_count):
620 if callback_index == 0:
621 if operation.is_static:
622 class_property = CLASS_STATIC % interface.id
623 blink_file.write(
624 Select_Stub(STATIC_OPERATION_0, is_native) %
625 (name, class_property, interface.id, name))
626 else:
627 blink_file.write(
628 Select_Stub(OPERATION_0, is_native) % (name, interface.id,
629 name))
630 else:
631 arguments = []
632 for i in range(0, callback_index):
633 arguments.append(ARGUMENT_NUM % i)
634 argument_list = ', '.join(arguments)
635 if operation.is_static:
636 class_property = CLASS_STATIC % interface.id
637 blink_file.write(
638 Select_Stub(STATIC_OPERATION_ARGS, is_native) %
639 (name, callback_index, argument_list, class_property,
640 interface.id, name, argument_list))
641 else:
642 blink_file.write(
643 Select_Stub(OPERATION_ARGS, is_native) %
644 (name, callback_index, argument_list, interface.id, name,
645 argument_list))
GLFWwindow * window
Definition: main.cc:45
struct MyStruct s
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 remove(*paths)
def print(*args, **kwargs)
Definition: run_tests.py:49
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741