Bug 1251337 - TreeWalker doesn't have to check ARIA owned children for each DOM state, r=yzen
authorAlexander Surkov <surkov.alexander@gmail.com>
Sun, 28 Feb 2016 11:30:46 -0500
changeset 324206 26c6132f3effd41c633aed6adca6268510c6e788
parent 324205 cbc8aa59e92914297dcda968745e03c847498515
child 324207 faa614e2ad4eff5e04c9886bd39f63ebe20fe00c
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyzen
bugs1251337
milestone47.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 1251337 - TreeWalker doesn't have to check ARIA owned children for each DOM state, r=yzen
accessible/base/TreeWalker.cpp
accessible/base/TreeWalker.h
--- a/accessible/base/TreeWalker.cpp
+++ b/accessible/base/TreeWalker.cpp
@@ -18,16 +18,17 @@ using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // TreeWalker
 ////////////////////////////////////////////////////////////////////////////////
 
 TreeWalker::
   TreeWalker(Accessible* aContext) :
   mDoc(aContext->Document()), mContext(aContext), mAnchorNode(nullptr),
+  mARIAOwnsIdx(0),
   mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(0)
 {
   mChildFilter |= mContext->NoXBLKids() ?
     nsIContent::eAllButXBL : nsIContent::eAllChildren;
 
   mAnchorNode = mContext->IsDoc() ?
     mDoc->DocumentNode()->GetRootElement() : mContext->GetContent();
 
@@ -36,19 +37,22 @@ TreeWalker::
   }
 
   MOZ_COUNT_CTOR(TreeWalker);
 }
 
 TreeWalker::
   TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags) :
   mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aAnchorNode),
+  mARIAOwnsIdx(0),
   mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(aFlags)
 {
   MOZ_ASSERT(aAnchorNode, "No anchor node for the accessible tree walker");
+  MOZ_ASSERT(mDoc->GetAccessibleOrContainer(aAnchorNode) == mContext,
+             "Unexpected anchor node was given");
 
   mChildFilter |= mContext->NoXBLKids() ?
     nsIContent::eAllButXBL : nsIContent::eAllChildren;
 
   PushState(aAnchorNode);
 
   MOZ_COUNT_CTOR(TreeWalker);
 }
@@ -59,107 +63,77 @@ TreeWalker::~TreeWalker()
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // TreeWalker: private
 
 Accessible*
 TreeWalker::Next()
 {
-  if (mStateStack.IsEmpty())
-    return nullptr;
+  if (mStateStack.IsEmpty()) {
+    return mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx++);
+  }
 
-  ChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
+  dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
   while (top) {
-    Accessible* child = nullptr;
-    bool skipSubtree = false;
-    while (nsIContent* childNode = Next(top, &child, &skipSubtree)) {
-      if (child)
+    while (nsIContent* childNode = top->GetNextChild()) {
+      bool skipSubtree = false;
+      Accessible* child = nullptr;
+      if (mFlags & eWalkCache) {
+        child = mDoc->GetAccessible(childNode);
+      }
+      else if (mContext->IsAcceptableChild(childNode)) {
+        child = GetAccService()->
+          GetOrCreateAccessible(childNode, mContext, &skipSubtree);
+      }
+
+      // Ignore the accessible and its subtree if it was repositioned by means
+      // of aria-owns.
+      if (child) {
+        if (child->IsRelocated()) {
+          continue;
+        }
         return child;
+      }
 
       // Walk down into subtree to find accessibles.
-      if (!skipSubtree && childNode->IsElement())
+      if (!skipSubtree && childNode->IsElement()) {
         top = PushState(childNode);
+      }
     }
-
     top = PopState();
   }
 
   // If we traversed the whole subtree of the anchor node. Move to next node
   // relative anchor node within the context subtree if possible.
   if (mFlags != eWalkContextTree)
-    return nullptr;
+    return Next();
 
   nsINode* contextNode = mContext->GetNode();
   while (mAnchorNode != contextNode) {
     nsINode* parentNode = mAnchorNode->GetFlattenedTreeParent();
     if (!parentNode || !parentNode->IsElement())
       return nullptr;
 
     nsIContent* parent = parentNode->AsElement();
     top = PushState(parent);
-    if (top->mDOMIter.Seek(mAnchorNode)) {
+    if (top->Seek(mAnchorNode)) {
       mAnchorNode = parent;
       return Next();
     }
 
     // XXX We really should never get here, it means we're trying to find an
     // accessible for a dom node where iterating over its parent's children
     // doesn't return it. However this sometimes happens when we're asked for
     // the nearest accessible to place holder content which we ignore.
     mAnchorNode = parent;
   }
 
-  return nullptr;
+  return Next();
 }
 
-nsIContent*
-TreeWalker::Next(ChildrenIterator* aIter, Accessible** aAccesible,
-                 bool* aSkipSubtree)
-{
-  nsIContent* childEl = aIter->mDOMIter.GetNextChild();
-  if (!aAccesible)
-    return childEl;
-
-  *aAccesible = nullptr;
-  *aSkipSubtree = false;
-
-  if (childEl) {
-    Accessible* accessible = nullptr;
-    if (mFlags & eWalkCache) {
-      accessible = mDoc->GetAccessible(childEl);
-    }
-    else if (mContext->IsAcceptableChild(childEl)) {
-      accessible = GetAccService()->
-        GetOrCreateAccessible(childEl, mContext, aSkipSubtree);
-    }
-
-    // Ignore the accessible and its subtree if it was repositioned by means of
-    // aria-owns.
-    if (accessible) {
-      if (accessible->IsRelocated()) {
-        *aSkipSubtree = true;
-      } else {
-        *aAccesible = accessible;
-      }
-    }
-    return childEl;
-  }
-
-  // At last iterate over ARIA owned children.
-  Accessible* parent = mDoc->GetAccessible(aIter->mDOMIter.Parent());
-  if (parent) {
-    Accessible* child = mDoc->ARIAOwnedAt(parent, aIter->mARIAOwnsIdx++);
-    if (child) {
-      *aAccesible = child;
-      return child->GetContent();
-    }
-  }
-  return nullptr;
-}
-
-TreeWalker::ChildrenIterator*
+dom::AllChildrenIterator*
 TreeWalker::PopState()
 {
   size_t length = mStateStack.Length();
   mStateStack.RemoveElementAt(length - 1);
   return mStateStack.IsEmpty() ? nullptr : &mStateStack[mStateStack.Length() - 1];
 }
--- a/accessible/base/TreeWalker.h
+++ b/accessible/base/TreeWalker.h
@@ -58,47 +58,40 @@ public:
    */
   Accessible* Next();
 
 private:
   TreeWalker();
   TreeWalker(const TreeWalker&);
   TreeWalker& operator =(const TreeWalker&);
 
-  struct ChildrenIterator {
-    ChildrenIterator(nsIContent* aNode, uint32_t aFilter) :
-      mDOMIter(aNode, aFilter), mARIAOwnsIdx(0) { }
-
-    dom::AllChildrenIterator mDOMIter;
-    uint32_t mARIAOwnsIdx;
-  };
-
-  nsIContent* Next(ChildrenIterator* aIter, Accessible** aAccessible = nullptr,
-                   bool* aSkipSubtree = nullptr);
-
   /**
    * Create new state for the given node and push it on top of stack.
    *
    * @note State stack is used to navigate up/down the DOM subtree during
    *        accessible children search.
    */
-  ChildrenIterator* PushState(nsIContent* aContent)
+  dom::AllChildrenIterator* PushState(nsIContent* aContent)
   {
-    return mStateStack.AppendElement(ChildrenIterator(aContent, mChildFilter));
+    return mStateStack.AppendElement(
+      dom::AllChildrenIterator(aContent, mChildFilter));
   }
 
   /**
    * Pop state from stack.
    */
-  ChildrenIterator* PopState();
+  dom::AllChildrenIterator* PopState();
 
   DocAccessible* mDoc;
   Accessible* mContext;
   nsIContent* mAnchorNode;
-  AutoTArray<ChildrenIterator, 20> mStateStack;
+
+  AutoTArray<dom::AllChildrenIterator, 20> mStateStack;
+  uint32_t mARIAOwnsIdx;
+
   int32_t mChildFilter;
   uint32_t mFlags;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_TreeWalker_h_