OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * The js.dart library provides simple JavaScript invocation from Dart that | 6 * The js.dart library provides simple JavaScript invocation from Dart that |
7 * works on both Dartium and on other modern browsers via Dart2JS. | 7 * works on both Dartium and on other modern browsers via Dart2JS. |
8 * | 8 * |
9 * It provides a model based on scoped [JsObject] objects. Proxies give Dart | 9 * It provides a model based on scoped [JsObject] objects. Proxies give Dart |
10 * code access to JavaScript objects, fields, and functions as well as the | 10 * code access to JavaScript objects, fields, and functions as well as the |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 } | 235 } |
236 } | 236 } |
237 | 237 |
238 /// Marker class used to indicate it is serializable to js. If a class is a | 238 /// Marker class used to indicate it is serializable to js. If a class is a |
239 /// [Serializable] the "toJs" method will be called and the result will be used | 239 /// [Serializable] the "toJs" method will be called and the result will be used |
240 /// as value. | 240 /// as value. |
241 abstract class Serializable<T> { | 241 abstract class Serializable<T> { |
242 T toJs(); | 242 T toJs(); |
243 } | 243 } |
244 | 244 |
245 // A table to managed local Dart objects that are proxied in JavaScript. | 245 // A table to managed local Dart objects that are proxied in JavaScript, |
| 246 // or proxies to JavaScript objects. |
246 class _ProxiedObjectTable { | 247 class _ProxiedObjectTable { |
247 // Debugging name. | 248 // Debugging name. |
248 final String _name; | 249 final String _name; |
249 | 250 |
250 // Generator for unique IDs. | 251 // Generator for unique IDs. |
251 int _nextId; | 252 int _nextId; |
252 | 253 |
253 // Table of IDs to Dart objects. | 254 // Table of IDs to Dart objects. |
254 final Map<String, Object> _registry; | 255 final Map<String, Object> _registry; |
255 | 256 |
(...skipping 20 matching lines...) Expand all Loading... |
276 throw 'Invocation unsupported on non-function Dart proxies'; | 277 throw 'Invocation unsupported on non-function Dart proxies'; |
277 } | 278 } |
278 } catch (e) { | 279 } catch (e) { |
279 // TODO(vsm): callSync should just handle exceptions itself. | 280 // TODO(vsm): callSync should just handle exceptions itself. |
280 return ['throws', '$e']; | 281 return ['throws', '$e']; |
281 } | 282 } |
282 }); | 283 }); |
283 } | 284 } |
284 | 285 |
285 // Adds a new object to the table and return a new ID for it. | 286 // Adds a new object to the table and return a new ID for it. |
286 String add(x) { | 287 String add(x, {String id}) { |
287 // TODO(vsm): Cache x and reuse id. | 288 // TODO(vsm): Cache x and reuse id. |
288 final id = '$_name-${_nextId++}'; | 289 id = (id != null) ? id : '$_name-${_nextId++}'; |
289 _registry[id] = x; | 290 _registry[id] = x; |
290 return id; | 291 return id; |
291 } | 292 } |
292 | 293 |
293 // Gets an object by ID. | 294 // Gets an object by ID. |
294 Object get(String id) { | 295 Object get(String id) { |
295 return _registry[id]; | 296 return _registry[id]; |
296 } | 297 } |
297 | 298 |
298 // Gets the current number of objects kept alive by this table. | 299 // Gets the current number of objects kept alive by this table. |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 } | 341 } |
341 | 342 |
342 _deserialize(var message) { | 343 _deserialize(var message) { |
343 deserializeFunction(message) { | 344 deserializeFunction(message) { |
344 var id = message[1]; | 345 var id = message[1]; |
345 var port = message[2]; | 346 var port = message[2]; |
346 if (port == _proxiedObjectTable.sendPort) { | 347 if (port == _proxiedObjectTable.sendPort) { |
347 // Local function. | 348 // Local function. |
348 return _proxiedObjectTable.get(id); | 349 return _proxiedObjectTable.get(id); |
349 } else { | 350 } else { |
350 // Remote function. Forward to its port. | 351 // Remote function. |
351 return new JsFunction._internal(port, id); | 352 var jsFunction = _proxiedObjectTable.get(id); |
| 353 if (jsFunction == null) { |
| 354 jsFunction = new JsFunction._internal(port, id); |
| 355 _proxiedObjectTable.add(jsFunction, id: id); |
| 356 } |
| 357 return jsFunction; |
352 } | 358 } |
353 } | 359 } |
354 | 360 |
355 deserializeObject(message) { | 361 deserializeObject(message) { |
356 var id = message[1]; | 362 var id = message[1]; |
357 var port = message[2]; | 363 var port = message[2]; |
358 if (port == _proxiedObjectTable.sendPort) { | 364 if (port == _proxiedObjectTable.sendPort) { |
359 // Local object. | 365 // Local object. |
360 return _proxiedObjectTable.get(id); | 366 return _proxiedObjectTable.get(id); |
361 } else { | 367 } else { |
362 // Remote object. | 368 // Remote object. |
363 return new JsObject._internal(port, id); | 369 var jsObject = _proxiedObjectTable.get(id); |
| 370 if (jsObject == null) { |
| 371 jsObject = new JsObject._internal(port, id); |
| 372 _proxiedObjectTable.add(jsObject, id: id); |
| 373 } |
| 374 return jsObject; |
364 } | 375 } |
365 } | 376 } |
366 | 377 |
367 if (message == null) { | 378 if (message == null) { |
368 return null; // Convert undefined to null. | 379 return null; // Convert undefined to null. |
369 } else if (message is String || | 380 } else if (message is String || |
370 message is num || | 381 message is num || |
371 message is bool) { | 382 message is bool) { |
372 // Primitives are passed directly through. | 383 // Primitives are passed directly through. |
373 return message; | 384 return message; |
374 } else if (message is SendPortSync) { | 385 } else if (message is SendPortSync) { |
375 // Serialized type. | 386 // Serialized type. |
376 return message; | 387 return message; |
377 } | 388 } |
378 var tag = message[0]; | 389 var tag = message[0]; |
379 switch (tag) { | 390 switch (tag) { |
380 case 'funcref': return deserializeFunction(message); | 391 case 'funcref': return deserializeFunction(message); |
381 case 'objref': return deserializeObject(message); | 392 case 'objref': return deserializeObject(message); |
382 } | 393 } |
383 throw 'Unsupported serialized data: $message'; | 394 throw 'Unsupported serialized data: $message'; |
384 } | 395 } |
OLD | NEW |