Bug 582569 - Fire an event in child frame scripts when the TabChild is closing [r=smaug a=blocking-fennec]
authorMark Finkle <mfinkle@mozilla.com>
Thu, 12 Aug 2010 12:47:22 -0400
changeset 50357 541caee57ec7f0245c67085bfb5471b4bc6f9c1b
parent 50356 c727df97c28cf4a0eb4a808f8238b7cb270c24ea
child 50358 117166848ffac0fc6a9c1854850e3293c22cdcb2
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, blocking-fennec
bugs582569
milestone2.0b4pre
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 582569 - Fire an event in child frame scripts when the TabChild is closing [r=smaug a=blocking-fennec]
content/base/src/nsInProcessTabChildGlobal.cpp
content/base/src/nsInProcessTabChildGlobal.h
dom/ipc/TabChild.cpp
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -44,16 +44,17 @@
 #include "nsIComponentManager.h"
 #include "nsIServiceManager.h"
 #include "nsIJSRuntimeService.h"
 #include "nsComponentManagerUtils.h"
 #include "nsNetUtil.h"
 #include "nsScriptLoader.h"
 #include "nsIJSContextStack.h"
 #include "nsFrameLoader.h"
+#include "nsIPrivateDOMEvent.h"
 
 bool SendSyncMessageToParent(void* aCallbackData,
                              const nsAString& aMessage,
                              const nsAString& aJSON,
                              nsTArray<nsString>* aJSONRetVal)
 {
   nsInProcessTabChildGlobal* tabChild =
     static_cast<nsInProcessTabChildGlobal*>(aCallbackData);
@@ -112,17 +113,16 @@ nsInProcessTabChildGlobal::nsInProcessTa
                                                      nsFrameMessageManager* aChrome)
 : mDocShell(aShell), mInitialized(PR_FALSE), mLoadingScript(PR_FALSE),
   mDelayedDisconnect(PR_FALSE), mOwner(aOwner), mChromeMessageManager(aChrome)
 {
 }
 
 nsInProcessTabChildGlobal::~nsInProcessTabChildGlobal()
 {
-  Disconnect();
   NS_ASSERTION(!mCx, "Couldn't release JSContext?!?");
 }
 
 nsresult
 nsInProcessTabChildGlobal::Init()
 {
   nsresult rv = InitTabChildGlobal();
   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
@@ -177,23 +177,48 @@ nsInProcessTabChildGlobal::GetDocShell(n
 {
   NS_IF_ADDREF(*aDocShell = mDocShell);
   return NS_OK;
 }
 
 void
 nsInProcessTabChildGlobal::Disconnect()
 {
+  // Let the frame scripts know the child is being closed. We do any other
+  // cleanup after the event has been fired. See DelayedDisconnect
+  nsContentUtils::AddScriptRunner(
+     NS_NewRunnableMethod(this, &nsInProcessTabChildGlobal::DelayedDisconnect)
+  );
+}
+
+void
+nsInProcessTabChildGlobal::DelayedDisconnect()
+{
+  // Don't let the event escape
+  mOwner = nsnull;
+
+  // Fire the "unload" event
+  nsCOMPtr<nsIDOMEvent> event;
+  NS_NewDOMEvent(getter_AddRefs(event), nsnull, nsnull);
+  if (event) {
+    event->InitEvent(NS_LITERAL_STRING("unload"), PR_FALSE, PR_FALSE);
+    nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
+    privateEvent->SetTrusted(PR_TRUE);
+
+    PRBool dummy;
+    nsDOMEventTargetHelper::DispatchEvent(event, &dummy);
+  }
+
+  // Continue with the Disconnect cleanup
   nsCOMPtr<nsIDOMWindow> win = do_GetInterface(mDocShell);
   nsCOMPtr<nsPIDOMWindow> pwin = do_QueryInterface(win);
   if (pwin) {
     pwin->SetChromeEventHandler(pwin->GetChromeEventHandler());
   }
   mDocShell = nsnull;
-  mOwner = nsnull;
   mChromeMessageManager = nsnull;
   if (mMessageManager) {
     static_cast<nsFrameMessageManager*>(mMessageManager.get())->Disconnect();
     mMessageManager = nsnull;
   }
   if (!mLoadingScript) {
     if (mCx) {
       DestroyCx();
--- a/content/base/src/nsInProcessTabChildGlobal.h
+++ b/content/base/src/nsInProcessTabChildGlobal.h
@@ -116,16 +116,18 @@ public:
   nsFrameMessageManager* GetChromeMessageManager()
   {
     return mChromeMessageManager;
   }
   void SetChromeMessageManager(nsFrameMessageManager* aParent)
   {
     mChromeMessageManager = aParent;
   }
+
+  void DelayedDisconnect();
 protected:
   nsresult Init();
   nsresult InitTabChildGlobal();
   nsCOMPtr<nsIContentFrameMessageManager> mMessageManager;
   nsCOMPtr<nsIDocShell> mDocShell;
   PRPackedBool mInitialized;
   PRPackedBool mLoadingScript;
   PRPackedBool mDelayedDisconnect;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -70,16 +70,17 @@
 #include "nsComponentManagerUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsScriptLoader.h"
 #include "nsPIWindowRoot.h"
 #include "nsIScriptContext.h"
 #include "nsInterfaceHashtable.h"
 #include "nsPresContext.h"
 #include "nsIDocument.h"
+#include "nsIDOMDocument.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsWeakReference.h"
 
 #ifdef MOZ_WIDGET_QT
 #include <QX11EmbedWidget>
 #include <QGraphicsView>
 #include <QGraphicsWidget>
 #endif
@@ -948,24 +949,55 @@ TabChild::RecvAsyncMessage(const nsStrin
   if (mTabChildGlobal) {
     static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get())->
       ReceiveMessage(static_cast<nsPIDOMEventTarget*>(mTabChildGlobal),
                      aMessage, PR_FALSE, aJSON, nsnull, nsnull);
   }
   return true;
 }
 
+class UnloadScriptEvent : public nsRunnable
+{
+public:
+  UnloadScriptEvent(TabChild* aTabChild, TabChildGlobal* aTabChildGlobal)
+    : mTabChild(aTabChild), mTabChildGlobal(aTabChildGlobal)
+  { }
+
+  NS_IMETHOD Run()
+  {
+    nsCOMPtr<nsIDOMEvent> event;
+    NS_NewDOMEvent(getter_AddRefs(event), nsnull, nsnull);
+    if (event) {
+      event->InitEvent(NS_LITERAL_STRING("unload"), PR_FALSE, PR_FALSE);
+      nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
+      privateEvent->SetTrusted(PR_TRUE);
+
+      PRBool dummy;
+      mTabChildGlobal->DispatchEvent(event, &dummy);
+    }
+
+    return NS_OK;
+  }
+
+  nsRefPtr<TabChild> mTabChild;
+  TabChildGlobal* mTabChildGlobal;
+};
+
 bool
 TabChild::RecvDestroy()
 {
-    DestroyWidget();
+  // Let the frame scripts know the child is being closed
+  nsContentUtils::AddScriptRunner(
+    new UnloadScriptEvent(this, mTabChildGlobal)
+  );
 
-    // XXX what other code in ~TabChild() should we be running here?
+  // XXX what other code in ~TabChild() should we be running here?
+  DestroyWidget();
 
-    return Send__delete__(this);
+  return Send__delete__(this);
 }
 
 bool
 TabChild::InitTabChildGlobal()
 {
   nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
   NS_ENSURE_TRUE(window, false);
   nsCOMPtr<nsIDOMEventTarget> chromeHandler =