1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "AccIterator.h"
7 #include "AccGroupInfo.h"
9 #include "XULTreeAccessible.h"
12 #include "mozilla/dom/Element.h"
14 using namespace mozilla
;
15 using namespace mozilla::a11y
;
17 ////////////////////////////////////////////////////////////////////////////////
19 ////////////////////////////////////////////////////////////////////////////////
21 AccIterator::AccIterator(Accessible
* aAccessible
,
22 filters::FilterFuncPtr aFilterFunc
) :
23 mFilterFunc(aFilterFunc
)
25 mState
= new IteratorState(aAccessible
);
28 AccIterator::~AccIterator()
31 IteratorState
*tmp
= mState
;
32 mState
= tmp
->mParentState
;
41 Accessible
* child
= mState
->mParent
->GetChildAt(mState
->mIndex
++);
43 IteratorState
* tmp
= mState
;
44 mState
= mState
->mParentState
;
50 uint32_t result
= mFilterFunc(child
);
51 if (result
& filters::eMatch
)
54 if (!(result
& filters::eSkipSubtree
)) {
55 IteratorState
* childState
= new IteratorState(child
, mState
);
63 ////////////////////////////////////////////////////////////////////////////////
64 // nsAccIterator::IteratorState
66 AccIterator::IteratorState::IteratorState(Accessible
* aParent
,
67 IteratorState
*mParentState
) :
68 mParent(aParent
), mIndex(0), mParentState(mParentState
)
73 ////////////////////////////////////////////////////////////////////////////////
75 ////////////////////////////////////////////////////////////////////////////////
78 RelatedAccIterator(DocAccessible
* aDocument
, nsIContent
* aDependentContent
,
80 mDocument(aDocument
), mRelAttr(aRelAttr
), mProviders(nullptr),
81 mBindingParent(nullptr), mIndex(0)
83 mBindingParent
= aDependentContent
->GetBindingParent();
84 nsIAtom
* IDAttr
= mBindingParent
?
85 nsGkAtoms::anonid
: nsGkAtoms::id
;
88 if (aDependentContent
->GetAttr(kNameSpaceID_None
, IDAttr
, id
))
89 mProviders
= mDocument
->mDependentIDsHash
.Get(id
);
93 RelatedAccIterator::Next()
98 while (mIndex
< mProviders
->Length()) {
99 DocAccessible::AttrRelProvider
* provider
= (*mProviders
)[mIndex
++];
101 // Return related accessible for the given attribute and if the provider
102 // content is in the same binding in the case of XBL usage.
103 if (provider
->mRelAttr
== mRelAttr
) {
104 nsIContent
* bindingParent
= provider
->mContent
->GetBindingParent();
105 bool inScope
= mBindingParent
== bindingParent
||
106 mBindingParent
== provider
->mContent
;
109 Accessible
* related
= mDocument
->GetAccessible(provider
->mContent
);
113 // If the document content is pointed by relation then return the document
115 if (provider
->mContent
== mDocument
->GetContent())
125 ////////////////////////////////////////////////////////////////////////////////
127 ////////////////////////////////////////////////////////////////////////////////
130 HTMLLabelIterator(DocAccessible
* aDocument
, const Accessible
* aAccessible
,
131 LabelFilter aFilter
) :
132 mRelIter(aDocument
, aAccessible
->GetContent(), nsGkAtoms::_for
),
133 mAcc(aAccessible
), mLabelFilter(aFilter
)
138 HTMLLabelIterator::Next()
140 // Get either <label for="[id]"> element which explicitly points to given
141 // element, or <label> ancestor which implicitly point to it.
142 Accessible
* label
= nullptr;
143 while ((label
= mRelIter
.Next())) {
144 if (label
->GetContent()->Tag() == nsGkAtoms::label
)
148 // Ignore ancestor label on not widget accessible.
149 if (mLabelFilter
== eSkipAncestorLabel
|| !mAcc
->IsWidget())
152 // Go up tree to get a name of ancestor label if there is one (an ancestor
153 // <label> implicitly points to us). Don't go up farther than form or
155 Accessible
* walkUp
= mAcc
->Parent();
156 while (walkUp
&& !walkUp
->IsDoc()) {
157 nsIContent
* walkUpElm
= walkUp
->GetContent();
158 if (walkUpElm
->IsHTML()) {
159 if (walkUpElm
->Tag() == nsGkAtoms::label
&&
160 !walkUpElm
->HasAttr(kNameSpaceID_None
, nsGkAtoms::_for
)) {
161 mLabelFilter
= eSkipAncestorLabel
; // prevent infinite loop
165 if (walkUpElm
->Tag() == nsGkAtoms::form
)
169 walkUp
= walkUp
->Parent();
176 ////////////////////////////////////////////////////////////////////////////////
177 // HTMLOutputIterator
178 ////////////////////////////////////////////////////////////////////////////////
181 HTMLOutputIterator(DocAccessible
* aDocument
, nsIContent
* aElement
) :
182 mRelIter(aDocument
, aElement
, nsGkAtoms::_for
)
187 HTMLOutputIterator::Next()
189 Accessible
* output
= nullptr;
190 while ((output
= mRelIter
.Next())) {
191 if (output
->GetContent()->Tag() == nsGkAtoms::output
)
199 ////////////////////////////////////////////////////////////////////////////////
201 ////////////////////////////////////////////////////////////////////////////////
204 XULLabelIterator(DocAccessible
* aDocument
, nsIContent
* aElement
) :
205 mRelIter(aDocument
, aElement
, nsGkAtoms::control
)
210 XULLabelIterator::Next()
212 Accessible
* label
= nullptr;
213 while ((label
= mRelIter
.Next())) {
214 if (label
->GetContent()->Tag() == nsGkAtoms::label
)
222 ////////////////////////////////////////////////////////////////////////////////
223 // XULDescriptionIterator
224 ////////////////////////////////////////////////////////////////////////////////
226 XULDescriptionIterator::
227 XULDescriptionIterator(DocAccessible
* aDocument
, nsIContent
* aElement
) :
228 mRelIter(aDocument
, aElement
, nsGkAtoms::control
)
233 XULDescriptionIterator::Next()
235 Accessible
* descr
= nullptr;
236 while ((descr
= mRelIter
.Next())) {
237 if (descr
->GetContent()->Tag() == nsGkAtoms::description
)
244 ////////////////////////////////////////////////////////////////////////////////
246 ////////////////////////////////////////////////////////////////////////////////
249 IDRefsIterator(DocAccessible
* aDoc
, nsIContent
* aContent
,
250 nsIAtom
* aIDRefsAttr
) :
251 mContent(aContent
), mDoc(aDoc
), mCurrIdx(0)
253 if (mContent
->IsInDoc())
254 mContent
->GetAttr(kNameSpaceID_None
, aIDRefsAttr
, mIDs
);
257 const nsDependentSubstring
258 IDRefsIterator::NextID()
260 for (; mCurrIdx
< mIDs
.Length(); mCurrIdx
++) {
261 if (!NS_IsAsciiWhitespace(mIDs
[mCurrIdx
]))
265 if (mCurrIdx
>= mIDs
.Length())
266 return nsDependentSubstring();
268 nsAString::index_type idStartIdx
= mCurrIdx
;
269 while (++mCurrIdx
< mIDs
.Length()) {
270 if (NS_IsAsciiWhitespace(mIDs
[mCurrIdx
]))
274 return Substring(mIDs
, idStartIdx
, mCurrIdx
++ - idStartIdx
);
278 IDRefsIterator::NextElem()
281 const nsDependentSubstring id
= NextID();
285 nsIContent
* refContent
= GetElem(id
);
294 IDRefsIterator::GetElem(const nsDependentSubstring
& aID
)
296 // Get elements in DOM tree by ID attribute if this is an explicit content.
297 // In case of bound element check its anonymous subtree.
298 if (!mContent
->IsInAnonymousSubtree()) {
299 dom::Element
* refElm
= mContent
->OwnerDoc()->GetElementById(aID
);
300 if (refElm
|| !mContent
->GetXBLBinding())
304 // If content is in anonymous subtree or an element having anonymous subtree
305 // then use "anonid" attribute to get elements in anonymous subtree.
307 // Check inside the binding the element is contained in.
308 nsIContent
* bindingParent
= mContent
->GetBindingParent();
310 nsIContent
* refElm
= bindingParent
->OwnerDoc()->
311 GetAnonymousElementByAttribute(bindingParent
, nsGkAtoms::anonid
, aID
);
317 // Check inside the binding of the element.
318 if (mContent
->GetXBLBinding()) {
319 return mContent
->OwnerDoc()->
320 GetAnonymousElementByAttribute(mContent
, nsGkAtoms::anonid
, aID
);
327 IDRefsIterator::Next()
329 nsIContent
* nextElm
= NextElem();
330 return nextElm
? mDoc
->GetAccessible(nextElm
) : nullptr;
334 ////////////////////////////////////////////////////////////////////////////////
336 ////////////////////////////////////////////////////////////////////////////////
339 SingleAccIterator::Next()
341 nsRefPtr
<Accessible
> nextAcc
;
343 return (nextAcc
&& !nextAcc
->IsDefunct()) ? nextAcc
: nullptr;
347 ////////////////////////////////////////////////////////////////////////////////
349 ////////////////////////////////////////////////////////////////////////////////
355 mAnchor
= AccGroupInfo::FirstItemOf(mContainer
);
356 mContainer
= nullptr;
360 return mAnchor
? (mAnchor
= AccGroupInfo::NextItemTo(mAnchor
)) : nullptr;
364 ////////////////////////////////////////////////////////////////////////////////
365 // XULTreeItemIterator
366 ////////////////////////////////////////////////////////////////////////////////
368 XULTreeItemIterator::XULTreeItemIterator(XULTreeAccessible
* aXULTree
,
369 nsITreeView
* aTreeView
,
371 mXULTree(aXULTree
), mTreeView(aTreeView
), mRowCount(-1),
372 mContainerLevel(-1), mCurrRowIdx(aRowIdx
+ 1)
374 mTreeView
->GetRowCount(&mRowCount
);
376 mTreeView
->GetLevel(aRowIdx
, &mContainerLevel
);
380 XULTreeItemIterator::Next()
382 while (mCurrRowIdx
< mRowCount
) {
384 mTreeView
->GetLevel(mCurrRowIdx
, &level
);
386 if (level
== mContainerLevel
+ 1)
387 return mXULTree
->GetTreeItemAccessible(mCurrRowIdx
++);
389 if (level
<= mContainerLevel
) { // got level up
390 mCurrRowIdx
= mRowCount
;