Bug 1249730 - make TreeWalker bi-directional, r=yzen

This commit is contained in:
Alexander Surkov 2016-03-08 08:27:59 -05:00
parent a7ff33a68b
commit 2e774e974c
2 changed files with 68 additions and 3 deletions

View File

@ -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()

View File

@ -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.