diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp
index 3b24aed96182..08f25b3ff8f3 100644
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -2040,6 +2040,16 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace)
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
+ // check whether we're in the middle of unload. If so, ignore this call.
+ nsCOMPtr shell = do_QueryReferent(mDocumentContainer);
+ if (shell) {
+ PRBool inUnload;
+ shell->GetIsInUnload(&inUnload);
+ if (inUnload) {
+ return NS_OK;
+ }
+ }
+
// Note: We want to use GetDocumentFromContext here because this document
// should inherit the security information of the document that's opening us,
// (since if it's secure, then it's presumeably trusted).
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index 1ff8df784647..2bbbc310bab9 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -671,6 +671,9 @@ nsDocShell::LoadURI(nsIURI * aURI,
PRUint32 aLoadFlags,
PRBool aFirstParty)
{
+ if (mFiredUnloadEvent) {
+ return NS_OK; // JS may not handle returning of an error code
+ }
nsresult rv;
nsCOMPtr referrer;
nsCOMPtr postStream;
@@ -973,6 +976,7 @@ nsDocShell::FirePageHideNotification(PRBool aIsUnload)
}
}
}
+
return NS_OK;
}
@@ -2198,6 +2202,13 @@ nsDocShell::SetChildOffset(PRUint32 aChildOffset)
return NS_OK;
}
+NS_IMETHODIMP
+nsDocShell::GetIsInUnload(PRBool* aIsInUnload)
+{
+ *aIsInUnload = mFiredUnloadEvent;
+ return NS_OK;
+}
+
//*****************************************************************************
// nsDocShell::nsIDocShellTreeNode
//*****************************************************************************
@@ -2630,6 +2641,12 @@ nsDocShell::IsPrintingOrPP(PRBool aDisplayErrorDialog)
return mIsPrintingOrPP;
}
+PRBool
+nsDocShell::IsNavigationAllowed(PRBool aDisplayPrintErrorDialog)
+{
+ return !IsPrintingOrPP(aDisplayPrintErrorDialog) && !mFiredUnloadEvent;
+}
+
//*****************************************************************************
// nsDocShell::nsIWebNavigation
//*****************************************************************************
@@ -2637,7 +2654,7 @@ nsDocShell::IsPrintingOrPP(PRBool aDisplayErrorDialog)
NS_IMETHODIMP
nsDocShell::GetCanGoBack(PRBool * aCanGoBack)
{
- if (IsPrintingOrPP(PR_FALSE)) {
+ if (!IsNavigationAllowed(PR_FALSE)) {
*aCanGoBack = PR_FALSE;
return NS_OK; // JS may not handle returning of an error code
}
@@ -2654,7 +2671,7 @@ nsDocShell::GetCanGoBack(PRBool * aCanGoBack)
NS_IMETHODIMP
nsDocShell::GetCanGoForward(PRBool * aCanGoForward)
{
- if (IsPrintingOrPP(PR_FALSE)) {
+ if (!IsNavigationAllowed(PR_FALSE)) {
*aCanGoForward = PR_FALSE;
return NS_OK; // JS may not handle returning of an error code
}
@@ -2671,7 +2688,7 @@ nsDocShell::GetCanGoForward(PRBool * aCanGoForward)
NS_IMETHODIMP
nsDocShell::GoBack()
{
- if (IsPrintingOrPP()) {
+ if (!IsNavigationAllowed()) {
return NS_OK; // JS may not handle returning of an error code
}
nsresult rv;
@@ -2687,7 +2704,7 @@ nsDocShell::GoBack()
NS_IMETHODIMP
nsDocShell::GoForward()
{
- if (IsPrintingOrPP()) {
+ if (!IsNavigationAllowed()) {
return NS_OK; // JS may not handle returning of an error code
}
nsresult rv;
@@ -2702,7 +2719,7 @@ nsDocShell::GoForward()
NS_IMETHODIMP nsDocShell::GotoIndex(PRInt32 aIndex)
{
- if (IsPrintingOrPP()) {
+ if (!IsNavigationAllowed()) {
return NS_OK; // JS may not handle returning of an error code
}
nsresult rv;
@@ -2723,7 +2740,7 @@ nsDocShell::LoadURI(const PRUnichar * aURI,
nsIInputStream * aPostStream,
nsIInputStream * aHeaderStream)
{
- if (IsPrintingOrPP()) {
+ if (!IsNavigationAllowed()) {
return NS_OK; // JS may not handle returning of an error code
}
nsCOMPtr uri;
@@ -3107,7 +3124,7 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
NS_IMETHODIMP
nsDocShell::Reload(PRUint32 aReloadFlags)
{
- if (IsPrintingOrPP()) {
+ if (!IsNavigationAllowed()) {
return NS_OK; // JS may not handle returning of an error code
}
nsresult rv;
diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h
index 74a75c5ea335..7128622e4c7c 100644
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -380,6 +380,7 @@ protected:
const PRUnichar *aPage,
const PRUnichar *aDescription,
nsIChannel* aFailedChannel);
+ PRBool IsNavigationAllowed(PRBool aDisplayPrintErrorDialog = PR_TRUE);
PRBool IsPrintingOrPP(PRBool aDisplayErrorDialog = PR_TRUE);
nsresult SetBaseUrlForWyciwyg(nsIContentViewer * aContentViewer);
diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl
index 81fa00b4556d..86a2935211f9 100644
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -68,7 +68,7 @@ interface nsILayoutHistoryState;
interface nsISecureBrowserUI;
interface nsIDOMStorage;
-[scriptable, uuid(db67b973-ba1a-49fa-b5b4-7670d203fa0e)]
+[scriptable, uuid(10ed386d-8598-408c-b571-e75ad18edeb0)]
interface nsIDocShell : nsISupports
{
/**
@@ -184,6 +184,9 @@ interface nsIDocShell : nsISupports
* Notify the associated content viewer and all child docshells that they are
* about to be hidden. If |isUnload| is true, then the document is being
* unloaded as well.
+ *
+ * @param isUnload if true, fire the unload event in addition to the pagehide
+ * event.
*/
[noscript] void firePageHideNotification(in boolean isUnload);
@@ -438,5 +441,12 @@ interface nsIDocShell : nsISupports
* Set the offset of this child in its container.
*/
[noscript] void setChildOffset(in unsigned long offset);
+
+ /**
+ * Find out whether the docshell is currently in the middle of a page
+ * transition (after the onunload event has fired, but before the new
+ * document has been set up)
+ */
+ readonly attribute boolean isInUnload;
};
diff --git a/docshell/base/nsWebShell.cpp b/docshell/base/nsWebShell.cpp
index 9812201bf3ef..ad27f542e774 100644
--- a/docshell/base/nsWebShell.cpp
+++ b/docshell/base/nsWebShell.cpp
@@ -768,6 +768,11 @@ nsWebShell::OnLinkClick(nsIContent* aContent,
nsIInputStream* aHeadersDataStream)
{
NS_ASSERTION(NS_IsMainThread(), "wrong thread");
+
+ if (mFiredUnloadEvent) {
+ return NS_OK;
+ }
+
nsCOMPtr ev =
new OnLinkClickEvent(this, aContent, aURI, aTargetSpec,
aPostDataStream, aHeadersDataStream);
@@ -791,6 +796,10 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent,
*aRequest = nsnull;
}
+ if (mFiredUnloadEvent) {
+ return NS_OK;
+ }
+
{
// defer to an external protocol handler if necessary...
nsCOMPtr extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);