Monday, March 8, 2010

informing chrome about content

Hi everyone,

Post number two and I am already off-topic. The bug that I've been working on lately doesn't make anything start any faster (at least not right now), but it does get us closer to a world where Firefox gets to run its UI and content in different processes.

[If you haven't heard about Mozilla's grand plan to separate these into multiple processes, you better get with the program, dude! Or read that link, then you will be with the program.]

So one problem that happens if you run UI (chrome) and content (webpage stuff) in different processes is, you want to be able to update the UI according to how content is changing. Then you can have things like the progress and status bars that tell you the page is loading, or the Rainbow Pinwheel of Death to tell you when we are going to hang or crash. (Just kidding, maintaining control of the UI when content crashes is one of the main goals of this thing). But if they are running in different processes, you have to communicate that data between the processes.

In good old single-process Firefox, the content is loaded by the XUL element (sort of), and has an attribute called "webProgress" that lets you register listeners. Then, when it does navigation, it will send notifications to the listeners for different events like changes in the location, status, or security of the loaded document. So other UI elements can listen for changes this way. This webProgress thing is implemented basically just by exposing the C++ object that does the navigation (it is called a DocShell).

In multi-process Firefox, there are a couple of steps to make this happen. The element lives in the chrome process, because it is UI. But the loading happens in the content, because it is webpage stuff! So I am taking advantage of a pair of objects (TabChild and TabParent) that are already communicating through IPDL. TabChild runs in the content process, so I register it as a listener on the docshell that is doing the loading in the content process. Then, when it gets notifications, it sends messages to TabParent, which lives in the chrome process. TabParent implements nsIWebProgress, so listeners in the chrome process can register as listeners on that, and TabParent will notify them when it gets these messages.

A little fiddling around with browser.xml, and 's webProgress attribute now returns TabParent to its getters (but only if it is a MOZ_IPC is turned on, and it is a remote browser).

Some next steps: in the bug, some people said it would be nice if the chrome process could tell content to stop loading, or load in a different process, or things like that. It will be interesting to work that out, because communication is asynchronous (so maybe the content won't get the notice in time!)

Another problem is that the interface for the event listeners actually expects an object, nsIRequest, to be passed along with the other parameters (like status message, amount of progress made, etc). But we are actually just passing null for now, instead of sending that through IPDL. Listeners also expect an nsIWebProgress (the object that fired the notification) to be passed. In this case that is TabParent, but the 'true' notifier is really the docShell in the content process that sent the event to TabChild which passed it to TabParent... but we aren't passing that docShell through IPDL either. So we'll see if my use of those dummy objects becomes a problem in the future.

Cliffhanger!