Bug 827188 - Initialize the hidden private window lazily; r=bzbarsky
☠☠ backed out by dfba6fd60061 ☠ ☠
authorEhsan Akhgari <ehsan@mozilla.com>
Sun, 06 Jan 2013 21:16:48 -0500
changeset 127981 f3a6aff3dbbc693797ef0c65418ef0f3bb69613c
parent 127980 0cb72eb178444a16df0f2304ed09a3f64888f752
child 127982 65517a277d6ba2b4765f01867a9a257e39bedb26
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs827188
milestone21.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 827188 - Initialize the hidden private window lazily; r=bzbarsky
content/base/src/nsCCUncollectableMarker.cpp
docshell/base/nsDocShell.cpp
toolkit/components/startup/nsAppStartup.cpp
xpfe/appshell/public/nsIAppShellService.idl
xpfe/appshell/src/nsAppShellService.cpp
xpfe/appshell/src/nsAppShellService.h
--- a/content/base/src/nsCCUncollectableMarker.cpp
+++ b/content/base/src/nsCCUncollectableMarker.cpp
@@ -363,22 +363,26 @@ nsCCUncollectableMarker::Observe(nsISupp
     appShell->GetHiddenWindow(getter_AddRefs(hw));
     if (hw) {
       nsCOMPtr<nsIDocShell> shell;
       hw->GetDocShell(getter_AddRefs(shell));
       nsCOMPtr<nsIDocShellTreeNode> shellTreeNode = do_QueryInterface(shell);
       MarkDocShell(shellTreeNode, cleanupJS, prepareForCC);
     }
 #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
-    appShell->GetHiddenPrivateWindow(getter_AddRefs(hw));
-    if (hw) {
-      nsCOMPtr<nsIDocShell> shell;
-      hw->GetDocShell(getter_AddRefs(shell));
-      nsCOMPtr<nsIDocShellTreeNode> shellTreeNode = do_QueryInterface(shell);
-      MarkDocShell(shellTreeNode, cleanupJS, prepareForCC);
+    bool hasHiddenPrivateWindow = false;
+    appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow);
+    if (hasHiddenPrivateWindow) {
+      appShell->GetHiddenPrivateWindow(getter_AddRefs(hw));
+      if (hw) {
+        nsCOMPtr<nsIDocShell> shell;
+        hw->GetDocShell(getter_AddRefs(shell));
+        nsCOMPtr<nsIDocShellTreeNode> shellTreeNode = do_QueryInterface(shell);
+        MarkDocShell(shellTreeNode, cleanupJS, prepareForCC);
+      }
     }
 #endif
   }
 
 #ifdef MOZ_XUL
   nsXULPrototypeCache* xulCache = nsXULPrototypeCache::GetInstance();
   if (xulCache) {
     xulCache->MarkInCCGeneration(sGeneration);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -188,17 +188,20 @@
 
 #include "nsDOMNavigationTiming.h"
 #include "nsITimedChannel.h"
 #include "mozilla/StartupTimeline.h"
 
 #include "mozilla/Telemetry.h"
 #include "nsISecurityUITelemetry.h"
 
-#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+#include "nsIAppShellService.h"
+#include "nsAppShellCID.h"
+#else
 #include "nsIPrivateBrowsingService.h"
 #endif
 
 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
                      NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
@@ -215,19 +218,19 @@ static int32_t gNumberOfDocumentsLoading
 // Global count of existing docshells.
 static int32_t gDocShellCount = 0;
 
 // Global count of docshells with the private attribute set
 static uint32_t gNumberOfPrivateDocShells = 0;
 
 // Global count of private docshells which will always remain open
 #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
-static const uint32_t kNumberOfAlwaysOpenPrivateDocShells = 1; // the private hidden window
+static uint32_t gNumberOfAlwaysOpenPrivateDocShells = 0; // the private hidden window
 #else
-static const uint32_t kNumberOfAlwaysOpenPrivateDocShells = 0;
+static const uint32_t gNumberOfAlwaysOpenPrivateDocShells = 0;
 #endif
 
 // Global reference to the URI fixup service.
 nsIURIFixup *nsDocShell::sURIFixup = 0;
 
 // True means we validate window targets to prevent frameset
 // spoofing. Initialize this to a non-bolean value so we know to check
 // the pref on the creation of the first docshell.
@@ -684,34 +687,52 @@ ConvertLoadTypeToNavigationType(uint32_t
   }
 
   return result;
 }
 
 static nsISHEntry* GetRootSHEntry(nsISHEntry *entry);
 
 static void
+AdjustAlwaysOpenPrivateDocShellCount()
+{
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+    nsCOMPtr<nsIAppShellService> appShell
+      (do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
+    bool hasHiddenPrivateWindow = false;
+    if (appShell) {
+      appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow);
+    }
+    gNumberOfAlwaysOpenPrivateDocShells = hasHiddenPrivateWindow ? 1 : 0;
+#endif
+}
+
+static void
 IncreasePrivateDocShellCount()
 {
+    AdjustAlwaysOpenPrivateDocShellCount();
+
     gNumberOfPrivateDocShells++;
-    if (gNumberOfPrivateDocShells > kNumberOfAlwaysOpenPrivateDocShells + 1 ||
+    if (gNumberOfPrivateDocShells > gNumberOfAlwaysOpenPrivateDocShells + 1 ||
         XRE_GetProcessType() != GeckoProcessType_Content) {
         return;
     }
 
     mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
     cc->SendPrivateDocShellsExist(true);
 }
 
 static void
 DecreasePrivateDocShellCount()
 {
+    AdjustAlwaysOpenPrivateDocShellCount();
+
     MOZ_ASSERT(gNumberOfPrivateDocShells > 0);
     gNumberOfPrivateDocShells--;
-    if (gNumberOfPrivateDocShells == kNumberOfAlwaysOpenPrivateDocShells)
+    if (gNumberOfPrivateDocShells == gNumberOfAlwaysOpenPrivateDocShells)
     {
         if (XRE_GetProcessType() == GeckoProcessType_Content) {
             mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
             cc->SendPrivateDocShellsExist(false);
             return;
         }
 
         nsCOMPtr<nsIObserverService> obsvc = mozilla::services::GetObserverService();
--- a/toolkit/components/startup/nsAppStartup.cpp
+++ b/toolkit/components/startup/nsAppStartup.cpp
@@ -309,44 +309,52 @@ nsAppStartup::Quit(uint32_t aMode)
   if (mShuttingDown)
     return NS_OK;
 
   SAMPLE_MARKER("Shutdown start");
   mozilla::RecordShutdownStartTimeStamp();
 
   // If we're considering quitting, we will only do so if:
   if (ferocity == eConsiderQuit) {
+#ifdef XP_MACOSX
+    nsCOMPtr<nsIAppShellService> appShell
+      (do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
+    bool hasHiddenPrivateWindow = false;
+    if (appShell) {
+      appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow);
+    }
+    int32_t suspiciousCount = hasHiddenPrivateWindow ? 2 : 1;
+#endif
+
     if (mConsiderQuitStopper == 0) {
       // there are no windows...
       ferocity = eAttemptQuit;
     }
 #ifdef XP_MACOSX
-#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
-    else if (mConsiderQuitStopper == 2) {
-#else
-    else if (mConsiderQuitStopper == 1) {
-#endif
+    else if (mConsiderQuitStopper == suspiciousCount) {
       // ... or there is only a hiddenWindow left, and it's useless:
-      nsCOMPtr<nsIAppShellService> appShell
-        (do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
 
       // Failure shouldn't be fatal, but will abort quit attempt:
       if (!appShell)
         return NS_OK;
 
       bool usefulHiddenWindow;
       appShell->GetApplicationProvidedHiddenWindow(&usefulHiddenWindow);
       nsCOMPtr<nsIXULWindow> hiddenWindow;
       appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
 #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+      // If the remaining windows are useful, we won't quit:
       nsCOMPtr<nsIXULWindow> hiddenPrivateWindow;
-      appShell->GetHiddenPrivateWindow(getter_AddRefs(hiddenPrivateWindow));
-      // If the remaining windows are useful, we won't quit:
-      if ((!hiddenWindow && !hiddenPrivateWindow) || usefulHiddenWindow)
+      if (hasHiddenPrivateWindow) {
+        appShell->GetHiddenPrivateWindow(getter_AddRefs(hiddenPrivateWindow));
+        if ((!hiddenWindow && !hiddenPrivateWindow) || usefulHiddenWindow)
+          return NS_OK;
+      } else if (!hiddenWindow || usefulHiddenWindow) {
         return NS_OK;
+      }
 #else
       // If the one window is useful, we won't quit:
       if (!hiddenWindow || usefulHiddenWindow)
         return NS_OK;
 #endif
 
       ferocity = eAttemptQuit;
     }
--- a/xpfe/appshell/public/nsIAppShellService.idl
+++ b/xpfe/appshell/public/nsIAppShellService.idl
@@ -11,17 +11,17 @@ interface nsIDOMWindow;
 interface nsIAppShell;
 
 [ptr] native JSContext(JSContext);
 
 %{C++
 struct JSContext;
 %}
 
-[scriptable, uuid(76e6364a-5453-47c7-ad83-8c30eff20a75)]
+[scriptable, uuid(5c19ab54-67bf-46d0-ac5b-21abd9050c3b)]
 interface nsIAppShellService : nsISupports
 {
   /**
    * Create a window, which will be initially invisible.
    * @param aParent the parent window.  Can be null.
    * @param aUrl the contents of the new window.
    * @param aChromeMask chrome flags affecting the kind of OS border
    *                    given to the window. see nsIBrowserWindow for
@@ -112,9 +112,15 @@ interface nsIAppShellService : nsISuppor
 
   /**
    * Remove a window from the application's window registry. Note that
    * this method won't automatically attempt to quit the app when
    * the last window is unregistered. For that, see Quit().
    * @param aWindow you see the pattern
    */
   void unregisterTopLevelWindow(in nsIXULWindow aWindow);
+
+  /**
+   * Whether the hidden private window has been lazily created.
+   */
+  [noscript]
+  readonly attribute boolean hasHiddenPrivateWindow;
 };
--- a/xpfe/appshell/src/nsAppShellService.cpp
+++ b/xpfe/appshell/src/nsAppShellService.cpp
@@ -78,52 +78,73 @@ nsAppShellService::~nsAppShellService()
  */
 NS_IMPL_ISUPPORTS2(nsAppShellService,
                    nsIAppShellService,
                    nsIObserver)
 
 NS_IMETHODIMP
 nsAppShellService::CreateHiddenWindow()
 {
+  return CreateHiddenWindowHelper(false);
+}
+
+void
+nsAppShellService::EnsurePrivateHiddenWindow()
+{
+  if (!mHiddenPrivateWindow) {
+    CreateHiddenWindowHelper(true);
+  }
+}
+
+nsresult
+nsAppShellService::CreateHiddenWindowHelper(bool aIsPrivate)
+{
   nsresult rv;
   int32_t initialHeight = 100, initialWidth = 100;
 
 #ifdef XP_MACOSX
   uint32_t    chromeMask = 0;
   nsAdoptingCString prefVal =
       Preferences::GetCString("browser.hiddenWindowChromeURL");
   const char* hiddenWindowURL = prefVal.get() ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL;
-  mApplicationProvidedHiddenWindow = prefVal.get() ? true : false;
+  if (aIsPrivate) {
+    hiddenWindowURL = DEFAULT_HIDDENWINDOW_URL;
+  } else {
+    mApplicationProvidedHiddenWindow = prefVal.get() ? true : false;
+  }
 #else
   static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL;
   uint32_t    chromeMask =  nsIWebBrowserChrome::CHROME_ALL;
 #endif
 
   nsCOMPtr<nsIURI> url;
   rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsRefPtr<nsWebShellWindow> newWindow;
-  rv = JustCreateTopWindow(nullptr, url,
-                           chromeMask, initialWidth, initialHeight,
-                           true, getter_AddRefs(newWindow));
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (!aIsPrivate) {
+    rv = JustCreateTopWindow(nullptr, url,
+                             chromeMask, initialWidth, initialHeight,
+                             true, getter_AddRefs(newWindow));
+    NS_ENSURE_SUCCESS(rv, rv);
 
-  mHiddenWindow.swap(newWindow);
-
+    mHiddenWindow.swap(newWindow);
+  }
 #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
-  // Create the hidden private window
-  chromeMask |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
+  else {
+    // Create the hidden private window
+    chromeMask |= nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW;
 
-  rv = JustCreateTopWindow(nullptr, url,
-                           chromeMask, initialWidth, initialHeight,
-                           true, getter_AddRefs(newWindow));
-  NS_ENSURE_SUCCESS(rv, rv);
+    rv = JustCreateTopWindow(nullptr, url,
+                             chromeMask, initialWidth, initialHeight,
+                             true, getter_AddRefs(newWindow));
+    NS_ENSURE_SUCCESS(rv, rv);
 
-  mHiddenPrivateWindow.swap(newWindow);
+    mHiddenPrivateWindow.swap(newWindow);
+  }
 #endif
 
   // RegisterTopLevelWindow(newWindow); -- Mac only
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -441,28 +462,32 @@ nsAppShellService::GetHiddenDOMWindow(ns
 }
 
 NS_IMETHODIMP
 nsAppShellService::GetHiddenPrivateWindow(nsIXULWindow **aWindow)
 {
 #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
   NS_ENSURE_ARG_POINTER(aWindow);
 
+  EnsurePrivateHiddenWindow();
+
   *aWindow = mHiddenPrivateWindow;
   NS_IF_ADDREF(*aWindow);
   return *aWindow ? NS_OK : NS_ERROR_FAILURE;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
 }
 
 NS_IMETHODIMP
 nsAppShellService::GetHiddenPrivateDOMWindow(nsIDOMWindow **aWindow)
 {
 #ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+  EnsurePrivateHiddenWindow();
+
   nsresult rv;
   nsCOMPtr<nsIDocShell> docShell;
   NS_ENSURE_TRUE(mHiddenPrivateWindow, NS_ERROR_FAILURE);
 
   rv = mHiddenPrivateWindow->GetDocShell(getter_AddRefs(docShell));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDOMWindow> hiddenPrivateDOMWindow(do_GetInterface(docShell, &rv));
@@ -472,16 +497,29 @@ nsAppShellService::GetHiddenPrivateDOMWi
   NS_IF_ADDREF(*aWindow);
   return NS_OK;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif
 }
 
 NS_IMETHODIMP
+nsAppShellService::GetHasHiddenPrivateWindow(bool* aHasPrivateWindow)
+{
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+  NS_ENSURE_ARG_POINTER(aHasPrivateWindow);
+
+  *aHasPrivateWindow = !!mHiddenPrivateWindow;
+  return NS_OK;
+#else
+  return NS_ERROR_NOT_IMPLEMENTED;
+#endif
+}
+
+NS_IMETHODIMP
 nsAppShellService::GetHiddenWindowAndJSContext(nsIDOMWindow **aWindow,
                                                JSContext    **aJSContext)
 {
     nsresult rv = NS_OK;
     if ( aWindow && aJSContext ) {
         *aWindow    = nullptr;
         *aJSContext = nullptr;
 
--- a/xpfe/appshell/src/nsAppShellService.h
+++ b/xpfe/appshell/src/nsAppShellService.h
@@ -27,16 +27,19 @@ public:
   NS_DECL_NSIAPPSHELLSERVICE
   NS_DECL_NSIOBSERVER
 
   nsAppShellService();
 
 protected:
   ~nsAppShellService();
 
+  nsresult CreateHiddenWindowHelper(bool aIsPrivate);
+  void EnsurePrivateHiddenWindow();
+
   nsresult JustCreateTopWindow(nsIXULWindow *aParent,
                                nsIURI *aUrl, 
                                uint32_t aChromeMask,
                                int32_t aInitialWidth, int32_t aInitialHeight,
                                bool aIsHiddenWindow,
                                nsWebShellWindow **aResult);
   uint32_t CalculateWindowZLevel(nsIXULWindow *aParent, uint32_t aChromeMask);