| Index: sdk/lib/html/html_common/conversions_dartium.dart
|
| diff --git a/sdk/lib/html/html_common/conversions_dartium.dart b/sdk/lib/html/html_common/conversions_dartium.dart
|
| index 66299a05389fd4c7b79a0ef086ac052eccdd82ec..ef02c00b649893a847584e2d827e179424b73e14 100644
|
| --- a/sdk/lib/html/html_common/conversions_dartium.dart
|
| +++ b/sdk/lib/html/html_common/conversions_dartium.dart
|
| @@ -7,11 +7,11 @@ convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) =>
|
| new _AcceptStructuredCloneDartium().convertNativeToDart_AcceptStructuredClone(object, mustCopy: mustCopy);
|
|
|
| class _StructuredCloneDartium extends _StructuredClone {
|
| - newJsMap() => new js.JsObject(js.context["Object"]);
|
| - putIntoMap(map, key, value) => map[key] = value;
|
| - // TODO(alanknight): Don't create two extra lists to get a fixed-length JS list.
|
| - newJsList(length) => new js.JsArray.from(new List(length));
|
| - cloneNotRequired(e) => e is js.JsObject;
|
| + newJsMap() => js.JsNative.newObject();
|
| + putIntoMap(map, key, value) => js.JsNative.setProperty(map, key, value);
|
| + newJsList(length) => js.JsNative.newArray()..length = length;
|
| + cloneNotRequired(e) =>
|
| + e is js.JSObject || e is TypedData || e is ByteBuffer;
|
| }
|
|
|
| /// A version of _AcceptStructuredClone, but using a different algorithm
|
| @@ -24,15 +24,14 @@ class _StructuredCloneDartium extends _StructuredClone {
|
| class _AcceptStructuredCloneDartium {
|
| newDartList(length) => new List(length);
|
|
|
| - // JsObjects won't be identical, but will be equal only if the underlying
|
| - // Js entities are identical.
|
| - bool identicalInJs(a, b) =>
|
| - (a is js.JsObject) ? a == b : identical(a, b);
|
| + // As long as we stick to JSObject instead of intermingling legacy JsObject,
|
| + // we can simply use identical.
|
| + bool identicalInJs(a, b) => identical(a, b);
|
|
|
| void forEachJsField(jsObject, action) {
|
| - var keys = js.context["Object"].callMethod("keys", [jsObject]);
|
| + var keys = js.JsNative.callMethod(_object, "keys", [jsObject]);
|
| for (var key in keys) {
|
| - action(key, jsObject[key]);
|
| + action(key, js.JsNative.getProperty(jsObject, key));
|
| }
|
| }
|
|
|
| @@ -52,10 +51,7 @@ class _AcceptStructuredCloneDartium {
|
| if (e is bool) return e;
|
| if (e is num) return e;
|
| if (e is String) return e;
|
| -
|
| - if (isJavaScriptDate(e)) {
|
| - return convertNativeToDart_DateTime(e);
|
| - }
|
| + if (e is DateTime) return e;
|
|
|
| if (isJavaScriptRegExp(e)) {
|
| // TODO(sra).
|
| @@ -106,51 +102,60 @@ class _AcceptStructuredCloneDartium {
|
| }
|
| }
|
|
|
| -final _dateConstructor = js.context["Date"];
|
| -final _regexConstructor = js.context["RegExp"];
|
| +final _dateConstructor = js.JsNative.getProperty(window, "Date");
|
| +final _regexConstructor = js.JsNative.getProperty(window, "RegExp");
|
|
|
| -bool isJavaScriptDate(value) => value is js.JsObject && value.instanceof(_dateConstructor);
|
| -bool isJavaScriptRegExp(value) => value is js.JsObject && value.instanceof(_regexConstructor);
|
| -bool isJavaScriptArray(value) => value is js.JsArray;
|
| +bool isJavaScriptDate(value) => value is js.JSObject && js.JsNative.instanceof(value, _dateConstructor);
|
| +bool isJavaScriptRegExp(value) => value is js.JSObject && js.JsNative.instanceof(value, _regexConstructor);
|
| +bool isJavaScriptArray(value) => value is js.JSArray;
|
|
|
| -final _object = js.context["Object"];
|
| -final _getPrototypeOf = _object["getPrototypeOf"];
|
| +final _object = js.JsNative.getProperty(window, "Object");
|
| +final _getPrototypeOf = js.JsNative.getProperty(_object, "getPrototypeOf");
|
| _getProto(object) {
|
| - return _getPrototypeOf.apply([object]);
|
| + return _getPrototypeOf(object);
|
| }
|
| -final _objectProto = js.context["Object"]["prototype"];
|
| +final _objectProto = js.JsNative.getProperty(_object, "prototype");
|
|
|
| bool isJavaScriptSimpleObject(value) {
|
| - if (value is! js.JsObject) return false;
|
| + if (value is! js.JSObject) return false;
|
| var proto = _getProto(value);
|
| return proto == _objectProto || proto == null;
|
| }
|
| +
|
| +// TODO(jacobr): this makes little sense unless we are doing something
|
| +// ambitious to make Dartium and Dart2Js interop well with each other.
|
| bool isImmutableJavaScriptArray(value) =>
|
| - isJavaScriptArray(value) && value["immutable$list"] != null;
|
| + isJavaScriptArray(value) && js.JsNative.getProperty(value, "immutable$list") != null;
|
|
|
| -final _promiseConstructor = js.context['Promise'];
|
| -bool isJavaScriptPromise(value) => value is js.JsObject && value['constructor'] == _promiseConstructor;
|
| +final _promiseConstructor = js.JsNative.getProperty(window, 'Promise');
|
| +bool isJavaScriptPromise(value) => value is js.JSObject && identical(js.JsNative.getProperty(value, 'constructor'), _promiseConstructor);
|
|
|
| -Future convertNativePromiseToDartFuture(js.JsObject promise) {
|
| +Future convertNativePromiseToDartFuture(js.JSObject promise) {
|
| var completer = new Completer();
|
| - var newPromise = promise
|
| - .callMethod("then", [(result) => completer.complete(result)])
|
| - .callMethod("catch", [(result) => completer.completeError(result)]);
|
| + var newPromise = js.JsNative.callMethod(js.JsNative.callMethod(promise,
|
| + "then", [js.allowInterop((result) => completer.complete(result))]),
|
| + "catch", [js.allowInterop((result) => completer.completeError(result))]);
|
| return completer.future;
|
| }
|
|
|
| convertDartToNative_DateTime(DateTime date) {
|
| - return new js.JsObject(js.context["Date"], [date.millisecondsSinceEpoch]);
|
| + return date;
|
| }
|
|
|
| /// Creates a Dart Rectangle from a Javascript object with properties
|
| -/// left, top, width and height. Used internally in Dartium.
|
| -Rectangle make_dart_rectangle(r) =>
|
| - r == null ? null : new Rectangle(
|
| - js.JsNative.getProperty(r, 'left'),
|
| - js.JsNative.getProperty(r, 'top'),
|
| - js.JsNative.getProperty(r, 'width'),
|
| - js.JsNative.getProperty(r, 'height'));
|
| +/// left, top, width and height or a 4 element array of integers. Used internally in Dartium.
|
| +Rectangle make_dart_rectangle(r) {
|
| + if (r == null) return null;
|
| + if (r is List) {
|
| + return new Rectangle(r[0], r[1], r[2], r[3]);
|
| + }
|
| +
|
| + return new Rectangle(
|
| + js.JsNative.getProperty(r, 'left'),
|
| + js.JsNative.getProperty(r, 'top'),
|
| + js.JsNative.getProperty(r, 'width'),
|
| + js.JsNative.getProperty(r, 'height'));
|
| +}
|
|
|
| // Converts a flat Dart map into a JavaScript object with properties this is
|
| // is the Dartium only version it uses dart:js.
|
| @@ -158,16 +163,16 @@ Rectangle make_dart_rectangle(r) =>
|
| // code in html_common and be more general.
|
| convertDartToNative_Dictionary(Map dict) {
|
| if (dict == null) return null;
|
| - var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object'));
|
| + var jsObject = js.JsNative.newObject();
|
| dict.forEach((String key, value) {
|
| if (value is List) {
|
| - var jsArray = new js.JsArray();
|
| + var jsArray = js.JsNative.newArray();
|
| value.forEach((elem) {
|
| jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem);
|
| });
|
| - jsObject[key] = jsArray;
|
| + js.JsNative.setProperty(jsObject, key, jsArray);
|
| } else {
|
| - jsObject[key] = value;
|
| + js.JsNative.setProperty(jsObject, key, value);
|
| }
|
| });
|
| return jsObject;
|
| @@ -196,8 +201,15 @@ class _ReturnedDictionary {
|
|
|
| // Helper function to wrapped a returned dictionary from blink to a Dart looking
|
| // class.
|
| -convertNativeDictionaryToDartDictionary(Map values) =>
|
| - values != null ? new _ReturnedDictionary(values) : null;
|
| +convertNativeDictionaryToDartDictionary(values) {
|
| + if (values is! Map) {
|
| + // TODO(jacobr): wish wwe didn't have to do this.
|
| + values = convertNativeToDart_SerializedScriptValue(values);
|
| + }
|
| + return values != null ? new _ReturnedDictionary(values) : null;
|
| +}
|
| +
|
| +convertNativeToDart_Dictionary(values) => convertNativeToDart_SerializedScriptValue(values);
|
|
|
| // Conversion function place holder (currently not used in dart2js or dartium).
|
| List convertDartToNative_StringArray(List<String> input) => input;
|
| @@ -205,284 +217,59 @@ List convertDartToNative_StringArray(List<String> input) => input;
|
| // Converts a Dart list into a JsArray. For the Dartium version only.
|
| convertDartToNative_List(List input) => new js.JsArray()..addAll(input);
|
|
|
| -/// Find the underlying JS object for a dart:html Dart object.
|
| -unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance);
|
| -
|
| -// Flag to disable JS interop asserts. Setting to false will speed up the
|
| -// wrap_jso calls.
|
| -bool interop_checks = false;
|
| -
|
| -/// Wrap a JS object with an instance of the matching dart:html class. Used only in Dartium.
|
| -wrap_jso(jsObject) {
|
| +// Incredibly slow implementation to lookup the runtime type for an object.
|
| +// Fortunately, performance doesn't matter much as the results are cached
|
| +// as long as the object being looked up has a valid prototype.
|
| +// TODO(jacobr): we should track the # of lookups to ensure that things aren't
|
| +// going off the rails due to objects with null prototypes, etc.
|
| +// Note: unlike all other methods in this class, here we intentionally use
|
| +// the old JsObject types to bootstrap the new typed bindings.
|
| +Type lookupType(js.JsObject jsObject, bool isElement) {
|
| try {
|
| - if (jsObject is! js.JsObject || jsObject == null) {
|
| - // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
|
| - // or it's a simple type.
|
| - return jsObject;
|
| - }
|
| -
|
| - var wrapper = js.getDartHtmlWrapperFor(jsObject);
|
| - // if we have a wrapper return the Dart instance.
|
| - if (wrapper != null) {
|
| - return wrapper;
|
| - }
|
| -
|
| - if (jsObject is js.JsArray) {
|
| - wrapper = new js.JSArray.create(jsObject);
|
| - js.setDartHtmlWrapperFor(jsObject, wrapper);
|
| - return wrapper;
|
| - }
|
| - if (jsObject is js.JsFunction) {
|
| - wrapper = new js.JSFunction.create(jsObject);
|
| - js.setDartHtmlWrapperFor(jsObject, wrapper);
|
| - return wrapper;
|
| - }
|
| -
|
| - // Try the most general type conversions on it.
|
| - // TODO(alanknight): We may be able to do better. This maintains identity,
|
| - // which is useful, but expensive. And if we nest something that only
|
| - // this conversion handles, how does that work? e.g. a list of maps of elements.
|
| - var converted = convertNativeToDart_SerializedScriptValue(jsObject);
|
| - if (!identical(converted, jsObject)) {
|
| - return converted;
|
| - }
|
| + // TODO(jacobr): add static methods that return the runtime type of the patch
|
| + // class so that this code works as expected.
|
| + if (jsObject is js.JsArray) {
|
| + return js.JSArray.instanceRuntimeType;
|
| + }
|
| + if (jsObject is js.JsFunction) {
|
| + return js.JSFunction.instanceRuntimeType;
|
| + }
|
|
|
| var constructor = js.JsNative.getProperty(jsObject, 'constructor');
|
| if (constructor == null) {
|
| // Perfectly valid case for JavaScript objects where __proto__ has
|
| // intentionally been set to null.
|
| - js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject));
|
| - return jsObject;
|
| + // We should track and warn about this case as peformance will be poor.
|
| + return js.JSObject.instanceRuntimeType;
|
| }
|
| var jsTypeName = js.JsNative.getProperty(constructor, 'name');
|
| if (jsTypeName is! String || jsTypeName.length == 0) {
|
| // Not an html type.
|
| - wrapper = new js.JSObject.create(jsObject);
|
| - js.setDartHtmlWrapperFor(jsObject, wrapper);
|
| - return wrapper;
|
| + return js.JSObject.instanceRuntimeType;
|
| }
|
|
|
| var dartClass_instance;
|
| var customElementClass = null;
|
| - var extendsTag = "";
|
| - var custom = getCustomElementEntry(jsObject);
|
| - if (custom != null) {
|
| - customElementClass = custom['type'];
|
| - extendsTag = custom['extends'];
|
| - }
|
| -
|
| - // Only allow custom elements to be created in the html or svg default
|
| - // namespace.
|
| - var func;
|
| - var defaultNS = jsObject['namespaceURI'] == 'http://www.w3.org/1999/xhtml' ||
|
| - jsObject['namespaceURI'] == 'http://www.w3.org/2000/svg';
|
| - if (customElementClass != null && extendsTag == "" && defaultNS) {
|
| - // The customElementClass is known but we can't create the real class so
|
| - // create the HtmlElement and it will get upgraded when registerElement's
|
| - // createdCallback is called.
|
| - func = getHtmlCreateFunction('HTMLElement');
|
| - } else {
|
| - func = getHtmlCreateFunction(jsTypeName);
|
| - if (func == null) {
|
| - // Start walking the prototype chain looking for a JS class.
|
| - var prototype = jsObject['__proto__'];
|
| - var keepWalking = true;
|
| - while (keepWalking && prototype.hasProperty('__proto__')) {
|
| - prototype = prototype['__proto__'];
|
| - if (prototype != null && prototype is Element &&
|
| - prototype.blink_jsObject != null) {
|
| - // We're a Dart class that's pointing to a JS class.
|
| - var blinkJso = prototype.blink_jsObject;
|
| - jsTypeName = blinkJso['constructor']['name'];
|
| - func = getHtmlCreateFunction(jsTypeName);
|
| - keepWalking = func == null;
|
| - }
|
| - }
|
| + var extendsTag = "";
|
| +
|
| + Type type = getHtmlCreateType(jsTypeName);
|
| + if (type != null) return type;
|
| +
|
| + // Start walking the prototype chain looking for a JS class.
|
| + var prototype = js.JsNative.getProperty(jsObject, '__proto__');
|
| + while (prototype != null) {
|
| + // We're a Dart class that's pointing to a JS class.
|
| + var constructor = js.JsNative.getProperty(prototype, 'constructor');
|
| + if (constructor != null) {
|
| + jsTypeName = js.JsNative.getProperty(constructor, 'name');
|
| + type = getHtmlCreateType(jsTypeName);
|
| + if (type != null) return type;
|
| }
|
| + prototype = js.JsNative.getProperty(prototype, '__proto__');
|
| }
|
| -
|
| - // Can we construct a Dart class?
|
| - if (func != null) {
|
| - dartClass_instance = func();
|
| -
|
| - // Wrap our Dart instance in both directions.
|
| - dartClass_instance.blink_jsObject = jsObject;
|
| - js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
|
| - }
|
| -
|
| - // TODO(jacobr): cache that this is not a dart:html JS class.
|
| - return dartClass_instance;
|
| - } catch (e, stacktrace) {
|
| - if (interop_checks) {
|
| - if (e is DebugAssertException) window.console
|
| - .log("${e.message}\n ${stacktrace}");
|
| - else window.console.log("${stacktrace}");
|
| - }
|
| - }
|
| -
|
| - return null;
|
| -}
|
| -
|
| -/**
|
| - * Create Dart class that maps to the JS Type, add the JsObject as an expando
|
| - * on the Dart class and return the created Dart class.
|
| - */
|
| -wrap_jso_no_SerializedScriptvalue(jsObject) {
|
| - try {
|
| - if (jsObject is! js.JsObject || jsObject == null) {
|
| - // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
|
| - // or it's a simple type.
|
| - return jsObject;
|
| - }
|
| -
|
| - // TODO(alanknight): With upgraded custom elements this causes a failure because
|
| - // we need a new wrapper after the type changes. We could possibly invalidate this
|
| - // if the constructor name didn't match?
|
| - var wrapper = js.getDartHtmlWrapperFor(jsObject);
|
| - if (wrapper != null) {
|
| - return wrapper;
|
| - }
|
| -
|
| - if (jsObject is js.JsArray) {
|
| - wrapper = new js.JSArray.create(jsObject);
|
| - js.setDartHtmlWrapperFor(jsObject, wrapper);
|
| - return wrapper;
|
| - }
|
| - if (jsObject is js.JsFunction) {
|
| - wrapper = new js.JSFunction.create(jsObject);
|
| - js.setDartHtmlWrapperFor(jsObject, wrapper);
|
| - return wrapper;
|
| - }
|
| -
|
| - var constructor = js.JsNative.getProperty(jsObject, 'constructor');
|
| - if (constructor == null) {
|
| - // Perfectly valid case for JavaScript objects where __proto__ has
|
| - // intentionally been set to null.
|
| - js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject));
|
| - return jsObject;
|
| - }
|
| - var jsTypeName = js.JsNative.getProperty(constructor, 'name');
|
| - if (jsTypeName is! String || jsTypeName.length == 0) {
|
| - // Not an html type.
|
| - wrapper = new js.JSObject.create(jsObject);
|
| - js.setDartHtmlWrapperFor(jsObject, wrapper);
|
| - return wrapper;
|
| - }
|
| -
|
| - var func = getHtmlCreateFunction(jsTypeName);
|
| - if (func != null) {
|
| - var dartClass_instance = func();
|
| - dartClass_instance.blink_jsObject = jsObject;
|
| - js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
|
| - return dartClass_instance;
|
| - }
|
| - wrapper = new js.JSObject.create(jsObject);
|
| - js.setDartHtmlWrapperFor(jsObject, wrapper);
|
| - return wrapper;
|
| } catch (e, stacktrace) {
|
| - if (interop_checks) {
|
| - if (e is DebugAssertException) window.console
|
| - .log("${e.message}\n ${stacktrace}");
|
| - else window.console.log("${stacktrace}");
|
| - }
|
| - }
|
| -
|
| - return null;
|
| -}
|
| -
|
| -/**
|
| - * Create Dart class that maps to the JS Type that is the JS type being
|
| - * extended using JS interop createCallback (we need the base type of the
|
| - * custom element) not the Dart created constructor.
|
| - */
|
| -wrap_jso_custom_element(jsObject) {
|
| - try {
|
| - if (jsObject is! js.JsObject) {
|
| - // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
|
| - return jsObject;
|
| - }
|
| -
|
| - // Find out what object we're extending.
|
| - var objectName = jsObject.toString();
|
| - // Expect to see something like '[object HTMLElement]'.
|
| - if (!objectName.startsWith('[object ')) {
|
| - return jsObject;
|
| - }
|
| -
|
| - var extendsClass = objectName.substring(8, objectName.length - 1);
|
| - var func = getHtmlCreateFunction(extendsClass);
|
| - if (interop_checks)
|
| - debug_or_assert("func != null name = ${extendsClass}", func != null);
|
| - var dartClass_instance = func();
|
| - dartClass_instance.blink_jsObject = jsObject;
|
| - return dartClass_instance;
|
| - } catch(e, stacktrace){
|
| - if (interop_checks) {
|
| - if (e is DebugAssertException)
|
| - window.console.log("${e.message}\n ${stacktrace}");
|
| - else
|
| - window.console.log("${stacktrace}");
|
| - }
|
| -
|
| - // Problem?
|
| - return null;
|
| - }
|
| -}
|
| -
|
| -getCustomElementEntry(element) {
|
| - var hasAttribute = false;
|
| -
|
| - var jsObject;
|
| - var tag = "";
|
| - var runtimeType = element.runtimeType;
|
| - if (runtimeType == HtmlElement) {
|
| - tag = element.localName;
|
| - } else if (runtimeType == TemplateElement) {
|
| - // Data binding with a Dart class.
|
| - tag = element.attributes['is'];
|
| - } else if (runtimeType == js.JsObject) {
|
| - // It's a Polymer core element (written in JS).
|
| - // Make sure it's an element anything else we can ignore.
|
| - if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
|
| - if (js.JsNative.callMethod(element, 'hasAttribute', ['is'])) {
|
| - hasAttribute = true;
|
| - // It's data binding use the is attribute.
|
| - tag = js.JsNative.callMethod(element, 'getAttribute', ['is']);
|
| - } else {
|
| - // It's a custom element we want the local name.
|
| - tag = element['localName'];
|
| - }
|
| - }
|
| - } else {
|
| - throw new UnsupportedError(
|
| - 'Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObject.');
|
| - }
|
| -
|
| - var entry = _knownCustomElements[tag];
|
| - if (entry != null) {
|
| - // If there's an 'is' attribute then check if the extends tag registered
|
| - // matches the tag if so then return the entry that's registered for this
|
| - // extendsTag or if there's no 'is' tag then return the entry found.
|
| - if ((hasAttribute && entry['extends'] == tag) || !hasAttribute) {
|
| - return entry;
|
| - }
|
| - }
|
| -
|
| - return null;
|
| -}
|
| -
|
| -// List of known tagName to DartClass for custom elements, used for upgrade.
|
| -var _knownCustomElements = new Map<String, Map<Type, String>>();
|
| -
|
| -void addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
|
| - _knownCustomElements[tagName] =
|
| - {'type': dartClass, 'extends': extendTag != null ? extendTag : "" };
|
| -}
|
| -
|
| -Type getCustomElementType(object) {
|
| - var entry = getCustomElementEntry(object);
|
| - if (entry != null) {
|
| - return entry['type'];
|
| + if (e is DebugAssertException) print("${e.message}\n ${stacktrace}");
|
| + else print("${stacktrace}");
|
| }
|
| - return null;
|
| + return js.JSObject.instanceRuntimeType;
|
| }
|
|
|