Bug 1718535 [wpt PR 29519] - [Credentialless] Fix flaky reporting-subresource-corp...
[gecko.git] / accessible / xul / XULListboxAccessible.cpp
blob6e48aee6dd77ad261aa8925d2d2dfd63dc45315e
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/. */
6 #include "XULListboxAccessible.h"
8 #include "LocalAccessible-inl.h"
9 #include "nsAccessibilityService.h"
10 #include "nsAccUtils.h"
11 #include "DocAccessible.h"
12 #include "Role.h"
13 #include "States.h"
15 #include "nsComponentManagerUtils.h"
16 #include "nsIAutoCompletePopup.h"
17 #include "nsIDOMXULMenuListElement.h"
18 #include "nsIDOMXULMultSelectCntrlEl.h"
19 #include "nsIDOMXULSelectCntrlItemEl.h"
20 #include "nsINodeList.h"
22 using namespace mozilla::a11y;
24 ////////////////////////////////////////////////////////////////////////////////
25 // XULColumAccessible
26 ////////////////////////////////////////////////////////////////////////////////
28 XULColumAccessible::XULColumAccessible(nsIContent* aContent,
29 DocAccessible* aDoc)
30 : AccessibleWrap(aContent, aDoc) {}
32 role XULColumAccessible::NativeRole() const { return roles::LIST; }
34 uint64_t XULColumAccessible::NativeState() const { return states::READONLY; }
36 ////////////////////////////////////////////////////////////////////////////////
37 // XULColumnItemAccessible
38 ////////////////////////////////////////////////////////////////////////////////
40 XULColumnItemAccessible::XULColumnItemAccessible(nsIContent* aContent,
41 DocAccessible* aDoc)
42 : LeafAccessible(aContent, aDoc) {}
44 role XULColumnItemAccessible::NativeRole() const { return roles::COLUMNHEADER; }
46 uint64_t XULColumnItemAccessible::NativeState() const {
47 return states::READONLY;
50 uint8_t XULColumnItemAccessible::ActionCount() const { return 1; }
52 void XULColumnItemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
53 if (aIndex == eAction_Click) aName.AssignLiteral("click");
56 bool XULColumnItemAccessible::DoAction(uint8_t aIndex) const {
57 if (aIndex != eAction_Click) return false;
59 DoCommand();
60 return true;
63 ////////////////////////////////////////////////////////////////////////////////
64 // XULListboxAccessible
65 ////////////////////////////////////////////////////////////////////////////////
67 XULListboxAccessible::XULListboxAccessible(nsIContent* aContent,
68 DocAccessible* aDoc)
69 : XULSelectControlAccessible(aContent, aDoc) {
70 nsIContent* parentContent = mContent->GetFlattenedTreeParent();
71 if (parentContent) {
72 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
73 parentContent->AsElement()->AsAutoCompletePopup();
74 if (autoCompletePopupElm) mGenericTypes |= eAutoCompletePopup;
77 if (IsMulticolumn()) mGenericTypes |= eTable;
80 ////////////////////////////////////////////////////////////////////////////////
81 // XULListboxAccessible: LocalAccessible
83 uint64_t XULListboxAccessible::NativeState() const {
84 // As a XULListboxAccessible we can have the following states:
85 // FOCUSED, READONLY, FOCUSABLE
87 // Get focus status from base class
88 uint64_t states = LocalAccessible::NativeState();
90 // see if we are multiple select if so set ourselves as such
92 if (mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::seltype,
93 nsGkAtoms::multiple, eCaseMatters)) {
94 states |= states::MULTISELECTABLE | states::EXTSELECTABLE;
97 return states;
100 role XULListboxAccessible::NativeRole() const {
101 // A richlistbox is used with the new autocomplete URL bar, and has a parent
102 // popup <panel>.
103 if (mContent->GetParent() &&
104 mContent->GetParent()->IsXULElement(nsGkAtoms::panel)) {
105 return roles::COMBOBOX_LIST;
108 return IsMulticolumn() ? roles::TABLE : roles::LISTBOX;
111 ////////////////////////////////////////////////////////////////////////////////
112 // XULListboxAccessible: Table
114 uint32_t XULListboxAccessible::ColCount() const { return 0; }
116 uint32_t XULListboxAccessible::RowCount() {
117 nsCOMPtr<nsIDOMXULSelectControlElement> element = Elm()->AsXULSelectControl();
119 uint32_t itemCount = 0;
120 if (element) element->GetItemCount(&itemCount);
122 return itemCount;
125 LocalAccessible* XULListboxAccessible::CellAt(uint32_t aRowIndex,
126 uint32_t aColumnIndex) {
127 nsCOMPtr<nsIDOMXULSelectControlElement> control = Elm()->AsXULSelectControl();
128 NS_ENSURE_TRUE(control, nullptr);
130 RefPtr<dom::Element> element;
131 control->GetItemAtIndex(aRowIndex, getter_AddRefs(element));
132 if (!element) return nullptr;
134 LocalAccessible* row = mDoc->GetAccessible(element);
135 NS_ENSURE_TRUE(row, nullptr);
137 return row->LocalChildAt(aColumnIndex);
140 bool XULListboxAccessible::IsColSelected(uint32_t aColIdx) {
141 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
142 Elm()->AsXULMultiSelectControl();
143 NS_ASSERTION(control,
144 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
146 int32_t selectedrowCount = 0;
147 nsresult rv = control->GetSelectedCount(&selectedrowCount);
148 NS_ENSURE_SUCCESS(rv, false);
150 return selectedrowCount == static_cast<int32_t>(RowCount());
153 bool XULListboxAccessible::IsRowSelected(uint32_t aRowIdx) {
154 nsCOMPtr<nsIDOMXULSelectControlElement> control = Elm()->AsXULSelectControl();
155 NS_ASSERTION(control, "Doesn't implement nsIDOMXULSelectControlElement.");
157 RefPtr<dom::Element> element;
158 nsresult rv = control->GetItemAtIndex(aRowIdx, getter_AddRefs(element));
159 NS_ENSURE_SUCCESS(rv, false);
160 if (!element) {
161 return false;
164 nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
165 element->AsXULSelectControlItem();
167 bool isSelected = false;
168 item->GetSelected(&isSelected);
169 return isSelected;
172 bool XULListboxAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) {
173 return IsRowSelected(aRowIdx);
176 uint32_t XULListboxAccessible::SelectedCellCount() {
177 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
178 Elm()->AsXULMultiSelectControl();
179 NS_ASSERTION(control,
180 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
182 nsCOMPtr<nsINodeList> selectedItems;
183 control->GetSelectedItems(getter_AddRefs(selectedItems));
184 if (!selectedItems) return 0;
186 uint32_t selectedItemsCount = selectedItems->Length();
188 return selectedItemsCount * ColCount();
191 uint32_t XULListboxAccessible::SelectedColCount() {
192 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
193 Elm()->AsXULMultiSelectControl();
194 NS_ASSERTION(control,
195 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
197 int32_t selectedRowCount = 0;
198 nsresult rv = control->GetSelectedCount(&selectedRowCount);
199 NS_ENSURE_SUCCESS(rv, 0);
201 return selectedRowCount > 0 &&
202 selectedRowCount == static_cast<int32_t>(RowCount())
203 ? ColCount()
204 : 0;
207 uint32_t XULListboxAccessible::SelectedRowCount() {
208 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
209 Elm()->AsXULMultiSelectControl();
210 NS_ASSERTION(control,
211 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
213 int32_t selectedRowCount = 0;
214 nsresult rv = control->GetSelectedCount(&selectedRowCount);
215 NS_ENSURE_SUCCESS(rv, 0);
217 return selectedRowCount >= 0 ? selectedRowCount : 0;
220 void XULListboxAccessible::SelectedCells(nsTArray<LocalAccessible*>* aCells) {
221 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
222 Elm()->AsXULMultiSelectControl();
223 NS_ASSERTION(control,
224 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
226 nsCOMPtr<nsINodeList> selectedItems;
227 control->GetSelectedItems(getter_AddRefs(selectedItems));
228 if (!selectedItems) return;
230 uint32_t selectedItemsCount = selectedItems->Length();
232 for (uint32_t index = 0; index < selectedItemsCount; index++) {
233 nsIContent* itemContent = selectedItems->Item(index);
234 LocalAccessible* item = mDoc->GetAccessible(itemContent);
236 if (item) {
237 uint32_t cellCount = item->ChildCount();
238 for (uint32_t cellIdx = 0; cellIdx < cellCount; cellIdx++) {
239 LocalAccessible* cell = mChildren[cellIdx];
240 if (cell->Role() == roles::CELL) aCells->AppendElement(cell);
246 void XULListboxAccessible::SelectedCellIndices(nsTArray<uint32_t>* aCells) {
247 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
248 Elm()->AsXULMultiSelectControl();
249 NS_ASSERTION(control,
250 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
252 nsCOMPtr<nsINodeList> selectedItems;
253 control->GetSelectedItems(getter_AddRefs(selectedItems));
254 if (!selectedItems) return;
256 uint32_t selectedItemsCount = selectedItems->Length();
258 uint32_t colCount = ColCount();
259 aCells->SetCapacity(selectedItemsCount * colCount);
260 aCells->AppendElements(selectedItemsCount * colCount);
262 for (uint32_t selItemsIdx = 0, cellsIdx = 0; selItemsIdx < selectedItemsCount;
263 selItemsIdx++) {
264 nsIContent* itemContent = selectedItems->Item(selItemsIdx);
266 nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
267 itemContent->AsElement()->AsXULSelectControlItem();
268 if (item) {
269 int32_t itemIdx = -1;
270 control->GetIndexOfItem(item, &itemIdx);
271 if (itemIdx >= 0) {
272 for (uint32_t colIdx = 0; colIdx < colCount; colIdx++, cellsIdx++) {
273 aCells->ElementAt(cellsIdx) = itemIdx * colCount + colIdx;
280 void XULListboxAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols) {
281 uint32_t selColCount = SelectedColCount();
282 aCols->SetCapacity(selColCount);
284 for (uint32_t colIdx = 0; colIdx < selColCount; colIdx++) {
285 aCols->AppendElement(colIdx);
289 void XULListboxAccessible::SelectedRowIndices(nsTArray<uint32_t>* aRows) {
290 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
291 Elm()->AsXULMultiSelectControl();
292 NS_ASSERTION(control,
293 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
295 nsCOMPtr<nsINodeList> selectedItems;
296 control->GetSelectedItems(getter_AddRefs(selectedItems));
297 if (!selectedItems) return;
299 uint32_t rowCount = selectedItems->Length();
301 if (!rowCount) return;
303 aRows->SetCapacity(rowCount);
304 aRows->AppendElements(rowCount);
306 for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
307 nsIContent* itemContent = selectedItems->Item(rowIdx);
308 nsCOMPtr<nsIDOMXULSelectControlItemElement> item =
309 itemContent->AsElement()->AsXULSelectControlItem();
311 if (item) {
312 int32_t itemIdx = -1;
313 control->GetIndexOfItem(item, &itemIdx);
314 if (itemIdx >= 0) aRows->ElementAt(rowIdx) = itemIdx;
319 void XULListboxAccessible::SelectRow(uint32_t aRowIdx) {
320 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
321 Elm()->AsXULMultiSelectControl();
322 NS_ASSERTION(control,
323 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
325 RefPtr<dom::Element> item;
326 control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
327 if (!item) {
328 return;
331 nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
332 item->AsXULSelectControlItem();
333 control->SelectItem(itemElm);
336 void XULListboxAccessible::UnselectRow(uint32_t aRowIdx) {
337 nsCOMPtr<nsIDOMXULMultiSelectControlElement> control =
338 Elm()->AsXULMultiSelectControl();
339 NS_ASSERTION(control,
340 "Doesn't implement nsIDOMXULMultiSelectControlElement.");
342 RefPtr<dom::Element> item;
343 control->GetItemAtIndex(aRowIdx, getter_AddRefs(item));
344 if (!item) {
345 return;
348 nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
349 item->AsXULSelectControlItem();
350 control->RemoveItemFromSelection(itemElm);
353 ////////////////////////////////////////////////////////////////////////////////
354 // XULListboxAccessible: Widgets
356 bool XULListboxAccessible::IsWidget() const { return true; }
358 bool XULListboxAccessible::IsActiveWidget() const {
359 if (IsAutoCompletePopup()) {
360 nsIContent* parentContent = mContent->GetParent();
361 if (parentContent) {
362 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
363 parentContent->AsElement()->AsAutoCompletePopup();
364 if (autoCompletePopupElm) {
365 bool isOpen = false;
366 autoCompletePopupElm->GetPopupOpen(&isOpen);
367 return isOpen;
371 return FocusMgr()->HasDOMFocus(mContent);
374 bool XULListboxAccessible::AreItemsOperable() const {
375 if (IsAutoCompletePopup()) {
376 nsIContent* parentContent = mContent->GetParent();
377 if (parentContent) {
378 nsCOMPtr<nsIAutoCompletePopup> autoCompletePopupElm =
379 parentContent->AsElement()->AsAutoCompletePopup();
380 if (autoCompletePopupElm) {
381 bool isOpen = false;
382 autoCompletePopupElm->GetPopupOpen(&isOpen);
383 return isOpen;
387 return true;
390 LocalAccessible* XULListboxAccessible::ContainerWidget() const {
391 if (IsAutoCompletePopup() && mContent->GetParent()) {
392 // This works for XUL autocompletes. It doesn't work for HTML forms
393 // autocomplete because of potential crossprocess calls (when autocomplete
394 // lives in content process while popup lives in chrome process). If that's
395 // a problem then rethink Widgets interface.
396 nsCOMPtr<nsIDOMXULMenuListElement> menuListElm =
397 mContent->GetParent()->AsElement()->AsXULMenuList();
398 if (menuListElm) {
399 RefPtr<mozilla::dom::Element> inputElm;
400 menuListElm->GetInputField(getter_AddRefs(inputElm));
401 if (inputElm) {
402 LocalAccessible* input = mDoc->GetAccessible(inputElm);
403 return input ? input->ContainerWidget() : nullptr;
407 return nullptr;
410 ////////////////////////////////////////////////////////////////////////////////
411 // XULListitemAccessible
412 ////////////////////////////////////////////////////////////////////////////////
414 XULListitemAccessible::XULListitemAccessible(nsIContent* aContent,
415 DocAccessible* aDoc)
416 : XULMenuitemAccessible(aContent, aDoc) {
417 mIsCheckbox = mContent->AsElement()->AttrValueIs(
418 kNameSpaceID_None, nsGkAtoms::type, nsGkAtoms::checkbox, eCaseMatters);
419 mType = eXULListItemType;
422 XULListitemAccessible::~XULListitemAccessible() {}
424 LocalAccessible* XULListitemAccessible::GetListAccessible() const {
425 if (IsDefunct()) return nullptr;
427 nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
428 Elm()->AsXULSelectControlItem();
429 if (!listItem) return nullptr;
431 RefPtr<dom::Element> listElement;
432 listItem->GetControl(getter_AddRefs(listElement));
433 if (!listElement) return nullptr;
435 return mDoc->GetAccessible(listElement);
438 ////////////////////////////////////////////////////////////////////////////////
439 // XULListitemAccessible LocalAccessible
441 void XULListitemAccessible::Description(nsString& aDesc) {
442 AccessibleWrap::Description(aDesc);
445 ////////////////////////////////////////////////////////////////////////////////
446 // XULListitemAccessible: LocalAccessible
449 * Get the name from GetXULName.
451 ENameValueFlag XULListitemAccessible::NativeName(nsString& aName) const {
452 return LocalAccessible::NativeName(aName);
455 role XULListitemAccessible::NativeRole() const {
456 LocalAccessible* list = GetListAccessible();
457 if (!list) {
458 NS_ERROR("No list accessible for listitem accessible!");
459 return roles::NOTHING;
462 if (list->Role() == roles::TABLE) return roles::ROW;
464 if (mIsCheckbox) return roles::CHECK_RICH_OPTION;
466 if (mParent && mParent->Role() == roles::COMBOBOX_LIST) {
467 return roles::COMBOBOX_OPTION;
470 return roles::RICH_OPTION;
473 uint64_t XULListitemAccessible::NativeState() const {
474 if (mIsCheckbox) return XULMenuitemAccessible::NativeState();
476 uint64_t states = NativeInteractiveState();
478 nsCOMPtr<nsIDOMXULSelectControlItemElement> listItem =
479 Elm()->AsXULSelectControlItem();
480 if (listItem) {
481 bool isSelected;
482 listItem->GetSelected(&isSelected);
483 if (isSelected) states |= states::SELECTED;
485 if (FocusMgr()->IsFocused(this)) states |= states::FOCUSED;
488 return states;
491 uint64_t XULListitemAccessible::NativeInteractiveState() const {
492 return NativelyUnavailable() || (mParent && mParent->NativelyUnavailable())
493 ? states::UNAVAILABLE
494 : states::FOCUSABLE | states::SELECTABLE;
497 void XULListitemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) {
498 if (aIndex == eAction_Click && mIsCheckbox) {
499 uint64_t states = NativeState();
500 if (states & states::CHECKED) {
501 aName.AssignLiteral("uncheck");
502 } else {
503 aName.AssignLiteral("check");
508 ////////////////////////////////////////////////////////////////////////////////
509 // XULListitemAccessible: Widgets
511 LocalAccessible* XULListitemAccessible::ContainerWidget() const {
512 return LocalParent();