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