Index: lib/html/dartium/html_dartium.dart |
diff --git a/lib/html/dartium/html_dartium.dart b/lib/html/dartium/html_dartium.dart |
index 80d48c4622423c6c4c2ce8e270b314eb4abd84d4..2367fa47c9f94f2851c3d5e1d2bf28abdfa96c9b 100644 |
--- a/lib/html/dartium/html_dartium.dart |
+++ b/lib/html/dartium/html_dartium.dart |
@@ -49,56 +49,29 @@ 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); |
+int _getNewIsolateId() { |
+ // TODO(vsm): We need a Dartium native for this. |
+ return 1; |
} |
-class _JsDeserializer extends _Deserializer { |
+bool _callPortInitialized = false; |
+var _callPortLastResult = null; |
- 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; |
+_callPortSync(num id, var message) { |
+ if (!_callPortInitialized) { |
window.on['js-result'].add((event) { |
- lastResult = JSON.parse(event.data); |
+ _callPortLastResult = JSON.parse(event.data); |
}, false); |
- initialized = true; |
+ _callPortInitialized = 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; |
- } |
- |
+ var data = JSON.stringify({ 'id': id, 'message': message }); |
+ var event = document.$dom_createEvent('TextEvent'); |
+ event.initTextEvent('js-sync-message', false, false, window, data); |
+ assert(_callPortLastResult == null); |
+ window.$dom_dispatchEvent(event); |
+ var result = _callPortLastResult; |
+ _callPortLastResult = null; |
+ return result; |
} |
class _AbstractWorkerEventsImpl extends _EventsImpl implements AbstractWorkerEvents { |
@@ -5205,12 +5178,17 @@ class _DOMWindowImpl extends _EventTargetImpl implements Window { |
IDBFactory get indexedDB() => webkitIndexedDB; |
- // TODO(kasperl): Document this. |
+ // TODO(kasperl): Document these. |
lookupPort(String name) { |
var port = JSON.parse(localStorage['dart-port:$name']); |
return _deserialize(port); |
} |
+ registerPort(String name, var port) { |
+ var serialized = _serialize(port); |
+ localStorage['dart-port:$name'] = JSON.stringify(serialized); |
+ } |
+ |
_WindowEventsImpl get on() => |
new _WindowEventsImpl(this); |
@@ -40825,6 +40803,207 @@ interface IDBOpenDBRequestEvents extends IDBRequestEvents { |
// 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. |
+_serialize(var message) { |
+ return new _JsSerializer().traverse(message); |
+} |
+ |
+class _JsSerializer extends _Serializer { |
+ |
+ visitSendPortSync(SendPortSync x) { |
+ if (x is _JsSendPortSync) return visitJsSendPortSync(x); |
+ if (x is _LocalSendPortSync) return visitLocalSendPortSync(x); |
+ if (x is _RemoteSendPortSync) return visitRemoteSendPortSync(x); |
+ throw "Illegal underlying port $x"; |
+ } |
+ |
+ visitJsSendPortSync(_JsSendPortSync x) { |
+ return [ 'sendport', 'nativejs', x._id ]; |
+ } |
+ |
+ visitLocalSendPortSync(_LocalSendPortSync x) { |
+ return [ 'sendport', 'dart', |
+ ReceivePortSync._isolateId, x._receivePort._portId ]; |
+ } |
+ |
+ visitRemoteSendPortSync(_RemoteSendPortSync x) { |
+ return [ 'sendport', 'dart', |
+ x._receivePort._isolateId, x._receivePort._portId ]; |
+ } |
+} |
+ |
+_deserialize(var message) { |
+ return new _JsDeserializer().deserialize(message); |
+} |
+ |
+class _JsDeserializer extends _Deserializer { |
+ |
+ deserializeSendPort(List x) { |
+ String tag = x[1]; |
+ switch (tag) { |
+ case 'nativejs': |
+ num id = x[2]; |
+ return new _JsSendPortSync(id); |
+ case 'dart': |
+ num isolateId = x[2]; |
+ num portId = x[3]; |
+ return ReceivePortSync._lookup(isolateId, portId); |
+ default: |
+ throw 'Illegal SendPortSync type: $tag'; |
+ } |
+ } |
+ |
+} |
+ |
+// The receiver is JS. |
+class _JsSendPortSync implements SendPortSync { |
+ |
+ num _id; |
+ _JsSendPortSync(this._id); |
+ |
+ callSync(var message) { |
+ var serialized = _serialize(message); |
+ var result = _callPortSync(_id, serialized); |
+ return _deserialize(result); |
+ } |
+ |
+} |
+ |
+// TODO(vsm): Differentiate between Dart2Js and Dartium isolates. |
+// The receiver is a different Dart isolate, compiled to JS. |
+class _RemoteSendPortSync implements SendPortSync { |
+ |
+ int _isolateId; |
+ int _portId; |
+ _RemoteSendPortSync(this._isolateId, this._portId); |
+ |
+ callSync(var message) { |
+ var serialized = _serialize(message); |
+ var result = _call(_isolateId, _portId, serialized); |
+ return _deserialize(result); |
+ } |
+ |
+ static _call(int isolateId, int portId, var message) { |
+ var target = 'dart-port-$isolateId-$portId'; |
+ // TODO(vsm): Make this re-entrant. |
+ // TODO(vsm): Set this up set once, on the first call. |
+ var source = '$target-result'; |
+ var result = null; |
+ var listener = (TextEvent e) { |
+ result = JSON.parse(e.data); |
+ }; |
+ window.on[source].add(listener); |
+ _dispatchEvent(target, [source, message]); |
+ window.on[source].remove(listener); |
+ return result; |
+ } |
+} |
+ |
+// The receiver is in the same Dart isolate, compiled to JS. |
+class _LocalSendPortSync implements SendPortSync { |
+ |
+ ReceivePortSync _receivePort; |
+ |
+ _LocalSendPortSync._internal(this._receivePort); |
+ |
+ callSync(var message) { |
+ // TODO(vsm): Do a more efficient deep copy. |
+ var copy = _deserialize(_serialize(message)); |
+ var result = _receivePort._callback(copy); |
+ return _deserialize(_serialize(result)); |
+ } |
+} |
+ |
+// TODO(vsm): Move this to dart:isolate. This will take some |
+// refactoring as there are dependences here on the DOM. Users |
+// interact with this class (or interface if we change it) directly - |
+// new ReceivePortSync. I think most of the DOM logic could be |
+// delayed until the corresponding SendPort is registered on the |
+// window. |
+ |
+// A Dart ReceivePortSync (tagged 'dart' when serialized) is |
+// identifiable / resolvable by the combination of its isolateid and |
+// portid. When a corresponding SendPort is used within the same |
+// isolate, the _portMap below can be used to obtain the |
+// ReceivePortSync directly. Across isolates (or from JS), an |
+// EventListener can be used to communicate with the port indirectly. |
+class ReceivePortSync { |
+ |
+ static Map<int, ReceivePortSync> _portMap; |
+ static int _portIdCount; |
+ static int _cachedIsolateId; |
+ |
+ num _portId; |
+ Function _callback; |
+ EventListener _listener; |
+ |
+ ReceivePortSync() { |
+ if (_portIdCount == null) { |
+ _portIdCount = 0; |
+ _portMap = new Map<int, ReceivePortSync>(); |
+ } |
+ _portId = _portIdCount++; |
+ _portMap[_portId] = this; |
+ } |
+ |
+ static int get _isolateId() { |
+ // TODO(vsm): Make this coherent with existing isolate code. |
+ if (_cachedIsolateId == null) { |
+ _cachedIsolateId = _getNewIsolateId(); |
+ } |
+ return _cachedIsolateId; |
+ } |
+ |
+ static String _getListenerName(isolateId, portId) => |
+ 'dart-port-$isolateId-$portId'; |
+ String get _listenerName() => _getListenerName(_isolateId, _portId); |
+ |
+ void receive(callback(var message)) { |
+ // Clear old listener. |
+ if (_callback != null) { |
+ window.on[_listenerName].remove(_listener); |
+ } |
+ |
+ _callback = callback; |
+ |
+ // Install new listener. |
+ var sendport = toSendPort(); |
+ _listener = (TextEvent e) { |
+ var data = JSON.parse(e.data); |
+ var replyTo = data[0]; |
+ var message = _deserialize(data[1]); |
+ var result = sendport.callSync(message); |
+ _dispatchEvent(replyTo, _serialize(result)); |
+ }; |
+ window.on[_listenerName].add(_listener); |
+ } |
+ |
+ void close() { |
+ _portMap.remove(_portId); |
+ window.on[_listenerName].remove(_listener); |
+ } |
+ |
+ SendPortSync toSendPort() { |
+ return new _LocalSendPortSync._internal(this); |
+ } |
+ |
+ static SendPortSync _lookup(int isolateId, int portId) { |
+ if (isolateId == _isolateId) { |
+ return _portMap[portId].toSendPort(); |
+ } else { |
+ return new _RemoteSendPortSync(isolateId, portId); |
+ } |
+ } |
+} |
+ |
+void _dispatchEvent(String receiver, var message) { |
+ var event = document.$dom_createEvent('TextEvent'); |
+ event.initTextEvent(receiver, false, false, window, JSON.stringify(message)); |
+ window.$dom_dispatchEvent(event); |
+} |
+// 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. |
+ |
typedef Object ComputeValue(); |
class _MeasurementRequest<T> { |