Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/Element.h"
14 using namespace mozilla::a11y;
16 ////////////////////////////////////////////////////////////////////////////////
17 // WalkState
18 ////////////////////////////////////////////////////////////////////////////////
20 namespace mozilla {
21 namespace a11y {
23 struct WalkState
24 {
25 WalkState(nsIContent *aContent) :
26 content(aContent), childIdx(0), prevState(nullptr) {}
28 nsCOMPtr<nsIContent> content;
29 nsCOMPtr<nsINodeList> childList;
30 uint32_t childIdx;
31 WalkState *prevState;
32 };
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)
45 {
46 NS_ASSERTION(aContent, "No node for the accessible tree walker!");
48 if (aContent)
49 mState = new WalkState(aContent);
51 mChildFilter = mContext->CanHaveAnonChildren() ?
52 nsIContent::eAllChildren : nsIContent::eAllButXBL;
54 mChildFilter |= nsIContent::eSkipPlaceholderContent;
56 MOZ_COUNT_CTOR(TreeWalker);
57 }
59 TreeWalker::~TreeWalker()
60 {
61 // Clear state stack from memory
62 while (mState)
63 PopState();
65 MOZ_COUNT_DTOR(TreeWalker);
66 }
68 ////////////////////////////////////////////////////////////////////////////////
69 // TreeWalker: private
71 Accessible*
72 TreeWalker::NextChildInternal(bool aNoWalkUp)
73 {
74 if (!mState || !mState->content)
75 return nullptr;
77 if (!mState->childList)
78 mState->childList = mState->content->GetChildren(mChildFilter);
80 uint32_t length = 0;
81 if (mState->childList)
82 mState->childList->GetLength(&length);
84 while (mState->childIdx < length) {
85 nsIContent* childNode = mState->childList->Item(mState->childIdx);
86 mState->childIdx++;
88 bool isSubtreeHidden = false;
89 Accessible* accessible = mFlags & eWalkCache ?
90 mDoc->GetAccessible(childNode) :
91 GetAccService()->GetOrCreateAccessible(childNode, mContext,
92 &isSubtreeHidden);
94 if (accessible)
95 return accessible;
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 }
106 // No more children, get back to the parent.
107 nsIContent* anchorNode = mState->content;
108 PopState();
109 if (aNoWalkUp)
110 return nullptr;
112 if (mState)
113 return NextChildInternal(false);
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;
120 while (anchorNode != mContext->GetNode()) {
121 nsINode* parentNode = anchorNode->GetFlattenedTreeParent();
122 if (!parentNode || !parentNode->IsElement())
123 return nullptr;
125 PushState(parentNode->AsElement());
126 mState->childList = mState->content->GetChildren(mChildFilter);
127 length = 0;
128 if (mState->childList)
129 mState->childList->GetLength(&length);
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();
139 anchorNode = parentNode->AsElement();
140 }
142 return nullptr;
143 }
145 void
146 TreeWalker::PopState()
147 {
148 WalkState* prevToLastState = mState->prevState;
149 delete mState;
150 mState = prevToLastState;
151 }
153 void
154 TreeWalker::PushState(nsIContent* aContent)
155 {
156 WalkState* nextToLastState = new WalkState(aContent);
157 nextToLastState->prevState = mState;
158 mState = nextToLastState;
159 }