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);