Line data Source code
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/. */
4 :
5 : #include "AccIterator.h"
6 :
7 : #include "AccGroupInfo.h"
8 : #ifdef MOZ_XUL
9 : #include "XULTreeAccessible.h"
10 : #endif
11 :
12 : #include "mozilla/dom/HTMLLabelElement.h"
13 :
14 : using namespace mozilla;
15 : using namespace mozilla::a11y;
16 :
17 : ////////////////////////////////////////////////////////////////////////////////
18 : // AccIterator
19 : ////////////////////////////////////////////////////////////////////////////////
20 :
21 0 : AccIterator::AccIterator(Accessible* aAccessible,
22 0 : filters::FilterFuncPtr aFilterFunc) :
23 0 : mFilterFunc(aFilterFunc)
24 : {
25 0 : mState = new IteratorState(aAccessible);
26 0 : }
27 :
28 0 : AccIterator::~AccIterator()
29 : {
30 0 : while (mState) {
31 0 : IteratorState *tmp = mState;
32 0 : mState = tmp->mParentState;
33 : delete tmp;
34 : }
35 0 : }
36 :
37 : Accessible*
38 0 : AccIterator::Next()
39 : {
40 0 : while (mState) {
41 0 : Accessible* child = mState->mParent->GetChildAt(mState->mIndex++);
42 0 : if (!child) {
43 0 : IteratorState* tmp = mState;
44 0 : mState = mState->mParentState;
45 : delete tmp;
46 :
47 0 : continue;
48 : }
49 :
50 0 : uint32_t result = mFilterFunc(child);
51 0 : if (result & filters::eMatch)
52 0 : return child;
53 :
54 0 : if (!(result & filters::eSkipSubtree)) {
55 0 : IteratorState* childState = new IteratorState(child, mState);
56 0 : mState = childState;
57 : }
58 : }
59 :
60 0 : return nullptr;
61 : }
62 :
63 : ////////////////////////////////////////////////////////////////////////////////
64 : // nsAccIterator::IteratorState
65 :
66 0 : AccIterator::IteratorState::IteratorState(Accessible* aParent,
67 0 : IteratorState *mParentState) :
68 0 : mParent(aParent), mIndex(0), mParentState(mParentState)
69 : {
70 0 : }
71 :
72 :
73 : ////////////////////////////////////////////////////////////////////////////////
74 : // RelatedAccIterator
75 : ////////////////////////////////////////////////////////////////////////////////
76 :
77 0 : RelatedAccIterator::
78 : RelatedAccIterator(DocAccessible* aDocument, nsIContent* aDependentContent,
79 0 : nsIAtom* aRelAttr) :
80 : mDocument(aDocument), mRelAttr(aRelAttr), mProviders(nullptr),
81 0 : mBindingParent(nullptr), mIndex(0)
82 : {
83 0 : mBindingParent = aDependentContent->GetBindingParent();
84 0 : nsIAtom* IDAttr = mBindingParent ?
85 0 : nsGkAtoms::anonid : nsGkAtoms::id;
86 :
87 0 : nsAutoString id;
88 0 : if (aDependentContent->GetAttr(kNameSpaceID_None, IDAttr, id))
89 0 : mProviders = mDocument->mDependentIDsHash.Get(id);
90 0 : }
91 :
92 : Accessible*
93 0 : RelatedAccIterator::Next()
94 : {
95 0 : if (!mProviders)
96 0 : return nullptr;
97 :
98 0 : while (mIndex < mProviders->Length()) {
99 0 : DocAccessible::AttrRelProvider* provider = (*mProviders)[mIndex++];
100 :
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 0 : if (provider->mRelAttr == mRelAttr) {
104 0 : nsIContent* bindingParent = provider->mContent->GetBindingParent();
105 0 : bool inScope = mBindingParent == bindingParent ||
106 0 : mBindingParent == provider->mContent;
107 :
108 0 : if (inScope) {
109 0 : Accessible* related = mDocument->GetAccessible(provider->mContent);
110 0 : if (related)
111 0 : return related;
112 :
113 : // If the document content is pointed by relation then return the document
114 : // itself.
115 0 : if (provider->mContent == mDocument->GetContent())
116 0 : return mDocument;
117 : }
118 : }
119 : }
120 :
121 0 : return nullptr;
122 : }
123 :
124 :
125 : ////////////////////////////////////////////////////////////////////////////////
126 : // HTMLLabelIterator
127 : ////////////////////////////////////////////////////////////////////////////////
128 :
129 0 : HTMLLabelIterator::
130 : HTMLLabelIterator(DocAccessible* aDocument, const Accessible* aAccessible,
131 0 : LabelFilter aFilter) :
132 : mRelIter(aDocument, aAccessible->GetContent(), nsGkAtoms::_for),
133 0 : mAcc(aAccessible), mLabelFilter(aFilter)
134 : {
135 0 : }
136 :
137 : bool
138 0 : HTMLLabelIterator::IsLabel(Accessible* aLabel)
139 : {
140 : dom::HTMLLabelElement* labelEl =
141 0 : dom::HTMLLabelElement::FromContent(aLabel->GetContent());
142 0 : return labelEl && labelEl->GetControl() == mAcc->GetContent();
143 : }
144 :
145 : Accessible*
146 0 : HTMLLabelIterator::Next()
147 : {
148 : // Get either <label for="[id]"> element which explicitly points to given
149 : // element, or <label> ancestor which implicitly point to it.
150 0 : Accessible* label = nullptr;
151 0 : while ((label = mRelIter.Next())) {
152 0 : if (IsLabel(label)) {
153 0 : return label;
154 : }
155 : }
156 :
157 : // Ignore ancestor label on not widget accessible.
158 0 : if (mLabelFilter == eSkipAncestorLabel || !mAcc->IsWidget())
159 0 : return nullptr;
160 :
161 : // Go up tree to get a name of ancestor label if there is one (an ancestor
162 : // <label> implicitly points to us). Don't go up farther than form or
163 : // document.
164 0 : Accessible* walkUp = mAcc->Parent();
165 0 : while (walkUp && !walkUp->IsDoc()) {
166 0 : nsIContent* walkUpEl = walkUp->GetContent();
167 0 : if (IsLabel(walkUp) &&
168 0 : !walkUpEl->HasAttr(kNameSpaceID_None, nsGkAtoms::_for)) {
169 0 : mLabelFilter = eSkipAncestorLabel; // prevent infinite loop
170 0 : return walkUp;
171 : }
172 :
173 0 : if (walkUpEl->IsHTMLElement(nsGkAtoms::form))
174 0 : break;
175 :
176 0 : walkUp = walkUp->Parent();
177 : }
178 :
179 0 : return nullptr;
180 : }
181 :
182 :
183 : ////////////////////////////////////////////////////////////////////////////////
184 : // HTMLOutputIterator
185 : ////////////////////////////////////////////////////////////////////////////////
186 :
187 0 : HTMLOutputIterator::
188 0 : HTMLOutputIterator(DocAccessible* aDocument, nsIContent* aElement) :
189 0 : mRelIter(aDocument, aElement, nsGkAtoms::_for)
190 : {
191 0 : }
192 :
193 : Accessible*
194 0 : HTMLOutputIterator::Next()
195 : {
196 0 : Accessible* output = nullptr;
197 0 : while ((output = mRelIter.Next())) {
198 0 : if (output->GetContent()->IsHTMLElement(nsGkAtoms::output))
199 0 : return output;
200 : }
201 :
202 0 : return nullptr;
203 : }
204 :
205 :
206 : ////////////////////////////////////////////////////////////////////////////////
207 : // XULLabelIterator
208 : ////////////////////////////////////////////////////////////////////////////////
209 :
210 0 : XULLabelIterator::
211 0 : XULLabelIterator(DocAccessible* aDocument, nsIContent* aElement) :
212 0 : mRelIter(aDocument, aElement, nsGkAtoms::control)
213 : {
214 0 : }
215 :
216 : Accessible*
217 0 : XULLabelIterator::Next()
218 : {
219 0 : Accessible* label = nullptr;
220 0 : while ((label = mRelIter.Next())) {
221 0 : if (label->GetContent()->IsXULElement(nsGkAtoms::label))
222 0 : return label;
223 : }
224 :
225 0 : return nullptr;
226 : }
227 :
228 :
229 : ////////////////////////////////////////////////////////////////////////////////
230 : // XULDescriptionIterator
231 : ////////////////////////////////////////////////////////////////////////////////
232 :
233 0 : XULDescriptionIterator::
234 0 : XULDescriptionIterator(DocAccessible* aDocument, nsIContent* aElement) :
235 0 : mRelIter(aDocument, aElement, nsGkAtoms::control)
236 : {
237 0 : }
238 :
239 : Accessible*
240 0 : XULDescriptionIterator::Next()
241 : {
242 0 : Accessible* descr = nullptr;
243 0 : while ((descr = mRelIter.Next())) {
244 0 : if (descr->GetContent()->IsXULElement(nsGkAtoms::description))
245 0 : return descr;
246 : }
247 :
248 0 : return nullptr;
249 : }
250 :
251 : ////////////////////////////////////////////////////////////////////////////////
252 : // IDRefsIterator
253 : ////////////////////////////////////////////////////////////////////////////////
254 :
255 0 : IDRefsIterator::
256 : IDRefsIterator(DocAccessible* aDoc, nsIContent* aContent,
257 0 : nsIAtom* aIDRefsAttr) :
258 0 : mContent(aContent), mDoc(aDoc), mCurrIdx(0)
259 : {
260 0 : if (mContent->IsInUncomposedDoc())
261 0 : mContent->GetAttr(kNameSpaceID_None, aIDRefsAttr, mIDs);
262 0 : }
263 :
264 : const nsDependentSubstring
265 0 : IDRefsIterator::NextID()
266 : {
267 0 : for (; mCurrIdx < mIDs.Length(); mCurrIdx++) {
268 0 : if (!NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
269 0 : break;
270 : }
271 :
272 0 : if (mCurrIdx >= mIDs.Length())
273 0 : return nsDependentSubstring();
274 :
275 0 : nsAString::index_type idStartIdx = mCurrIdx;
276 0 : while (++mCurrIdx < mIDs.Length()) {
277 0 : if (NS_IsAsciiWhitespace(mIDs[mCurrIdx]))
278 0 : break;
279 : }
280 :
281 0 : return Substring(mIDs, idStartIdx, mCurrIdx++ - idStartIdx);
282 : }
283 :
284 : nsIContent*
285 0 : IDRefsIterator::NextElem()
286 : {
287 : while (true) {
288 0 : const nsDependentSubstring id = NextID();
289 0 : if (id.IsEmpty())
290 0 : break;
291 :
292 0 : nsIContent* refContent = GetElem(id);
293 0 : if (refContent)
294 0 : return refContent;
295 0 : }
296 :
297 0 : return nullptr;
298 : }
299 :
300 : nsIContent*
301 0 : IDRefsIterator::GetElem(const nsDependentSubstring& aID)
302 : {
303 : // Get elements in DOM tree by ID attribute if this is an explicit content.
304 : // In case of bound element check its anonymous subtree.
305 0 : if (!mContent->IsInAnonymousSubtree()) {
306 0 : dom::Element* refElm = mContent->OwnerDoc()->GetElementById(aID);
307 0 : if (refElm || !mContent->GetXBLBinding())
308 0 : return refElm;
309 : }
310 :
311 : // If content is in anonymous subtree or an element having anonymous subtree
312 : // then use "anonid" attribute to get elements in anonymous subtree.
313 :
314 : // Check inside the binding the element is contained in.
315 0 : nsIContent* bindingParent = mContent->GetBindingParent();
316 0 : if (bindingParent) {
317 0 : nsIContent* refElm = bindingParent->OwnerDoc()->
318 0 : GetAnonymousElementByAttribute(bindingParent, nsGkAtoms::anonid, aID);
319 :
320 0 : if (refElm)
321 0 : return refElm;
322 : }
323 :
324 : // Check inside the binding of the element.
325 0 : if (mContent->GetXBLBinding()) {
326 0 : return mContent->OwnerDoc()->
327 0 : GetAnonymousElementByAttribute(mContent, nsGkAtoms::anonid, aID);
328 : }
329 :
330 0 : return nullptr;
331 : }
332 :
333 : Accessible*
334 0 : IDRefsIterator::Next()
335 : {
336 0 : nsIContent* nextEl = nullptr;
337 0 : while ((nextEl = NextElem())) {
338 0 : Accessible* acc = mDoc->GetAccessible(nextEl);
339 0 : if (acc) {
340 0 : return acc;
341 : }
342 : }
343 0 : return nullptr;
344 : }
345 :
346 :
347 : ////////////////////////////////////////////////////////////////////////////////
348 : // SingleAccIterator
349 : ////////////////////////////////////////////////////////////////////////////////
350 :
351 : Accessible*
352 0 : SingleAccIterator::Next()
353 : {
354 0 : RefPtr<Accessible> nextAcc;
355 0 : mAcc.swap(nextAcc);
356 0 : if (!nextAcc || nextAcc->IsDefunct()) {
357 0 : return nullptr;
358 : }
359 0 : return nextAcc;
360 : }
361 :
362 :
363 : ////////////////////////////////////////////////////////////////////////////////
364 : // ItemIterator
365 : ////////////////////////////////////////////////////////////////////////////////
366 :
367 : Accessible*
368 0 : ItemIterator::Next()
369 : {
370 0 : if (mContainer) {
371 0 : mAnchor = AccGroupInfo::FirstItemOf(mContainer);
372 0 : mContainer = nullptr;
373 0 : return mAnchor;
374 : }
375 :
376 0 : return mAnchor ? (mAnchor = AccGroupInfo::NextItemTo(mAnchor)) : nullptr;
377 : }
378 :
379 :
380 : ////////////////////////////////////////////////////////////////////////////////
381 : // XULTreeItemIterator
382 : ////////////////////////////////////////////////////////////////////////////////
383 :
384 0 : XULTreeItemIterator::XULTreeItemIterator(XULTreeAccessible* aXULTree,
385 : nsITreeView* aTreeView,
386 0 : int32_t aRowIdx) :
387 : mXULTree(aXULTree), mTreeView(aTreeView), mRowCount(-1),
388 0 : mContainerLevel(-1), mCurrRowIdx(aRowIdx + 1)
389 : {
390 0 : mTreeView->GetRowCount(&mRowCount);
391 0 : if (aRowIdx != -1)
392 0 : mTreeView->GetLevel(aRowIdx, &mContainerLevel);
393 0 : }
394 :
395 : Accessible*
396 0 : XULTreeItemIterator::Next()
397 : {
398 0 : while (mCurrRowIdx < mRowCount) {
399 0 : int32_t level = 0;
400 0 : mTreeView->GetLevel(mCurrRowIdx, &level);
401 :
402 0 : if (level == mContainerLevel + 1)
403 0 : return mXULTree->GetTreeItemAccessible(mCurrRowIdx++);
404 :
405 0 : if (level <= mContainerLevel) { // got level up
406 0 : mCurrRowIdx = mRowCount;
407 0 : break;
408 : }
409 :
410 0 : mCurrRowIdx++;
411 : }
412 :
413 0 : return nullptr;
414 : }
|