Per-window Private Browsing/Front-end implementation notes
Here's a list of useful notes for the front-end hacking necessary for implementing per-window private browsing.
Contents
Goals
- Be able to open a single window in private browsing mode without closing off the existing session.
- Be able to create a special build of the browser which supports per-window private browsing, while keeping the existing global private browsing mode intact.
Notes about how per-window private browsing works
Each browser window is organized as a tree hierarchy of documents. Usually, at the root of a browser window there is the browser.xul document, under which one or more content documents get loaded (one per tab). If a document is loaded inside an iframe in a parent document, then that document gets added to the tree as well. Here's an example of a browser window which has one CNN and one hacker news tab open:
* root document (chrome, browser.xul) +-- child document (content, cnn.com) | +-- child document (content, cnn.com/ad1) | +-- child document (content, cnn.com/ad2) +-- child document (content, news.ycombinator.com)
Each document has a docshell object associated with it, so there is an equivalent docshell tree hierarchy as well.
In the global private browsing implementation, everywhere that we need to know whether to store something on disk or not, we would just look at a global boolean flag (nsIPrivateBrowsingService.privateBrowsingEnabled) and determine whether or not we should store something to disk. In the per-tab private browsing implementation, instead of doing that we find the docshell corresponding to the task at hand, and look at the private browsing boolean flag stored in that docshell to determine whether we should store something on disk. Each docshell has one boolean private browsing flag, and it propagates to the children, so that when you first create a docshell, we set its flag to the value of its parent's flag, and when you set the flag on a given docshell living in its hierarchy, the flag gets propagated down to all of its descendants.
Given the above, a private browsing window would effectively be a window which has the flag set to true on its root docshell. The true flag would automatically propagate to all of the child docshells, that is, to all of the tabs and iframes loaded inside the tabs in that window.
The front-end APIs
- To determine whether a given window object (either chrome or content window) is private or not, use PrivateBrowsingUtils.isWindowPrivate(window), defined in resource://gre/modules/PrivateBrowsingUtils.jsm.
- To open a new private browsing window, call OpenBrowserWindow({private: true}).
Development
In order to build Firefox with per-window private browsing support, add the following to your mozconfig:
export MOZ_PER_WINDOW_PRIVATE_BROWSING=1
We should attempt to use the per-window private browsing API as much as possible. That API is designed to work with both the global private browsing service and the flags living in the docshells. Currently, the global service will set this flag on every existing docshell when we switch to private browsing mode, in order to make it possible to port things to use the new APIs over time. But for some things this will just not be possible. In that case, we should hide the new code behind MOZ_PER_WINDOW_PRIVATE_BROWSING #ifdefs (for the current examples of this, see this query). The goal here is that at any point in time, if you build Firefox without MOZ_PER_WINDOW_PRIVATE_BROWSING=1 in your mozconfig, you should get a working Firefox with global private browsing support, and if you put MOZ_PER_WINDOW_PRIVATE_BROWSING=1 in your mozconfig, you should get a working Firefox with per-window private browsing support.
All of the fixes for per-window private browsing should go through the normal review process and land on mozilla-inbound/central. For reviews for private browsing code, you can ask either ehsan or jdm.
The birch branch has been setup to do per-window PB builds, and gets automated updates from mozilla-central twice a day. Nothing should directly land on birch. For submitting try patches, please import this patch into your patch queue.
Testing
New tests for per-window private browsing should be added to browser/components/tests/browser/perwindow. We do currently have a few tests there, and we should look into porting the tests inside browser/components/tests/browser/global as well. The perwindow tests are currently only run on builds with MOZ_PER_WINDOW_PRIVATE_BROWSING defined.