Bug 573469 - part1, add iterator for IDRefs elements, r=fherrera, sr=neil, a=blockingFinal+
authorAlexander Surkov <surkov.alexander@gmail.com>
Tue, 16 Nov 2010 22:32:15 -0500
changeset 57626 384f1f7127dfb7245c881eb2ce066ea0bbf59cd9
parent 57625 dab3886f5e70ebd02101f992936525d76a3133d0
child 57627 908443327ad31bd8cb22f5e6a8f44eab83b65db6
push id17014
push usersurkov.alexander@gmail.com
push dateWed, 17 Nov 2010 03:32:52 +0000
treeherdermozilla-central@384f1f7127df [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfherrera, neil, blockingFinal
bugs573469
milestone2.0b8pre
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 573469 - part1, add iterator for IDRefs elements, r=fherrera, sr=neil, a=blockingFinal+
accessible/src/base/nsCoreUtils.cpp
accessible/src/base/nsCoreUtils.h
accessible/src/base/nsRelUtils.cpp
accessible/src/base/nsTextEquivUtils.cpp
accessible/src/html/nsHTMLTableAccessible.cpp
--- a/accessible/src/base/nsCoreUtils.cpp
+++ b/accessible/src/base/nsCoreUtils.cpp
@@ -42,17 +42,16 @@
 
 #include "nsAccessNode.h"
 
 #include "nsIDocument.h"
 #include "nsIDOMAbstractView.h"
 #include "nsIDOM3Node.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentView.h"
-#include "nsIDOMDocumentXBL.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMViewCSS.h"
 #include "nsIDOMWindowInternal.h"
 #include "nsIDOMXULElement.h"
 #include "nsIDocShell.h"
@@ -801,77 +800,16 @@ nsCoreUtils::GetLanguageFor(nsIContent *
   nsIContent *walkUp = aContent;
   while (walkUp && walkUp != aRootContent &&
          !walkUp->GetAttr(kNameSpaceID_None,
                           nsAccessibilityAtoms::lang, aLanguage))
     walkUp = walkUp->GetParent();
 }
 
 void
-nsCoreUtils::GetElementsByIDRefsAttr(nsIContent *aContent, nsIAtom *aAttr,
-                                     nsIArray **aRefElements)
-{
-  *aRefElements = nsnull;
-
-  nsAutoString ids;
-  if (!aContent->GetAttr(kNameSpaceID_None, aAttr, ids))
-    return;
-
-  ids.CompressWhitespace(PR_TRUE, PR_TRUE);
-
-  nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(aContent->GetOwnerDoc());
-  NS_ASSERTION(document, "The given node is not in document!");
-  if (!document)
-    return;
-
-  nsCOMPtr<nsIDOMDocumentXBL> xblDocument;
-  if (aContent->IsInAnonymousSubtree())
-    xblDocument = do_QueryInterface(document);
-
-  nsCOMPtr<nsIMutableArray> refElms = do_CreateInstance(NS_ARRAY_CONTRACTID);
-
-  while (!ids.IsEmpty()) {
-    nsAutoString id;
-    PRInt32 idLength = ids.FindChar(' ');
-    NS_ASSERTION(idLength != 0,
-                 "Should not be 0 because of CompressWhitespace() call above");
-
-    if (idLength == kNotFound) {
-      id = ids;
-      ids.Truncate();
-    } else {
-      id = Substring(ids, 0, idLength);
-      ids.Cut(0, idLength + 1);
-    }
-
-    // If content is anonymous subtree then use "anonid" attribute to get
-    // elements, otherwise search elements in DOM by ID attribute.
-    nsCOMPtr<nsIDOMElement> refElement;
-    if (xblDocument) {
-      nsCOMPtr<nsIDOMElement> elm =
-        do_QueryInterface(aContent->GetBindingParent());
-      xblDocument->GetAnonymousElementByAttribute(elm,
-                                                  NS_LITERAL_STRING("anonid"),
-                                                  id,
-                                                  getter_AddRefs(refElement));
-    } else {
-      document->GetElementById(id, getter_AddRefs(refElement));
-    }
-
-    if (!refElement)
-      continue;
-
-    refElms->AppendElement(refElement, PR_FALSE);
-  }
-
-  NS_ADDREF(*aRefElements = refElms);
-  return;
-}
-
-void
 nsCoreUtils::GetElementsHavingIDRefsAttr(nsIContent *aRootContent,
                                          nsIContent *aContent,
                                          nsIAtom *aIDRefsAttr,
                                          nsIArray **aElements)
 {
   *aElements = nsnull;
 
   nsAutoString id;
@@ -1160,8 +1098,79 @@ nsAccessibleDOMStringList::GetLength(PRU
 
 NS_IMETHODIMP
 nsAccessibleDOMStringList::Contains(const nsAString& aString, PRBool *aResult)
 {
   *aResult = mNames.Contains(aString);
 
   return NS_OK;
 }
+
+
+////////////////////////////////////////////////////////////////////////////////
+// IDRefsIterator
+////////////////////////////////////////////////////////////////////////////////
+
+IDRefsIterator::IDRefsIterator(nsIContent* aContent, nsIAtom* aIDRefsAttr) :
+  mCurrIdx(0)
+{
+  if (!aContent->IsInDoc() ||
+      !aContent->GetAttr(kNameSpaceID_None, aIDRefsAttr, mIDs))
+    return;
+
+  if (aContent->IsInAnonymousSubtree()) {
+    mXBLDocument = do_QueryInterface(aContent->GetOwnerDoc());
+    mBindingParent = do_QueryInterface(aContent->GetBindingParent());
+  } else {
+    mDocument = aContent->GetOwnerDoc();
+  }
+}
+
+const nsDependentSubstring
+IDRefsIterator::NextID()
+{
+  for (; mCurrIdx < mIDs.Length(); mCurrIdx++) {
+    if (!NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
+      break;
+  }
+
+  if (mCurrIdx >= mIDs.Length())
+    return nsDependentSubstring();
+
+  nsAString::index_type idStartIdx = mCurrIdx;
+  while (++mCurrIdx < mIDs.Length()) {
+    if (NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
+      break;
+  }
+
+  return Substring(mIDs, idStartIdx, mCurrIdx++ - idStartIdx);
+}
+
+nsIContent*
+IDRefsIterator::NextElem()
+{
+  while (true) {
+    const nsDependentSubstring id = NextID();
+    if (id.IsEmpty())
+      break;
+
+    if (mXBLDocument) {
+      // If content is anonymous subtree then use "anonid" attribute to get
+      // elements, otherwise search elements in DOM by ID attribute.
+
+      nsCOMPtr<nsIDOMElement> refElm;
+      mXBLDocument->GetAnonymousElementByAttribute(mBindingParent,
+                                                   NS_LITERAL_STRING("anonid"),
+                                                   id,
+                                                   getter_AddRefs(refElm));
+      nsCOMPtr<nsIContent> refContent = do_QueryInterface(refElm);
+      if (refContent)
+        return refContent;
+
+    } else {
+      nsIContent* refContent = mDocument->GetElementById(id);
+      if (refContent)
+        return refContent;
+    }
+  }
+
+  return nsnull;
+}
--- a/accessible/src/base/nsCoreUtils.h
+++ b/accessible/src/base/nsCoreUtils.h
@@ -36,16 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsCoreUtils_h_
 #define nsCoreUtils_h_
 
 #include "nsAccessibilityAtoms.h"
 
+#include "nsIDOMDocumentXBL.h"
 #include "nsIDOMNode.h"
 #include "nsIContent.h"
 #include "nsIBoxObject.h"
 #include "nsITreeBoxObject.h"
 #include "nsITreeColumns.h"
 
 #include "nsIFrame.h"
 #include "nsIDocShellTreeItem.h"
@@ -300,27 +301,16 @@ public:
    * @param aContent     [in] the given node
    * @param aRootContent [in] container of the given node
    * @param aLanguage    [out] language
    */
   static void GetLanguageFor(nsIContent *aContent, nsIContent *aRootContent,
                              nsAString& aLanguage);
 
   /**
-   * Return the array of elements the given node is referred to by its
-   * IDRefs attribute.
-   *
-   * @param aContent     [in] the given node
-   * @param aAttr        [in] IDRefs attribute on the given node
-   * @param aRefElements [out] result array of elements
-   */
-  static void GetElementsByIDRefsAttr(nsIContent *aContent, nsIAtom *aAttr,
-                                      nsIArray **aRefElements);
-
-  /**
    * Return the array of elements having IDRefs that points to the given node.
    *
    * @param  aRootContent  [in] root element to search inside
    * @param  aContent      [in] an element having ID attribute
    * @param  aIDRefsAttr   [in] IDRefs attribute
    * @param  aElements     [out] result array of elements
    */
   static void GetElementsHavingIDRefsAttr(nsIContent *aRootContent,
@@ -510,10 +500,39 @@ public:
   PRBool Add(const nsAString& aName) {
     return mNames.AppendElement(aName) != nsnull;
   }
 
 private:
   nsTArray<nsString> mNames;
 };
 
+/**
+ * Used to iterate through IDs or elements pointed by IDRefs attribute. Note,
+ * any method used to iterate through IDs or elements moves iterator to next
+ * position.
+ */
+class IDRefsIterator
+{
+public:
+  IDRefsIterator(nsIContent* aContent, nsIAtom* aIDRefsAttr);
+
+  /**
+   * Return next ID.
+   */
+  const nsDependentSubstring NextID();
+
+  /**
+   * Return next element.
+   */
+  nsIContent* NextElem();
+
+private:
+  nsString mIDs;
+  nsAString::index_type mCurrIdx;
+
+  nsIDocument* mDocument;
+  nsCOMPtr<nsIDOMDocumentXBL> mXBLDocument;
+  nsCOMPtr<nsIDOMElement> mBindingParent;
+};
+
 #endif
 
--- a/accessible/src/base/nsRelUtils.cpp
+++ b/accessible/src/base/nsRelUtils.cpp
@@ -129,37 +129,26 @@ nsRelUtils::AddTargetFromIDRefAttr(PRUin
   return AddTargetFromContent(aRelationType, aRelation, refContent);
 }
 
 nsresult
 nsRelUtils::AddTargetFromIDRefsAttr(PRUint32 aRelationType,
                                     nsIAccessibleRelation **aRelation,
                                     nsIContent *aContent, nsIAtom *aAttr)
 {
-  nsCOMPtr<nsIArray> refElms;
-  nsCoreUtils::GetElementsByIDRefsAttr(aContent, aAttr, getter_AddRefs(refElms));
-
-  if (!refElms)
-    return NS_OK_NO_RELATION_TARGET;
+  nsresult rv = NS_OK_NO_RELATION_TARGET;
 
-  PRUint32 count = 0;
-  nsresult rv = refElms->GetLength(&count);
-  if (NS_FAILED(rv) || count == 0)
-    return NS_OK_NO_RELATION_TARGET;
-
-  nsCOMPtr<nsIContent> content;
-  for (PRUint32 idx = 0; idx < count; idx++) {
-    content = do_QueryElementAt(refElms, idx, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = AddTargetFromContent(aRelationType, aRelation, content);
+  nsIContent* refElm = nsnull;
+  IDRefsIterator iter(aContent, aAttr);
+  while ((refElm = iter.NextElem())) {
+    rv = AddTargetFromContent(aRelationType, aRelation, refElm);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  return NS_OK;
+  return rv;
 }
 
 nsresult
 nsRelUtils::AddTargetFromNeighbour(PRUint32 aRelationType,
                                    nsIAccessibleRelation **aRelation,
                                    nsIContent *aContent,
                                    nsIAtom *aNeighboutAttr,
                                    nsIAtom *aNeighboutTagName)
--- a/accessible/src/base/nsTextEquivUtils.cpp
+++ b/accessible/src/base/nsTextEquivUtils.cpp
@@ -87,36 +87,24 @@ nsTextEquivUtils::GetTextEquivFromIDRefs
                                          nsAString& aTextEquiv)
 {
   aTextEquiv.Truncate();
 
   nsIContent* content = aAccessible->GetContent();
   if (!content)
     return NS_OK;
 
-  nsCOMPtr<nsIArray> refElms;
-  nsCoreUtils::GetElementsByIDRefsAttr(content, aIDRefsAttr,
-                                       getter_AddRefs(refElms));
-
-  if (!refElms)
-    return NS_OK;
-
-  PRUint32 count = 0;
-  nsresult rv = refElms->GetLength(&count);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIContent> refContent;
-  for (PRUint32 idx = 0; idx < count; idx++) {
-    refContent = do_QueryElementAt(refElms, idx, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
+  nsIContent* refContent = nsnull;
+  IDRefsIterator iter(content, aIDRefsAttr);
+  while ((refContent = iter.NextElem())) {
     if (!aTextEquiv.IsEmpty())
       aTextEquiv += ' ';
 
-    rv = AppendTextEquivFromContent(aAccessible, refContent, &aTextEquiv);
+    nsresult rv = AppendTextEquivFromContent(aAccessible, refContent,
+                                             &aTextEquiv);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsTextEquivUtils::AppendTextEquivFromContent(nsAccessible *aInitiatorAcc,
--- a/accessible/src/html/nsHTMLTableAccessible.cpp
+++ b/accessible/src/html/nsHTMLTableAccessible.cpp
@@ -303,44 +303,37 @@ nsHTMLTableCellAccessible::GetCellIndexe
   return cellLayout->GetCellIndexes(aRowIndex, aColIndex);
 }
 
 nsresult
 nsHTMLTableCellAccessible::GetHeaderCells(PRInt32 aRowOrColumnHeaderCell,
                                           nsIArray **aHeaderCells)
 {
   // Get header cells from @header attribute.
-  nsCOMPtr<nsIArray> headerCellElms;
-  nsCoreUtils::GetElementsByIDRefsAttr(mContent, nsAccessibilityAtoms::headers,
-                                       getter_AddRefs(headerCellElms));
-
-  if (headerCellElms) {
+  IDRefsIterator iter(mContent, nsAccessibilityAtoms::headers);
+  nsIContent* headerCellElm = iter.NextElem();
+  if (headerCellElm) {
     nsresult rv = NS_OK;
     nsCOMPtr<nsIMutableArray> headerCells =
       do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    PRUint32 count = 0;
-    rv = headerCellElms->GetLength(&count);
-    if (NS_SUCCEEDED(rv) && count > 0) {
-      nsCOMPtr<nsIContent> headerCellContent;
-      for (PRUint32 idx = 0; idx < count; idx++) {
-        headerCellContent = do_QueryElementAt(headerCellElms, idx, &rv);
-        nsAccessible *headerCell =
-          GetAccService()->GetAccessibleInWeakShell(headerCellContent, mWeakShell);
+    do {
+      nsAccessible* headerCell =
+        GetAccService()->GetAccessibleInWeakShell(headerCellElm, mWeakShell);
 
-        if (headerCell &&
-            (aRowOrColumnHeaderCell == nsAccUtils::eRowHeaderCells &&
-             headerCell->Role() == nsIAccessibleRole::ROLE_ROWHEADER ||
-             aRowOrColumnHeaderCell == nsAccUtils::eColumnHeaderCells &&
-             headerCell->Role() == nsIAccessibleRole::ROLE_COLUMNHEADER))
-          headerCells->AppendElement(static_cast<nsIAccessible*>(headerCell),
-                                     PR_FALSE);
+      if (headerCell &&
+          (aRowOrColumnHeaderCell == nsAccUtils::eRowHeaderCells &&
+              headerCell->Role() == nsIAccessibleRole::ROLE_ROWHEADER ||
+              aRowOrColumnHeaderCell == nsAccUtils::eColumnHeaderCells &&
+              headerCell->Role() == nsIAccessibleRole::ROLE_COLUMNHEADER)) {
+        headerCells->AppendElement(static_cast<nsIAccessible*>(headerCell),
+                                   PR_FALSE);
       }
-    }
+    } while ((headerCellElm = iter.NextElem()));
 
     NS_ADDREF(*aHeaderCells = headerCells);
     return NS_OK;
   }
 
   // Otherwise calculate header cells from hierarchy (see 11.4.3 "Algorithm to
   // find heading information" of w3c HTML 4.01).
   nsCOMPtr<nsIAccessibleTable> table = GetTableAccessible();