From c308f45fce3ff56705254ec66450c26f1187c04f Mon Sep 17 00:00:00 2001 From: "rpotts%netscape.com" Date: Tue, 17 Jul 2001 20:17:38 +0000 Subject: [PATCH] bug #84749. (r=nisheeth, sr=jst). Document unload() events fired *after* the current URI had been changed - this allowed JS to track where the user was going next... git-svn-id: svn://10.0.0.236/trunk@99429 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/content/base/src/nsDocumentViewer.cpp | 32 ++++++++++ mozilla/docshell/base/nsDocShell.cpp | 44 ++++++++++++++ mozilla/docshell/base/nsDocShell.h | 9 +-- mozilla/docshell/base/nsIContentViewer.idl | 1 + mozilla/docshell/base/nsIDocShell.idl | 2 + mozilla/docshell/base/nsWebShell.cpp | 59 ------------------- mozilla/docshell/base/nsWebShell.h | 5 -- mozilla/layout/base/nsDocumentViewer.cpp | 32 ++++++++++ .../plugin/base/src/nsPluginViewer.cpp | 7 +++ .../modules/plugin/nglsrc/nsPluginViewer.cpp | 7 +++ mozilla/webshell/public/nsIWebShell.h | 5 -- 11 files changed, 130 insertions(+), 73 deletions(-) diff --git a/mozilla/content/base/src/nsDocumentViewer.cpp b/mozilla/content/base/src/nsDocumentViewer.cpp index 53f2cc1fb5d..de0d5725719 100644 --- a/mozilla/content/base/src/nsDocumentViewer.cpp +++ b/mozilla/content/base/src/nsDocumentViewer.cpp @@ -379,6 +379,7 @@ public: NS_IMETHOD GetContainer(nsISupports** aContainerResult); NS_IMETHOD LoadStart(nsISupports* aDoc); NS_IMETHOD LoadComplete(nsresult aStatus); + NS_IMETHOD Unload(void); NS_IMETHOD Destroy(void); NS_IMETHOD Stop(void); NS_IMETHOD GetDOMDocument(nsIDOMDocument **aResult); @@ -1133,6 +1134,37 @@ DocumentViewerImpl::LoadComplete(nsresult aStatus) return rv; } +NS_IMETHODIMP +DocumentViewerImpl::Unload() +{ + nsresult rv; + + if (!mDocument) { + return NS_ERROR_NULL_POINTER; + } + + // First, get the script global object from the document... + nsCOMPtr global; + + rv = mDocument->GetScriptGlobalObject(getter_AddRefs(global)); + if (!global) { + // Fail if no ScriptGlobalObject is available... + NS_ASSERTION(0, "nsIScriptGlobalObject not set for document!"); + return NS_ERROR_NULL_POINTER; + } + + // Now, fire an Unload event to the document... + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + + event.eventStructType = NS_EVENT; + event.message = NS_PAGE_UNLOAD; + rv = global->HandleDOMEvent(mPresContext, &event, nsnull, + NS_EVENT_FLAG_INIT, &status); + + return rv; +} + NS_IMETHODIMP DocumentViewerImpl::Destroy() { diff --git a/mozilla/docshell/base/nsDocShell.cpp b/mozilla/docshell/base/nsDocShell.cpp index 696bf9fa4da..82636e1b3d4 100644 --- a/mozilla/docshell/base/nsDocShell.cpp +++ b/mozilla/docshell/base/nsDocShell.cpp @@ -187,6 +187,7 @@ nsDocShell::nsDocShell(): mFocusDocFirst(PR_FALSE), mAppType(nsIDocShell::APP_TYPE_UNKNOWN), mBusyFlags(BUSY_FLAGS_NONE), + mFiredUnloadEvent(PR_FALSE), mEODForCurrentDocument(PR_FALSE), mURIResultedInDocument(PR_FALSE), mUseExternalProtocolHandler(PR_FALSE), @@ -740,6 +741,33 @@ nsDocShell::PrepareForNewContentModel() return NS_OK; } + +NS_IMETHODIMP +nsDocShell::FireUnloadNotification() +{ + nsresult rv; + + if (mContentViewer && !mFiredUnloadEvent) { + mFiredUnloadEvent = PR_TRUE; + + rv = mContentViewer->Unload(); + + PRInt32 i, n = mChildren.Count(); + for (i = 0; i < n; i++) { + nsIDocShellTreeItem* item = (nsIDocShellTreeItem*) mChildren.ElementAt(i); + if(item) { + nsCOMPtr shell(do_QueryInterface(item)); + if (shell) { + rv = shell->FireUnloadNotification(); + } + } + } + } + + return NS_OK; +} + + // // Bug 13871: Prevent frameset spoofing // Check if origin document uri is the equivalent to target's principal. @@ -2399,6 +2427,9 @@ nsDocShell::Create() NS_IMETHODIMP nsDocShell::Destroy() { + //Fire unload event before we blow anything away. + (void) FireUnloadNotification(); + mIsBeingDestroyed = PR_TRUE; // Stop any URLs that are currently being loaded... @@ -3779,6 +3810,18 @@ nsDocShell::CreateContentViewer(const char *aContentType, if (NS_FAILED(rv)) return NS_ERROR_FAILURE; + // Notify the current document that it is about to be unloaded!! + // + // It is important to fire the unload() notification *before* any state + // is changed within the DocShell - otherwise, javascript will get the + // wrong information :-( + // + (void) FireUnloadNotification(); + + // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the + // *new* document will fire. + mFiredUnloadEvent = PR_FALSE; + // we've created a new document so go ahead and call OnLoadingSite mURIResultedInDocument = PR_TRUE; @@ -4133,6 +4176,7 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer) return NS_OK; } + //***************************************************************************** // nsDocShell: Site Loading //***************************************************************************** diff --git a/mozilla/docshell/base/nsDocShell.h b/mozilla/docshell/base/nsDocShell.h index ead84c11e55..8aeb94bcb09 100644 --- a/mozilla/docshell/base/nsDocShell.h +++ b/mozilla/docshell/base/nsDocShell.h @@ -273,10 +273,9 @@ protected: // Helper method that is called when a new document (including any // sub-documents - ie. frames) has been completely loaded. // - virtual nsresult EndPageLoad(nsIWebProgress * aProgress, - nsIChannel * aChannel, - nsresult aResult); - + virtual nsresult EndPageLoad(nsIWebProgress * aProgress, + nsIChannel * aChannel, + nsresult aResult); protected: nsString mName; nsString mTitle; @@ -325,6 +324,8 @@ protected: // Somebody give me better name nsCOMPtr mLSHE; + PRBool mFiredUnloadEvent; + // this flag is for bug #21358. a docshell may load many urls // which don't result in new documents being created (i.e. a new content viewer) // we want to make sure we don't call a on load event more than once for a given diff --git a/mozilla/docshell/base/nsIContentViewer.idl b/mozilla/docshell/base/nsIContentViewer.idl index 3a5bb57f051..de6e6b39807 100644 --- a/mozilla/docshell/base/nsIContentViewer.idl +++ b/mozilla/docshell/base/nsIContentViewer.idl @@ -25,6 +25,7 @@ interface nsIContentViewer : nsISupports void loadStart(in nsISupports aDoc); void loadComplete(in unsigned long aStatus); + void unload(); void destroy(); void stop(); diff --git a/mozilla/docshell/base/nsIDocShell.idl b/mozilla/docshell/base/nsIDocShell.idl index dbaf2c5b9a3..a2954db7952 100644 --- a/mozilla/docshell/base/nsIDocShell.idl +++ b/mozilla/docshell/base/nsIDocShell.idl @@ -144,6 +144,8 @@ interface nsIDocShell : nsISupports */ void prepareForNewContentModel(); + [noscript] void FireUnloadNotification(); + /** * Presentation context for the currently loaded document. This may be null. */ diff --git a/mozilla/docshell/base/nsWebShell.cpp b/mozilla/docshell/base/nsWebShell.cpp index 316564ad3ff..00c62192510 100644 --- a/mozilla/docshell/base/nsWebShell.cpp +++ b/mozilla/docshell/base/nsWebShell.cpp @@ -176,7 +176,6 @@ nsWebShell::nsWebShell() : nsDocShell() mItemType = typeContent; mCharsetReloadState = eCharsetReloadInit; mHistoryState = nsnull; - mFiredUnloadEvent = PR_FALSE; mBounds.SetRect(0, 0, 0, 0); } @@ -227,54 +226,6 @@ void nsWebShell::InitFrameData() SetMarginHeight(-1); } -nsresult -nsWebShell::FireUnloadForChildren() -{ - nsresult rv = NS_OK; - - PRInt32 i, n = mChildren.Count(); - for (i = 0; i < n; i++) { - nsIDocShell* shell = (nsIDocShell*) mChildren.ElementAt(i); - if(shell) { - nsCOMPtr webShell(do_QueryInterface(shell)); - rv = webShell->FireUnloadEvent(); - } - } - - return rv; -} - -NS_IMETHODIMP -nsWebShell::FireUnloadEvent() -{ - nsresult rv = NS_OK; - - if (!mFiredUnloadEvent) { - mFiredUnloadEvent = PR_TRUE; - - if (mScriptGlobal) { - nsIDocumentViewer* docViewer; - if (mContentViewer && NS_SUCCEEDED(mContentViewer->QueryInterface(NS_GET_IID(nsIDocumentViewer), (void**)&docViewer))) { - nsIPresContext *presContext; - if (NS_SUCCEEDED(docViewer->GetPresContext(presContext))) { - nsEventStatus status = nsEventStatus_eIgnore; - nsMouseEvent event; - event.eventStructType = NS_EVENT; - event.message = NS_PAGE_UNLOAD; - rv = mScriptGlobal->HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); - - NS_RELEASE(presContext); - } - NS_RELEASE(docViewer); - } - } - } - //Fire child unloads now while our data is intact. - rv = FireUnloadForChildren(); - - return rv; -} - NS_IMPL_ADDREF_INHERITED(nsWebShell, nsDocShell) NS_IMPL_RELEASE_INHERITED(nsWebShell, nsDocShell) @@ -346,13 +297,8 @@ nsWebShell::GetInterface(const nsIID &aIID, void** aInstancePtr) NS_IMETHODIMP nsWebShell::SetupNewViewer(nsIContentViewer* aViewer) { - NS_ENSURE_SUCCESS(FireUnloadEvent(), NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(nsDocShell::SetupNewViewer(aViewer), NS_ERROR_FAILURE); - // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the - // *new* document will fire. - mFiredUnloadEvent = PR_FALSE; - // If the history state has been set by session history, // set it on the pres shell now that we have a content // viewer. @@ -1424,11 +1370,6 @@ NS_IMETHODIMP nsWebShell::Create() NS_IMETHODIMP nsWebShell::Destroy() { - nsresult rv = NS_OK; - - //Fire unload event before we blow anything away. - rv = FireUnloadEvent(); - nsDocShell::Destroy(); SetContainer(nsnull); diff --git a/mozilla/docshell/base/nsWebShell.h b/mozilla/docshell/base/nsWebShell.h index 073a30d6f2e..cb44cfdfbba 100644 --- a/mozilla/docshell/base/nsWebShell.h +++ b/mozilla/docshell/base/nsWebShell.h @@ -84,7 +84,6 @@ public: // nsIWebShellContainer NS_IMETHOD SetHistoryState(nsISupports* aLayoutHistoryState); - NS_IMETHOD FireUnloadEvent(void); // nsILinkHandler NS_IMETHOD OnLinkClick(nsIContent* aContent, @@ -144,16 +143,12 @@ protected: nsIWebShellContainer* mContainer; nsIDocumentLoader* mDocLoader; - PRBool mFiredUnloadEvent; - nsRect mBounds; eCharsetReloadState mCharsetReloadState; nsISupports* mHistoryState; // Weak reference. Session history owns this. - nsresult FireUnloadForChildren(); - nsresult CreateViewer(nsIRequest* request, const char* aContentType, const char* aCommand, diff --git a/mozilla/layout/base/nsDocumentViewer.cpp b/mozilla/layout/base/nsDocumentViewer.cpp index 53f2cc1fb5d..de0d5725719 100644 --- a/mozilla/layout/base/nsDocumentViewer.cpp +++ b/mozilla/layout/base/nsDocumentViewer.cpp @@ -379,6 +379,7 @@ public: NS_IMETHOD GetContainer(nsISupports** aContainerResult); NS_IMETHOD LoadStart(nsISupports* aDoc); NS_IMETHOD LoadComplete(nsresult aStatus); + NS_IMETHOD Unload(void); NS_IMETHOD Destroy(void); NS_IMETHOD Stop(void); NS_IMETHOD GetDOMDocument(nsIDOMDocument **aResult); @@ -1133,6 +1134,37 @@ DocumentViewerImpl::LoadComplete(nsresult aStatus) return rv; } +NS_IMETHODIMP +DocumentViewerImpl::Unload() +{ + nsresult rv; + + if (!mDocument) { + return NS_ERROR_NULL_POINTER; + } + + // First, get the script global object from the document... + nsCOMPtr global; + + rv = mDocument->GetScriptGlobalObject(getter_AddRefs(global)); + if (!global) { + // Fail if no ScriptGlobalObject is available... + NS_ASSERTION(0, "nsIScriptGlobalObject not set for document!"); + return NS_ERROR_NULL_POINTER; + } + + // Now, fire an Unload event to the document... + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + + event.eventStructType = NS_EVENT; + event.message = NS_PAGE_UNLOAD; + rv = global->HandleDOMEvent(mPresContext, &event, nsnull, + NS_EVENT_FLAG_INIT, &status); + + return rv; +} + NS_IMETHODIMP DocumentViewerImpl::Destroy() { diff --git a/mozilla/modules/plugin/base/src/nsPluginViewer.cpp b/mozilla/modules/plugin/base/src/nsPluginViewer.cpp index 9f6a176ea04..c0f908419a8 100644 --- a/mozilla/modules/plugin/base/src/nsPluginViewer.cpp +++ b/mozilla/modules/plugin/base/src/nsPluginViewer.cpp @@ -176,6 +176,7 @@ public: NS_IMETHOD GetContainer(nsISupports** aContainerResult); NS_IMETHOD LoadStart(nsISupports* aDoc); NS_IMETHOD LoadComplete(nsresult aStatus); + NS_IMETHOD Unload(void); NS_IMETHOD Destroy(void); NS_IMETHOD Stop(void); NS_IMETHOD GetDOMDocument(nsIDOMDocument **aResult); @@ -428,6 +429,12 @@ PluginViewerImpl::LoadComplete(nsresult aStatus) return NS_ERROR_FAILURE; } +NS_IMETHODIMP +PluginViewerImpl::Unload(void) +{ + return NS_OK; +} + NS_IMETHODIMP PluginViewerImpl::Destroy(void) { diff --git a/mozilla/modules/plugin/nglsrc/nsPluginViewer.cpp b/mozilla/modules/plugin/nglsrc/nsPluginViewer.cpp index 9f6a176ea04..c0f908419a8 100644 --- a/mozilla/modules/plugin/nglsrc/nsPluginViewer.cpp +++ b/mozilla/modules/plugin/nglsrc/nsPluginViewer.cpp @@ -176,6 +176,7 @@ public: NS_IMETHOD GetContainer(nsISupports** aContainerResult); NS_IMETHOD LoadStart(nsISupports* aDoc); NS_IMETHOD LoadComplete(nsresult aStatus); + NS_IMETHOD Unload(void); NS_IMETHOD Destroy(void); NS_IMETHOD Stop(void); NS_IMETHOD GetDOMDocument(nsIDOMDocument **aResult); @@ -428,6 +429,12 @@ PluginViewerImpl::LoadComplete(nsresult aStatus) return NS_ERROR_FAILURE; } +NS_IMETHODIMP +PluginViewerImpl::Unload(void) +{ + return NS_OK; +} + NS_IMETHODIMP PluginViewerImpl::Destroy(void) { diff --git a/mozilla/webshell/public/nsIWebShell.h b/mozilla/webshell/public/nsIWebShell.h index 68f40ac89c5..9ae10f14752 100644 --- a/mozilla/webshell/public/nsIWebShell.h +++ b/mozilla/webshell/public/nsIWebShell.h @@ -131,11 +131,6 @@ public: * Set the URL of the current WebShell. */ NS_IMETHOD SetURL(const PRUnichar* aURL) = 0; - - /** - * Notify children to fire unload events before root data gone - */ - NS_IMETHOD FireUnloadEvent(void) = 0; }; #endif /* nsIWebShell_h___ */