diff --git a/content/base/public/nsIContent.h b/content/base/public/nsIContent.h index 105be819376a..e9d07e044e72 100644 --- a/content/base/public/nsIContent.h +++ b/content/base/public/nsIContent.h @@ -63,8 +63,8 @@ class nsIDocShell; // IID for the nsIContent interface #define NS_ICONTENT_IID \ -{ 0x36b375cb, 0xf01e, 0x4c18, \ - { 0xbf, 0x9e, 0xba, 0xad, 0x77, 0x1d, 0xce, 0x22 } } +{ 0xe0c5d967, 0x2c15, 0x4097, \ + { 0xb0, 0xdc, 0x75, 0xa3, 0xa7, 0xfc, 0xcd, 0x1a } } // hack to make egcs / gcc 2.95.2 happy class nsIContent_base : public nsINode { @@ -793,6 +793,12 @@ public: */ virtual void UpdateEditableState(); + /** + * Destroy this node and it's children. Ideally this shouldn't be needed + * but for now we need to do it to break cycles. + */ + virtual void DestroyContent() = 0; + #ifdef DEBUG /** * List the content (and anything it contains) out to the given diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index a4605b5c0e27..8886ac7797ea 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -2058,7 +2058,10 @@ SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) SubDocMapEntry *e = static_cast(entry); NS_RELEASE(e->mKey); - NS_IF_RELEASE(e->mSubDocument); + if (e->mSubDocument) { + e->mSubDocument->SetParentDocument(nsnull); + NS_RELEASE(e->mSubDocument); + } } PR_STATIC_CALLBACK(PRBool) @@ -2091,8 +2094,6 @@ nsDocument::SetSubDocumentFor(nsIContent *aContent, nsIDocument* aSubDoc) PL_DHASH_LOOKUP)); if (PL_DHASH_ENTRY_IS_BUSY(entry)) { - entry->mSubDocument->SetParentDocument(nsnull); - PL_DHashTableRawRemove(mSubDocuments, entry); } } @@ -5572,26 +5573,16 @@ nsDocument::Destroy() if (mIsGoingAway) return; - PRInt32 count = mChildren.ChildCount(); - mIsGoingAway = PR_TRUE; - DestroyLinkMap(); - for (PRInt32 indx = 0; indx < count; ++indx) { - // XXXbz what we _should_ do here is to clear mChildren and null out - // mRootContent. If we did this (or at least the latter), we could remove - // the silly null-checks in nsHTMLDocument::MatchLinks. Unfortunately, - // doing that introduces several problems: - // 1) Focus issues (see bug 341730). The fix for bug 303260 may fix these. - // 2) Crashes in OnPageHide if it fires after Destroy. See bug 303260 - // comments 9 and 10. - // So we're just creating an inconsistent DOM for now and hoping. :( - mChildren.ChildAt(indx)->UnbindFromTree(); + + PRUint32 i, count = mChildren.ChildCount(); + for (i = 0; i < count; ++i) { + mChildren.ChildAt(i)->DestroyContent(); } + mLayoutHistoryState = nsnull; nsContentList::OnDocumentDestroy(this); - delete mContentWrapperHash; - mContentWrapperHash = nsnull; } already_AddRefed diff --git a/content/base/src/nsGenericDOMDataNode.cpp b/content/base/src/nsGenericDOMDataNode.cpp index 884bd15f62c1..1eabde52c2b6 100644 --- a/content/base/src/nsGenericDOMDataNode.cpp +++ b/content/base/src/nsGenericDOMDataNode.cpp @@ -811,6 +811,10 @@ nsGenericDOMDataNode::IsNodeOfType(PRUint32 aFlags) const return !(aFlags & ~(eCONTENT | eDATA_NODE)); } +void +nsGenericDOMDataNode::DestroyContent() +{ +} #ifdef DEBUG void diff --git a/content/base/src/nsGenericDOMDataNode.h b/content/base/src/nsGenericDOMDataNode.h index dedcbcd51c95..efeb7fc9cfb5 100644 --- a/content/base/src/nsGenericDOMDataNode.h +++ b/content/base/src/nsGenericDOMDataNode.h @@ -225,6 +225,7 @@ public: PRBool aNotify); virtual PRBool TextIsOnlyWhitespace(); virtual void AppendTextTo(nsAString& aResult); + virtual void DestroyContent(); #ifdef DEBUG virtual void List(FILE* out, PRInt32 aIndent) const; virtual void DumpContent(FILE* out, PRInt32 aIndent, PRBool aDumpAll) const; diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index bc8d699d7a1b..052696acb1d5 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -2857,6 +2857,22 @@ nsGenericElement::GetPrimaryFrameFor(nsIContent* aContent, return presShell->GetPrimaryFrameFor(aContent); } +void +nsGenericElement::DestroyContent() +{ + nsIDocument *document = GetOwnerDoc(); + if (document) { + document->BindingManager()->ChangeDocumentFor(this, document, nsnull); + document->ClearBoxObjectFor(this); + } + + PRUint32 i, count = mAttrsAndChildren.ChildCount(); + for (i = 0; i < count; ++i) { + // The child can remove itself from the parent in BindToTree. + mAttrsAndChildren.ChildAt(i)->DestroyContent(); + } +} + //---------------------------------------------------------------------- // Generic DOMNode implementations @@ -3348,8 +3364,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGenericElement) // Unlink any DOM slots of interest. { nsDOMSlots *slots = tmp->GetExistingDOMSlots(); - if (slots) + if (slots) { slots->mAttributeMap = nsnull; + if (tmp->IsNodeOfType(nsINode::eXUL)) + NS_IF_RELEASE(slots->mControllers); + } } NS_IMPL_CYCLE_COLLECTION_UNLINK_END diff --git a/content/base/src/nsGenericElement.h b/content/base/src/nsGenericElement.h index e61a2fd61e68..b74b29af0324 100644 --- a/content/base/src/nsGenericElement.h +++ b/content/base/src/nsGenericElement.h @@ -434,6 +434,7 @@ public: virtual PRUint32 GetScriptTypeID() const; virtual nsresult SetScriptTypeID(PRUint32 aLang); + virtual void DestroyContent(); #ifdef DEBUG virtual void List(FILE* out, PRInt32 aIndent) const { diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index a64c49b72b06..abe1d00b1e1b 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -3065,6 +3065,17 @@ nsGenericHTMLFrameElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, return rv; } +void +nsGenericHTMLFrameElement::DestroyContent() +{ + if (mFrameLoader) { + mFrameLoader->Destroy(); + mFrameLoader = nsnull; + } + + nsGenericHTMLElement::DestroyContent(); +} + //---------------------------------------------------------------------- void diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h index 56284fafc35d..a418280bfd33 100644 --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -919,6 +919,7 @@ public: virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, const nsAString& aValue, PRBool aNotify); + virtual void DestroyContent(); // nsIDOMNSHTMLElement NS_IMETHOD GetTabIndex(PRInt32 *aTabIndex); diff --git a/content/html/content/src/nsHTMLFormElement.cpp b/content/html/content/src/nsHTMLFormElement.cpp index 513ffad15609..bf94cdabe318 100644 --- a/content/html/content/src/nsHTMLFormElement.cpp +++ b/content/html/content/src/nsHTMLFormElement.cpp @@ -323,7 +323,7 @@ protected: /** The request currently being submitted */ nsCOMPtr mSubmittingRequest; /** The web progress object we are currently listening to */ - nsCOMPtr mWebProgress; + nsWeakPtr mWebProgress; /** The default submit element -- WEAK */ nsIFormControl* mDefaultSubmitElement; @@ -1025,10 +1025,12 @@ nsHTMLFormElement::SubmitSubmission(nsIFormSubmission* aFormSubmission) PRBool pending = PR_FALSE; mSubmittingRequest->IsPending(&pending); if (pending && !schemeIsJavaScript) { - mWebProgress = do_GetInterface(docShell); - NS_ASSERTION(mWebProgress, "nsIDocShell not converted to nsIWebProgress!"); - rv = mWebProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_ALL); + nsCOMPtr webProgress = do_GetInterface(docShell); + NS_ASSERTION(webProgress, "nsIDocShell not converted to nsIWebProgress!"); + rv = webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_ALL); NS_ENSURE_SUBMIT_SUCCESS(rv); + mWebProgress = do_GetWeakReference(webProgress); + NS_ASSERTION(mWebProgress, "can't hold weak ref to webprogress!"); } else { ForgetCurrentSubmission(); } @@ -1645,10 +1647,11 @@ nsHTMLFormElement::ForgetCurrentSubmission() mNotifiedObservers = PR_FALSE; mIsSubmitting = PR_FALSE; mSubmittingRequest = nsnull; - if (mWebProgress) { - mWebProgress->RemoveProgressListener(this); - mWebProgress = nsnull; + nsCOMPtr webProgress = do_QueryReferent(mWebProgress); + if (webProgress) { + webProgress->RemoveProgressListener(this); } + mWebProgress = nsnull; } // nsIWebProgressListener diff --git a/content/xtf/src/nsXTFElementWrapper.cpp b/content/xtf/src/nsXTFElementWrapper.cpp index 2d0eb36e904d..a73f12467930 100644 --- a/content/xtf/src/nsXTFElementWrapper.cpp +++ b/content/xtf/src/nsXTFElementWrapper.cpp @@ -104,8 +104,15 @@ nsXTFElementWrapper::Init() //---------------------------------------------------------------------- // nsISupports implementation -NS_IMPL_ADDREF_INHERITED(nsXTFElementWrapper,nsXTFElementWrapperBase) -NS_IMPL_RELEASE_INHERITED(nsXTFElementWrapper,nsXTFElementWrapperBase) +NS_IMPL_ADDREF_INHERITED(nsXTFElementWrapper, nsXTFElementWrapperBase) +NS_IMPL_RELEASE_INHERITED(nsXTFElementWrapper, nsXTFElementWrapperBase) + +NS_IMPL_CYCLE_COLLECTION_CLASS(nsXTFElementWrapper) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXTFElementWrapper, + nsXTFElementWrapperBase) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXTFElement) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mAttributeHandler) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMETHODIMP nsXTFElementWrapper::QueryInterface(REFNSIID aIID, void** aInstancePtr) diff --git a/content/xtf/src/nsXTFElementWrapper.h b/content/xtf/src/nsXTFElementWrapper.h index b85fae777363..556d633d727f 100644 --- a/content/xtf/src/nsXTFElementWrapper.h +++ b/content/xtf/src/nsXTFElementWrapper.h @@ -65,6 +65,8 @@ public: // nsISupports interface NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsXTFElementWrapper, + nsXTFElementWrapperBase) // nsIXTFElementWrapper NS_DECL_NSIXTFELEMENTWRAPPER diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index cfab65cdc95a..4bea7933f892 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -1447,6 +1447,16 @@ nsXULElement::GetAttrCount() const return count; } +void +nsXULElement::DestroyContent() +{ + nsDOMSlots* slots = GetExistingDOMSlots(); + if (slots) { + NS_IF_RELEASE(slots->mControllers); + } + + nsGenericElement::DestroyContent(); +} #ifdef DEBUG void diff --git a/content/xul/content/src/nsXULElement.h b/content/xul/content/src/nsXULElement.h index aed4c073b3b8..a79edf49c870 100644 --- a/content/xul/content/src/nsXULElement.h +++ b/content/xul/content/src/nsXULElement.h @@ -531,6 +531,7 @@ public: PRBool aNotify); virtual const nsAttrName* GetAttrNameAt(PRUint32 aIndex) const; virtual PRUint32 GetAttrCount() const; + virtual void DestroyContent(); #ifdef DEBUG virtual void List(FILE* out, PRInt32 aIndent) const;