Bug 307394 part 1. Create a non-COM way to get at XBL child nodes, and put an IndexOf() method on nsINodeList. r+sr=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 29 Jan 2009 14:46:18 -0500
changeset 24403 c9a94760bc2a509c279c9cfb414549a51c179de6
parent 24402 0c39d79738c4303c6ee51ce8915aa82b4400cee2
child 24404 0d5743c16ba8ff65afa71c1e4c7b0ce54fee11ef
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs307394
milestone1.9.2a1pre
Bug 307394 part 1. Create a non-COM way to get at XBL child nodes, and put an IndexOf() method on nsINodeList. r+sr=peterv
content/base/public/nsINode.h
content/base/public/nsINodeList.h
content/base/src/nsContentList.cpp
content/base/src/nsContentList.h
content/base/src/nsGenericElement.cpp
content/base/src/nsGenericElement.h
content/xbl/src/nsBindingManager.cpp
content/xbl/src/nsBindingManager.h
content/xbl/src/nsXBLBinding.cpp
content/xbl/src/nsXBLBinding.h
content/xbl/src/nsXBLInsertionPoint.h
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -46,16 +46,17 @@
 #include "nsCOMPtr.h"
 #include "nsWrapperCache.h"
 
 class nsIContent;
 class nsIDocument;
 class nsIDOMEvent;
 class nsIDOMNode;
 class nsIDOMNodeList;
+class nsINodeList;
 class nsIPresShell;
 class nsPresContext;
 class nsEventChainVisitor;
 class nsEventChainPreVisitor;
 class nsEventChainPostVisitor;
 class nsIEventListenerManager;
 class nsIPrincipal;
 class nsVoidArray;
@@ -148,18 +149,18 @@ inline nsINode* NODE_FROM(C& aContent, D
   if (aContent)
     return static_cast<nsINode*>(aContent);
   return static_cast<nsINode*>(aDocument);
 }
 
 
 // IID for the nsINode interface
 #define NS_INODE_IID \
-{ 0x0dc8fad3, 0xcb3f, 0x4f14, \
- { 0x8e, 0x7e, 0x4f, 0x62, 0xab, 0x74, 0xb8, 0x1e } }
+{ 0x355cc896, 0x2ed0, 0x4237, \
+ { 0x85, 0xf7, 0x4d, 0xb0, 0xcf, 0x4d, 0xc4, 0x90 } }
  
 /**
  * An internal interface that abstracts some DOMNode-related parts that both
  * nsIContent and nsIDocument share.  An instance of this interface has a list
  * of nsIContent children and provides access to them.
  */
 class nsINode : public nsPIDOMEventTarget,
                 public nsWrapperCache
@@ -685,17 +686,17 @@ public:
    * Get the nearest selection root, ie. the node that will be selected if the
    * user does "Select All" while the focus is in this node. Note that if this
    * node is not in an editor, the result comes from the nsFrameSelection that
    * is related to aPresShell, so the result might not be the ancestor of this
    * node.
    */
   nsIContent* GetSelectionRootContent(nsIPresShell* aPresShell);
 
-  virtual nsIDOMNodeList* GetChildNodesList();
+  virtual nsINodeList* GetChildNodesList();
   nsIContent* GetSibling(PRInt32 aOffset)
   {
     nsINode *parent = GetNodeParent();
     if (!parent) {
       return nsnull;
     }
 
     return parent->GetChildAt(parent->IndexOf(this) + aOffset);
--- a/content/base/public/nsINodeList.h
+++ b/content/base/public/nsINodeList.h
@@ -35,35 +35,42 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsINodeList_h___
 #define nsINodeList_h___
 
 #include "nsIDOMNodeList.h"
 
-class nsINode;
+class nsIContent;
 
 // IID for the nsINodeList interface
 #define NS_INODELIST_IID \
-{ 0x943420c4, 0x8774, 0x43ea, \
- { 0xb3, 0x53, 0x62, 0xa1, 0x26, 0x1c, 0x9b, 0x55 } }
+{ 0x57ac9ea2, 0xe95f, 0x4856, \
+ { 0xbb, 0xac, 0x82, 0x2d, 0x65, 0xb1, 0x92, 0x57 } }
 
 /**
- * An internal interface that allows QI-less getting of nodes from node lists
+ * An internal interface that allows QI-less getting of nodes from
+ * node lists and reasonably fast indexOf.
  */
 class nsINodeList : public nsIDOMNodeList
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_INODELIST_IID)
 
   /**
    * Get the node at the index.  Returns null if the index is out of bounds
    */
-  virtual nsINode* GetNodeAt(PRUint32 aIndex) = 0;
+  virtual nsIContent* GetNodeAt(PRUint32 aIndex) = 0;
+
+  /**
+   * Get the index of the given node in the list.  Will return -1 if the node
+   * is not in the list.
+   */
+  virtual PRInt32 IndexOf(nsIContent* aContent) = 0;
 };
 
 #define NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class)                  \
   NS_OFFSET_AND_INTERFACE_TABLE_BEGIN_AMBIGUOUS(_class, nsINodeList)
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsINodeList, NS_INODELIST_IID)
 
 #endif /* nsINodeList_h___ */
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -119,17 +119,17 @@ nsBaseContentList::Item(PRUint32 aIndex,
     *aReturn = nsnull;
 
     return NS_OK;
   }
 
   return CallQueryInterface(tmp, aReturn);
 }
 
-nsINode*
+nsIContent*
 nsBaseContentList::GetNodeAt(PRUint32 aIndex)
 {
   return mElements.SafeObjectAt(aIndex);
 }
 
 void
 nsBaseContentList::AppendElement(nsIContent *aContent)
 {
@@ -143,16 +143,22 @@ nsBaseContentList::RemoveElement(nsICont
 }
 
 PRInt32
 nsBaseContentList::IndexOf(nsIContent *aContent, PRBool aDoFlush)
 {
   return mElements.IndexOf(aContent);
 }
 
+PRInt32
+nsBaseContentList::IndexOf(nsIContent* aContent)
+{
+  return IndexOf(aContent, PR_TRUE);
+}
+
 void
 nsBaseContentList::Reset()
 {
   mElements.Clear();
 }
 
 // static
 void
@@ -439,16 +445,22 @@ nsContentList::NamedItem(const nsAString
 PRInt32
 nsContentList::IndexOf(nsIContent *aContent, PRBool aDoFlush)
 {
   BringSelfUpToDate(aDoFlush);
     
   return mElements.IndexOf(aContent);
 }
 
+PRInt32
+nsContentList::IndexOf(nsIContent* aContent)
+{
+  return IndexOf(aContent, PR_TRUE);
+}
+
 void
 nsContentList::NodeWillBeDestroyed(const nsINode* aNode)
 {
   // We shouldn't do anything useful from now on
 
   RemoveFromHashtable();
   mRootNode = nsnull;
 
@@ -503,17 +515,17 @@ nsContentList::NamedItem(const nsAString
     return CallQueryInterface(content, aReturn);
   }
 
   *aReturn = nsnull;
 
   return NS_OK;
 }
 
-nsINode*
+nsIContent*
 nsContentList::GetNodeAt(PRUint32 aIndex)
 {
   return Item(aIndex, PR_TRUE);
 }
 
 nsISupports*
 nsContentList::GetNodeAt(PRUint32 aIndex, nsresult* aResult)
 {
--- a/content/base/src/nsContentList.h
+++ b/content/base/src/nsContentList.h
@@ -81,17 +81,18 @@ public:
   virtual ~nsBaseContentList();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   // nsIDOMNodeList
   NS_DECL_NSIDOMNODELIST
 
   // nsINodeList
-  virtual nsINode* GetNodeAt(PRUint32 aIndex);
+  virtual nsIContent* GetNodeAt(PRUint32 aIndex);
+  virtual PRInt32 IndexOf(nsIContent* aContent);
   
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsBaseContentList, nsINodeList)
 
   void AppendElement(nsIContent *aContent);
   void RemoveElement(nsIContent *aContent);
   virtual PRInt32 IndexOf(nsIContent *aContent, PRBool aDoFlush);
   void Reset();
 
@@ -237,17 +238,18 @@ public:
                 PRBool aFuncMayDependOnAttr = PR_TRUE);
   virtual ~nsContentList();
 
   // nsIDOMHTMLCollection
   NS_DECL_NSIDOMHTMLCOLLECTION
 
   // nsBaseContentList overrides
   virtual PRInt32 IndexOf(nsIContent *aContent, PRBool aDoFlush);
-  virtual nsINode* GetNodeAt(PRUint32 aIndex);
+  virtual nsIContent* GetNodeAt(PRUint32 aIndex);
+  virtual PRInt32 IndexOf(nsIContent* aContent);
 
   // nsIHTMLCollection
   virtual nsISupports* GetNodeAt(PRUint32 aIndex, nsresult* aResult);
   virtual nsISupports* GetNamedItem(const nsAString& aName, nsresult* aResult);
 
   // nsContentList public methods
   NS_HIDDEN_(nsISupports*) GetParentObject();
   NS_HIDDEN_(PRUint32) Length(PRBool aDoFlush);
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -419,17 +419,17 @@ nsINode::GetSelectionRootContent(nsIPres
   content = fs->GetAncestorLimiter();
   if (content)
     return content;
   nsIDocument* doc = aPresShell->GetDocument();
   NS_ENSURE_TRUE(doc, nsnull);
   return doc->GetRootContent();
 }
 
-nsIDOMNodeList*
+nsINodeList*
 nsINode::GetChildNodesList()
 {
   nsSlots *slots = GetSlots();
   if (!slots) {
     return nsnull;
   }
 
   if (!slots->mChildNodes) {
@@ -584,26 +584,36 @@ nsChildContentList::Item(PRUint32 aIndex
     *aReturn = nsnull;
 
     return NS_OK;
   }
 
   return CallQueryInterface(node, aReturn);
 }
 
-nsINode*
+nsIContent*
 nsChildContentList::GetNodeAt(PRUint32 aIndex)
 {
   if (mNode) {
     return mNode->GetChildAt(aIndex);
   }
 
   return nsnull;
 }
 
+PRInt32
+nsChildContentList::IndexOf(nsIContent* aContent)
+{
+  if (mNode) {
+    return mNode->IndexOf(aContent);
+  }
+
+  return -1;
+}
+
 //----------------------------------------------------------------------
 
 NS_IMPL_CYCLE_COLLECTION_1(nsNode3Tearoff, mContent)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsNode3Tearoff)
   NS_INTERFACE_MAP_ENTRY(nsIDOM3Node)
 NS_INTERFACE_MAP_END_AGGREGATED(mContent)
 
--- a/content/base/src/nsGenericElement.h
+++ b/content/base/src/nsGenericElement.h
@@ -103,17 +103,18 @@ public:
   }
 
   NS_DECL_ISUPPORTS
 
   // nsIDOMNodeList interface
   NS_DECL_NSIDOMNODELIST
 
   // nsINodeList interface
-  virtual nsINode* GetNodeAt(PRUint32 aIndex);  
+  virtual nsIContent* GetNodeAt(PRUint32 aIndex);
+  virtual PRInt32 IndexOf(nsIContent* aContent);
   
   void DropReference()
   {
     mNode = nsnull;
   }
 
   nsISupports* GetParentObject()
   {
--- a/content/xbl/src/nsBindingManager.cpp
+++ b/content/xbl/src/nsBindingManager.cpp
@@ -98,17 +98,18 @@ public:
   virtual ~nsAnonymousContentList();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsAnonymousContentList, nsINodeList)
   // nsIDOMNodeList interface
   NS_DECL_NSIDOMNODELIST
 
   // nsINodeList interface
-  virtual nsINode* GetNodeAt(PRUint32 aIndex);
+  virtual nsIContent* GetNodeAt(PRUint32 aIndex);
+  virtual PRInt32 IndexOf(nsIContent* aContent);
 
   PRInt32 GetInsertionPointCount() { return mElements->Length(); }
 
   nsXBLInsertionPoint* GetInsertionPointAt(PRInt32 i) { return static_cast<nsXBLInsertionPoint*>(mElements->ElementAt(i)); }
   void RemoveInsertionPointAt(PRInt32 i) { mElements->RemoveElementAt(i); }
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ANONYMOUS_CONTENT_LIST_IID)
 private:
   nsInsertionPointList* mElements;
@@ -180,17 +181,17 @@ nsAnonymousContentList::Item(PRUint32 aI
 {
   nsINode* item = GetNodeAt(aIndex);
   if (!item)
     return NS_ERROR_FAILURE;
 
   return CallQueryInterface(item, aReturn);    
 }
 
-nsINode*
+nsIContent*
 nsAnonymousContentList::GetNodeAt(PRUint32 aIndex)
 {
   PRInt32 cnt = mElements->Length();
   PRUint32 pointCount = 0;
 
   for (PRInt32 i = 0; i < cnt; i++) {
     aIndex -= pointCount;
     
@@ -200,16 +201,37 @@ nsAnonymousContentList::GetNodeAt(PRUint
     if (aIndex < pointCount) {
       return point->ChildAt(aIndex);
     }
   }
 
   return nsnull;
 }
 
+PRInt32
+nsAnonymousContentList::IndexOf(nsIContent* aContent)
+{
+  PRInt32 cnt = mElements->Length();
+  PRInt32 lengthSoFar = 0;
+
+  for (PRInt32 i = 0; i < cnt; ++i) {
+    nsXBLInsertionPoint* point =
+      static_cast<nsXBLInsertionPoint*>(mElements->ElementAt(i));
+    PRInt32 idx = point->IndexOf(aContent);
+    if (idx != -1) {
+      return idx + lengthSoFar;
+    }
+
+    lengthSoFar += point->ChildCount();
+  }
+
+  // Didn't find it anywhere
+  return -1;
+}
+
 //
 // Generic pldhash table stuff for mapping one nsISupports to another
 //
 // These values are never null - a null value implies that this
 // whole key should be removed (See SetOrRemoveObject)
 class ObjectEntry : public PLDHashEntryHdr
 {
 public:
@@ -658,21 +680,20 @@ nsBindingManager::ResolveTag(nsIContent*
 
   *aNameSpaceID = aContent->GetNameSpaceID();
   return aContent->Tag();
 }
 
 nsresult
 nsBindingManager::GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult)
 { 
-  // Locate the primary binding and get its node list of anonymous children.
   *aResult = nsnull;
   
   if (mContentListTable.ops) {
-    *aResult = static_cast<nsIDOMNodeList*>
+    *aResult = static_cast<nsAnonymousContentList*>
                           (LookupObject(mContentListTable, aContent));
     NS_IF_ADDREF(*aResult);
   }
   
   if (!*aResult) {
     nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
     node->GetChildNodes(aResult);
   }
@@ -683,17 +704,17 @@ nsBindingManager::GetContentListFor(nsIC
 nsresult
 nsBindingManager::SetContentListFor(nsIContent* aContent,
                                     nsInsertionPointList* aList)
 {
   if (mDestroyed) {
     return NS_OK;
   }
 
-  nsIDOMNodeList* contentList = nsnull;
+  nsAnonymousContentList* contentList = nsnull;
   if (aList) {
     contentList = new nsAnonymousContentList(aList);
     if (!contentList) {
       delete aList;
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
@@ -701,110 +722,108 @@ nsBindingManager::SetContentListFor(nsIC
 }
 
 PRBool
 nsBindingManager::HasContentListFor(nsIContent* aContent)
 {
   return mContentListTable.ops && LookupObject(mContentListTable, aContent);
 }
 
-nsresult
+nsINodeList*
 nsBindingManager::GetAnonymousNodesInternal(nsIContent* aContent,
-                                            nsIDOMNodeList** aResult,
                                             PRBool* aIsAnonymousContentList)
 { 
-  // Locate the primary binding and get its node list of anonymous children.
-  *aResult = nsnull;
+  nsINodeList* result = nsnull;
   if (mAnonymousNodesTable.ops) {
-    *aResult = static_cast<nsIDOMNodeList*>
-                          (LookupObject(mAnonymousNodesTable, aContent));
-    NS_IF_ADDREF(*aResult);
+    result = static_cast<nsAnonymousContentList*>
+                        (LookupObject(mAnonymousNodesTable, aContent));
   }
 
-  if (!*aResult) {
+  if (!result) {
     *aIsAnonymousContentList = PR_FALSE;
     nsXBLBinding *binding = GetBinding(aContent);
     if (binding) {
-      *aResult = binding->GetAnonymousNodes().get();
-      return NS_OK;
+      result = binding->GetAnonymousNodes();
     }
   } else
     *aIsAnonymousContentList = PR_TRUE;
 
-  return NS_OK;
+  return result;
 }
 
 nsresult
 nsBindingManager::GetAnonymousNodesFor(nsIContent* aContent,
                                        nsIDOMNodeList** aResult)
 {
   PRBool dummy;
-  return GetAnonymousNodesInternal(aContent, aResult, &dummy);
+  NS_IF_ADDREF(*aResult = GetAnonymousNodesInternal(aContent, &dummy));
+  return NS_OK;
 }
 
 nsresult
 nsBindingManager::SetAnonymousNodesFor(nsIContent* aContent,
                                        nsInsertionPointList* aList)
 {
   if (mDestroyed) {
     return NS_OK;
   }
 
-  nsIDOMNodeList* contentList = nsnull;
+  nsAnonymousContentList* contentList = nsnull;
   if (aList) {
     contentList = new nsAnonymousContentList(aList);
     if (!contentList) {
       delete aList;
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   return SetOrRemoveObject(mAnonymousNodesTable, aContent, contentList);
 }
 
-nsresult
+nsINodeList*
 nsBindingManager::GetXBLChildNodesInternal(nsIContent* aContent,
-                                           nsIDOMNodeList** aResult,
                                            PRBool* aIsAnonymousContentList)
 {
-  *aResult = nsnull;
-
   PRUint32 length;
 
   // Retrieve the anonymous content that we should build.
-  nsCOMPtr<nsIDOMNodeList> result;
-  GetAnonymousNodesInternal(aContent, getter_AddRefs(result),
-                            aIsAnonymousContentList);
+  nsINodeList* result = GetAnonymousNodesInternal(aContent,
+                                                  aIsAnonymousContentList);
   if (result) {
     result->GetLength(&length);
     if (length == 0)
       result = nsnull;
   }
     
   // We may have an altered list of children from XBL insertion points.
   // If we don't have any anonymous kids, we next check to see if we have 
   // insertion points.
   if (!result) {
     if (mContentListTable.ops) {
-      result = static_cast<nsIDOMNodeList*>
+      result = static_cast<nsAnonymousContentList*>
                           (LookupObject(mContentListTable, aContent));
       *aIsAnonymousContentList = PR_TRUE;
     }
   }
 
-  result.swap(*aResult);
-
-  return NS_OK;
+  return result;
 }
 
 nsresult
 nsBindingManager::GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult)
 {
+  NS_IF_ADDREF(*aResult = GetXBLChildNodesFor(aContent));
+  return NS_OK;
+}
+
+nsINodeList*
+nsBindingManager::GetXBLChildNodesFor(nsIContent* aContent)
+{
   PRBool dummy;
-  return GetXBLChildNodesInternal(aContent, aResult, &dummy);
+  return GetXBLChildNodesInternal(aContent, &dummy);
 }
 
 nsIContent*
 nsBindingManager::GetInsertionPoint(nsIContent* aParent, nsIContent* aChild,
                                     PRUint32* aIndex)
 {
   nsXBLBinding *binding = GetBinding(aParent);
   return binding ? binding->GetInsertionPoint(aChild, aIndex) : nsnull;
@@ -1421,20 +1440,19 @@ nsBindingManager::ContentAppended(nsIDoc
       PRInt32 childCount = aContainer->GetChildCount();
       NS_ASSERTION(aNewIndexInContainer >= 0, "Bogus index");
       for (PRInt32 idx = aNewIndexInContainer; idx < childCount; ++idx) {
         HandleChildInsertion(aContainer, aContainer->GetChildAt(idx),
                              idx, PR_TRUE);
       }
     }
     else if (ins) {
-      nsCOMPtr<nsIDOMNodeList> nodeList;
       PRBool isAnonymousContentList;
-      GetXBLChildNodesInternal(ins, getter_AddRefs(nodeList),
-                               &isAnonymousContentList);
+      nsCOMPtr<nsIDOMNodeList> nodeList =
+        GetXBLChildNodesInternal(ins, &isAnonymousContentList);
 
       if (nodeList && isAnonymousContentList) {
         // Find the one non-pseudo-insertion point and just add ourselves.
         nsAnonymousContentList* contentList =
           static_cast<nsAnonymousContentList*>(nodeList.get());
 
         PRInt32 count = contentList->GetInsertionPointCount();
         for (PRInt32 i = 0; i < count; i++) {
@@ -1498,20 +1516,19 @@ nsBindingManager::ContentRemoved(nsIDocu
                                  PRInt32 aIndexInContainer)
 {
   if (aContainer && aIndexInContainer != -1 &&
       (mContentListTable.ops || mAnonymousNodesTable.ops)) {
     // It's not anonymous
     nsCOMPtr<nsIContent> point = GetNestedInsertionPoint(aContainer, aChild);
 
     if (point) {
-      nsCOMPtr<nsIDOMNodeList> nodeList;
       PRBool isAnonymousContentList;
-      GetXBLChildNodesInternal(point, getter_AddRefs(nodeList),
-                               &isAnonymousContentList);
+      nsCOMPtr<nsIDOMNodeList> nodeList =
+        GetXBLChildNodesInternal(point, &isAnonymousContentList);
       
       if (nodeList && isAnonymousContentList) {
         // Find a non-pseudo-insertion point and remove ourselves.
         RemoveChildFromInsertionPoint(static_cast<nsAnonymousContentList*>
                                         (static_cast<nsIDOMNodeList*>
                                                     (nodeList)),
                                       aChild,
                                       PR_FALSE);
@@ -1519,19 +1536,18 @@ nsBindingManager::ContentRemoved(nsIDocu
       }
     }
 
     // Whether the child has a nested insertion point or not, aContainer might
     // have insertion points under it.  If that's the case, we need to remove
     // aChild from the pseudo insertion point it's in.
     if (mContentListTable.ops) {
       nsAnonymousContentList* insertionPointList =
-        static_cast<nsAnonymousContentList*>(
-          static_cast<nsIDOMNodeList*>(LookupObject(mContentListTable,
-                                                    aContainer)));
+        static_cast<nsAnonymousContentList*>(LookupObject(mContentListTable,
+                                                          aContainer));
       if (insertionPointList) {
         RemoveChildFromInsertionPoint(insertionPointList, aChild, PR_TRUE);
       }
     }
   }
 }
 
 void
@@ -1617,20 +1633,19 @@ nsBindingManager::HandleChildInsertion(n
   NS_PRECONDITION(aChild, "Must have child");
   NS_PRECONDITION(!aContainer ||
                   PRUint32(aContainer->IndexOf(aChild)) == aIndexInContainer,
                   "Child not at the right index?");
 
   nsIContent* ins = GetNestedInsertionPoint(aContainer, aChild);
 
   if (ins) {
-    nsCOMPtr<nsIDOMNodeList> nodeList;
     PRBool isAnonymousContentList;
-    GetXBLChildNodesInternal(ins, getter_AddRefs(nodeList),
-                             &isAnonymousContentList);
+    nsCOMPtr<nsIDOMNodeList> nodeList =
+      GetXBLChildNodesInternal(ins, &isAnonymousContentList);
 
     if (nodeList && isAnonymousContentList) {
       // Find a non-pseudo-insertion point and just jam ourselves in.  This is
       // not 100% correct, since there might be multiple insertion points under
       // this insertion parent, and we should really be using the one that
       // matches our content...  Hack city, baby.
       nsAnonymousContentList* contentList =
         static_cast<nsAnonymousContentList*>(nodeList.get());
--- a/content/xbl/src/nsBindingManager.h
+++ b/content/xbl/src/nsBindingManager.h
@@ -117,17 +117,20 @@ public:
 
   /**
    * Determine whether or not the explicit child list has been altered
    * by XBL insertion points.
    */
   PRBool HasContentListFor(nsIContent* aContent);
 
   /**
-   * For a given element, retrieve the anonymous child content.
+   * Return the nodelist of "anonymous" kids for this node.  This might
+   * actually include some of the nodes actual DOM kids, if there are
+   * <children> tags directly as kids of <content>.  This will only end up
+   * returning a non-null list for nodes which have a binding attached.
    */
   nsresult GetAnonymousNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
 
   /**
    * Set the anonymous child content for the specified element.
    * The binding manager assumes ownership of aList.
    */
   nsresult SetAnonymousNodesFor(nsIContent* aContent,
@@ -137,16 +140,21 @@ public:
    * Retrieves the anonymous list of children if the element has one;
    * otherwise, retrieves the list of explicit children. N.B. that if
    * the explicit child list has not been altered by XBL insertion
    * points, then aResult will be null.
    */
   nsresult GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult);
 
   /**
+   * Non-COMy version of GetXBLChildNodesFor
+   */
+  nsINodeList* GetXBLChildNodesFor(nsIContent* aContent);
+
+  /**
    * Given a parent element and a child content, determine where the
    * child content should be inserted in the parent element's
    * anonymous content tree. Specifically, aChild should be inserted
    * beneath aResult at the index specified by aIndex.
    */
   nsIContent* GetInsertionPoint(nsIContent* aParent,
                                 nsIContent* aChild, PRUint32* aIndex);
 
@@ -207,22 +215,20 @@ public:
 
   // Called when the document is going away
   void DropDocumentReference();
 
 protected:
   nsIXPConnectWrappedJS* GetWrappedJS(nsIContent* aContent);
   nsresult SetWrappedJS(nsIContent* aContent, nsIXPConnectWrappedJS* aResult);
 
-  nsresult GetXBLChildNodesInternal(nsIContent* aContent,
-                                    nsIDOMNodeList** aResult,
-                                    PRBool* aIsAnonymousContentList);
-  nsresult GetAnonymousNodesInternal(nsIContent* aContent,
-                                     nsIDOMNodeList** aResult,
-                                     PRBool* aIsAnonymousContentList);
+  nsINodeList* GetXBLChildNodesInternal(nsIContent* aContent,
+                                        PRBool* aIsAnonymousContentList);
+  nsINodeList* GetAnonymousNodesInternal(nsIContent* aContent,
+                                         PRBool* aIsAnonymousContentList);
 
   nsIContent* GetNestedInsertionPoint(nsIContent* aParent, nsIContent* aChild);
   nsIContent* GetNestedSingleInsertionPoint(nsIContent* aParent,
                                             PRBool* aMultipleInsertionPoints);
 
   // Called by ContentAppended and ContentInserted to handle a single child
   // insertion.  aChild must not be null.  aContainer may be null.
   // aIndexInContainer is the index of the child in the parent.  aAppend is
@@ -239,34 +245,32 @@ protected:
 
 // MEMBER VARIABLES
 protected: 
   void RemoveInsertionParent(nsIContent* aParent);
   // A mapping from nsIContent* to the nsXBLBinding* that is
   // installed on that element.
   nsRefPtrHashtable<nsISupportsHashKey,nsXBLBinding> mBindingTable;
 
-  // A mapping from nsIContent* to an nsIDOMNodeList*
-  // (nsAnonymousContentList*).  This list contains an accurate
-  // reflection of our *explicit* children (once intermingled with
-  // insertion points) in the altered DOM.  There is an entry for a
-  // content node in this table only if that content node has some
-  // <children> kids.
+  // A mapping from nsIContent* to an nsAnonymousContentList*.  This
+  // list contains an accurate reflection of our *explicit* children
+  // (once intermingled with insertion points) in the altered DOM.
+  // There is an entry for a content node in this table only if that
+  // content node has some <children> kids.
   PLDHashTable mContentListTable;
 
-  // A mapping from nsIContent* to an nsIDOMNodeList*
-  // (nsAnonymousContentList*).  This list contains an accurate
-  // reflection of our *anonymous* children (if and only if they are
-  // intermingled with insertion points) in the altered DOM.  This
-  // table is not used if no insertion points were defined directly
-  // underneath a <content> tag in a binding.  The NodeList from the
-  // <content> is used instead as a performance optimization.  There
-  // is an entry for a content node in this table only if that content
-  // node has a binding with a <content> attached and this <content>
-  // contains <children> elements directly.
+  // A mapping from nsIContent* to an nsAnonymousContentList*.  This
+  // list contains an accurate reflection of our *anonymous* children
+  // (if and only if they are intermingled with insertion points) in
+  // the altered DOM.  This table is not used if no insertion points
+  // were defined directly underneath a <content> tag in a binding.
+  // The NodeList from the <content> is used instead as a performance
+  // optimization.  There is an entry for a content node in this table
+  // only if that content node has a binding with a <content> attached
+  // and this <content> contains <children> elements directly.
   PLDHashTable mAnonymousNodesTable;
 
   // A mapping from nsIContent* to nsIContent*.  The insertion parent
   // is our one true parent in the transformed DOM.  This gives us a
   // more-or-less O(1) way of obtaining our transformed parent.
   PLDHashTable mInsertionParentTable;
 
   // A mapping from nsIContent* to nsIXPWrappedJS* (an XPConnect
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -1565,24 +1565,21 @@ nsXBLBinding::MarkForDeath()
 
 PRBool
 nsXBLBinding::ImplementsInterface(REFNSIID aIID) const
 {
   return mPrototypeBinding->ImplementsInterface(aIID) ||
     (mNextBinding && mNextBinding->ImplementsInterface(aIID));
 }
 
-already_AddRefed<nsIDOMNodeList>
+nsINodeList*
 nsXBLBinding::GetAnonymousNodes()
 {
   if (mContent) {
-    nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mContent));
-    nsIDOMNodeList *nodeList = nsnull;
-    elt->GetChildNodes(&nodeList);
-    return nodeList;
+    return mContent->GetChildNodesList();
   }
 
   if (mNextBinding)
     return mNextBinding->GetAnonymousNodes();
 
   return nsnull;
 }
 
--- a/content/xbl/src/nsXBLBinding.h
+++ b/content/xbl/src/nsXBLBinding.h
@@ -36,17 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsXBLBinding_h_
 #define nsXBLBinding_h_
 
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
-#include "nsIDOMNodeList.h"
+#include "nsINodeList.h"
 #include "nsIStyleRuleProcessor.h"
 #include "nsClassHashtable.h"
 #include "nsTArray.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsXBLPrototypeBinding;
 class nsIContent;
 class nsIAtom;
@@ -151,17 +151,17 @@ public:
 
   void AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID,
                         PRBool aRemoveFlag, PRBool aNotify);
 
   void ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument);
 
   void WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc, void* aData);
 
-  already_AddRefed<nsIDOMNodeList> GetAnonymousNodes();
+  nsINodeList* GetAnonymousNodes();
 
   static nsresult DoInitJSClass(JSContext *cx, JSObject *global, JSObject *obj,
                                 const nsAFlatCString& aClassName,
                                 nsXBLPrototypeBinding* aProtoBinding,
                                 void **aClassObject);
 
   PRBool AllowScripts();  // XXX make const
 
--- a/content/xbl/src/nsXBLInsertionPoint.h
+++ b/content/xbl/src/nsXBLInsertionPoint.h
@@ -76,16 +76,18 @@ public:
   void AddChild(nsIContent* aChildElement) { mElements.AppendObject(aChildElement); }
   void InsertChildAt(PRInt32 aIndex, nsIContent* aChildElement) { mElements.InsertObjectAt(aChildElement, aIndex); }
   void RemoveChild(nsIContent* aChildElement) { mElements.RemoveObject(aChildElement); }
   
   PRInt32 ChildCount() { return mElements.Count(); }
 
   nsIContent* ChildAt(PRUint32 aIndex);
 
+  PRInt32 IndexOf(nsIContent* aContent) { return mElements.IndexOf(aContent); }
+
   PRBool Matches(nsIContent* aContent, PRUint32 aIndex);
 
   // Unbind all the default content in this insertion point.  Used
   // when the insertion parent is going away.
   void UnbindDefaultContent();
 
 protected:
   nsAutoRefCnt mRefCnt;