| Index: tools/dom/scripts/generate_blink_file.py
|
| diff --git a/tools/dom/scripts/generate_blink_file.py b/tools/dom/scripts/generate_blink_file.py
|
| index 6f274da35b6ae30b6cf35c5375cb3db6e271a321..bc78c70a43691c71472e132945a5bb0fd3e7f38c 100644
|
| --- a/tools/dom/scripts/generate_blink_file.py
|
| +++ b/tools/dom/scripts/generate_blink_file.py
|
| @@ -7,9 +7,80 @@
|
| """Generates sdk/lib/_blink/dartium/_blink_dartium.dart file."""
|
|
|
| import os
|
| -
|
| +from sets import Set
|
| from generator import AnalyzeOperation, AnalyzeConstructor
|
|
|
| +# This is list of all methods with native c++ implementations
|
| +# If performing a dartium merge, the best practice is to comment out this list,
|
| +# ensure everything runs, and then uncomment this list which might possibly
|
| +# introduce breaking changes due to changes to these method signatures.
|
| +_js_custom_members = Set([
|
| + 'Element.id',
|
| + 'Element.tagName',
|
| + 'Element.className',
|
| + 'Element.setAttribute',
|
| + 'Element.getAttribute',
|
| + 'Node.appendChild', # actually not removed, just native implementation.
|
| + 'Node.cloneNode',
|
| + 'Node.insertBefore',
|
| + 'Node.lastChild',
|
| + 'Node.firstChild',
|
| + 'Node.parentElement',
|
| + 'Node.parentNode',
|
| + 'Node.childNodes',
|
| + 'Node.removeChild',
|
| + 'Node.contains',
|
| + 'Node.nextSibling',
|
| + 'Node.previousSibling',
|
| + 'Document.createTextNode',
|
| + 'Window.location',
|
| + 'Location.href',
|
| + 'Node.querySelector',
|
| +
|
| + 'HTMLElement.hidden',
|
| + 'HTMLElement.style',
|
| + 'Window.innerWidth',
|
| +
|
| + 'ChildNode.remove',
|
| + 'NodeList.length',
|
| + 'NodeList.item',
|
| + 'ParentNode.children',
|
| + 'ParentNode.firstElementChild',
|
| + 'ParentNode.lastElementChild',
|
| + 'Event.target',
|
| + 'MouseEvent.clientY',
|
| + 'MouseEvent.clientX',
|
| +
|
| + 'Node.nodeType',
|
| + 'Node.textContent',
|
| +
|
| + 'HTMLCollection.length',
|
| + 'HTMLCollection.item',
|
| + 'Node.lastElementChild',
|
| + 'Node.firstElementChild',
|
| + 'HTMLElement_tabIndex',
|
| +
|
| + 'Element.clientWidth',
|
| + 'Element.clientHeight',
|
| + 'Document.body',
|
| + 'Element.removeAttribute',
|
| + 'Element.getBoundingClientRect',
|
| + 'CSSStyleDeclaration.getPropertyValue',
|
| + 'CSSStyleDeclaration.setProperty',
|
| + 'CSSStyleDeclaration.__propertyQuery__',
|
| +
|
| + # TODO(jacobr): consider implementing these methods as well as they show
|
| + # up in benchmarks for some sample applications.
|
| + #'Document.createEvent',
|
| + #'Document.initEvent',
|
| + #'EventTarget.dispatchEvent',
|
| + ])
|
| +
|
| +# Uncomment out this line to short circuited native methods and run all of
|
| +# dart:html through JS interop except for createElement which is slightly more
|
| +# tightly natively wired.
|
| +# _js_custom_members = Set([])
|
| +
|
| HEADER = """/* Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| * for details. All rights reserved. Use of this source code is governed by a
|
| * BSD-style license that can be found in the LICENSE file.
|
| @@ -50,7 +121,25 @@ class Blink_Utils {
|
|
|
| static register(document, tag, customType, extendsTagName) native "Utils_register";
|
|
|
| - static createElement(document, tagName) native "Utils_createElement";
|
| + // Methods fast-pathed to improve raw DOM performance for typical applications.
|
| + static createElement(tagName) native "Utils_createElement";
|
| +
|
| +/*
|
| + static getLocation(element) native "Utils_getLocation";
|
| + static getHTMLAnchorElementHref(element) native "HTMLAnchorElement_getHref";
|
| + static getLocationHref(element) native "Location_getHref";
|
| + static getHidden(element) native "Utils_getHidden";
|
| + static getClientX(element) native "Utils_getClientX";
|
| + static getClientY(element) native "Utils_getClientY";
|
| + static getStyle(element) native "Utils_getStyle";
|
| + static getStatus(element) native "Utils_getStatus";
|
| + */
|
| +
|
| +
|
| + // Defines an interceptor if there is an appropriate JavaScript prototype to define it on.
|
| + // In any case, returns a typed JS wrapper compatibile with dart:html and the new
|
| + // typed JS Interop.
|
| + static defineInterceptor(JsObject jsObject, Type type) native "Utils_defineInterceptor";
|
|
|
| static constructElement(element_type, jsObject) native "Utils_constructor_create";
|
|
|
| @@ -106,9 +195,63 @@ class Blink_DOMStringMap {
|
| }
|
|
|
| // Calls through JsNative but returns DomException instead of error strings.
|
| +class Stats {
|
| + Stats(this.name) {
|
| + counts = new Map<String, int>();
|
| + }
|
| +
|
| + String name;
|
| + Map<String, int> counts;
|
| + clear() {
|
| + counts.clear();
|
| + }
|
| +
|
| + track(String v) {
|
| + counts[v] = counts.putIfAbsent(v, ()=> 0) + 1;
|
| + }
|
| + toString() {
|
| + StringBuffer sb = new StringBuffer();
|
| + sb.write('================');
|
| + sb.write('$name ${counts.length}');
|
| + var keys = counts.keys.toList();
|
| + keys.sort((a,b) => counts[b].compareTo(counts[a]));
|
| + for (var key in keys) {
|
| + print("$key => ${counts[key]}");
|
| + }
|
| + sb.write('---------------');
|
| + sb.write('================');
|
| + return sb;
|
| + }
|
| +}
|
| +
|
| +bool TRACK_STATS = true;
|
| +dumpStats() {
|
| + print("------------ STATS ----------------");
|
| + print(Blink_JsNative_DomException.getPropertyStats.toString());
|
| + print(Blink_JsNative_DomException.setPropertyStats.toString());
|
| + print(Blink_JsNative_DomException.callMethodStats.toString());
|
| + print(Blink_JsNative_DomException.constructorStats.toString());
|
| + print("-----------------------------------");
|
| +}
|
| +
|
| +clearStats() {
|
| + Blink_JsNative_DomException.getPropertyStats.clear();
|
| + Blink_JsNative_DomException.setPropertyStats.clear();
|
| + Blink_JsNative_DomException.callMethodStats.clear();
|
| + Blink_JsNative_DomException.constructorStats.clear();
|
| +}
|
| +
|
| class Blink_JsNative_DomException {
|
| - static getProperty(js.JsObject o, name) {
|
| + static var getPropertyStats = new Stats('get property');
|
| + static var setPropertyStats = new Stats('set property');
|
| + static var callMethodStats = new Stats('call method');
|
| + static var constructorStats = new Stats('constructor');
|
| +
|
| + static var constructors = new Map<String, dynamic>();
|
| +
|
| + static getProperty(o, String className, String name) {
|
| try {
|
| + if (TRACK_STATS) getPropertyStats.track('${className}_$name');
|
| return js.JsNative.getProperty(o, name);
|
| } catch (e) {
|
| // Re-throw any errors (returned as a string) as a DomException.
|
| @@ -116,8 +259,51 @@ class Blink_JsNative_DomException {
|
| }
|
| }
|
|
|
| - static callMethod(js.JsObject o, String method, List args) {
|
| + static propertyQuery(o, String name) {
|
| + try {
|
| + if (TRACK_STATS) getPropertyStats.track('__propertyQuery__');
|
| + return js.JsNative.getProperty(o, name);
|
| + } catch (e) {
|
| + // Re-throw any errors (returned as a string) as a DomException.
|
| + throw new DomException.jsInterop(e);
|
| + }
|
| + }
|
| +
|
| + static callConstructor0(String name) {
|
| + try {
|
| + if (TRACK_STATS) constructorStats.track(name);
|
| + var constructor = constructors.putIfAbsent(name, () => js.context[name]);
|
| + return js.JsNative.callConstructor0(constructor);
|
| + } catch (e) {
|
| + // Re-throw any errors (returned as a string) as a DomException.
|
| + throw new DomException.jsInterop(e);
|
| + }
|
| + }
|
| +
|
| + static callConstructor(String name, List args) {
|
| + try {
|
| + if (TRACK_STATS) constructorStats.track(name);
|
| + var constructor = constructors.putIfAbsent(name, () => js.context[name]);
|
| + return js.JsNative.callConstructor(constructor, args);
|
| + } catch (e) {
|
| + // Re-throw any errors (returned as a string) as a DomException.
|
| + throw new DomException.jsInterop(e);
|
| + }
|
| + }
|
| +
|
| + static setProperty(o, String className, String name, value) {
|
| + try {
|
| + if (TRACK_STATS) setPropertyStats.track('${className}_$name');
|
| + return js.JsNative.setProperty(o, name, value);
|
| + } catch (e) {
|
| + // Re-throw any errors (returned as a string) as a DomException.
|
| + throw new DomException.jsInterop(e);
|
| + }
|
| + }
|
| +
|
| + static callMethod(o, String className, String method, List args) {
|
| try {
|
| + if (TRACK_STATS) callMethodStats.track('${className}_$method');
|
| return js.JsNative.callMethod(o, method, args);
|
| } catch (e) {
|
| // Re-throw any errors (returned as a string) as a DomException.
|
| @@ -137,38 +323,73 @@ CLASS_DEFINITION_EXTENDS = """class Blink%s extends Blink%s {
|
| """
|
|
|
| #(interface_name)
|
| -CONSTRUCTOR_0 = ' constructorCallback_0_() => new js.JsObject(Blink_JsNative_DomException.getProperty(js.context, "%s"), []);\n\n'
|
| +
|
| +#
|
| +CONSTRUCTOR_0 = [' constructorCallback_0_()',
|
| + ' => Blink_JsNative_DomException.callConstructor0("%s");\n\n',
|
| + ' native "Blink_Constructor_%s";\n\n']
|
|
|
| #(argument_count, arguments, interface_name, arguments)
|
| -CONSTRUCTOR_ARGS = ' constructorCallback_%s_(%s) => new js.JsObject(Blink_JsNative_DomException.getProperty(js.context, "%s"), [%s]);\n\n'
|
| +CONSTRUCTOR_ARGS = [' constructorCallback_%s_(%s)',
|
| + ' => Blink_JsNative_DomException.callConstructor("%s", [%s]);\n\n',
|
| + ' native "Blink_Constructor_Args_%s" /* %s */;\n\n']
|
|
|
| #(attribute_name, attribute_name)
|
| -ATTRIBUTE_GETTER = ' %s_Getter_(mthis) => Blink_JsNative_DomException.getProperty(mthis, "%s");\n\n'
|
| -ATTRIBUTE_SETTER = ' %s_Setter_(mthis, __arg_0) => mthis["%s"] = __arg_0;\n\n'
|
| +ATTRIBUTE_GETTER = [' %s_Getter_(mthis)',
|
| + ' => Blink_JsNative_DomException.getProperty(mthis, "%s" /* className */, "%s");\n\n',
|
| + ' native "Blink_Getter_%s_%s";\n\n'
|
| + ]
|
| +
|
| +ATTRIBUTE_SETTER = [' %s_Setter_(mthis, __arg_0)',
|
| + ' => Blink_JsNative_DomException.setProperty(mthis, "%s" /* className */, "%s", __arg_0);\n\n',
|
| + ' native "Blink_Setter_%s_%s";\n\n'
|
| + ]
|
|
|
| #(operation_name, operationName)
|
| -OPERATION_0 = ' %s_Callback_0_(mthis) => Blink_JsNative_DomException.callMethod(mthis, "%s", []);\n\n'
|
| +OPERATION_0 = [' %s_Callback_0_(mthis)',
|
| + ' => Blink_JsNative_DomException.callMethod(mthis, "%s" /* className */, "%s", []);\n\n',
|
| + ' native "Blink_Operation_0_%s_%s";\n\n'
|
| + ]
|
|
|
| # getter, setter, deleter and propertyQuery code
|
| -OPERATION_1 = ' $%s_Callback_1_(mthis, __arg_0) => Blink_JsNative_DomException.callMethod(mthis, "%s", [__arg_0]);\n\n'
|
| -OPERATION_2 = ' $%s_Callback_2_(mthis, __arg_0, __arg_1) => Blink_JsNative_DomException.callMethod(mthis, "%s", [__arg_0, __arg_1]);\n\n'
|
| -OPERATION_PQ = ' $%s_Callback_1_(mthis, __arg_0) => mthis[__arg_0];\n\n'
|
| +OPERATION_1 = [' $%s_Callback_1_(mthis, __arg_0)',
|
| + ' => Blink_JsNative_DomException.callMethod(mthis, "%s" /* className */, "%s", [__arg_0]);\n\n',
|
| + ' native "Blink_Operation_1_%s_%s";\n\n'
|
| + ]
|
| +
|
| +OPERATION_2 = [' $%s_Callback_2_(mthis, __arg_0, __arg_1)',
|
| + ' => Blink_JsNative_DomException.callMethod(mthis, "%s" /* className */, "%s", [__arg_0, __arg_1]);\n\n',
|
| + ' native "Blink_Operation_2_%s_%s";\n\n']
|
| +
|
| +OPERATION_PQ = [' $%s_Callback_1_(mthis, __arg_0)',
|
| + ' => Blink_JsNative_DomException.propertyQuery(mthis, __arg_0); /* %s */ \n\n',
|
| + ' native "Blink_Operation_PQ_%s";\n\n']
|
|
|
| #(operation_name, argument_count, arguments, operation_name, arguments)
|
| ARGUMENT_NUM = "__arg_%s"
|
| -OPERATION_ARGS = ' %s_Callback_%s_(mthis, %s) => Blink_JsNative_DomException.callMethod(mthis, "%s", [%s]);\n\n'
|
| +OPERATION_ARGS = [' %s_Callback_%s_(mthis, %s)',
|
| + ' => Blink_JsNative_DomException.callMethod(mthis, "%s" /* className */, "%s", [%s]);\n\n',
|
| + ' native "Blink_Operation_%s_%s"; /* %s */\n\n']
|
| +
|
| +
|
|
|
| # get class property to make static call.
|
| CLASS_STATIC = 'Blink_JsNative_DomException.getProperty(js.context, "%s")'
|
|
|
| # name, classname_getproperty, name
|
| -STATIC_ATTRIBUTE_GETTER = ' %s_Getter_() => Blink_JsNative_DomException.getProperty(%s, "%s");\n\n'
|
| +STATIC_ATTRIBUTE_GETTER = [' %s_Getter_()',
|
| + ' => Blink_JsNative_DomException.getProperty(%s, "%s" /* className */, "%s");\n\n',
|
| + ' /* %s */ native "Blink_Static_getter_%s_%s"']
|
|
|
| # name, classname_getproperty, name
|
| -STATIC_OPERATION_0 = ' %s_Callback_0_() => Blink_JsNative_DomException.callMethod(%s, "%s", []);\n\n'
|
| +STATIC_OPERATION_0 = [' %s_Callback_0_()',
|
| + ' => Blink_JsNative_DomException.callMethod(%s, "%s" /* className */, "%s", []);\n\n',
|
| + ' /* %s */ native "Blink_Static_Operation_0_%s_%s']
|
|
|
| # name, argsCount, args, classname_getproperty, name, args
|
| -STATIC_OPERATION_ARGS = ' %s_Callback_%s_(%s) => Blink_JsNative_DomException.callMethod(%s, "%s", [%s]);\n\n'
|
| +STATIC_OPERATION_ARGS = [' %s_Callback_%s_(%s)',
|
| + ' => Blink_JsNative_DomException.callMethod(%s, "%s" /* className */, "%s", [%s]);\n\n',
|
| + ' /* %s */ native "Blink_Static_Operations_%s_%s" /* %s */ \n\n']
|
|
|
| CLASS_DEFINITION_END = """}
|
|
|
| @@ -197,6 +418,27 @@ constructor_renames = {
|
| def rename_constructor(name):
|
| return constructor_renames[name] if name in constructor_renames else name
|
|
|
| +
|
| +def _Find_Match(interface_id, member, member_prefix, candidates):
|
| + member_name = interface_id + '.' + member
|
| + if member_name in candidates:
|
| + return member_name
|
| + member_name = interface_id + '.' + member_prefix + member
|
| + if member_name in candidates:
|
| + return member_name
|
| + member_name = interface_id + '.*'
|
| + if member_name in candidates:
|
| + return member_name
|
| +
|
| +def _Is_Native(interface, member):
|
| + return _Find_Match(interface, member, '', _js_custom_members)
|
| +
|
| +def Select_Stub(template, is_native):
|
| + if is_native:
|
| + return template[0] + template[2]
|
| + else:
|
| + return template[0] + template[1]
|
| +
|
| def Generate_Blink(output_dir, database, type_registry):
|
| blink_filename = os.path.join(output_dir, '_blink_dartium.dart')
|
| blink_file = open(blink_filename, 'w')
|
| @@ -226,7 +468,7 @@ def Generate_Blink(output_dir, database, type_registry):
|
| _Emit_Blink_Constructors(blink_file, analyzed_constructors)
|
| elif 'Constructor' in interface.ext_attrs:
|
| # Zero parameter constructor.
|
| - blink_file.write(CONSTRUCTOR_0 % rename_constructor(name))
|
| + blink_file.write(Select_Stub(CONSTRUCTOR_0, _Is_Native(name, 'constructor')) % rename_constructor(name))
|
|
|
| _Process_Attributes(blink_file, interface, interface.attributes)
|
| _Process_Operations(blink_file, interface, interface.operations)
|
| @@ -250,27 +492,29 @@ def _Emit_Blink_Constructors(blink_file, analyzed_constructors):
|
|
|
| for callback_index in range(arg_min_count, arg_max_count):
|
| if callback_index == 0:
|
| - blink_file.write(CONSTRUCTOR_0 % (rename_constructor(name)))
|
| + blink_file.write(Select_Stub(CONSTRUCTOR_0, _Is_Native(name, 'constructor')) % (rename_constructor(name)))
|
| else:
|
| arguments = []
|
| for i in range(0, callback_index):
|
| arguments.append(ARGUMENT_NUM % i)
|
| argument_list = ', '.join(arguments)
|
| - blink_file.write(CONSTRUCTOR_ARGS % (callback_index, argument_list, rename_constructor(name), argument_list))
|
| + blink_file.write(
|
| + Select_Stub(CONSTRUCTOR_ARGS, _Is_Native(name, 'constructor')) % (callback_index, argument_list, rename_constructor(name), argument_list))
|
|
|
| def _Process_Attributes(blink_file, interface, attributes):
|
| # Emit an interface's attributes and operations.
|
| for attribute in sorted(attributes, ConstantOutputOrder):
|
| name = attribute.id
|
| + is_native = _Is_Native(interface.id, name)
|
| if attribute.is_read_only:
|
| if attribute.is_static:
|
| class_property = CLASS_STATIC % interface.id
|
| - blink_file.write(STATIC_ATTRIBUTE_GETTER % (name, class_property, name))
|
| + blink_file.write(Select_Stub(STATIC_ATTRIBUTE_GETTER, is_native) % (name, class_property, interface.id, name))
|
| else:
|
| - blink_file.write(ATTRIBUTE_GETTER % (name, name))
|
| + blink_file.write(Select_Stub(ATTRIBUTE_GETTER, is_native) % (name, interface.id, name))
|
| else:
|
| - blink_file.write(ATTRIBUTE_GETTER % (name, name))
|
| - blink_file.write(ATTRIBUTE_SETTER % (name, name))
|
| + blink_file.write(Select_Stub(ATTRIBUTE_GETTER, is_native) % (name, interface.id, name))
|
| + blink_file.write(Select_Stub(ATTRIBUTE_SETTER, is_native) % (name, interface.id, name))
|
|
|
| def _Process_Operations(blink_file, interface, operations):
|
| analyzeOperations = []
|
| @@ -292,6 +536,7 @@ def _Emit_Blink_Operation(blink_file, interface, analyzeOperations):
|
| analyzed = AnalyzeOperation(interface, analyzeOperations)
|
| (arg_min_count, arg_max_count) = generate_parameter_entries(analyzed.param_infos)
|
| name = analyzed.js_name
|
| + is_native = _Is_Native(interface.id, name)
|
|
|
| operation = analyzeOperations[0]
|
| if (name.startswith('__') and \
|
| @@ -299,13 +544,13 @@ def _Emit_Blink_Operation(blink_file, interface, analyzeOperations):
|
| 'setter' in operation.specials or \
|
| 'deleter' in operation.specials)):
|
| if name == '__propertyQuery__':
|
| - blink_file.write(OPERATION_PQ % (name))
|
| + blink_file.write(Select_Stub(OPERATION_PQ, is_native) % (name, interface.id))
|
| else:
|
| arg_min_count = arg_max_count
|
| if arg_max_count == 2:
|
| - blink_file.write(OPERATION_1 % (name, name))
|
| + blink_file.write(Select_Stub(OPERATION_1, is_native) % (name, interface.id, name))
|
| elif arg_max_count == 3:
|
| - blink_file.write(OPERATION_2 % (name, name))
|
| + blink_file.write(Select_Stub(OPERATION_2, is_native) % (name, interface.id, name))
|
| else:
|
| print "FATAL ERROR: _blink emitter operator %s.%s" % (interface.id, name)
|
| exit
|
| @@ -316,9 +561,9 @@ def _Emit_Blink_Operation(blink_file, interface, analyzeOperations):
|
| if callback_index == 0:
|
| if operation.is_static:
|
| class_property = CLASS_STATIC % interface.id
|
| - blink_file.write(STATIC_OPERATION_0 % (name, class_property, name))
|
| + blink_file.write(Select_Stub(STATIC_OPERATION_0, is_native) % (name, class_property, interface.id, name))
|
| else:
|
| - blink_file.write(OPERATION_0 % (name, name))
|
| + blink_file.write(Select_Stub(OPERATION_0, is_native) % (name, interface.id, name))
|
| else:
|
| arguments = []
|
| for i in range(0, callback_index):
|
| @@ -326,6 +571,6 @@ def _Emit_Blink_Operation(blink_file, interface, analyzeOperations):
|
| argument_list = ', '.join(arguments)
|
| if operation.is_static:
|
| class_property = CLASS_STATIC % interface.id
|
| - blink_file.write(STATIC_OPERATION_ARGS % (name, callback_index, argument_list, class_property, name, argument_list))
|
| + blink_file.write(Select_Stub(STATIC_OPERATION_ARGS, is_native) % (name, callback_index, argument_list, class_property, interface.id, name, argument_list))
|
| else:
|
| - blink_file.write(OPERATION_ARGS % (name, callback_index, argument_list, name, argument_list))
|
| + blink_file.write(Select_Stub(OPERATION_ARGS, is_native) % (name, callback_index, argument_list, interface.id, name, argument_list))
|
|
|