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

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: update cached patches Created 4 years, 8 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() => js.JsNative.newObject();
11 putIntoMap(map, key, value) => map[key] = value; 11 putIntoMap(map, key, value) => js.JsNative.setProperty(map, key, value);
12 // TODO(alanknight): Don't create two extra lists to get a fixed-length JS lis t. 12 newJsList(length) => js.JsNative.newArray()..length = length;
13 newJsList(length) => new js.JsArray.from(new List(length)); 13 cloneNotRequired(e) =>
14 cloneNotRequired(e) => e is js.JsObject; 14 e is js.JSObject || e is TypedData || e is ByteBuffer;
15 } 15 }
16 16
17 /// A version of _AcceptStructuredClone, but using a different algorithm 17 /// A version of _AcceptStructuredClone, but using a different algorithm
18 /// so we can take advantage of an identity HashMap on Dartium without 18 /// so we can take advantage of an identity HashMap on Dartium without
19 /// the bad side-effect of modifying the JS source objects if we do the same in 19 /// the bad side-effect of modifying the JS source objects if we do the same in
20 /// dart2js. 20 /// dart2js.
21 /// 21 ///
22 /// This no longer inherits anything from _AcceptStructuredClone 22 /// This no longer inherits anything from _AcceptStructuredClone
23 /// and is never used polymorphically with it, so it doesn't inherit. 23 /// and is never used polymorphically with it, so it doesn't inherit.
24 class _AcceptStructuredCloneDartium { 24 class _AcceptStructuredCloneDartium {
25 newDartList(length) => new List(length); 25 newDartList(length) => new List(length);
26 26
27 // JsObjects won't be identical, but will be equal only if the underlying 27 // As long as we stick to JSObject instead of intermingling legacy JsObject,
28 // Js entities are identical. 28 // we can simply use identical.
29 bool identicalInJs(a, b) => 29 bool identicalInJs(a, b) => identical(a, b);
30 (a is js.JsObject) ? a == b : identical(a, b);
31 30
32 void forEachJsField(jsObject, action) { 31 void forEachJsField(jsObject, action) {
33 var keys = js.context["Object"].callMethod("keys", [jsObject]); 32 var keys = js.JsNative.callMethod(_object, "keys", [jsObject]);
34 for (var key in keys) { 33 for (var key in keys) {
35 action(key, jsObject[key]); 34 action(key, js.JsNative.getProperty(jsObject, key));
36 } 35 }
37 } 36 }
38 37
39 // Keep track of the clones, keyed by the original object. If we're 38 // Keep track of the clones, keyed by the original object. If we're
40 // not copying, these may be the same. 39 // not copying, these may be the same.
41 var clones = new HashMap.identity(); 40 var clones = new HashMap.identity();
42 bool mustCopy = false; 41 bool mustCopy = false;
43 42
44 Object findSlot(value) { 43 Object findSlot(value) {
45 return clones.putIfAbsent(value, () => null); 44 return clones.putIfAbsent(value, () => null);
46 } 45 }
47 46
48 writeSlot(original, x) { clones[original] = x; } 47 writeSlot(original, x) { clones[original] = x; }
49 48
50 walk(e) { 49 walk(e) {
51 if (e == null) return e; 50 if (e == null) return e;
52 if (e is bool) return e; 51 if (e is bool) return e;
53 if (e is num) return e; 52 if (e is num) return e;
54 if (e is String) return e; 53 if (e is String) return e;
55 54 if (e is DateTime) return e;
56 if (isJavaScriptDate(e)) {
57 return convertNativeToDart_DateTime(e);
58 }
59 55
60 if (isJavaScriptRegExp(e)) { 56 if (isJavaScriptRegExp(e)) {
61 // TODO(sra). 57 // TODO(sra).
62 throw new UnimplementedError('structured clone of RegExp'); 58 throw new UnimplementedError('structured clone of RegExp');
63 } 59 }
64 60
65 if (isJavaScriptPromise(e)) { 61 if (isJavaScriptPromise(e)) {
66 return convertNativePromiseToDartFuture(e); 62 return convertNativePromiseToDartFuture(e);
67 } 63 }
68 64
(...skipping 30 matching lines...) Expand all
99 return e; 95 return e;
100 } 96 }
101 97
102 convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) { 98 convertNativeToDart_AcceptStructuredClone(object, {mustCopy: false}) {
103 this.mustCopy = mustCopy; 99 this.mustCopy = mustCopy;
104 var copy = walk(object); 100 var copy = walk(object);
105 return copy; 101 return copy;
106 } 102 }
107 } 103 }
108 104
109 final _dateConstructor = js.context["Date"]; 105 final _dateConstructor = js.JsNative.getProperty(window, "Date");
110 final _regexConstructor = js.context["RegExp"]; 106 final _regexConstructor = js.JsNative.getProperty(window, "RegExp");
111 107
112 bool isJavaScriptDate(value) => value is js.JsObject && value.instanceof(_dateCo nstructor); 108 bool isJavaScriptDate(value) => value is js.JSObject && js.JsNative.instanceof(v alue, _dateConstructor);
113 bool isJavaScriptRegExp(value) => value is js.JsObject && value.instanceof(_rege xConstructor); 109 bool isJavaScriptRegExp(value) => value is js.JSObject && js.JsNative.instanceof (value, _regexConstructor);
114 bool isJavaScriptArray(value) => value is js.JsArray; 110 bool isJavaScriptArray(value) => value is js.JSArray;
115 111
116 final _object = js.context["Object"]; 112 final _object = js.JsNative.getProperty(window, "Object");
117 final _getPrototypeOf = _object["getPrototypeOf"]; 113 final _getPrototypeOf = js.JsNative.getProperty(_object, "getPrototypeOf");
118 _getProto(object) { 114 _getProto(object) {
119 return _getPrototypeOf.apply([object]); 115 return _getPrototypeOf(object);
120 } 116 }
121 final _objectProto = js.context["Object"]["prototype"]; 117 final _objectProto = js.JsNative.getProperty(_object, "prototype");
122 118
123 bool isJavaScriptSimpleObject(value) { 119 bool isJavaScriptSimpleObject(value) {
124 if (value is! js.JsObject) return false; 120 if (value is! js.JSObject) return false;
125 var proto = _getProto(value); 121 var proto = _getProto(value);
126 return proto == _objectProto || proto == null; 122 return proto == _objectProto || proto == null;
127 } 123 }
124
125 // TODO(jacobr): this makes little sense unless we are doing something
126 // ambitious to make Dartium and Dart2Js interop well with each other.
128 bool isImmutableJavaScriptArray(value) => 127 bool isImmutableJavaScriptArray(value) =>
129 isJavaScriptArray(value) && value["immutable$list"] != null; 128 isJavaScriptArray(value) && js.JsNative.getProperty(value, "immutable$list") != null;
130 129
131 final _promiseConstructor = js.context['Promise']; 130 final _promiseConstructor = js.JsNative.getProperty(window, 'Promise');
132 bool isJavaScriptPromise(value) => value is js.JsObject && value['constructor'] == _promiseConstructor; 131 bool isJavaScriptPromise(value) => value is js.JSObject && identical(js.JsNative .getProperty(value, 'constructor'), _promiseConstructor);
133 132
134 Future convertNativePromiseToDartFuture(js.JsObject promise) { 133 Future convertNativePromiseToDartFuture(js.JSObject promise) {
135 var completer = new Completer(); 134 var completer = new Completer();
136 var newPromise = promise 135 var newPromise = js.JsNative.callMethod(js.JsNative.callMethod(promise,
137 .callMethod("then", [(result) => completer.complete(result)]) 136 "then", [js.allowInterop((result) => completer.complete(result))]),
138 .callMethod("catch", [(result) => completer.completeError(result)]); 137 "catch", [js.allowInterop((result) => completer.completeError(result))]);
139 return completer.future; 138 return completer.future;
140 } 139 }
141 140
142 convertDartToNative_DateTime(DateTime date) { 141 convertDartToNative_DateTime(DateTime date) {
143 return new js.JsObject(js.context["Date"], [date.millisecondsSinceEpoch]); 142 return date;
144 } 143 }
145 144
146 /// Creates a Dart Rectangle from a Javascript object with properties 145 /// Creates a Dart Rectangle from a Javascript object with properties
147 /// left, top, width and height. Used internally in Dartium. 146 /// left, top, width and height or a 4 element array of integers. Used internall y in Dartium.
148 Rectangle make_dart_rectangle(r) => 147 Rectangle make_dart_rectangle(r) {
149 r == null ? null : new Rectangle( 148 if (r == null) return null;
150 js.JsNative.getProperty(r, 'left'), 149 if (r is List) {
151 js.JsNative.getProperty(r, 'top'), 150 return new Rectangle(r[0], r[1], r[2], r[3]);
152 js.JsNative.getProperty(r, 'width'), 151 }
153 js.JsNative.getProperty(r, 'height')); 152
153 return new Rectangle(
154 js.JsNative.getProperty(r, 'left'),
155 js.JsNative.getProperty(r, 'top'),
156 js.JsNative.getProperty(r, 'width'),
157 js.JsNative.getProperty(r, 'height'));
158 }
154 159
155 // Converts a flat Dart map into a JavaScript object with properties this is 160 // Converts a flat Dart map into a JavaScript object with properties this is
156 // is the Dartium only version it uses dart:js. 161 // is the Dartium only version it uses dart:js.
157 // TODO(alanknight): This could probably be unified with the dart2js conversions 162 // TODO(alanknight): This could probably be unified with the dart2js conversions
158 // code in html_common and be more general. 163 // code in html_common and be more general.
159 convertDartToNative_Dictionary(Map dict) { 164 convertDartToNative_Dictionary(Map dict) {
160 if (dict == null) return null; 165 if (dict == null) return null;
161 var jsObject = new js.JsObject(js.JsNative.getProperty(js.context, 'Object')); 166 var jsObject = js.JsNative.newObject();
162 dict.forEach((String key, value) { 167 dict.forEach((String key, value) {
163 if (value is List) { 168 if (value is List) {
164 var jsArray = new js.JsArray(); 169 var jsArray = js.JsNative.newArray();
165 value.forEach((elem) { 170 value.forEach((elem) {
166 jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem); 171 jsArray.add(elem is Map ? convertDartToNative_Dictionary(elem): elem);
167 }); 172 });
168 jsObject[key] = jsArray; 173 js.JsNative.setProperty(jsObject, key, jsArray);
169 } else { 174 } else {
170 jsObject[key] = value; 175 js.JsNative.setProperty(jsObject, key, value);
171 } 176 }
172 }); 177 });
173 return jsObject; 178 return jsObject;
174 } 179 }
175 180
176 // Creates a Dart class to allow members of the Map to be fetched (as if getters exist). 181 // Creates a Dart class to allow members of the Map to be fetched (as if getters exist).
177 // TODO(terry): Need to use package:js but that's a problem in dart:html. Talk t o 182 // TODO(terry): Need to use package:js but that's a problem in dart:html. Talk t o
178 // Jacob about how to do this properly using dart:js. 183 // Jacob about how to do this properly using dart:js.
179 class _ReturnedDictionary { 184 class _ReturnedDictionary {
180 Map _values; 185 Map _values;
181 186
182 noSuchMethod(Invocation invocation) { 187 noSuchMethod(Invocation invocation) {
183 var key = MirrorSystem.getName(invocation.memberName); 188 var key = MirrorSystem.getName(invocation.memberName);
184 if (invocation.isGetter) { 189 if (invocation.isGetter) {
185 return _values[key]; 190 return _values[key];
186 } else if (invocation.isSetter && key.endsWith('=')) { 191 } else if (invocation.isSetter && key.endsWith('=')) {
187 key = key.substring(0, key.length-1); 192 key = key.substring(0, key.length-1);
188 _values[key] = invocation.positionalArguments[0]; 193 _values[key] = invocation.positionalArguments[0];
189 } 194 }
190 } 195 }
191 196
192 Map get toMap => _values; 197 Map get toMap => _values;
193 198
194 _ReturnedDictionary(Map value): _values = value != null ? value : {}; 199 _ReturnedDictionary(Map value): _values = value != null ? value : {};
195 } 200 }
196 201
197 // Helper function to wrapped a returned dictionary from blink to a Dart looking 202 // Helper function to wrapped a returned dictionary from blink to a Dart looking
198 // class. 203 // class.
199 convertNativeDictionaryToDartDictionary(Map values) => 204 convertNativeDictionaryToDartDictionary(values) {
200 values != null ? new _ReturnedDictionary(values) : null; 205 if (values is! Map) {
206 // TODO(jacobr): wish wwe didn't have to do this.
207 values = convertNativeToDart_SerializedScriptValue(values);
208 }
209 return values != null ? new _ReturnedDictionary(values) : null;
210 }
211
212 convertNativeToDart_Dictionary(values) => convertNativeToDart_SerializedScriptVa lue(values);
201 213
202 // Conversion function place holder (currently not used in dart2js or dartium). 214 // Conversion function place holder (currently not used in dart2js or dartium).
203 List convertDartToNative_StringArray(List<String> input) => input; 215 List convertDartToNative_StringArray(List<String> input) => input;
204 216
205 // Converts a Dart list into a JsArray. For the Dartium version only. 217 // Converts a Dart list into a JsArray. For the Dartium version only.
206 convertDartToNative_List(List input) => new js.JsArray()..addAll(input); 218 convertDartToNative_List(List input) => new js.JsArray()..addAll(input);
207 219
208 /// Find the underlying JS object for a dart:html Dart object. 220 // Incredibly slow implementation to lookup the runtime type for an object.
209 unwrap_jso(dartClass_instance) => js.unwrap_jso(dartClass_instance); 221 // Fortunately, performance doesn't matter much as the results are cached
210 222 // 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 223 // TODO(jacobr): we should track the # of lookups to ensure that things aren't
212 // wrap_jso calls. 224 // going off the rails due to objects with null prototypes, etc.
213 bool interop_checks = false; 225 // Note: unlike all other methods in this class, here we intentionally use
214 226 // the old JsObject types to bootstrap the new typed bindings.
215 /// Wrap a JS object with an instance of the matching dart:html class. Used only in Dartium. 227 Type lookupType(js.JsObject jsObject, bool isElement) {
216 wrap_jso(jsObject) {
217 try { 228 try {
218 if (jsObject is! js.JsObject || jsObject == null) { 229 // 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. 230 // class so that this code works as expected.
220 // or it's a simple type. 231 if (jsObject is js.JsArray) {
221 return jsObject; 232 return js.JSArray.instanceRuntimeType;
222 } 233 }
223 234 if (jsObject is js.JsFunction) {
224 var wrapper = js.getDartHtmlWrapperFor(jsObject); 235 return js.JSFunction.instanceRuntimeType;
225 // if we have a wrapper return the Dart instance. 236 }
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 237
250 var constructor = js.JsNative.getProperty(jsObject, 'constructor'); 238 var constructor = js.JsNative.getProperty(jsObject, 'constructor');
251 if (constructor == null) { 239 if (constructor == null) {
252 // Perfectly valid case for JavaScript objects where __proto__ has 240 // Perfectly valid case for JavaScript objects where __proto__ has
253 // intentionally been set to null. 241 // intentionally been set to null.
254 js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject)); 242 // We should track and warn about this case as peformance will be poor.
255 return jsObject; 243 return js.JSObject.instanceRuntimeType;
256 } 244 }
257 var jsTypeName = js.JsNative.getProperty(constructor, 'name'); 245 var jsTypeName = js.JsNative.getProperty(constructor, 'name');
258 if (jsTypeName is! String || jsTypeName.length == 0) { 246 if (jsTypeName is! String || jsTypeName.length == 0) {
259 // Not an html type. 247 // Not an html type.
260 wrapper = new js.JSObject.create(jsObject); 248 return js.JSObject.instanceRuntimeType;
261 js.setDartHtmlWrapperFor(jsObject, wrapper);
262 return wrapper;
263 } 249 }
264 250
265 var dartClass_instance; 251 var dartClass_instance;
266 var customElementClass = null; 252 var customElementClass = null;
267 var extendsTag = ""; 253 var extendsTag = "";
268 var custom = getCustomElementEntry(jsObject); 254
269 if (custom != null) { 255 Type type = getHtmlCreateType(jsTypeName);
270 customElementClass = custom['type']; 256 if (type != null) return type;
271 extendsTag = custom['extends']; 257
258 // Start walking the prototype chain looking for a JS class.
259 var prototype = js.JsNative.getProperty(jsObject, '__proto__');
260 while (prototype != null) {
261 // We're a Dart class that's pointing to a JS class.
262 var constructor = js.JsNative.getProperty(prototype, 'constructor');
263 if (constructor != null) {
264 jsTypeName = js.JsNative.getProperty(constructor, 'name');
265 type = getHtmlCreateType(jsTypeName);
266 if (type != null) return type;
267 }
268 prototype = js.JsNative.getProperty(prototype, '__proto__');
272 } 269 }
273
274 // Only allow custom elements to be created in the html or svg default
275 // namespace.
276 var func;
277 var defaultNS = jsObject['namespaceURI'] == 'http://www.w3.org/1999/xhtml' | |
278 jsObject['namespaceURI'] == 'http://www.w3.org/2000/svg';
279 if (customElementClass != null && extendsTag == "" && defaultNS) {
280 // 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
282 // createdCallback is called.
283 func = getHtmlCreateFunction('HTMLElement');
284 } else {
285 func = getHtmlCreateFunction(jsTypeName);
286 if (func == null) {
287 // Start walking the prototype chain looking for a JS class.
288 var prototype = jsObject['__proto__'];
289 var keepWalking = true;
290 while (keepWalking && prototype.hasProperty('__proto__')) {
291 prototype = prototype['__proto__'];
292 if (prototype != null && prototype is Element &&
293 prototype.blink_jsObject != null) {
294 // We're a Dart class that's pointing to a JS class.
295 var blinkJso = prototype.blink_jsObject;
296 jsTypeName = blinkJso['constructor']['name'];
297 func = getHtmlCreateFunction(jsTypeName);
298 keepWalking = func == null;
299 }
300 }
301 }
302 }
303
304 // Can we construct a Dart class?
305 if (func != null) {
306 dartClass_instance = func();
307
308 // Wrap our Dart instance in both directions.
309 dartClass_instance.blink_jsObject = jsObject;
310 js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
311 }
312
313 // TODO(jacobr): cache that this is not a dart:html JS class.
314 return dartClass_instance;
315 } catch (e, stacktrace) { 270 } catch (e, stacktrace) {
316 if (interop_checks) { 271 if (e is DebugAssertException) print("${e.message}\n ${stacktrace}");
317 if (e is DebugAssertException) window.console 272 else print("${stacktrace}");
318 .log("${e.message}\n ${stacktrace}");
319 else window.console.log("${stacktrace}");
320 }
321 } 273 }
322 274 return js.JSObject.instanceRuntimeType;
323 return null;
324 } 275 }
325
326 /**
327 * Create Dart class that maps to the JS Type, add the JsObject as an expando
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
338 // TODO(alanknight): With upgraded custom elements this causes a failure bec ause
339 // we need a new wrapper after the type changes. We could possibly invalidat e this
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 }
473
474 // List of known tagName to DartClass for custom elements, used for upgrade.
475 var _knownCustomElements = new Map<String, Map<Type, String>>();
476
477 void addCustomElementType(String tagName, Type dartClass, [String extendTag]) {
478 _knownCustomElements[tagName] =
479 {'type': dartClass, 'extends': extendTag != null ? extendTag : "" };
480 }
481
482 Type getCustomElementType(object) {
483 var entry = getCustomElementEntry(object);
484 if (entry != null) {
485 return entry['type'];
486 }
487 return null;
488 }
OLDNEW
« no previous file with comments | « sdk/lib/html/html_common/conversions_dart2js.dart ('k') | sdk/lib/indexed_db/dartium/indexed_db_dartium.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698