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 "nsIDOMNodeList.h"
21 #include "nsIDOMXULPopupElement.h"
22 #include "nsIDOMXULSelectCntrlItemEl.h"
23 #include "nsIMutableArray.h"
24 #include "nsIPersistentProperties2.h"
25
26 using namespace mozilla::a11y;
27
28 ////////////////////////////////////////////////////////////////////////////////
29 // XULColumAccessible
30 ////////////////////////////////////////////////////////////////////////////////
31
32 XULColumAccessible::
XULColumAccessible(nsIContent * aContent,DocAccessible * aDoc)33 XULColumAccessible(nsIContent* aContent, DocAccessible* aDoc) :
34 AccessibleWrap(aContent, aDoc)
35 {
36 }
37
38 role
NativeRole()39 XULColumAccessible::NativeRole()
40 {
41 return roles::LIST;
42 }
43
44 uint64_t
NativeState()45 XULColumAccessible::NativeState()
46 {
47 return states::READONLY;
48 }
49
50
51 ////////////////////////////////////////////////////////////////////////////////
52 // XULColumnItemAccessible
53 ////////////////////////////////////////////////////////////////////////////////
54
55 XULColumnItemAccessible::
XULColumnItemAccessible(nsIContent * aContent,DocAccessible * aDoc)56 XULColumnItemAccessible(nsIContent* aContent, DocAccessible* aDoc) :
57 LeafAccessible(aContent, aDoc)
58 {
59 }
60
61 role
NativeRole()62 XULColumnItemAccessible::NativeRole()
63 {
64 return roles::COLUMNHEADER;
65 }
66
67 uint64_t
NativeState()68 XULColumnItemAccessible::NativeState()
69 {
70 return states::READONLY;
71 }
72
73 uint8_t
ActionCount()74 XULColumnItemAccessible::ActionCount()
75 {
76 return 1;
77 }
78
79 void
ActionNameAt(uint8_t aIndex,nsAString & aName)80 XULColumnItemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
81 {
82 if (aIndex == eAction_Click)
83 aName.AssignLiteral("click");
84 }
85
86 bool
DoAction(uint8_t aIndex)87 XULColumnItemAccessible::DoAction(uint8_t aIndex)
88 {
89 if (aIndex != eAction_Click)
90 return false;
91
92 DoCommand();
93 return true;
94 }
95
96 ////////////////////////////////////////////////////////////////////////////////
97 // XULListboxAccessible
98 ////////////////////////////////////////////////////////////////////////////////
99
100 XULListboxAccessible::
XULListboxAccessible(nsIContent * aContent,DocAccessible * aDoc)101 XULListboxAccessible(nsIContent* aContent, DocAccessible* aDoc) :
102 XULSelectControlAccessible(aContent, aDoc)
103 {
104 nsIContent* parentContent = mContent->GetFlattenedTreeParent();
105 if (parentContent) {
106 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
107 do_QueryInterface(parentContent);
108 if (autoCompletePopupElm)
109 mGenericTypes |= eAutoCompletePopup;
110 }
111
112 if (IsMulticolumn())
113 mGenericTypes |= eTable;
114 }
115
116 ////////////////////////////////////////////////////////////////////////////////
117 // XULListboxAccessible: Accessible
118
119 uint64_t
NativeState()120 XULListboxAccessible::NativeState()
121 {
122 // As a XULListboxAccessible we can have the following states:
123 // FOCUSED, READONLY, FOCUSABLE
124
125 // Get focus status from base class
126 uint64_t states = Accessible::NativeState();
127
128 // see if we are multiple select if so set ourselves as such
129
130 if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::seltype,
131 nsGkAtoms::multiple, eCaseMatters)) {
132 states |= states::MULTISELECTABLE | states::EXTSELECTABLE;
133 }
134
135 return states;
136 }
137
138 /**
139 * Our value is the label of our ( first ) selected child.
140 */
141 void
Value(nsString & aValue)142 XULListboxAccessible::Value(nsString& aValue)
143 {
144 aValue.Truncate();
145
146 nsCOMPtr<nsIDOMXULSelectControlElement> select(do_QueryInterface(mContent));
147 if (select) {
148 nsCOMPtr<nsIDOMXULSelectControlItemElement> selectedItem;
149 select->GetSelectedItem(getter_AddRefs(selectedItem));
150 if (selectedItem)
151 selectedItem->GetLabel(aValue);
152 }
153 }
154
155 role
NativeRole()156 XULListboxAccessible::NativeRole()
157 {
158 // A richlistbox is used with the new autocomplete URL bar, and has a parent
159 // popup <panel>.
160 nsCOMPtr<nsIDOMXULPopupElement> xulPopup =
161 do_QueryInterface(mContent->GetParent());
162 if (xulPopup)
163 return roles::COMBOBOX_LIST;
164
165 return IsMulticolumn() ? roles::TABLE : roles::LISTBOX;
166 }
167
168 ////////////////////////////////////////////////////////////////////////////////
169 // XULListboxAccessible: Table
170
171 uint32_t
ColCount()172 XULListboxAccessible::ColCount()
173 {
174 nsIContent* headContent = nullptr;
175 for (nsIContent* childContent = mContent->GetFirstChild(); childContent;
176 childContent = childContent->GetNextSibling()) {
177 if (childContent->NodeInfo()->Equals(nsGkAtoms::listcols,
178 kNameSpaceID_XUL)) {
179 headContent = childContent;
180 }
181 }
182 if (!headContent)
183 return 0;
184
185 uint32_t columnCount = 0;
186 for (nsIContent* childContent = headContent->GetFirstChild(); childContent;
187 childContent = childContent->GetNextSibling()) {
188 if (childContent->NodeInfo()->Equals(nsGkAtoms::listcol,
189 kNameSpaceID_XUL)) {
190 columnCount++;
191 }
192 }
193
194 return columnCount;
195 }
196
197 uint32_t
RowCount()198 XULListboxAccessible::RowCount()
199 {
200 nsCOMPtr<nsIDOMXULSelectControlElement> element(do_QueryInterface(mContent));
201
202 uint32_t itemCount = 0;
203 if(element)
204 element->GetItemCount(&itemCount);
205
206 return itemCount;
207 }
208
209 Accessible*
CellAt(uint32_t aRowIndex,uint32_t aColumnIndex)210 XULListboxAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex)
211 {
212 nsCOMPtr<nsIDOMXULSelectControlElement> control =
213 do_QueryInterface(mContent);
214 NS_ENSURE_TRUE(control, nullptr);
215
216 nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
217 control->GetItemAtIndex(aRowIndex, getter_AddRefs(item));
218 if (!item)
219 return nullptr;
220
221 nsCOMPtr<nsIContent> itemContent(do_QueryInterface(item));
222 if (!itemContent)
223 return nullptr;
224
225 Accessible* row = mDoc->GetAccessible(itemContent);
226 NS_ENSURE_TRUE(row, nullptr);
227
228 return row->GetChildAt(aColumnIndex);
229 }
230
231 bool
IsColSelected(uint32_t aColIdx)232 XULListboxAccessible::IsColSelected(uint32_t aColIdx)
233 {
234 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
235 do_QueryInterface(mContent);
236 NS_ASSERTION(control,
237 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
238
239 int32_t selectedrowCount = 0;
240 nsresult rv = control->GetSelectedCount(&selectedrowCount);
241 NS_ENSURE_SUCCESS(rv, false);
242
243 return selectedrowCount == static_cast<int32_t>(RowCount());
244 }
245
246 bool
IsRowSelected(uint32_t aRowIdx)247 XULListboxAccessible::IsRowSelected(uint32_t aRowIdx)
248 {
249 nsCOMPtr<nsIDOMXULSelectControlElement> control =
250 do_QueryInterface(mContent);
251 NS_ASSERTION(control,
252 "Doesn't implement nsIDOMXULSelectControlElement.");
253
254 nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
255 nsresult rv = control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
256 NS_ENSURE_SUCCESS(rv, false);
257
258 bool isSelected = false;
259 item->GetSelected(&isSelected);
260 return isSelected;
261 }
262
263 bool
IsCellSelected(uint32_t aRowIdx,uint32_t aColIdx)264 XULListboxAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx)
265 {
266 return IsRowSelected(aRowIdx);
267 }
268
269 uint32_t
SelectedCellCount()270 XULListboxAccessible::SelectedCellCount()
271 {
272 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
273 do_QueryInterface(mContent);
274 NS_ASSERTION(control,
275 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
276
277 nsCOMPtr<nsIDOMNodeList> selectedItems;
278 control->GetSelectedItems(getter_AddRefs(selectedItems));
279 if (!selectedItems)
280 return 0;
281
282 uint32_t selectedItemsCount = 0;
283 nsresult rv = selectedItems->GetLength(&selectedItemsCount);
284 NS_ENSURE_SUCCESS(rv, 0);
285
286 return selectedItemsCount * ColCount();
287 }
288
289 uint32_t
SelectedColCount()290 XULListboxAccessible::SelectedColCount()
291 {
292 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
293 do_QueryInterface(mContent);
294 NS_ASSERTION(control,
295 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
296
297 int32_t selectedRowCount = 0;
298 nsresult rv = control->GetSelectedCount(&selectedRowCount);
299 NS_ENSURE_SUCCESS(rv, 0);
300
301 return selectedRowCount > 0 &&
302 selectedRowCount == static_cast<int32_t>(RowCount()) ? ColCount() : 0;
303 }
304
305 uint32_t
SelectedRowCount()306 XULListboxAccessible::SelectedRowCount()
307 {
308 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
309 do_QueryInterface(mContent);
310 NS_ASSERTION(control,
311 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
312
313 int32_t selectedRowCount = 0;
314 nsresult rv = control->GetSelectedCount(&selectedRowCount);
315 NS_ENSURE_SUCCESS(rv, 0);
316
317 return selectedRowCount >= 0 ? selectedRowCount : 0;
318 }
319
320 void
SelectedCells(nsTArray<Accessible * > * aCells)321 XULListboxAccessible::SelectedCells(nsTArray<Accessible*>* aCells)
322 {
323 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
324 do_QueryInterface(mContent);
325 NS_ASSERTION(control,
326 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
327
328 nsCOMPtr<nsIDOMNodeList> selectedItems;
329 control->GetSelectedItems(getter_AddRefs(selectedItems));
330 if (!selectedItems)
331 return;
332
333 uint32_t selectedItemsCount = 0;
334 DebugOnly<nsresult> rv = selectedItems->GetLength(&selectedItemsCount);
335 NS_ASSERTION(NS_SUCCEEDED(rv), "GetLength() Shouldn't fail!");
336
337 for (uint32_t index = 0; index < selectedItemsCount; index++) {
338 nsCOMPtr<nsIDOMNode> itemNode;
339 selectedItems->Item(index, getter_AddRefs(itemNode));
340 nsCOMPtr<nsIContent> itemContent(do_QueryInterface(itemNode));
341 Accessible* item = mDoc->GetAccessible(itemContent);
342
343 if (item) {
344 uint32_t cellCount = item->ChildCount();
345 for (uint32_t cellIdx = 0; cellIdx < cellCount; cellIdx++) {
346 Accessible* cell = mChildren[cellIdx];
347 if (cell->Role() == roles::CELL)
348 aCells->AppendElement(cell);
349 }
350 }
351 }
352 }
353
354 void
SelectedCellIndices(nsTArray<uint32_t> * aCells)355 XULListboxAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells)
356 {
357 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
358 do_QueryInterface(mContent);
359 NS_ASSERTION(control,
360 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
361
362 nsCOMPtr<nsIDOMNodeList> selectedItems;
363 control->GetSelectedItems(getter_AddRefs(selectedItems));
364 if (!selectedItems)
365 return;
366
367 uint32_t selectedItemsCount = 0;
368 DebugOnly<nsresult> rv = selectedItems->GetLength(&selectedItemsCount);
369 NS_ASSERTION(NS_SUCCEEDED(rv), "GetLength() Shouldn't fail!");
370
371 uint32_t colCount = ColCount();
372 aCells->SetCapacity(selectedItemsCount * colCount);
373 aCells->AppendElements(selectedItemsCount * colCount);
374
375 for (uint32_t selItemsIdx = 0, cellsIdx = 0;
376 selItemsIdx < selectedItemsCount; selItemsIdx++) {
377
378 nsCOMPtr<nsIDOMNode> itemNode;
379 selectedItems->Item(selItemsIdx, getter_AddRefs(itemNode));
380 nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
381 do_QueryInterface(itemNode);
382
383 if (item) {
384 int32_t itemIdx = -1;
385 control->GetIndexOfItem(item, &itemIdx);
386 if (itemIdx >= 0)
387 for (uint32_t colIdx = 0; colIdx < colCount; colIdx++, cellsIdx++)
388 aCells->ElementAt(cellsIdx) = itemIdx * colCount + colIdx;
389 }
390 }
391 }
392
393 void
SelectedColIndices(nsTArray<uint32_t> * aCols)394 XULListboxAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols)
395 {
396 uint32_t selColCount = SelectedColCount();
397 aCols->SetCapacity(selColCount);
398
399 for (uint32_t colIdx = 0; colIdx < selColCount; colIdx++)
400 aCols->AppendElement(colIdx);
401 }
402
403 void
SelectedRowIndices(nsTArray<uint32_t> * aRows)404 XULListboxAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows)
405 {
406 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
407 do_QueryInterface(mContent);
408 NS_ASSERTION(control,
409 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
410
411 nsCOMPtr<nsIDOMNodeList> selectedItems;
412 control->GetSelectedItems(getter_AddRefs(selectedItems));
413 if (!selectedItems)
414 return;
415
416 uint32_t rowCount = 0;
417 DebugOnly<nsresult> rv = selectedItems->GetLength(&rowCount);
418 NS_ASSERTION(NS_SUCCEEDED(rv), "GetLength() Shouldn't fail!");
419
420 if (!rowCount)
421 return;
422
423 aRows->SetCapacity(rowCount);
424 aRows->AppendElements(rowCount);
425
426 for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
427 nsCOMPtr<nsIDOMNode> itemNode;
428 selectedItems->Item(rowIdx, getter_AddRefs(itemNode));
429 nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
430 do_QueryInterface(itemNode);
431
432 if (item) {
433 int32_t itemIdx = -1;
434 control->GetIndexOfItem(item, &itemIdx);
435 if (itemIdx >= 0)
436 aRows->ElementAt(rowIdx) = itemIdx;
437 }
438 }
439 }
440
441 void
SelectRow(uint32_t aRowIdx)442 XULListboxAccessible::SelectRow(uint32_t aRowIdx)
443 {
444 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
445 do_QueryInterface(mContent);
446 NS_ASSERTION(control,
447 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
448
449 nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
450 control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
451 control->SelectItem(item);
452 }
453
454 void
UnselectRow(uint32_t aRowIdx)455 XULListboxAccessible::UnselectRow(uint32_t aRowIdx)
456 {
457 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
458 do_QueryInterface(mContent);
459 NS_ASSERTION(control,
460 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
461
462 nsCOMPtr<nsIDOMXULSelectControlItemElement> item;
463 control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
464 control->RemoveItemFromSelection(item);
465 }
466
467 ////////////////////////////////////////////////////////////////////////////////
468 // XULListboxAccessible: Widgets
469
470 bool
IsWidget() const471 XULListboxAccessible::IsWidget() const
472 {
473 return true;
474 }
475
476 bool
IsActiveWidget() const477 XULListboxAccessible::IsActiveWidget() const
478 {
479 if (IsAutoCompletePopup()) {
480 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
481 do_QueryInterface(mContent->GetParent());
482
483 if (autoCompletePopupElm) {
484 bool isOpen = false;
485 autoCompletePopupElm->GetPopupOpen(&isOpen);
486 return isOpen;
487 }
488 }
489 return FocusMgr()->HasDOMFocus(mContent);
490 }
491
492 bool
AreItemsOperable() const493 XULListboxAccessible::AreItemsOperable() const
494 {
495 if (IsAutoCompletePopup()) {
496 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
497 do_QueryInterface(mContent->GetParent());
498
499 if (autoCompletePopupElm) {
500 bool isOpen = false;
501 autoCompletePopupElm->GetPopupOpen(&isOpen);
502 return isOpen;
503 }
504 }
505 return true;
506 }
507
508 Accessible*
ContainerWidget() const509 XULListboxAccessible::ContainerWidget() const
510 {
511 if (IsAutoCompletePopup()) {
512 // This works for XUL autocompletes. It doesn't work for HTML forms
513 // autocomplete because of potential crossprocess calls (when autocomplete
514 // lives in content process while popup lives in chrome process). If that's
515 // a problem then rethink Widgets interface.
516 nsCOMPtr<nsIDOMXULMenuListElement> menuListElm =
517 do_QueryInterface(mContent->GetParent());
518 if (menuListElm) {
519 nsCOMPtr<nsIDOMNode> inputElm;
520 menuListElm->GetInputField(getter_AddRefs(inputElm));
521 if (inputElm) {
522 nsCOMPtr<nsINode> inputNode = do_QueryInterface(inputElm);
523 if (inputNode) {
524 Accessible* input =
525 mDoc->GetAccessible(inputNode);
526 return input ? input->ContainerWidget() : nullptr;
527 }
528 }
529 }
530 }
531 return nullptr;
532 }
533
534 ////////////////////////////////////////////////////////////////////////////////
535 // XULListitemAccessible
536 ////////////////////////////////////////////////////////////////////////////////
537
538 XULListitemAccessible::
XULListitemAccessible(nsIContent * aContent,DocAccessible * aDoc)539 XULListitemAccessible(nsIContent* aContent, DocAccessible* aDoc) :
540 XULMenuitemAccessible(aContent, aDoc)
541 {
542 mIsCheckbox = mContent->AttrValueIs(kNameSpaceID_None,
543 nsGkAtoms::type,
544 nsGkAtoms::checkbox,
545 eCaseMatters);
546 mType = eXULListItemType;
547
548 // Walk XBL anonymous children for list items. Overrides the flag value from
549 // base XULMenuitemAccessible class.
550 mStateFlags &= ~eNoXBLKids;
551 }
552
~XULListitemAccessible()553 XULListitemAccessible::~XULListitemAccessible()
554 {
555 }
556
NS_IMPL_ISUPPORTS_INHERITED0(XULListitemAccessible,Accessible)557 NS_IMPL_ISUPPORTS_INHERITED0(XULListitemAccessible, Accessible)
558
559 Accessible*
560 XULListitemAccessible::GetListAccessible() const
561 {
562 if (IsDefunct())
563 return nullptr;
564
565 nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
566 do_QueryInterface(mContent);
567 if (!listItem)
568 return nullptr;
569
570 nsCOMPtr<nsIDOMXULSelectControlElement> list;
571 listItem->GetControl(getter_AddRefs(list));
572
573 nsCOMPtr<nsIContent> listContent(do_QueryInterface(list));
574 if (!listContent)
575 return nullptr;
576
577 return mDoc->GetAccessible(listContent);
578 }
579
580 ////////////////////////////////////////////////////////////////////////////////
581 // XULListitemAccessible Accessible
582
583 void
Description(nsString & aDesc)584 XULListitemAccessible::Description(nsString& aDesc)
585 {
586 AccessibleWrap::Description(aDesc);
587 }
588
589 ////////////////////////////////////////////////////////////////////////////////
590 // XULListitemAccessible: Accessible
591
592 /**
593 * If there is a Listcell as a child ( not anonymous ) use it, otherwise
594 * default to getting the name from GetXULName
595 */
596 ENameValueFlag
NativeName(nsString & aName)597 XULListitemAccessible::NativeName(nsString& aName)
598 {
599 nsIContent* childContent = mContent->GetFirstChild();
600 if (childContent) {
601 if (childContent->NodeInfo()->Equals(nsGkAtoms::listcell,
602 kNameSpaceID_XUL)) {
603 childContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aName);
604 return eNameOK;
605 }
606 }
607
608 return Accessible::NativeName(aName);
609 }
610
611 role
NativeRole()612 XULListitemAccessible::NativeRole()
613 {
614 Accessible* list = GetListAccessible();
615 if (!list) {
616 NS_ERROR("No list accessible for listitem accessible!");
617 return roles::NOTHING;
618 }
619
620 if (list->Role() == roles::TABLE)
621 return roles::ROW;
622
623 if (mIsCheckbox)
624 return roles::CHECK_RICH_OPTION;
625
626 if (mParent && mParent->Role() == roles::COMBOBOX_LIST)
627 return roles::COMBOBOX_OPTION;
628
629 return roles::RICH_OPTION;
630 }
631
632 uint64_t
NativeState()633 XULListitemAccessible::NativeState()
634 {
635 if (mIsCheckbox)
636 return XULMenuitemAccessible::NativeState();
637
638 uint64_t states = NativeInteractiveState();
639
640 nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
641 do_QueryInterface(mContent);
642
643 if (listItem) {
644 bool isSelected;
645 listItem->GetSelected(&isSelected);
646 if (isSelected)
647 states |= states::SELECTED;
648
649 if (FocusMgr()->IsFocused(this))
650 states |= states::FOCUSED;
651 }
652
653 return states;
654 }
655
656 uint64_t
NativeInteractiveState() const657 XULListitemAccessible::NativeInteractiveState() const
658 {
659 return NativelyUnavailable() || (mParent && mParent->NativelyUnavailable()) ?
660 states::UNAVAILABLE : states::FOCUSABLE | states::SELECTABLE;
661 }
662
663 void
ActionNameAt(uint8_t aIndex,nsAString & aName)664 XULListitemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName)
665 {
666 if (aIndex == eAction_Click && mIsCheckbox) {
667 uint64_t states = NativeState();
668 if (states & states::CHECKED)
669 aName.AssignLiteral("uncheck");
670 else
671 aName.AssignLiteral("check");
672 }
673 }
674
675 ////////////////////////////////////////////////////////////////////////////////
676 // XULListitemAccessible: Widgets
677
678 Accessible*
ContainerWidget() const679 XULListitemAccessible::ContainerWidget() const
680 {
681 return Parent();
682 }
683
684
685 ////////////////////////////////////////////////////////////////////////////////
686 // XULListCellAccessible
687 ////////////////////////////////////////////////////////////////////////////////
688
689 XULListCellAccessible::
XULListCellAccessible(nsIContent * aContent,DocAccessible * aDoc)690 XULListCellAccessible(nsIContent* aContent, DocAccessible* aDoc) :
691 HyperTextAccessibleWrap(aContent, aDoc)
692 {
693 mGenericTypes |= eTableCell;
694 }
695
696 ////////////////////////////////////////////////////////////////////////////////
697 // nsISupports
698
NS_IMPL_ISUPPORTS_INHERITED0(XULListCellAccessible,HyperTextAccessible)699 NS_IMPL_ISUPPORTS_INHERITED0(XULListCellAccessible,
700 HyperTextAccessible)
701
702 ////////////////////////////////////////////////////////////////////////////////
703 // XULListCellAccessible: TableCell
704
705 TableAccessible*
706 XULListCellAccessible::Table() const
707 {
708 Accessible* thisRow = Parent();
709 if (!thisRow || thisRow->Role() != roles::ROW)
710 return nullptr;
711
712 Accessible* table = thisRow->Parent();
713 if (!table || table->Role() != roles::TABLE)
714 return nullptr;
715
716 return table->AsTable();
717 }
718
719 uint32_t
ColIdx() const720 XULListCellAccessible::ColIdx() const
721 {
722 Accessible* row = Parent();
723 if (!row)
724 return 0;
725
726 int32_t indexInRow = IndexInParent();
727 uint32_t colIdx = 0;
728 for (int32_t idx = 0; idx < indexInRow; idx++) {
729 Accessible* cell = row->GetChildAt(idx);
730 roles::Role role = cell->Role();
731 if (role == roles::CELL || role == roles::GRID_CELL ||
732 role == roles::ROWHEADER || role == roles::COLUMNHEADER)
733 colIdx++;
734 }
735
736 return colIdx;
737 }
738
739 uint32_t
RowIdx() const740 XULListCellAccessible::RowIdx() const
741 {
742 Accessible* row = Parent();
743 if (!row)
744 return 0;
745
746 Accessible* table = row->Parent();
747 if (!table)
748 return 0;
749
750 int32_t indexInTable = row->IndexInParent();
751 uint32_t rowIdx = 0;
752 for (int32_t idx = 0; idx < indexInTable; idx++) {
753 row = table->GetChildAt(idx);
754 if (row->Role() == roles::ROW)
755 rowIdx++;
756 }
757
758 return rowIdx;
759 }
760
761 void
ColHeaderCells(nsTArray<Accessible * > * aCells)762 XULListCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aCells)
763 {
764 TableAccessible* table = Table();
765 NS_ASSERTION(table, "cell not in a table!");
766 if (!table)
767 return;
768
769 // Get column header cell from XUL listhead.
770 Accessible* list = nullptr;
771
772 Accessible* tableAcc = table->AsAccessible();
773 uint32_t tableChildCount = tableAcc->ChildCount();
774 for (uint32_t childIdx = 0; childIdx < tableChildCount; childIdx++) {
775 Accessible* child = tableAcc->GetChildAt(childIdx);
776 if (child->Role() == roles::LIST) {
777 list = child;
778 break;
779 }
780 }
781
782 if (list) {
783 Accessible* headerCell = list->GetChildAt(ColIdx());
784 if (headerCell) {
785 aCells->AppendElement(headerCell);
786 return;
787 }
788 }
789
790 // No column header cell from XUL markup, try to get it from ARIA markup.
791 TableCellAccessible::ColHeaderCells(aCells);
792 }
793
794 bool
Selected()795 XULListCellAccessible::Selected()
796 {
797 TableAccessible* table = Table();
798 NS_ENSURE_TRUE(table, false); // we expect to be in a listbox (table)
799
800 return table->IsRowSelected(RowIdx());
801 }
802
803 ////////////////////////////////////////////////////////////////////////////////
804 // XULListCellAccessible. Accessible implementation
805
806 role
NativeRole()807 XULListCellAccessible::NativeRole()
808 {
809 return roles::CELL;
810 }
811
812 already_AddRefed<nsIPersistentProperties>
NativeAttributes()813 XULListCellAccessible::NativeAttributes()
814 {
815 nsCOMPtr<nsIPersistentProperties> attributes =
816 HyperTextAccessibleWrap::NativeAttributes();
817
818 // "table-cell-index" attribute
819 TableAccessible* table = Table();
820 if (!table) // we expect to be in a listbox (table)
821 return attributes.forget();
822
823 nsAutoString stringIdx;
824 stringIdx.AppendInt(table->CellIndexAt(RowIdx(), ColIdx()));
825 nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx);
826
827 return attributes.forget();
828 }
829