From 1ac65a91faefef6299c2c531732d9ecd125fa10e Mon Sep 17 00:00:00 2001 From: "cvshook%sicking.cc" Date: Tue, 16 May 2006 14:51:52 +0000 Subject: [PATCH] Bug 335913: Reimplement CompareDocumentPosition using nsINode interfaces. r/sr=bz git-svn-id: svn://10.0.0.236/trunk@196673 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/content/base/public/nsContentUtils.h | 51 +-- mozilla/content/base/public/nsINode.h | 2 +- .../content/base/src/nsAttrAndChildArray.cpp | 2 +- .../content/base/src/nsAttrAndChildArray.h | 3 +- mozilla/content/base/src/nsAttrName.h | 5 + mozilla/content/base/src/nsContentList.cpp | 16 +- mozilla/content/base/src/nsContentUtils.cpp | 307 +++++++----------- mozilla/content/base/src/nsDOMAttribute.cpp | 132 +------- mozilla/content/base/src/nsDOMAttribute.h | 2 +- mozilla/content/base/src/nsDocument.cpp | 69 +--- mozilla/content/base/src/nsDocument.h | 2 +- .../content/base/src/nsDocumentFragment.cpp | 48 +-- .../content/base/src/nsGenericDOMDataNode.cpp | 2 +- .../content/base/src/nsGenericDOMDataNode.h | 2 +- mozilla/content/base/src/nsGenericElement.cpp | 63 +--- mozilla/content/base/src/nsGenericElement.h | 2 +- .../content/xul/content/src/nsXULElement.cpp | 2 +- .../content/xul/content/src/nsXULElement.h | 2 +- 18 files changed, 195 insertions(+), 517 deletions(-) diff --git a/mozilla/content/base/public/nsContentUtils.h b/mozilla/content/base/public/nsContentUtils.h index 504de426100..0aa60db77b2 100644 --- a/mozilla/content/base/public/nsContentUtils.h +++ b/mozilla/content/base/public/nsContentUtils.h @@ -51,6 +51,7 @@ #include "nsContentList.h" #include "nsDOMClassInfoID.h" #include "nsIClassInfo.h" +#include "nsIDOM3Node.h" class nsIDOMScriptObjectFactory; class nsIXPConnect; @@ -175,41 +176,49 @@ public: /* * The out parameter, |aCommonAncestor| will be the closest node, if any, * to both |aNode| and |aOther| which is also an ancestor of each. + * Returns an error if the two nodes are disconnected and don't have + * a common ancestor. */ static nsresult GetCommonAncestor(nsIDOMNode *aNode, nsIDOMNode *aOther, nsIDOMNode** aCommonAncestor); - /* - * |aDifferentNodes| will contain up to 3 elements. - * The first, if present, is the common ancestor of |aNode| and |aOther|. - * The second, if present, is the ancestor node of |aNode| which is - * closest to the common ancestor, but not an ancestor of |aOther|. - * The third, if present, is the ancestor node of |aOther| which is - * closest to the common ancestor, but not an ancestor of |aNode|. - * - * @throws NS_ERROR_FAILURE if aNode and aOther are disconnected. + /** + * Returns the common ancestor, if any, for two nodes. Returns null if the + * nodes are disconnected. */ - static nsresult GetFirstDifferentAncestors(nsIDOMNode *aNode, - nsIDOMNode *aOther, - nsCOMArray& aDifferentNodes); + static nsINode* GetCommonAncestor(nsINode* aNode1, + nsINode* aNode2); /** - * Compares the document position of nodes which may have parents. - * DO NOT pass in nodes that cannot have a parentNode. In other words: - * DO NOT pass in Attr, Document, DocumentFragment, Entity, or Notation! - * The results will be completely wrong! + * Compares the document position of nodes. * - * @param aNode The node to which you are comparing. - * @param aOther The reference node to which aNode is compared. + * @param aNode1 The node whose position is being compared to the reference + * node + * @param aNode2 The reference node * - * @return The document position flags of the nodes. + * @return The document position flags of the nodes. aNode1 is compared to + * aNode2, i.e. if aNode1 is before aNode2 then + * DOCUMENT_POSITION_PRECEDING will be set. * * @see nsIDOMNode * @see nsIDOM3Node */ - static PRUint16 ComparePositionWithAncestors(nsIDOMNode *aNode, - nsIDOMNode *aOther); + static PRUint16 ComparePosition(nsINode* aNode1, + nsINode* aNode2); + + /** + * Returns true if aNode1 is before aNode2 in the same connected + * tree. + */ + static PRBool PositionIsBefore(nsINode* aNode1, + nsINode* aNode2) + { + return ComparePosition(aNode1, aNode2) & + (nsIDOM3Node::DOCUMENT_POSITION_PRECEDING | + nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED) == + nsIDOM3Node::DOCUMENT_POSITION_PRECEDING; + } /** * Brute-force search of the element subtree rooted at aContent for diff --git a/mozilla/content/base/public/nsINode.h b/mozilla/content/base/public/nsINode.h index 37860f561eb..55b5764547d 100644 --- a/mozilla/content/base/public/nsINode.h +++ b/mozilla/content/base/public/nsINode.h @@ -175,7 +175,7 @@ public: * If the return value is not -1, then calling GetChildAt() with that value * will return aPossibleChild. */ - virtual PRInt32 IndexOf(nsIContent* aPossibleChild) const = 0; + virtual PRInt32 IndexOf(nsINode* aPossibleChild) const = 0; /** * Do we need a GetCurrentDoc of some sort? I don't think we do... diff --git a/mozilla/content/base/src/nsAttrAndChildArray.cpp b/mozilla/content/base/src/nsAttrAndChildArray.cpp index 60b700c833f..9b9e2603ff1 100644 --- a/mozilla/content/base/src/nsAttrAndChildArray.cpp +++ b/mozilla/content/base/src/nsAttrAndChildArray.cpp @@ -220,7 +220,7 @@ nsAttrAndChildArray::RemoveChildAt(PRUint32 aPos) } PRInt32 -nsAttrAndChildArray::IndexOfChild(nsIContent* aPossibleChild) const +nsAttrAndChildArray::IndexOfChild(nsINode* aPossibleChild) const { if (!mImpl) { return -1; diff --git a/mozilla/content/base/src/nsAttrAndChildArray.h b/mozilla/content/base/src/nsAttrAndChildArray.h index 63ab30fe96b..826b375f5fb 100644 --- a/mozilla/content/base/src/nsAttrAndChildArray.h +++ b/mozilla/content/base/src/nsAttrAndChildArray.h @@ -48,6 +48,7 @@ #include "nsAttrName.h" #include "nsAttrValue.h" +class nsINode; class nsIContent; class nsMappedAttributes; class nsHTMLStyleSheet; @@ -93,7 +94,7 @@ public: } nsresult InsertChildAt(nsIContent* aChild, PRUint32 aPos); void RemoveChildAt(PRUint32 aPos); - PRInt32 IndexOfChild(nsIContent* aPossibleChild) const; + PRInt32 IndexOfChild(nsINode* aPossibleChild) const; PRUint32 AttrCount() const; const nsAttrValue* GetAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID = kNameSpaceID_None) const; diff --git a/mozilla/content/base/src/nsAttrName.h b/mozilla/content/base/src/nsAttrName.h index 4a411011563..8a0714cc606 100644 --- a/mozilla/content/base/src/nsAttrName.h +++ b/mozilla/content/base/src/nsAttrName.h @@ -148,6 +148,11 @@ public: return !IsAtom() && NodeInfo()->Equals(aLocalName, aNamespaceID); } + PRBool Equals(nsINodeInfo* aNodeInfo) const + { + return Equals(aNodeInfo->NameAtom(), aNodeInfo->NamespaceID()); + } + PRInt32 NamespaceID() const { return IsAtom() ? kNameSpaceID_None : NodeInfo()->NamespaceID(); diff --git a/mozilla/content/base/src/nsContentList.cpp b/mozilla/content/base/src/nsContentList.cpp index 155356b0d2c..92bc2b16dee 100644 --- a/mozilla/content/base/src/nsContentList.cpp +++ b/mozilla/content/base/src/nsContentList.cpp @@ -597,19 +597,9 @@ nsContentList::ContentAppended(nsIDocument *aDocument, nsIContent* aContainer, * We want to append instead of invalidating if the first thing * that got appended comes after ourLastContent. */ - nsCOMPtr ourLastDOM3Node(do_QueryInterface(ourLastContent)); - if (ourLastDOM3Node) { - nsCOMPtr newNode = - do_QueryInterface(aContainer->GetChildAt(aNewIndexInContainer)); - NS_ASSERTION(newNode, "Content being inserted is not a node.... why?"); - - PRUint16 comparisonFlags; - nsresult rv = - ourLastDOM3Node->CompareDocumentPosition(newNode, &comparisonFlags); - if (NS_SUCCEEDED(rv) && - (comparisonFlags & nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING)) { - appendToList = PR_TRUE; - } + if (nsContentUtils::PositionIsBefore(ourLastContent, + aContainer->GetChildAt(aNewIndexInContainer))) { + appendToList = PR_TRUE; } } diff --git a/mozilla/content/base/src/nsContentUtils.cpp b/mozilla/content/base/src/nsContentUtils.cpp index a30b4f5f550..c7532e1d6e7 100644 --- a/mozilla/content/base/src/nsContentUtils.cpp +++ b/mozilla/content/base/src/nsContentUtils.cpp @@ -129,6 +129,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID); #include "nsICharsetConverterManager.h" #include "nsXULAtoms.h" #include "nsIEventListenerManager.h" +#include "nsAttrName.h" // for ReportToConsole #include "nsIStringBundle.h" @@ -1179,213 +1180,164 @@ nsContentUtils::GetCommonAncestor(nsIDOMNode *aNode, { *aCommonAncestor = nsnull; - nsCOMArray nodeArray; - nsresult rv = GetFirstDifferentAncestors(aNode, aOther, nodeArray); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr node1 = do_QueryInterface(aNode); + nsCOMPtr node2 = do_QueryInterface(aOther); - nsIDOMNode *common = nodeArray[0]; + NS_ENSURE_TRUE(node1 && node2, NS_ERROR_UNEXPECTED); - NS_ASSERTION(common, "The common ancestor is null! Very bad!"); + nsINode* common = GetCommonAncestor(node1, node2); + NS_ENSURE_TRUE(common, NS_ERROR_NOT_AVAILABLE); - *aCommonAncestor = common; - NS_IF_ADDREF(*aCommonAncestor); - - return NS_OK; + return CallQueryInterface(common, aCommonAncestor); } // static -nsresult -nsContentUtils::GetFirstDifferentAncestors(nsIDOMNode *aNode, - nsIDOMNode *aOther, - nsCOMArray& aDifferentNodes) +nsINode* +nsContentUtils::GetCommonAncestor(nsINode* aNode1, + nsINode* aNode2) { - NS_ENSURE_ARG_POINTER(aNode); - NS_ENSURE_ARG_POINTER(aOther); - - if (aDifferentNodes.Count() != 0) { - NS_WARNING("The aDifferentNodes array passed in is not empty!"); - aDifferentNodes.Clear(); + if (aNode1 == aNode2) { + return aNode1; } - // Test if both are the same node. - if (aNode == aOther) { - aDifferentNodes.AppendObject(aNode); - return NS_OK; - } - - nsCOMArray nodeAncestors; - nsCOMArray otherAncestors; - - // Insert all the ancestors of |aNode| - nsCOMPtr node(aNode); - nsCOMPtr ancestor(node); + // Build the chain of parents + nsAutoVoidArray parents1, parents2; do { - nodeAncestors.AppendObject(node); - node->GetParentNode(getter_AddRefs(ancestor)); - if (ancestor == aOther) { - aDifferentNodes.AppendObject(aOther); - return NS_OK; + parents1.AppendElement(aNode1); + aNode1 = aNode1->GetNodeParent(); + } while (aNode1); + do { + parents2.AppendElement(aNode2); + aNode2 = aNode2->GetNodeParent(); + } while (aNode2); + + // Find where the parent chain differs + PRUint32 pos1 = parents1.Count(); + PRUint32 pos2 = parents2.Count(); + nsINode* parent = nsnull; + PRUint32 len; + for (len = PR_MIN(pos1, pos2); len > 0; --len) { + nsINode* child1 = NS_STATIC_CAST(nsINode*, parents1.FastElementAt(--pos1)); + nsINode* child2 = NS_STATIC_CAST(nsINode*, parents2.FastElementAt(--pos2)); + if (child1 != child2) { + break; } - node.swap(ancestor); - } while (node); - - // Insert all the ancestors of |aOther| - nsCOMPtr other(aOther); - ancestor = other; - do { - otherAncestors.AppendObject(other); - other->GetParentNode(getter_AddRefs(ancestor)); - if (ancestor == aNode) { - aDifferentNodes.AppendObject(aNode); - return NS_OK; - } - other.swap(ancestor); - } while (other); - - PRInt32 nodeIdx = nodeAncestors.Count() - 1; - PRInt32 otherIdx = otherAncestors.Count() - 1; - - if (nodeAncestors[nodeIdx] != otherAncestors[otherIdx]) { - // These two nodes are disconnected. We can't get a common ancestor. - return NS_ERROR_FAILURE; + parent = child1; } - // Go back through the ancestors, starting from the root, - // until the first different ancestor found. - do { - --nodeIdx; - --otherIdx; - } while (nodeAncestors[nodeIdx] == otherAncestors[otherIdx]); - - NS_ASSERTION(nodeIdx >= 0 && otherIdx >= 0, - "Something's wrong: our indices should not be negative here!"); - - aDifferentNodes.AppendObject(nodeAncestors[nodeIdx + 1]); - aDifferentNodes.AppendObject(nodeAncestors[nodeIdx]); - aDifferentNodes.AppendObject(otherAncestors[otherIdx]); - - return NS_OK; + return parent; } PRUint16 -nsContentUtils::ComparePositionWithAncestors(nsIDOMNode *aNode, - nsIDOMNode *aOther) +nsContentUtils::ComparePosition(nsINode* aNode1, + nsINode* aNode2) { -#ifdef DEBUG - PRUint16 nodeType = 0; - PRUint16 otherType = 0; - aNode->GetNodeType(&nodeType); - aOther->GetNodeType(&otherType); + NS_PRECONDITION(aNode1 && aNode2, "don't pass null"); - NS_PRECONDITION(nodeType != nsIDOMNode::ATTRIBUTE_NODE && - nodeType != nsIDOMNode::DOCUMENT_NODE && - nodeType != nsIDOMNode::DOCUMENT_FRAGMENT_NODE && - nodeType != nsIDOMNode::ENTITY_NODE && - nodeType != nsIDOMNode::NOTATION_NODE && - otherType != nsIDOMNode::ATTRIBUTE_NODE && - otherType != nsIDOMNode::DOCUMENT_NODE && - otherType != nsIDOMNode::DOCUMENT_FRAGMENT_NODE && - otherType != nsIDOMNode::ENTITY_NODE && - otherType != nsIDOMNode::NOTATION_NODE, - "Bad. Go read the documentation in the header!"); -#endif // DEBUG - - PRUint16 mask = 0; - - nsCOMArray nodeAncestors; - - nsresult rv = - nsContentUtils::GetFirstDifferentAncestors(aNode, aOther, nodeAncestors); - - if (NS_FAILED(rv)) { - // If there is no common container node, then the order is based upon - // order between the root container of each node that is in no container. - // In this case, the result is disconnected and implementation-dependent. - mask = (nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED | - nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); - - return mask; + if (aNode1 == aNode2) { + return 0; } - nsIDOMNode* commonAncestor = nodeAncestors[0]; + nsAutoVoidArray parents1, parents2; - if (commonAncestor == aNode) { - mask = (nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY | - nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING); - - return mask; + // Check if either node is an attribute + nsIAttribute* attr1 = nsnull; + if (aNode1->IsNodeOfType(nsINode::eATTRIBUTE)) { + attr1 = NS_STATIC_CAST(nsIAttribute*, aNode1); + nsIContent* elem = attr1->GetContent(); + // If there is an owner element add the attribute + // to the chain and walk up to the element + if (elem) { + aNode1 = elem; + parents1.AppendElement(attr1); + } } + if (aNode2->IsNodeOfType(nsINode::eATTRIBUTE)) { + nsIAttribute* attr2 = NS_STATIC_CAST(nsIAttribute*, aNode2); + nsIContent* elem = attr2->GetContent(); + if (elem == aNode1 && attr1) { + // Both nodes are attributes on the same element. + // Compare position between the attributes. - if (commonAncestor == aOther) { - mask |= (nsIDOM3Node::DOCUMENT_POSITION_CONTAINS | - nsIDOM3Node::DOCUMENT_POSITION_PRECEDING); - - return mask; - } - - // GetFirstDifferentAncestors should only succeed if one of the - // two nodes is the common ancestor, or if we have a common ancestor - // and the two first different ancestors. We checked the case above - // where one of the two nodes were the common ancestor, so we must - // have three items in our array now. - NS_ASSERTION(commonAncestor && nodeAncestors.Count() == 3, - "Something's wrong"); - - nsIDOMNode* nodeAncestor = nodeAncestors[1]; - nsIDOMNode* otherAncestor = nodeAncestors[2]; - - if (nodeAncestor && otherAncestor) { - // Find out which of the two nodes comes first in the document order. - // First get the children of the common ancestor. - nsCOMPtr children; - commonAncestor->GetChildNodes(getter_AddRefs(children)); - PRUint32 numKids; - children->GetLength(&numKids); - for (PRUint32 i = 0; i < numKids; ++i) { - // Then go through the children one at a time to see which we hit first. - nsCOMPtr childNode; - children->Item(i, getter_AddRefs(childNode)); - if (childNode == nodeAncestor) { - mask |= nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING; - break; + PRUint32 i; + const nsAttrName* attrName; + for (i = 0; (attrName = elem->GetAttrNameAt(i)); ++i) { + if (attrName->Equals(attr1->NodeInfo())) { + NS_ASSERTION(!attrName->Equals(attr2->NodeInfo()), + "Different attrs at same position"); + return nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | + nsIDOM3Node::DOCUMENT_POSITION_PRECEDING; + } + if (attrName->Equals(attr2->NodeInfo())) { + return nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | + nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING; + } } + NS_NOTREACHED("neither attribute in the element"); + return nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED; + } - if (childNode == otherAncestor) { - mask |= nsIDOM3Node::DOCUMENT_POSITION_PRECEDING; - break; - } + if (elem) { + aNode2 = elem; + parents2.AppendElement(attr2); } } - return mask; -} + // We now know that both nodes are either nsIContents or nsIDocuments. + // If either node started out as an attribute, that attribute will have + // the same relative position as its ownerElement, except if the + // ownerElement ends up being the container for the other node -PRUint16 -nsContentUtils::ReverseDocumentPosition(PRUint16 aDocumentPosition) -{ - // Disconnected and implementation-specific flags cannot be reversed. - // Keep them. - PRUint16 reversedPosition = - aDocumentPosition & (nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED | - nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); + // Build the chain of parents + do { + parents1.AppendElement(aNode1); + aNode1 = aNode1->GetNodeParent(); + } while (aNode1); + do { + parents2.AppendElement(aNode2); + aNode2 = aNode2->GetNodeParent(); + } while (aNode2); - // Following/preceding - if (aDocumentPosition & nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING) { - reversedPosition |= nsIDOM3Node::DOCUMENT_POSITION_PRECEDING; - } - else if (aDocumentPosition & nsIDOM3Node::DOCUMENT_POSITION_PRECEDING) { - reversedPosition |= nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING; + // Check if the nodes are disconnected. + PRUint32 pos1 = parents1.Count(); + PRUint32 pos2 = parents2.Count(); + nsINode* top1 = NS_STATIC_CAST(nsINode*, parents1.FastElementAt(--pos1)); + nsINode* top2 = NS_STATIC_CAST(nsINode*, parents2.FastElementAt(--pos2)); + if (top1 != top2) { + return top1 < top2 ? + (nsIDOM3Node::DOCUMENT_POSITION_PRECEDING | + nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED | + nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC) : + (nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING | + nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED | + nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); } - // Is contained/contains. - if (aDocumentPosition & nsIDOM3Node::DOCUMENT_POSITION_CONTAINS) { - reversedPosition |= nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY; - } - else if (aDocumentPosition & nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY) { - reversedPosition |= nsIDOM3Node::DOCUMENT_POSITION_CONTAINS; + // Find where the parent chain differs and check indices in the parent. + nsINode* parent = top1; + PRUint32 len; + for (len = PR_MIN(pos1, pos2); len > 0; --len) { + nsINode* child1 = NS_STATIC_CAST(nsINode*, parents1.FastElementAt(--pos1)); + nsINode* child2 = NS_STATIC_CAST(nsINode*, parents2.FastElementAt(--pos2)); + if (child1 != child2) { + // child1 or child2 can be an attribute here. This will work fine since + // IndexOf will return -1 for the attribute making the attribute be + // considered before any child. + return parent->IndexOf(child1) < parent->IndexOf(child2) ? + NS_STATIC_CAST(PRUint16, nsIDOM3Node::DOCUMENT_POSITION_PRECEDING) : + NS_STATIC_CAST(PRUint16, nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING); + } + parent = child1; } - return reversedPosition; + // We hit the end of one of the parent chains without finding a difference + // between the chains. That must mean that one node is an ancestor of the + // other. The one with the shortest chain must be the ancestor. + return pos1 < pos2 ? + (nsIDOM3Node::DOCUMENT_POSITION_PRECEDING | + nsIDOM3Node::DOCUMENT_POSITION_CONTAINS) : + (nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING | + nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY); } inline PRBool @@ -1753,14 +1705,7 @@ nsContentUtils::BelongsInForm(nsIDOMHTMLFormElement *aForm, // we check whether the content comes after the form. If it does, // return true. If it does not, then it couldn't have been inside // the form in the HTML. - nsCOMPtr contentAsDOM3(do_QueryInterface(aContent)); - PRUint16 comparisonFlags = 0; - nsresult rv = NS_OK; - if (contentAsDOM3) { - rv = contentAsDOM3->CompareDocumentPosition(aForm, &comparisonFlags); - } - if (NS_FAILED(rv) || - comparisonFlags & nsIDOM3Node::DOCUMENT_POSITION_PRECEDING) { + if (PositionIsBefore(form, aContent)) { // We could be in this form! // In the future, we may want to get document.forms, look at the // form after aForm, and if aContent is after that form after diff --git a/mozilla/content/base/src/nsDOMAttribute.cpp b/mozilla/content/base/src/nsDOMAttribute.cpp index 45f8d84cf9c..96647f9a3ae 100644 --- a/mozilla/content/base/src/nsDOMAttribute.cpp +++ b/mozilla/content/base/src/nsDOMAttribute.cpp @@ -504,135 +504,11 @@ nsDOMAttribute::CompareDocumentPosition(nsIDOMNode* aOther, PRUint16* aReturn) { NS_ENSURE_ARG_POINTER(aOther); - NS_PRECONDITION(aReturn, "Must have an out parameter"); - PRUint16 mask = 0; + nsCOMPtr other = do_QueryInterface(aOther); + NS_ENSURE_TRUE(other, NS_ERROR_DOM_NOT_SUPPORTED_ERR); - PRBool sameNode = PR_FALSE; - IsSameNode(aOther, &sameNode); - if (sameNode) { - // If the two nodes being compared are the same node, - // then no flags are set on the return. - *aReturn = 0; - return NS_OK; - } - - nsCOMPtr el; - GetOwnerElement(getter_AddRefs(el)); - if (!el) { - // If we have no owner element then there is no common container node, - // (of course there isn't if we have no container!) and the order is - // then based upon order between the root container of each node that - // is in no container. In this case, the result is disconnected - // and implementation-dependent. - mask |= (nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED | - nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); - - *aReturn = mask; - - return NS_OK; - } - - // Check to see if the other node is also an attribute - PRUint16 nodeType = 0; - aOther->GetNodeType(&nodeType); - if (nodeType == nsIDOMNode::ATTRIBUTE_NODE) { - nsCOMPtr otherAttr(do_QueryInterface(aOther)); - nsCOMPtr otherEl; - otherAttr->GetOwnerElement(getter_AddRefs(otherEl)); - if (!otherEl) { - // This is as if they were comparing to us, and our element was null. - // See "if (!el)" above. - mask |= (nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED | - nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); - } - else if (el == otherEl) { - // If neither of the two determining nodes is a child node and - // nodeType is the same for both determining nodes, then an - // implementation-dependent order between the determining nodes - // is returned. - mask |= nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC; - } - else - { - // For attrs owned by elements A and B, if A != B, the right value is - // comparing the tree position of A and B. - nsCOMPtr elNode3(do_QueryInterface(el)); - PRUint16 parentMask; - elNode3->CompareDocumentPosition(otherEl, &parentMask); - // Though elements can contain each other, attributes can't. - parentMask &= ~(nsIDOM3Node::DOCUMENT_POSITION_CONTAINS | - nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY); - mask |= parentMask; - } - - *aReturn = mask; - - return NS_OK; - } - - if (nodeType == nsIDOMNode::TEXT_NODE || - nodeType == nsIDOMNode::CDATA_SECTION_NODE || - nodeType == nsIDOMNode::ENTITY_REFERENCE_NODE) { - // XXXcaa we really should check the other node's parentNode - // against ourselves. But since we can't, we should walk our - // child node list to see if it's a descendant. But wait! - // We suck so bad that we cannot even do that, since we store - // only one text node per attribute, even if there are multiple. - // So technically, we could walk the child nodes list, but it - // would not make sense really to walk it for only one thing. - // How lame. So.... it seems the only option that we DO have - // is to get our one and only child and compare it against the - // other node. As such, that is exactly what we'll do. - // *Sigh* These silly hacks are quite disgusting, really.... - - nsCOMPtr ourOnlyChild; - GetFirstChild(getter_AddRefs(ourOnlyChild)); - - nsCOMPtr longLostRelative(do_QueryInterface(aOther)); - NS_ASSERTION(longLostRelative, "All our data nodes support DOM3Node"); - - longLostRelative->IsSameNode(ourOnlyChild, &sameNode); - if (sameNode) { - // Woohoo! We found our long lost relative and it's our child! - // Throw a party! Celebrate by returning that it is contained - // and following this node. - - mask |= (nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY | - nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING); - - *aReturn = mask; - return NS_OK; - } - - // Sigh. The other node isn't our child, but it still may be - // related to us. Fall through so we can keep looking. - } - - - // The other node isn't an attribute, or a child. - // Compare position relative to this attribute's owner element. - - nsCOMPtr parent(do_QueryInterface(el)); - parent->IsSameNode(aOther, &sameNode); - if (sameNode) { - // If the other node contains us, then it precedes us. - mask |= (nsIDOM3Node::DOCUMENT_POSITION_CONTAINS | - nsIDOM3Node::DOCUMENT_POSITION_PRECEDING); - - *aReturn = mask; - return NS_OK; - } - - PRUint16 parentMask = 0; - parent->CompareDocumentPosition(aOther, &parentMask); - - // We already established earlier that the node is not contained - // by this attribute. So if it is contained by our owner element, - // unset the flag. - mask |= parentMask & ~nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY; - - *aReturn = mask; + *aReturn = nsContentUtils::ComparePosition(other, this); return NS_OK; } @@ -789,7 +665,7 @@ nsDOMAttribute::GetChildAt(PRUint32 aIndex) const } PRInt32 -nsDOMAttribute::IndexOf(nsIContent* aPossibleChild) const +nsDOMAttribute::IndexOf(nsINode* aPossibleChild) const { // No need to call EnsureChildState here. If we don't already have a child // then aPossibleChild can't possibly be our child. diff --git a/mozilla/content/base/src/nsDOMAttribute.h b/mozilla/content/base/src/nsDOMAttribute.h index acbbd3b27f8..0a893d660ec 100644 --- a/mozilla/content/base/src/nsDOMAttribute.h +++ b/mozilla/content/base/src/nsDOMAttribute.h @@ -112,7 +112,7 @@ public: virtual PRBool IsNodeOfType(PRUint32 aFlags) const; virtual PRUint32 GetChildCount() const; virtual nsIContent *GetChildAt(PRUint32 aIndex) const; - virtual PRInt32 IndexOf(nsIContent* aPossibleChild) const; + virtual PRInt32 IndexOf(nsINode* aPossibleChild) const; virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify); virtual nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify); diff --git a/mozilla/content/base/src/nsDocument.cpp b/mozilla/content/base/src/nsDocument.cpp index 690226e5e33..e4dd9a19b42 100644 --- a/mozilla/content/base/src/nsDocument.cpp +++ b/mozilla/content/base/src/nsDocument.cpp @@ -1707,7 +1707,7 @@ nsDocument::GetChildAt(PRUint32 aIndex) const } PRInt32 -nsDocument::IndexOf(nsIContent* aPossibleChild) const +nsDocument::IndexOf(nsINode* aPossibleChild) const { return mChildren.IndexOfChild(aPossibleChild); } @@ -3614,69 +3614,16 @@ NS_IMETHODIMP nsDocument::CompareDocumentPosition(nsIDOMNode* aOther, PRUint16* aReturn) { NS_ENSURE_ARG_POINTER(aOther); - NS_PRECONDITION(aReturn, "Must have an out parameter"); - if (this == aOther) { - // If the two nodes being compared are the same node, - // then no flags are set on the return. - *aReturn = 0; + // We could optimize this by getting the other nodes current document + // and comparing with ourself. But then we'd have to deal with the + // current document being null and such so it's easier this way. + // It's hardly a case to optimize anyway. - return NS_OK; - } - - PRUint16 mask = 0; - - nsCOMPtr otherContent(do_QueryInterface(aOther)); - if (!otherContent) { - PRUint16 otherNodeType = 0; - aOther->GetNodeType(&otherNodeType); - NS_ASSERTION(otherNodeType == nsIDOMNode::DOCUMENT_NODE || - otherNodeType == nsIDOMNode::ATTRIBUTE_NODE, - "Hmm, this really _should_ support nsIContent..."); - if (otherNodeType == nsIDOMNode::ATTRIBUTE_NODE) { - nsCOMPtr otherAttr(do_QueryInterface(aOther)); - NS_ASSERTION(otherAttr, "Attributes really should be supporting " - "nsIDOMAttr you know..."); - - nsCOMPtr otherOwnerEl; - otherAttr->GetOwnerElement(getter_AddRefs(otherOwnerEl)); - if (otherOwnerEl) { - // Documents have no direct relationship to attribute - // nodes. So we'll look at our relationship in relation - // to its owner element, since that is also our relation - // to the attribute. - return CompareDocumentPosition(otherOwnerEl, aReturn); - } - } - - // If there is no common container node, then the order - // is based upon order between the root container of each - // node that is in no container. In this case, the result - // is disconnected and implementation-dependent. - mask |= (nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED | - nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); - - *aReturn = mask; - return NS_OK; - } - - if (this == otherContent->GetDocument()) { - // If the node being compared is contained by our node, - // then it follows it. - mask |= (nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY | - nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING); - } - else { - // If there is no common container node, then the order - // is based upon order between the root container of each - // node that is in no container. In this case, the result - // is disconnected and implementation-dependent. - mask |= (nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED | - nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); - } - - *aReturn = mask; + nsCOMPtr other = do_QueryInterface(aOther); + NS_ENSURE_TRUE(other, NS_ERROR_DOM_NOT_SUPPORTED_ERR); + *aReturn = nsContentUtils::ComparePosition(other, this); return NS_OK; } diff --git a/mozilla/content/base/src/nsDocument.h b/mozilla/content/base/src/nsDocument.h index 8ae051c7dea..ddcaa4a1d0a 100644 --- a/mozilla/content/base/src/nsDocument.h +++ b/mozilla/content/base/src/nsDocument.h @@ -531,7 +531,7 @@ public: // nsINode virtual PRBool IsNodeOfType(PRUint32 aFlags) const; virtual nsIContent *GetChildAt(PRUint32 aIndex) const; - virtual PRInt32 IndexOf(nsIContent* aPossibleChild) const; + virtual PRInt32 IndexOf(nsINode* aPossibleChild) const; virtual PRUint32 GetChildCount() const; virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify); diff --git a/mozilla/content/base/src/nsDocumentFragment.cpp b/mozilla/content/base/src/nsDocumentFragment.cpp index 1f2f4c1e0dd..b80f5fc69e6 100644 --- a/mozilla/content/base/src/nsDocumentFragment.cpp +++ b/mozilla/content/base/src/nsDocumentFragment.cpp @@ -267,53 +267,11 @@ nsDocumentFragment::CompareDocumentPosition(nsIDOMNode* aOther, PRUint16* aReturn) { NS_ENSURE_ARG_POINTER(aOther); - NS_PRECONDITION(aReturn, "Must have an out parameter"); - if (this == aOther) { - // If the two nodes being compared are the same node, - // then no flags are set on the return. - *aReturn = 0; - return NS_OK; - } + nsCOMPtr other = do_QueryInterface(aOther); + NS_ENSURE_TRUE(other, NS_ERROR_DOM_NOT_SUPPORTED_ERR); - PRUint16 mask = 0; - - nsCOMPtr other(aOther); - do { - nsCOMPtr tmp(other); - tmp->GetParentNode(getter_AddRefs(other)); - if (!other) { - // No parent. Check to see if we're at an attribute node. - PRUint16 nodeType = 0; - tmp->GetNodeType(&nodeType); - if (nodeType != nsIDOMNode::ATTRIBUTE_NODE) { - // If there is no common container node, then the order - // is based upon order between the root container of each - // node that is in no container. In this case, the result - // is disconnected and implementation-dependent. - mask |= (nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED | - nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC); - - break; - } - - // If we are, let's get the owner element and continue up the tree - nsCOMPtr attr(do_QueryInterface(tmp)); - nsCOMPtr owner; - attr->GetOwnerElement(getter_AddRefs(owner)); - other = do_QueryInterface(owner); - } - - if (NS_STATIC_CAST(nsIDOMNode*, this) == other) { - // If the node being compared is contained by our node, - // then it follows it. - mask |= (nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY | - nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING); - break; - } - } while (other); - - *aReturn = mask; + *aReturn = nsContentUtils::ComparePosition(other, this); return NS_OK; } diff --git a/mozilla/content/base/src/nsGenericDOMDataNode.cpp b/mozilla/content/base/src/nsGenericDOMDataNode.cpp index ffcc4f27ec0..2a30848823f 100644 --- a/mozilla/content/base/src/nsGenericDOMDataNode.cpp +++ b/mozilla/content/base/src/nsGenericDOMDataNode.cpp @@ -831,7 +831,7 @@ nsGenericDOMDataNode::GetChildAt(PRUint32 aIndex) const } PRInt32 -nsGenericDOMDataNode::IndexOf(nsIContent* aPossibleChild) const +nsGenericDOMDataNode::IndexOf(nsINode* aPossibleChild) const { return -1; } diff --git a/mozilla/content/base/src/nsGenericDOMDataNode.h b/mozilla/content/base/src/nsGenericDOMDataNode.h index 5a615c838c1..32fcf146e48 100644 --- a/mozilla/content/base/src/nsGenericDOMDataNode.h +++ b/mozilla/content/base/src/nsGenericDOMDataNode.h @@ -187,7 +187,7 @@ public: // nsINode methods virtual PRUint32 GetChildCount() const; virtual nsIContent *GetChildAt(PRUint32 aIndex) const; - virtual PRInt32 IndexOf(nsIContent* aPossibleChild) const; + virtual PRInt32 IndexOf(nsINode* aPossibleChild) const; virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify); virtual nsresult AppendChildTo(nsIContent* aKid, PRBool aNotify); diff --git a/mozilla/content/base/src/nsGenericElement.cpp b/mozilla/content/base/src/nsGenericElement.cpp index a3120ade71d..28b021a2790 100644 --- a/mozilla/content/base/src/nsGenericElement.cpp +++ b/mozilla/content/base/src/nsGenericElement.cpp @@ -479,59 +479,11 @@ nsNode3Tearoff::CompareDocumentPosition(nsIDOMNode* aOther, PRUint16* aReturn) { NS_ENSURE_ARG_POINTER(aOther); - NS_PRECONDITION(aReturn, "Must have an out parameter"); - nsCOMPtr node(do_QueryInterface(mContent)); - if (node == aOther) { - // If the two nodes being compared are the same node, - // then no flags are set on the return. - *aReturn = 0; - return NS_OK; - } + nsCOMPtr other = do_QueryInterface(aOther); + NS_ENSURE_TRUE(other, NS_ERROR_DOM_NOT_SUPPORTED_ERR); - PRUint16 mask = 0; - - // If the other node is an attribute, document, or document fragment, - // we can find the position easier by comparing this node relative to - // the other node, and then reversing positions. - PRUint16 otherType = 0; - aOther->GetNodeType(&otherType); - if (otherType == nsIDOMNode::ATTRIBUTE_NODE || - otherType == nsIDOMNode::DOCUMENT_NODE || - otherType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) { - PRUint16 otherMask = 0; - nsCOMPtr other(do_QueryInterface(aOther)); - other->CompareDocumentPosition(node, &otherMask); - - *aReturn = nsContentUtils::ReverseDocumentPosition(otherMask); - return NS_OK; - } - -#ifdef DEBUG - { - PRUint16 nodeType = 0; - node->GetNodeType(&nodeType); - - if (nodeType == nsIDOMNode::ENTITY_NODE || - nodeType == nsIDOMNode::NOTATION_NODE) { - NS_NOTYETIMPLEMENTED("Entities and Notations are not fully supported yet"); - } - else { - NS_ASSERTION((nodeType == nsIDOMNode::ELEMENT_NODE || - nodeType == nsIDOMNode::TEXT_NODE || - nodeType == nsIDOMNode::CDATA_SECTION_NODE || - nodeType == nsIDOMNode::ENTITY_REFERENCE_NODE || - nodeType == nsIDOMNode::PROCESSING_INSTRUCTION_NODE || - nodeType == nsIDOMNode::COMMENT_NODE || - nodeType == nsIDOMNode::DOCUMENT_TYPE_NODE), - "Invalid node type!"); - } - } -#endif - - mask |= nsContentUtils::ComparePositionWithAncestors(node, aOther); - - *aReturn = mask; + *aReturn = nsContentUtils::ComparePosition(other, mContent); return NS_OK; } @@ -539,14 +491,9 @@ NS_IMETHODIMP nsNode3Tearoff::IsSameNode(nsIDOMNode* aOther, PRBool* aReturn) { - PRBool sameNode = PR_FALSE; - nsCOMPtr other(do_QueryInterface(aOther)); - if (mContent == other) { - sameNode = PR_TRUE; - } + *aReturn = mContent == other; - *aReturn = sameNode; return NS_OK; } @@ -3807,7 +3754,7 @@ nsGenericElement::GetChildAt(PRUint32 aIndex) const } PRInt32 -nsGenericElement::IndexOf(nsIContent* aPossibleChild) const +nsGenericElement::IndexOf(nsINode* aPossibleChild) const { return mAttrsAndChildren.IndexOfChild(aPossibleChild); } diff --git a/mozilla/content/base/src/nsGenericElement.h b/mozilla/content/base/src/nsGenericElement.h index 8d33478ee5a..f5ae9b02b0d 100644 --- a/mozilla/content/base/src/nsGenericElement.h +++ b/mozilla/content/base/src/nsGenericElement.h @@ -307,7 +307,7 @@ public: // nsINode interface methods virtual PRUint32 GetChildCount() const; virtual nsIContent *GetChildAt(PRUint32 aIndex) const; - virtual PRInt32 IndexOf(nsIContent* aPossibleChild) const; + virtual PRInt32 IndexOf(nsINode* aPossibleChild) const; virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify); virtual 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 2a69336db20..7baa2d6fb05 100644 --- a/mozilla/content/xul/content/src/nsXULElement.cpp +++ b/mozilla/content/xul/content/src/nsXULElement.cpp @@ -1014,7 +1014,7 @@ nsXULElement::GetChildAt(PRUint32 aIndex) const } PRInt32 -nsXULElement::IndexOf(nsIContent* aPossibleChild) const +nsXULElement::IndexOf(nsINode* aPossibleChild) const { if (NS_FAILED(EnsureContentsGenerated())) { return -1; diff --git a/mozilla/content/xul/content/src/nsXULElement.h b/mozilla/content/xul/content/src/nsXULElement.h index f96df2785fd..411e1202e5a 100644 --- a/mozilla/content/xul/content/src/nsXULElement.h +++ b/mozilla/content/xul/content/src/nsXULElement.h @@ -464,7 +464,7 @@ public: // nsINode virtual PRUint32 GetChildCount() const; virtual nsIContent *GetChildAt(PRUint32 aIndex) const; - virtual PRInt32 IndexOf(nsIContent* aPossibleChild) const; + virtual PRInt32 IndexOf(nsINode* aPossibleChild) const; virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor); virtual nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify);