From 2e774e974c45ac51e4e3010cac056a9a3f8d4862 Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Tue, 8 Mar 2016 08:27:59 -0500 Subject: [PATCH] Bug 1249730 - make TreeWalker bi-directional, r=yzen --- accessible/base/TreeWalker.cpp | 53 ++++++++++++++++++++++++++++++++-- accessible/base/TreeWalker.h | 18 +++++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/accessible/base/TreeWalker.cpp b/accessible/base/TreeWalker.cpp index 8e66aeeff23c..ff0475ed97b8 100644 --- a/accessible/base/TreeWalker.cpp +++ b/accessible/base/TreeWalker.cpp @@ -58,8 +58,57 @@ TreeWalker::~TreeWalker() MOZ_COUNT_DTOR(TreeWalker); } -//////////////////////////////////////////////////////////////////////////////// -// TreeWalker: private +bool +TreeWalker::Seek(nsIContent* aChildNode) +{ + MOZ_ASSERT(aChildNode, "Child cannot be null"); + + mPhase = eAtStart; + mStateStack.Clear(); + mARIAOwnsIdx = 0; + + nsIContent* childNode = nullptr; + nsINode* parentNode = aChildNode; + do { + childNode = parentNode->AsContent(); + parentNode = childNode->HasFlag(NODE_MAY_BE_IN_BINDING_MNGR) && + (mChildFilter & nsIContent::eAllButXBL) ? + childNode->GetParentNode() : childNode->GetFlattenedTreeParent(); + + if (!parentNode || !parentNode->IsElement()) { + return false; + } + + // If ARIA owned child. + Accessible* child = mDoc->GetAccessible(childNode); + if (child && child->IsRelocated()) { + if (child->Parent() != mContext) { + return false; + } + + Accessible* ownedChild = nullptr; + while ((ownedChild = mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx++)) && + ownedChild != child); + + MOZ_ASSERT(ownedChild, "A child has to be in ARIA owned elements"); + mPhase = eAtARIAOwns; + return true; + } + + // Look in DOM. + dom::AllChildrenIterator* iter = PrependState(parentNode->AsElement(), true); + if (!iter->Seek(childNode)) { + return false; + } + + if (parentNode == mAnchorNode) { + mPhase = eAtDOM; + return true; + } + } while (true); + + return false; +} Accessible* TreeWalker::Next() diff --git a/accessible/base/TreeWalker.h b/accessible/base/TreeWalker.h index a6d1dcab6279..215bf8d8107d 100644 --- a/accessible/base/TreeWalker.h +++ b/accessible/base/TreeWalker.h @@ -49,6 +49,12 @@ public: ~TreeWalker(); + /** + * Clears the tree walker state and resets it to the given child within + * the anchor. + */ + bool Seek(nsIContent* aChildNode); + /** * Return the next/prev accessible. * @@ -59,13 +65,17 @@ public: Accessible* Next(); Accessible* Prev(); + Accessible* Context() const { return mContext; } + DocAccessible* Document() const { return mDoc; } + private: TreeWalker(); TreeWalker(const TreeWalker&); TreeWalker& operator =(const TreeWalker&); /** - * Create new state for the given node and push it on top of stack. + * Create new state for the given node and push it on top of stack / at bottom + * of stack. * * @note State stack is used to navigate up/down the DOM subtree during * accessible children search. @@ -76,6 +86,12 @@ private: return mStateStack.AppendElement( dom::AllChildrenIterator(aContent, mChildFilter, aStartAtBeginning)); } + dom::AllChildrenIterator* PrependState(nsIContent* aContent, + bool aStartAtBeginning) + { + return mStateStack.InsertElementAt(0, + dom::AllChildrenIterator(aContent, mChildFilter, aStartAtBeginning)); + } /** * Pop state from stack.