Content Process Event Handlers: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
(Created page with '[https://bugzilla.mozilla.org/show_bug.cgi?id=542242 Bug 542242] adds support for content process event listeners. The basic idea is that chrome asks content process to load scri…')
 
No edit summary
Line 1: Line 1:
[https://bugzilla.mozilla.org/show_bug.cgi?id=542242 Bug 542242] adds support for content process event listeners. The basic idea is that chrome asks content process to load script files which add listeners to the content process root event handling scope. The event listeners can then send messages to chrome process.
[https://bugzilla.mozilla.org/show_bug.cgi?id=542242 Bug 542242] added support for content process event listeners. The basic idea is that chrome asks content process to load script files which add listeners to the content process root event handling scope. The event listeners can then send messages to chrome process.


[http://hg.mozilla.org/projects/electrolysis/file/416375517820/content/base/public/nsIFrameMessageManager.idl nsIFrameMessageManager] file has the new interfaces related to content process event listeners and message handling.
[http://hg.mozilla.org/projects/electrolysis/file/416375517820/content/base/public/nsIFrameMessageManager.idl nsIFrameMessageManager] file has the new interfaces related to content process event listeners and message handling.

Revision as of 21:40, 20 February 2010

Bug 542242 added support for content process event listeners. The basic idea is that chrome asks content process to load script files which add listeners to the content process root event handling scope. The event listeners can then send messages to chrome process.

nsIFrameMessageManager file has the new interfaces related to content process event listeners and message handling.

ALL THE COMMENTS ABOUT THE API ARE VERY WELCOME! (Ping smaug on IRC)

Content Process

For each tab the child process has a JS context/scope, which implements nsIContentFrameMessageManager and nsIDOMEventTarget. That scope is above the current top level content window, so capturing event listeners will be called first using event listeners added in that scope and event listeners added to bubble phase will be called after listeners in the content page. The current top level window can be accessed using content property. The scope has also the methods from nsIDOMEventTarget and the new methods from nsIContentFrameMessageManager:

- addMessageListener adds a listeners for messages coming from chrome. First parameter is the name of the message, second one is the listener (a JS Function).

- removeMessageListener removes a message listener. First parameter is the name of the message, second one is the listener (a JS Function).

- sendAsyncMessage sends asynchronously a message to chrome. It takes 1 or 2 parameters; first one is the name of the message and second one is a JS object which will be JSON'ed.

- sendSyncMessage sends synchronously a message to chrome. Currently it takes 1 or 2 parameters; first one is the name of the message and second one is a JS object which will be JSON'ed. If chrome process message listener returns some value, it will be JSON'ed and sendSyncMessage() returns that in an array. (In an array because chrome process may have several listeners for a message and each one may return a result.)
NOTE! In the near future sendSyncMessage() will be able to take more parameters. The parameters after 2nd one will be send as CPOW objects to the chrome process.

- dump prints a string to stdout.

Chrome process

On chrome side the chrome window and each nsIFrameLoader object have messageManager property, which implements nsIChromeFrameMessageManager. When the one from window is used, it forwards sendAsyncMessage and loadFrameScript calls to each remote frame in the document. When a message is received from content process, listeners in nsIFrameLoader's message manager will be called first, and then the ones in the window's message manager.

messageManager has the following methods:

- addMessageListener adds a listeners for messages coming from content. First parameter is the name of the message, second one is the listener (a JS Function).

- removeMessageListener removes a message listener. First parameter is the name of the message, second one is the listener (a JS Function).

- sendAsyncMessage sends asynchronously a message to content. It takes 1 or 2 parameters; first one is the name of the message and second one is a JS object which will be JSON'ed.

- loadFrameScript asks content process root scope to load a script. The first parameter is the absolute URL of the script and the second one is a boolean, which indicates whether messageManager should try to load the url once the content process root scope becomes available. If false, and the root scope isn't there yet, the method does nothing.
NOTE! Using data: urls does work. Sending the following URL should print out "Hello world!": data:,dump("Hello world!");
ISSUE! While using chrome URLs does work, there is currently an open bug 542907 to support all the same chrome URLs in the content process what chrome process sees.

Messages and message listeners

Message listeners get a JS object as the parameter. The object looks current like the following:

 {
   name:    %message name%,
   sync:    %true or false%.
   json:    %json object or null%,
 }

When the CPOW support is added to the synchronous messages, the object will have also property objects.

When a listener is called, 'this' value points to the target of the message. In content process it is always to root scope. In chrome process it points to the iframe element in which the remote frame is.


Examples

Forward all the clicks on an HTML A to chrome

// remote.js
// Note, this is just an example. Doesn't work if click happens in a
// descendant element of the A.

addEventListener("click",
  function(e) {
    if (e.target instanceof Components.interfaces.nsIDOMHTMLAnchorElement) {
      if (sendSyncMessage("linkclick", { href : e.target.href })[0].cancel) {
        e.preventDefault();
      }
    }
  },
  true);
// some-script-in-chrome.js
messageManager.addMessageListener("linkclick"
  function(m) {
    return { cancel: !confirm("Do you want to load " + m.href) };
  }
);