mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1251337 - TreeWalker doesn't have to check ARIA owned children for each DOM state, r=yzen
This commit is contained in:
parent
06d19d0d14
commit
9ab0baec7f
@ -23,6 +23,7 @@ using namespace mozilla::a11y;
|
|||||||
TreeWalker::
|
TreeWalker::
|
||||||
TreeWalker(Accessible* aContext) :
|
TreeWalker(Accessible* aContext) :
|
||||||
mDoc(aContext->Document()), mContext(aContext), mAnchorNode(nullptr),
|
mDoc(aContext->Document()), mContext(aContext), mAnchorNode(nullptr),
|
||||||
|
mARIAOwnsIdx(0),
|
||||||
mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(0)
|
mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(0)
|
||||||
{
|
{
|
||||||
mChildFilter |= mContext->NoXBLKids() ?
|
mChildFilter |= mContext->NoXBLKids() ?
|
||||||
@ -41,9 +42,12 @@ TreeWalker::
|
|||||||
TreeWalker::
|
TreeWalker::
|
||||||
TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags) :
|
TreeWalker(Accessible* aContext, nsIContent* aAnchorNode, uint32_t aFlags) :
|
||||||
mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aAnchorNode),
|
mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aAnchorNode),
|
||||||
|
mARIAOwnsIdx(0),
|
||||||
mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(aFlags)
|
mChildFilter(nsIContent::eSkipPlaceholderContent), mFlags(aFlags)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aAnchorNode, "No anchor node for the accessible tree walker");
|
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() ?
|
mChildFilter |= mContext->NoXBLKids() ?
|
||||||
nsIContent::eAllButXBL : nsIContent::eAllChildren;
|
nsIContent::eAllButXBL : nsIContent::eAllChildren;
|
||||||
@ -64,29 +68,44 @@ TreeWalker::~TreeWalker()
|
|||||||
Accessible*
|
Accessible*
|
||||||
TreeWalker::Next()
|
TreeWalker::Next()
|
||||||
{
|
{
|
||||||
if (mStateStack.IsEmpty())
|
if (mStateStack.IsEmpty()) {
|
||||||
return nullptr;
|
return mDoc->ARIAOwnedAt(mContext, mARIAOwnsIdx++);
|
||||||
|
}
|
||||||
|
|
||||||
ChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
|
dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
|
||||||
while (top) {
|
while (top) {
|
||||||
Accessible* child = nullptr;
|
while (nsIContent* childNode = top->GetNextChild()) {
|
||||||
bool skipSubtree = false;
|
bool skipSubtree = false;
|
||||||
while (nsIContent* childNode = Next(top, &child, &skipSubtree)) {
|
Accessible* child = nullptr;
|
||||||
if (child)
|
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;
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
// Walk down into subtree to find accessibles.
|
// Walk down into subtree to find accessibles.
|
||||||
if (!skipSubtree && childNode->IsElement())
|
if (!skipSubtree && childNode->IsElement()) {
|
||||||
top = PushState(childNode);
|
top = PushState(childNode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
top = PopState();
|
top = PopState();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we traversed the whole subtree of the anchor node. Move to next node
|
// If we traversed the whole subtree of the anchor node. Move to next node
|
||||||
// relative anchor node within the context subtree if possible.
|
// relative anchor node within the context subtree if possible.
|
||||||
if (mFlags != eWalkContextTree)
|
if (mFlags != eWalkContextTree)
|
||||||
return nullptr;
|
return Next();
|
||||||
|
|
||||||
nsINode* contextNode = mContext->GetNode();
|
nsINode* contextNode = mContext->GetNode();
|
||||||
while (mAnchorNode != contextNode) {
|
while (mAnchorNode != contextNode) {
|
||||||
@ -96,7 +115,7 @@ TreeWalker::Next()
|
|||||||
|
|
||||||
nsIContent* parent = parentNode->AsElement();
|
nsIContent* parent = parentNode->AsElement();
|
||||||
top = PushState(parent);
|
top = PushState(parent);
|
||||||
if (top->mDOMIter.Seek(mAnchorNode)) {
|
if (top->Seek(mAnchorNode)) {
|
||||||
mAnchorNode = parent;
|
mAnchorNode = parent;
|
||||||
return Next();
|
return Next();
|
||||||
}
|
}
|
||||||
@ -108,55 +127,10 @@ TreeWalker::Next()
|
|||||||
mAnchorNode = parent;
|
mAnchorNode = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return Next();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIContent*
|
dom::AllChildrenIterator*
|
||||||
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*
|
|
||||||
TreeWalker::PopState()
|
TreeWalker::PopState()
|
||||||
{
|
{
|
||||||
size_t length = mStateStack.Length();
|
size_t length = mStateStack.Length();
|
||||||
|
@ -63,37 +63,30 @@ private:
|
|||||||
TreeWalker(const TreeWalker&);
|
TreeWalker(const TreeWalker&);
|
||||||
TreeWalker& operator =(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.
|
* 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
|
* @note State stack is used to navigate up/down the DOM subtree during
|
||||||
* accessible children search.
|
* 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.
|
* Pop state from stack.
|
||||||
*/
|
*/
|
||||||
ChildrenIterator* PopState();
|
dom::AllChildrenIterator* PopState();
|
||||||
|
|
||||||
DocAccessible* mDoc;
|
DocAccessible* mDoc;
|
||||||
Accessible* mContext;
|
Accessible* mContext;
|
||||||
nsIContent* mAnchorNode;
|
nsIContent* mAnchorNode;
|
||||||
AutoTArray<ChildrenIterator, 20> mStateStack;
|
|
||||||
|
AutoTArray<dom::AllChildrenIterator, 20> mStateStack;
|
||||||
|
uint32_t mARIAOwnsIdx;
|
||||||
|
|
||||||
int32_t mChildFilter;
|
int32_t mChildFilter;
|
||||||
uint32_t mFlags;
|
uint32_t mFlags;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user