Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/accessible/xul/XULListboxAccessible.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; 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/. */
5
6
#include "XULListboxAccessible.h"
7
8
#include "Accessible-inl.h"
9
#include "nsAccessibilityService.h"
10
#include "nsAccUtils.h"
11
#include "DocAccessible.h"
12
#include "Role.h"
13
#include "States.h"
14
15
#include "nsComponentManagerUtils.h"
16
#include "nsIAutoCompleteInput.h"
17
#include "nsIAutoCompletePopup.h"
18
#include "nsIDOMXULMenuListElement.h"
19
#include "nsIDOMXULMultSelectCntrlEl.h"
20
#include "nsIDOMXULSelectCntrlItemEl.h"
21
#include "nsIMutableArray.h"
22
#include "nsINodeList.h"
23
#include "nsIPersistentProperties2.h"
24
25
using namespace mozilla::a11y;
26
27
////////////////////////////////////////////////////////////////////////////////
28
// XULColumAccessible
29
////////////////////////////////////////////////////////////////////////////////
30
31
XULColumAccessible::
32
  XULColumAccessible(nsIContent* aContent, DocAccessible* aDoc) :
33
  AccessibleWrap(aContent, aDoc)
34
0
{
35
0
}
36
37
role
38
XULColumAccessible::NativeRole() const
39
0
{
40
0
  return roles::LIST;
41
0
}
42
43
uint64_t
44
XULColumAccessible::NativeState() const
45
0
{
46
0
  return states::READONLY;
47
0
}
48
49
50
////////////////////////////////////////////////////////////////////////////////
51
// XULColumnItemAccessible
52
////////////////////////////////////////////////////////////////////////////////
53
54
XULColumnItemAccessible::
55
  XULColumnItemAccessible(nsIContent* aContent, DocAccessible* aDoc) :
56
  LeafAccessible(aContent, aDoc)
57
0
{
58
0
}
59
60
role
61
XULColumnItemAccessible::NativeRole() const
62
0
{
63
0
  return roles::COLUMNHEADER;
64
0
}
65
66
uint64_t
67
XULColumnItemAccessible::NativeState() const
68
0
{
69
0
  return states::READONLY;
70
0
}
71
72
uint8_t
73
XULColumnItemAccessible::ActionCount() const
74
0
{
75
0
  return 1;
76
0
}
77
78
void
79
XULColumnItemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
80
0
{
81
0
  if (aIndex == eAction_Click)
82
0
    aName.AssignLiteral("click");
83
0
}
84
85
bool
86
XULColumnItemAccessible::DoAction(uint8_t aIndex) const
87
0
{
88
0
  if (aIndex != eAction_Click)
89
0
    return false;
90
0
91
0
  DoCommand();
92
0
  return true;
93
0
}
94
95
////////////////////////////////////////////////////////////////////////////////
96
// XULListboxAccessible
97
////////////////////////////////////////////////////////////////////////////////
98
99
XULListboxAccessible::
100
  XULListboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
101
  XULSelectControlAccessible(aContent, aDoc)
102
0
{
103
0
  nsIContent* parentContent = mContent->GetFlattenedTreeParent();
104
0
  if (parentContent) {
105
0
    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
106
0
      do_QueryInterface(parentContent);
107
0
    if (autoCompletePopupElm)
108
0
      mGenericTypes |= eAutoCompletePopup;
109
0
  }
110
0
111
0
  if (IsMulticolumn())
112
0
    mGenericTypes |= eTable;
113
0
}
114
115
////////////////////////////////////////////////////////////////////////////////
116
// XULListboxAccessible: Accessible
117
118
uint64_t
119
XULListboxAccessible::NativeState() const
120
0
{
121
0
  // As a XULListboxAccessible we can have the following states:
122
0
  //   FOCUSED, READONLY, FOCUSABLE
123
0
124
0
  // Get focus status from base class
125
0
  uint64_t states = Accessible::NativeState();
126
0
127
0
  // see if we are multiple select if so set ourselves as such
128
0
129
0
  if (mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::seltype,
130
0
                                         nsGkAtoms::multiple, eCaseMatters)) {
131
0
      states |= states::MULTISELECTABLE | states::EXTSELECTABLE;
132
0
  }
133
0
134
0
  return states;
135
0
}
136
137
/**
138
  * Our value is the label of our ( first ) selected child.
139
  */
140
void
141
XULListboxAccessible::Value(nsString& aValue) const
142
0
{
143
0
  aValue.Truncate();
144
0
145
0
  nsCOMPtr<nsIDOMXULSelectControlElement> select(do_QueryInterface(mContent));
146
0
  if (select) {
147
0
    nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
148
0
    select->GetSelectedItem(getter_AddRefs(selectedItem));
149
0
    if (selectedItem)
150
0
      selectedItem->GetLabel(aValue);
151
0
  }
152
0
}
153
154
role
155
XULListboxAccessible::NativeRole() const
156
0
{
157
0
  // A richlistbox is used with the new autocomplete URL bar, and has a parent
158
0
  // popup <panel>.
159
0
  if (mContent->GetParent() && mContent->GetParent()->IsXULElement(nsGkAtoms::panel))
160
0
    return roles::COMBOBOX_LIST;
161
0
162
0
  return IsMulticolumn() ? roles::TABLE : roles::LISTBOX;
163
0
}
164
165
////////////////////////////////////////////////////////////////////////////////
166
// XULListboxAccessible: Table
167
168
uint32_t
169
XULListboxAccessible::ColCount() const
170
0
{
171
0
  return 0;
172
0
}
173
174
uint32_t
175
XULListboxAccessible::RowCount()
176
0
{
177
0
  nsCOMPtr<nsIDOMXULSelectControlElement> element(do_QueryInterface(mContent));
178
0
179
0
  uint32_t itemCount = 0;
180
0
  if(element)
181
0
    element->GetItemCount(&itemCount);
182
0
183
0
  return itemCount;
184
0
}
185
186
Accessible*
187
XULListboxAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
188
0
{
189
0
  nsCOMPtr<nsIDOMXULSelectControlElement> control =
190
0
    do_QueryInterface(mContent);
191
0
  NS_ENSURE_TRUE(control, nullptr);
192
0
193
0
  nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
194
0
  control->GetItemAtIndex(aRowIndex, getter_AddRefs(item));
195
0
  if (!item)
196
0
    return nullptr;
197
0
198
0
  nsCOMPtr<nsIContent> itemContent(do_QueryInterface(item));
199
0
  if (!itemContent)
200
0
    return nullptr;
201
0
202
0
  Accessible* row = mDoc->GetAccessible(itemContent);
203
0
  NS_ENSURE_TRUE(row, nullptr);
204
0
205
0
  return row->GetChildAt(aColumnIndex);
206
0
}
207
208
bool
209
XULListboxAccessible::IsColSelected(uint32_t aColIdx)
210
0
{
211
0
  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
212
0
    do_QueryInterface(mContent);
213
0
  NS_ASSERTION(control,
214
0
               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
215
0
216
0
  int32_t selectedrowCount = 0;
217
0
  nsresult rv = control->GetSelectedCount(&selectedrowCount);
218
0
  NS_ENSURE_SUCCESS(rv, false);
219
0
220
0
  return selectedrowCount == static_cast<int32_t>(RowCount());
221
0
}
222
223
bool
224
XULListboxAccessible::IsRowSelected(uint32_t aRowIdx)
225
0
{
226
0
  nsCOMPtr<nsIDOMXULSelectControlElement> control =
227
0
    do_QueryInterface(mContent);
228
0
  NS_ASSERTION(control,
229
0
               "Doesn't implement nsIDOMXULSelectControlElement.");
230
0
231
0
  nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
232
0
  nsresult rv = control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
233
0
  NS_ENSURE_SUCCESS(rv, false);
234
0
235
0
  bool isSelected = false;
236
0
  item->GetSelected(&isSelected);
237
0
  return isSelected;
238
0
}
239
240
bool
241
XULListboxAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
242
0
{
243
0
  return IsRowSelected(aRowIdx);
244
0
}
245
246
uint32_t
247
XULListboxAccessible::SelectedCellCount()
248
0
{
249
0
  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
250
0
    do_QueryInterface(mContent);
251
0
  NS_ASSERTION(control,
252
0
               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
253
0
254
0
  nsCOMPtr<nsINodeList> selectedItems;
255
0
  control->GetSelectedItems(getter_AddRefs(selectedItems));
256
0
  if (!selectedItems)
257
0
    return 0;
258
0
259
0
  uint32_t selectedItemsCount = selectedItems->Length();
260
0
261
0
  return selectedItemsCount * ColCount();
262
0
}
263
264
uint32_t
265
XULListboxAccessible::SelectedColCount()
266
0
{
267
0
  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
268
0
    do_QueryInterface(mContent);
269
0
  NS_ASSERTION(control,
270
0
               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
271
0
272
0
  int32_t selectedRowCount = 0;
273
0
  nsresult rv = control->GetSelectedCount(&selectedRowCount);
274
0
  NS_ENSURE_SUCCESS(rv, 0);
275
0
276
0
  return selectedRowCount > 0 &&
277
0
   selectedRowCount == static_cast<int32_t>(RowCount()) ? ColCount() : 0;
278
0
}
279
280
uint32_t
281
XULListboxAccessible::SelectedRowCount()
282
0
{
283
0
  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
284
0
    do_QueryInterface(mContent);
285
0
  NS_ASSERTION(control,
286
0
               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
287
0
288
0
  int32_t selectedRowCount = 0;
289
0
  nsresult rv = control->GetSelectedCount(&selectedRowCount);
290
0
  NS_ENSURE_SUCCESS(rv, 0);
291
0
292
0
  return selectedRowCount >= 0 ? selectedRowCount : 0;
293
0
}
294
295
void
296
XULListboxAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
297
0
{
298
0
  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
299
0
    do_QueryInterface(mContent);
300
0
  NS_ASSERTION(control,
301
0
               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
302
0
303
0
  nsCOMPtr<nsINodeList> selectedItems;
304
0
  control->GetSelectedItems(getter_AddRefs(selectedItems));
305
0
  if (!selectedItems)
306
0
    return;
307
0
308
0
  uint32_t selectedItemsCount = selectedItems->Length();
309
0
310
0
  for (uint32_t index = 0; index < selectedItemsCount; index++) {
311
0
    nsIContent* itemContent = selectedItems->Item(index);
312
0
    Accessible* item = mDoc->GetAccessible(itemContent);
313
0
314
0
    if (item) {
315
0
      uint32_t cellCount = item->ChildCount();
316
0
      for (uint32_t cellIdx = 0; cellIdx < cellCount; cellIdx++) {
317
0
        Accessible* cell = mChildren[cellIdx];
318
0
        if (cell->Role() == roles::CELL)
319
0
          aCells->AppendElement(cell);
320
0
      }
321
0
    }
322
0
  }
323
0
}
324
325
void
326
XULListboxAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
327
0
{
328
0
  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
329
0
    do_QueryInterface(mContent);
330
0
  NS_ASSERTION(control,
331
0
               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
332
0
333
0
  nsCOMPtr<nsINodeList> selectedItems;
334
0
  control->GetSelectedItems(getter_AddRefs(selectedItems));
335
0
  if (!selectedItems)
336
0
    return;
337
0
338
0
  uint32_t selectedItemsCount = selectedItems->Length();
339
0
340
0
  uint32_t colCount = ColCount();
341
0
  aCells->SetCapacity(selectedItemsCount * colCount);
342
0
  aCells->AppendElements(selectedItemsCount * colCount);
343
0
344
0
  for (uint32_t selItemsIdx = 0, cellsIdx = 0;
345
0
       selItemsIdx < selectedItemsCount; selItemsIdx++) {
346
0
347
0
    nsIContent* itemContent = selectedItems->Item(selItemsIdx);
348
0
    nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
349
0
      do_QueryInterface(itemContent);
350
0
351
0
    if (item) {
352
0
      int32_t itemIdx = -1;
353
0
      control->GetIndexOfItem(item, &itemIdx);
354
0
      if (itemIdx >= 0)
355
0
        for (uint32_t colIdx = 0; colIdx < colCount; colIdx++, cellsIdx++)
356
0
          aCells->ElementAt(cellsIdx) = itemIdx * colCount + colIdx;
357
0
    }
358
0
  }
359
0
}
360
361
void
362
XULListboxAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
363
0
{
364
0
  uint32_t selColCount = SelectedColCount();
365
0
  aCols->SetCapacity(selColCount);
366
0
367
0
  for (uint32_t colIdx = 0; colIdx < selColCount; colIdx++)
368
0
    aCols->AppendElement(colIdx);
369
0
}
370
371
void
372
XULListboxAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
373
0
{
374
0
  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
375
0
    do_QueryInterface(mContent);
376
0
  NS_ASSERTION(control,
377
0
               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
378
0
379
0
  nsCOMPtr<nsINodeList> selectedItems;
380
0
  control->GetSelectedItems(getter_AddRefs(selectedItems));
381
0
  if (!selectedItems)
382
0
    return;
383
0
384
0
  uint32_t rowCount = selectedItems->Length();
385
0
386
0
  if (!rowCount)
387
0
    return;
388
0
389
0
  aRows->SetCapacity(rowCount);
390
0
  aRows->AppendElements(rowCount);
391
0
392
0
  for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
393
0
    nsIContent* itemContent = selectedItems->Item(rowIdx);
394
0
    nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
395
0
      do_QueryInterface(itemContent);
396
0
397
0
    if (item) {
398
0
      int32_t itemIdx = -1;
399
0
      control->GetIndexOfItem(item, &itemIdx);
400
0
      if (itemIdx >= 0)
401
0
        aRows->ElementAt(rowIdx) = itemIdx;
402
0
    }
403
0
  }
404
0
}
405
406
void
407
XULListboxAccessible::SelectRow(uint32_t aRowIdx)
408
0
{
409
0
  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
410
0
    do_QueryInterface(mContent);
411
0
  NS_ASSERTION(control,
412
0
               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
413
0
414
0
  nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
415
0
  control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
416
0
  control->SelectItem(item);
417
0
}
418
419
void
420
XULListboxAccessible::UnselectRow(uint32_t aRowIdx)
421
0
{
422
0
  nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
423
0
    do_QueryInterface(mContent);
424
0
  NS_ASSERTION(control,
425
0
               "Doesn't implement nsIDOMXULMultiSelectControlElement.");
426
0
427
0
  nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
428
0
  control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
429
0
  control->RemoveItemFromSelection(item);
430
0
}
431
432
////////////////////////////////////////////////////////////////////////////////
433
// XULListboxAccessible: Widgets
434
435
bool
436
XULListboxAccessible::IsWidget() const
437
0
{
438
0
  return true;
439
0
}
440
441
bool
442
XULListboxAccessible::IsActiveWidget() const
443
0
{
444
0
  if (IsAutoCompletePopup()) {
445
0
    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
446
0
      do_QueryInterface(mContent->GetParent());
447
0
448
0
    if (autoCompletePopupElm) {
449
0
      bool isOpen = false;
450
0
      autoCompletePopupElm->GetPopupOpen(&isOpen);
451
0
      return isOpen;
452
0
    }
453
0
  }
454
0
  return FocusMgr()->HasDOMFocus(mContent);
455
0
}
456
457
bool
458
XULListboxAccessible::AreItemsOperable() const
459
0
{
460
0
  if (IsAutoCompletePopup()) {
461
0
    nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
462
0
      do_QueryInterface(mContent->GetParent());
463
0
464
0
    if (autoCompletePopupElm) {
465
0
      bool isOpen = false;
466
0
      autoCompletePopupElm->GetPopupOpen(&isOpen);
467
0
      return isOpen;
468
0
    }
469
0
  }
470
0
  return true;
471
0
}
472
473
Accessible*
474
XULListboxAccessible::ContainerWidget() const
475
0
{
476
0
  if (IsAutoCompletePopup()) {
477
0
    // This works for XUL autocompletes. It doesn't work for HTML forms
478
0
    // autocomplete because of potential crossprocess calls (when autocomplete
479
0
    // lives in content process while popup lives in chrome process). If that's
480
0
    // a problem then rethink Widgets interface.
481
0
    nsCOMPtr<nsIDOMXULMenuListElement> menuListElm =
482
0
      do_QueryInterface(mContent->GetParent());
483
0
    if (menuListElm) {
484
0
      RefPtr<mozilla::dom::Element> inputElm;
485
0
      menuListElm->GetInputField(getter_AddRefs(inputElm));
486
0
      if (inputElm) {
487
0
          Accessible* input = mDoc->GetAccessible(inputElm);
488
0
          return input ? input->ContainerWidget() : nullptr;
489
0
      }
490
0
    }
491
0
  }
492
0
  return nullptr;
493
0
}
494
495
////////////////////////////////////////////////////////////////////////////////
496
// XULListitemAccessible
497
////////////////////////////////////////////////////////////////////////////////
498
499
XULListitemAccessible::
500
  XULListitemAccessible(nsIContent* aContent, DocAccessible* aDoc) :
501
  XULMenuitemAccessible(aContent, aDoc)
502
0
{
503
0
  mIsCheckbox = mContent->AsElement()->AttrValueIs(kNameSpaceID_None,
504
0
                                                   nsGkAtoms::type,
505
0
                                                   nsGkAtoms::checkbox,
506
0
                                                   eCaseMatters);
507
0
  mType = eXULListItemType;
508
0
509
0
  // Walk XBL anonymous children for list items. Overrides the flag value from
510
0
  // base XULMenuitemAccessible class.
511
0
  mStateFlags &= ~eNoXBLKids;
512
0
}
513
514
XULListitemAccessible::~XULListitemAccessible()
515
0
{
516
0
}
517
518
Accessible*
519
XULListitemAccessible::GetListAccessible() const
520
0
{
521
0
  if (IsDefunct())
522
0
    return nullptr;
523
0
524
0
  nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
525
0
    do_QueryInterface(mContent);
526
0
  if (!listItem)
527
0
    return nullptr;
528
0
529
0
  nsCOMPtr<nsIDOMXULSelectControlElement> list;
530
0
  listItem->GetControl(getter_AddRefs(list));
531
0
532
0
  nsCOMPtr<nsIContent> listContent(do_QueryInterface(list));
533
0
  if (!listContent)
534
0
    return nullptr;
535
0
536
0
  return mDoc->GetAccessible(listContent);
537
0
}
538
539
////////////////////////////////////////////////////////////////////////////////
540
// XULListitemAccessible Accessible
541
542
void
543
XULListitemAccessible::Description(nsString& aDesc)
544
0
{
545
0
  AccessibleWrap::Description(aDesc);
546
0
}
547
548
////////////////////////////////////////////////////////////////////////////////
549
// XULListitemAccessible: Accessible
550
551
/**
552
 * Get the name from GetXULName.
553
 */
554
ENameValueFlag
555
XULListitemAccessible::NativeName(nsString& aName) const
556
0
{
557
0
  return Accessible::NativeName(aName);
558
0
}
559
560
role
561
XULListitemAccessible::NativeRole() const
562
0
{
563
0
  Accessible* list = GetListAccessible();
564
0
  if (!list) {
565
0
    NS_ERROR("No list accessible for listitem accessible!");
566
0
    return roles::NOTHING;
567
0
  }
568
0
569
0
  if (list->Role() == roles::TABLE)
570
0
    return roles::ROW;
571
0
572
0
  if (mIsCheckbox)
573
0
    return roles::CHECK_RICH_OPTION;
574
0
575
0
  if (mParent && mParent->Role() == roles::COMBOBOX_LIST)
576
0
    return roles::COMBOBOX_OPTION;
577
0
578
0
  return roles::RICH_OPTION;
579
0
}
580
581
uint64_t
582
XULListitemAccessible::NativeState() const
583
0
{
584
0
  if (mIsCheckbox)
585
0
    return XULMenuitemAccessible::NativeState();
586
0
587
0
  uint64_t states = NativeInteractiveState();
588
0
589
0
  nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
590
0
    do_QueryInterface(mContent);
591
0
592
0
  if (listItem) {
593
0
    bool isSelected;
594
0
    listItem->GetSelected(&isSelected);
595
0
    if (isSelected)
596
0
      states |= states::SELECTED;
597
0
598
0
    if (FocusMgr()->IsFocused(this))
599
0
      states |= states::FOCUSED;
600
0
  }
601
0
602
0
  return states;
603
0
}
604
605
uint64_t
606
XULListitemAccessible::NativeInteractiveState() const
607
0
{
608
0
  return NativelyUnavailable() || (mParent && mParent->NativelyUnavailable()) ?
609
0
    states::UNAVAILABLE : states::FOCUSABLE | states::SELECTABLE;
610
0
}
611
612
void
613
XULListitemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
614
0
{
615
0
  if (aIndex == eAction_Click && mIsCheckbox) {
616
0
    uint64_t states = NativeState();
617
0
    if (states & states::CHECKED)
618
0
      aName.AssignLiteral("uncheck");
619
0
    else
620
0
      aName.AssignLiteral("check");
621
0
  }
622
0
}
623
624
////////////////////////////////////////////////////////////////////////////////
625
// XULListitemAccessible: Widgets
626
627
Accessible*
628
XULListitemAccessible::ContainerWidget() const
629
0
{
630
0
  return Parent();
631
0
}