зеркало из https://github.com/mozilla/gecko-dev.git
Fix for bug 540848 (Add appendChild/insertBefore/replaceChild/removeChild on nsINode). r=bz.
--HG-- extra : rebase_source : 4550ff196ab5fd1acbc72e7c94b7a31d073ae5dd
This commit is contained in:
Родитель
71086dbb3a
Коммит
3732c25789
|
@ -46,6 +46,7 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsIProgrammingLanguage.h" // for ::JAVASCRIPT
|
||||
#include "nsDOMError.h"
|
||||
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
|
@ -378,6 +379,38 @@ public:
|
|||
return IsInDoc() ? GetOwnerDoc() : nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetNodeType(PRUint16* aNodeType) = 0;
|
||||
|
||||
nsINode*
|
||||
InsertBefore(nsINode *aNewChild, nsINode *aRefChild, nsresult *aReturn)
|
||||
{
|
||||
return ReplaceOrInsertBefore(PR_FALSE, aNewChild, aRefChild, aReturn);
|
||||
}
|
||||
nsINode*
|
||||
ReplaceChild(nsINode *aNewChild, nsINode *aOldChild, nsresult *aReturn)
|
||||
{
|
||||
return ReplaceOrInsertBefore(PR_TRUE, aNewChild, aOldChild, aReturn);
|
||||
}
|
||||
nsINode*
|
||||
AppendChild(nsINode *aNewChild, nsresult *aReturn)
|
||||
{
|
||||
return InsertBefore(aNewChild, nsnull, aReturn);
|
||||
}
|
||||
nsresult RemoveChild(nsINode *aOldChild)
|
||||
{
|
||||
if (!aOldChild) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
PRInt32 index = IndexOf(aOldChild);
|
||||
if (index == -1) {
|
||||
// aOldChild isn't one of our children.
|
||||
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
||||
}
|
||||
|
||||
return RemoveChildAt(index, PR_TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a content node at a particular index. This method handles calling
|
||||
* BindToTree on the child appropriately.
|
||||
|
@ -938,6 +971,22 @@ protected:
|
|||
nsresult GetNextSibling(nsIDOMNode** aNextSibling);
|
||||
nsresult GetOwnerDocument(nsIDOMDocument** aOwnerDocument);
|
||||
|
||||
nsresult ReplaceOrInsertBefore(PRBool aReplace, nsIDOMNode *aNewChild,
|
||||
nsIDOMNode *aRefChild, nsIDOMNode **aReturn);
|
||||
nsINode* ReplaceOrInsertBefore(PRBool aReplace, nsINode *aNewChild,
|
||||
nsINode *aRefChild, nsresult *aReturn)
|
||||
{
|
||||
*aReturn = ReplaceOrInsertBefore(aReplace, aNewChild, aRefChild);
|
||||
if (NS_FAILED(*aReturn)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return aReplace ? aRefChild : aNewChild;
|
||||
}
|
||||
virtual nsresult ReplaceOrInsertBefore(PRBool aReplace, nsINode* aNewChild,
|
||||
nsINode* aRefChild);
|
||||
nsresult RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn);
|
||||
|
||||
nsCOMPtr<nsINodeInfo> mNodeInfo;
|
||||
|
||||
enum { PARENT_BIT_INDOCUMENT = 1 << 0, PARENT_BIT_PARENT_IS_CONTENT = 1 << 1 };
|
||||
|
|
|
@ -384,10 +384,7 @@ nsDOMAttribute::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild, nsIDO
|
|||
NS_IMETHODIMP
|
||||
nsDOMAttribute::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aOldChild);
|
||||
PRInt32 index = IndexOf(content);
|
||||
return (index == -1) ? NS_ERROR_DOM_NOT_FOUND_ERR :
|
||||
RemoveChildAt(index, PR_TRUE);
|
||||
return nsINode::RemoveChild(aOldChild, aReturn);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -252,7 +252,7 @@ nsDOMDocumentType::BindToTree(nsIDocument *aDocument, nsIContent *aParent,
|
|||
// case.
|
||||
// XXX We may want to move this to nsDOMImplementation::CreateDocument if
|
||||
// we want to rely on the nodeinfo and wrappers being right before
|
||||
// getting into doReplaceOrInsertBefore or doInsertChildAt. That would
|
||||
// getting into ReplaceOrInsertBefore or doInsertChildAt. That would
|
||||
// break inserting DOMDocumentType nodes through other DOM methods
|
||||
// though.
|
||||
nsNodeInfoManager *nimgr = aParent ?
|
||||
|
|
|
@ -5545,22 +5545,20 @@ NS_IMETHODIMP
|
|||
nsDocument::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
|
||||
nsIDOMNode** aReturn)
|
||||
{
|
||||
return nsGenericElement::doReplaceOrInsertBefore(PR_FALSE, aNewChild, aRefChild, nsnull, this,
|
||||
aReturn);
|
||||
return ReplaceOrInsertBefore(PR_FALSE, aNewChild, aRefChild, aReturn);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
|
||||
nsIDOMNode** aReturn)
|
||||
{
|
||||
return nsGenericElement::doReplaceOrInsertBefore(PR_TRUE, aNewChild, aOldChild, nsnull, this,
|
||||
aReturn);
|
||||
return ReplaceOrInsertBefore(PR_TRUE, aNewChild, aOldChild, aReturn);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
|
||||
{
|
||||
return nsGenericElement::doRemoveChild(aOldChild, nsnull, this, aReturn);
|
||||
return nsINode::RemoveChild(aOldChild, aReturn);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -567,6 +567,38 @@ nsINode::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
|
|||
return ownerDoc ? CallQueryInterface(ownerDoc, aOwnerDocument) : NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsINode::ReplaceOrInsertBefore(PRBool aReplace, nsIDOMNode* aNewChild,
|
||||
nsIDOMNode* aRefChild, nsIDOMNode** aReturn)
|
||||
{
|
||||
nsCOMPtr<nsINode> newChild = do_QueryInterface(aNewChild);
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINode> refChild;
|
||||
if (aRefChild) {
|
||||
refChild = do_QueryInterface(aRefChild, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = ReplaceOrInsertBefore(aReplace, newChild, refChild);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ADDREF(*aReturn = aReplace ? aRefChild : aNewChild);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsINode::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
|
||||
{
|
||||
nsCOMPtr<nsIContent> oldChild = do_QueryInterface(aOldChild);
|
||||
nsresult rv = RemoveChild(oldChild);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ADDREF(*aReturn = aOldChild);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
PRInt32
|
||||
|
@ -3516,45 +3548,22 @@ nsGenericElement::SaveSubtreeState()
|
|||
|
||||
// Generic DOMNode implementations
|
||||
|
||||
/*
|
||||
* This helper function checks if aChild is the same as aNode or if
|
||||
* aChild is one of aNode's ancestors. -- jst@citec.fi
|
||||
*/
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericElement::InsertBefore(nsIDOMNode *aNewChild, nsIDOMNode *aRefChild,
|
||||
nsIDOMNode **aReturn)
|
||||
{
|
||||
return doReplaceOrInsertBefore(PR_FALSE, aNewChild, aRefChild, this, GetCurrentDoc(),
|
||||
aReturn);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericElement::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
|
||||
nsIDOMNode** aReturn)
|
||||
{
|
||||
return doReplaceOrInsertBefore(PR_TRUE, aNewChild, aOldChild, this, GetCurrentDoc(),
|
||||
aReturn);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericElement::RemoveChild(nsIDOMNode *aOldChild, nsIDOMNode **aReturn)
|
||||
{
|
||||
return doRemoveChild(aOldChild, this, GetCurrentDoc(),
|
||||
aReturn);
|
||||
}
|
||||
|
||||
// When replacing, aRefContent is the content being replaced; when
|
||||
// inserting it's the content before which we're inserting. In the
|
||||
// latter case it may be null.
|
||||
static
|
||||
PRBool IsAllowedAsChild(nsIContent* aNewChild, PRUint16 aNewNodeType,
|
||||
nsIContent* aParent, nsIDocument* aDocument,
|
||||
PRBool aIsReplace, nsIContent* aRefContent)
|
||||
nsINode* aParent, PRBool aIsReplace,
|
||||
nsIContent* aRefContent)
|
||||
{
|
||||
NS_PRECONDITION(aNewChild, "Must have new child");
|
||||
NS_PRECONDITION(!aIsReplace || aRefContent,
|
||||
"Must have ref content for replace");
|
||||
NS_PRECONDITION(aParent->IsNodeOfType(nsINode::eDOCUMENT) ||
|
||||
aParent->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) ||
|
||||
aParent->IsNodeOfType(nsINode::eELEMENT),
|
||||
"Nodes that are not documents, document fragments or "
|
||||
"elements can't be parents!");
|
||||
#ifdef DEBUG
|
||||
PRUint16 debugNodeType = 0;
|
||||
nsCOMPtr<nsIDOMNode> debugNode(do_QueryInterface(aNewChild));
|
||||
|
@ -3581,12 +3590,13 @@ PRBool IsAllowedAsChild(nsIContent* aNewChild, PRUint16 aNewNodeType,
|
|||
return aParent != nsnull;
|
||||
case nsIDOMNode::ELEMENT_NODE :
|
||||
{
|
||||
if (aParent) {
|
||||
// Always ok to have elements under other elements
|
||||
if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
|
||||
// Always ok to have elements under other elements or document fragments
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsIContent* rootContent = aDocument->GetRootContent();
|
||||
nsIContent* rootContent =
|
||||
static_cast<nsIDocument*>(aParent)->GetRootContent();
|
||||
if (rootContent) {
|
||||
// Already have a documentElement, so this is only OK if we're
|
||||
// replacing it.
|
||||
|
@ -3601,7 +3611,7 @@ PRBool IsAllowedAsChild(nsIContent* aNewChild, PRUint16 aNewNodeType,
|
|||
}
|
||||
|
||||
// Now grovel for a doctype
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDocument);
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aParent);
|
||||
NS_ASSERTION(doc, "Shouldn't happen");
|
||||
nsCOMPtr<nsIDOMDocumentType> docType;
|
||||
doc->GetDoctype(getter_AddRefs(docType));
|
||||
|
@ -3612,8 +3622,8 @@ PRBool IsAllowedAsChild(nsIContent* aNewChild, PRUint16 aNewNodeType,
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRInt32 doctypeIndex = aDocument->IndexOf(docTypeContent);
|
||||
PRInt32 insertIndex = aDocument->IndexOf(aRefContent);
|
||||
PRInt32 doctypeIndex = aParent->IndexOf(docTypeContent);
|
||||
PRInt32 insertIndex = aParent->IndexOf(aRefContent);
|
||||
|
||||
// Now we're OK in the following two cases only:
|
||||
// 1) We're replacing something that's not before the doctype
|
||||
|
@ -3623,12 +3633,12 @@ PRBool IsAllowedAsChild(nsIContent* aNewChild, PRUint16 aNewNodeType,
|
|||
}
|
||||
case nsIDOMNode::DOCUMENT_TYPE_NODE :
|
||||
{
|
||||
if (aParent) {
|
||||
// no doctypes allowed under elements
|
||||
if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
|
||||
// doctypes only allowed under documents
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDocument);
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aParent);
|
||||
NS_ASSERTION(doc, "Shouldn't happen");
|
||||
nsCOMPtr<nsIDOMDocumentType> docType;
|
||||
doc->GetDoctype(getter_AddRefs(docType));
|
||||
|
@ -3640,7 +3650,8 @@ PRBool IsAllowedAsChild(nsIContent* aNewChild, PRUint16 aNewNodeType,
|
|||
|
||||
// We don't have a doctype yet. Our one remaining constraint is
|
||||
// that the doctype must come before the documentElement.
|
||||
nsIContent* rootContent = aDocument->GetRootContent();
|
||||
nsIContent* rootContent =
|
||||
static_cast<nsIDocument*>(aParent)->GetRootContent();
|
||||
if (!rootContent) {
|
||||
// It's all good
|
||||
return PR_TRUE;
|
||||
|
@ -3651,8 +3662,8 @@ PRBool IsAllowedAsChild(nsIContent* aNewChild, PRUint16 aNewNodeType,
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRInt32 rootIndex = aDocument->IndexOf(rootContent);
|
||||
PRInt32 insertIndex = aDocument->IndexOf(aRefContent);
|
||||
PRInt32 rootIndex = aParent->IndexOf(rootContent);
|
||||
PRInt32 insertIndex = aParent->IndexOf(aRefContent);
|
||||
|
||||
// Now we're OK if and only if insertIndex <= rootIndex. Indeed, either
|
||||
// we end up replacing aRefContent or we end up before it. Either one is
|
||||
|
@ -3664,7 +3675,7 @@ PRBool IsAllowedAsChild(nsIContent* aNewChild, PRUint16 aNewNodeType,
|
|||
// Note that for now we only allow nodes inside document fragments if
|
||||
// they're allowed inside elements. If we ever change this to allow
|
||||
// doctype nodes in document fragments, we'll need to update this code
|
||||
if (aParent) {
|
||||
if (!aParent->IsNodeOfType(nsINode::eDOCUMENT)) {
|
||||
// All good here
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -3686,8 +3697,8 @@ PRBool IsAllowedAsChild(nsIContent* aNewChild, PRUint16 aNewNodeType,
|
|||
nsCOMPtr<nsIDOMNode> childNode(do_QueryInterface(childContent));
|
||||
PRUint16 type;
|
||||
childNode->GetNodeType(&type);
|
||||
if (!IsAllowedAsChild(childContent, type, aParent, aDocument,
|
||||
aIsReplace, aRefContent)) {
|
||||
if (!IsAllowedAsChild(childContent, type, aParent, aIsReplace,
|
||||
aRefContent)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -3705,116 +3716,102 @@ PRBool IsAllowedAsChild(nsIContent* aNewChild, PRUint16 aNewNodeType,
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
||||
nsIDOMNode* aNewChild,
|
||||
nsIDOMNode* aRefChild,
|
||||
nsIContent* aParent,
|
||||
nsIDocument* aDocument,
|
||||
nsIDOMNode** aReturn)
|
||||
nsINode::ReplaceOrInsertBefore(PRBool aReplace, nsINode* aNewChild,
|
||||
nsINode* aRefChild)
|
||||
{
|
||||
NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
|
||||
NS_PRECONDITION(!aParent || aParent->GetCurrentDoc() == aDocument,
|
||||
"Incorrect aDocument");
|
||||
|
||||
*aReturn = nsnull;
|
||||
|
||||
if (!aNewChild || (aReplace && !aRefChild)) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
// Keep a strong reference to the node that we'll return to ensure it
|
||||
// doesn't go away.
|
||||
nsCOMPtr<nsIDOMNode> returnVal = aReplace ? aRefChild : aNewChild;
|
||||
|
||||
nsCOMPtr<nsIContent> refContent;
|
||||
nsIContent* refContent;
|
||||
nsresult res = NS_OK;
|
||||
PRInt32 insPos;
|
||||
|
||||
nsINode* container = NODE_FROM(aParent, aDocument);
|
||||
|
||||
// Figure out which index to insert at
|
||||
if (aRefChild) {
|
||||
refContent = do_QueryInterface(aRefChild);
|
||||
insPos = container->IndexOf(refContent);
|
||||
insPos = IndexOf(aRefChild);
|
||||
if (insPos < 0) {
|
||||
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
||||
}
|
||||
|
||||
if (aRefChild == aNewChild) {
|
||||
NS_ADDREF(*aReturn = aNewChild);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
insPos = container->GetChildCount();
|
||||
|
||||
NS_ASSERTION(aRefChild->IsNodeOfType(eCONTENT),
|
||||
"A child node must be nsIContent!");
|
||||
|
||||
refContent = static_cast<nsIContent*>(aRefChild);
|
||||
}
|
||||
else {
|
||||
insPos = GetChildCount();
|
||||
refContent = nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> newContent = do_QueryInterface(aNewChild);
|
||||
if (!newContent) {
|
||||
if (!aNewChild->IsNodeOfType(eCONTENT)) {
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
|
||||
nsIContent* newContent = static_cast<nsIContent*>(aNewChild);
|
||||
|
||||
PRUint16 nodeType = 0;
|
||||
res = aNewChild->GetNodeType(&nodeType);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
// Make sure that the inserted node is allowed as a child of its new parent.
|
||||
if (!IsAllowedAsChild(newContent, nodeType, aParent, aDocument, aReplace,
|
||||
refContent)) {
|
||||
if (!IsAllowedAsChild(newContent, nodeType, this, aReplace, refContent)) {
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
|
||||
nsIDocument *doc = container->GetOwnerDoc();
|
||||
nsIDocument *doc = GetOwnerDoc();
|
||||
|
||||
// DocumentType nodes are the only nodes that can have a null
|
||||
// ownerDocument according to the DOM spec, and we need to allow
|
||||
// inserting them w/o calling AdoptNode().
|
||||
if (!container->HasSameOwnerDoc(newContent) &&
|
||||
if (!HasSameOwnerDoc(newContent) &&
|
||||
(nodeType != nsIDOMNode::DOCUMENT_TYPE_NODE ||
|
||||
newContent->GetOwnerDoc())) {
|
||||
nsCOMPtr<nsIDOM3Document> domDoc = do_QueryInterface(doc);
|
||||
|
||||
if (domDoc) {
|
||||
nsCOMPtr<nsIDOMNode> adoptedKid;
|
||||
nsresult rv = domDoc->AdoptNode(aNewChild, getter_AddRefs(adoptedKid));
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIDOMNode> newChild = do_QueryInterface(aNewChild, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ASSERTION(adoptedKid == aNewChild, "Uh, adopt node changed nodes?");
|
||||
NS_ASSERTION(container->HasSameOwnerDoc(newContent) &&
|
||||
doc == container->GetOwnerDoc(),
|
||||
nsCOMPtr<nsIDOMNode> adoptedKid;
|
||||
rv = domDoc->AdoptNode(newChild, getter_AddRefs(adoptedKid));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ASSERTION(adoptedKid == newChild, "Uh, adopt node changed nodes?");
|
||||
NS_ASSERTION(HasSameOwnerDoc(newContent) && doc == GetOwnerDoc(),
|
||||
"ownerDocument changed again after adopting!");
|
||||
}
|
||||
}
|
||||
|
||||
// We want an update batch when we expect several mutations to be performed,
|
||||
// which is when we're replacing a node, or when we're inserting a fragment.
|
||||
mozAutoDocConditionalContentUpdateBatch batch(aDocument,
|
||||
mozAutoDocConditionalContentUpdateBatch batch(GetCurrentDoc(),
|
||||
aReplace || nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE);
|
||||
|
||||
// If we're replacing
|
||||
if (aReplace) {
|
||||
// Getting (and addrefing) the following child here is sort of wasteful
|
||||
// in the common case, but really, it's not that expensive. Get over it.
|
||||
refContent = container->GetChildAt(insPos + 1);
|
||||
refContent = GetChildAt(insPos + 1);
|
||||
|
||||
nsMutationGuard guard;
|
||||
|
||||
res = container->RemoveChildAt(insPos, PR_TRUE);
|
||||
res = RemoveChildAt(insPos, PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
if (guard.Mutated(1)) {
|
||||
insPos = refContent ? container->IndexOf(refContent) :
|
||||
container->GetChildCount();
|
||||
insPos = refContent ? IndexOf(refContent) : GetChildCount();
|
||||
if (insPos < 0) {
|
||||
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
||||
}
|
||||
|
||||
// Passing PR_FALSE for aIsReplace since we now have removed the node
|
||||
// to be replaced.
|
||||
if (!IsAllowedAsChild(newContent, nodeType, aParent, aDocument,
|
||||
PR_FALSE, refContent)) {
|
||||
if (!IsAllowedAsChild(newContent, nodeType, this, PR_FALSE, refContent)) {
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
}
|
||||
|
@ -3829,8 +3826,6 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
PRUint32 count = newContent->GetChildCount();
|
||||
|
||||
if (!count) {
|
||||
returnVal.swap(*aReturn);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -3865,7 +3860,7 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
for (i = 0; i < count; ++i) {
|
||||
// Get the n:th child from the array.
|
||||
nsIContent* childContent = fragChildren[i];
|
||||
if (!container->HasSameOwnerDoc(childContent) ||
|
||||
if (!HasSameOwnerDoc(childContent) ||
|
||||
doc != childContent->GetOwnerDoc()) {
|
||||
return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
|
||||
}
|
||||
|
@ -3875,14 +3870,13 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
tmpNode->GetNodeType(&tmpType);
|
||||
|
||||
if (childContent->GetNodeParent() ||
|
||||
!IsAllowedAsChild(childContent, tmpType, aParent, aDocument, PR_FALSE,
|
||||
!IsAllowedAsChild(childContent, tmpType, this, PR_FALSE,
|
||||
refContent)) {
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
insPos = refContent ? container->IndexOf(refContent) :
|
||||
container->GetChildCount();
|
||||
insPos = refContent ? IndexOf(refContent) : GetChildCount();
|
||||
if (insPos < 0) {
|
||||
// Someone seriously messed up the childlist. We have no idea
|
||||
// where to insert the remaining children, so just bail.
|
||||
|
@ -3890,7 +3884,7 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
}
|
||||
}
|
||||
|
||||
PRBool appending = aParent && (insPos == container->GetChildCount());
|
||||
PRBool appending = !IsNodeOfType(eDOCUMENT) && insPos == GetChildCount();
|
||||
PRBool firstInsPos = insPos;
|
||||
|
||||
// Iterate through the fragment's children, and insert them in the new
|
||||
|
@ -3900,23 +3894,24 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
|
||||
// XXXbz how come no reparenting here? That seems odd...
|
||||
// Insert the child.
|
||||
res = container->InsertChildAt(childContent, insPos, PR_FALSE);
|
||||
res = InsertChildAt(childContent, insPos, PR_FALSE);
|
||||
if (NS_FAILED(res)) {
|
||||
// Make sure to notify on any children that we did succeed to insert
|
||||
if (appending && i != 0) {
|
||||
nsNodeUtils::ContentAppended(aParent, firstInsPos);
|
||||
nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this),
|
||||
firstInsPos);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!appending) {
|
||||
nsNodeUtils::ContentInserted(container, childContent, insPos);
|
||||
nsNodeUtils::ContentInserted(this, childContent, insPos);
|
||||
}
|
||||
}
|
||||
|
||||
// Notify
|
||||
if (appending) {
|
||||
nsNodeUtils::ContentAppended(aParent, firstInsPos);
|
||||
nsNodeUtils::ContentAppended(static_cast<nsIContent*>(this), firstInsPos);
|
||||
}
|
||||
|
||||
// Fire mutation events. Optimize for the case when there are no listeners
|
||||
|
@ -3928,13 +3923,13 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
nsIContent* childContent = fragChildren[i];
|
||||
|
||||
if (nsContentUtils::HasMutationListeners(childContent,
|
||||
NS_EVENT_BITS_MUTATION_NODEINSERTED, container)) {
|
||||
mozAutoRemovableBlockerRemover blockerRemover(container->GetOwnerDoc());
|
||||
NS_EVENT_BITS_MUTATION_NODEINSERTED, this)) {
|
||||
mozAutoRemovableBlockerRemover blockerRemover(doc);
|
||||
|
||||
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEINSERTED);
|
||||
mutation.mRelatedNode = do_QueryInterface(container);
|
||||
mutation.mRelatedNode = do_QueryInterface(this);
|
||||
|
||||
mozAutoSubtreeModified subtree(container->GetOwnerDoc(), container);
|
||||
mozAutoSubtreeModified subtree(doc, this);
|
||||
nsEventDispatcher::Dispatch(childContent, nsnull, &mutation);
|
||||
}
|
||||
}
|
||||
|
@ -3962,7 +3957,7 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!(oldParent == container && removeIndex == insPos),
|
||||
NS_ASSERTION(!(oldParent == this && removeIndex == insPos),
|
||||
"invalid removeIndex");
|
||||
|
||||
nsMutationGuard guard;
|
||||
|
@ -3972,7 +3967,7 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
|
||||
// Adjust insert index if the node we ripped out was a sibling
|
||||
// of the node we're inserting before
|
||||
if (oldParent == container && removeIndex < insPos) {
|
||||
if (oldParent == this && removeIndex < insPos) {
|
||||
--insPos;
|
||||
}
|
||||
|
||||
|
@ -3981,8 +3976,7 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
|
||||
}
|
||||
|
||||
insPos = refContent ? container->IndexOf(refContent) :
|
||||
container->GetChildCount();
|
||||
insPos = refContent ? IndexOf(refContent) : GetChildCount();
|
||||
if (insPos < 0) {
|
||||
// Someone seriously messed up the childlist. We have no idea
|
||||
// where to insert the new child, so just bail.
|
||||
|
@ -3990,8 +3984,8 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
}
|
||||
|
||||
if (newContent->GetNodeParent() ||
|
||||
!IsAllowedAsChild(newContent, nodeType, aParent, aDocument,
|
||||
PR_FALSE, refContent)) {
|
||||
!IsAllowedAsChild(newContent, nodeType, this, PR_FALSE,
|
||||
refContent)) {
|
||||
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
||||
}
|
||||
}
|
||||
|
@ -4002,45 +3996,13 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
|
|||
// wrapper is not the wrapper for their ownerDocument (XUL elements,
|
||||
// form controls, ...).
|
||||
|
||||
res = container->InsertChildAt(newContent, insPos, PR_TRUE);
|
||||
res = InsertChildAt(newContent, insPos, PR_TRUE);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
|
||||
returnVal.swap(*aReturn);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
nsGenericElement::doRemoveChild(nsIDOMNode* aOldChild, nsIContent* aParent,
|
||||
nsIDocument* aDocument, nsIDOMNode** aReturn)
|
||||
{
|
||||
NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
|
||||
NS_PRECONDITION(!aParent || aParent->GetCurrentDoc() == aDocument,
|
||||
"Incorrect aDocument");
|
||||
|
||||
*aReturn = nsnull;
|
||||
NS_ENSURE_TRUE(aOldChild, NS_ERROR_NULL_POINTER);
|
||||
|
||||
nsINode* container = NODE_FROM(aParent, aDocument);
|
||||
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aOldChild);
|
||||
// fix children to be a passed argument
|
||||
PRInt32 index = container->IndexOf(content);
|
||||
if (index == -1) {
|
||||
// aOldChild isn't one of our children.
|
||||
return NS_ERROR_DOM_NOT_FOUND_ERR;
|
||||
}
|
||||
|
||||
nsresult rv = container->RemoveChildAt(index, PR_TRUE);
|
||||
|
||||
*aReturn = aOldChild;
|
||||
NS_ADDREF(aOldChild);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
// nsISupports implementation
|
||||
|
|
|
@ -493,12 +493,21 @@ public:
|
|||
const nsAString& aVersion, PRBool* aReturn);
|
||||
NS_IMETHOD HasAttributes(PRBool* aHasAttributes);
|
||||
NS_IMETHOD HasChildNodes(PRBool* aHasChildNodes);
|
||||
NS_IMETHOD InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
|
||||
nsIDOMNode** aReturn);
|
||||
NS_IMETHOD ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
|
||||
nsIDOMNode** aReturn);
|
||||
NS_IMETHOD RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn);
|
||||
NS_IMETHOD AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
|
||||
nsresult InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
|
||||
nsIDOMNode** aReturn)
|
||||
{
|
||||
return ReplaceOrInsertBefore(PR_FALSE, aNewChild, aRefChild, aReturn);
|
||||
}
|
||||
nsresult ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
|
||||
nsIDOMNode** aReturn)
|
||||
{
|
||||
return ReplaceOrInsertBefore(PR_TRUE, aNewChild, aOldChild, aReturn);
|
||||
}
|
||||
nsresult RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
|
||||
{
|
||||
return nsINode::RemoveChild(aOldChild, aReturn);
|
||||
}
|
||||
nsresult AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
|
||||
{
|
||||
return InsertBefore(aNewChild, nsnull, aReturn);
|
||||
}
|
||||
|
@ -589,39 +598,6 @@ public:
|
|||
|
||||
static PRBool ShouldBlur(nsIContent *aContent);
|
||||
|
||||
/**
|
||||
* Actual implementation of the DOM InsertBefore and ReplaceChild methods.
|
||||
* Shared by nsDocument. When called from nsDocument, aParent will be null.
|
||||
*
|
||||
* @param aReplace True if aNewChild should replace aRefChild. False if
|
||||
* aNewChild should be inserted before aRefChild.
|
||||
* @param aNewChild The child to insert
|
||||
* @param aRefChild The child to insert before or replace
|
||||
* @param aParent The parent to use for the new child
|
||||
* @param aDocument The document to use for the new child.
|
||||
* Must be non-null, if aParent is null and must match
|
||||
* aParent->GetCurrentDoc() if aParent is not null.
|
||||
* @param aReturn [out] the child we insert
|
||||
*/
|
||||
static nsresult doReplaceOrInsertBefore(PRBool aReplace, nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
|
||||
nsIContent* aParent, nsIDocument* aDocument,
|
||||
nsIDOMNode** aReturn);
|
||||
|
||||
/**
|
||||
* Actual implementation of the DOM RemoveChild method. Shared by
|
||||
* nsDocument. When called from nsDocument, aParent will be null.
|
||||
*
|
||||
* @param aOldChild The child to remove
|
||||
* @param aParent The parent to use for the new child
|
||||
* @param aDocument The document to use for the new child.
|
||||
* Must be non-null if aParent is null and must match
|
||||
* aParent->GetCurrentDoc() if aParent is not null.
|
||||
* @param aReturn [out] the child we remove
|
||||
*/
|
||||
static nsresult doRemoveChild(nsIDOMNode* aOldChild,
|
||||
nsIContent* aParent, nsIDocument* aDocument,
|
||||
nsIDOMNode** aReturn);
|
||||
|
||||
/**
|
||||
* Most of the implementation of the nsINode InsertChildAt method. Shared by
|
||||
* nsDocument. When called from nsDocument, aParent will be null.
|
||||
|
|
|
@ -77,7 +77,7 @@ var indexErrTests = ["characterdataindexsizeerrdeletedatacountnegative", "charac
|
|||
var attributeModTests = ["hc_attrappendchild1", "hc_attrappendchild2", "hc_attrappendchild3", "hc_attrappendchild5",
|
||||
"hc_attrappendchild6", "hc_attrchildnodes2", "hc_attrclonenode1", "hc_attrinsertbefore1",
|
||||
"hc_attrinsertbefore2", "hc_attrinsertbefore3", "hc_attrinsertbefore4", "hc_attrinsertbefore6",
|
||||
"hc_attrnormalize", "hc_attrremovechild1", "hc_attrremovechild2", "hc_attrreplacechild1", "hc_attrreplacechild2",
|
||||
"hc_attrnormalize", "hc_attrremovechild2", "hc_attrreplacechild1", "hc_attrreplacechild2",
|
||||
"hc_attrsetvalue2", "hc_elementnormalize2", "hc_elementnotfounderr", "hc_elementremoveattribute", "hc_elementnormalize2",
|
||||
"hc_elementnotfounderr", "hc_elementremoveattribute", ];
|
||||
var modTests = ["hc_elementwrongdocumenterr", "hc_namednodemapwrongdocumenterr", "hc_nodeappendchildnewchilddiffdocument", "hc_nodeinsertbeforenewchilddiffdocument",
|
||||
|
|
|
@ -15,9 +15,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=503926
|
|||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
var gWindowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
var passed = false;
|
||||
var obj = { QueryInterface: function() { passed = true; } }
|
||||
try { document.documentElement.appendChild(obj); } catch (e) {}
|
||||
try { gWindowUtils.dispatchDOMEventViaPresShell(obj, obj, false); } catch (e) {}
|
||||
var isDialog = location.hash != '#iframe';
|
||||
var outer = XPCNativeWrapper.unwrap(isDialog ? opener : top);
|
||||
outer.ok(passed, "chrome/chrome test passed: " + (isDialog ? "dialog" : "iframe"));
|
||||
|
|
|
@ -26,9 +26,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=503926
|
|||
|
||||
/** Test for Bug 503926 **/
|
||||
function iframe_loaded() {
|
||||
var gWindowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
|
||||
getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
var passed = false;
|
||||
var obj = { QueryInterface: function() { passed = true; } };
|
||||
try { document.documentElement.appendChild(obj); } catch (e) {}
|
||||
try { gWindowUtils.dispatchDOMEventViaPresShell(obj, obj, false); } catch (e) {}
|
||||
ok(passed, "trusted QIs should be called");
|
||||
|
||||
openDialog("chrome://mochikit/content/chrome/js/src/xpconnect/tests/chrome/bug503926.xul",
|
||||
|
|
Загрузка…
Ссылка в новой задаче