Electrolysis/Jetpack

From MozillaWiki
< Electrolysis
Revision as of 04:44, 19 March 2010 by Jdm (talk | contribs)
Jump to navigation Jump to search

In order to move Jetpack to an out-of-process implementation, a mixture of CPOWs and proxying appears to be necessary. I've encountered one main issue that must be considered:

Using callbacks

Given an API that allows the following:

   jetpack.tabs.onReady(
     function(doc) {
       $("#list", doc).appendChild(listElem);
     }
   }

Certain design choices are necessitated by the limitation of CPOWs - namely, functions cannot be sent directly between processes. Therefore, there are two choices:

1. any API that currently takes a callback must instead take an object with a named callback

In the chrome process:

 function onReady(callbackObj) {
   associateCallbackWithDOMDocumentLoaded(callbackObj.callback);
 }

In the Jetpack process, the jetpack.tabs object can theoretically be a CPOW to the chrome Tabs object, and everything should work fine.

2. any API that currently takes a callback can continue to do so, but must proxy the call

In the jetpack process:

 Tabs = {
   onReady: function(callback) {
     let uniqueSignature = new Date.time().toString();
     this.params[uniqueSignature] = callback;
     sendAsyncMessage("tabs.onReady", {callback: uniqueSignature});
   }
 }

In the chrome process:

 addMessageListener("tabs.onReady",
   function(m) {
     let child = getCPOW(m.target);
     JetpackEnv.Tabs.onReady(child.jetpack.Tabs.params[m.json.callback]);
   }
 Tabs = {
   onReady: function(callback) {
     associateCallbackWithDOMDocumentLoaded(callback);
   }
 }

In either instance, the chrome process will end up calling the CPOW callback using a CPOW document object (assuming content processes exist).

Note that the solutions as described are currently un-implementable, because there's no way to pass the document object to the CPOW callback as a parameter. We need chrome->jetpack CPOWs for that to work, and they don't exist yet.

The upside is that jQuery should Just Work as soon as the chrome -> jetpack CPOWs do exist.

Please note that the above code is very much simplified from the actual implementation. One complication is that <bsendAsyncMessage is not accessible at document level. Instead, you need code like the following to implement proxying:

From a script loaded into the remote jetpack process via loadFrameScript:

 addEventListener("tabs.onReady",
   function(event) {
     var signature = event.getData("signature").QueryInterface(Components.interfaces.nsIVariant);
     sendAsyncMessage("tabs.onReady", {callback: signature});
   }, false, true);

In the Jetpack process implementation:

 Tabs = {
   onReady: function(callback) {
     let uniqueSignature = new Date.time().toString();
     this.params[uniqueSignature] = callback;
     
     var eventDoc = document.QueryInterface(Ci.nsIDOMDocumentEvent);
     var event = eventDoc.createEvent("datacontainerevents");
     var container = event.QueryInterface(Ci.nsIDOMDataContainerEvent);
     var variant = Cc["@mozilla.org/variant;1"].createInstance(Ci.nsIWritableVariant);
     variant.setAsAString(uniqueSignature);
     container.setData("signature", variant);
     event.initEvent("tabs.onReady", true, false);
     window.dispatchEvent(event);
   }
 }

Still, that's just an implementation detail.