Bug 696205 part 1. Refactor querySelector and querySelectorAll so that there is only one codepath to modify. r=sicking
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 31 Oct 2011 22:49:10 -0400
changeset 79493 829a99f28b5c872f5c73d9a2a02a8289de4bddc4
parent 79492 74e1804b91de46028772433821eeafddc458f159
child 79494 b068485e4cc26cf7ad908e312bd1f47c50595098
push id21408
push userkhuey@mozilla.com
push dateTue, 01 Nov 2011 14:32:20 +0000
treeherdermozilla-central@cd9add22f090 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs696205
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 696205 part 1. Refactor querySelector and querySelectorAll so that there is only one codepath to modify. r=sicking
content/base/src/nsGenericElement.cpp
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -5347,78 +5347,83 @@ ParseSelectorList(nsINode* aNode,
       slot = &cur->mNext;
     }
   } while (*slot);
   *aSelectorList = selectorList;
 
   return NS_OK;
 }
 
-/* static */
-nsIContent*
-nsGenericElement::doQuerySelector(nsINode* aRoot, const nsAString& aSelector,
-                                  nsresult *aResult)
-{
-  NS_PRECONDITION(aResult, "Null out param?");
-
-  nsAutoPtr<nsCSSSelectorList> selectorList;
-  *aResult = ParseSelectorList(aRoot, aSelector,
-                               getter_Transfers(selectorList));
-  NS_ENSURE_SUCCESS(*aResult, nsnull);
-
-  TreeMatchContext matchingContext(false,
-                                   nsRuleWalker::eRelevantLinkUnvisited,
-                                   aRoot->OwnerDoc());
-  for (nsIContent* cur = aRoot->GetFirstChild();
-       cur;
-       cur = cur->GetNextNode(aRoot)) {
-    if (cur->IsElement() &&
-        nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(),
-                                                matchingContext,
-                                                selectorList)) {
-      return cur;
-    }
-  }
-
-  return nsnull;
-}
-
-/* static */
-nsresult
-nsGenericElement::doQuerySelectorAll(nsINode* aRoot,
-                                     const nsAString& aSelector,
-                                     nsIDOMNodeList **aReturn)
-{
-  NS_PRECONDITION(aReturn, "Null out param?");
-
-  nsSimpleContentList* contentList = new nsSimpleContentList(aRoot);
-  NS_ENSURE_TRUE(contentList, NS_ERROR_OUT_OF_MEMORY);
-  NS_ADDREF(*aReturn = contentList);
-  
+template<bool onlyFirstMatch, class T>
+inline static nsresult FindMatchingElements(nsINode* aRoot,
+                                            const nsAString& aSelector,
+                                            T &aList)
+{
   nsAutoPtr<nsCSSSelectorList> selectorList;
   nsresult rv = ParseSelectorList(aRoot, aSelector,
                                   getter_Transfers(selectorList));
   NS_ENSURE_SUCCESS(rv, rv);
 
   TreeMatchContext matchingContext(false,
                                    nsRuleWalker::eRelevantLinkUnvisited,
                                    aRoot->OwnerDoc());
   for (nsIContent* cur = aRoot->GetFirstChild();
        cur;
        cur = cur->GetNextNode(aRoot)) {
     if (cur->IsElement() &&
         nsCSSRuleProcessor::SelectorListMatches(cur->AsElement(),
                                                 matchingContext,
                                                 selectorList)) {
-      contentList->AppendElement(cur);
+      aList.AppendElement(cur->AsElement());
+      if (onlyFirstMatch) {
+        return NS_OK;
+      }
     }
   }
+
   return NS_OK;
 }
 
+struct ElementHolder {
+  ElementHolder() : mElement(nsnull) {}
+  void AppendElement(Element* aElement) {
+    NS_ABORT_IF_FALSE(!mElement, "Should only get one element");
+    mElement = aElement;
+  }
+  Element* mElement;
+};
+
+/* static */
+nsIContent*
+nsGenericElement::doQuerySelector(nsINode* aRoot, const nsAString& aSelector,
+                                  nsresult *aResult)
+{
+  NS_PRECONDITION(aResult, "Null out param?");
+
+  ElementHolder holder;
+  *aResult = FindMatchingElements<true>(aRoot, aSelector, holder);
+
+  return holder.mElement;
+}
+
+/* static */
+nsresult
+nsGenericElement::doQuerySelectorAll(nsINode* aRoot,
+                                     const nsAString& aSelector,
+                                     nsIDOMNodeList **aReturn)
+{
+  NS_PRECONDITION(aReturn, "Null out param?");
+
+  nsSimpleContentList* contentList = new nsSimpleContentList(aRoot);
+  NS_ENSURE_TRUE(contentList, NS_ERROR_OUT_OF_MEMORY);
+  NS_ADDREF(*aReturn = contentList);
+  
+  return FindMatchingElements<false>(aRoot, aSelector, *contentList);
+}
+
 
 bool
 nsGenericElement::MozMatchesSelector(const nsAString& aSelector, nsresult* aResult)
 {
   nsAutoPtr<nsCSSSelectorList> selectorList;
   bool matches = false;
 
   *aResult = ParseSelectorList(this, aSelector, getter_Transfers(selectorList));