Bug 749187 - Ensure new tabs and windows opened in private browsing mode have docshells set accordingly; r=gavin
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 26 Apr 2012 14:35:19 -0400
changeset 94141 d4068b54381a26e8b0d3423da48d03a86c6b0aa8
parent 94140 a9f05eabf20b35c61507f04315c675633a02862a
child 94142 10c12811006914f1920408a78e0a11198b975943
push id9490
push usereakhgari@mozilla.com
push dateWed, 16 May 2012 21:39:02 +0000
treeherdermozilla-inbound@d4068b54381a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgavin
bugs749187
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 749187 - Ensure new tabs and windows opened in private browsing mode have docshells set accordingly; r=gavin
browser/base/content/browser.js
browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
browser/components/privatebrowsing/test/browser/browser_privatebrowsing_ui.js
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -8863,27 +8863,29 @@ let gPrivateBrowsingUI = {
   },
 
   /**
    * These accessors are used to support per-window Private Browsing mode.
    * For now the getter returns nsIPrivateBrowsingService.privateBrowsingEnabled,
    * and the setter should only be used in tests.
    */
   get privateWindow() {
-    return window.getInterface(Ci.nsIWebNavigation)
+    return window.QueryInterface(Ci.nsIInterfaceRequestor)
+                 .getInterface(Ci.nsIWebNavigation)
                  .QueryInterface(Ci.nsIDocShellTreeItem)
                  .treeOwner
                  .QueryInterface(Ci.nsIInterfaceRequestor)
                  .getInterface(Ci.nsIXULWindow)
                  .docShell.QueryInterface(Ci.nsILoadContext)
                  .usePrivateBrowsing;
   },
 
   set privateWindow(val) {
-    return window.getInterface(Ci.nsIWebNavigation)
+    return window.QueryInterface(Ci.nsIInterfaceRequestor)
+                 .getInterface(Ci.nsIWebNavigation)
                  .QueryInterface(Ci.nsIDocShellTreeItem)
                  .treeOwner
                  .QueryInterface(Ci.nsIInterfaceRequestor)
                  .getInterface(Ci.nsIXULWindow)
                  .docShell.QueryInterface(Ci.nsILoadContext)
                  .usePrivateBrowsing = val;
   }
 };
--- a/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
+++ b/browser/components/privatebrowsing/src/nsPrivateBrowsingService.js
@@ -90,16 +90,17 @@ const STATE_RESTORE_FINISHED = 3;
 function PrivateBrowsingService() {
   this._obs = Cc["@mozilla.org/observer-service;1"].
               getService(Ci.nsIObserverService);
   this._obs.addObserver(this, "profile-after-change", true);
   this._obs.addObserver(this, "quit-application-granted", true);
   this._obs.addObserver(this, "private-browsing", true);
   this._obs.addObserver(this, "command-line-startup", true);
   this._obs.addObserver(this, "sessionstore-browser-state-restored", true);
+  this._obs.addObserver(this, "domwindowopened", true);
 
   // List of nsIXULWindows we are going to be closing during the transition
   this._windowsToClose = [];
 }
 
 PrivateBrowsingService.prototype = {
   // Preferences Service
   get _prefs() {
@@ -147,16 +148,27 @@ PrivateBrowsingService.prototype = {
 
   _unload: function PBS__destroy() {
     // Force an exit from the private browsing mode on shutdown
     this._quitting = true;
     if (this._inPrivateBrowsing)
       this.privateBrowsingEnabled = false;
   },
 
+  _setPerWindowPBFlag: function PBS__setPerWindowPBFlag(aWindow, aFlag) {
+    aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+           .getInterface(Ci.nsIWebNavigation)
+           .QueryInterface(Ci.nsIDocShellTreeItem)
+           .treeOwner
+           .QueryInterface(Ci.nsIInterfaceRequestor)
+           .getInterface(Ci.nsIXULWindow)
+           .docShell.QueryInterface(Ci.nsILoadContext)
+           .usePrivateBrowsing = aFlag;
+  },
+
   _onBeforePrivateBrowsingModeChange: function PBS__onBeforePrivateBrowsingModeChange() {
     // nothing needs to be done here if we're enabling at startup
     if (!this._autoStarted) {
       let ss = Cc["@mozilla.org/browser/sessionstore;1"].
                getService(Ci.nsISessionStore);
       let blankState = JSON.stringify({
         "windows": [{
           "tabs": [{
@@ -217,33 +229,25 @@ PrivateBrowsingService.prototype = {
           browserWindow.getInterface(Ci.nsIWebNavigation)
                        .QueryInterface(Ci.nsIDocShellTreeItem)
                        .treeOwner
                        .QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIXULWindow)
                        .docShell.contentViewer.resetCloseWindow();
         }
       }
-
-      if (!this._quitting) {
-        var windowsEnum = Services.wm.getEnumerator("navigator:browser");
-        while (windowsEnum.hasMoreElements()) {
-          var window = windowsEnum.getNext();
-          window.getInterface(Ci.nsIWebNavigation)
-                .QueryInterface(Ci.nsIDocShellTreeItem)
-                .treeOwner
-                .QueryInterface(Ci.nsIInterfaceRequestor)
-                .getInterface(Ci.nsIXULWindow)
-                .docShell.QueryInterface(Ci.nsILoadContext)
-                .usePrivateBrowsing = this._inPrivateBrowsing;
-        }
-      }
     }
     else
       this._saveSession = false;
+
+    var windowsEnum = Services.wm.getEnumerator("navigator:browser");
+    while (windowsEnum.hasMoreElements()) {
+      var window = windowsEnum.getNext();
+      this._setPerWindowPBFlag(window, this._inPrivateBrowsing);
+    }
   },
 
   _onAfterPrivateBrowsingModeChange: function PBS__onAfterPrivateBrowsingModeChange() {
     // nothing to do here if we're enabling at startup or the current session is being
     // used
     if (!this._autoStarted && this._saveSession) {
       let ss = Cc["@mozilla.org/browser/sessionstore;1"].
                getService(Ci.nsISessionStore);
@@ -518,16 +522,28 @@ PrivateBrowsingService.prototype = {
         }
         break;
       case "sessionstore-browser-state-restored":
         if (this._currentStatus == STATE_WAITING_FOR_RESTORE) {
           this._currentStatus = STATE_RESTORE_FINISHED;
           this._notifyIfTransitionComplete();
         }
         break;
+      case "domwindowopened":
+        let aWindow = aSubject;
+        let self = this;
+        aWindow.addEventListener("load", function PBS__onWindowLoad(aEvent) {
+          aWindow.removeEventListener("load", arguments.callee);
+          if (aWindow.document
+                     .documentElement
+                     .getAttribute("windowtype") == "navigator:browser") {
+            self._setPerWindowPBFlag(aWindow, self._inPrivateBrowsing);
+          }
+        }, false);
+        break;
     }
   },
 
   // nsICommandLineHandler
 
   handle: function PBS_handle(aCmdLine) {
     if (aCmdLine.handleFlag("private", false))
       aCmdLine.preventDefault = true; // It has already been handled
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_ui.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_ui.js
@@ -35,71 +35,101 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 // This test makes sure that the gPrivateBrowsingUI object, the Private Browsing
 // menu item and its XUL <command> element work correctly.
 
 function test() {
   // initialization
+  waitForExplicitFinish();
   gPrefService.setBoolPref("browser.privatebrowsing.keep_current_session", true);
   let pb = Cc["@mozilla.org/privatebrowsing;1"].
            getService(Ci.nsIPrivateBrowsingService);
   let observerData;
   function observer(aSubject, aTopic, aData) {
     if (aTopic == "private-browsing")
       observerData = aData;
   }
   Services.obs.addObserver(observer, "private-browsing", false);
   let pbMenuItem = document.getElementById("privateBrowsingItem");
   // add a new blank tab to ensure the title can be meaningfully compared later
   gBrowser.selectedTab = gBrowser.addTab();
   let originalTitle = document.title;
 
+  function testNewWindow(aCallback, expected) {
+    Services.obs.addObserver(function observer1(aSubject, aTopic, aData) {
+      aSubject.addEventListener("load", function() {
+        aSubject.removeEventListener("load", arguments.callee);
+        executeSoon(function() {
+          let ui = aSubject.gPrivateBrowsingUI;
+          is(ui.privateBrowsingEnabled, expected, "The privateBrowsingEnabled property on the new window is set correctly");
+          is(ui.privateWindow, expected, "The privateWindow property on the new window is set correctly");
+
+          Services.obs.addObserver(function observer2(aSubject, aTopic, aData) {
+            aCallback();
+            Services.obs.removeObserver(observer2, "domwindowclosed");
+          }, "domwindowclosed", false);
+          aSubject.close();
+        });
+        Services.obs.removeObserver(observer1, "domwindowopened");
+      }, false);
+    }, "domwindowopened", false);
+    OpenBrowserWindow();
+  }
+
   // test the gPrivateBrowsingUI object
   ok(gPrivateBrowsingUI, "The gPrivateBrowsingUI object exists");
   is(pb.privateBrowsingEnabled, false, "The private browsing mode should not be started initially");
   is(gPrivateBrowsingUI.privateBrowsingEnabled, false, "gPrivateBrowsingUI should expose the correct private browsing status");
   is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
   ok(pbMenuItem, "The Private Browsing menu item exists");
   is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("startlabel"), "The Private Browsing menu item should read \"Start Private Browsing\"");
-  gPrivateBrowsingUI.toggleMode();
-  is(pb.privateBrowsingEnabled, true, "The private browsing mode should be started");
-  is(gPrivateBrowsingUI.privateBrowsingEnabled, true, "gPrivateBrowsingUI should expose the correct private browsing status");
-  is(gPrivateBrowsingUI.privateWindow, true, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
-  // check to see if the Private Browsing mode was activated successfully
-  is(observerData, "enter", "Private Browsing mode was activated using the gPrivateBrowsingUI object");
-  is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("stoplabel"), "The Private Browsing menu item should read \"Stop Private Browsing\"");
-  gPrivateBrowsingUI.toggleMode()
-  is(pb.privateBrowsingEnabled, false, "The private browsing mode should not be started");
-  is(gPrivateBrowsingUI.privateBrowsingEnabled, false, "gPrivateBrowsingUI should expose the correct private browsing status");
-  is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
-  // check to see if the Private Browsing mode was deactivated successfully
-  is(observerData, "exit", "Private Browsing mode was deactivated using the gPrivateBrowsingUI object");
-  is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("startlabel"), "The Private Browsing menu item should read \"Start Private Browsing\"");
+  testNewWindow(function() {
+    gPrivateBrowsingUI.toggleMode();
+    is(pb.privateBrowsingEnabled, true, "The private browsing mode should be started");
+    is(gPrivateBrowsingUI.privateBrowsingEnabled, true, "gPrivateBrowsingUI should expose the correct private browsing status");
+    is(gPrivateBrowsingUI.privateWindow, true, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
+    // check to see if the Private Browsing mode was activated successfully
+    is(observerData, "enter", "Private Browsing mode was activated using the gPrivateBrowsingUI object");
+    is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("stoplabel"), "The Private Browsing menu item should read \"Stop Private Browsing\"");
+    testNewWindow(function() {
+      gPrivateBrowsingUI.toggleMode()
+      is(pb.privateBrowsingEnabled, false, "The private browsing mode should not be started");
+      is(gPrivateBrowsingUI.privateBrowsingEnabled, false, "gPrivateBrowsingUI should expose the correct private browsing status");
+      is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should expose the correct per-window private browsing status");
+      // check to see if the Private Browsing mode was deactivated successfully
+      is(observerData, "exit", "Private Browsing mode was deactivated using the gPrivateBrowsingUI object");
+      is(pbMenuItem.getAttribute("label"), pbMenuItem.getAttribute("startlabel"), "The Private Browsing menu item should read \"Start Private Browsing\"");
+
+      testNewWindow(function() {
+        // These are tests for the privateWindow setter.  Note that the setter should
+        // not be used anywhere else for now!
+        gPrivateBrowsingUI.privateWindow = true;
+        is(gPrivateBrowsingUI.privateWindow, true, "gPrivateBrowsingUI should accept the correct per-window private browsing status");
+        gPrivateBrowsingUI.privateWindow = false;
+        is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should accept the correct per-window private browsing status");
 
-  // These are tests for the privateWindow setter.  Note that the setter should
-  // not be used anywhere else for now!
-  gPrivateBrowsingUI.privateWindow = true;
-  is(gPrivateBrowsingUI.privateWindow, true, "gPrivateBrowsingUI should accept the correct per-window private browsing status");
-  gPrivateBrowsingUI.privateWindow = false;
-  is(gPrivateBrowsingUI.privateWindow, false, "gPrivateBrowsingUI should accept the correct per-window private browsing status");
+        // now, test using the <command> object
+        let cmd = document.getElementById("Tools:PrivateBrowsing");
+        isnot(cmd, null, "XUL command object for the private browsing service exists");
+        var func = new Function("", cmd.getAttribute("oncommand"));
+        func.call(cmd);
+        // check to see if the Private Browsing mode was activated successfully
+        is(observerData, "enter", "Private Browsing mode was activated using the command object");
+        // check to see that the window title has been changed correctly
+        isnot(document.title, originalTitle, "Private browsing mode has correctly changed the title");
+        func.call(cmd);
+        // check to see if the Private Browsing mode was deactivated successfully
+        is(observerData, "exit", "Private Browsing mode was deactivated using the command object");
+        // check to see that the window title has been restored correctly
+        is(document.title, originalTitle, "Private browsing mode has correctly restored the title");
 
-  // now, test using the <command> object
-  let cmd = document.getElementById("Tools:PrivateBrowsing");
-  isnot(cmd, null, "XUL command object for the private browsing service exists");
-  var func = new Function("", cmd.getAttribute("oncommand"));
-  func.call(cmd);
-  // check to see if the Private Browsing mode was activated successfully
-  is(observerData, "enter", "Private Browsing mode was activated using the command object");
-  // check to see that the window title has been changed correctly
-  isnot(document.title, originalTitle, "Private browsing mode has correctly changed the title");
-  func.call(cmd);
-  // check to see if the Private Browsing mode was deactivated successfully
-  is(observerData, "exit", "Private Browsing mode was deactivated using the command object");
-  // check to see that the window title has been restored correctly
-  is(document.title, originalTitle, "Private browsing mode has correctly restored the title");
+        // cleanup
+        gBrowser.removeCurrentTab();
+        Services.obs.removeObserver(observer, "private-browsing");
+        gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
 
-  // cleanup
-  gBrowser.removeCurrentTab();
-  Services.obs.removeObserver(observer, "private-browsing");
-  gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
+        finish();
+      }, false);
+    }, true);
+  }, false);
 }