diff --git a/mozilla/content/base/public/nsIContent.h b/mozilla/content/base/public/nsIContent.h index 76434c522da..9f3167132ef 100644 --- a/mozilla/content/base/public/nsIContent.h +++ b/mozilla/content/base/public/nsIContent.h @@ -60,8 +60,8 @@ class nsIURI; // IID for the nsIContent interface #define NS_ICONTENT_IID \ -{ 0x38824dfc, 0x5a2d, 0x4b86, \ - { 0x8c, 0x49, 0xcc, 0xbb, 0x70, 0x03, 0x47, 0x51 } } +{ 0x10caf6a4, 0x8891, 0x46c9, \ + { 0x9b, 0x6c, 0x6d, 0xc8, 0xdf, 0x01, 0x2d, 0x29 } } /** * A node of content in a document's content model. This interface @@ -82,16 +82,51 @@ public: virtual nsIDocument* GetDocument() const = 0; /** - * Set the document for this content. - * - * @param aDocument the new document to set (could be null) - * @param aDeep whether to set the document on children + * Bind this content node to a tree. If this method throws, the caller must + * call UnbindFromTree() on the node. In the typical case of a node being + * appended to a parent, this will be called after the node has been added to + * the parent's child list and before nsIDocumentObserver notifications for + * the addition are dispatched. + * @param aDocument The new document for the content node. Must match the + * current document of aParent, if aParent is not null. + * May not be null if aParent is null. + * @param aParent The new parent for the content node. May be null if the + * node is being bound as a direct child of the document. + * @param aBindingParent The new binding parent for the content node. + * This is allowed to be null. In that case, the + * binding parent of aParent, if any, will be used. * @param aCompileEventHandlers whether to initialize the event handlers in * the document (used by nsXULElement) + * @note either aDocument or aParent must be non-null. If both are null, + * this method _will_ crash. + * @note This method must not be called by consumers of nsIContent on a node + * that is already bound to a tree. Call UnbindFromTree first. + * @note This method will handle rebinding descendants appropriately (eg + * changing their binding parent as needed). + * @note This method does not add the content node to aParent's child list + * @throws NS_ERROR_OUT_OF_MEMORY if that happens */ - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) = 0; + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) = 0; + /** + * Unbind this content node from a tree. This will set its current document + * and binding parent to null. In the typical case of a node being removed + * from a parent, this will be called after it has been removed from the + * parent's child list and after the nsIDocumentObserver notifications for + * the removal have been dispatched. + * @param aDeep Whether to recursively unbind the entire subtree rooted at + * this node. The only time PR_FALSE should be passed is when the + * parent node of the content is being destroyed. + * @param aNullParent Whether to null out the parent pointer as well. This + * is usually desirable. This argument should only be false while + * recursively calling UnbindFromTree when a subtree is detached. + * @note This method is safe to call on nodes that are not bound to a tree. + */ + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE) = 0; + /** * Returns true if the content has an ancestor that is a document. * @@ -128,14 +163,6 @@ public: return NS_REINTERPRET_CAST(nsIContent *, mParentPtrBits & ~kParentBitMask); } - /** - * Set the parent content for this content. (This does not add the child to - * its parent's child list.) This clobbers the low 2 bits of the parent - * pointer, so subclasses which use those bits should override this. - * @param aParent the new parent content to set (could be null) - */ - virtual void SetParent(nsIContent* aParent) = 0; - /** * Get whether this content is C++-generated anonymous content * @see nsIAnonymousContentCreator @@ -198,6 +225,7 @@ public: * @param aNotify whether to notify the document that the insert has * occurred * @param aDeepSetDocument whether to set document on all children of aKid + * XXXbz aDeepSetDocument is now unused */ virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify, PRBool aDeepSetDocument) = 0; @@ -209,6 +237,7 @@ public: * @param aNotify whether to notify the document that the replace has * occurred * @param aDeepSetDocument whether to set document on all children of aKid + * XXXbz aDeepSetDocument is now unused */ virtual nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify, PRBool aDeepSetDocument) = 0; @@ -480,15 +509,6 @@ public: return PR_FALSE; } - /** - * Sets content node with the binding responsible for our construction (and - * existence). Used by anonymous content (XBL-generated). null for all - * explicit content. - * - * @param aContent the new binding parent - */ - virtual nsresult SetBindingParent(nsIContent* aContent) = 0; - /** * Gets content node with the binding responsible for our construction (and * existence). Used by anonymous content (XBL-generated). null for all diff --git a/mozilla/content/base/src/nsAttrAndChildArray.cpp b/mozilla/content/base/src/nsAttrAndChildArray.cpp index 9d59cfae7e9..5d837689ee4 100644 --- a/mozilla/content/base/src/nsAttrAndChildArray.cpp +++ b/mozilla/content/base/src/nsAttrAndChildArray.cpp @@ -617,7 +617,9 @@ nsAttrAndChildArray::Clear() PRUint32 end = slotCount * ATTRSIZE + ChildCount(); for (i = slotCount * ATTRSIZE; i < end; ++i) { nsIContent* child = NS_STATIC_CAST(nsIContent*, mImpl->mBuffer[i]); - child->SetParent(nsnull); // XXX is it better to let the owner do this? + // making this PR_FALSE so tree teardown doesn't end up being + // O(N*D) (number of nodes times average depth of tree). + child->UnbindFromTree(PR_FALSE); // XXX is it better to let the owner do this? NS_RELEASE(child); } diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp index 8b9175c6ce8..82c27afaf51 100644 --- a/mozilla/content/base/src/nsDocument.cpp +++ b/mozilla/content/base/src/nsDocument.cpp @@ -543,13 +543,15 @@ nsDocument::~nsDocument() } if (mRootContent) { - if (mRootContent->GetDocument()) { + if (mRootContent->GetCurrentDoc()) { + NS_ASSERTION(mRootContent->GetCurrentDoc() == this, + "Unexpected current doc in root content"); // The root content still has a pointer back to the document, // clear the document pointer in all children. PRInt32 count = mChildren.Count(); for (indx = 0; indx < count; ++indx) { - mChildren[indx]->SetDocument(nsnull, PR_TRUE, PR_FALSE); + mChildren[indx]->UnbindFromTree(); } } } @@ -751,7 +753,7 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup) for (i = 0; i < count; i++) { nsCOMPtr content = mChildren[i]; - content->SetDocument(nsnull, PR_TRUE, PR_TRUE); + content->UnbindFromTree(); ContentRemoved(nsnull, content, i); } mChildren.Clear(); @@ -1837,7 +1839,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject) mIsGoingAway = PR_TRUE; for (indx = 0; indx < count; ++indx) { - mChildren[indx]->SetDocument(nsnull, PR_TRUE, PR_TRUE); + mChildren[indx]->UnbindFromTree(); } // Propagate the out-of-band notification to each PresShell's @@ -3291,7 +3293,9 @@ nsDocument::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, } indx = mChildren.Count(); - mChildren.AppendObject(content); + if (!mChildren.AppendObject(content)) { + return NS_ERROR_OUT_OF_MEMORY; + } } else { nsCOMPtr refContent(do_QueryInterface(aRefChild)); @@ -3311,7 +3315,9 @@ nsDocument::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; } - mChildren.InsertObjectAt(content, indx); + if (!mChildren.InsertObjectAt(content, indx)) { + return NS_ERROR_OUT_OF_MEMORY; + } } // If we get here, we've succesfully inserted content into the @@ -3320,7 +3326,16 @@ nsDocument::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, mRootContent = content; } - content->SetDocument(this, PR_TRUE, PR_TRUE); + rv = content->BindToTree(this, nsnull, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + mChildren.RemoveObjectAt(indx); + if (mRootContent == content) { + mRootContent = nsnull; + } + content->UnbindFromTree(); + return rv; + } + ContentInserted(nsnull, content, indx); NS_ADDREF(*aReturn = aNewChild); @@ -3371,16 +3386,28 @@ nsDocument::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild, return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; } - ContentRemoved(nsnull, refContent, indx); - refContent->SetDocument(nsnull, PR_TRUE, PR_TRUE); + mChildren.RemoveObjectAt(indx); + + ContentRemoved(nsnull, refContent, indx); + refContent->UnbindFromTree(); - mChildren.ReplaceObjectAt(content, indx); // This is OK because we checked above. if (nodeType == nsIDOMNode::ELEMENT_NODE) { mRootContent = content; } - content->SetDocument(this, PR_TRUE, PR_TRUE); + mChildren.InsertObjectAt(content, indx); + + rv = content->BindToTree(this, nsnull, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + mChildren.RemoveObjectAt(indx); + if (mRootContent == content) { + mRootContent = nsnull; + } + content->UnbindFromTree(); + return rv; + } + ContentInserted(nsnull, content, indx); NS_ADDREF(*aReturn = aNewChild); @@ -3411,7 +3438,7 @@ nsDocument::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn) if (content == mRootContent) mRootContent = nsnull; - content->SetDocument(nsnull, PR_TRUE, PR_TRUE); + content->UnbindFromTree(); *aReturn = aOldChild; NS_ADDREF(aOldChild); diff --git a/mozilla/content/base/src/nsDocumentFragment.cpp b/mozilla/content/base/src/nsDocumentFragment.cpp index 1b68b02e22c..ecb1061a034 100644 --- a/mozilla/content/base/src/nsDocumentFragment.cpp +++ b/mozilla/content/base/src/nsDocumentFragment.cpp @@ -227,7 +227,11 @@ nsDocumentFragment::DisconnectChildren() PRUint32 i, count = GetChildCount(); for (i = 0; i < count; i++) { - GetChildAt(i)->SetParent(nsnull); + NS_ASSERTION(GetChildAt(i)->GetCurrentDoc() == nsnull, + "How did we get a child with a current doc?"); + // Safe to unbind PR_FALSE, since kids should never have a current document + // or a binding parent + GetChildAt(i)->UnbindFromTree(PR_FALSE); } return NS_OK; @@ -237,6 +241,8 @@ NS_IMETHODIMP nsDocumentFragment::ReconnectChildren() { PRUint32 i, count = GetChildCount(); + NS_PRECONDITION(GetCurrentDoc() == nsnull, + "We really shouldn't have a current doc!"); for (i = 0; i < count; i++) { nsIContent *child = GetChildAt(i); @@ -246,6 +252,7 @@ nsDocumentFragment::ReconnectChildren() // This is potentially a O(n**2) operation, but it should only // happen in error cases (such as out of memory or something // similar) so we don't care for now. + // XXXbz I don't think this is O(n**2) with our IndexOf cache, is it? PRInt32 indx = parent->IndexOf(child); @@ -254,7 +261,15 @@ nsDocumentFragment::ReconnectChildren() } } - child->SetParent(this); + nsresult rv = child->BindToTree(nsnull, this, nsnull, PR_FALSE); + if (NS_FAILED(rv)) { + // It's all bad now... Just forget about this kid, I guess + child->UnbindFromTree(); + mAttrsAndChildren.RemoveChildAt(i); + // Adjust count and iterator accordingly + --count; + --i; + } } return NS_OK; diff --git a/mozilla/content/base/src/nsGenericDOMDataNode.cpp b/mozilla/content/base/src/nsGenericDOMDataNode.cpp index b352941d355..5da10b817e9 100644 --- a/mozilla/content/base/src/nsGenericDOMDataNode.cpp +++ b/mozilla/content/base/src/nsGenericDOMDataNode.cpp @@ -590,24 +590,64 @@ nsGenericDOMDataNode::GetDocument() const return GetCurrentDoc(); } -void -nsGenericDOMDataNode::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { + NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!"); + // XXXbz XUL elements are confused about their current doc when they're + // cloned, so we don't assert if aParent is a XUL element and aDocument is + // null, even if aParent->GetCurrentDoc() is non-null + // NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(), + // "aDocument must be current doc of aParent"); + NS_PRECONDITION(!aParent || + (aParent->IsContentOfType(eXUL) && aDocument == nsnull) || + aDocument == aParent->GetCurrentDoc(), + "aDocument must be current doc of aParent"); + NS_PRECONDITION(!GetCurrentDoc(), "Already have a document. Unbind first!"); + // Note that as we recurse into the kids, they'll have a non-null parent. So + // only assert if our parent is _changing_ while we have a parent. + NS_PRECONDITION(!GetParent() || aParent == GetParent(), + "Already have a parent. Unbind first!"); + // XXXbz GetBindingParent() is broken for us, so can't assert + // anything about it yet. + // NS_PRECONDITION(!GetBindingParent() || + // aBindingParent == GetBindingParent() || + // (aParent && + // aParent->GetBindingParent() == GetBindingParent()), + // "Already have a binding parent. Unbind first!"); + + // XXXbz we don't keep track of the binding parent yet. We should. + + // Set parent + PtrBits new_bits = NS_REINTERPRET_CAST(PtrBits, aParent); + new_bits |= mParentPtrBits & nsIContent::kParentBitMask; + mParentPtrBits = new_bits; + + // Set document mDocument = aDocument; if (mDocument && mText.IsBidi()) { - aDocument->SetBidiEnabled(PR_TRUE); + mDocument->SetBidiEnabled(PR_TRUE); } + + NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document"); + NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent"); + // XXXbz GetBindingParent() is broken for us, so can't assert + // anything about it yet. + // NS_POSTCONDITION(aBindingParent = GetBindingParent(), + // "Bound to wrong binding parent"); + + return NS_OK; } void -nsGenericDOMDataNode::SetParent(nsIContent* aParent) +nsGenericDOMDataNode::UnbindFromTree(PRBool aDeep, PRBool aNullParent) { - PtrBits new_bits = NS_REINTERPRET_CAST(PtrBits, aParent); - - new_bits |= mParentPtrBits & nsIContent::kParentBitMask; - - mParentPtrBits = new_bits; + mDocument = nsnull; + if (aNullParent) { + mParentPtrBits &= nsIContent::kParentBitMask; + } } PRBool @@ -921,12 +961,6 @@ nsGenericDOMDataNode::GetBindingParent() const return parent ? parent->GetBindingParent() : nsnull; } -nsresult -nsGenericDOMDataNode::SetBindingParent(nsIContent* aParent) -{ - return NS_OK; -} - PRBool nsGenericDOMDataNode::IsContentOfType(PRUint32 aFlags) const { diff --git a/mozilla/content/base/src/nsGenericDOMDataNode.h b/mozilla/content/base/src/nsGenericDOMDataNode.h index 9147b3eeade..16b41cc5ac9 100644 --- a/mozilla/content/base/src/nsGenericDOMDataNode.h +++ b/mozilla/content/base/src/nsGenericDOMDataNode.h @@ -166,8 +166,11 @@ public: // Implementation for nsIContent nsIDocument* GetDocument() const; - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); PRBool IsInDoc() const { return !!mDocument; @@ -190,7 +193,6 @@ public: return parent ? parent->GetOwnerDoc() : nsnull; } - virtual void SetParent(nsIContent* aParent); virtual PRBool IsNativeAnonymous() const; virtual void SetNativeAnonymous(PRBool aAnonymous); virtual PRInt32 GetNameSpaceID() const; @@ -226,7 +228,6 @@ public: virtual const nsVoidArray *GetRangeList() const; virtual nsIContent *GetBindingParent() const; - virtual nsresult SetBindingParent(nsIContent* aParent); virtual PRBool IsContentOfType(PRUint32 aFlags) const; virtual nsresult GetListenerManager(nsIEventListenerManager **aResult); diff --git a/mozilla/content/base/src/nsGenericElement.cpp b/mozilla/content/base/src/nsGenericElement.cpp index 7cbbffaf100..b7b71e23208 100644 --- a/mozilla/content/base/src/nsGenericElement.cpp +++ b/mozilla/content/base/src/nsGenericElement.cpp @@ -1754,98 +1754,160 @@ nsGenericElement::Normalize() return result; } - -void -nsGenericElement::SetDocumentInChildrenOf(nsIContent* aContent, - nsIDocument* aDocument, - PRBool aCompileEventHandlers) +nsresult +nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - PRUint32 i, n = aContent->GetChildCount(); + NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!"); + // XXXbz XUL elements are confused about their current doc when they're + // cloned, so we don't assert if aParent is a XUL element and aDocument is + // null, even if aParent->GetCurrentDoc() is non-null + // NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(), + // "aDocument must be current doc of aParent"); + NS_PRECONDITION(!aParent || + (aParent->IsContentOfType(eXUL) && aDocument == nsnull) || + aDocument == aParent->GetCurrentDoc(), + "aDocument must be current doc of aParent"); + NS_PRECONDITION(!GetCurrentDoc(), "Already have a document. Unbind first!"); + // Note that as we recurse into the kids, they'll have a non-null parent. So + // only assert if our parent is _changing_ while we have a parent. + NS_PRECONDITION(!GetParent() || aParent == GetParent(), + "Already have a parent. Unbind first!"); + NS_PRECONDITION(!GetBindingParent() || + aBindingParent == GetBindingParent() || + (!aBindingParent && aParent && + aParent->GetBindingParent() == GetBindingParent()), + "Already have a binding parent. Unbind first!"); + + if (!aBindingParent && aParent) { + aBindingParent = aParent->GetBindingParent(); + } - for (i = 0; i < n; ++i) { - nsIContent *child = aContent->GetChildAt(i); + // First set the binding parent + if (aBindingParent) { + nsDOMSlots *slots = GetDOMSlots(); - if (child) { - child->SetDocument(aDocument, PR_TRUE, aCompileEventHandlers); + if (!slots) { + return NS_ERROR_OUT_OF_MEMORY; + } + + slots->mBindingParent = aBindingParent; // Weak, so no addref happens. + } + + // Now set the parent; make sure to preserve the bits we have stashed there + // Note that checking whether aParent == GetParent() is probably not worth it + // here. + PtrBits new_bits = NS_REINTERPRET_CAST(PtrBits, aParent); + new_bits |= mParentPtrBits & nsIContent::kParentBitMask; + mParentPtrBits = new_bits; + + nsresult rv; + + // Finally, set the document + if (aDocument) { + // Notify XBL- & nsIAnonymousContentCreator-generated + // anonymous content that the document is changing. + // XXXbz ordering issues here? Probably not, since ChangeDocumentFor is + // just pretty broken anyway.... Need to get it working. + // XXXbz XBL doesn't handle this (asserts), and we don't really want + // to be doing this during parsing anyway... sort this out. + // aDocument->BindingManager()->ChangeDocumentFor(this, nsnull, + // aDocument); + + // Being added to a document. + mParentPtrBits |= PARENT_BIT_INDOCUMENT; + + // check the document on the nodeinfo to see whether we need a + // new nodeinfo + // XXXbz sXBL/XBL2 issue! + nsIDocument *ownerDocument = GetOwnerDoc(); + if (aDocument != ownerDocument) { + + if (HasProperties()) { + ownerDocument->PropertyTable()->DeleteAllPropertiesFor(this); + } + + // get a new nodeinfo + nsNodeInfoManager* nodeInfoManager = aDocument->NodeInfoManager(); + if (nodeInfoManager) { + nsCOMPtr newNodeInfo; + rv = nodeInfoManager->GetNodeInfo(mNodeInfo->NameAtom(), + mNodeInfo->GetPrefixAtom(), + mNodeInfo->NamespaceID(), + getter_AddRefs(newNodeInfo)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ASSERTION(newNodeInfo, "GetNodeInfo lies"); + mNodeInfo.swap(newNodeInfo); + } } } + + // Now recurse into our kids + PRUint32 i, n = GetChildCount(); + + for (i = 0; i < n; ++i) { + rv = mAttrsAndChildren.ChildAt(i)->BindToTree(aDocument, this, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + } + + // XXXbz script execution during binding can trigger some of these + // postcondition asserts.... But we do want that, since things will + // generally be quite broken when that happens. + NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document"); + NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent"); + NS_POSTCONDITION(aBindingParent == GetBindingParent(), + "Bound to wrong binding parent"); + + return NS_OK; } void -nsGenericElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsGenericElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) { + NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()), + "Shallow unbind won't clear document and binding parent on " + "kids!"); + // Make sure to unbind this node before doing the kids nsIDocument *document = GetCurrentDoc(); - if (aDocument != document) { - // If we were part of a document, make sure we get rid of the - // script context reference to our script object so that our - // script object can be freed (or collected). + if (document) { + // Notify XBL- & nsIAnonymousContentCreator-generated + // anonymous content that the document is changing. + document->BindingManager()->ChangeDocumentFor(this, document, nsnull); - if (document && aDeep) { - // Notify XBL- & nsIAnonymousContentCreator-generated - // anonymous content that the document is changing. - document->BindingManager()->ChangeDocumentFor(this, document, aDocument); + nsCOMPtr domElement = do_QueryInterface(this); - nsCOMPtr domElement; - QueryInterface(NS_GET_IID(nsIDOMElement), getter_AddRefs(domElement)); - - if (domElement) { - nsCOMPtr nsDoc(do_QueryInterface(document)); - nsDoc->SetBoxObjectFor(domElement, nsnull); - } + if (domElement) { + nsCOMPtr nsDoc = do_QueryInterface(document); + nsDoc->SetBoxObjectFor(domElement, nsnull); } + } - if (aDocument) { - mParentPtrBits |= PARENT_BIT_INDOCUMENT; - - // check the document on the nodeinfo to see whether we need a - // new nodeinfo - // XXXbz sXBL/XBL2 issue! - nsIDocument *ownerDocument = GetOwnerDoc(); - if (aDocument != ownerDocument) { - - if (HasProperties()) { - ownerDocument->PropertyTable()->DeleteAllPropertiesFor(this); - } - - // get a new nodeinfo - nsNodeInfoManager* nodeInfoManager = aDocument->NodeInfoManager(); - if (nodeInfoManager) { - nsCOMPtr newNodeInfo; - nodeInfoManager->GetNodeInfo(mNodeInfo->NameAtom(), - mNodeInfo->GetPrefixAtom(), - mNodeInfo->NamespaceID(), - getter_AddRefs(newNodeInfo)); - if (newNodeInfo) { - mNodeInfo.swap(newNodeInfo); - } - } - } - } - else { - mParentPtrBits &= ~PARENT_BIT_INDOCUMENT; - } + // Unset things in the reverse order from how we set them in BindToTree + mParentPtrBits &= ~PARENT_BIT_INDOCUMENT; + + if (aNullParent) { + // Just mask it out + mParentPtrBits &= nsIContent::kParentBitMask; + } + + nsDOMSlots *slots = GetExistingDOMSlots(); + if (slots) { + slots->mBindingParent = nsnull; } if (aDeep) { - SetDocumentInChildrenOf(this, aDocument, aCompileEventHandlers); - } -} + // Do the kids + PRUint32 i, n = GetChildCount(); - -void -nsGenericElement::SetParent(nsIContent* aParent) -{ - PtrBits new_bits = NS_REINTERPRET_CAST(PtrBits, aParent); - - new_bits |= mParentPtrBits & nsIContent::kParentBitMask; - - mParentPtrBits = new_bits; - - if (aParent) { - nsIContent* bindingPar = aParent->GetBindingParent(); - if (bindingPar) - SetBindingParent(bindingPar); + for (i = 0; i < n; ++i) { + // Note that we pass PR_FALSE for aNullParent here, since we don't want + // the kids to forget us. We _do_ want them to forget their binding + // parent, though, since this only walks non-anonymous kids. + mAttrsAndChildren.ChildAt(i)->UnbindFromTree(PR_TRUE, PR_FALSE); + } } } @@ -2505,30 +2567,6 @@ nsGenericElement::GetBindingParent() const return nsnull; } -nsresult -nsGenericElement::SetBindingParent(nsIContent* aParent) -{ - nsDOMSlots *slots = GetDOMSlots(); - - if (!slots) { - return NS_ERROR_OUT_OF_MEMORY; - } - - slots->mBindingParent = aParent; // Weak, so no addref happens. - - nsresult rv = NS_OK; - - if (aParent) { - PRUint32 count = GetChildCount(); - - for (PRUint32 i = 0; i < count; ++i) { - rv |= GetChildAt(i)->SetBindingParent(aParent); - } - } - - return rv; -} - PRBool nsGenericElement::IsContentOfType(PRUint32 aFlags) const { @@ -2618,10 +2656,22 @@ nsGenericElement::InsertChildAt(nsIContent* aKid, nsresult rv = mAttrsAndChildren.InsertChildAt(aKid, aIndex); NS_ENSURE_SUCCESS(rv, rv); - aKid->SetParent(this); + rv = aKid->BindToTree(document, this, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + mAttrsAndChildren.RemoveChildAt(aIndex); + aKid->UnbindFromTree(); + return rv; + } + nsRange::OwnerChildInserted(this, aIndex); - if (document) { - aKid->SetDocument(document, aDeepSetDocument, PR_TRUE); + // The kid may have removed us from the document, so recheck that we're still + // in the document before proceeding. Also, the kid may have just removed + // itself, in which case we don't really want to fire ContentAppended or a + // mutation event. + // XXXbz What if the kid just moved us in the document? Scripts suck. We + // really need to stop running them while we're in the middle of modifying + // the DOM.... + if (document && document == GetCurrentDoc() && aKid->GetParent() == this) { if (aNotify) { if (isAppend) { document->ContentAppended(this, aIndex); @@ -2653,11 +2703,22 @@ nsGenericElement::AppendChildTo(nsIContent* aKid, PRBool aNotify, nsresult rv = mAttrsAndChildren.AppendChild(aKid); NS_ENSURE_SUCCESS(rv, rv); - aKid->SetParent(this); + rv = aKid->BindToTree(document, this, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + mAttrsAndChildren.RemoveChildAt(GetChildCount() - 1); + aKid->UnbindFromTree(); + return rv; + } // ranges don't need adjustment since new child is at end of list - if (document) { - aKid->SetDocument(document, aDeepSetDocument, PR_TRUE); + // The kid may have removed us from the document, so recheck that we're still + // in the document before proceeding. Also, the kid may have just removed + // itself, in which case we don't really want to fire ContentAppended or a + // mutation event. + // XXXbz What if the kid just moved us in the document? Scripts suck. We + // really need to stop running them while we're in the middle of modifying + // the DOM.... + if (document && document == GetCurrentDoc() && aKid->GetParent() == this) { if (aNotify) { document->ContentAppended(this, GetChildCount() - 1); } @@ -2699,8 +2760,7 @@ nsGenericElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify) document->ContentRemoved(this, oldKid, aIndex); } - oldKid->SetDocument(nsnull, PR_TRUE, PR_TRUE); - oldKid->SetParent(nsnull); + oldKid->UnbindFromTree(); } return NS_OK; @@ -3267,7 +3327,9 @@ nsGenericElement::AddScriptEventListener(nsIAtom* aAttribute, // If we have a document, and it has a script global, add the // event listener on the global. If not, proceed as normal. - nsIDocument *document = GetCurrentDoc(); + // XXXbz should we instead use GetCurrentDoc() here, override + // BindToTree for those classes and munge event listeners there? + nsIDocument *document = GetOwnerDoc(); if (document && (sgo = document->GetScriptGlobalObject())) { nsCOMPtr receiver(do_QueryInterface(sgo)); NS_ENSURE_TRUE(receiver, NS_ERROR_FAILURE); diff --git a/mozilla/content/base/src/nsGenericElement.h b/mozilla/content/base/src/nsGenericElement.h index 731f15990cc..5c6536f61b1 100644 --- a/mozilla/content/base/src/nsGenericElement.h +++ b/mozilla/content/base/src/nsGenericElement.h @@ -372,8 +372,11 @@ public: { return IsInDoc() ? GetOwnerDoc() : nsnull; } - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); PRBool IsInDoc() const { return mParentPtrBits & PARENT_BIT_INDOCUMENT; @@ -382,7 +385,6 @@ public: { return nsContentUtils::GetDocument(mNodeInfo); } - virtual void SetParent(nsIContent* aParent); virtual PRBool IsNativeAnonymous() const; virtual void SetNativeAnonymous(PRBool aAnonymous); virtual PRInt32 GetNameSpaceID() const; @@ -426,7 +428,6 @@ public: virtual void SetContentID(PRUint32 aID); virtual void SetFocus(nsPresContext* aContext); virtual nsIContent *GetBindingParent() const; - virtual nsresult SetBindingParent(nsIContent* aParent); virtual PRBool IsContentOfType(PRUint32 aFlags) const; virtual nsresult GetListenerManager(nsIEventListenerManager** aResult); virtual already_AddRefed GetBaseURI() const; diff --git a/mozilla/content/base/src/nsTextNode.cpp b/mozilla/content/base/src/nsTextNode.cpp index 03e2cbf3c60..68b99ddf43a 100644 --- a/mozilla/content/base/src/nsTextNode.cpp +++ b/mozilla/content/base/src/nsTextNode.cpp @@ -117,13 +117,12 @@ public: virtual ~nsAttributeTextNode() { DetachListener(); } - - virtual void SetParent(nsIContent* aParent) { - if (!aParent) { - DetachListener(); - } - nsTextNode::SetParent(aParent); - } + + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); nsRefPtr mListener; // our listener private: @@ -305,10 +304,9 @@ nsAttributeTextNode::nsAttrChangeListener::HandleEvent(nsIDOMEvent* aEvent) } nsresult -NS_NewAttributeContent(nsIContent* aContent, PRInt32 aNameSpaceID, - nsIAtom* aAttrName, nsIContent** aResult) +NS_NewAttributeContent(PRInt32 aNameSpaceID, nsIAtom* aAttrName, + nsIContent** aResult) { - NS_PRECONDITION(aContent, "Must have parent content"); NS_PRECONDITION(aAttrName, "Must have an attr name"); NS_PRECONDITION(aNameSpaceID != kNameSpaceID_Unknown, "Must know namespace"); @@ -317,47 +315,73 @@ NS_NewAttributeContent(nsIContent* aContent, PRInt32 aNameSpaceID, nsRefPtr textNode = new nsAttributeTextNode(); NS_ENSURE_TRUE(textNode, NS_ERROR_OUT_OF_MEMORY); - nsCOMPtr eventTarget(do_QueryInterface(aContent)); - NS_ENSURE_TRUE(eventTarget, NS_ERROR_UNEXPECTED); - - nsRefPtr listener = + textNode->mListener = new nsAttributeTextNode::nsAttrChangeListener(aNameSpaceID, aAttrName, textNode); - NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); - - nsresult rv = eventTarget->AddEventListener(NS_LITERAL_STRING("DOMAttrModified"), - listener, - PR_FALSE); - NS_ENSURE_SUCCESS(rv, rv); - - nsAutoString attrValue; - aContent->GetAttr(aNameSpaceID, aAttrName, attrValue); - textNode->SetData(attrValue); - - textNode->SetParent(aContent); - textNode->mListener = listener; // Now textNode going away will detach the listener automatically. + NS_ENSURE_TRUE(textNode->mListener, NS_ERROR_OUT_OF_MEMORY); NS_ADDREF(*aResult = textNode); return NS_OK; } +nsresult +nsAttributeTextNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) +{ + NS_PRECONDITION(aParent, "This node can't be a child of the document"); + + nsresult rv = nsTextNode::BindToTree(aDocument, aParent, + aBindingParent, aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + + if (mListener) { + // Attach it to the new parent + + nsCOMPtr eventTarget(do_QueryInterface(aParent)); + NS_ENSURE_TRUE(eventTarget, NS_ERROR_UNEXPECTED); + + rv = eventTarget->AddEventListener(NS_LITERAL_STRING("DOMAttrModified"), + mListener, + PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoString attrValue; + aParent->GetAttr(mListener->mNameSpaceID, mListener->mAttrName, + attrValue); + SetData(attrValue); + } + + return NS_OK; +} + +void +nsAttributeTextNode::UnbindFromTree(PRBool aDeep, PRBool aNullParent) +{ + // Detach the listener while we know who our parent is! + if (aNullParent) { + DetachListener(); + } + nsTextNode::UnbindFromTree(aDeep, aNullParent); +} + void nsAttributeTextNode::DetachListener() { if (!mListener) return; - NS_ASSERTION(GetParent(), "How did our parent go away while we still have an observer?"); - nsCOMPtr target(do_QueryInterface(GetParent())); + if (target) { #ifdef DEBUG - nsresult rv = + nsresult rv = #endif - target->RemoveEventListener(NS_LITERAL_STRING("DOMAttrModified"), - mListener, - PR_FALSE); - NS_ASSERTION(NS_SUCCEEDED(rv), "'Leaking' listener for lifetime of this page"); + target->RemoveEventListener(NS_LITERAL_STRING("DOMAttrModified"), + mListener, + PR_FALSE); + NS_ASSERTION(NS_SUCCEEDED(rv), "'Leaking' listener for lifetime of this page"); + } mListener->mContent = nsnull; // Make it forget us mListener = nsnull; // Goodbye, listener } diff --git a/mozilla/content/html/content/src/nsGenericHTMLElement.cpp b/mozilla/content/html/content/src/nsGenericHTMLElement.cpp index 0d09a88996b..9c5e0c4bdd2 100644 --- a/mozilla/content/html/content/src/nsGenericHTMLElement.cpp +++ b/mozilla/content/html/content/src/nsGenericHTMLElement.cpp @@ -1317,22 +1317,30 @@ nsGenericHTMLElement::InNavQuirksMode(nsIDocument* aDoc) return doc->GetCompatibilityMode() == eCompatibility_NavQuirks; } -void -nsGenericHTMLElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsIDocument *document = GetCurrentDoc(); - PRBool doNothing = aDocument == document; // short circuit useless work - - nsGenericElement::SetDocument(aDocument, aDeep, aCompileEventHandlers); + nsresult rv = nsGenericElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + // XXXbz if we already have a style attr parsed, this won't do + // anything... need to fix that. ReparseStyleAttribute(); - if (!doNothing && aDocument) { + + if (aDocument) { + // If we're in a document now, let our mapped attrs know what their new + // sheet is. nsHTMLStyleSheet* sheet = aDocument->GetAttributeStyleSheet(); if (sheet) { mAttrsAndChildren.SetMappedAttrStyleSheet(sheet); } } + + return rv; } already_AddRefed @@ -1951,7 +1959,7 @@ nsGenericHTMLElement::GetInlineStyleRule() if (attrVal->Type() != nsAttrValue::eCSSStyleRule) { ReparseStyleAttribute(); attrVal = mAttrsAndChildren.GetAttr(nsHTMLAtoms::style); - // hopefully value.GetUnit() is now eHTMLUnit_CSSStyleRule + // hopefully attrVal->Type() is now nsAttrValue::eCSSStyleRule } if (attrVal->Type() == nsAttrValue::eCSSStyleRule) { @@ -2597,11 +2605,7 @@ nsGenericHTMLElement::ParseStyleAttribute(nsIContent* aContent, nsresult result = NS_OK; NS_ASSERTION(aContent->GetNodeInfo(), "If we don't have a nodeinfo, we are very screwed"); - // XXX GetOwnerDoc - nsIDocument* doc = aContent->GetDocument(); - if (!doc) { - doc = nsContentUtils::GetDocument(aContent->GetNodeInfo()); - } + nsIDocument* doc = aContent->GetOwnerDoc(); if (doc) { PRBool isCSS = PR_TRUE; // assume CSS until proven otherwise @@ -3240,56 +3244,53 @@ nsGenericHTMLFrameElement::IsFocusable(PRInt32 *aTabIndex) return isFocusable; } -void -nsGenericHTMLFormElement::SetParent(nsIContent* aParent) +nsresult +nsGenericHTMLFormElement::BindToTree(nsIDocument* aDocument, + nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - // If we do any finding of the form, we need to do it after we've - // called SetParent on the superclass. - PRBool findForm = PR_FALSE; - if (!aParent && mForm) { - SetForm(nsnull); - } else if (aParent && (GetParent() || !mForm)) { - // If we have a new parent and either we had an old parent or we - // don't have a form, search for a containing form. If we didn't - // have an old parent, but we do have a form, we shouldn't do the - // search. In this case, someone (possibly the content sink) has - // already set the form for us. - findForm = PR_TRUE; - } + nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); - nsGenericHTMLElement::SetParent(aParent); - - if (findForm) { + if (!mForm && aParent) { + // We now have a parent, so we may have picked up an ancestor form. Search + // for it. Note that if mForm is already set we don't want to do this, + // because that means someone (probably the content sink) has already set + // it to the right value. Also note that even if being bound here didn't + // change our parent, we still need to search, since our parent chain + // probably changed _somewhere_. FindAndSetForm(); } + + return rv; } void -nsGenericHTMLFormElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsGenericHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) { - // Save state before doing anything if the document is being removed - if (!aDocument) { - SaveState(); - } + // Save state before doing anything + SaveState(); - if (aDocument && GetParent() && !mForm) { - FindAndSetForm(); - } else if (!aDocument && mForm) { - // We got removed from document. We have a parent form. Check - // that the form is still in the document, and if so remove - // ourselves from the form. This keeps ghosts from appearing in - // the form's |elements| array - nsCOMPtr formContent(do_QueryInterface(mForm)); - if (formContent && formContent->GetDocument()) { + if (mForm) { + // Might need to unset mForm + if (aNullParent) { + // No more parent means no more form SetForm(nsnull); + } else { + // Recheck whether we should still have an mForm. + nsCOMPtr form = FindForm(); + if (!form) { + SetForm(nsnull); + } } } - nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers); + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); } - nsresult nsGenericHTMLFormElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, const nsAString& aValue, @@ -3464,30 +3465,29 @@ nsGenericHTMLFrameElement::LoadSrc() return rv; } -void -nsGenericHTMLFrameElement::SetParent(nsIContent *aParent) +nsresult +nsGenericHTMLFrameElement::BindToTree(nsIDocument* aDocument, + nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsGenericHTMLElement::SetParent(aParent); + nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); - // When parent is being set to null on the element's destruction, do not - // call LoadSrc(). - if (!GetParent() || !IsInDoc()) { - return; + if (aDocument) { + // We're in a document now. Kick off the frame load. + LoadSrc(); } - - LoadSrc(); + + return rv; } void -nsGenericHTMLFrameElement::SetDocument(nsIDocument *aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsGenericHTMLFrameElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) { - const nsIDocument *old_doc = GetCurrentDoc(); - - nsGenericHTMLElement::SetDocument(aDocument, aDeep, - aCompileEventHandlers); - - if (!aDocument && mFrameLoader) { + if (mFrameLoader) { // This iframe is being taken out of the document, destroy the // iframe's frame loader (doing that will tear down the window in // this iframe). @@ -3498,12 +3498,7 @@ nsGenericHTMLFrameElement::SetDocument(nsIDocument *aDocument, PRBool aDeep, mFrameLoader = nsnull; } - // When document is being set to null on the element's destruction, - // or when the document is being set to what the document already - // is, do not call LoadSrc(). - if (GetParent() && aDocument && aDocument != old_doc) { - LoadSrc(); - } + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); } nsresult diff --git a/mozilla/content/html/content/src/nsGenericHTMLElement.h b/mozilla/content/html/content/src/nsGenericHTMLElement.h index 67a9e7e8966..f124d4f538b 100644 --- a/mozilla/content/html/content/src/nsGenericHTMLElement.h +++ b/mozilla/content/html/content/src/nsGenericHTMLElement.h @@ -181,8 +181,9 @@ public: static const nsSize GetClientAreaSize(nsIFrame *aFrame); // Implementation for nsIContent - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, PRBool aNotify) { @@ -829,10 +830,11 @@ public: } // nsIContent - virtual void SetParent(nsIContent *aParent); - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); - + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, PRBool aNotify) { @@ -887,9 +889,11 @@ public: // nsIContent virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull); - virtual void SetParent(nsIContent *aParent); - virtual void SetDocument(nsIDocument *aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, PRBool aNotify) { diff --git a/mozilla/content/html/content/src/nsHTMLAnchorElement.cpp b/mozilla/content/html/content/src/nsHTMLAnchorElement.cpp index 491de72b898..c29221e7a6b 100644 --- a/mozilla/content/html/content/src/nsHTMLAnchorElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLAnchorElement.cpp @@ -98,8 +98,11 @@ public: NS_IMETHOD SetLinkState(nsLinkState aState); NS_IMETHOD GetHrefURI(nsIURI** aURI); - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); virtual void SetFocus(nsPresContext* aPresContext); virtual PRBool IsFocusable(PRBool *aTabIndex = nsnull); @@ -168,24 +171,31 @@ NS_IMPL_STRING_ATTR(nsHTMLAnchorElement, Type, type) NS_IMPL_STRING_ATTR(nsHTMLAnchorElement, AccessKey, accesskey) -void -nsHTMLAnchorElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsHTMLAnchorElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsIDocument *document = GetCurrentDoc(); - PRBool documentChanging = (aDocument != document); - - // Unregister the access key for the old document. - if (documentChanging && document) { + nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + + if (aDocument) { + RegUnRegAccessKey(PR_TRUE); + } + + return rv; +} + +void +nsHTMLAnchorElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) +{ + if (IsInDoc()) { RegUnRegAccessKey(PR_FALSE); } - nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers); - - // Register the access key for the new document. - if (documentChanging && aDocument) { - RegUnRegAccessKey(PR_TRUE); - } + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); } NS_IMETHODIMP @@ -245,7 +255,6 @@ nsHTMLAnchorElement::IsFocusable(PRInt32 *aTabIndex) return PR_FALSE; } - PRBool isFocusable = PR_FALSE; if (!HasAttr(kNameSpaceID_None, nsHTMLAtoms::tabindex)) { // check whether we're actually a link nsCOMPtr linkURI = nsContentUtils::GetLinkURI(this); diff --git a/mozilla/content/html/content/src/nsHTMLAreaElement.cpp b/mozilla/content/html/content/src/nsHTMLAreaElement.cpp index a5b847316e6..06d9c5e915f 100644 --- a/mozilla/content/html/content/src/nsHTMLAreaElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLAreaElement.cpp @@ -88,8 +88,11 @@ public: nsEventStatus* aEventStatus); virtual void SetFocus(nsPresContext* aPresContext); - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, PRBool aNotify) { @@ -201,24 +204,31 @@ nsHTMLAreaElement::SetFocus(nsPresContext* aPresContext) } } -void -nsHTMLAreaElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsHTMLAreaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsIDocument *document = GetCurrentDoc(); - PRBool documentChanging = (aDocument != document); - - // Unregister the access key for the old document. - if (documentChanging && document) { + nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + + if (aDocument) { + RegUnRegAccessKey(PR_TRUE); + } + + return rv; +} + +void +nsHTMLAreaElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) +{ + if (IsInDoc()) { RegUnRegAccessKey(PR_FALSE); } - nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers); - - // Register the access key for the new document. - if (documentChanging && aDocument) { - RegUnRegAccessKey(PR_TRUE); - } + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); } nsresult diff --git a/mozilla/content/html/content/src/nsHTMLBodyElement.cpp b/mozilla/content/html/content/src/nsHTMLBodyElement.cpp index 7cd12df5ef7..1c3ca3ae602 100644 --- a/mozilla/content/html/content/src/nsHTMLBodyElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLBodyElement.cpp @@ -109,8 +109,8 @@ public: virtual PRBool ParseAttribute(nsIAtom* aAttribute, const nsAString& aValue, nsAttrValue& aResult); - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker); NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const; @@ -413,17 +413,16 @@ nsHTMLBodyElement::ParseAttribute(nsIAtom* aAttribute, } void -nsHTMLBodyElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsHTMLBodyElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) { - nsIDocument *document = GetCurrentDoc(); - if (aDocument != document && mContentStyleRule) { + if (mContentStyleRule) { mContentStyleRule->mPart = nsnull; - // destroy old style rule since the sheet will probably change + // destroy old style rule NS_RELEASE(mContentStyleRule); } - nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers); + + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); } static diff --git a/mozilla/content/html/content/src/nsHTMLFormElement.cpp b/mozilla/content/html/content/src/nsHTMLFormElement.cpp index d14f583ed22..20a9e1851a6 100644 --- a/mozilla/content/html/content/src/nsHTMLFormElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLFormElement.cpp @@ -171,8 +171,11 @@ public: nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, nsEventStatus* aEventStatus); - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, PRBool aNotify) { @@ -614,25 +617,36 @@ nsHTMLFormElement::ParseAttribute(nsIAtom* aAttribute, return nsGenericHTMLElement::ParseAttribute(aAttribute, aValue, aResult); } -void -nsHTMLFormElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsHTMLFormElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsCOMPtr oldDocument = do_QueryInterface(GetCurrentDoc()); - nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers); - - nsCOMPtr newDocument = do_QueryInterface(GetCurrentDoc()); - if (oldDocument != newDocument) { - if (oldDocument) { - oldDocument->RemovedForm(); - ForgetCurrentSubmission(); - } - if (newDocument) { - newDocument->AddedForm(); - } + nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr htmlDoc(do_QueryInterface(aDocument)); + if (htmlDoc) { + htmlDoc->AddedForm(); } + + return rv; } +void +nsHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) +{ + nsCOMPtr oldDocument = do_QueryInterface(GetCurrentDoc()); + + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); + + if (oldDocument) { + oldDocument->RemovedForm(); + } + ForgetCurrentSubmission(); +} nsresult nsHTMLFormElement::HandleDOMEvent(nsPresContext* aPresContext, diff --git a/mozilla/content/html/content/src/nsHTMLImageElement.cpp b/mozilla/content/html/content/src/nsHTMLImageElement.cpp index ce24d439123..966aec38842 100644 --- a/mozilla/content/html/content/src/nsHTMLImageElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLImageElement.cpp @@ -141,9 +141,9 @@ public: // XXXbz What about UnsetAttr? We don't seem to unload images when // that happens... - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); - virtual void SetParent(nsIContent* aParent); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); protected: void GetImageFrame(nsIImageFrame** aImageFrame); @@ -581,37 +581,25 @@ nsHTMLImageElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, aNotify); } -void -nsHTMLImageElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsHTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - PRBool documentChanging = aDocument && aDocument != GetCurrentDoc(); - - nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers); - if (documentChanging && GetParent()) { - // Our base URI may have changed; claim that our URI changed, and the - // nsImageLoadingContent will decide whether a new image load is warranted. - nsAutoString uri; - nsresult result = GetAttr(kNameSpaceID_None, nsHTMLAtoms::src, uri); - if (result == NS_CONTENT_ATTR_HAS_VALUE) { - ImageURIChanged(uri); - } - } -} + nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); -void -nsHTMLImageElement::SetParent(nsIContent* aParent) -{ - nsGenericHTMLElement::SetParent(aParent); - if (aParent && IsInDoc()) { - // Our base URI may have changed; claim that our URI changed, and the - // nsImageLoadingContent will decide whether a new image load is warranted. - nsAutoString uri; - nsresult result = GetAttr(kNameSpaceID_None, nsHTMLAtoms::src, uri); - if (result == NS_CONTENT_ATTR_HAS_VALUE) { - ImageURIChanged(uri); - } + // Our base URI may have changed; claim that our URI changed, and the + // nsImageLoadingContent will decide whether a new image load is warranted. + nsAutoString uri; + nsresult result = GetAttr(kNameSpaceID_None, nsHTMLAtoms::src, uri); + if (result == NS_CONTENT_ATTR_HAS_VALUE) { + ImageURIChanged(uri); } + + return rv; } NS_IMETHODIMP diff --git a/mozilla/content/html/content/src/nsHTMLInputElement.cpp b/mozilla/content/html/content/src/nsHTMLInputElement.cpp index 9fd9ae60917..fa9c94046c0 100644 --- a/mozilla/content/html/content/src/nsHTMLInputElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLInputElement.cpp @@ -187,10 +187,12 @@ public: nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, nsEventStatus* aEventStatus); - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); - virtual void SetParent(nsIContent* aParent); - + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); + nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, PRBool aNotify) { @@ -896,9 +898,7 @@ nsHTMLInputElement::GetRadioGroupContainer() nsIRadioGroupContainer* retval = nsnull; if (mForm) { CallQueryInterface(mForm, &retval); - } else if (GetParent()) { - // XXXbz the GetParent() check is needed because we sometimes have a doc - // when we're not really in one, I think... Need BindToTree! + } else { nsIDocument* currentDoc = GetCurrentDoc(); if (currentDoc) { CallQueryInterface(currentDoc, &retval); @@ -1674,24 +1674,17 @@ nsHTMLInputElement::HandleDOMEvent(nsPresContext* aPresContext, } -void -nsHTMLInputElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsHTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - PRBool documentChanging = (aDocument != GetCurrentDoc()); + nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); - // SetDocument() sets the form and that takes care of form's WillRemove - // so we just have to take care of the case where we're removing from the - // document and we don't have a form - if (documentChanging && !mForm && mType == NS_FORM_INPUT_RADIO) { - WillRemoveFromRadioGroup(); - } - - nsGenericHTMLFormElement::SetDocument(aDocument, aDeep, - aCompileEventHandlers); - - if (mType == NS_FORM_INPUT_IMAGE && - documentChanging && aDocument && GetParent()) { + if (mType == NS_FORM_INPUT_IMAGE) { // Our base URI may have changed; claim that our URI changed, and the // nsImageLoadingContent will decide whether a new image load is warranted. nsAutoString uri; @@ -1700,12 +1693,15 @@ nsHTMLInputElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, ImageURIChanged(uri); } } - + // If this is radio button which is in a form, // and the parser is still creating the element. + // XXXbz hmmm Do we need this BF_PARSER_CREATING thing? I suspect + // we don't and that it was a hackaround around the way-early + // SetDocument call in the parser. if (mForm || mType != NS_FORM_INPUT_RADIO || GET_BOOLBIT(mBitField, BF_PARSER_CREATING)) { - return; + return rv; } // Add radio to document if we don't have a form already (if we do it's @@ -1713,21 +1709,23 @@ nsHTMLInputElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, if (aDocument && !mForm && mType == NS_FORM_INPUT_RADIO) { AddedToRadioGroup(); } + + return rv; } void -nsHTMLInputElement::SetParent(nsIContent* aParent) +nsHTMLInputElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) { - nsGenericHTMLFormElement::SetParent(aParent); - if (mType == NS_FORM_INPUT_IMAGE && aParent && IsInDoc()) { - // Our base URI may have changed; claim that our URI changed, and the - // nsImageLoadingContent will decide whether a new image load is warranted. - nsAutoString uri; - nsresult result = GetAttr(kNameSpaceID_None, nsHTMLAtoms::src, uri); - if (result == NS_CONTENT_ATTR_HAS_VALUE) { - ImageURIChanged(uri); - } + // If we have a form and are unbound from it, + // nsGenericHTMLFormElement::SetDocument() will unset the form and + // that takes care of form's WillRemove so we just have to take care + // of the case where we're removing from the document and we don't + // have a form + if (!mForm && mType == NS_FORM_INPUT_RADIO) { + WillRemoveFromRadioGroup(); } + + nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent); } static const nsAttrValue::EnumTable kInputTypeTable[] = { diff --git a/mozilla/content/html/content/src/nsHTMLLabelElement.cpp b/mozilla/content/html/content/src/nsHTMLLabelElement.cpp index 1dfde446268..e647c52f81b 100644 --- a/mozilla/content/html/content/src/nsHTMLLabelElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLLabelElement.cpp @@ -82,8 +82,11 @@ public: nsIContent* aSubmitElement); // nsIContent - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); virtual nsresult HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, @@ -155,25 +158,31 @@ nsHTMLLabelElement::GetForm(nsIDOMHTMLFormElement** aForm) NS_IMPL_STRING_ATTR(nsHTMLLabelElement, AccessKey, accesskey) NS_IMPL_STRING_ATTR(nsHTMLLabelElement, HtmlFor, _for) -void -nsHTMLLabelElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsHTMLLabelElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsIDocument *document = GetCurrentDoc(); - PRBool documentChanging = (aDocument != document); + nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); - // Unregister the access key for the old document. - if (documentChanging && document) { + if (aDocument) { + RegUnRegAccessKey(PR_TRUE); + } + + return rv; +} + +void +nsHTMLLabelElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) +{ + if (IsInDoc()) { RegUnRegAccessKey(PR_FALSE); } - nsGenericHTMLFormElement::SetDocument(aDocument, aDeep, - aCompileEventHandlers); - - // Register the access key for the new document. - if (documentChanging && aDocument) { - RegUnRegAccessKey(PR_TRUE); - } + nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent); } static PRBool diff --git a/mozilla/content/html/content/src/nsHTMLLegendElement.cpp b/mozilla/content/html/content/src/nsHTMLLegendElement.cpp index 8f7980918f8..8fde7f0af96 100644 --- a/mozilla/content/html/content/src/nsHTMLLegendElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLLegendElement.cpp @@ -79,8 +79,11 @@ public: nsIContent* aSubmitElement); // nsIContent - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); virtual void SetFocus(nsPresContext* aPresContext); virtual PRBool ParseAttribute(nsIAtom* aAttribute, const nsAString& aValue, @@ -214,25 +217,31 @@ nsHTMLLegendElement::Reset() return NS_OK; } -void -nsHTMLLegendElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsHTMLLegendElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsIDocument *document = GetCurrentDoc(); - PRBool documentChanging = (aDocument != document); - - // Unregister the access key for the old document. - if (documentChanging && document) { + nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + + if (aDocument) { + RegUnRegAccessKey(PR_TRUE); + } + + return rv; +} + +void +nsHTMLLegendElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) +{ + if (IsInDoc()) { RegUnRegAccessKey(PR_FALSE); } - nsGenericHTMLFormElement::SetDocument(aDocument, aDeep, - aCompileEventHandlers); - - // Register the access key for the new document. - if (documentChanging && document) { - RegUnRegAccessKey(PR_TRUE); - } + nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent); } void diff --git a/mozilla/content/html/content/src/nsHTMLLinkElement.cpp b/mozilla/content/html/content/src/nsHTMLLinkElement.cpp index 97e1f27dd86..24386fccb78 100644 --- a/mozilla/content/html/content/src/nsHTMLLinkElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLLinkElement.cpp @@ -86,11 +86,12 @@ public: NS_IMETHOD SetLinkState(nsLinkState aState); NS_IMETHOD GetHrefURI(nsIURI** aURI); - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); - void CreateAndDispatchEvent(nsIDocument* aDoc, const nsString& aRel, - const nsString& aRev, - const nsAString& aEventName); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); + void CreateAndDispatchEvent(nsIDocument* aDoc, const nsAString& aEventName); nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, PRBool aNotify) { @@ -189,36 +190,52 @@ NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Rev, rev) NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Target, target) NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Type, type) +nsresult +nsHTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) +{ + nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + + UpdateStyleSheet(nsnull); + + // XXXbz we really shouldn't fire the event until after we've finished with + // the outermost BindToTree... In particular, this can effectively cause us + // to reenter this code, or for some part of the document to become unbound + // inside the event! + CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMLinkAdded")); + + return rv; +} + void -nsHTMLLinkElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsHTMLLinkElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) { nsCOMPtr oldDoc = GetCurrentDoc(); + // XXXbz we really shouldn't fire the event until after we've finished with + // the outermost UnbindFromTree... In particular, this can effectively cause + // us to reenter this code, or to be bound to a different tree inside the + // event! + CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved")); + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); + UpdateStyleSheet(oldDoc); +} + +void +nsHTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc, + const nsAString& aEventName) +{ + if (!aDoc) + return; + nsAutoString rel; nsAutoString rev; GetAttr(kNameSpaceID_None, nsHTMLAtoms::rel, rel); GetAttr(kNameSpaceID_None, nsHTMLAtoms::rev, rev); - - CreateAndDispatchEvent(oldDoc, rel, rev, - NS_LITERAL_STRING("DOMLinkRemoved")); - - // Do the removal and addition into the new doc. - nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers); - UpdateStyleSheet(oldDoc); - - CreateAndDispatchEvent(aDocument, rel, rev, - NS_LITERAL_STRING("DOMLinkAdded")); -} - -void -nsHTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc, - const nsString& aRel, - const nsString& aRev, - const nsAString& aEventName) -{ - if (!aDoc) - return; // In the unlikely case that both rev is specified *and* rel=stylesheet, // this code will cause the event to fire, on the principle that maybe the @@ -226,8 +243,8 @@ nsHTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc, // this should never actually happen and the performance hit is minimal, // doing the "right" thing costs virtually nothing here, even if it doesn't // make much sense. - if (aRev.IsEmpty() && - (aRel.IsEmpty() || aRel.LowerCaseEqualsLiteral("stylesheet"))) + if (rev.IsEmpty() && + (rel.IsEmpty() || rel.LowerCaseEqualsLiteral("stylesheet"))) return; nsCOMPtr docEvent(do_QueryInterface(aDoc)); diff --git a/mozilla/content/html/content/src/nsHTMLMapElement.cpp b/mozilla/content/html/content/src/nsHTMLMapElement.cpp index 57bba5ec2e5..e43905bed1b 100644 --- a/mozilla/content/html/content/src/nsHTMLMapElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLMapElement.cpp @@ -68,9 +68,11 @@ public: // nsIDOMHTMLMapElement NS_DECL_NSIDOMHTMLMAPELEMENT - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); - + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); protected: nsRefPtr mAreas; }; @@ -103,33 +105,36 @@ NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLMapElement, nsGenericHTMLElement) NS_HTML_CONTENT_INTERFACE_MAP_END -void -nsHTMLMapElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsHTMLMapElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsIDocument *document = GetCurrentDoc(); - PRBool documentChanging = (aDocument != document); - - if (documentChanging) { - nsCOMPtr htmlDoc = do_QueryInterface(document); + nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); - if (htmlDoc) { - htmlDoc->RemoveImageMap(this); - } + nsCOMPtr htmlDoc = do_QueryInterface(aDocument); + + if (htmlDoc) { + htmlDoc->AddImageMap(this); } - nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers); - - if (documentChanging) { - // Since we changed the document, gotta re-QI - nsCOMPtr htmlDoc = do_QueryInterface(aDocument); - - if (htmlDoc) { - htmlDoc->AddImageMap(this); - } - } + return rv; } +void +nsHTMLMapElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) +{ + nsCOMPtr htmlDoc = do_QueryInterface(GetCurrentDoc()); + + if (htmlDoc) { + htmlDoc->RemoveImageMap(this); + } + + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); +} NS_IMPL_DOM_CLONENODE(nsHTMLMapElement) diff --git a/mozilla/content/html/content/src/nsHTMLScriptElement.cpp b/mozilla/content/html/content/src/nsHTMLScriptElement.cpp index e0c14662b16..fe8d1557980 100644 --- a/mozilla/content/html/content/src/nsHTMLScriptElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLScriptElement.cpp @@ -346,8 +346,10 @@ public: virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, const nsAString& aValue, PRBool aNotify); - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify, PRBool aDeepSetDocument); virtual nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify, @@ -437,14 +439,21 @@ nsHTMLScriptElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, return rv; } -void -nsHTMLScriptElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsHTMLScriptElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers); + nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + if (aDocument) { MaybeProcessScript(); } + + return rv; } nsresult @@ -639,7 +648,7 @@ nsHTMLScriptElement::GetScriptLineNumber() void nsHTMLScriptElement::MaybeProcessScript() { - if (mIsEvaluated || mEvaluating || !IsInDoc() || !GetParent()) { + if (mIsEvaluated || mEvaluating || !IsInDoc()) { return; } diff --git a/mozilla/content/html/content/src/nsHTMLStyleElement.cpp b/mozilla/content/html/content/src/nsHTMLStyleElement.cpp index 26cac30b872..29b1ea006aa 100644 --- a/mozilla/content/html/content/src/nsHTMLStyleElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLStyleElement.cpp @@ -79,8 +79,11 @@ public: virtual nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify, PRBool aDeepSetDocument); virtual nsresult RemoveChildAt(PRUint32 aIndex, PRBool aNotify); - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, PRBool aNotify) { @@ -210,17 +213,30 @@ nsHTMLStyleElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify) return rv; } +nsresult +nsHTMLStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) +{ + nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + + UpdateStyleSheet(nsnull); + + return rv; +} + void -nsHTMLStyleElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsHTMLStyleElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) { nsCOMPtr oldDoc = GetCurrentDoc(); - nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers); - + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); UpdateStyleSheet(oldDoc); } - + nsresult nsHTMLStyleElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, const nsAString& aValue, diff --git a/mozilla/content/html/document/src/nsHTMLContentSink.cpp b/mozilla/content/html/document/src/nsHTMLContentSink.cpp index f1b6d2c46bd..8c652832809 100644 --- a/mozilla/content/html/document/src/nsHTMLContentSink.cpp +++ b/mozilla/content/html/document/src/nsHTMLContentSink.cpp @@ -703,6 +703,8 @@ public: // appended to it's parent until the container is closed. By setting // pre-append to true, the container will be appended when it is // created. + // XXXbz why do we really need this "no pre-appending" thing? Seems + // a little weird to me.... void SetPreAppend(PRBool aPreAppend) { mPreAppend = aPreAppend; @@ -1237,7 +1239,6 @@ SinkContext::OpenContainer(const nsIParserNode& aNode) mStack[mStackPos].mFlags = 0; mStack[mStackPos].mNumFlushed = 0; mStack[mStackPos].mInsertionPoint = -1; - content->SetDocument(mSink->mDocument, PR_FALSE, PR_TRUE); // Make sure to add base tag info, if needed, before setting any other // attributes -- what URI attrs do will depend on the base URI. Only do this @@ -1477,9 +1478,6 @@ SinkContext::AddLeaf(const nsIParserNode& aNode) mSink->mCurrentForm, mSink->mDocShell); NS_ENSURE_TRUE(content, NS_ERROR_OUT_OF_MEMORY); - // Set the content's document - content->SetDocument(mSink->mDocument, PR_FALSE, PR_TRUE); - // Make sure to add base tag info, if needed, before setting any other // attributes -- what URI attrs do will depend on the base URI. Only do // this for elements that have useful URI attributes. @@ -1607,8 +1605,6 @@ SinkContext::AddComment(const nsIParserNode& aNode) domComment->AppendData(aNode.GetText()); - comment->SetDocument(mSink->mDocument, PR_FALSE, PR_TRUE); - NS_ASSERTION(mStackPos > 0, "stack out of bounds"); if (mStackPos <= 0) { return NS_ERROR_FAILURE; @@ -1875,9 +1871,6 @@ SinkContext::FlushText(PRBool* aDidFlush, PRBool aReleaseLast) mLastTextNode = textContent; - // Set the content's document - mLastTextNode->SetDocument(mSink->mDocument, PR_FALSE, PR_TRUE); - // Set the text in the text node mLastTextNode->SetText(mText, mTextLength, PR_FALSE); @@ -2176,7 +2169,11 @@ HTMLContentSink::Init(nsIDocument* aDoc, } NS_ADDREF(mRoot); - mRoot->SetDocument(mDocument, PR_FALSE, PR_TRUE); + rv = mRoot->BindToTree(mDocument, nsnull, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + mRoot->UnbindFromTree(); + return rv; + } mDocument->SetRootContent(mRoot); } @@ -3188,7 +3185,6 @@ HTMLContentSink::SetDocumentTitle(const nsAString& aTitle, const nsIParserNode* text->SetText(title, PR_TRUE); it->AppendChildTo(text, PR_FALSE, PR_FALSE); - text->SetDocument(mDocument, PR_FALSE, PR_TRUE); mHead->AppendChildTo(it, PR_FALSE, PR_FALSE); @@ -3710,9 +3706,6 @@ HTMLContentSink::ProcessAREATag(const nsIParserNode& aNode) return NS_ERROR_OUT_OF_MEMORY; } - // Set the content's document - area->SetDocument(mDocument, PR_FALSE, PR_TRUE); - // Make sure to add base tag info, if needed, before setting any other // attributes -- what URI attrs do will depend on the base URI. Only do this // for elements that have useful URI attributes. @@ -3844,9 +3837,8 @@ HTMLContentSink::ProcessBASETag(const nsIParserNode& aNode) element->SetContentID(mDocument->GetAndIncrementContentID()); - // Add in the attributes and add the style content object to the + // Add in the attributes and add the base content object to the // head container. - element->SetDocument(mDocument, PR_FALSE, PR_TRUE); result = AddAttributes(aNode, element); NS_ENSURE_SUCCESS(result, result); @@ -3904,7 +3896,6 @@ HTMLContentSink::ProcessLINKTag(const nsIParserNode& aNode) // Add in the attributes and add the style content object to the // head container. - element->SetDocument(mDocument, PR_FALSE, PR_TRUE); AddBaseTagInfo(element); result = AddAttributes(aNode, element); if (NS_FAILED(result)) { @@ -3991,7 +3982,6 @@ HTMLContentSink::ProcessMETATag(const nsIParserNode& aNode) // Add in the attributes and add the meta content object to the head // container. - it->SetDocument(mDocument, PR_FALSE, PR_TRUE); AddBaseTagInfo(it); rv = AddAttributes(aNode, it); if (NS_FAILED(rv)) { @@ -4180,9 +4170,8 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode) element->SetContentID(mDocument->GetAndIncrementContentID()); - // Add in the attributes and add the style content object to the + // Add in the attributes and add the script content object to the // head container. - element->SetDocument(mDocument, PR_FALSE, PR_TRUE); AddBaseTagInfo(element); rv = AddAttributes(aNode, element); if (NS_FAILED(rv)) { @@ -4214,7 +4203,6 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode) text->SetText(script, PR_TRUE); element->AppendChildTo(text, PR_FALSE, PR_FALSE); - text->SetDocument(mDocument, PR_FALSE, PR_TRUE); } nsCOMPtr loader; @@ -4241,6 +4229,13 @@ HTMLContentSink::ProcessSCRIPTTag(const nsIParserNode& aNode) mScriptElements.AppendObject(sele); } + // Now flush out tags so that the script will actually be bound to a + // document and will evaluate as soon as it's appended. + SINK_TRACE(SINK_TRACE_CALLS, + ("HTMLContentSink::ProcessSCRIPTTag: flushing tags before " + "appending script")); + mCurrentContext->FlushTags(PR_FALSE); + // Insert the child into the content tree. This will evaluate the // script as well. if (mCurrentContext->mStack[mCurrentContext->mStackPos - 1].mInsertionPoint != -1) { @@ -4312,7 +4307,6 @@ HTMLContentSink::ProcessSTYLETag(const nsIParserNode& aNode) // Add in the attributes and add the style content object to the // head container. - element->SetDocument(mDocument, PR_FALSE, PR_TRUE); AddBaseTagInfo(element); rv = AddAttributes(aNode, element); if (NS_FAILED(rv)) { diff --git a/mozilla/content/html/document/src/nsIHTMLDocument.h b/mozilla/content/html/document/src/nsIHTMLDocument.h index 55dc1648b03..926338114e4 100644 --- a/mozilla/content/html/document/src/nsIHTMLDocument.h +++ b/mozilla/content/html/document/src/nsIHTMLDocument.h @@ -93,7 +93,7 @@ public: virtual already_AddRefed GetFormControlElements() = 0; /** - * Called when form->SetDocument() is called so that document knows + * Called when form->BindToTree() is called so that document knows * immediately when a form is added */ virtual void AddedForm() = 0; diff --git a/mozilla/content/html/document/src/nsImageDocument.cpp b/mozilla/content/html/document/src/nsImageDocument.cpp index 36a5a61064f..eb9d7bfacb0 100644 --- a/mozilla/content/html/document/src/nsImageDocument.cpp +++ b/mozilla/content/html/document/src/nsImageDocument.cpp @@ -587,7 +587,6 @@ nsImageDocument::CreateSyntheticDocument() if (!mImageContent) { return NS_ERROR_OUT_OF_MEMORY; } - mImageContent->SetDocument(this, PR_FALSE, PR_TRUE); nsCOMPtr imageLoader = do_QueryInterface(mImageContent); NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED); diff --git a/mozilla/content/html/document/src/nsMediaDocument.cpp b/mozilla/content/html/document/src/nsMediaDocument.cpp index f57cbe8e2a3..0ce97491b8c 100644 --- a/mozilla/content/html/document/src/nsMediaDocument.cpp +++ b/mozilla/content/html/document/src/nsMediaDocument.cpp @@ -242,7 +242,11 @@ nsMediaDocument::CreateSyntheticDocument() if (!root) { return NS_ERROR_OUT_OF_MEMORY; } - root->SetDocument(this, PR_FALSE, PR_TRUE); + rv = root->BindToTree(this, nsnull, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + root->UnbindFromTree(); + return rv; + } SetRootContent(root); rv = mNodeInfoManager->GetNodeInfo(nsHTMLAtoms::body, nsnull, @@ -254,7 +258,6 @@ nsMediaDocument::CreateSyntheticDocument() if (!body) { return NS_ERROR_OUT_OF_MEMORY; } - body->SetDocument(this, PR_FALSE, PR_TRUE); mBodyContent = do_QueryInterface(body); root->AppendChildTo(body, PR_FALSE, PR_FALSE); diff --git a/mozilla/content/html/document/src/nsPluginDocument.cpp b/mozilla/content/html/document/src/nsPluginDocument.cpp index 4111f97d586..4590838b6c1 100644 --- a/mozilla/content/html/document/src/nsPluginDocument.cpp +++ b/mozilla/content/html/document/src/nsPluginDocument.cpp @@ -180,7 +180,6 @@ nsPluginDocument::CreateSyntheticPluginDocument() if (!mPluginContent) { return NS_ERROR_OUT_OF_MEMORY; } - mPluginContent->SetDocument(this, PR_FALSE, PR_TRUE); // make it a named element mPluginContent->SetAttr(kNameSpaceID_None, nsHTMLAtoms::name, diff --git a/mozilla/content/svg/content/src/nsSVGElement.cpp b/mozilla/content/svg/content/src/nsSVGElement.cpp index 62e56dc559c..e87b405a0fe 100644 --- a/mozilla/content/svg/content/src/nsSVGElement.cpp +++ b/mozilla/content/svg/content/src/nsSVGElement.cpp @@ -102,12 +102,26 @@ NS_INTERFACE_MAP_END_INHERITING(nsGenericElement) //---------------------------------------------------------------------- // nsIContent methods -void -nsSVGElement::SetParent(nsIContent* aParent) +nsresult +nsSVGElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsGenericElement::SetParent(aParent); + nsresult rv = nsGenericElement::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); ParentChainChanged(); + + return rv; +} + +void +nsSVGElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) +{ + nsGenericElement::UnbindFromTree(aDeep, aNullParent); + ParentChainChanged(); } nsIAtom * @@ -241,17 +255,6 @@ nsSVGElement::UnsetAttr(PRInt32 aNamespaceID, nsIAtom* aName, return nsGenericElement::UnsetAttr(aNamespaceID, aName, aNotify); } -nsresult -nsSVGElement::SetBindingParent(nsIContent* aParent) -{ - nsresult rv = nsGenericElement::SetBindingParent(aParent); - - // XXX Are parent and bindingparent always in sync? (in which case - // we don't have to call ParentChainChanged() here) - ParentChainChanged(); - return rv; -} - PRBool nsSVGElement::IsContentOfType(PRUint32 aFlags) const { diff --git a/mozilla/content/svg/content/src/nsSVGElement.h b/mozilla/content/svg/content/src/nsSVGElement.h index 38ce4d0bd41..517524a102a 100644 --- a/mozilla/content/svg/content/src/nsSVGElement.h +++ b/mozilla/content/svg/content/src/nsSVGElement.h @@ -69,7 +69,11 @@ public: // nsIContent interface methods - virtual void SetParent(nsIContent* aParent); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); virtual nsIAtom *GetIDAttributeName() const; virtual nsIAtom *GetClassAttributeName() const; nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, @@ -83,7 +87,6 @@ public: virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRBool aNotify); - virtual nsresult SetBindingParent(nsIContent* aParent); virtual PRBool IsContentOfType(PRUint32 aFlags) const; NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker); diff --git a/mozilla/content/svg/content/src/nsSVGScriptElement.cpp b/mozilla/content/svg/content/src/nsSVGScriptElement.cpp index b292148eb9a..964a279ff5c 100644 --- a/mozilla/content/svg/content/src/nsSVGScriptElement.cpp +++ b/mozilla/content/svg/content/src/nsSVGScriptElement.cpp @@ -95,8 +95,9 @@ public: nsISVGValue::modificationType aModType); // nsIContent specializations: - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify, PRBool aDeepSetDocument); virtual nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify, @@ -356,14 +357,21 @@ nsSVGScriptElement::DidModifySVGObservable(nsISVGValue* aObservable, //---------------------------------------------------------------------- // nsIContent methods -void -nsSVGScriptElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsSVGScriptElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsSVGScriptElementBase::SetDocument(aDocument, aDeep, aCompileEventHandlers); + nsresult rv = nsSVGScriptElementBase::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + if (aDocument) { MaybeProcessScript(); } + + return rv; } nsresult @@ -400,7 +408,7 @@ nsSVGScriptElement::AppendChildTo(nsIContent* aKid, PRBool aNotify, void nsSVGScriptElement::MaybeProcessScript() { - if (mIsEvaluated || mEvaluating || !IsInDoc() || !GetParent()) { + if (mIsEvaluated || mEvaluating || !IsInDoc()) { return; } diff --git a/mozilla/content/svg/content/src/nsSVGStyleElement.cpp b/mozilla/content/svg/content/src/nsSVGStyleElement.cpp index 1b74afd6365..077cc741a05 100644 --- a/mozilla/content/svg/content/src/nsSVGStyleElement.cpp +++ b/mozilla/content/svg/content/src/nsSVGStyleElement.cpp @@ -70,8 +70,11 @@ public: virtual nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify, PRBool aDeepSetDocument); virtual nsresult RemoveChildAt(PRUint32 aIndex, PRBool aNotify); - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString& aValue, PRBool aNotify) { @@ -181,17 +184,30 @@ nsSVGStyleElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify) return rv; } +nsresult +nsSVGStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) +{ + nsresult rv = nsSVGStyleElementBase::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + + UpdateStyleSheet(nsnull); + + return rv; +} + void -nsSVGStyleElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsSVGStyleElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) { nsCOMPtr oldDoc = GetCurrentDoc(); - nsSVGStyleElementBase::SetDocument(aDocument, aDeep, aCompileEventHandlers); - + nsSVGStyleElementBase::UnbindFromTree(aDeep, aNullParent); UpdateStyleSheet(oldDoc); } - + nsresult nsSVGStyleElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, const nsAString& aValue, diff --git a/mozilla/content/xbl/src/nsBindingManager.cpp b/mozilla/content/xbl/src/nsBindingManager.cpp index e0bcfe84af7..e783287240d 100644 --- a/mozilla/content/xbl/src/nsBindingManager.cpp +++ b/mozilla/content/xbl/src/nsBindingManager.cpp @@ -407,7 +407,11 @@ NS_IMETHODIMP nsBindingManager::ChangeDocumentFor(nsIContent* aContent, nsIDocument* aOldDocument, nsIDocument* aNewDocument) { + // XXXbz this code is pretty broken, since moving from one document + // to another always passes through a null document! NS_PRECONDITION(aOldDocument != nsnull, "no old document"); + NS_PRECONDITION(!aNewDocument, + "Changing to a non-null new document not supported yet"); if (! aOldDocument) return NS_ERROR_NULL_POINTER; @@ -432,6 +436,8 @@ nsBindingManager::ChangeDocumentFor(nsIContent* aContent, nsIDocument* aOldDocum // See if the element has nsIAnonymousContentCreator-created // anonymous content... + // XXXbz this really doesn't belong here, somehow... either that, or we + // need to better define what sort of bindings we're managing. nsCOMPtr anonymousElements; shell->GetAnonymousContentFor(aContent, getter_AddRefs(anonymousElements)); @@ -447,9 +453,12 @@ nsBindingManager::ChangeDocumentFor(nsIContent* aContent, nsIDocument* aOldDocum if (! content) continue; - content->SetDocument(aNewDocument, PR_TRUE, PR_TRUE); + content->UnbindFromTree(); } } + + // now clear out the anonymous content for this node in the old presshell. + shell->SetAnonymousContentFor(aContent, nsnull); } return NS_OK; diff --git a/mozilla/content/xbl/src/nsXBLBinding.cpp b/mozilla/content/xbl/src/nsXBLBinding.cpp index 1ac57b147da..726a76229a8 100644 --- a/mozilla/content/xbl/src/nsXBLBinding.cpp +++ b/mozilla/content/xbl/src/nsXBLBinding.cpp @@ -191,19 +191,27 @@ nsXBLBinding::InstallAnonymousContent(nsIContent* aAnonParent, nsIContent* aElem // We need to ensure two things. // (1) The anonymous content should be fooled into thinking it's in the bound // element's document, assuming that the bound element is in a document - nsIDocument* doc = aElement->GetCurrentDoc(); - - if (doc) { - aAnonParent->SetDocument(doc, PR_TRUE, AllowScripts()); - } - + // Note that we don't change the current doc of aAnonParent here, since that + // quite simply does not matter. aAnonParent is just a way of keeping refs + // to all its kids, which are anonymous content from the point of view of + // aElement. // (2) The children's parent back pointer should not be to this synthetic root // but should instead point to the enclosing parent element. + nsIDocument* doc = aElement->GetCurrentDoc(); + PRBool allowScripts = AllowScripts(); + PRUint32 childCount = aAnonParent->GetChildCount(); for (PRUint32 i = 0; i < childCount; i++) { nsIContent *child = aAnonParent->GetChildAt(i); - child->SetParent(aElement); - child->SetBindingParent(mBoundElement); + child->UnbindFromTree(); + nsresult rv = + child->BindToTree(doc, aElement, mBoundElement, allowScripts); + if (NS_FAILED(rv)) { + // Oh, well... Just give up. + // XXXbz This really shouldn't be a void method! + child->UnbindFromTree(); + return; + } #ifdef MOZ_XUL // To make XUL templates work (and other goodies that happen when @@ -410,7 +418,7 @@ ChangeDocumentForDefaultContent(nsHashKey* aKey, void* aData, void* aClosure) nsCOMPtr defContent = currPoint->GetDefaultContent(); if (defContent) - defContent->SetDocument(nsnull, PR_TRUE, PR_TRUE); + defContent->UnbindFromTree(); } return PR_TRUE; @@ -909,7 +917,7 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen nsCOMPtr xuldoc(do_QueryInterface(aOldDocument)); #endif - anonymous->SetDocument(nsnull, PR_TRUE, PR_TRUE); // Kill it. + anonymous->UnbindFromTree(); // Kill it. #ifdef MOZ_XUL // To make XUL templates work (and other XUL-specific stuff), diff --git a/mozilla/content/xbl/src/nsXBLPrototypeBinding.cpp b/mozilla/content/xbl/src/nsXBLPrototypeBinding.cpp index c31cf19c73f..e32f9602a1d 100644 --- a/mozilla/content/xbl/src/nsXBLPrototypeBinding.cpp +++ b/mozilla/content/xbl/src/nsXBLPrototypeBinding.cpp @@ -141,6 +141,15 @@ private: class nsXBLInsertionPointEntry { public: + ~nsXBLInsertionPointEntry() { + if (mDefaultContent) { + // mDefaultContent is a sort of anonymous content within the XBL + // document, and we own and manage it. Unhook it here, since we're going + // away. + mDefaultContent->UnbindFromTree(); + } + } + nsIContent* GetInsertionParent() { return mInsertionParent; } PRUint32 GetInsertionIndex() { return mInsertionIndex; } void SetInsertionIndex(PRUint32 aIndex) { mInsertionIndex = aIndex; } @@ -1186,7 +1195,14 @@ nsXBLPrototypeBinding::ConstructInsertionTable(nsIContent* aContent) // to work with on default content. // XXXbz this is somewhat screwed up, since it's sort of like anonymous // content... but not. - child->SetParent(parent); + nsresult rv = + child->BindToTree(parent->GetCurrentDoc(), parent, nsnull, PR_FALSE); + if (NS_FAILED(rv)) { + // Well... now what? Just unbind and bail out, I guess... + // XXXbz This really shouldn't be a void method! + child->UnbindFromTree(); + return; + } } } } diff --git a/mozilla/content/xml/content/src/nsXMLStylesheetPI.cpp b/mozilla/content/xml/content/src/nsXMLStylesheetPI.cpp index 3b1f99137d0..e8173fc1b06 100644 --- a/mozilla/content/xml/content/src/nsXMLStylesheetPI.cpp +++ b/mozilla/content/xml/content/src/nsXMLStylesheetPI.cpp @@ -62,9 +62,12 @@ public: NS_IMETHOD CloneNode(PRBool aDeep, nsIDOMNode** aReturn); // nsIContent - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); - + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); + // nsStyleLinkElement NS_IMETHOD GetCharset(nsAString& aCharset); @@ -102,17 +105,29 @@ nsXMLStylesheetPI::~nsXMLStylesheetPI() // nsIContent -void -nsXMLStylesheetPI::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsXMLStylesheetPI::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsCOMPtr oldDoc = GetCurrentDoc(); - nsXMLProcessingInstruction::SetDocument(aDocument, aDeep, - aCompileEventHandlers); + nsresult rv = nsXMLProcessingInstruction::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); - UpdateStyleSheet(oldDoc); + UpdateStyleSheet(nsnull); + + return rv; } +void +nsXMLStylesheetPI::UnbindFromTree(PRBool aDeep, PRBool aNullParent) +{ + nsCOMPtr oldDoc = GetCurrentDoc(); + + nsXMLProcessingInstruction::UnbindFromTree(aDeep, aNullParent); + UpdateStyleSheet(oldDoc); +} // nsIDOMNode diff --git a/mozilla/content/xml/document/src/nsXMLContentSink.cpp b/mozilla/content/xml/document/src/nsXMLContentSink.cpp index 9cb30383e71..63d3cb20de0 100644 --- a/mozilla/content/xml/document/src/nsXMLContentSink.cpp +++ b/mozilla/content/xml/document/src/nsXMLContentSink.cpp @@ -743,9 +743,6 @@ nsXMLContentSink::FlushText(PRBool aCreateTextNode, PRBool* aDidFlush) rv = NS_NewTextNode(getter_AddRefs(textContent)); NS_ENSURE_SUCCESS(rv, rv); - // Set the content's document - textContent->SetDocument(mDocument, PR_FALSE, PR_TRUE); - // Set the text in the text node textContent->SetText(mText, mTextLength, PR_FALSE); @@ -877,6 +874,13 @@ nsXMLContentSink::SetDocElement(PRInt32 aNameSpaceID, mDocElement = aContent; NS_ADDREF(mDocElement); + nsresult rv = mDocElement->BindToTree(mDocument, nsnull, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + mDocElement->UnbindFromTree(); + // If we return PR_FALSE here, the caller will bail out because it won't + // find a parent content node to append to, which is fine. + return PR_FALSE; + } mDocument->SetRootContent(mDocElement); return PR_TRUE; } @@ -927,7 +931,6 @@ nsXMLContentSink::HandleStartElement(const PRUnichar *aName, if (mDocument) { content->SetContentID(mDocument->GetAndIncrementContentID()); } - content->SetDocument(mDocument, PR_FALSE, PR_TRUE); // Set the ID attribute atom on the node info object for this node // This must occur before the attributes are added so the name @@ -1040,7 +1043,6 @@ nsXMLContentSink::HandleComment(const PRUnichar *aName) nsCOMPtr domComment = do_QueryInterface(comment, &result); if (domComment) { domComment->AppendData(nsDependentString(aName)); - comment->SetDocument(mDocument, PR_FALSE, PR_TRUE); result = AddContentAsLeaf(comment); } } @@ -1064,7 +1066,6 @@ nsXMLContentSink::HandleCDataSection(const PRUnichar *aData, nsCOMPtr domCDATA = do_QueryInterface(cdata); if (domCDATA) { domCDATA->SetData(nsDependentString(aData, aLength)); - cdata->SetDocument(mDocument, PR_FALSE, PR_TRUE); result = AddContentAsLeaf(cdata); } } diff --git a/mozilla/content/xtf/src/nsXTFElementWrapper.cpp b/mozilla/content/xtf/src/nsXTFElementWrapper.cpp index 9728fc06fdd..8d009b05769 100644 --- a/mozilla/content/xtf/src/nsXTFElementWrapper.cpp +++ b/mozilla/content/xtf/src/nsXTFElementWrapper.cpp @@ -115,46 +115,83 @@ nsXTFElementWrapper::QueryInterface(REFNSIID aIID, void** aInstancePtr) //---------------------------------------------------------------------- // nsIContent methods: -void -nsXTFElementWrapper::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsXTFElementWrapper::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - // XXX For some reason we often get 2 SetDocument notifications with - // identical aDocument (one when expat encounters the element and - // another when the element is appended to its parent). We want to - // make sure that we only route notifications if the document has - // actually changed. - bool docReallyChanged = false; - if (aDocument!=GetCurrentDoc()) docReallyChanged = true; - + // XXXbz making up random order for the notifications... Perhaps + // this api should more closely match BindToTree/UnbindFromTree? + nsCOMPtr domParent; + if (aParent != GetParent()) { + domParent = do_QueryInterface(aParent); + } + nsCOMPtr domDocument; - if (docReallyChanged && - mNotificationMask & (nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT | - nsIXTFElement::NOTIFY_DOCUMENT_CHANGED)) + if (aDocument && + (mNotificationMask & (nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT | + nsIXTFElement::NOTIFY_DOCUMENT_CHANGED))) { domDocument = do_QueryInterface(aDocument); - - if (docReallyChanged && - (mNotificationMask & nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT)) + } + + if (domDocument && + (mNotificationMask & (nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT))) { GetXTFElement()->WillChangeDocument(domDocument); - nsXTFElementWrapperBase::SetDocument(aDocument, aDeep, aCompileEventHandlers); - if (docReallyChanged && - (mNotificationMask & nsIXTFElement::NOTIFY_DOCUMENT_CHANGED)) + } + + if (domParent && + (mNotificationMask & (nsIXTFElement::NOTIFY_WILL_CHANGE_PARENT))) { + GetXTFElement()->WillChangeParent(domParent); + } + + nsresult rv = nsXTFElementWrapperBase::BindToTree(aDocument, aParent, + aBindingParent, + aCompileEventHandlers); + + NS_ENSURE_SUCCESS(rv, rv); + + if (domDocument && + (mNotificationMask & (nsIXTFElement::NOTIFY_DOCUMENT_CHANGED))) { GetXTFElement()->DocumentChanged(domDocument); + } + + if (domParent && + (mNotificationMask & (nsIXTFElement::NOTIFY_PARENT_CHANGED))) { + GetXTFElement()->ParentChanged(domParent); + } + + return rv; } void -nsXTFElementWrapper::SetParent(nsIContent* aParent) +nsXTFElementWrapper::UnbindFromTree(PRBool aDeep, PRBool aNullParent) { - nsCOMPtr domParent; - if (mNotificationMask & (nsIXTFElement::NOTIFY_WILL_CHANGE_PARENT | - nsIXTFElement::NOTIFY_PARENT_CHANGED)) - domParent = do_QueryInterface(aParent); - - if (mNotificationMask & nsIXTFElement::NOTIFY_WILL_CHANGE_PARENT) - GetXTFElement()->WillChangeParent(domParent); - nsXTFElementWrapperBase::SetParent(aParent); - if (mNotificationMask & nsIXTFElement::NOTIFY_PARENT_CHANGED) - GetXTFElement()->ParentChanged(domParent); + // XXXbz making up random order for the notifications... Perhaps + // this api should more closely match BindToTree/UnbindFromTree? + PRBool inDoc = IsInDoc(); + if (inDoc && + (mNotificationMask & nsIXTFElement::NOTIFY_WILL_CHANGE_DOCUMENT)) { + GetXTFElement()->WillChangeDocument(nsnull); + } + + PRBool parentChanged = aNullParent && GetParent(); + + if (parentChanged && + (mNotificationMask & nsIXTFElement::NOTIFY_WILL_CHANGE_PARENT)) { + GetXTFElement()->WillChangeParent(nsnull); + } + + nsXTFElementWrapperBase::UnbindFromTree(aDeep, aNullParent); + + if (parentChanged && + (mNotificationMask & nsIXTFElement::NOTIFY_PARENT_CHANGED)) { + GetXTFElement()->ParentChanged(nsnull); + } + + if (inDoc && + (mNotificationMask & nsIXTFElement::NOTIFY_DOCUMENT_CHANGED)) { + GetXTFElement()->DocumentChanged(nsnull); + } } nsresult diff --git a/mozilla/content/xtf/src/nsXTFElementWrapper.h b/mozilla/content/xtf/src/nsXTFElementWrapper.h index 487bf3a3367..807b3d6ed03 100644 --- a/mozilla/content/xtf/src/nsXTFElementWrapper.h +++ b/mozilla/content/xtf/src/nsXTFElementWrapper.h @@ -76,9 +76,11 @@ public: // virtual PRUint32 GetElementType() = 0; // nsIContent specializations: - void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); - void SetParent(nsIContent* aParent); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify, PRBool aDeepSetDocument); nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify, diff --git a/mozilla/content/xul/content/src/nsXULElement.cpp b/mozilla/content/xul/content/src/nsXULElement.cpp index b1c6b46009f..64754a8fafb 100644 --- a/mozilla/content/xul/content/src/nsXULElement.cpp +++ b/mozilla/content/xul/content/src/nsXULElement.cpp @@ -353,10 +353,12 @@ nsXULElement::nsXULElement(nsINodeInfo* aNodeInfo) nsXULElement::~nsXULElement() { - //XXX SetDocument(nsnull) is not called always before dtor. + //XXX UnbindFromTree is not called always before dtor. //XXX Related to templates or overlays? - if (IsInDoc()) - SetDocument(nsnull, PR_TRUE, PR_FALSE); + //XXXbz probably related to the cloning thing! + if (IsInDoc()) { + UnbindFromTree(); + } nsDOMSlots* slots = GetExistingDOMSlots(); if (slots) { @@ -512,24 +514,35 @@ nsXULElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn) nsCOMPtr result; + // XXX setting document on some nodes not in a document so XBL will bind + // and chrome won't break. Make XBL bind to document-less nodes! + // XXXbz Once this is fixed, fix up the asserts in all implementations of + // BindToTree to assert what they would like to assert, and fix the + // ChangeDocumentFor() call in nsXULElement::BindToTree as well. Also, + // remove the UnbindFromTree call in ~nsXULElement, and add back in the + // precondition in nsXULElement::UnbindFromTree. + // Note: Make sure to do this witchery _after_ we've done any deep + // cloning, so kids of the new node aren't confused about whether they're + // in a document. + + PRBool fakeBeingInDocument = PR_TRUE; + // If we have a prototype, so will our clone. if (mPrototype) { rv = nsXULElement::Create(mPrototype, GetOwnerDoc(), PR_TRUE, getter_AddRefs(result)); NS_ENSURE_SUCCESS(rv, rv); - if (!IsInDoc()) { - nsIContent* element = result; - NS_STATIC_CAST(nsXULElement*, element)-> - mParentPtrBits &= ~PARENT_BIT_INDOCUMENT; - } + // Make sure to unset the "in document" bit we picked up in Create() + // while we create our kids. We'll reset it as needed at the end of + // this function. + NS_STATIC_CAST(nsXULElement*, + NS_STATIC_CAST(nsIContent*, result.get()))-> + mParentPtrBits &= ~PARENT_BIT_INDOCUMENT; + fakeBeingInDocument = IsInDoc(); } else { rv = NS_NewXULElement(getter_AddRefs(result), mNodeInfo); NS_ENSURE_SUCCESS(rv, rv); - - // XXX setting document on nodes not in a document so XBL will bind - // and chrome won't break. Make XBL bind to document-less nodes! - result->SetDocument(GetCurrentDoc(), PR_TRUE, PR_TRUE); } // Copy attributes @@ -579,6 +592,14 @@ nsXULElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn) } } + if (fakeBeingInDocument) { + // Don't use BindToTree here so we don't confuse the descendant + // non-XUL nodes. + NS_STATIC_CAST(nsXULElement*, + NS_STATIC_CAST(nsIContent*, result.get()))-> + mParentPtrBits |= PARENT_BIT_INDOCUMENT; + } + return CallQueryInterface(result, aReturn); } @@ -620,6 +641,8 @@ nsresult nsXULElement::AddScriptEventListener(nsIAtom* aName, const nsAString& aValue) { // XXX sXBL/XBL2 issue! Owner or current document? + // Note that If it's current, then we need to hook up listeners on the root + // when we BindToTree... nsIDocument* doc = GetOwnerDoc(); if (!doc) return NS_OK; // XXX @@ -854,102 +877,214 @@ nsXULElement::MaybeAddPopupListener(nsIAtom* aLocalName) // nsIContent interface // -void -nsXULElement::SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers) +nsresult +nsXULElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers) { - nsIDocument* doc = GetCurrentDoc(); - if (aDocument != doc) { - if (doc) { - // Notify XBL- & nsIAnonymousContentCreator-generated - // anonymous content that the document is changing. - doc->BindingManager()->ChangeDocumentFor(this, doc, aDocument); + NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!"); + // XXXbz XUL elements are confused about their current doc when they're + // cloned, so we don't assert if aParent is a XUL element and aDocument is + // null, even if aParent->GetCurrentDoc() is non-null + // NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(), + // "aDocument must be current doc of aParent"); + NS_PRECONDITION(!aParent || + (aParent->IsContentOfType(eXUL) && aDocument == nsnull) || + aDocument == aParent->GetCurrentDoc(), + "aDocument must be current doc of aParent"); + // XXXbz we'd like to assert that GetCurrentDoc() is null, but the cloning + // mess makes that impossible. We can't even assert that aDocument == + // GetCurrentDoc() when GetCurrentDoc() is non-null, since we may be + // getting inserted into a different document. :( + // NS_PRECONDITION(!GetCurrentDoc(), + // "Already have a document. Unbind first!"); - nsCOMPtr nsDoc(do_QueryInterface(doc)); - nsDoc->SetBoxObjectFor(this, nsnull); + // Note that as we recurse into the kids, they'll have a non-null + // parent. So only assert if our parent is _changing_ while we + // have a parent. + NS_PRECONDITION(!GetParent() || aParent == GetParent(), + "Already have a parent. Unbind first!"); + NS_PRECONDITION(!GetBindingParent() || + aBindingParent == GetBindingParent() || + (!aBindingParent && aParent && + aParent->GetBindingParent() == GetBindingParent()), + "Already have a binding parent. Unbind first!"); - if (HasProperties()) { - doc->PropertyTable()->DeleteAllPropertiesFor(this); - } - } + if (!aBindingParent && aParent) { + aBindingParent = aParent->GetBindingParent(); + } - // mControllers can own objects that are implemented - // in JavaScript (such as some implementations of - // nsIControllers. These objects prevent their global - // object's script object from being garbage collected, - // which means JS continues to hold an owning reference - // to the nsGlobalWindow, which owns the document, - // which owns this content. That's a cycle, so we break - // it here. (It might be better to break this by releasing - // mDocument in nsGlobalWindow::SetDocShell, but I'm not - // sure whether that would fix all possible cycles through - // mControllers.) - nsDOMSlots* slots = GetExistingDOMSlots(); - if (!aDocument && slots) { - NS_IF_RELEASE(slots->mControllers); // Forces release - } + // First set the binding parent + mBindingParent = aBindingParent; + + // Now set the parent; make sure to preserve the bits we have + // stashed there Note that checking whether aParent == GetParent() + // is probably not worth it here. + PtrBits new_bits = NS_REINTERPRET_CAST(PtrBits, aParent); + new_bits |= mParentPtrBits & nsIContent::kParentBitMask; + mParentPtrBits = new_bits; - if (mListenerManager) - mListenerManager->SetListenerTarget(nsnull); - mListenerManager = nsnull; + // Finally, set the document + if (aDocument && aDocument != GetCurrentDoc()) { + // Notify XBL- & nsIAnonymousContentCreator-generated + // anonymous content that the document is changing. + // XXXbz ordering issues here? Probably not, since ChangeDocumentFor + // is just pretty broken anyway.... Need to get it working. + // XXXbz XBL doesn't handle this (asserts), and we don't really want + // to be doing this during parsing anyway... sort this out. + // aDocument->BindingManager()->ChangeDocumentFor(this, nsnull, + // aDocument); + + // Being added to a document. + mParentPtrBits |= PARENT_BIT_INDOCUMENT; - if (aDocument) { - mParentPtrBits |= PARENT_BIT_INDOCUMENT; - if (aDocument != mNodeInfo->GetDocument()) { - // get a new nodeinfo - nsNodeInfoManager* nodeInfoManager = aDocument->NodeInfoManager(); - if (nodeInfoManager) { + // check the document on the nodeinfo to see whether we need a + // new nodeinfo + // XXXbz sXBL/XBL2 issue! + nsIDocument *ownerDocument = GetOwnerDoc(); + if (aDocument != ownerDocument) { + + if (HasProperties()) { + ownerDocument->PropertyTable()->DeleteAllPropertiesFor(this); + } + + // get a new nodeinfo + nsNodeInfoManager* nodeInfoManager = aDocument->NodeInfoManager(); + if (nodeInfoManager) { nsCOMPtr newNodeInfo; - nodeInfoManager->GetNodeInfo(mNodeInfo->NameAtom(), - mNodeInfo->GetPrefixAtom(), - mNodeInfo->NamespaceID(), - getter_AddRefs(newNodeInfo)); - if (newNodeInfo) { - mNodeInfo.swap(newNodeInfo); - } - } - } - // When we SetDocument(), we're either adding an element - // into the document that wasn't there before, or we're - // moving the element from one document to - // another. Regardless, we need to (re-)initialize several - // attributes that are dependant on the document. Do that - // now. - PRInt32 count = mAttrsAndChildren.AttrCount(); - PRBool haveLocalAttributes = (count > 0); - PRInt32 i; - for (i = 0; i < count; i++) { - AddListenerFor(*mAttrsAndChildren.GetSafeAttrNameAt(i), - aCompileEventHandlers); - } - - if (mPrototype) { - PRInt32 count = mPrototype->mNumAttributes; - for (i = 0; i < count; i++) { - nsXULPrototypeAttribute *protoattr = - &mPrototype->mAttributes[i]; - - // Don't clobber a locally modified attribute. - if (haveLocalAttributes && - mAttrsAndChildren.GetAttr(protoattr->mName.LocalName(), - protoattr->mName.NamespaceID())) { - continue; - } - - AddListenerFor(protoattr->mName, aCompileEventHandlers); - } + nsresult rv = + nodeInfoManager->GetNodeInfo(mNodeInfo->NameAtom(), + mNodeInfo->GetPrefixAtom(), + mNodeInfo->NamespaceID(), + getter_AddRefs(newNodeInfo)); + NS_ENSURE_SUCCESS(rv, rv); + NS_ASSERTION(newNodeInfo, "GetNodeInfo lies"); + mNodeInfo.swap(newNodeInfo); } } - else { - mParentPtrBits &= ~PARENT_BIT_INDOCUMENT; + + // we need to (re-)initialize several attributes that are dependant on + // the document. Do that now. + // XXXbz why do we have attributes depending on the current document? + // Shouldn't they depend on the owner document? Or is this code just + // misplaced, basically? + + PRInt32 count = mAttrsAndChildren.AttrCount(); + PRBool haveLocalAttributes = (count > 0); + PRInt32 i; + for (i = 0; i < count; i++) { + AddListenerFor(*mAttrsAndChildren.GetSafeAttrNameAt(i), + aCompileEventHandlers); + } + + if (mPrototype) { + PRInt32 count = mPrototype->mNumAttributes; + for (i = 0; i < count; i++) { + nsXULPrototypeAttribute *protoattr = + &mPrototype->mAttributes[i]; + + // Don't clobber a locally modified attribute. + if (haveLocalAttributes && + mAttrsAndChildren.GetAttr(protoattr->mName.LocalName(), + protoattr->mName.NamespaceID())) { + continue; + } + + AddListenerFor(protoattr->mName, aCompileEventHandlers); + } } } + // Now recurse into our kids + PRUint32 i, n = GetChildCount(); + + for (i = 0; i < n; ++i) { + nsresult rv = + mAttrsAndChildren.ChildAt(i)->BindToTree(aDocument, this, + aBindingParent, + aCompileEventHandlers); + NS_ENSURE_SUCCESS(rv, rv); + } + + // XXXbz script execution during binding can trigger some of these + // postcondition asserts.... But we do want that, since things will + // generally be quite broken when that happens. + // XXXbz we'd like to assert that we have the right GetCurrentDoc(), but + // we may be being bound to a null document while we already have a + // current doc, due to the cloneNode hack... So can't assert that yet. + // NS_POSTCONDITION(aDocument == GetCurrentDoc(), + // "Bound to wrong document"); + NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent"); + NS_POSTCONDITION(aBindingParent == GetBindingParent(), + "Bound to wrong binding parent"); + + return NS_OK; +} + +void +nsXULElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) +{ + // XXXbz we'd like to assert that called didn't screw up aDeep, but I'm not + // sure we can.... + // NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()), + // "Shallow unbind won't clear document and binding " + // "parent on kids!"); + // Make sure to unbind this node before doing the kids + nsIDocument *document = GetCurrentDoc(); + if (document) { + // Notify XBL- & nsIAnonymousContentCreator-generated + // anonymous content that the document is changing. + document->BindingManager()->ChangeDocumentFor(this, document, nsnull); + + nsCOMPtr nsDoc(do_QueryInterface(document)); + nsDoc->SetBoxObjectFor(this, nsnull); + } + + // mControllers can own objects that are implemented + // in JavaScript (such as some implementations of + // nsIControllers. These objects prevent their global + // object's script object from being garbage collected, + // which means JS continues to hold an owning reference + // to the nsGlobalWindow, which owns the document, + // which owns this content. That's a cycle, so we break + // it here. (It might be better to break this by releasing + // mDocument in nsGlobalWindow::SetDocShell, but I'm not + // sure whether that would fix all possible cycles through + // mControllers.) + nsDOMSlots* slots = GetExistingDOMSlots(); + if (slots) { + NS_IF_RELEASE(slots->mControllers); + } + + // XXXbz why are we nuking our listener manager? We can get events while + // not in a document! + if (mListenerManager) { + mListenerManager->SetListenerTarget(nsnull); + mListenerManager = nsnull; + } + + // Unset things in the reverse order from how we set them in BindToTree + mParentPtrBits &= ~PARENT_BIT_INDOCUMENT; + + if (aNullParent) { + // Just mask it out + mParentPtrBits &= nsIContent::kParentBitMask; + } + + mBindingParent = nsnull; + if (aDeep) { - PRInt32 i; - for (i = mAttrsAndChildren.ChildCount() - 1; i >= 0; --i) { - mAttrsAndChildren.ChildAt(i)->SetDocument(aDocument, aDeep, - aCompileEventHandlers); + // Do the kids. Note that we don't want to GetChildCount(), because + // that will force content generation... if we never had to generate + // the content, we shouldn't force it now! + PRUint32 i, n = PeekChildCount(); + + for (i = 0; i < n; ++i) { + // Note that we pass PR_FALSE for aNullParent here, since we don't + // want the kids to forget us. We _do_ want them to forget their + // binding parent, though, since this only walks non-anonymous + // kids. + mAttrsAndChildren.ChildAt(i)->UnbindFromTree(PR_TRUE, PR_FALSE); } } } @@ -1014,12 +1149,25 @@ nsXULElement::InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify, rv = mAttrsAndChildren.InsertChildAt(aKid, aIndex); NS_ENSURE_SUCCESS(rv, rv); - aKid->SetParent(this); + rv = aKid->BindToTree(doc, this, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + mAttrsAndChildren.RemoveChildAt(aIndex); + aKid->UnbindFromTree(); + return rv; + } + + // XXXbz this screws up ranges, no? Need to figure out why this is + // commented and uncomment.... //nsRange::OwnerChildInserted(this, aIndex); - if (doc) { - aKid->SetDocument(doc, aDeepSetDocument, PR_TRUE); - + // The kid may have removed us from the document, so recheck that we're + // still in the document before proceeding. Also, the kid may have just + // removed itself, in which case we don't really want to fire + // ContentAppended or a mutation event. + // XXXbz What if the kid just moved us in the document? Scripts suck. We + // really need to stop running them while we're in the middle of modifying + // the DOM.... + if (doc && doc == GetCurrentDoc() && aKid->GetParent() == this) { if (aNotify) { if (isAppend) { doc->ContentAppended(this, aIndex); @@ -1059,12 +1207,22 @@ nsXULElement::AppendChildTo(nsIContent* aKid, PRBool aNotify, rv = mAttrsAndChildren.AppendChild(aKid); NS_ENSURE_SUCCESS(rv, rv); - aKid->SetParent(this); + rv = aKid->BindToTree(doc, this, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + mAttrsAndChildren.RemoveChildAt(GetChildCount() - 1); + aKid->UnbindFromTree(); + return rv; + } // ranges don't need adjustment since new child is at end of list - if (doc) { - aKid->SetDocument(doc, aDeepSetDocument, PR_TRUE); - + // The kid may have removed us from the document, so recheck that we're + // still in the document before proceeding. Also, the kid may have just + // removed itself, in which case we don't really want to fire + // ContentAppended or a mutation event. + // XXXbz What if the kid just moved us in the document? Scripts suck. We + // really need to stop running them while we're in the middle of modifying + // the DOM.... + if (doc && doc == GetCurrentDoc() && aKid->GetParent() == this) { if (aNotify) { doc->ContentAppended(this, mAttrsAndChildren.ChildCount() - 1); } @@ -1205,10 +1363,7 @@ nsXULElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify) // This will cause the script object to be unrooted for each // element in the subtree. - oldKid->SetDocument(nsnull, PR_TRUE, PR_TRUE); - - // We've got no mo' parent. - oldKid->SetParent(nsnull); + oldKid->UnbindFromTree(); return NS_OK; } @@ -2655,22 +2810,6 @@ nsXULElement::GetBindingParent() const return mBindingParent; } -nsresult -nsXULElement::SetBindingParent(nsIContent* aParent) -{ - nsresult rv = NS_OK; - - mBindingParent = aParent; // [Weak] no addref - if (mBindingParent) { - PRUint32 count = GetChildCount(); - for (PRUint32 i = 0; i < count; i++) { - rv |= GetChildAt(i)->SetBindingParent(aParent); - } - } - - return rv; -} - PRBool nsXULElement::IsContentOfType(PRUint32 aFlags) const { diff --git a/mozilla/content/xul/content/src/nsXULElement.h b/mozilla/content/xul/content/src/nsXULElement.h index 7191a5d4eea..37d63182697 100644 --- a/mozilla/content/xul/content/src/nsXULElement.h +++ b/mozilla/content/xul/content/src/nsXULElement.h @@ -461,8 +461,11 @@ public: NS_DECL_ISUPPORTS_INHERITED // nsIContent - virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep, - PRBool aCompileEventHandlers); + virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, + nsIContent* aBindingParent, + PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); virtual PRBool IsNativeAnonymous() const; virtual PRUint32 GetChildCount() const; virtual nsIContent *GetChildAt(PRUint32 aIndex) const; @@ -511,7 +514,6 @@ public: virtual void RemoveFocus(nsPresContext* aPresContext); virtual nsIContent *GetBindingParent() const; - virtual nsresult SetBindingParent(nsIContent* aParent); virtual PRBool IsContentOfType(PRUint32 aFlags) const; virtual nsresult GetListenerManager(nsIEventListenerManager** aResult); virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull); diff --git a/mozilla/content/xul/document/src/nsXULDocument.cpp b/mozilla/content/xul/document/src/nsXULDocument.cpp index 92771d7d4d2..0af2fc80575 100644 --- a/mozilla/content/xul/document/src/nsXULDocument.cpp +++ b/mozilla/content/xul/document/src/nsXULDocument.cpp @@ -2573,6 +2573,9 @@ nsXULDocument::PrepareToWalk() rv = CreateElementFromPrototype(proto, getter_AddRefs(root)); if (NS_FAILED(rv)) return rv; + rv = root->BindToTree(this, nsnull, nsnull, PR_TRUE); + if (NS_FAILED(rv)) return rv; + SetRootContent(root); // Add the root element to the XUL document's ID-to-element map. @@ -3545,8 +3548,6 @@ nsXULDocument::CreateElementFromPrototype(nsXULPrototypeElement* aPrototype, aPrototype->mNodeInfo); if (NS_FAILED(rv)) return rv; - result->SetDocument(this, PR_FALSE, PR_TRUE); - rv = AddAttributes(aPrototype, result); if (NS_FAILED(rv)) return rv; } diff --git a/mozilla/content/xul/document/src/nsXULDocument.h b/mozilla/content/xul/document/src/nsXULDocument.h index 8ac3953eb40..0088480d94a 100644 --- a/mozilla/content/xul/document/src/nsXULDocument.h +++ b/mozilla/content/xul/document/src/nsXULDocument.h @@ -357,6 +357,7 @@ protected: /** * Create a delegate content model element from a prototype. + * Note that the resulting content node is not bound to any tree */ nsresult CreateElementFromPrototype(nsXULPrototypeElement* aPrototype, nsIContent** aResult); diff --git a/mozilla/content/xul/templates/src/nsXULContentBuilder.cpp b/mozilla/content/xul/templates/src/nsXULContentBuilder.cpp index c216967ad0e..7ad68bb09f4 100644 --- a/mozilla/content/xul/templates/src/nsXULContentBuilder.cpp +++ b/mozilla/content/xul/templates/src/nsXULContentBuilder.cpp @@ -1065,13 +1065,12 @@ nsXULContentBuilder::RemoveMember(nsIContent* aContainerElement, NS_ASSERTION(pos >= 0, "parent doesn't think this child has an index"); if (pos < 0) continue; + // Note: RemoveChildAt sets |child|'s document to null so that + // it'll get knocked out of the XUL doc's resource-to-element + // map. rv = parent->RemoveChildAt(pos, aNotify); if (NS_FAILED(rv)) return rv; - // Set its document to null so that it'll get knocked out of - // the XUL doc's resource-to-element map. - child->SetDocument(nsnull, PR_TRUE, PR_TRUE); - // Remove from the content support map. mContentSupportMap.Remove(child); @@ -1472,8 +1471,6 @@ nsXULContentBuilder::CreateElement(PRInt32 aNameSpaceID, rv = NS_NewElement(getter_AddRefs(result), aNameSpaceID, nodeInfo); if (NS_FAILED(rv)) return rv; - result->SetDocument(doc, PR_FALSE, PR_TRUE); - *aResult = result; NS_ADDREF(*aResult); return NS_OK; diff --git a/mozilla/editor/libeditor/html/nsHTMLAnonymousUtils.cpp b/mozilla/editor/libeditor/html/nsHTMLAnonymousUtils.cpp index dcf5f8f78cf..c8f26a814fd 100644 --- a/mozilla/editor/libeditor/html/nsHTMLAnonymousUtils.cpp +++ b/mozilla/editor/libeditor/html/nsHTMLAnonymousUtils.cpp @@ -153,9 +153,12 @@ nsHTMLEditor::CreateAnonymousElement(const nsAString & aTag, nsIDOMNode * aPare // establish parenthood of the element newContent->SetNativeAnonymous(PR_TRUE); - newContent->SetParent(parentContent); - newContent->SetDocument(doc, PR_TRUE, PR_TRUE); - newContent->SetBindingParent(newContent); + res = newContent->BindToTree(doc, parentContent, newContent, PR_TRUE); + if (NS_FAILED(res)) { + newContent->UnbindFromTree(); + return res; + } + // display the element ps->RecreateFramesFor(newContent); @@ -178,10 +181,8 @@ nsHTMLEditor::DeleteRefToAnonymousNode(nsIDOMElement* aElement, nsCOMPtr content = do_QueryInterface(aElement); if (content) { aDocObserver->ContentRemoved(content->GetCurrentDoc(), - aParentContent, content, -1); - content->SetParent(nsnull); - content->SetBindingParent(nsnull); - content->SetDocument(nsnull, PR_TRUE, PR_TRUE); + aParentContent, content, -1); + content->UnbindFromTree(); } } } diff --git a/mozilla/extensions/transformiix/source/xslt/txMozillaTextOutput.cpp b/mozilla/extensions/transformiix/source/xslt/txMozillaTextOutput.cpp index 921dc3cc893..9cb6da4ee4c 100644 --- a/mozilla/extensions/transformiix/source/xslt/txMozillaTextOutput.cpp +++ b/mozilla/extensions/transformiix/source/xslt/txMozillaTextOutput.cpp @@ -249,7 +249,12 @@ void txMozillaTextOutput::createResultDocument(nsIDOMDocument* aSourceDocument, return; } - rootContent->SetDocument(doc, PR_FALSE, PR_TRUE); + rv = rootContent->BindToTree(doc, nsnull, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + NS_ERROR("Failed to bind root to tree"); + rootContent->UnbindFromTree(); + return rv; + } doc->SetRootContent(rootContent); diff --git a/mozilla/extensions/transformiix/source/xslt/txMozillaXMLOutput.cpp b/mozilla/extensions/transformiix/source/xslt/txMozillaXMLOutput.cpp index f942399565e..3f8875d96cd 100644 --- a/mozilla/extensions/transformiix/source/xslt/txMozillaXMLOutput.cpp +++ b/mozilla/extensions/transformiix/source/xslt/txMozillaXMLOutput.cpp @@ -296,12 +296,12 @@ void txMozillaXMLOutput::endElement(const nsAString& aName, const PRInt32 aNsID) // up the tree // we can't use GetParentNode to check if mCurrentNode is the // "non-added node" since that does strange things when we've called - // SetDocument manually + // BindToTree manually if (mCurrentNode == mNonAddedNode) { nsCOMPtr document = do_QueryInterface(mNonAddedParent); if (document && !mRootContent) { mRootContent = do_QueryInterface(mCurrentNode); - mRootContent->SetDocument(document, PR_FALSE, PR_TRUE); + mRootContent->BindToTree(document, nsnull, nsnull, PR_TRUE); document->SetRootContent(mRootContent); } else { @@ -455,11 +455,6 @@ void txMozillaXMLOutput::startElement(const nsAString& aName, ssle->InitStyleLinkElement(nsnull, PR_FALSE); ssle->SetEnableUpdates(PR_FALSE); } - - nsCOMPtr cont = do_QueryInterface(element); - NS_ASSERTION(cont, "element doesn't implement nsIContent"); - nsCOMPtr doc = do_QueryInterface(mDocument); - cont->SetDocument(doc, PR_FALSE, PR_TRUE); } mParentNode = mCurrentNode; mCurrentNode = do_QueryInterface(element); @@ -498,7 +493,7 @@ void txMozillaXMLOutput::closePrevious(PRInt8 aAction) mParentNode = wrapper; mRootContent = do_QueryInterface(wrapper); - mRootContent->SetDocument(document, PR_FALSE, PR_TRUE); + mRootContent->BindToTree(document, nsnull, nsnull, PR_TRUE); document->SetRootContent(mRootContent); } @@ -509,7 +504,7 @@ void txMozillaXMLOutput::closePrevious(PRInt8 aAction) else { if (document && currentElement && !mRootContent) { mRootContent = do_QueryInterface(mCurrentNode); - mRootContent->SetDocument(document, PR_FALSE, PR_TRUE); + mRootContent->BindToTree(document, nsnull, nsnull, PR_TRUE); document->SetRootContent(mRootContent); } else { diff --git a/mozilla/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp b/mozilla/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp index dfbf39d3a32..ddc743c8f0f 100644 --- a/mozilla/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp +++ b/mozilla/extensions/transformiix/source/xslt/txMozillaXSLTProcessor.cpp @@ -712,7 +712,7 @@ txMozillaXSLTProcessor::notifyError() return; } - rootContent->SetDocument(document, PR_FALSE, PR_TRUE); + rootContent->BindToTree(document, nsnull, nsnull, PR_TRUE); document->SetRootContent(rootContent); nsCOMPtr text; diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index 82bae3ac3fa..7cbda46b6d1 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -2024,13 +2024,16 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram // Set aContent as the parent content and set the document object. This // way event handling works - content->SetParent(aContent); - content->SetDocument(mDocument, PR_TRUE, PR_TRUE); + // Hack the binding parent to make document rules not match (not + // like it matters, since we already have a non-element style + // context... which is totally wacky, but anyway). + rv = content->BindToTree(mDocument, aContent, content, PR_TRUE); + if (NS_FAILED(rv)) { + content->UnbindFromTree(); + return rv; + } + content->SetNativeAnonymous(PR_TRUE); - // hack to make document rules not match (not like it matters, since we - // already have a non-element style context... which is totally wacky, but - // anyway). - content->SetBindingParent(content); // Create an image frame and initialize it nsIFrame* imageFrame = nsnull; @@ -2086,15 +2089,18 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram nsresult rv = NS_ERROR_FAILURE; if (attrName) { nsIFrame* textFrame = nsnull; - rv = NS_NewAttributeContent(aContent, attrNameSpace, attrName, + rv = NS_NewAttributeContent(attrNameSpace, attrName, getter_AddRefs(content)); NS_ENSURE_SUCCESS(rv, rv); // Set aContent as the parent content so that event handling works. - content->SetParent(aContent); - content->SetDocument(mDocument, PR_TRUE, PR_TRUE); + rv = content->BindToTree(mDocument, aContent, content, PR_TRUE); + if (NS_FAILED(rv)) { + content->UnbindFromTree(); + return rv; + } + content->SetNativeAnonymous(PR_TRUE); - content->SetBindingParent(content); // Create a text frame and initialize it NS_NewTextFrame(mPresShell, &textFrame); @@ -2182,10 +2188,14 @@ nsCSSFrameConstructor::CreateGeneratedFrameFor(nsIFrame* aParentFram } // Set aContent as the parent content so that event handling works. - textContent->SetParent(aContent); - textContent->SetDocument(mDocument, PR_TRUE, PR_TRUE); + nsresult rv = textContent->BindToTree(mDocument, aContent, textContent, + PR_TRUE); + if (NS_FAILED(rv)) { + textContent->UnbindFromTree(); + return rv; + } + textContent->SetNativeAnonymous(PR_TRUE); - textContent->SetBindingParent(textContent); // Create a text frame and initialize it NS_NewTextFrame(mPresShell, &textFrame); @@ -5615,10 +5625,9 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState, continue; content->SetNativeAnonymous(PR_TRUE); - content->SetParent(aParent); - content->SetDocument(aDocument, PR_TRUE, PR_TRUE); nsresult rv; + nsIContent* bindingParent = content; #ifdef MOZ_XUL // Only cut XUL scrollbars off if they're not in a XUL document. // This allows scrollbars to be styled from XUL (although not @@ -5629,15 +5638,13 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState, ni->Equals(nsXULAtoms::scrollcorner, kNameSpaceID_XUL))) { nsCOMPtr xulDoc(do_QueryInterface(aDocument)); if (xulDoc) - rv = content->SetBindingParent(aParent); - else - rv = content->SetBindingParent(content); + bindingParent = aParent; } else #endif #ifdef MOZ_XTF if (aForceBindingParent) - rv = content->SetBindingParent(aParent); + bindingParent = aParent; else #endif #ifdef MOZ_SVG @@ -5646,12 +5653,14 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState, if (aParent && aParent->GetNodeInfo() && aParent->GetNodeInfo()->Equals(nsSVGAtoms::use, kNameSpaceID_SVG)) - rv = content->SetBindingParent(aParent); - else + bindingParent = aParent; #endif - rv = content->SetBindingParent(content); - NS_ENSURE_SUCCESS(rv, rv); + rv = content->BindToTree(aDocument, aParent, bindingParent, PR_TRUE); + if (NS_FAILED(rv)) { + content->UnbindFromTree(); + return rv; + } nsIFrame * newFrame = nsnull; rv = creator->CreateFrameFor(aState.mPresContext, content, &newFrame); @@ -10484,8 +10493,14 @@ nsCSSFrameConstructor::ConstructAlternateFrame(nsIContent* aContent, altTextContent->SetText(altText, PR_TRUE); // Set aContent as the parent content. - altTextContent->SetParent(aContent); - altTextContent->SetDocument(mDocument, PR_TRUE, PR_TRUE); + // XXXbz should this set the binding parent to |altTextContent|? + rv = altTextContent->BindToTree(mDocument, aContent, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + altTextContent->UnbindFromTree(); + return rv; + } + + // XXXbz shouldn't it be set native anonymous too? // Create either an inline frame, block frame, or area frame nsIFrame* containerFrame; diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index 13e06874256..2694c7bc98b 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -4904,7 +4904,7 @@ PresShell::SetAnonymousContentFor(nsIContent* aContent, nsISupportsArray* aAnony if (! content) continue; - content->SetDocument(nsnull, PR_TRUE, PR_TRUE); + content->UnbindFromTree(); } } } @@ -4943,7 +4943,7 @@ ClearDocumentEnumerator(nsHashKey* aKey, void* aData, void* aClosure) if (! content) continue; - content->SetDocument(nsnull, PR_TRUE, PR_TRUE); + content->UnbindFromTree(); } return PR_TRUE; diff --git a/mozilla/layout/build/nsContentDLF.cpp b/mozilla/layout/build/nsContentDLF.cpp index 532048ecbcb..b3f3a735922 100644 --- a/mozilla/layout/build/nsContentDLF.cpp +++ b/mozilla/layout/build/nsContentDLF.cpp @@ -362,15 +362,20 @@ nsContentDLF::CreateBlankDocument(nsILoadGroup *aLoadGroup, nsIDocument **aDocum // blat in the structure if (htmlElement && headElement && bodyElement) { - htmlElement->SetDocument(blankDoc, PR_FALSE, PR_TRUE); - blankDoc->SetRootContent(htmlElement); + rv = htmlElement->BindToTree(blankDoc, nsnull, nsnull, PR_TRUE); + if (NS_FAILED(rv)) { + htmlElement->UnbindFromTree(); + } else { + blankDoc->SetRootContent(htmlElement); - htmlElement->AppendChildTo(headElement, PR_FALSE, PR_FALSE); + htmlElement->AppendChildTo(headElement, PR_FALSE, PR_FALSE); - bodyElement->SetContentID(blankDoc->GetAndIncrementContentID()); - htmlElement->AppendChildTo(bodyElement, PR_FALSE, PR_FALSE); + bodyElement->SetContentID(blankDoc->GetAndIncrementContentID()); + // XXXbz Why not notifying here? + htmlElement->AppendChildTo(bodyElement, PR_FALSE, PR_FALSE); - rv = NS_OK; + rv = NS_OK; + } } } diff --git a/mozilla/layout/generic/nsContainerFrame.cpp b/mozilla/layout/generic/nsContainerFrame.cpp index a9e0639a257..db71f910ad7 100644 --- a/mozilla/layout/generic/nsContainerFrame.cpp +++ b/mozilla/layout/generic/nsContainerFrame.cpp @@ -130,8 +130,7 @@ CleanupGeneratedContentIn(nsIContent* aRealContent, nsIFrame* aRoot) { while (child) { nsIContent* content = child->GetContent(); if (content && content != aRealContent) { - content->SetParent(nsnull); - content->SetDocument(nsnull, PR_TRUE, PR_TRUE); + content->UnbindFromTree(); } ::CleanupGeneratedContentIn(aRealContent, child); child = child->GetNextSibling(); diff --git a/mozilla/layout/generic/nsHTMLParts.h b/mozilla/layout/generic/nsHTMLParts.h index 8a38a494585..ed80098bc98 100644 --- a/mozilla/layout/generic/nsHTMLParts.h +++ b/mozilla/layout/generic/nsHTMLParts.h @@ -89,8 +89,8 @@ NS_NewBlockFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame, // Special Generated Content Frame nsresult -NS_NewAttributeContent(nsIContent* aContent, PRInt32 aNameSpaceID, - nsIAtom* aAttrName, nsIContent** aResult); +NS_NewAttributeContent(PRInt32 aNameSpaceID, nsIAtom* aAttrName, + nsIContent** aResult); // Create a basic area frame but the GetFrameForPoint is overridden to always // return the option frame diff --git a/mozilla/layout/generic/nsObjectFrame.cpp b/mozilla/layout/generic/nsObjectFrame.cpp index 7e5b7f6a297..de85a00b7ba 100644 --- a/mozilla/layout/generic/nsObjectFrame.cpp +++ b/mozilla/layout/generic/nsObjectFrame.cpp @@ -1564,9 +1564,13 @@ nsObjectFrame::CreateDefaultFrames(nsPresContext *aPresContext, img->SetNativeAnonymous(PR_TRUE); text->SetNativeAnonymous(PR_TRUE); - // Set up the anonymous tree - anchor->SetParent(mContent); - anchor->SetDocument(doc, PR_TRUE, PR_TRUE); + // Set up the anonymous tree. Note that the binding parent for the anchor is + // used to cut off style rules from the page so they won't apply to it. + rv = anchor->BindToTree(doc, mContent, anchor, PR_TRUE); + if (NS_FAILED(rv)) { + anchor->UnbindFromTree(); + return rv; + } anchor->AppendChildTo(img, PR_FALSE, PR_TRUE); anchor->AppendChildTo(text, PR_FALSE, PR_TRUE); diff --git a/mozilla/layout/html/tests/TestAttributes.cpp b/mozilla/layout/html/tests/TestAttributes.cpp index 1c611e0eb84..57641686ebe 100644 --- a/mozilla/layout/html/tests/TestAttributes.cpp +++ b/mozilla/layout/html/tests/TestAttributes.cpp @@ -263,7 +263,12 @@ int main(int argc, char** argv) txt->AppendData(tmp); NS_RELEASE(txt); - text->SetDocument(myDoc, PR_FALSE, PR_TRUE); + rv = text->BindToTree(myDoc, nsnull, nsnull, PR_FALSE); + if (NS_FAILED(rv)) { + printf("Could not bind text content to tree.\n"); + text->UnbindFromTree(); + return -1; + } #if 0 // Query ITextContent interface