From 65b7ab15174d9cd5b63e21868fdae51d4d76495f Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Mon, 1 Sep 2014 14:31:35 +0200 Subject: [PATCH] Backed out changeset a7840102579b (bug 1052122) for causing regressions on a CLOSED TREE --- accessible/base/TreeWalker.cpp | 107 ++++++++++++++++++++++----------- accessible/base/TreeWalker.h | 29 +++++---- 2 files changed, 90 insertions(+), 46 deletions(-) diff --git a/accessible/base/TreeWalker.cpp b/accessible/base/TreeWalker.cpp index 8b4cd9125c3b..8e97e38c7a60 100644 --- a/accessible/base/TreeWalker.cpp +++ b/accessible/base/TreeWalker.cpp @@ -12,17 +12,36 @@ #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 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!"); @@ -31,13 +50,17 @@ TreeWalker:: 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); } @@ -45,60 +68,74 @@ TreeWalker::~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); } - - top = PopState(); } + // No more children, get back to the parent. + nsIContent* anchorNode = mState->content; + PopState(); + if (aNoWalkUp) + return nullptr; + + 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; } diff --git a/accessible/base/TreeWalker.h b/accessible/base/TreeWalker.h index d34e5e9bb2e2..aa993b1679b5 100644 --- a/accessible/base/TreeWalker.h +++ b/accessible/base/TreeWalker.h @@ -8,8 +8,6 @@ #include "mozilla/Attributes.h" #include -#include "mozilla/dom/ChildIterator.h" -#include "nsCOMPtr.h" class nsIContent; @@ -19,6 +17,8 @@ namespace a11y { class Accessible; class DocAccessible; +struct WalkState; + /** * This class is used to walk the DOM tree to create accessible tree. */ @@ -50,36 +50,43 @@ public: * 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 mStateStack; int32_t mChildFilter; uint32_t mFlags; + WalkState* mState; }; } // namespace a11y