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"
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 ////////////////////////////////////////////////////////////////////////////////
26 ////////////////////////////////////////////////////////////////////////////////
28 XULColumAccessible::XULColumAccessible(nsIContent
* aContent
,
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
,
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;
63 ////////////////////////////////////////////////////////////////////////////////
64 // XULListboxAccessible
65 ////////////////////////////////////////////////////////////////////////////////
67 XULListboxAccessible::XULListboxAccessible(nsIContent
* aContent
,
69 : XULSelectControlAccessible(aContent
, aDoc
) {
70 nsIContent
* parentContent
= mContent
->GetFlattenedTreeParent();
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
;
100 role
XULListboxAccessible::NativeRole() const {
101 // A richlistbox is used with the new autocomplete URL bar, and has a parent
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
);
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);
164 nsCOMPtr
<nsIDOMXULSelectControlItemElement
> item
=
165 element
->AsXULSelectControlItem();
167 bool isSelected
= false;
168 item
->GetSelected(&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())
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
);
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
;
264 nsIContent
* itemContent
= selectedItems
->Item(selItemsIdx
);
266 nsCOMPtr
<nsIDOMXULSelectControlItemElement
> item
=
267 itemContent
->AsElement()->AsXULSelectControlItem();
269 int32_t itemIdx
= -1;
270 control
->GetIndexOfItem(item
, &itemIdx
);
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();
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
));
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
));
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();
362 nsCOMPtr
<nsIAutoCompletePopup
> autoCompletePopupElm
=
363 parentContent
->AsElement()->AsAutoCompletePopup();
364 if (autoCompletePopupElm
) {
366 autoCompletePopupElm
->GetPopupOpen(&isOpen
);
371 return FocusMgr()->HasDOMFocus(mContent
);
374 bool XULListboxAccessible::AreItemsOperable() const {
375 if (IsAutoCompletePopup()) {
376 nsIContent
* parentContent
= mContent
->GetParent();
378 nsCOMPtr
<nsIAutoCompletePopup
> autoCompletePopupElm
=
379 parentContent
->AsElement()->AsAutoCompletePopup();
380 if (autoCompletePopupElm
) {
382 autoCompletePopupElm
->GetPopupOpen(&isOpen
);
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();
399 RefPtr
<mozilla::dom::Element
> inputElm
;
400 menuListElm
->GetInputField(getter_AddRefs(inputElm
));
402 LocalAccessible
* input
= mDoc
->GetAccessible(inputElm
);
403 return input
? input
->ContainerWidget() : nullptr;
410 ////////////////////////////////////////////////////////////////////////////////
411 // XULListitemAccessible
412 ////////////////////////////////////////////////////////////////////////////////
414 XULListitemAccessible::XULListitemAccessible(nsIContent
* aContent
,
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();
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();
482 listItem
->GetSelected(&isSelected
);
483 if (isSelected
) states
|= states::SELECTED
;
485 if (FocusMgr()->IsFocused(this)) states
|= states::FOCUSED
;
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");
503 aName
.AssignLiteral("check");
508 ////////////////////////////////////////////////////////////////////////////////
509 // XULListitemAccessible: Widgets
511 LocalAccessible
* XULListitemAccessible::ContainerWidget() const {
512 return LocalParent();