From 982f9ff69de0dcb360ee4bd714f487dccd89021b Mon Sep 17 00:00:00 2001 From: "bent.mozilla%gmail.com" Date: Wed, 13 Feb 2008 23:41:17 +0000 Subject: [PATCH] Bug 416939 - "Broadcast the destruction of DOM windows". r+sr=jst, a=blocking1.9+. git-svn-id: svn://10.0.0.236/trunk@245649 18797224-902f-48f8-a5cc-f745e15eee43 --- .../templates/src/nsXULTemplateBuilder.cpp | 48 ++++++++++++++++++- .../xul/templates/src/nsXULTemplateBuilder.h | 12 +++++ mozilla/dom/public/base/nsPIDOMWindow.h | 2 + mozilla/dom/src/base/nsGlobalWindow.cpp | 27 ++++++++++- mozilla/dom/src/base/nsGlobalWindow.h | 3 ++ 5 files changed, 89 insertions(+), 3 deletions(-) diff --git a/mozilla/content/xul/templates/src/nsXULTemplateBuilder.cpp b/mozilla/content/xul/templates/src/nsXULTemplateBuilder.cpp index 9c029e8c1d9..a9a38c28405 100644 --- a/mozilla/content/xul/templates/src/nsXULTemplateBuilder.cpp +++ b/mozilla/content/xul/templates/src/nsXULTemplateBuilder.cpp @@ -70,6 +70,7 @@ #include "nsBindingManager.h" #include "nsIDOMNodeList.h" #include "nsINameSpaceManager.h" +#include "nsIObserverService.h" #include "nsIRDFCompositeDataSource.h" #include "nsIRDFInferDataSource.h" #include "nsIRDFContainerUtils.h" @@ -98,6 +99,7 @@ #include "pldhash.h" #include "plhash.h" #include "nsIDOMClassInfo.h" +#include "nsPIDOMWindow.h" #include "nsNetUtil.h" #include "nsXULTemplateBuilder.h" @@ -120,6 +122,7 @@ nsIRDFService* nsXULTemplateBuilder::gRDFService; nsIRDFContainerUtils* nsXULTemplateBuilder::gRDFContainerUtils; nsIScriptSecurityManager* nsXULTemplateBuilder::gScriptSecurityManager; nsIPrincipal* nsXULTemplateBuilder::gSystemPrincipal; +nsIObserverService* nsXULTemplateBuilder::gObserverService; #ifdef PR_LOGGING PRLogModuleInfo* gXULTemplateLog; @@ -135,7 +138,8 @@ PRLogModuleInfo* gXULTemplateLog; nsXULTemplateBuilder::nsXULTemplateBuilder(void) : mQueriesCompiled(PR_FALSE), mFlags(0), - mTop(nsnull) + mTop(nsnull), + mObservedDocument(nsnull) { } @@ -161,6 +165,7 @@ nsXULTemplateBuilder::~nsXULTemplateBuilder(void) NS_IF_RELEASE(gRDFContainerUtils); NS_IF_RELEASE(gSystemPrincipal); NS_IF_RELEASE(gScriptSecurityManager); + NS_IF_RELEASE(gObserverService); } Uninit(PR_TRUE); @@ -191,6 +196,10 @@ nsXULTemplateBuilder::InitGlobals() rv = gScriptSecurityManager->GetSystemPrincipal(&gSystemPrincipal); if (NS_FAILED(rv)) return rv; + + rv = CallGetService(NS_OBSERVERSERVICE_CONTRACTID, &gObserverService); + if (NS_FAILED(rv)) + return rv; } #ifdef PR_LOGGING @@ -227,6 +236,8 @@ nsXULTemplateBuilder::Uninit(PRBool aIsFinal) mMemberVariable = nsnull; mQueriesCompiled = PR_FALSE; + + NS_ASSERTION(!mObservedDocument, "Shouldn't be observing anymore!"); } static PLDHashOperator @@ -286,6 +297,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULTemplateBuilder) NS_INTERFACE_MAP_ENTRY(nsIXULTemplateBuilder) NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver) NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) + NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULTemplateBuilder) NS_INTERFACE_MAP_ENTRY_DOM_CLASSINFO(XULTemplateBuilder) NS_INTERFACE_MAP_END @@ -409,6 +421,10 @@ nsXULTemplateBuilder::Init(nsIContent* aElement) if (NS_SUCCEEDED(rv)) { // Add ourselves as a document observer doc->AddObserver(this); + + mObservedDocument = doc; + gObserverService->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, + PR_FALSE); } return rv; @@ -1029,6 +1045,26 @@ nsXULTemplateBuilder::RemoveListener(nsIXULBuilderListener* aListener) return NS_OK; } +NS_IMETHODIMP +nsXULTemplateBuilder::Observe(nsISupports* aSubject, + const char* aTopic, + const PRUnichar* aData) +{ + // Uuuuber hack to clean up circular references that the cycle collector + // doesn't know about. See bug 394514. + if (!strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC)) { + nsCOMPtr window = do_QueryInterface(aSubject); + if (window) { + nsCOMPtr doc = + do_QueryInterface(window->GetExtantDocument()); + NS_ASSERTION(doc, "Null document, notification came too late?"); + + if (doc == mObservedDocument) + NodeWillBeDestroyed(doc); + } + } + return NS_OK; +} //---------------------------------------------------------------------- // // nsIDocumentOberver interface @@ -1069,6 +1105,11 @@ nsXULTemplateBuilder::ContentRemoved(nsIDocument* aDocument, if (mRoot && nsContentUtils::ContentIsDescendantOf(mRoot, aChild)) { nsRefPtr kungFuDeathGrip(this); + if (mObservedDocument) { + gObserverService->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC); + mObservedDocument = nsnull; + } + if (mQueryProcessor) mQueryProcessor->Done(); @@ -1103,6 +1144,11 @@ nsXULTemplateBuilder::NodeWillBeDestroyed(const nsINode* aNode) // |this|, so hold another reference. nsRefPtr kungFuDeathGrip(this); + if (mObservedDocument) { + gObserverService->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC); + mObservedDocument = nsnull; + } + // Break circular references if (mQueryProcessor) mQueryProcessor->Done(); diff --git a/mozilla/content/xul/templates/src/nsXULTemplateBuilder.h b/mozilla/content/xul/templates/src/nsXULTemplateBuilder.h index 937c8b7a6aa..ea32001c21f 100644 --- a/mozilla/content/xul/templates/src/nsXULTemplateBuilder.h +++ b/mozilla/content/xul/templates/src/nsXULTemplateBuilder.h @@ -46,6 +46,7 @@ #include "nsStubDocumentObserver.h" #include "nsIScriptSecurityManager.h" #include "nsIContent.h" +#include "nsIObserver.h" #include "nsIRDFCompositeDataSource.h" #include "nsIRDFContainer.h" #include "nsIRDFContainerUtils.h" @@ -71,12 +72,14 @@ extern PRLogModuleInfo* gXULTemplateLog; class nsIXULDocument; class nsIRDFCompositeDataSource; +class nsIObserverService; /** * An object that translates an RDF graph into a presentation using a * set of rules. */ class nsXULTemplateBuilder : public nsIXULTemplateBuilder, + public nsIObserver, public nsStubDocumentObserver { public: @@ -99,6 +102,9 @@ public: // nsIXULTemplateBuilder interface NS_DECL_NSIXULTEMPLATEBUILDER + // nsIObserver Interface + NS_DECL_NSIOBSERVER + // nsIMutationObserver NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED @@ -410,6 +416,7 @@ protected: static nsIRDFContainerUtils* gRDFContainerUtils; static nsIScriptSecurityManager* gScriptSecurityManager; static nsIPrincipal* gSystemPrincipal; + static nsIObserverService* gObserverService; enum { eDontTestEmpty = (1 << 0), @@ -488,6 +495,11 @@ protected: virtual void Traverse(nsCycleCollectionTraversalCallback &cb) const { } + + /** + * Document that we're observing. Weak ref! + */ + nsIDocument* mObservedDocument; }; #endif // nsXULTemplateBuilder_h__ diff --git a/mozilla/dom/public/base/nsPIDOMWindow.h b/mozilla/dom/public/base/nsPIDOMWindow.h index 62a338011b3..a86283f6bae 100644 --- a/mozilla/dom/public/base/nsPIDOMWindow.h +++ b/mozilla/dom/public/base/nsPIDOMWindow.h @@ -50,6 +50,8 @@ #include "nsCOMPtr.h" #include "nsEvent.h" +#define DOM_WINDOW_DESTROYED_TOPIC "dom-window-destroyed" + class nsIPrincipal; // Popup control state enum. The values in this enum must go from most diff --git a/mozilla/dom/src/base/nsGlobalWindow.cpp b/mozilla/dom/src/base/nsGlobalWindow.cpp index 0f2bf9d2d39..29330399c15 100644 --- a/mozilla/dom/src/base/nsGlobalWindow.cpp +++ b/mozilla/dom/src/base/nsGlobalWindow.cpp @@ -209,6 +209,7 @@ nsIFactory *nsGlobalWindow::sComputedDOMStyleFactory = nsnull; static nsIEntropyCollector *gEntropyCollector = nsnull; static PRInt32 gRefCnt = 0; +static PRUint32 gSerialCounter = 0; static PRInt32 gOpenPopupSpamCount = 0; static PopupControlState gPopupControlState = openAbused; static PRInt32 gRunningTimeoutDepth = 0; @@ -654,7 +655,10 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector); } #ifdef DEBUG - printf("++DOMWINDOW == %d\n", gRefCnt); + printf("++DOMWINDOW == %d (%p) [serial = %d] [Outer = %p]\n", gRefCnt, + static_cast(this), ++gSerialCounter, + aOuterWindow); + mSerial = gSerialCounter; #endif #ifdef PR_LOGGING @@ -673,7 +677,8 @@ nsGlobalWindow::~nsGlobalWindow() NS_IF_RELEASE(gEntropyCollector); } #ifdef DEBUG - printf("--DOMWINDOW == %d\n", gRefCnt); + printf("--DOMWINDOW == %d (%p) [serial = %d] [Outer = %p]\n", gRefCnt, + static_cast(this), mSerial, mOuterWindow); #endif #ifdef PR_LOGGING @@ -867,6 +872,9 @@ nsGlobalWindow::FreeInnerObjects(PRBool aClearScope) nsCycleCollector_DEBUG_shouldBeFreed(nsCOMPtr(do_QueryInterface(mDocument))); #endif + // Make sure that this is called before we null out the document. + NotifyDOMWindowDestroyed(this); + // Remove our reference to the document and the document principal. mDocument = nsnull; mDoc = nsnull; @@ -1965,6 +1973,9 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell) inner->FreeInnerObjects(PR_TRUE); } + // Make sure that this is called before we null out the document. + NotifyDOMWindowDestroyed(this); + nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal(); if (currentInner) { @@ -5507,6 +5518,18 @@ nsGlobalWindow::IsInModalState() (top.get()))->mModalStateDepth != 0; } +// static +void +nsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow) { + nsCOMPtr observerService = + do_GetService(NS_OBSERVERSERVICE_CONTRACTID); + if (observerService) { + observerService-> + NotifyObservers(static_cast(aWindow), + DOM_WINDOW_DESTROYED_TOPIC, nsnull); + } +} + void nsGlobalWindow::InitJavaProperties() { diff --git a/mozilla/dom/src/base/nsGlobalWindow.h b/mozilla/dom/src/base/nsGlobalWindow.h index 2c96aff1845..ce1116a65d8 100644 --- a/mozilla/dom/src/base/nsGlobalWindow.h +++ b/mozilla/dom/src/base/nsGlobalWindow.h @@ -628,6 +628,8 @@ protected: return aList != &mTimeouts; } + static void NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow); + // When adding new member variables, be careful not to create cycles // through JavaScript. If there is any chance that a member variable // could own objects that are implemented in JavaScript, then those @@ -728,6 +730,7 @@ protected: #ifdef DEBUG PRBool mSetOpenerWindowCalled; + PRUint32 mSerial; #endif nsCOMPtr mApplicationCache;