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 ////////////////////////////////////////////////////////////////////////////////
19 ////////////////////////////////////////////////////////////////////////////////
26 WalkState(nsIContent
*aContent
, uint32_t aFilter
) :
27 content(aContent
), prevState(nullptr), iter(aContent
, aFilter
) {}
29 nsCOMPtr
<nsIContent
> content
;
31 dom::AllChildrenIterator iter
;
35 } // namespace mozilla
37 ////////////////////////////////////////////////////////////////////////////////
39 ////////////////////////////////////////////////////////////////////////////////
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
;
53 mState
= new WalkState(aContent
, mChildFilter
);
55 MOZ_COUNT_CTOR(TreeWalker
);
58 TreeWalker::~TreeWalker()
60 // Clear state stack from memory
64 MOZ_COUNT_DTOR(TreeWalker
);
67 ////////////////////////////////////////////////////////////////////////////////
68 // TreeWalker: private
71 TreeWalker::NextChildInternal(bool aNoWalkUp
)
73 if (!mState
|| !mState
->content
)
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
,
86 // Walk down into subtree to find accessibles.
87 if (!isSubtreeHidden
&& childNode
->IsElement()) {
89 accessible
= NextChildInternal(true);
95 // No more children, get back to the parent.
96 nsIContent
* anchorNode
= mState
->content
;
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
)
109 while (anchorNode
!= mContext
->GetNode()) {
110 nsINode
* parentNode
= anchorNode
->GetFlattenedTreeParent();
111 if (!parentNode
|| !parentNode
->IsElement())
114 PushState(parentNode
->AsElement());
115 while (nsIContent
* childNode
= mState
->iter
.GetNextChild()) {
116 if (childNode
== anchorNode
)
117 return NextChildInternal(false);
121 anchorNode
= parentNode
->AsElement();
128 TreeWalker::PopState()
130 WalkState
* prevToLastState
= mState
->prevState
;
132 mState
= prevToLastState
;
136 TreeWalker::PushState(nsIContent
* aContent
)
138 WalkState
* nextToLastState
= new WalkState(aContent
, mChildFilter
);
139 nextToLastState
->prevState
= mState
;
140 mState
= nextToLastState
;