Backed out changeset a7840102579b (bug 1052122) for causing regressions on a CLOSED TREE
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 01 Sep 2014 14:31:35 +0200
changeset 224393 532b5fb77ba1257d2eeb45aa9692cb73504e701a
parent 224392 738469449872ffc1d278c33fc900af5348fa57fb
child 224416 b4eb275c7fd874faddbe2356a3ddd50b4dd9b3ca
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1052122
milestone34.0a1
backs outa7840102579bb11fa60237349236118d38adb7c2
first release with
nightly linux32
532b5fb77ba1 / 34.0a1 / 20140901091008 / files
nightly linux64
532b5fb77ba1 / 34.0a1 / 20140901091008 / files
nightly mac
532b5fb77ba1 / 34.0a1 / 20140901091008 / files
nightly win32
532b5fb77ba1 / 34.0a1 / 20140901091008 / files
nightly win64
532b5fb77ba1 / 34.0a1 / 20140901091008 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset a7840102579b (bug 1052122) for causing regressions on a CLOSED TREE
accessible/base/TreeWalker.cpp
accessible/base/TreeWalker.h
--- a/accessible/base/TreeWalker.cpp
+++ b/accessible/base/TreeWalker.cpp
@@ -7,98 +7,135 @@
 
 #include "Accessible.h"
 #include "nsAccessibilityService.h"
 #include "DocAccessible.h"
 
 #include "mozilla/dom/ChildIterator.h"
 #include "mozilla/dom/Element.h"
 
-using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
+// WalkState
+////////////////////////////////////////////////////////////////////////////////
+
+namespace mozilla {
+namespace a11y {
+
+struct WalkState
+{
+  WalkState(nsIContent *aContent, uint32_t aFilter) :
+    content(aContent), prevState(nullptr), iter(aContent, aFilter) {}
+
+  nsCOMPtr<nsIContent> content;
+  WalkState *prevState;
+  dom::AllChildrenIterator iter;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+////////////////////////////////////////////////////////////////////////////////
 // TreeWalker
 ////////////////////////////////////////////////////////////////////////////////
 
 TreeWalker::
   TreeWalker(Accessible* aContext, nsIContent* aContent, uint32_t aFlags) :
-  mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aContent),
-  mFlags(aFlags)
+  mDoc(aContext->Document()), mContext(aContext),
+  mFlags(aFlags), mState(nullptr)
 {
   NS_ASSERTION(aContent, "No node for the accessible tree walker!");
 
   mChildFilter = mContext->CanHaveAnonChildren() ?
     nsIContent::eAllChildren : nsIContent::eAllButXBL;
   mChildFilter |= nsIContent::eSkipPlaceholderContent;
 
   if (aContent)
-    PushState(aContent);
+    mState = new WalkState(aContent, mChildFilter);
 
   MOZ_COUNT_CTOR(TreeWalker);
 }
 
 TreeWalker::~TreeWalker()
 {
+  // Clear state stack from memory
+  while (mState)
+    PopState();
+
   MOZ_COUNT_DTOR(TreeWalker);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // TreeWalker: private
 
 Accessible*
-TreeWalker::NextChild()
+TreeWalker::NextChildInternal(bool aNoWalkUp)
 {
-  if (mStateStack.IsEmpty())
+  if (!mState || !mState->content)
     return nullptr;
 
-  dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
-  while (top) {
-    while (nsIContent* childNode = top->GetNextChild()) {
-      bool isSubtreeHidden = false;
-      Accessible* accessible = mFlags & eWalkCache ?
-        mDoc->GetAccessible(childNode) :
-        GetAccService()->GetOrCreateAccessible(childNode, mContext,
-                                               &isSubtreeHidden);
+  while (nsIContent* childNode = mState->iter.GetNextChild()) {
+    bool isSubtreeHidden = false;
+    Accessible* accessible = mFlags & eWalkCache ?
+      mDoc->GetAccessible(childNode) :
+      GetAccService()->GetOrCreateAccessible(childNode, mContext,
+                                             &isSubtreeHidden);
 
+    if (accessible)
+      return accessible;
+
+    // Walk down into subtree to find accessibles.
+    if (!isSubtreeHidden && childNode->IsElement()) {
+      PushState(childNode);
+      accessible = NextChildInternal(true);
       if (accessible)
         return accessible;
+    }
+  }
 
-      // Walk down into subtree to find accessibles.
-      if (!isSubtreeHidden && childNode->IsElement())
-        top = PushState(childNode);
-    }
+  // No more children, get back to the parent.
+  nsIContent* anchorNode = mState->content;
+  PopState();
+  if (aNoWalkUp)
+    return nullptr;
 
-    top = PopState();
-  }
+  if (mState)
+    return NextChildInternal(false);
 
   // 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;
 
-  nsINode* contextNode = mContext->GetNode();
-  while (mAnchorNode != contextNode) {
-    nsINode* parentNode = mAnchorNode->GetFlattenedTreeParent();
+  while (anchorNode != mContext->GetNode()) {
+    nsINode* parentNode = anchorNode->GetFlattenedTreeParent();
     if (!parentNode || !parentNode->IsElement())
       return nullptr;
 
-    nsIContent* parent = parentNode->AsElement();
-    top = mStateStack.AppendElement(dom::AllChildrenIterator(parent,
-                                                             mChildFilter));
-    while (nsIContent* childNode = top->GetNextChild()) {
-      if (childNode == mAnchorNode) {
-        mAnchorNode = parent;
-        return NextChild();
-      }
+    PushState(parentNode->AsElement());
+    while (nsIContent* childNode = mState->iter.GetNextChild()) {
+      if (childNode == anchorNode)
+        return NextChildInternal(false);
     }
+    PopState();
+
+    anchorNode = parentNode->AsElement();
   }
 
   return nullptr;
 }
 
-dom::AllChildrenIterator*
+void
 TreeWalker::PopState()
 {
-  size_t length = mStateStack.Length();
-  mStateStack.RemoveElementAt(length - 1);
-  return mStateStack.IsEmpty() ? nullptr : &mStateStack[mStateStack.Length() - 1];
+  WalkState* prevToLastState = mState->prevState;
+  delete mState;
+  mState = prevToLastState;
 }
+
+void
+TreeWalker::PushState(nsIContent* aContent)
+{
+  WalkState* nextToLastState = new WalkState(aContent, mChildFilter);
+  nextToLastState->prevState = mState;
+  mState = nextToLastState;
+}
--- a/accessible/base/TreeWalker.h
+++ b/accessible/base/TreeWalker.h
@@ -3,27 +3,27 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_a11y_TreeWalker_h_
 #define mozilla_a11y_TreeWalker_h_
 
 #include "mozilla/Attributes.h"
 #include <stdint.h>
-#include "mozilla/dom/ChildIterator.h"
-#include "nsCOMPtr.h"
 
 class nsIContent;
 
 namespace mozilla {
 namespace a11y {
 
 class Accessible;
 class DocAccessible;
 
+struct WalkState;
+
 /**
  * This class is used to walk the DOM tree to create accessible tree.
  */
 class TreeWalker MOZ_FINAL
 {
 public:
   enum {
     // used to walk the existing tree of the given node
@@ -45,44 +45,51 @@ public:
 
   /**
    * Return the next child accessible.
    *
    * @note Returned accessible is bound to the document, if the accessible is
    *       rejected during tree creation then the caller should be unbind it
    *       from the document.
    */
-  Accessible* NextChild();
+  Accessible* NextChild()
+  {
+    return NextChildInternal(false);
+  }
 
 private:
   TreeWalker();
   TreeWalker(const TreeWalker&);
   TreeWalker& operator =(const TreeWalker&);
 
   /**
+   * Return the next child accessible.
+   *
+   * @param  aNoWalkUp  [in] specifies the walk direction, true means we
+   *                     shouldn't go up through the tree if we failed find
+   *                     accessible children.
+   */
+  Accessible* NextChildInternal(bool aNoWalkUp);
+
+  /**
    * 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.
    */
-  dom::AllChildrenIterator* PushState(nsIContent* aContent)
-  {
-    return mStateStack.AppendElement(dom::AllChildrenIterator(aContent,
-                                                              mChildFilter));
-  }
+  void PushState(nsIContent* aNode);
 
   /**
    * Pop state from stack.
    */
-  dom::AllChildrenIterator* PopState();
+  void PopState();
 
   DocAccessible* mDoc;
   Accessible* mContext;
-  nsIContent* mAnchorNode;
-  nsAutoTArray<dom::AllChildrenIterator, 20> mStateStack;
   int32_t mChildFilter;
   uint32_t mFlags;
+  WalkState* mState;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_TreeWalker_h_