Bumping manifests a=b2g-bump
[gecko.git] / accessible / base / TreeWalker.cpp
blob8e97e38c7a60b4c0288d0d4b40ad4e368e7b7fac
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "TreeWalker.h"
8 #include "Accessible.h"
9 #include "nsAccessibilityService.h"
10 #include "DocAccessible.h"
12 #include "mozilla/dom/ChildIterator.h"
13 #include "mozilla/dom/Element.h"
15 using namespace mozilla::a11y;
17 ////////////////////////////////////////////////////////////////////////////////
18 // WalkState
19 ////////////////////////////////////////////////////////////////////////////////
21 namespace mozilla {
22 namespace a11y {
24 struct WalkState
26 WalkState(nsIContent *aContent, uint32_t aFilter) :
27 content(aContent), prevState(nullptr), iter(aContent, aFilter) {}
29 nsCOMPtr<nsIContent> content;
30 WalkState *prevState;
31 dom::AllChildrenIterator iter;
34 } // namespace a11y
35 } // namespace mozilla
37 ////////////////////////////////////////////////////////////////////////////////
38 // TreeWalker
39 ////////////////////////////////////////////////////////////////////////////////
41 TreeWalker::
42 TreeWalker(Accessible* aContext, nsIContent* aContent, uint32_t aFlags) :
43 mDoc(aContext->Document()), mContext(aContext),
44 mFlags(aFlags), mState(nullptr)
46 NS_ASSERTION(aContent, "No node for the accessible tree walker!");
48 mChildFilter = mContext->CanHaveAnonChildren() ?
49 nsIContent::eAllChildren : nsIContent::eAllButXBL;
50 mChildFilter |= nsIContent::eSkipPlaceholderContent;
52 if (aContent)
53 mState = new WalkState(aContent, mChildFilter);
55 MOZ_COUNT_CTOR(TreeWalker);
58 TreeWalker::~TreeWalker()
60 // Clear state stack from memory
61 while (mState)
62 PopState();
64 MOZ_COUNT_DTOR(TreeWalker);
67 ////////////////////////////////////////////////////////////////////////////////
68 // TreeWalker: private
70 Accessible*
71 TreeWalker::NextChildInternal(bool aNoWalkUp)
73 if (!mState || !mState->content)
74 return nullptr;
76 while (nsIContent* childNode = mState->iter.GetNextChild()) {
77 bool isSubtreeHidden = false;
78 Accessible* accessible = mFlags & eWalkCache ?
79 mDoc->GetAccessible(childNode) :
80 GetAccService()->GetOrCreateAccessible(childNode, mContext,
81 &isSubtreeHidden);
83 if (accessible)
84 return accessible;
86 // Walk down into subtree to find accessibles.
87 if (!isSubtreeHidden && childNode->IsElement()) {
88 PushState(childNode);
89 accessible = NextChildInternal(true);
90 if (accessible)
91 return accessible;
95 // No more children, get back to the parent.
96 nsIContent* anchorNode = mState->content;
97 PopState();
98 if (aNoWalkUp)
99 return nullptr;
101 if (mState)
102 return NextChildInternal(false);
104 // If we traversed the whole subtree of the anchor node. Move to next node
105 // relative anchor node within the context subtree if possible.
106 if (mFlags != eWalkContextTree)
107 return nullptr;
109 while (anchorNode != mContext->GetNode()) {
110 nsINode* parentNode = anchorNode->GetFlattenedTreeParent();
111 if (!parentNode || !parentNode->IsElement())
112 return nullptr;
114 PushState(parentNode->AsElement());
115 while (nsIContent* childNode = mState->iter.GetNextChild()) {
116 if (childNode == anchorNode)
117 return NextChildInternal(false);
119 PopState();
121 anchorNode = parentNode->AsElement();
124 return nullptr;
127 void
128 TreeWalker::PopState()
130 WalkState* prevToLastState = mState->prevState;
131 delete mState;
132 mState = prevToLastState;
135 void
136 TreeWalker::PushState(nsIContent* aContent)
138 WalkState* nextToLastState = new WalkState(aContent, mChildFilter);
139 nextToLastState->prevState = mState;
140 mState = nextToLastState;