Fixing bug 197427. Making insertBefore, appendChild, replaceChild, and removeChild() work correctly on XUL elements by sharing the implementation with nsGenericElement. r=jonas@sicking.cc, sr=bzbarsky@mit.edu

This commit is contained in:
jst%mozilla.jstenback.com 2004-02-05 06:48:30 +00:00
parent ce288b37c7
commit cb45f84bb7
5 changed files with 72 additions and 178 deletions

View File

@ -2577,10 +2577,10 @@ isSelfOrAncestor(nsIContent *aNode, nsIContent *aChild)
}
// static
nsresult
nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
nsIDOMNode* aRefChild,
nsIDOMNode** aReturn)
nsGenericElement::doInsertBefore(nsIContent *aElement, nsIDOMNode *aNewChild,
nsIDOMNode *aRefChild, nsIDOMNode **aReturn)
{
if (!aReturn) {
return NS_ERROR_NULL_POINTER;
@ -2607,13 +2607,13 @@ nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
return NS_ERROR_DOM_NOT_FOUND_ERR;
}
refPos = IndexOf(refContent);
refPos = aElement->IndexOf(refContent);
if (refPos < 0) {
return NS_ERROR_DOM_NOT_FOUND_ERR;
}
} else {
refPos = GetChildCount();
refPos = aElement->GetChildCount();
}
PRUint16 nodeType = 0;
@ -2648,7 +2648,7 @@ nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
}
nsCOMPtr<nsIDocument> old_doc = newContent->GetDocument();
if (old_doc && old_doc != mDocument &&
if (old_doc && old_doc != aElement->GetDocument() &&
!nsContentUtils::CanCallerAccess(aNewChild)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
@ -2658,7 +2658,7 @@ nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
* ancestors. Doing this check here should be safe even if newContent
* is a document fragment.
*/
if (isSelfOrAncestor(this, newContent)) {
if (isSelfOrAncestor(aElement, newContent)) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
@ -2675,7 +2675,7 @@ nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
PRUint32 count = newContent->GetChildCount();
PRUint32 old_count = GetChildCount();
PRUint32 old_count = aElement->GetChildCount();
PRBool do_notify = !!aRefChild;
@ -2683,7 +2683,7 @@ nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
// ourselves... Also, if count is 0 there will be no updates. So we only
// want an update batch to happen if count is nonzero and do_notify is not
// true.
mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL,
mozAutoDocUpdate updateBatch(aElement->GetDocument(), UPDATE_CONTENT_MODEL,
count && !do_notify);
/*
@ -2703,7 +2703,8 @@ nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
childContent = newContent->GetChildAt(i);
// Insert the child and increment the insertion position
res = InsertChildAt(childContent, refPos++, do_notify, PR_TRUE);
res = aElement->InsertChildAt(childContent, refPos++, do_notify,
PR_TRUE);
if (NS_FAILED(res)) {
break;
@ -2720,8 +2721,10 @@ nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
return res;
}
if (count && !do_notify && mDocument) {
mDocument->ContentAppended(this, old_count);
nsIDocument *doc = aElement->GetDocument();
if (count && !do_notify && doc) {
doc->ContentAppended(aElement, old_count);
}
doc_fragment->DropChildReferences();
@ -2742,14 +2745,14 @@ nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
if (oldParent) {
nsCOMPtr<nsIDOMNode> tmpNode;
PRUint32 origChildCount = GetChildCount();
PRUint32 origChildCount = aElement->GetChildCount();
/*
* We don't care here if the return fails or not.
*/
oldParent->RemoveChild(aNewChild, getter_AddRefs(tmpNode));
PRUint32 newChildCount = GetChildCount();
PRUint32 newChildCount = aElement->GetChildCount();
/*
* Check if our child count changed during the RemoveChild call, if
@ -2764,7 +2767,7 @@ nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
* previous siblings.
*/
if (refContent == GetChildAt(refPos - 1)) {
if (refContent == aElement->GetChildAt(refPos - 1)) {
refPos--;
}
} else {
@ -2776,10 +2779,10 @@ nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
}
}
nsContentUtils::ReparentContentWrapper(newContent, this, mDocument,
old_doc);
nsContentUtils::ReparentContentWrapper(newContent, aElement,
aElement->GetDocument(), old_doc);
res = InsertChildAt(newContent, refPos, PR_TRUE, PR_TRUE);
res = aElement->InsertChildAt(newContent, refPos, PR_TRUE, PR_TRUE);
if (NS_FAILED(res)) {
return res;
@ -2793,10 +2796,10 @@ nsGenericElement::doInsertBefore(nsIDOMNode* aNewChild,
}
// static
nsresult
nsGenericElement::doReplaceChild(nsIDOMNode* aNewChild,
nsIDOMNode* aOldChild,
nsIDOMNode** aReturn)
nsGenericElement::doReplaceChild(nsIContent* aElement, nsIDOMNode* aNewChild,
nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
{
if (!aReturn) {
return NS_ERROR_NULL_POINTER;
@ -2821,13 +2824,13 @@ nsGenericElement::doReplaceChild(nsIDOMNode* aNewChild,
return NS_ERROR_DOM_NOT_FOUND_ERR;
}
oldPos = IndexOf(oldContent);
oldPos = aElement->IndexOf(oldContent);
if (oldPos < 0) {
return NS_ERROR_DOM_NOT_FOUND_ERR;
}
nsCOMPtr<nsIContent> replacedChild = GetChildAt(oldPos);
nsCOMPtr<nsIContent> replacedChild = aElement->GetChildAt(oldPos);
PRUint16 nodeType = 0;
@ -2861,7 +2864,7 @@ nsGenericElement::doReplaceChild(nsIDOMNode* aNewChild,
}
nsCOMPtr<nsIDocument> old_doc = newContent->GetDocument();
if (old_doc && old_doc != mDocument &&
if (old_doc && old_doc != aElement->GetDocument() &&
!nsContentUtils::CanCallerAccess(aNewChild)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
@ -2871,7 +2874,7 @@ nsGenericElement::doReplaceChild(nsIDOMNode* aNewChild,
* ancestors. Doing this check here should be safe even if newContent
* is a document fragment.
*/
if (isSelfOrAncestor(this, newContent)) {
if (isSelfOrAncestor(aElement, newContent)) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
@ -2902,9 +2905,11 @@ nsGenericElement::doReplaceChild(nsIDOMNode* aNewChild,
// Insert the child and increment the insertion position
if (i) {
res = InsertChildAt(childContent, oldPos++, PR_TRUE, PR_TRUE);
res = aElement->InsertChildAt(childContent, oldPos++, PR_TRUE,
PR_TRUE);
} else {
res = ReplaceChildAt(childContent, oldPos++, PR_TRUE, PR_TRUE);
res = aElement->ReplaceChildAt(childContent, oldPos++, PR_TRUE,
PR_TRUE);
}
if (NS_FAILED(res)) {
@ -2928,14 +2933,14 @@ nsGenericElement::doReplaceChild(nsIDOMNode* aNewChild,
if (oldParent) {
nsCOMPtr<nsIDOMNode> tmpNode;
PRUint32 origChildCount = GetChildCount();
PRUint32 origChildCount = aElement->GetChildCount();
/*
* We don't care here if the return fails or not.
*/
oldParent->RemoveChild(aNewChild, getter_AddRefs(tmpNode));
PRUint32 newChildCount = GetChildCount();
PRUint32 newChildCount = aElement->GetChildCount();
/*
* Check if our child count changed during the RemoveChild call, if
@ -2947,7 +2952,7 @@ nsGenericElement::doReplaceChild(nsIDOMNode* aNewChild,
* Check if aOldChild is now at oldPos - 1, this will happend if
* the new child was one of aOldChilds' previous siblings.
*/
nsIContent *tmpContent = GetChildAt(oldPos - 1);
nsIContent *tmpContent = aElement->GetChildAt(oldPos - 1);
if (oldContent == tmpContent) {
oldPos--;
@ -2955,8 +2960,8 @@ nsGenericElement::doReplaceChild(nsIDOMNode* aNewChild,
}
}
nsContentUtils::ReparentContentWrapper(newContent, this, mDocument,
old_doc);
nsContentUtils::ReparentContentWrapper(newContent, aElement,
aElement->GetDocument(), old_doc);
if (aNewChild == aOldChild) {
// We're replacing a child with itself. In this case the child
@ -2965,9 +2970,9 @@ nsGenericElement::doReplaceChild(nsIDOMNode* aNewChild,
// longer at oldPos). In stead we'll call InsertChildAt() to put
// the child back where it was.
res = InsertChildAt(newContent, oldPos, PR_TRUE, PR_TRUE);
res = aElement->InsertChildAt(newContent, oldPos, PR_TRUE, PR_TRUE);
} else {
res = ReplaceChildAt(newContent, oldPos, PR_TRUE, PR_TRUE);
res = aElement->ReplaceChildAt(newContent, oldPos, PR_TRUE, PR_TRUE);
}
if (NS_FAILED(res)) {
@ -2979,8 +2984,10 @@ nsGenericElement::doReplaceChild(nsIDOMNode* aNewChild,
}
// static
nsresult
nsGenericElement::doRemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
nsGenericElement::doRemoveChild(nsIContent *aElement, nsIDOMNode *aOldChild,
nsIDOMNode **aReturn)
{
*aReturn = nsnull;
@ -3000,7 +3007,7 @@ nsGenericElement::doRemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
return NS_ERROR_DOM_NOT_FOUND_ERR;
}
PRInt32 pos = IndexOf(content);
PRInt32 pos = aElement->IndexOf(content);
if (pos < 0) {
/*
@ -3009,7 +3016,7 @@ nsGenericElement::doRemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
return NS_ERROR_DOM_NOT_FOUND_ERR;
}
res = RemoveChildAt(pos, PR_TRUE);
res = aElement->RemoveChildAt(pos, PR_TRUE);
*aReturn = aOldChild;
NS_ADDREF(aOldChild);

View File

@ -485,19 +485,20 @@ public:
* Generic implementation of InsertBefore to be called by subclasses
* @see nsIDOMNode::InsertBefore
*/
nsresult doInsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
nsIDOMNode** aReturn);
static nsresult doInsertBefore(nsIContent *aElement, nsIDOMNode* aNewChild,
nsIDOMNode* aRefChild, nsIDOMNode** aReturn);
/**
* Generic implementation of ReplaceChild to be called by subclasses
* @see nsIDOMNode::ReplaceChild
*/
nsresult doReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
nsIDOMNode** aReturn);
static nsresult doReplaceChild(nsIContent *aElement, nsIDOMNode* aNewChild,
nsIDOMNode* aOldChild, nsIDOMNode** aReturn);
/**
* Generic implementation of RemoveChild to be called by subclasses
* @see nsIDOMNode::RemoveChild
*/
nsresult doRemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn);
static nsresult doRemoveChild(nsIContent *aElement, nsIDOMNode* aOldChild,
nsIDOMNode** aReturn);
//----------------------------------------
@ -762,20 +763,22 @@ public:
NS_IMETHOD InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
nsIDOMNode** aReturn)
{
return nsGenericElement::doInsertBefore(aNewChild, aRefChild, aReturn);
return nsGenericElement::doInsertBefore(this, aNewChild, aRefChild,
aReturn);
}
NS_IMETHOD ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
nsIDOMNode** aReturn)
{
return nsGenericElement::doReplaceChild(aNewChild, aOldChild, aReturn);
return nsGenericElement::doReplaceChild(this, aNewChild, aOldChild,
aReturn);
}
NS_IMETHOD RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
{
return nsGenericElement::doRemoveChild(aOldChild, aReturn);
return nsGenericElement::doRemoveChild(this, aOldChild, aReturn);
}
NS_IMETHOD AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
{
return nsGenericElement::doInsertBefore(aNewChild, nsnull, aReturn);
return nsGenericElement::doInsertBefore(this, aNewChild, nsnull, aReturn);
}
// Remainder of nsIContent

View File

@ -905,20 +905,22 @@ public:
NS_METHOD InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
nsIDOMNode** aReturn)
{
return nsGenericElement::doInsertBefore(aNewChild, aRefChild, aReturn);
return nsGenericElement::doInsertBefore(this, aNewChild, aRefChild,
aReturn);
}
NS_METHOD ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
nsIDOMNode** aReturn)
{
return nsGenericElement::doReplaceChild(aNewChild, aOldChild, aReturn);
return nsGenericElement::doReplaceChild(this, aNewChild, aOldChild,
aReturn);
}
NS_METHOD RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
{
return nsGenericElement::doRemoveChild(aOldChild, aReturn);
return nsGenericElement::doRemoveChild(this, aOldChild, aReturn);
}
NS_METHOD AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
{
return nsGenericElement::doInsertBefore(aNewChild, nsnull, aReturn);
return nsGenericElement::doInsertBefore(this, aNewChild, nsnull, aReturn);
}
// Remainder of nsIHTMLContent (and nsIContent)

View File

@ -396,25 +396,25 @@ nsSVGElement::GetLocalName(nsAString& aLocalName)
NS_IMETHODIMP
nsSVGElement::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild, nsIDOMNode** aReturn)
{
return nsGenericElement::doInsertBefore(aNewChild, aRefChild, aReturn);
return nsGenericElement::doInsertBefore(this, aNewChild, aRefChild, aReturn);
}
NS_IMETHODIMP
nsSVGElement::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
{
return nsGenericElement::doReplaceChild(aNewChild, aOldChild, aReturn);
return nsGenericElement::doReplaceChild(this, aNewChild, aOldChild, aReturn);
}
NS_IMETHODIMP
nsSVGElement::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
{
return nsGenericElement::doRemoveChild(aOldChild, aReturn);
return nsGenericElement::doRemoveChild(this, aOldChild, aReturn);
}
NS_IMETHODIMP
nsSVGElement::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
{
return nsGenericElement::doInsertBefore(aNewChild, nsnull, aReturn);
return nsGenericElement::doInsertBefore(this, aNewChild, nsnull, aReturn);
}
NS_IMETHODIMP

View File

@ -858,74 +858,8 @@ NS_IMETHODIMP
nsXULElement::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
nsIDOMNode** aReturn)
{
NS_PRECONDITION(aNewChild != nsnull, "null ptr");
if (! aNewChild)
return NS_ERROR_NULL_POINTER;
// aRefChild may be null; that means "append".
nsresult rv = nsContentUtils::CheckSameOrigin(this, aNewChild);
if (NS_FAILED(rv))
return rv;
// We can't insert an ancestor or ourself.
if (IsAncestor(aNewChild, this)) {
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
nsCOMPtr<nsIContent> newcontent = do_QueryInterface(aNewChild);
NS_ASSERTION(newcontent != nsnull, "not an nsIContent");
if (! newcontent)
return NS_ERROR_UNEXPECTED;
// First, check to see if the content was already parented
// somewhere. If so, remove it.
nsCOMPtr<nsIContent> oldparent = newcontent->GetParent();
if (oldparent) {
PRInt32 oldindex = oldparent->IndexOf(newcontent);
NS_ASSERTION(oldindex >= 0, "old parent didn't think aNewChild was a child");
if (oldindex >= 0) {
rv = oldparent->RemoveChildAt(oldindex, PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
}
// Now, insert the element into the content model under 'this'
if (aRefChild) {
nsCOMPtr<nsIContent> refcontent = do_QueryInterface(aRefChild);
NS_ASSERTION(refcontent != nsnull, "not an nsIContent");
if (! refcontent)
return NS_ERROR_UNEXPECTED;
PRInt32 pos = IndexOf(refcontent);
if (pos >= 0) {
// Some frames assume that the document will have been set,
// so pass in PR_TRUE for aDeepSetDocument here.
rv = InsertChildAt(newcontent, pos, PR_TRUE, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to insert aNewChild");
if (NS_FAILED(rv)) return rv;
}
// XXX Hmm. There's a case here that we handle ambiguously, I
// think. If aRefChild _isn't_ actually one of our kids, then
// pos == -1, and we'll never insert the new kid. Should we
// just append it?
}
else {
// Some frames assume that the document will have been set,
// so pass in PR_TRUE for aDeepSetDocument here.
rv = AppendChildTo(newcontent, PR_TRUE, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to append a aNewChild");
if (NS_FAILED(rv)) return rv;
}
NS_ADDREF(aNewChild);
*aReturn = aNewChild;
return NS_OK;
return nsGenericElement::doInsertBefore(this, aNewChild, aRefChild,
aReturn);
}
@ -933,74 +867,22 @@ NS_IMETHODIMP
nsXULElement::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
nsIDOMNode** aReturn)
{
NS_PRECONDITION(aNewChild != nsnull, "null ptr");
if (! aNewChild)
return NS_ERROR_NULL_POINTER;
NS_PRECONDITION(aOldChild != nsnull, "null ptr");
if (! aOldChild)
return NS_ERROR_NULL_POINTER;
nsresult rv = nsContentUtils::CheckSameOrigin(this, aNewChild);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIContent> oldelement = do_QueryInterface(aOldChild);
NS_ASSERTION(oldelement != nsnull, "not an nsIContent");
if (oldelement) {
PRInt32 pos = IndexOf(oldelement);
if (pos >= 0) {
nsCOMPtr<nsIContent> newelement = do_QueryInterface(aNewChild);
NS_ASSERTION(newelement != nsnull, "not an nsIContent");
if (newelement) {
// Some frames assume that the document will have been set,
// so pass in PR_TRUE for aDeepSetDocument here.
rv = ReplaceChildAt(newelement, pos, PR_TRUE, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to replace old child");
}
}
}
NS_ADDREF(aNewChild);
*aReturn = aNewChild;
return NS_OK;
return nsGenericElement::doReplaceChild(this, aNewChild, aOldChild,
aReturn);
}
NS_IMETHODIMP
nsXULElement::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
{
NS_PRECONDITION(aOldChild != nsnull, "null ptr");
if (! aOldChild)
return NS_ERROR_NULL_POINTER;
nsresult rv;
nsCOMPtr<nsIContent> element = do_QueryInterface(aOldChild);
NS_ASSERTION(element != nsnull, "not an nsIContent");
if (element) {
PRInt32 pos = IndexOf(element);
if (pos >= 0) {
rv = RemoveChildAt(pos, PR_TRUE);
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to remove old child");
}
}
NS_ADDREF(aOldChild);
*aReturn = aOldChild;
return NS_OK;
return nsGenericElement::doRemoveChild(this, aOldChild, aReturn);
}
NS_IMETHODIMP
nsXULElement::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
{
return InsertBefore(aNewChild, nsnull, aReturn);
return nsGenericElement::doInsertBefore(this, aNewChild, nsnull, aReturn);
}