| OLD | NEW |
| (Empty) |
| 1 part of html_common; | |
| 2 | |
| 3 convertDartToNative_PrepareForStructuredClone(value) => | |
| 4 new _StructuredCloneDartium() | |
| 5 .convertDartToNative_PrepareForStructuredClone(value); | |
| 6 | |
| 7 convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) => | |
| 8 new _AcceptStructuredCloneDartium() | |
| 9 .convertNativeToDart_AcceptStructuredClone(object, mustCopy: mustCopy); | |
| 10 | |
| 11 class _StructuredCloneDartium extends _StructuredClone { | |
| 12 newJsMap() => js.JsNative.newObject(); | |
| 13 putIntoMap(map, key, value) => js.JsNative.setProperty(map, key, value); | |
| 14 newJsList(length) => js.JsNative.newArray()..length = length; | |
| 15 cloneNotRequired(e) => e is js.JSObject || e is TypedData || e is ByteBuffer; | |
| 16 } | |
| 17 | |
| 18 /// A version of _AcceptStructuredClone, but using a different algorithm | |
| 19 /// so we can take advantage of an identity HashMap on Dartium without | |
| 20 /// the bad side-effect of modifying the JS source objects if we do the same in | |
| 21 /// dart2js. | |
| 22 /// | |
| 23 /// This no longer inherits anything from _AcceptStructuredClone | |
| 24 /// and is never used polymorphically with it, so it doesn't inherit. | |
| 25 class _AcceptStructuredCloneDartium { | |
| 26 newDartList(length) => new List(length); | |
| 27 | |
| 28 // As long as we stick to JSObject instead of intermingling legacy JsObject, | |
| 29 // we can simply use identical. | |
| 30 bool identicalInJs(a, b) => identical(a, b); | |
| 31 | |
| 32 void forEachJsField(jsObject, action) { | |
| 33 var keys = js.JsNative.callMethod(_object, "keys", [jsObject]); | |
| 34 for (var key in keys) { | |
| 35 action(key, js.JsNative.getProperty(jsObject, key)); | |
| 36 } | |
| 37 } | |
| 38 | |
| 39 // Keep track of the clones, keyed by the original object. If we're | |
| 40 // not copying, these may be the same. | |
| 41 var clones = new HashMap.identity(); | |
| 42 bool mustCopy = false; | |
| 43 | |
| 44 Object findSlot(value) { | |
| 45 return clones.putIfAbsent(value, () => null); | |
| 46 } | |
| 47 | |
| 48 writeSlot(original, x) { | |
| 49 clones[original] = x; | |
| 50 } | |
| 51 | |
| 52 walk(e) { | |
| 53 if (e == null) return e; | |
| 54 if (e is bool) return e; | |
| 55 if (e is num) return e; | |
| 56 if (e is String) return e; | |
| 57 if (e is DateTime) return e; | |
| 58 | |
| 59 if (isJavaScriptRegExp(e)) { | |
| 60 // TODO(sra). | |
| 61 throw new UnimplementedError('structured clone of RegExp'); | |
| 62 } | |
| 63 | |
| 64 if (isJavaScriptPromise(e)) { | |
| 65 return convertNativePromiseToDartFuture(e); | |
| 66 } | |
| 67 | |
| 68 if (isJavaScriptSimpleObject(e)) { | |
| 69 // TODO(sra): If mustCopy is false, swizzle the prototype for one of a Map | |
| 70 // implementation that uses the properies as storage. | |
| 71 var copy = findSlot(e); | |
| 72 if (copy != null) return copy; | |
| 73 copy = {}; | |
| 74 | |
| 75 writeSlot(e, copy); | |
| 76 forEachJsField(e, (key, value) => copy[key] = walk(value)); | |
| 77 return copy; | |
| 78 } | |
| 79 | |
| 80 if (isJavaScriptArray(e)) { | |
| 81 var copy = findSlot(e); | |
| 82 if (copy != null) return copy; | |
| 83 | |
| 84 int length = e.length; | |
| 85 // Since a JavaScript Array is an instance of Dart List, we can modify it | |
| 86 // in-place unless we must copy. | |
| 87 copy = mustCopy ? newDartList(length) : e; | |
| 88 writeSlot(e, copy); | |
| 89 | |
| 90 for (int i = 0; i < length; i++) { | |
| 91 copy[i] = walk(e[i]); | |
| 92 } | |
| 93 return copy; | |
| 94 } | |
| 95 | |
| 96 // Assume anything else is already a valid Dart object, either by having | |
| 97 // already been processed, or e.g. a clonable native class. | |
| 98 return e; | |
| 99 } | |
| 100 | |
| 101 convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) { | |
| 102 this.mustCopy = mustCopy; | |
| 103 var copy = walk(object); | |
| 104 return copy; | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 final _dateConstructor = js.JsNative.getProperty(window, "Date"); | |
| 109 final _regexConstructor = js.JsNative.getProperty(window, "RegExp"); | |
| 110 | |
| 111 bool isJavaScriptDate(value) => | |
| 112 value is js.JSObject && js.JsNative.instanceof(value, _dateConstructor); | |
| 113 bool isJavaScriptRegExp(value) => | |
| 114 value is js.JSObject && js.JsNative.instanceof(value, _regexConstructor); | |
| 115 bool isJavaScriptArray(value) => value is js.JSArray; | |
| 116 | |
| 117 final _object = js.JsNative.getProperty(window, "Object"); | |
| 118 final _getPrototypeOf = js.JsNative.getProperty(_object, "getPrototypeOf"); | |
| 119 _getProto(object) { | |
| 120 return _getPrototypeOf(object); | |
| 121 } | |
| 122 | |
| 123 final _objectProto = js.JsNative.getProperty(_object, "prototype"); | |
| 124 | |
| 125 bool isJavaScriptSimpleObject(value) { | |
| 126 if (value is! js.JSObject) return false; | |
| 127 var proto = _getProto(value); | |
| 128 return proto == _objectProto || proto == null; | |
| 129 } | |
| 130 | |
| 131 // TODO(jacobr): this makes little sense unless we are doing something | |
| 132 // ambitious to make Dartium and Dart2Js interop well with each other. | |
| 133 bool isImmutableJavaScriptArray(value) => | |
| 134 isJavaScriptArray(value) && | |
| 135 js.JsNative.getProperty(value, "immutable$list") != null; | |
| 136 | |
| 137 final _promiseConstructor = js.JsNative.getProperty(window, 'Promise'); | |
| 138 bool isJavaScriptPromise(value) => | |
| 139 value is js.JSObject && | |
| 140 identical( | |
| 141 js.JsNative.getProperty(value, 'constructor'), _promiseConstructor); | |
| 142 | |
| 143 Future convertNativePromiseToDartFuture(js.JSObject promise) { | |
| 144 var completer = new Completer(); | |
| 145 var newPromise = js.JsNative.callMethod( | |
| 146 js.JsNative.callMethod(promise, "then", | |
| 147 [js.allowInterop((result) => completer.complete(result))]), | |
| 148 "catch", | |
| 149 [js.allowInterop((result) => completer.completeError(result))]); | |
| 150 return completer.future; | |
| 151 } | |
| 152 | |
| 153 convertDartToNative_DateTime(DateTime date) { | |
| 154 return date; | |
| 155 } | |
| 156 | |
| 157 /// Creates a Dart Rectangle from a Javascript object with properties | |
| 158 /// left, top, width and height or a 4 element array of integers. Used internall
y in Dartium. | |
| 159 Rectangle make_dart_rectangle(r) { | |
| 160 if (r == null) return null; | |
| 161 if (r is List) { | |
| 162 return new Rectangle(r[0], r[1], r[2], r[3]); | |
| 163 } | |
| 164 | |
| 165 return new Rectangle( | |
| 166 js.JsNative.getProperty(r, 'left'), | |
| 167 js.JsNative.getProperty(r, 'top'), | |
| 168 js.JsNative.getProperty(r, 'width'), | |
| 169 js.JsNative.getProperty(r, 'height')); | |
| 170 } | |
| 171 | |
| 172 // Converts a flat Dart map into a JavaScript object with properties this is | |
| 173 // is the Dartium only version it uses dart:js. | |
| 174 // TODO(alanknight): This could probably be unified with the dart2js conversions | |
| 175 // code in html_common and be more general. | |
| 176 convertDartToNative_Dictionary(Map dict) { | |
| 177 if (dict == null) return null; | |
| 178 var jsObject = js.JsNative.newObject(); | |
| 179 dict.forEach((String key, value) { | |
| 180 if (value is List) { | |
| 181 var jsArray = js.JsNative.newArray(); | |
| 182 value.forEach((elem) { | |
| 183 jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem) : elem); | |
| 184 }); | |
| 185 js.JsNative.setProperty(jsObject, key, jsArray); | |
| 186 } else { | |
| 187 js.JsNative.setProperty(jsObject, key, value); | |
| 188 } | |
| 189 }); | |
| 190 return jsObject; | |
| 191 } | |
| 192 | |
| 193 // Creates a Dart class to allow members of the Map to be fetched (as if getters
exist). | |
| 194 // TODO(terry): Need to use package:js but that's a problem in dart:html. Talk t
o | |
| 195 // Jacob about how to do this properly using dart:js. | |
| 196 class _ReturnedDictionary { | |
| 197 Map _values; | |
| 198 | |
| 199 noSuchMethod(Invocation invocation) { | |
| 200 var key = MirrorSystem.getName(invocation.memberName); | |
| 201 if (invocation.isGetter) { | |
| 202 return _values[key]; | |
| 203 } else if (invocation.isSetter && key.endsWith('=')) { | |
| 204 key = key.substring(0, key.length - 1); | |
| 205 _values[key] = invocation.positionalArguments[0]; | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 Map get toMap => _values; | |
| 210 | |
| 211 _ReturnedDictionary(Map value) : _values = value != null ? value : {}; | |
| 212 } | |
| 213 | |
| 214 // Helper function to wrapped a returned dictionary from blink to a Dart looking | |
| 215 // class. | |
| 216 convertNativeDictionaryToDartDictionary(values) { | |
| 217 if (values is! Map) { | |
| 218 // TODO(jacobr): wish wwe didn't have to do this. | |
| 219 values = convertNativeToDart_SerializedScriptValue(values); | |
| 220 } | |
| 221 return values != null ? new _ReturnedDictionary(values) : null; | |
| 222 } | |
| 223 | |
| 224 convertNativeToDart_Dictionary(values) => | |
| 225 convertNativeToDart_SerializedScriptValue(values); | |
| 226 | |
| 227 // Conversion function place holder (currently not used in dart2js or dartium). | |
| 228 List convertDartToNative_StringArray(List<String> input) => input; | |
| 229 | |
| 230 // Converts a Dart list into a JsArray. For the Dartium version only. | |
| 231 convertDartToNative_List(List input) => new js.JsArray()..addAll(input); | |
| 232 | |
| 233 // Incredibly slow implementation to lookup the runtime type for an object. | |
| 234 // Fortunately, performance doesn't matter much as the results are cached | |
| 235 // as long as the object being looked up has a valid prototype. | |
| 236 // TODO(jacobr): we should track the # of lookups to ensure that things aren't | |
| 237 // going off the rails due to objects with null prototypes, etc. | |
| 238 // Note: unlike all other methods in this class, here we intentionally use | |
| 239 // the old JsObject types to bootstrap the new typed bindings. | |
| 240 Type lookupType(js.JsObject jsObject, bool isElement) { | |
| 241 try { | |
| 242 // TODO(jacobr): add static methods that return the runtime type of the patc
h | |
| 243 // class so that this code works as expected. | |
| 244 if (jsObject is js.JsArray) { | |
| 245 return js.JSArray.instanceRuntimeType; | |
| 246 } | |
| 247 if (jsObject is js.JsFunction) { | |
| 248 return js.JSFunction.instanceRuntimeType; | |
| 249 } | |
| 250 | |
| 251 var constructor = js.JsNative.getProperty(jsObject, 'constructor'); | |
| 252 if (constructor == null) { | |
| 253 // Perfectly valid case for JavaScript objects where __proto__ has | |
| 254 // intentionally been set to null. | |
| 255 // We should track and warn about this case as peformance will be poor. | |
| 256 return js.JSObject.instanceRuntimeType; | |
| 257 } | |
| 258 var jsTypeName = js.JsNative.getProperty(constructor, 'name'); | |
| 259 if (jsTypeName is! String || jsTypeName.length == 0) { | |
| 260 // Not an html type. | |
| 261 return js.JSObject.instanceRuntimeType; | |
| 262 } | |
| 263 | |
| 264 var dartClass_instance; | |
| 265 var customElementClass = null; | |
| 266 var extendsTag = ""; | |
| 267 | |
| 268 Type type = getHtmlCreateType(jsTypeName); | |
| 269 if (type != null) return type; | |
| 270 | |
| 271 // Start walking the prototype chain looking for a JS class. | |
| 272 var prototype = js.JsNative.getProperty(jsObject, '__proto__'); | |
| 273 while (prototype != null) { | |
| 274 // We're a Dart class that's pointing to a JS class. | |
| 275 var constructor = js.JsNative.getProperty(prototype, 'constructor'); | |
| 276 if (constructor != null) { | |
| 277 jsTypeName = js.JsNative.getProperty(constructor, 'name'); | |
| 278 type = getHtmlCreateType(jsTypeName); | |
| 279 if (type != null) return type; | |
| 280 } | |
| 281 prototype = js.JsNative.getProperty(prototype, '__proto__'); | |
| 282 } | |
| 283 } catch (e) { | |
| 284 // This case can happen for cross frame objects. | |
| 285 if (js.JsNative.hasProperty(e, "postMessage")) { | |
| 286 // assume this is a Window. To match Dart2JS, separate conversion code | |
| 287 // in dart:html will switch the wrapper to a cross frame window as | |
| 288 // required. | |
| 289 // TODO(jacobr): we could consider removing this code completely. | |
| 290 return Window.instanceRuntimeType; | |
| 291 } | |
| 292 } | |
| 293 return js.JSObject.instanceRuntimeType; | |
| 294 } | |
| OLD | NEW |