Coverage Report

Created: 2018-09-25 14:53

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