Bug 416939 - "Broadcast the destruction of DOM windows". r+sr=jst, a=blocking1.9+.

This commit is contained in:
bent.mozilla@gmail.com 2008-02-13 15:41:17 -08:00
parent 18f47ac952
commit 566b83da67
5 changed files with 89 additions and 3 deletions

View File

@ -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<nsPIDOMWindow> window = do_QueryInterface(aSubject);
if (window) {
nsCOMPtr<nsIDocument> 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<nsXULTemplateBuilder> 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<nsXULTemplateBuilder> kungFuDeathGrip(this);
if (mObservedDocument) {
gObserverService->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
mObservedDocument = nsnull;
}
// Break circular references
if (mQueryProcessor)
mQueryProcessor->Done();

View File

@ -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__

View File

@ -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

View File

@ -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<nsIScriptGlobalObject*>(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<nsIScriptGlobalObject*>(this), mSerial, mOuterWindow);
#endif
#ifdef PR_LOGGING
@ -867,6 +872,9 @@ nsGlobalWindow::FreeInnerObjects(PRBool aClearScope)
nsCycleCollector_DEBUG_shouldBeFreed(nsCOMPtr<nsISupports>(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<nsIObserverService> observerService =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
if (observerService) {
observerService->
NotifyObservers(static_cast<nsIScriptGlobalObject*>(aWindow),
DOM_WINDOW_DESTROYED_TOPIC, nsnull);
}
}
void
nsGlobalWindow::InitJavaProperties()
{

View File

@ -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<nsIDOMOfflineResourceList> mApplicationCache;