From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- accessible/xul/XULListboxAccessible.cpp | 828 ++++++++++++++++++++++++++++++++ 1 file changed, 828 insertions(+) create mode 100644 accessible/xul/XULListboxAccessible.cpp (limited to 'accessible/xul/XULListboxAccessible.cpp') diff --git a/accessible/xul/XULListboxAccessible.cpp b/accessible/xul/XULListboxAccessible.cpp new file mode 100644 index 000000000..52c3ddf0f --- /dev/null +++ b/accessible/xul/XULListboxAccessible.cpp @@ -0,0 +1,828 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "XULListboxAccessible.h" + +#include "Accessible-inl.h" +#include "nsAccessibilityService.h" +#include "nsAccUtils.h" +#include "DocAccessible.h" +#include "Role.h" +#include "States.h" + +#include "nsComponentManagerUtils.h" +#include "nsIAutoCompleteInput.h" +#include "nsIAutoCompletePopup.h" +#include "nsIDOMXULMenuListElement.h" +#include "nsIDOMXULMultSelectCntrlEl.h" +#include "nsIDOMNodeList.h" +#include "nsIDOMXULPopupElement.h" +#include "nsIDOMXULSelectCntrlItemEl.h" +#include "nsIMutableArray.h" +#include "nsIPersistentProperties2.h" + +using namespace mozilla::a11y; + +//////////////////////////////////////////////////////////////////////////////// +// XULColumAccessible +//////////////////////////////////////////////////////////////////////////////// + +XULColumAccessible:: + XULColumAccessible(nsIContent* aContent, DocAccessible* aDoc) : + AccessibleWrap(aContent, aDoc) +{ +} + +role +XULColumAccessible::NativeRole() +{ + return roles::LIST; +} + +uint64_t +XULColumAccessible::NativeState() +{ + return states::READONLY; +} + + +//////////////////////////////////////////////////////////////////////////////// +// XULColumnItemAccessible +//////////////////////////////////////////////////////////////////////////////// + +XULColumnItemAccessible:: + XULColumnItemAccessible(nsIContent* aContent, DocAccessible* aDoc) : + LeafAccessible(aContent, aDoc) +{ +} + +role +XULColumnItemAccessible::NativeRole() +{ + return roles::COLUMNHEADER; +} + +uint64_t +XULColumnItemAccessible::NativeState() +{ + return states::READONLY; +} + +uint8_t +XULColumnItemAccessible::ActionCount() +{ + return 1; +} + +void +XULColumnItemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) +{ + if (aIndex == eAction_Click) + aName.AssignLiteral("click"); +} + +bool +XULColumnItemAccessible::DoAction(uint8_t aIndex) +{ + if (aIndex != eAction_Click) + return false; + + DoCommand(); + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// XULListboxAccessible +//////////////////////////////////////////////////////////////////////////////// + +XULListboxAccessible:: + XULListboxAccessible(nsIContent* aContent, DocAccessible* aDoc) : + XULSelectControlAccessible(aContent, aDoc) +{ + nsIContent* parentContent = mContent->GetFlattenedTreeParent(); + if (parentContent) { + nsCOMPtr autoCompletePopupElm = + do_QueryInterface(parentContent); + if (autoCompletePopupElm) + mGenericTypes |= eAutoCompletePopup; + } + + if (IsMulticolumn()) + mGenericTypes |= eTable; +} + +//////////////////////////////////////////////////////////////////////////////// +// XULListboxAccessible: Accessible + +uint64_t +XULListboxAccessible::NativeState() +{ + // As a XULListboxAccessible we can have the following states: + // FOCUSED, READONLY, FOCUSABLE + + // Get focus status from base class + uint64_t states = Accessible::NativeState(); + + // see if we are multiple select if so set ourselves as such + + if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::seltype, + nsGkAtoms::multiple, eCaseMatters)) { + states |= states::MULTISELECTABLE | states::EXTSELECTABLE; + } + + return states; +} + +/** + * Our value is the label of our ( first ) selected child. + */ +void +XULListboxAccessible::Value(nsString& aValue) +{ + aValue.Truncate(); + + nsCOMPtr select(do_QueryInterface(mContent)); + if (select) { + nsCOMPtr selectedItem; + select->GetSelectedItem(getter_AddRefs(selectedItem)); + if (selectedItem) + selectedItem->GetLabel(aValue); + } +} + +role +XULListboxAccessible::NativeRole() +{ + // A richlistbox is used with the new autocomplete URL bar, and has a parent + // popup . + nsCOMPtr xulPopup = + do_QueryInterface(mContent->GetParent()); + if (xulPopup) + return roles::COMBOBOX_LIST; + + return IsMulticolumn() ? roles::TABLE : roles::LISTBOX; +} + +//////////////////////////////////////////////////////////////////////////////// +// XULListboxAccessible: Table + +uint32_t +XULListboxAccessible::ColCount() +{ + nsIContent* headContent = nullptr; + for (nsIContent* childContent = mContent->GetFirstChild(); childContent; + childContent = childContent->GetNextSibling()) { + if (childContent->NodeInfo()->Equals(nsGkAtoms::listcols, + kNameSpaceID_XUL)) { + headContent = childContent; + } + } + if (!headContent) + return 0; + + uint32_t columnCount = 0; + for (nsIContent* childContent = headContent->GetFirstChild(); childContent; + childContent = childContent->GetNextSibling()) { + if (childContent->NodeInfo()->Equals(nsGkAtoms::listcol, + kNameSpaceID_XUL)) { + columnCount++; + } + } + + return columnCount; +} + +uint32_t +XULListboxAccessible::RowCount() +{ + nsCOMPtr element(do_QueryInterface(mContent)); + + uint32_t itemCount = 0; + if(element) + element->GetItemCount(&itemCount); + + return itemCount; +} + +Accessible* +XULListboxAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) +{ + nsCOMPtr control = + do_QueryInterface(mContent); + NS_ENSURE_TRUE(control, nullptr); + + nsCOMPtr item; + control->GetItemAtIndex(aRowIndex, getter_AddRefs(item)); + if (!item) + return nullptr; + + nsCOMPtr itemContent(do_QueryInterface(item)); + if (!itemContent) + return nullptr; + + Accessible* row = mDoc->GetAccessible(itemContent); + NS_ENSURE_TRUE(row, nullptr); + + return row->GetChildAt(aColumnIndex); +} + +bool +XULListboxAccessible::IsColSelected(uint32_t aColIdx) +{ + nsCOMPtr control = + do_QueryInterface(mContent); + NS_ASSERTION(control, + "Doesn't implement nsIDOMXULMultiSelectControlElement."); + + int32_t selectedrowCount = 0; + nsresult rv = control->GetSelectedCount(&selectedrowCount); + NS_ENSURE_SUCCESS(rv, false); + + return selectedrowCount == static_cast(RowCount()); +} + +bool +XULListboxAccessible::IsRowSelected(uint32_t aRowIdx) +{ + nsCOMPtr control = + do_QueryInterface(mContent); + NS_ASSERTION(control, + "Doesn't implement nsIDOMXULSelectControlElement."); + + nsCOMPtr item; + nsresult rv = control->GetItemAtIndex(aRowIdx, getter_AddRefs(item)); + NS_ENSURE_SUCCESS(rv, false); + + bool isSelected = false; + item->GetSelected(&isSelected); + return isSelected; +} + +bool +XULListboxAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) +{ + return IsRowSelected(aRowIdx); +} + +uint32_t +XULListboxAccessible::SelectedCellCount() +{ + nsCOMPtr control = + do_QueryInterface(mContent); + NS_ASSERTION(control, + "Doesn't implement nsIDOMXULMultiSelectControlElement."); + + nsCOMPtr selectedItems; + control->GetSelectedItems(getter_AddRefs(selectedItems)); + if (!selectedItems) + return 0; + + uint32_t selectedItemsCount = 0; + nsresult rv = selectedItems->GetLength(&selectedItemsCount); + NS_ENSURE_SUCCESS(rv, 0); + + return selectedItemsCount * ColCount(); +} + +uint32_t +XULListboxAccessible::SelectedColCount() +{ + nsCOMPtr control = + do_QueryInterface(mContent); + NS_ASSERTION(control, + "Doesn't implement nsIDOMXULMultiSelectControlElement."); + + int32_t selectedRowCount = 0; + nsresult rv = control->GetSelectedCount(&selectedRowCount); + NS_ENSURE_SUCCESS(rv, 0); + + return selectedRowCount > 0 && + selectedRowCount == static_cast(RowCount()) ? ColCount() : 0; +} + +uint32_t +XULListboxAccessible::SelectedRowCount() +{ + nsCOMPtr control = + do_QueryInterface(mContent); + NS_ASSERTION(control, + "Doesn't implement nsIDOMXULMultiSelectControlElement."); + + int32_t selectedRowCount = 0; + nsresult rv = control->GetSelectedCount(&selectedRowCount); + NS_ENSURE_SUCCESS(rv, 0); + + return selectedRowCount >= 0 ? selectedRowCount : 0; +} + +void +XULListboxAccessible::SelectedCells(nsTArray* aCells) +{ + nsCOMPtr control = + do_QueryInterface(mContent); + NS_ASSERTION(control, + "Doesn't implement nsIDOMXULMultiSelectControlElement."); + + nsCOMPtr selectedItems; + control->GetSelectedItems(getter_AddRefs(selectedItems)); + if (!selectedItems) + return; + + uint32_t selectedItemsCount = 0; + DebugOnly rv = selectedItems->GetLength(&selectedItemsCount); + NS_ASSERTION(NS_SUCCEEDED(rv), "GetLength() Shouldn't fail!"); + + for (uint32_t index = 0; index < selectedItemsCount; index++) { + nsCOMPtr itemNode; + selectedItems->Item(index, getter_AddRefs(itemNode)); + nsCOMPtr itemContent(do_QueryInterface(itemNode)); + Accessible* item = mDoc->GetAccessible(itemContent); + + if (item) { + uint32_t cellCount = item->ChildCount(); + for (uint32_t cellIdx = 0; cellIdx < cellCount; cellIdx++) { + Accessible* cell = mChildren[cellIdx]; + if (cell->Role() == roles::CELL) + aCells->AppendElement(cell); + } + } + } +} + +void +XULListboxAccessible::SelectedCellIndices(nsTArray* aCells) +{ + nsCOMPtr control = + do_QueryInterface(mContent); + NS_ASSERTION(control, + "Doesn't implement nsIDOMXULMultiSelectControlElement."); + + nsCOMPtr selectedItems; + control->GetSelectedItems(getter_AddRefs(selectedItems)); + if (!selectedItems) + return; + + uint32_t selectedItemsCount = 0; + DebugOnly rv = selectedItems->GetLength(&selectedItemsCount); + NS_ASSERTION(NS_SUCCEEDED(rv), "GetLength() Shouldn't fail!"); + + uint32_t colCount = ColCount(); + aCells->SetCapacity(selectedItemsCount * colCount); + aCells->AppendElements(selectedItemsCount * colCount); + + for (uint32_t selItemsIdx = 0, cellsIdx = 0; + selItemsIdx < selectedItemsCount; selItemsIdx++) { + + nsCOMPtr itemNode; + selectedItems->Item(selItemsIdx, getter_AddRefs(itemNode)); + nsCOMPtr item = + do_QueryInterface(itemNode); + + if (item) { + int32_t itemIdx = -1; + control->GetIndexOfItem(item, &itemIdx); + if (itemIdx >= 0) + for (uint32_t colIdx = 0; colIdx < colCount; colIdx++, cellsIdx++) + aCells->ElementAt(cellsIdx) = itemIdx * colCount + colIdx; + } + } +} + +void +XULListboxAccessible::SelectedColIndices(nsTArray* aCols) +{ + uint32_t selColCount = SelectedColCount(); + aCols->SetCapacity(selColCount); + + for (uint32_t colIdx = 0; colIdx < selColCount; colIdx++) + aCols->AppendElement(colIdx); +} + +void +XULListboxAccessible::SelectedRowIndices(nsTArray* aRows) +{ + nsCOMPtr control = + do_QueryInterface(mContent); + NS_ASSERTION(control, + "Doesn't implement nsIDOMXULMultiSelectControlElement."); + + nsCOMPtr selectedItems; + control->GetSelectedItems(getter_AddRefs(selectedItems)); + if (!selectedItems) + return; + + uint32_t rowCount = 0; + DebugOnly rv = selectedItems->GetLength(&rowCount); + NS_ASSERTION(NS_SUCCEEDED(rv), "GetLength() Shouldn't fail!"); + + if (!rowCount) + return; + + aRows->SetCapacity(rowCount); + aRows->AppendElements(rowCount); + + for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) { + nsCOMPtr itemNode; + selectedItems->Item(rowIdx, getter_AddRefs(itemNode)); + nsCOMPtr item = + do_QueryInterface(itemNode); + + if (item) { + int32_t itemIdx = -1; + control->GetIndexOfItem(item, &itemIdx); + if (itemIdx >= 0) + aRows->ElementAt(rowIdx) = itemIdx; + } + } +} + +void +XULListboxAccessible::SelectRow(uint32_t aRowIdx) +{ + nsCOMPtr control = + do_QueryInterface(mContent); + NS_ASSERTION(control, + "Doesn't implement nsIDOMXULMultiSelectControlElement."); + + nsCOMPtr item; + control->GetItemAtIndex(aRowIdx, getter_AddRefs(item)); + control->SelectItem(item); +} + +void +XULListboxAccessible::UnselectRow(uint32_t aRowIdx) +{ + nsCOMPtr control = + do_QueryInterface(mContent); + NS_ASSERTION(control, + "Doesn't implement nsIDOMXULMultiSelectControlElement."); + + nsCOMPtr item; + control->GetItemAtIndex(aRowIdx, getter_AddRefs(item)); + control->RemoveItemFromSelection(item); +} + +//////////////////////////////////////////////////////////////////////////////// +// XULListboxAccessible: Widgets + +bool +XULListboxAccessible::IsWidget() const +{ + return true; +} + +bool +XULListboxAccessible::IsActiveWidget() const +{ + if (IsAutoCompletePopup()) { + nsCOMPtr autoCompletePopupElm = + do_QueryInterface(mContent->GetParent()); + + if (autoCompletePopupElm) { + bool isOpen = false; + autoCompletePopupElm->GetPopupOpen(&isOpen); + return isOpen; + } + } + return FocusMgr()->HasDOMFocus(mContent); +} + +bool +XULListboxAccessible::AreItemsOperable() const +{ + if (IsAutoCompletePopup()) { + nsCOMPtr autoCompletePopupElm = + do_QueryInterface(mContent->GetParent()); + + if (autoCompletePopupElm) { + bool isOpen = false; + autoCompletePopupElm->GetPopupOpen(&isOpen); + return isOpen; + } + } + return true; +} + +Accessible* +XULListboxAccessible::ContainerWidget() const +{ + if (IsAutoCompletePopup()) { + // This works for XUL autocompletes. It doesn't work for HTML forms + // autocomplete because of potential crossprocess calls (when autocomplete + // lives in content process while popup lives in chrome process). If that's + // a problem then rethink Widgets interface. + nsCOMPtr menuListElm = + do_QueryInterface(mContent->GetParent()); + if (menuListElm) { + nsCOMPtr inputElm; + menuListElm->GetInputField(getter_AddRefs(inputElm)); + if (inputElm) { + nsCOMPtr inputNode = do_QueryInterface(inputElm); + if (inputNode) { + Accessible* input = + mDoc->GetAccessible(inputNode); + return input ? input->ContainerWidget() : nullptr; + } + } + } + } + return nullptr; +} + +//////////////////////////////////////////////////////////////////////////////// +// XULListitemAccessible +//////////////////////////////////////////////////////////////////////////////// + +XULListitemAccessible:: + XULListitemAccessible(nsIContent* aContent, DocAccessible* aDoc) : + XULMenuitemAccessible(aContent, aDoc) +{ + mIsCheckbox = mContent->AttrValueIs(kNameSpaceID_None, + nsGkAtoms::type, + nsGkAtoms::checkbox, + eCaseMatters); + mType = eXULListItemType; + + // Walk XBL anonymous children for list items. Overrides the flag value from + // base XULMenuitemAccessible class. + mStateFlags &= ~eNoXBLKids; +} + +XULListitemAccessible::~XULListitemAccessible() +{ +} + +NS_IMPL_ISUPPORTS_INHERITED0(XULListitemAccessible, Accessible) + +Accessible* +XULListitemAccessible::GetListAccessible() const +{ + if (IsDefunct()) + return nullptr; + + nsCOMPtr listItem = + do_QueryInterface(mContent); + if (!listItem) + return nullptr; + + nsCOMPtr list; + listItem->GetControl(getter_AddRefs(list)); + + nsCOMPtr listContent(do_QueryInterface(list)); + if (!listContent) + return nullptr; + + return mDoc->GetAccessible(listContent); +} + +//////////////////////////////////////////////////////////////////////////////// +// XULListitemAccessible Accessible + +void +XULListitemAccessible::Description(nsString& aDesc) +{ + AccessibleWrap::Description(aDesc); +} + +//////////////////////////////////////////////////////////////////////////////// +// XULListitemAccessible: Accessible + +/** + * If there is a Listcell as a child ( not anonymous ) use it, otherwise + * default to getting the name from GetXULName + */ +ENameValueFlag +XULListitemAccessible::NativeName(nsString& aName) +{ + nsIContent* childContent = mContent->GetFirstChild(); + if (childContent) { + if (childContent->NodeInfo()->Equals(nsGkAtoms::listcell, + kNameSpaceID_XUL)) { + childContent->GetAttr(kNameSpaceID_None, nsGkAtoms::label, aName); + return eNameOK; + } + } + + return Accessible::NativeName(aName); +} + +role +XULListitemAccessible::NativeRole() +{ + Accessible* list = GetListAccessible(); + if (!list) { + NS_ERROR("No list accessible for listitem accessible!"); + return roles::NOTHING; + } + + if (list->Role() == roles::TABLE) + return roles::ROW; + + if (mIsCheckbox) + return roles::CHECK_RICH_OPTION; + + if (mParent && mParent->Role() == roles::COMBOBOX_LIST) + return roles::COMBOBOX_OPTION; + + return roles::RICH_OPTION; +} + +uint64_t +XULListitemAccessible::NativeState() +{ + if (mIsCheckbox) + return XULMenuitemAccessible::NativeState(); + + uint64_t states = NativeInteractiveState(); + + nsCOMPtr listItem = + do_QueryInterface(mContent); + + if (listItem) { + bool isSelected; + listItem->GetSelected(&isSelected); + if (isSelected) + states |= states::SELECTED; + + if (FocusMgr()->IsFocused(this)) + states |= states::FOCUSED; + } + + return states; +} + +uint64_t +XULListitemAccessible::NativeInteractiveState() const +{ + return NativelyUnavailable() || (mParent && mParent->NativelyUnavailable()) ? + states::UNAVAILABLE : states::FOCUSABLE | states::SELECTABLE; +} + +void +XULListitemAccessible::ActionNameAt(uint8_t aIndex, nsAString& aName) +{ + if (aIndex == eAction_Click && mIsCheckbox) { + uint64_t states = NativeState(); + if (states & states::CHECKED) + aName.AssignLiteral("uncheck"); + else + aName.AssignLiteral("check"); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// XULListitemAccessible: Widgets + +Accessible* +XULListitemAccessible::ContainerWidget() const +{ + return Parent(); +} + + +//////////////////////////////////////////////////////////////////////////////// +// XULListCellAccessible +//////////////////////////////////////////////////////////////////////////////// + +XULListCellAccessible:: + XULListCellAccessible(nsIContent* aContent, DocAccessible* aDoc) : + HyperTextAccessibleWrap(aContent, aDoc) +{ + mGenericTypes |= eTableCell; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsISupports + +NS_IMPL_ISUPPORTS_INHERITED0(XULListCellAccessible, + HyperTextAccessible) + +//////////////////////////////////////////////////////////////////////////////// +// XULListCellAccessible: TableCell + +TableAccessible* +XULListCellAccessible::Table() const +{ + Accessible* thisRow = Parent(); + if (!thisRow || thisRow->Role() != roles::ROW) + return nullptr; + + Accessible* table = thisRow->Parent(); + if (!table || table->Role() != roles::TABLE) + return nullptr; + + return table->AsTable(); +} + +uint32_t +XULListCellAccessible::ColIdx() const +{ + Accessible* row = Parent(); + if (!row) + return 0; + + int32_t indexInRow = IndexInParent(); + uint32_t colIdx = 0; + for (int32_t idx = 0; idx < indexInRow; idx++) { + Accessible* cell = row->GetChildAt(idx); + roles::Role role = cell->Role(); + if (role == roles::CELL || role == roles::GRID_CELL || + role == roles::ROWHEADER || role == roles::COLUMNHEADER) + colIdx++; + } + + return colIdx; +} + +uint32_t +XULListCellAccessible::RowIdx() const +{ + Accessible* row = Parent(); + if (!row) + return 0; + + Accessible* table = row->Parent(); + if (!table) + return 0; + + int32_t indexInTable = row->IndexInParent(); + uint32_t rowIdx = 0; + for (int32_t idx = 0; idx < indexInTable; idx++) { + row = table->GetChildAt(idx); + if (row->Role() == roles::ROW) + rowIdx++; + } + + return rowIdx; +} + +void +XULListCellAccessible::ColHeaderCells(nsTArray* aCells) +{ + TableAccessible* table = Table(); + NS_ASSERTION(table, "cell not in a table!"); + if (!table) + return; + + // Get column header cell from XUL listhead. + Accessible* list = nullptr; + + Accessible* tableAcc = table->AsAccessible(); + uint32_t tableChildCount = tableAcc->ChildCount(); + for (uint32_t childIdx = 0; childIdx < tableChildCount; childIdx++) { + Accessible* child = tableAcc->GetChildAt(childIdx); + if (child->Role() == roles::LIST) { + list = child; + break; + } + } + + if (list) { + Accessible* headerCell = list->GetChildAt(ColIdx()); + if (headerCell) { + aCells->AppendElement(headerCell); + return; + } + } + + // No column header cell from XUL markup, try to get it from ARIA markup. + TableCellAccessible::ColHeaderCells(aCells); +} + +bool +XULListCellAccessible::Selected() +{ + TableAccessible* table = Table(); + NS_ENSURE_TRUE(table, false); // we expect to be in a listbox (table) + + return table->IsRowSelected(RowIdx()); +} + +//////////////////////////////////////////////////////////////////////////////// +// XULListCellAccessible. Accessible implementation + +role +XULListCellAccessible::NativeRole() +{ + return roles::CELL; +} + +already_AddRefed +XULListCellAccessible::NativeAttributes() +{ + nsCOMPtr attributes = + HyperTextAccessibleWrap::NativeAttributes(); + + // "table-cell-index" attribute + TableAccessible* table = Table(); + if (!table) // we expect to be in a listbox (table) + return attributes.forget(); + + nsAutoString stringIdx; + stringIdx.AppendInt(table->CellIndexAt(RowIdx(), ColIdx())); + nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx); + + return attributes.forget(); +} -- cgit v1.2.3