Content to Chrome Event Handling

From MozillaWiki
Jump to: navigation, search

In electrolysis (and also in general), event propagation should not automatically happen between content and chrome. This is because forwarding unnecessary events between content and chrome causes lots of extra IPC traffic, and the events will not provide access to the content nodes directly (in most cases).

Instead, there should be two methods for noticing and handling events in chrome:

xulbrowser.registerEventListener("load", function(e) {
  // handler
  // will be a JPW
}, true);
// true means "handle event synchronously", false means "handle event asynchronously)

xulbrowser.registerRemoteEventListener("load", "resource:///browser-contenthandlers.js", "functionName", function(json) {
  // resource:///browser-contenthandlers.js is loaded as a JS module within
  // the content process. `functionName` is looked up within this module and
  // called with the DOM event.
  // functionName returns something which can be serialized as JSON
  // this function gets the JSON and does something with it.

These APIs should be provided and behave roughly identically whether or not the xul:browser is actually remote or local. Under no circumstances will .addEventListener in the XUL document receive DOM events which originate directly from content.

Few comments (by Olli)

- registerEventListener needs a parameter for the event phase, so does registerRemoteEventListener.

bsmedberg: Hrm. If we're handling asynchronously, I don't think it makes sense to select a phase. Handling synchronously it does make sense.

olli: We need the phase to indicate the phase we add the listener in content process to. Also, we may need yet another (optional) flag for system event group. And should event propagation to chrome process happen even if content script calls event.preventDefault() or do we need a flag to control that?

- I'm not sure why .addEventListener shouldn't receive events which originate from content. I'd like to use the normal DOM event dispatch for all events. <browser> is usually hidden somewhere in XBL and in <tabbrowser> case there are several <browser> elements. It is handy to have just one listener for all of them. Currently E10s FrameLoader has activateFrameEvent method, which activates event forwarding from content process to chrome process. Even that isn't very good since whenever a new tab is added, activateFrameEvent needs to be called for all the needed events. Or do we just add some code to <tabbrowser> which keeps a list of all the listeners which need to be added to a <browser> when new tab is added?

bsmedberg: The last thing, I think. It seems strange (to me) to have events which originate in a different document and security context propagating through chrome as if they were part of the chrome document. But

olli: I may have changed my mind here. Perhaps content events shouldn't be dispatched normally to chrome. See the comment below about having only remote event listeners.

- Should registerRemoteEventListener have also sync-or-async parameter?

bsmedberg: I figured that remote listeners would always be async, but perhaps there is a case where a sync listener makes sense.

- When adding a new tab, it must be possible to add event listeners early enough so that no events coming from content process is missed. (For example the load event from about:blank ContentViewer.)

bsmedberg: ugh. Perhaps we should treat the load event specially (always forward it)? bz would know better the sequence of events we really want in this case. Fennec takes special pains to *cancel* the about:blank load when we first load the <browser> since apparently it makes startup faster.

Some more comments (by Olli)

- Do we need to handle cases like chrome getting an event from content process, and then dispatching a new event to content synchronously? What happens if content process has a listener for that event and the listener uses synchronous XHR (so chrome would be blocked)?

- What if all the event handling happened in the content process? The remote event listener could return an array of objects:

function someRemoteListener(evt) {
  // Do something...
  return [, event.relatedTarget, someJSON, ...];

This is quite far from the current API, so all the addons and FF UI would need pretty significant changes. But still, if we are not going to have normal event dispatch for content events in chrome, JS code needs to be changed anyway. And actually, perhaps we could have some default behavior for remote event listeners to forward the event object (the chrome JS would get JPW of the event). For example if the second parameter for registerRemoteEventListener was null.

- What if there are event listeners implemented in C++? Or do we just not care.

- In which JS context or with what kind of privileges should remote listener run? Some "allow access to all content but no chrome" sandbox?

- Jetpack Where and when should jetpack handle events?