Serialize Elements through PortSync

Review URL: https://chromiumcodereview.appspot.com//10883037

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@11365 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
vsm@google.com 2012-08-26 21:55:31 +00:00
parent 1bca4e07d5
commit 8802f83208
5 changed files with 204 additions and 0 deletions

View file

@ -88,6 +88,12 @@ function ReceivePortSync() {
} else if (message instanceof Function) {
return [ 'funcref', functionRefTable.makeRef(message),
doSerialize(functionRefTable.sendPort) ];
} else if (message instanceof HTMLElement) {
var id = elementId(message);
// Verify that the element is connected to the document.
// Otherwise, we will not be able to find it on the other side.
getElement(id);
return [ 'element', id ];
} else if (message instanceof DartProxy) {
return [ 'objref', message._id, doSerialize(message._port) ];
} else if (message.__proto__ != {}.__proto__) {
@ -126,6 +132,7 @@ function ReceivePortSync() {
case 'list': return deserializeList(message);
case 'funcref': return deserializeFunction(message);
case 'objref': return deserializeProxy(message);
case 'element': return deserializeElement(message);
default: throw 'unimplemented';
}
}
@ -187,6 +194,11 @@ function ReceivePortSync() {
throw 'Illegal proxy object: ' + message;
}
function deserializeElement(message) {
var id = message[1];
return getElement(id);
}
window.registerPort = function(name, port) {
var stringified = JSON.stringify(serialize(port));
window.localStorage['dart-port:' + name] = stringified;
@ -376,4 +388,24 @@ function ReceivePortSync() {
return sendPort.callSync([ref, Array.prototype.slice.call(arguments)]);
}
}
var localNextElementId = 0;
var _DART_ID = 'data-dart_id';
function elementId(e) {
if (e.hasAttribute(_DART_ID)) return e.getAttribute(_DART_ID);
var id = (localNextElementId++).toString();
e.setAttribute(_DART_ID, id);
return id;
}
function getElement(id) {
var list = document.querySelectorAll('[' + _DART_ID + '="' + id + '"]');
if (list.length > 1) throw 'Non unique ID: ' + id;
if (list.length == 0) {
throw 'Element must be attached to the document: ' + id;
}
return list[0];
}
})();

View file

@ -37682,6 +37682,26 @@ class JsProxy {
}
}
int _localNextElementId = 0;
const _DART_ID = 'data-dart_id';
var _elementId(Element e) {
if (e.attributes.containsKey(_DART_ID)) return e.attributes[_DART_ID];
var id = '$_isolateId-${_localNextElementId++}';
e.attributes[_DART_ID] = id;
return id;
}
Element _getElement(var id) {
var list = queryAll('[$_DART_ID="$id"]');
if (list.length > 1) throw 'Non unique ID: $id';
if (list.length == 0) {
throw 'Only elements attached to document can be serialized: $id';
}
return list[0];
}
class _JsSerializer extends _Serializer {
visitSendPortSync(SendPortSync x) {
@ -37708,6 +37728,7 @@ class _JsSerializer extends _Serializer {
visitObject(Object x) {
if (x is Function) return visitFunction(x);
if (x is JsProxy) return visitJsProxy(x);
if (x is Element) return visitElement(x);
// TODO: Handle DOM elements and proxy other objects.
var proxyId = _dartProxyRegistry._add(x);
@ -37724,6 +37745,14 @@ class _JsSerializer extends _Serializer {
visitJsProxy(JsProxy proxy) {
return [ 'objref', proxy._id, visitSendPortSync(proxy._port) ];
}
visitElement(Element element) {
var id = _elementId(element);
// Verify that the element is connected to the document.
// Otherwise, we will not be able to find it on the other side.
_getElement(id);
return [ 'element', id ];
}
}
// Leaking implementation. Later will be backend specific and hopefully
@ -37828,6 +37857,7 @@ class _JsDeserializer extends _Deserializer {
switch (tag) {
case 'funcref': return deserializeFunction(x);
case 'objref': return deserializeProxy(x);
case 'element': return deserializeElement(x);
default: throw 'Illegal object type: $x';
}
}
@ -37855,6 +37885,11 @@ class _JsDeserializer extends _Deserializer {
if (port is _RemoteSendPortSync) throw 'Remote Dart proxies unsupported';
throw 'Illegal proxy: $port';
}
deserializeElement(x) {
var id = x[1];
return _getElement(id);
}
}
// The receiver is JS.
@ -37992,6 +38027,8 @@ class ReceivePortSync {
}
}
get _isolateId => ReceivePortSync._isolateId;
void _dispatchEvent(String receiver, var message) {
var event = document.$dom_createEvent('TextEvent');
event.initTextEvent(receiver, false, false, window, JSON.stringify(message));

View file

@ -40787,6 +40787,26 @@ class JsProxy {
}
}
int _localNextElementId = 0;
const _DART_ID = 'data-dart_id';
var _elementId(Element e) {
if (e.attributes.containsKey(_DART_ID)) return e.attributes[_DART_ID];
var id = '$_isolateId-${_localNextElementId++}';
e.attributes[_DART_ID] = id;
return id;
}
Element _getElement(var id) {
var list = queryAll('[$_DART_ID="$id"]');
if (list.length > 1) throw 'Non unique ID: $id';
if (list.length == 0) {
throw 'Only elements attached to document can be serialized: $id';
}
return list[0];
}
class _JsSerializer extends _Serializer {
visitSendPortSync(SendPortSync x) {
@ -40813,6 +40833,7 @@ class _JsSerializer extends _Serializer {
visitObject(Object x) {
if (x is Function) return visitFunction(x);
if (x is JsProxy) return visitJsProxy(x);
if (x is Element) return visitElement(x);
// TODO: Handle DOM elements and proxy other objects.
var proxyId = _dartProxyRegistry._add(x);
@ -40829,6 +40850,14 @@ class _JsSerializer extends _Serializer {
visitJsProxy(JsProxy proxy) {
return [ 'objref', proxy._id, visitSendPortSync(proxy._port) ];
}
visitElement(Element element) {
var id = _elementId(element);
// Verify that the element is connected to the document.
// Otherwise, we will not be able to find it on the other side.
_getElement(id);
return [ 'element', id ];
}
}
// Leaking implementation. Later will be backend specific and hopefully
@ -40933,6 +40962,7 @@ class _JsDeserializer extends _Deserializer {
switch (tag) {
case 'funcref': return deserializeFunction(x);
case 'objref': return deserializeProxy(x);
case 'element': return deserializeElement(x);
default: throw 'Illegal object type: $x';
}
}
@ -40960,6 +40990,11 @@ class _JsDeserializer extends _Deserializer {
if (port is _RemoteSendPortSync) throw 'Remote Dart proxies unsupported';
throw 'Illegal proxy: $port';
}
deserializeElement(x) {
var id = x[1];
return _getElement(id);
}
}
// The receiver is JS.
@ -41097,6 +41132,8 @@ class ReceivePortSync {
}
}
get _isolateId => ReceivePortSync._isolateId;
void _dispatchEvent(String receiver, var message) {
var event = document.$dom_createEvent('TextEvent');
event.initTextEvent(receiver, false, false, window, JSON.stringify(message));

View file

@ -23,6 +23,26 @@ class JsProxy {
}
}
int _localNextElementId = 0;
const _DART_ID = 'data-dart_id';
var _elementId(Element e) {
if (e.attributes.containsKey(_DART_ID)) return e.attributes[_DART_ID];
var id = '$_isolateId-${_localNextElementId++}';
e.attributes[_DART_ID] = id;
return id;
}
Element _getElement(var id) {
var list = queryAll('[$_DART_ID="$id"]');
if (list.length > 1) throw 'Non unique ID: $id';
if (list.length == 0) {
throw 'Only elements attached to document can be serialized: $id';
}
return list[0];
}
class _JsSerializer extends _Serializer {
visitSendPortSync(SendPortSync x) {
@ -49,6 +69,7 @@ class _JsSerializer extends _Serializer {
visitObject(Object x) {
if (x is Function) return visitFunction(x);
if (x is JsProxy) return visitJsProxy(x);
if (x is Element) return visitElement(x);
// TODO: Handle DOM elements and proxy other objects.
var proxyId = _dartProxyRegistry._add(x);
@ -65,6 +86,14 @@ class _JsSerializer extends _Serializer {
visitJsProxy(JsProxy proxy) {
return [ 'objref', proxy._id, visitSendPortSync(proxy._port) ];
}
visitElement(Element element) {
var id = _elementId(element);
// Verify that the element is connected to the document.
// Otherwise, we will not be able to find it on the other side.
_getElement(id);
return [ 'element', id ];
}
}
// Leaking implementation. Later will be backend specific and hopefully
@ -169,6 +198,7 @@ class _JsDeserializer extends _Deserializer {
switch (tag) {
case 'funcref': return deserializeFunction(x);
case 'objref': return deserializeProxy(x);
case 'element': return deserializeElement(x);
default: throw 'Illegal object type: $x';
}
}
@ -196,6 +226,11 @@ class _JsDeserializer extends _Deserializer {
if (port is _RemoteSendPortSync) throw 'Remote Dart proxies unsupported';
throw 'Illegal proxy: $port';
}
deserializeElement(x) {
var id = x[1];
return _getElement(id);
}
}
// The receiver is JS.
@ -333,6 +368,8 @@ class ReceivePortSync {
}
}
get _isolateId => ReceivePortSync._isolateId;
void _dispatchEvent(String receiver, var message) {
var event = document.$dom_createEvent('TextEvent');
event.initTextEvent(receiver, false, false, window, JSON.stringify(message));

View file

@ -0,0 +1,61 @@
// 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
#library('JsInteropElementTest');
#import('../../pkg/unittest/unittest.dart');
#import('../../pkg/unittest/html_config.dart');
#import('dart:html');
#import('dart:isolate');
injectSource(code) {
final script = new ScriptElement();
script.type = 'text/javascript';
script.innerHTML = code;
document.body.nodes.add(script);
}
var jsElementTest = """
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
var port = window.lookupPort('test1');
port.callSync(canvas);
""";
var dartElementTest = """
var port = new ReceivePortSync();
port.receive(function (data) {
return (data instanceof HTMLDivElement);
});
window.registerPort('test2', port.toSendPort());
""";
main() {
useHtmlConfiguration();
test('js-element', () {
int invoked = 0;
var port = new ReceivePortSync();
port.receive((data) {
expect(data is CanvasElement);
++invoked;
});
window.registerPort('test1', port.toSendPort());
injectSource(jsElementTest);
expect(invoked, equals(1));
});
test('dart-element', () {
injectSource(dartElementTest);
var port = window.lookupPort('test2');
var div = new DivElement();
var canvas = new CanvasElement(100,100);
document.body.nodes.addAll([div, canvas]);
expect(port.callSync(div));
expect(!port.callSync(canvas));
});
}