Index: lib/html/frog/html_frog.dart |
diff --git a/lib/html/frog/html_frog.dart b/lib/html/frog/html_frog.dart |
index c31628ee56fb73c4252607fc6e01400b165c8733..7d059b1ac4534e20bf2b190a1121ced7c948c45b 100644 |
--- a/lib/html/frog/html_frog.dart |
+++ b/lib/html/frog/html_frog.dart |
@@ -1,5 +1,7 @@ |
#library('html'); |
+#import('dart:isolate'); |
+#import('dart:json'); |
// 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. |
@@ -12,6 +14,7 @@ |
+ |
Window get window() native "return window;"; |
_WindowImpl get _window() native "return window;"; |
@@ -27,6 +30,43 @@ ElementList queryAll(String selector) => _document.queryAll(selector); |
class _HTMLElementImpl extends _ElementImpl native "*HTMLElement" { |
} |
+_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 { |
+ |
+ num _id; |
+ _JsSendPortSync(this._id); |
+ |
+ callSync(var message) { |
+ var serialized = _serialize(message); |
+ var result = _call(_id, serialized); |
+ return _deserialize(result); |
+ } |
+ |
+ static _call(num id, var message) native @""" |
+ var deserialized = _deserialize(message); |
+ var result = ReceivePortSync.map[id].callback(deserialized); |
+ return _serialize(result); |
+ """; |
+ |
+} |
+ |
class _AbstractWorkerImpl extends _EventTargetImpl implements AbstractWorker native "*AbstractWorker" { |
_AbstractWorkerEventsImpl get on() => |
@@ -16448,6 +16488,12 @@ class _WindowImpl extends _EventTargetImpl implements Window native "@*DOMWindow |
_IDBFactoryImpl _get_indexedDB() native |
'return this.indexedDB || this.webkitIndexedDB || this.mozIndexedDB'; |
+ // TODO(kasperl): Document this. |
+ lookupPort(String name) { |
+ var port = JSON.parse(localStorage['dart-port:$name']); |
+ return _deserialize(port); |
+ } |
+ |
_WindowEventsImpl get on() => |
new _WindowEventsImpl(this); |
@@ -37389,3 +37435,199 @@ 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); |
+ |
+} |