accessible/src/base/TreeWalker.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:bc7cd86a6e55
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/. */
5
6 #include "TreeWalker.h"
7
8 #include "Accessible.h"
9 #include "nsAccessibilityService.h"
10 #include "DocAccessible.h"
11
12 #include "mozilla/dom/Element.h"
13
14 using namespace mozilla::a11y;
15
16 ////////////////////////////////////////////////////////////////////////////////
17 // WalkState
18 ////////////////////////////////////////////////////////////////////////////////
19
20 namespace mozilla {
21 namespace a11y {
22
23 struct WalkState
24 {
25 WalkState(nsIContent *aContent) :
26 content(aContent), childIdx(0), prevState(nullptr) {}
27
28 nsCOMPtr<nsIContent> content;
29 nsCOMPtr<nsINodeList> childList;
30 uint32_t childIdx;
31 WalkState *prevState;
32 };
33
34 } // namespace a11y
35 } // namespace mozilla
36
37 ////////////////////////////////////////////////////////////////////////////////
38 // TreeWalker
39 ////////////////////////////////////////////////////////////////////////////////
40
41 TreeWalker::
42 TreeWalker(Accessible* aContext, nsIContent* aContent, uint32_t aFlags) :
43 mDoc(aContext->Document()), mContext(aContext),
44 mFlags(aFlags), mState(nullptr)
45 {
46 NS_ASSERTION(aContent, "No node for the accessible tree walker!");
47
48 if (aContent)
49 mState = new WalkState(aContent);
50
51 mChildFilter = mContext->CanHaveAnonChildren() ?
52 nsIContent::eAllChildren : nsIContent::eAllButXBL;
53
54 mChildFilter |= nsIContent::eSkipPlaceholderContent;
55
56 MOZ_COUNT_CTOR(TreeWalker);
57 }
58
59 TreeWalker::~TreeWalker()
60 {
61 // Clear state stack from memory
62 while (mState)
63 PopState();
64
65 MOZ_COUNT_DTOR(TreeWalker);
66 }
67
68 ////////////////////////////////////////////////////////////////////////////////
69 // TreeWalker: private
70
71 Accessible*
72 TreeWalker::NextChildInternal(bool aNoWalkUp)
73 {
74 if (!mState || !mState->content)
75 return nullptr;
76
77 if (!mState->childList)
78 mState->childList = mState->content->GetChildren(mChildFilter);
79
80 uint32_t length = 0;
81 if (mState->childList)
82 mState->childList->GetLength(&length);
83
84 while (mState->childIdx < length) {
85 nsIContent* childNode = mState->childList->Item(mState->childIdx);
86 mState->childIdx++;
87
88 bool isSubtreeHidden = false;
89 Accessible* accessible = mFlags & eWalkCache ?
90 mDoc->GetAccessible(childNode) :
91 GetAccService()->GetOrCreateAccessible(childNode, mContext,
92 &isSubtreeHidden);
93
94 if (accessible)
95 return accessible;
96
97 // Walk down into subtree to find accessibles.
98 if (!isSubtreeHidden) {
99 PushState(childNode);
100 accessible = NextChildInternal(true);
101 if (accessible)
102 return accessible;
103 }
104 }
105
106 // No more children, get back to the parent.
107 nsIContent* anchorNode = mState->content;
108 PopState();
109 if (aNoWalkUp)
110 return nullptr;
111
112 if (mState)
113 return NextChildInternal(false);
114
115 // If we traversed the whole subtree of the anchor node. Move to next node
116 // relative anchor node within the context subtree if possible.
117 if (mFlags != eWalkContextTree)
118 return nullptr;
119
120 while (anchorNode != mContext->GetNode()) {
121 nsINode* parentNode = anchorNode->GetFlattenedTreeParent();
122 if (!parentNode || !parentNode->IsElement())
123 return nullptr;
124
125 PushState(parentNode->AsElement());
126 mState->childList = mState->content->GetChildren(mChildFilter);
127 length = 0;
128 if (mState->childList)
129 mState->childList->GetLength(&length);
130
131 while (mState->childIdx < length) {
132 nsIContent* childNode = mState->childList->Item(mState->childIdx);
133 mState->childIdx++;
134 if (childNode == anchorNode)
135 return NextChildInternal(false);
136 }
137 PopState();
138
139 anchorNode = parentNode->AsElement();
140 }
141
142 return nullptr;
143 }
144
145 void
146 TreeWalker::PopState()
147 {
148 WalkState* prevToLastState = mState->prevState;
149 delete mState;
150 mState = prevToLastState;
151 }
152
153 void
154 TreeWalker::PushState(nsIContent* aContent)
155 {
156 WalkState* nextToLastState = new WalkState(aContent);
157 nextToLastState->prevState = mState;
158 mState = nextToLastState;
159 }

mercurial