Bug 859230 - fix windowless docshell crash by returning object with strong ref to the browser. r=bz
authorMark Hammond <mhammond@skippinet.com.au>
Thu, 11 Apr 2013 17:09:13 +1000
changeset 139338 a3b06580a0dad0274c28691fc0f31d8d6789f327
parent 139337 4705e2c47b2b33d05cb966394b916d17c55aa020
child 139339 b47c83333ec72f0ec0fc0410f7189aa2cba66930
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs859230
milestone23.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 859230 - fix windowless docshell crash by returning object with strong ref to the browser. r=bz
xpfe/appshell/src/nsAppShellService.cpp
--- a/xpfe/appshell/src/nsAppShellService.cpp
+++ b/xpfe/appshell/src/nsAppShellService.cpp
@@ -205,30 +205,32 @@ nsAppShellService::CreateTopLevelWindow(
   return rv;
 }
 
 /*
  * This class provides a stub implementation of nsIWebBrowserChrome2, as needed
  * by nsAppShellService::CreateWindowlessBrowser
  */
 class WebBrowserChrome2Stub : public nsIWebBrowserChrome2,
-                              public nsIInterfaceRequestor {
+                              public nsIInterfaceRequestor,
+                              public nsSupportsWeakReference {
 public:
     virtual ~WebBrowserChrome2Stub() {}
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
     NS_DECL_NSIINTERFACEREQUESTOR
 };
 
 NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome)
   NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2)
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(WebBrowserChrome2Stub)
 NS_IMPL_RELEASE(WebBrowserChrome2Stub)
 
 NS_IMETHODIMP
 WebBrowserChrome2Stub::SetStatus(uint32_t aStatusType, const PRUnichar* aStatus)
 {
@@ -307,16 +309,49 @@ WebBrowserChrome2Stub::SetStatusWithCont
 }
 
 NS_IMETHODIMP
 WebBrowserChrome2Stub::GetInterface(const nsIID & aIID, void **aSink)
 {
     return QueryInterface(aIID, aSink);
 }
 
+// This is the "stub" we return from CreateWindowlessBrowser - it exists
+// purely to keep a strong reference to the browser and the container to
+// prevent the container being collected while the stub remains alive.
+class WindowlessBrowserStub: public nsIWebNavigation,
+                             public nsIInterfaceRequestor {
+public:
+  WindowlessBrowserStub(nsIWebBrowser *aBrowser, nsISupports *aContainer) {
+    mBrowser = aBrowser;
+    mWebNavigation = do_QueryInterface(aBrowser);
+    mInterfaceRequestor = do_QueryInterface(aBrowser);
+    mContainer = aContainer;
+  }
+  NS_DECL_ISUPPORTS
+  NS_FORWARD_NSIWEBNAVIGATION(mWebNavigation->)
+  NS_FORWARD_NSIINTERFACEREQUESTOR(mInterfaceRequestor->)
+private:
+  nsCOMPtr<nsIWebBrowser> mBrowser;
+  nsCOMPtr<nsIWebNavigation> mWebNavigation;
+  nsCOMPtr<nsIInterfaceRequestor> mInterfaceRequestor;
+  // we don't use the container but just hold a reference to it.
+  nsCOMPtr<nsISupports> mContainer;
+};
+
+NS_INTERFACE_MAP_BEGIN(WindowlessBrowserStub)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebNavigation)
+  NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
+  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(WindowlessBrowserStub)
+NS_IMPL_RELEASE(WindowlessBrowserStub)
+
+
 NS_IMETHODIMP
 nsAppShellService::CreateWindowlessBrowser(nsIWebNavigation **aResult)
 {
   /* First, we create an instance of nsWebBrowser. Instances of this class have
    * an associated doc shell, which is what we're interested in.
    */
   nsCOMPtr<nsIWebBrowser> browser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID);
   if (!browser) {
@@ -352,17 +387,19 @@ nsAppShellService::CreateWindowlessBrows
     return NS_ERROR_FAILURE;
   }
   widget->Create(nullptr, 0, nsIntRect(nsIntPoint(0, 0), nsIntSize(0, 0)),
                  nullptr, nullptr);
   nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(navigation);
   window->InitWindow(0, widget, 0, 0, 0, 0);
   window->Create();
 
-  navigation.forget(aResult);
+  nsISupports *isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome2*, stub);
+  nsRefPtr<nsIWebNavigation> result = new WindowlessBrowserStub(browser, isstub);
+  result.forget(aResult);
   return NS_OK;
 }
 
 uint32_t
 nsAppShellService::CalculateWindowZLevel(nsIXULWindow *aParent,
                                          uint32_t      aChromeMask)
 {
   uint32_t zLevel;