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