Index: lib/html/dartium/html_dartium.dart |
diff --git a/lib/html/dartium/html_dartium.dart b/lib/html/dartium/html_dartium.dart |
index eac0ae22ccee02b3d2ba7c73fa0cf545e112f2e3..83399e6ef863312323c44c1e948ee8471e55a62a 100644 |
--- a/lib/html/dartium/html_dartium.dart |
+++ b/lib/html/dartium/html_dartium.dart |
@@ -1,6 +1,7 @@ |
#library('html'); |
#import('dart:isolate'); |
+#import('dart:json'); |
#import('dart:nativewrappers'); |
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
// for details. All rights reserved. Use of this source code is governed by a |
@@ -48,6 +49,58 @@ class _Null { |
final _null = const _Null(); |
+// TODO(vsm): Move this to a separate Isolates.dart file. |
+_serialize(var message) { |
+ // TODO(kasperl): Specialize the serializer. |
+ return new _Serializer().traverse(message); |
+} |
+ |
+_deserialize(var message) { |
+ return new _JsDeserializer().deserialize(message); |
+} |
+ |
+class _JsDeserializer extends _Deserializer { |
+ |
+ deserializeSendPort(List x) { |
+ num id = x[1]; |
+ return new _JsSendPortSync(id); |
+ } |
+ |
+} |
+ |
+class _JsSendPortSync implements SendPortSync { |
+ |
+ static bool initialized = false; |
+ static var lastResult = null; |
+ |
+ num _id; |
+ _JsSendPortSync(this._id) { |
+ if (initialized) return; |
+ window.on['js-result'].add((event) { |
+ lastResult = JSON.parse(event.data); |
+ }, false); |
+ initialized = true; |
+ } |
+ |
+ callSync(var message) { |
+ var serialized = _serialize(message); |
+ var result = _callUsingEvent(_id, serialized); |
+ return _deserialize(result); |
+ } |
+ |
+ static _callUsingEvent(num id, var message) { |
+ var data = JSON.stringify({ 'id': id, 'message': message }); |
+ var event = document.$dom_createEvent('TextEvent'); |
+ event.initTextEvent('js-sync-message', false, false, window, data); |
+ assert(lastResult == null); |
+ window.$dom_dispatchEvent(event); |
+ var result = lastResult; |
+ lastResult = null; |
+ return result; |
+ } |
+ |
+} |
+ |
class _AbstractWorkerEventsImpl extends _EventsImpl implements AbstractWorkerEvents { |
_AbstractWorkerEventsImpl(_ptr) : super(_ptr); |
@@ -5152,6 +5205,12 @@ class _DOMWindowImpl extends _EventTargetImpl implements Window { |
IDBFactory get indexedDB() => webkitIndexedDB; |
+ // TODO(kasperl): Document this. |
+ lookupPort(String name) { |
+ var port = JSON.parse(localStorage['dart-port:$name']); |
+ return _deserialize(port); |
+ } |
+ |
_WindowEventsImpl get on() => |
new _WindowEventsImpl(this); |
@@ -41021,6 +41080,202 @@ class _Lists { |
return accumulator; |
} |
} |
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+class _MessageTraverserVisitedMap { |
+ |
+ operator[](var object) => null; |
+ void operator[]=(var object, var info) { } |
+ |
+ void reset() { } |
+ void cleanup() { } |
+ |
+} |
+ |
+/** Abstract visitor for dart objects that can be sent as isolate messages. */ |
+class _MessageTraverser { |
+ |
+ _MessageTraverserVisitedMap _visited; |
+ _MessageTraverser() : _visited = new _MessageTraverserVisitedMap(); |
+ |
+ /** Visitor's entry point. */ |
+ traverse(var x) { |
+ if (isPrimitive(x)) return visitPrimitive(x); |
+ _visited.reset(); |
+ var result; |
+ try { |
+ result = _dispatch(x); |
+ } finally { |
+ _visited.cleanup(); |
+ } |
+ return result; |
+ } |
+ |
+ _dispatch(var x) { |
+ if (isPrimitive(x)) return visitPrimitive(x); |
+ if (x is List) return visitList(x); |
+ if (x is Map) return visitMap(x); |
+ if (x is SendPort) return visitSendPort(x); |
+ |
+ // TODO(floitsch): make this a real exception. (which one)? |
+ throw "Message serialization: Illegal value $x passed"; |
+ } |
+ |
+ abstract visitPrimitive(x); |
+ abstract visitList(List x); |
+ abstract visitMap(Map x); |
+ abstract visitSendPort(SendPort x); |
+ |
+ static bool isPrimitive(x) { |
+ return (x === null) || (x is String) || (x is num) || (x is bool); |
+ } |
+} |
+ |
+ |
+/** A visitor that recursively copies a message. */ |
+class _Copier extends _MessageTraverser { |
+ |
+ visitPrimitive(x) => x; |
+ |
+ List visitList(List list) { |
+ List copy = _visited[list]; |
+ if (copy !== null) return copy; |
+ |
+ int len = list.length; |
+ |
+ // TODO(floitsch): we loose the generic type of the List. |
+ copy = new List(len); |
+ _visited[list] = copy; |
+ for (int i = 0; i < len; i++) { |
+ copy[i] = _dispatch(list[i]); |
+ } |
+ return copy; |
+ } |
+ |
+ Map visitMap(Map map) { |
+ Map copy = _visited[map]; |
+ if (copy !== null) return copy; |
+ |
+ // TODO(floitsch): we loose the generic type of the map. |
+ copy = new Map(); |
+ _visited[map] = copy; |
+ map.forEach((key, val) { |
+ copy[_dispatch(key)] = _dispatch(val); |
+ }); |
+ return copy; |
+ } |
+ |
+} |
+ |
+/** Visitor that serializes a message as a JSON array. */ |
+class _Serializer extends _MessageTraverser { |
+ int _nextFreeRefId = 0; |
+ |
+ visitPrimitive(x) => x; |
+ |
+ visitList(List list) { |
+ int copyId = _visited[list]; |
+ if (copyId !== null) return ['ref', copyId]; |
+ |
+ int id = _nextFreeRefId++; |
+ _visited[list] = id; |
+ var jsArray = _serializeList(list); |
+ // TODO(floitsch): we are losing the generic type. |
+ return ['list', id, jsArray]; |
+ } |
+ |
+ visitMap(Map map) { |
+ int copyId = _visited[map]; |
+ if (copyId !== null) return ['ref', copyId]; |
+ |
+ int id = _nextFreeRefId++; |
+ _visited[map] = id; |
+ var keys = _serializeList(map.getKeys()); |
+ var values = _serializeList(map.getValues()); |
+ // TODO(floitsch): we are losing the generic type. |
+ return ['map', id, keys, values]; |
+ } |
+ |
+ _serializeList(List list) { |
+ int len = list.length; |
+ var result = new List(len); |
+ for (int i = 0; i < len; i++) { |
+ result[i] = _dispatch(list[i]); |
+ } |
+ return result; |
+ } |
+} |
+ |
+/** Deserializes arrays created with [_Serializer]. */ |
+class _Deserializer { |
+ Map<int, Dynamic> _deserialized; |
+ |
+ _Deserializer(); |
+ |
+ static bool isPrimitive(x) { |
+ return (x === null) || (x is String) || (x is num) || (x is bool); |
+ } |
+ |
+ deserialize(x) { |
+ if (isPrimitive(x)) return x; |
+ // TODO(floitsch): this should be new HashMap<int, var|Dynamic>() |
+ _deserialized = new HashMap(); |
+ return _deserializeHelper(x); |
+ } |
+ |
+ _deserializeHelper(x) { |
+ if (isPrimitive(x)) return x; |
+ assert(x is List); |
+ switch (x[0]) { |
+ case 'ref': return _deserializeRef(x); |
+ case 'list': return _deserializeList(x); |
+ case 'map': return _deserializeMap(x); |
+ case 'sendport': return deserializeSendPort(x); |
+ // TODO(floitsch): Use real exception (which one?). |
+ default: throw "Unexpected serialized object"; |
+ } |
+ } |
+ |
+ _deserializeRef(List x) { |
+ int id = x[1]; |
+ var result = _deserialized[id]; |
+ assert(result !== null); |
+ return result; |
+ } |
+ |
+ List _deserializeList(List x) { |
+ int id = x[1]; |
+ // We rely on the fact that Dart-lists are directly mapped to Js-arrays. |
+ List dartList = x[2]; |
+ _deserialized[id] = dartList; |
+ int len = dartList.length; |
+ for (int i = 0; i < len; i++) { |
+ dartList[i] = _deserializeHelper(dartList[i]); |
+ } |
+ return dartList; |
+ } |
+ |
+ Map _deserializeMap(List x) { |
+ Map result = new Map(); |
+ int id = x[1]; |
+ _deserialized[id] = result; |
+ List keys = x[2]; |
+ List values = x[3]; |
+ int len = keys.length; |
+ assert(len == values.length); |
+ for (int i = 0; i < len; i++) { |
+ var key = _deserializeHelper(keys[i]); |
+ var value = _deserializeHelper(values[i]); |
+ result[key] = value; |
+ } |
+ return result; |
+ } |
+ |
+ abstract deserializeSendPort(List x); |
+ |
+} |
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |