Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(300)

Side by Side Diff: sdk/lib/html/html_common/conversions_dartium.dart

Issue 1832713002: Optimize dartium dart:html bindings so real world application performance is acceptable. Improves d… (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 part of html_common; 1 part of html_common;
2 2
3 convertDartToNative_PrepareForStructuredClone(value) => 3 convertDartToNative_PrepareForStructuredClone(value) =>
4 new _StructuredCloneDartium().convertDartToNative_PrepareForStructuredClone( value); 4 new _StructuredCloneDartium().convertDartToNative_PrepareForStructuredClone( value);
5 5
6 convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) => 6 convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) =>
7 new _AcceptStructuredCloneDartium().convertNativeToDart_AcceptStructuredClon e(object, mustCopy: mustCopy); 7 new _AcceptStructuredCloneDartium().convertNativeToDart_AcceptStructuredClon e(object, mustCopy: mustCopy);
8 8
9 class _StructuredCloneDartium extends _StructuredClone { 9 class _StructuredCloneDartium extends _StructuredClone {
10 newJsMap() => new js.JsObject(js.context["Object"]); 10 newJsMap() => new js.JsObject(js.context["Object"]);
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 133
134 Future convertNativePromiseToDartFuture(js.JsObject promise) { 134 Future convertNativePromiseToDartFuture(js.JsObject promise) {
135 var completer = new Completer(); 135 var completer = new Completer();
136 var newPromise = promise 136 var newPromise = promise
137 .callMethod("then", [(result) => completer.complete(result)]) 137 .callMethod("then", [(result) => completer.complete(result)])
138 .callMethod("catch", [(result) => completer.completeError(result)]); 138 .callMethod("catch", [(result) => completer.completeError(result)]);
139 return completer.future; 139 return completer.future;
140 } 140 }
141 141
142 convertDartToNative_DateTime(DateTime date) { 142 convertDartToNative_DateTime(DateTime date) {
143 return new js.JsObject(js.context["Date"], [date.millisecondsSinceEpoch]); 143 return date; // TODO(jacobr): I don't get why this is needed. new js.JsObject( js.context["Date"], [date.millisecondsSinceEpoch]);
Alan Knight 2016/03/25 21:39:09 There will be explicit calls to it from conversion
Jacob 2016/03/30 00:19:00 Removed. This is already done in Dartium C++
144 } 144 }
145 145
146 /// Creates a Dart Rectangle from a Javascript object with properties 146 /// Creates a Dart Rectangle from a Javascript object with properties
147 /// left, top, width and height. Used internally in Dartium. 147 /// left, top, width and height or a 4 element array of integers. Used internall y in Dartium.
148 Rectangle make_dart_rectangle(r) => 148 Rectangle make_dart_rectangle(r) {
149 r == null ? null : new Rectangle( 149 if (r == null) return null;
150 js.JsNative.getProperty(r, 'left'), 150 if (r is List) {
151 js.JsNative.getProperty(r, 'top'), 151 return new Rectangle(r[0], r[1], r[2], r[3]);
152 js.JsNative.getProperty(r, 'width'), 152 }
153 js.JsNative.getProperty(r, 'height')); 153
154 return new Rectangle(
155 js.JsNative.getProperty(r, 'left'),
156 js.JsNative.getProperty(r, 'top'),
157 js.JsNative.getProperty(r, 'width'),
158 js.JsNative.getProperty(r, 'height'));
159 }
154 160
155 // Converts a flat Dart map into a JavaScript object with properties this is 161 // Converts a flat Dart map into a JavaScript object with properties this is
156 // is the Dartium only version it uses dart:js. 162 // is the Dartium only version it uses dart:js.
157 // TODO(alanknight): This could probably be unified with the dart2js conversions 163 // TODO(alanknight): This could probably be unified with the dart2js conversions
158 // code in html_common and be more general. 164 // code in html_common and be more general.
159 convertDartToNative_Dictionary(Map dict) { 165 convertDartToNative_Dictionary(Map dict) {
160 if (dict == null) return null; 166 if (dict == null) return null;
161 var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object')); 167 var jsObject = new js.JsObject(js.context['Object']);
162 dict.forEach((String key, value) { 168 dict.forEach((String key, value) {
163 if (value is List) { 169 if (value is List) {
164 var jsArray = new js.JsArray(); 170 var jsArray = new js.JsArray();
165 value.forEach((elem) { 171 value.forEach((elem) {
166 jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem); 172 jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem);
167 }); 173 });
168 jsObject[key] = jsArray; 174 jsObject[key] = jsArray;
169 } else { 175 } else {
170 jsObject[key] = value; 176 jsObject[key] = value;
171 } 177 }
(...skipping 26 matching lines...) Expand all
198 // class. 204 // class.
199 convertNativeDictionaryToDartDictionary(Map values) => 205 convertNativeDictionaryToDartDictionary(Map values) =>
200 values != null ? new _ReturnedDictionary(values) : null; 206 values != null ? new _ReturnedDictionary(values) : null;
201 207
202 // Conversion function place holder (currently not used in dart2js or dartium). 208 // Conversion function place holder (currently not used in dart2js or dartium).
203 List convertDartToNative_StringArray(List<String> input) => input; 209 List convertDartToNative_StringArray(List<String> input) => input;
204 210
205 // Converts a Dart list into a JsArray. For the Dartium version only. 211 // Converts a Dart list into a JsArray. For the Dartium version only.
206 convertDartToNative_List(List input) => new js.JsArray()..addAll(input); 212 convertDartToNative_List(List input) => new js.JsArray()..addAll(input);
207 213
208 /// Find the underlying JS object for a dart:html Dart object. 214 // Incredibly slow implementation to lookup the runtime type for an object.
209 unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance); 215 // Fortunately, performance doesn't matter much as the results are cached
210 216 // as long as the object being looked up has a valid prototype.
211 // Flag to disable JS interop asserts. Setting to false will speed up the 217 // TODO(jacobr): we should track the # of lookups to ensure that things aren't
212 // wrap_jso calls. 218 // going off the rails due to objects with null prototypes, etc.
213 bool interop_checks = false; 219 Type lookupType(js.JsObject jsObject) {
Alan Knight 2016/03/25 21:39:09 Will probably break if we have JS objects that sha
Jacob 2016/03/30 00:19:00 Yep. But there is no cost of failing in the same p
214
215 /// Wrap a JS object with an instance of the matching dart:html class. Used only in Dartium.
216 wrap_jso(jsObject) {
217 try { 220 try {
218 if (jsObject is! js.JsObject || jsObject == null) { 221 // TODO(jacobr): add static methods that return the runtime type of the patch
219 // JS Interop converted the object to a Dart class e.g., Uint8ClampedList. 222 // class so that this code works as expected.
220 // or it's a simple type. 223 if (jsObject is js.JsArray) {
221 return jsObject; 224 return js.JSArray.instanceRuntimeType;
222 } 225 }
223 226 if (jsObject is js.JsFunction) {
224 var wrapper = js.getDartHtmlWrapperFor(jsObject); 227 return js.JSFunction.instanceRuntimeType;
225 // if we have a wrapper return the Dart instance. 228 }
226 if (wrapper != null) {
227 return wrapper;
228 }
229
230 if (jsObject is js.JsArray) {
231 wrapper = new js.JSArray.create(jsObject);
232 js.setDartHtmlWrapperFor(jsObject, wrapper);
233 return wrapper;
234 }
235 if (jsObject is js.JsFunction) {
236 wrapper = new js.JSFunction.create(jsObject);
237 js.setDartHtmlWrapperFor(jsObject, wrapper);
238 return wrapper;
239 }
240
241 // Try the most general type conversions on it.
242 // TODO(alanknight): We may be able to do better. This maintains identity,
243 // which is useful, but expensive. And if we nest something that only
244 // this conversion handles, how does that work? e.g. a list of maps of eleme nts.
245 var converted = convertNativeToDart_SerializedScriptValue(jsObject);
246 if (!identical(converted, jsObject)) {
247 return converted;
248 }
249 229
250 var constructor = js.JsNative.getProperty(jsObject, 'constructor'); 230 var constructor = js.JsNative.getProperty(jsObject, 'constructor');
251 if (constructor == null) { 231 if (constructor == null) {
252 // Perfectly valid case for JavaScript objects where __proto__ has 232 // Perfectly valid case for JavaScript objects where __proto__ has
253 // intentionally been set to null. 233 // intentionally been set to null.
254 js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject)); 234 // We should track and warn about this case as peformance will be poor.
255 return jsObject; 235 return js.JSObject.instanceRuntimeType;
256 } 236 }
257 var jsTypeName = js.JsNative.getProperty(constructor, 'name'); 237 var jsTypeName = js.JsNative.getProperty(constructor, 'name');
258 if (jsTypeName is! String || jsTypeName.length == 0) { 238 if (jsTypeName is! String || jsTypeName.length == 0) {
259 // Not an html type. 239 // Not an html type.
260 wrapper = new js.JSObject.create(jsObject); 240 return js.JSObject.instanceRuntimeType;
261 js.setDartHtmlWrapperFor(jsObject, wrapper);
262 return wrapper;
263 } 241 }
264 242
265 var dartClass_instance; 243 var dartClass_instance;
266 var customElementClass = null; 244 var customElementClass = null;
267 var extendsTag = ""; 245 var extendsTag = "";
268 var custom = getCustomElementEntry(jsObject); 246 var custom = getCustomElementEntry(jsObject);
269 if (custom != null) { 247 if (custom != null) {
270 customElementClass = custom['type']; 248 customElementClass = custom['type'];
271 extendsTag = custom['extends']; 249 extendsTag = custom['extends'];
272 } 250 }
273 251
274 // Only allow custom elements to be created in the html or svg default 252 // Only allow custom elements to be created in the html or svg default
275 // namespace. 253 // namespace.
276 var func; 254 var func;
277 var defaultNS = jsObject['namespaceURI'] == 'http://www.w3.org/1999/xhtml' | | 255 var defaultNS = jsObject['namespaceURI'] == 'http://www.w3.org/1999/xhtml' | |
278 jsObject['namespaceURI'] == 'http://www.w3.org/2000/svg'; 256 jsObject['namespaceURI'] == 'http://www.w3.org/2000/svg';
279 if (customElementClass != null && extendsTag == "" && defaultNS) { 257 if (customElementClass != null && extendsTag == "" && defaultNS) {
280 // The customElementClass is known but we can't create the real class so 258 // The customElementClass is known but we can't create the real class so
281 // create the HtmlElement and it will get upgraded when registerElement's 259 // create the HtmlElement and it will get upgraded when registerElement's
282 // createdCallback is called. 260 // createdCallback is called.
283 func = getHtmlCreateFunction('HTMLElement'); 261 func = getHtmlCreateFunction('HTMLElement');
284 } else { 262 } else {
285 func = getHtmlCreateFunction(jsTypeName); 263 func = getHtmlCreateFunction(jsTypeName);
286 if (func == null) { 264 if (func == null) {
287 // Start walking the prototype chain looking for a JS class. 265 // Start walking the prototype chain looking for a JS class.
288 var prototype = jsObject['__proto__']; 266 var prototype = jsObject['__proto__'];
289 var keepWalking = true; 267 while (prototype != null && prototype.hasProperty('__proto__')) {
290 while (keepWalking && prototype.hasProperty('__proto__')) {
291 prototype = prototype['__proto__']; 268 prototype = prototype['__proto__'];
292 if (prototype != null && prototype is Element && 269 // XXX FIX this... we are hosed if we hit a not JS class
293 prototype.blink_jsObject != null) { 270 // so this makes little sense.
294 // We're a Dart class that's pointing to a JS class. 271 if (prototype is! js.JsObject) break;
295 var blinkJso = prototype.blink_jsObject; 272
296 jsTypeName = blinkJso['constructor']['name']; 273 // We're a Dart class that's pointing to a JS class.
274 var constructor = prototype['constructor'];
275 if (constructor is js.JsObject) {
276 jsTypeName = constructor['name'];
297 func = getHtmlCreateFunction(jsTypeName); 277 func = getHtmlCreateFunction(jsTypeName);
298 keepWalking = func == null; 278 if (func != null) break;
299 } 279 }
300 } 280 }
301 } 281 }
302 } 282 }
303 283
304 // Can we construct a Dart class? 284 // Can we construct a Dart class?
305 if (func != null) { 285 if (func != null) {
306 dartClass_instance = func(); 286 var ret = func().runtimeType;
287 return ret;
288 }
289 } catch (e, stacktrace) {
290 if (e is DebugAssertException) print("${e.message}\n ${stacktrace}");
291 else print("${stacktrace}");
292 }
293 return js.JSObject.instanceRuntimeType;
294 }
307 295
308 // Wrap our Dart instance in both directions. 296 CustomElementEntry getCustomElementEntry(element) {
309 dartClass_instance.blink_jsObject = jsObject; 297 var hasAttribute = false;
310 js.setDartHtmlWrapperFor(jsObject, dartClass_instance); 298
299 var jsObject;
300 var tag;
301
302 // It's a Polymer core element (written in JS).
303 // Make sure it's an element anything else we can ignore.
304 if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
305 if (js.JsNative.callMethod(element, 'hasAttribute', ['is'])) {
306 hasAttribute = true;
307 // It's data binding use the is attribute.
308 tag = js.JsNative.callMethod(element, 'getAttribute', ['is']);
309 } else {
310 // It's a custom element we want the local name.
311 tag = js.JsNative.getProperty(element, 'localName');
311 } 312 }
313 }
312 314
313 // TODO(jacobr): cache that this is not a dart:html JS class. 315 // TODO: handle template element case? I think it is handled by is, etc.
314 return dartClass_instance; 316 if (tag != null) {
315 } catch (e, stacktrace) { 317 CustomElementEntry entry = _knownCustomElements[tag];
316 if (interop_checks) { 318 if (entry != null) {
317 if (e is DebugAssertException) window.console 319 // If there's an 'is' attribute then check if the extends tag registered
318 .log("${e.message}\n ${stacktrace}"); 320 // matches the tag if so then return the entry that's registered for this
319 else window.console.log("${stacktrace}"); 321 // extendsTag or if there's no 'is' tag then return the entry found.
322 if ((hasAttribute && entry.extendTag == tag) || !hasAttribute) {
323 return entry;
324 }
320 } 325 }
321 } 326 }
322 327
323 return null; 328 return null;
324 } 329 }
325 330
326 /** 331 class CustomElementEntry {
327 * Create Dart class that maps to the JS Type, add the JsObject as an expando 332 CustomElementEntry({this.type, this.extendTag});
328 * on the Dart class and return the created Dart class.
329 */
330 wrap_jso_no_SerializedScriptvalue(jsObject) {
331 try {
332 if (jsObject is! js.JsObject || jsObject == null) {
333 // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
334 // or it's a simple type.
335 return jsObject;
336 }
337 333
338 // TODO(alanknight): With upgraded custom elements this causes a failure bec ause 334 final Type type;
339 // we need a new wrapper after the type changes. We could possibly invalidat e this 335 final String extendTag;
340 // if the constructor name didn't match?
341 var wrapper = js.getDartHtmlWrapperFor(jsObject);
342 if (wrapper != null) {
343 return wrapper;
344 }
345
346 if (jsObject is js.JsArray) {
347 wrapper = new js.JSArray.create(jsObject);
348 js.setDartHtmlWrapperFor(jsObject, wrapper);
349 return wrapper;
350 }
351 if (jsObject is js.JsFunction) {
352 wrapper = new js.JSFunction.create(jsObject);
353 js.setDartHtmlWrapperFor(jsObject, wrapper);
354 return wrapper;
355 }
356
357 var constructor = js.JsNative.getProperty(jsObject, 'constructor');
358 if (constructor == null) {
359 // Perfectly valid case for JavaScript objects where __proto__ has
360 // intentionally been set to null.
361 js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject));
362 return jsObject;
363 }
364 var jsTypeName = js.JsNative.getProperty(constructor, 'name');
365 if (jsTypeName is! String || jsTypeName.length == 0) {
366 // Not an html type.
367 wrapper = new js.JSObject.create(jsObject);
368 js.setDartHtmlWrapperFor(jsObject, wrapper);
369 return wrapper;
370 }
371
372 var func = getHtmlCreateFunction(jsTypeName);
373 if (func != null) {
374 var dartClass_instance = func();
375 dartClass_instance.blink_jsObject = jsObject;
376 js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
377 return dartClass_instance;
378 }
379 wrapper = new js.JSObject.create(jsObject);
380 js.setDartHtmlWrapperFor(jsObject, wrapper);
381 return wrapper;
382 } catch (e, stacktrace) {
383 if (interop_checks) {
384 if (e is DebugAssertException) window.console
385 .log("${e.message}\n ${stacktrace}");
386 else window.console.log("${stacktrace}");
387 }
388 }
389
390 return null;
391 }
392
393 /**
394 * Create Dart class that maps to the JS Type that is the JS type being
395 * extended using JS interop createCallback (we need the base type of the
396 * custom element) not the Dart created constructor.
397 */
398 wrap_jso_custom_element(jsObject) {
399 try {
400 if (jsObject is! js.JsObject) {
401 // JS Interop converted the object to a Dart class e.g., Uint8ClampedList.
402 return jsObject;
403 }
404
405 // Find out what object we're extending.
406 var objectName = jsObject.toString();
407 // Expect to see something like '[object HTMLElement]'.
408 if (!objectName.startsWith('[object ')) {
409 return jsObject;
410 }
411
412 var extendsClass = objectName.substring(8, objectName.length - 1);
413 var func = getHtmlCreateFunction(extendsClass);
414 if (interop_checks)
415 debug_or_assert("func != null name = ${extendsClass}", func != null);
416 var dartClass_instance = func();
417 dartClass_instance.blink_jsObject = jsObject;
418 return dartClass_instance;
419 } catch(e, stacktrace){
420 if (interop_checks) {
421 if (e is DebugAssertException)
422 window.console.log("${e.message}\n ${stacktrace}");
423 else
424 window.console.log("${stacktrace}");
425 }
426
427 // Problem?
428 return null;
429 }
430 }
431
432 getCustomElementEntry(element) {
433 var hasAttribute = false;
434
435 var jsObject;
436 var tag = "";
437 var runtimeType = element.runtimeType;
438 if (runtimeType == HtmlElement) {
439 tag = element.localName;
440 } else if (runtimeType == TemplateElement) {
441 // Data binding with a Dart class.
442 tag = element.attributes['is'];
443 } else if (runtimeType == js.JsObject) {
444 // It's a Polymer core element (written in JS).
445 // Make sure it's an element anything else we can ignore.
446 if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
447 if (js.JsNative.callMethod(element, 'hasAttribute', ['is'])) {
448 hasAttribute = true;
449 // It's data binding use the is attribute.
450 tag = js.JsNative.callMethod(element, 'getAttribute', ['is']);
451 } else {
452 // It's a custom element we want the local name.
453 tag = element['localName'];
454 }
455 }
456 } else {
457 throw new UnsupportedError(
458 'Element is incorrect type. Got ${runtimeType}, expected HtmlElement/Htm lTemplate/JsObject.');
459 }
460
461 var entry = _knownCustomElements[tag];
462 if (entry != null) {
463 // If there's an 'is' attribute then check if the extends tag registered
464 // matches the tag if so then return the entry that's registered for this
465 // extendsTag or if there's no 'is' tag then return the entry found.
466 if ((hasAttribute && entry['extends'] == tag) || !hasAttribute) {
467 return entry;
468 }
469 }
470
471 return null;
472 } 336 }
473 337
474 // List of known tagName to DartClass for custom elements, used for upgrade. 338 // List of known tagName to DartClass for custom elements, used for upgrade.
475 var _knownCustomElements = new Map<String, Map<Type, String>>(); 339 var _knownCustomElements = new Map<String, CustomElementEntry>();
476 340
477 void addCustomElementType(String tagName, Type dartClass, [String extendTag]) { 341 void addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
478 _knownCustomElements[tagName] = 342 _knownCustomElements[tagName] =
479 {'type': dartClass, 'extends': extendTag != null ? extendTag : "" }; 343 new CustomElementEntry(type: dartClass, extendTag: extendTag != null ? ext endTag : "");
480 } 344 }
481 345
482 Type getCustomElementType(object) { 346 Type getCustomElementType(object) {
483 var entry = getCustomElementEntry(object); 347 var entry = getCustomElementEntry(object);
484 if (entry != null) { 348 if (entry != null) {
485 return entry['type']; 349 return entry.type;
486 } 350 }
487 return null; 351 return null;
488 } 352 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698