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/generic/ARIAGridAccessible-inl.h | 39 + accessible/generic/ARIAGridAccessible.cpp | 702 +++++++ accessible/generic/ARIAGridAccessible.h | 138 ++ accessible/generic/Accessible-inl.h | 135 ++ accessible/generic/Accessible.cpp | 2856 ++++++++++++++++++++++++++ accessible/generic/Accessible.h | 1269 ++++++++++++ accessible/generic/ApplicationAccessible.cpp | 201 ++ accessible/generic/ApplicationAccessible.h | 120 ++ accessible/generic/BaseAccessibles.cpp | 264 +++ accessible/generic/BaseAccessibles.h | 132 ++ accessible/generic/DocAccessible-inl.h | 189 ++ accessible/generic/DocAccessible.cpp | 2387 +++++++++++++++++++++ accessible/generic/DocAccessible.h | 718 +++++++ accessible/generic/FormControlAccessible.cpp | 193 ++ accessible/generic/FormControlAccessible.h | 76 + accessible/generic/HyperTextAccessible-inl.h | 180 ++ accessible/generic/HyperTextAccessible.cpp | 2230 ++++++++++++++++++++ accessible/generic/HyperTextAccessible.h | 592 ++++++ accessible/generic/ImageAccessible.cpp | 224 ++ accessible/generic/ImageAccessible.h | 87 + accessible/generic/OuterDocAccessible.cpp | 218 ++ accessible/generic/OuterDocAccessible.h | 61 + accessible/generic/RootAccessible.cpp | 732 +++++++ accessible/generic/RootAccessible.h | 92 + accessible/generic/TableAccessible.h | 187 ++ accessible/generic/TableCellAccessible.cpp | 67 + accessible/generic/TableCellAccessible.h | 70 + accessible/generic/TextLeafAccessible.cpp | 54 + accessible/generic/TextLeafAccessible.h | 51 + accessible/generic/moz.build | 70 + 30 files changed, 14334 insertions(+) create mode 100644 accessible/generic/ARIAGridAccessible-inl.h create mode 100644 accessible/generic/ARIAGridAccessible.cpp create mode 100644 accessible/generic/ARIAGridAccessible.h create mode 100644 accessible/generic/Accessible-inl.h create mode 100644 accessible/generic/Accessible.cpp create mode 100644 accessible/generic/Accessible.h create mode 100644 accessible/generic/ApplicationAccessible.cpp create mode 100644 accessible/generic/ApplicationAccessible.h create mode 100644 accessible/generic/BaseAccessibles.cpp create mode 100644 accessible/generic/BaseAccessibles.h create mode 100644 accessible/generic/DocAccessible-inl.h create mode 100644 accessible/generic/DocAccessible.cpp create mode 100644 accessible/generic/DocAccessible.h create mode 100644 accessible/generic/FormControlAccessible.cpp create mode 100644 accessible/generic/FormControlAccessible.h create mode 100644 accessible/generic/HyperTextAccessible-inl.h create mode 100644 accessible/generic/HyperTextAccessible.cpp create mode 100644 accessible/generic/HyperTextAccessible.h create mode 100644 accessible/generic/ImageAccessible.cpp create mode 100644 accessible/generic/ImageAccessible.h create mode 100644 accessible/generic/OuterDocAccessible.cpp create mode 100644 accessible/generic/OuterDocAccessible.h create mode 100644 accessible/generic/RootAccessible.cpp create mode 100644 accessible/generic/RootAccessible.h create mode 100644 accessible/generic/TableAccessible.h create mode 100644 accessible/generic/TableCellAccessible.cpp create mode 100644 accessible/generic/TableCellAccessible.h create mode 100644 accessible/generic/TextLeafAccessible.cpp create mode 100644 accessible/generic/TextLeafAccessible.h create mode 100644 accessible/generic/moz.build (limited to 'accessible/generic') diff --git a/accessible/generic/ARIAGridAccessible-inl.h b/accessible/generic/ARIAGridAccessible-inl.h new file mode 100644 index 000000000..bb2bc9705 --- /dev/null +++ b/accessible/generic/ARIAGridAccessible-inl.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_a11y_ARIAGridAccessible_inl_h__ +#define mozilla_a11y_ARIAGridAccessible_inl_h__ + +#include "ARIAGridAccessible.h" + +#include "AccIterator.h" +#include "nsAccUtils.h" + +namespace mozilla { +namespace a11y { + +inline int32_t +ARIAGridCellAccessible::RowIndexFor(Accessible* aRow) const +{ + Accessible* table = nsAccUtils::TableFor(aRow); + if (table) { + int32_t rowIdx = 0; + Accessible* row = nullptr; + AccIterator rowIter(table, filters::GetRow); + while ((row = rowIter.Next()) && row != aRow) + rowIdx++; + + if (row) + return rowIdx; + } + + return -1; +} + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/generic/ARIAGridAccessible.cpp b/accessible/generic/ARIAGridAccessible.cpp new file mode 100644 index 000000000..48de9bbf0 --- /dev/null +++ b/accessible/generic/ARIAGridAccessible.cpp @@ -0,0 +1,702 @@ +/* -*- Mode: C++; tab-width: 2; 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 "ARIAGridAccessible-inl.h" + +#include "Accessible-inl.h" +#include "AccIterator.h" +#include "nsAccUtils.h" +#include "Role.h" +#include "States.h" + +#include "nsIMutableArray.h" +#include "nsIPersistentProperties2.h" +#include "nsComponentManagerUtils.h" + +using namespace mozilla; +using namespace mozilla::a11y; + +//////////////////////////////////////////////////////////////////////////////// +// ARIAGridAccessible +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +// Constructor + +ARIAGridAccessible:: + ARIAGridAccessible(nsIContent* aContent, DocAccessible* aDoc) : + AccessibleWrap(aContent, aDoc) +{ +} + +NS_IMPL_ISUPPORTS_INHERITED0(ARIAGridAccessible, Accessible) + +//////////////////////////////////////////////////////////////////////////////// +// Table + +uint32_t +ARIAGridAccessible::ColCount() +{ + AccIterator rowIter(this, filters::GetRow); + Accessible* row = rowIter.Next(); + if (!row) + return 0; + + AccIterator cellIter(row, filters::GetCell); + Accessible* cell = nullptr; + + uint32_t colCount = 0; + while ((cell = cellIter.Next())) + colCount++; + + return colCount; +} + +uint32_t +ARIAGridAccessible::RowCount() +{ + uint32_t rowCount = 0; + AccIterator rowIter(this, filters::GetRow); + while (rowIter.Next()) + rowCount++; + + return rowCount; +} + +Accessible* +ARIAGridAccessible::CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) +{ + Accessible* row = GetRowAt(aRowIndex); + if (!row) + return nullptr; + + return GetCellInRowAt(row, aColumnIndex); +} + +bool +ARIAGridAccessible::IsColSelected(uint32_t aColIdx) +{ + if (IsARIARole(nsGkAtoms::table)) + return false; + + AccIterator rowIter(this, filters::GetRow); + Accessible* row = rowIter.Next(); + if (!row) + return false; + + do { + if (!nsAccUtils::IsARIASelected(row)) { + Accessible* cell = GetCellInRowAt(row, aColIdx); + if (!cell || !nsAccUtils::IsARIASelected(cell)) + return false; + } + } while ((row = rowIter.Next())); + + return true; +} + +bool +ARIAGridAccessible::IsRowSelected(uint32_t aRowIdx) +{ + if (IsARIARole(nsGkAtoms::table)) + return false; + + Accessible* row = GetRowAt(aRowIdx); + if(!row) + return false; + + if (!nsAccUtils::IsARIASelected(row)) { + AccIterator cellIter(row, filters::GetCell); + Accessible* cell = nullptr; + while ((cell = cellIter.Next())) { + if (!nsAccUtils::IsARIASelected(cell)) + return false; + } + } + + return true; +} + +bool +ARIAGridAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) +{ + if (IsARIARole(nsGkAtoms::table)) + return false; + + Accessible* row = GetRowAt(aRowIdx); + if(!row) + return false; + + if (!nsAccUtils::IsARIASelected(row)) { + Accessible* cell = GetCellInRowAt(row, aColIdx); + if (!cell || !nsAccUtils::IsARIASelected(cell)) + return false; + } + + return true; +} + +uint32_t +ARIAGridAccessible::SelectedCellCount() +{ + if (IsARIARole(nsGkAtoms::table)) + return 0; + + uint32_t count = 0, colCount = ColCount(); + + AccIterator rowIter(this, filters::GetRow); + Accessible* row = nullptr; + + while ((row = rowIter.Next())) { + if (nsAccUtils::IsARIASelected(row)) { + count += colCount; + continue; + } + + AccIterator cellIter(row, filters::GetCell); + Accessible* cell = nullptr; + + while ((cell = cellIter.Next())) { + if (nsAccUtils::IsARIASelected(cell)) + count++; + } + } + + return count; +} + +uint32_t +ARIAGridAccessible::SelectedColCount() +{ + if (IsARIARole(nsGkAtoms::table)) + return 0; + + uint32_t colCount = ColCount(); + if (!colCount) + return 0; + + AccIterator rowIter(this, filters::GetRow); + Accessible* row = rowIter.Next(); + if (!row) + return 0; + + nsTArray isColSelArray(colCount); + isColSelArray.AppendElements(colCount); + memset(isColSelArray.Elements(), true, colCount * sizeof(bool)); + + uint32_t selColCount = colCount; + do { + if (nsAccUtils::IsARIASelected(row)) + continue; + + AccIterator cellIter(row, filters::GetCell); + Accessible* cell = nullptr; + for (uint32_t colIdx = 0; + (cell = cellIter.Next()) && colIdx < colCount; colIdx++) + if (isColSelArray[colIdx] && !nsAccUtils::IsARIASelected(cell)) { + isColSelArray[colIdx] = false; + selColCount--; + } + } while ((row = rowIter.Next())); + + return selColCount; +} + +uint32_t +ARIAGridAccessible::SelectedRowCount() +{ + if (IsARIARole(nsGkAtoms::table)) + return 0; + + uint32_t count = 0; + + AccIterator rowIter(this, filters::GetRow); + Accessible* row = nullptr; + + while ((row = rowIter.Next())) { + if (nsAccUtils::IsARIASelected(row)) { + count++; + continue; + } + + AccIterator cellIter(row, filters::GetCell); + Accessible* cell = cellIter.Next(); + if (!cell) + continue; + + bool isRowSelected = true; + do { + if (!nsAccUtils::IsARIASelected(cell)) { + isRowSelected = false; + break; + } + } while ((cell = cellIter.Next())); + + if (isRowSelected) + count++; + } + + return count; +} + +void +ARIAGridAccessible::SelectedCells(nsTArray* aCells) +{ + if (IsARIARole(nsGkAtoms::table)) + return; + + AccIterator rowIter(this, filters::GetRow); + + Accessible* row = nullptr; + while ((row = rowIter.Next())) { + AccIterator cellIter(row, filters::GetCell); + Accessible* cell = nullptr; + + if (nsAccUtils::IsARIASelected(row)) { + while ((cell = cellIter.Next())) + aCells->AppendElement(cell); + + continue; + } + + while ((cell = cellIter.Next())) { + if (nsAccUtils::IsARIASelected(cell)) + aCells->AppendElement(cell); + } + } +} + +void +ARIAGridAccessible::SelectedCellIndices(nsTArray* aCells) +{ + if (IsARIARole(nsGkAtoms::table)) + return; + + uint32_t colCount = ColCount(); + + AccIterator rowIter(this, filters::GetRow); + Accessible* row = nullptr; + for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) { + if (nsAccUtils::IsARIASelected(row)) { + for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) + aCells->AppendElement(rowIdx * colCount + colIdx); + + continue; + } + + AccIterator cellIter(row, filters::GetCell); + Accessible* cell = nullptr; + for (uint32_t colIdx = 0; (cell = cellIter.Next()); colIdx++) { + if (nsAccUtils::IsARIASelected(cell)) + aCells->AppendElement(rowIdx * colCount + colIdx); + } + } +} + +void +ARIAGridAccessible::SelectedColIndices(nsTArray* aCols) +{ + if (IsARIARole(nsGkAtoms::table)) + return; + + uint32_t colCount = ColCount(); + if (!colCount) + return; + + AccIterator rowIter(this, filters::GetRow); + Accessible* row = rowIter.Next(); + if (!row) + return; + + nsTArray isColSelArray(colCount); + isColSelArray.AppendElements(colCount); + memset(isColSelArray.Elements(), true, colCount * sizeof(bool)); + + do { + if (nsAccUtils::IsARIASelected(row)) + continue; + + AccIterator cellIter(row, filters::GetCell); + Accessible* cell = nullptr; + for (uint32_t colIdx = 0; + (cell = cellIter.Next()) && colIdx < colCount; colIdx++) + if (isColSelArray[colIdx] && !nsAccUtils::IsARIASelected(cell)) { + isColSelArray[colIdx] = false; + } + } while ((row = rowIter.Next())); + + for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) + if (isColSelArray[colIdx]) + aCols->AppendElement(colIdx); +} + +void +ARIAGridAccessible::SelectedRowIndices(nsTArray* aRows) +{ + if (IsARIARole(nsGkAtoms::table)) + return; + + AccIterator rowIter(this, filters::GetRow); + Accessible* row = nullptr; + for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) { + if (nsAccUtils::IsARIASelected(row)) { + aRows->AppendElement(rowIdx); + continue; + } + + AccIterator cellIter(row, filters::GetCell); + Accessible* cell = cellIter.Next(); + if (!cell) + continue; + + bool isRowSelected = true; + do { + if (!nsAccUtils::IsARIASelected(cell)) { + isRowSelected = false; + break; + } + } while ((cell = cellIter.Next())); + + if (isRowSelected) + aRows->AppendElement(rowIdx); + } +} + +void +ARIAGridAccessible::SelectRow(uint32_t aRowIdx) +{ + if (IsARIARole(nsGkAtoms::table)) + return; + + AccIterator rowIter(this, filters::GetRow); + + Accessible* row = nullptr; + for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) { + DebugOnly rv = SetARIASelected(row, rowIdx == aRowIdx); + NS_ASSERTION(NS_SUCCEEDED(rv), "SetARIASelected() Shouldn't fail!"); + } +} + +void +ARIAGridAccessible::SelectCol(uint32_t aColIdx) +{ + if (IsARIARole(nsGkAtoms::table)) + return; + + AccIterator rowIter(this, filters::GetRow); + + Accessible* row = nullptr; + while ((row = rowIter.Next())) { + // Unselect all cells in the row. + DebugOnly rv = SetARIASelected(row, false); + NS_ASSERTION(NS_SUCCEEDED(rv), "SetARIASelected() Shouldn't fail!"); + + // Select cell at the column index. + Accessible* cell = GetCellInRowAt(row, aColIdx); + if (cell) + SetARIASelected(cell, true); + } +} + +void +ARIAGridAccessible::UnselectRow(uint32_t aRowIdx) +{ + if (IsARIARole(nsGkAtoms::table)) + return; + + Accessible* row = GetRowAt(aRowIdx); + if (row) + SetARIASelected(row, false); +} + +void +ARIAGridAccessible::UnselectCol(uint32_t aColIdx) +{ + if (IsARIARole(nsGkAtoms::table)) + return; + + AccIterator rowIter(this, filters::GetRow); + + Accessible* row = nullptr; + while ((row = rowIter.Next())) { + Accessible* cell = GetCellInRowAt(row, aColIdx); + if (cell) + SetARIASelected(cell, false); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Protected + +Accessible* +ARIAGridAccessible::GetRowAt(int32_t aRow) +{ + int32_t rowIdx = aRow; + + AccIterator rowIter(this, filters::GetRow); + + Accessible* row = rowIter.Next(); + while (rowIdx != 0 && (row = rowIter.Next())) + rowIdx--; + + return row; +} + +Accessible* +ARIAGridAccessible::GetCellInRowAt(Accessible* aRow, int32_t aColumn) +{ + int32_t colIdx = aColumn; + + AccIterator cellIter(aRow, filters::GetCell); + Accessible* cell = cellIter.Next(); + while (colIdx != 0 && (cell = cellIter.Next())) + colIdx--; + + return cell; +} + +nsresult +ARIAGridAccessible::SetARIASelected(Accessible* aAccessible, + bool aIsSelected, bool aNotify) +{ + if (IsARIARole(nsGkAtoms::table)) + return NS_OK; + + nsIContent *content = aAccessible->GetContent(); + NS_ENSURE_STATE(content); + + nsresult rv = NS_OK; + if (aIsSelected) + rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected, + NS_LITERAL_STRING("true"), aNotify); + else + rv = content->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_selected, + NS_LITERAL_STRING("false"), aNotify); + + NS_ENSURE_SUCCESS(rv, rv); + + // No "smart" select/unselect for internal call. + if (!aNotify) + return NS_OK; + + // If row or cell accessible was selected then we're able to not bother about + // selection of its cells or its row because our algorithm is row oriented, + // i.e. we check selection on row firstly and then on cells. + if (aIsSelected) + return NS_OK; + + roles::Role role = aAccessible->Role(); + + // If the given accessible is row that was unselected then remove + // aria-selected from cell accessible. + if (role == roles::ROW) { + AccIterator cellIter(aAccessible, filters::GetCell); + Accessible* cell = nullptr; + + while ((cell = cellIter.Next())) { + rv = SetARIASelected(cell, false, false); + NS_ENSURE_SUCCESS(rv, rv); + } + return NS_OK; + } + + // If the given accessible is cell that was unselected and its row is selected + // then remove aria-selected from row and put aria-selected on + // siblings cells. + if (role == roles::GRID_CELL || role == roles::ROWHEADER || + role == roles::COLUMNHEADER) { + Accessible* row = aAccessible->Parent(); + + if (row && row->Role() == roles::ROW && + nsAccUtils::IsARIASelected(row)) { + rv = SetARIASelected(row, false, false); + NS_ENSURE_SUCCESS(rv, rv); + + AccIterator cellIter(row, filters::GetCell); + Accessible* cell = nullptr; + while ((cell = cellIter.Next())) { + if (cell != aAccessible) { + rv = SetARIASelected(cell, true, false); + NS_ENSURE_SUCCESS(rv, rv); + } + } + } + } + + return NS_OK; +} + + +//////////////////////////////////////////////////////////////////////////////// +// ARIARowAccessible +//////////////////////////////////////////////////////////////////////////////// + +ARIARowAccessible:: + ARIARowAccessible(nsIContent* aContent, DocAccessible* aDoc) : + AccessibleWrap(aContent, aDoc) +{ + mGenericTypes |= eTableRow; +} + +NS_IMPL_ISUPPORTS_INHERITED0(ARIARowAccessible, Accessible) + +GroupPos +ARIARowAccessible::GroupPosition() +{ + int32_t count = 0, index = 0; + Accessible* table = nsAccUtils::TableFor(this); + if (table && nsCoreUtils::GetUIntAttr(table->GetContent(), + nsGkAtoms::aria_rowcount, &count) && + nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_rowindex, &index)) { + return GroupPos(0, index, count); + } + + return AccessibleWrap::GroupPosition(); +} + + +//////////////////////////////////////////////////////////////////////////////// +// ARIAGridCellAccessible +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +// Constructor + +ARIAGridCellAccessible:: + ARIAGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc) : + HyperTextAccessibleWrap(aContent, aDoc) +{ + mGenericTypes |= eTableCell; +} + +NS_IMPL_ISUPPORTS_INHERITED0(ARIAGridCellAccessible, HyperTextAccessible) + +//////////////////////////////////////////////////////////////////////////////// +// TableCell + +TableAccessible* +ARIAGridCellAccessible::Table() const +{ + Accessible* table = nsAccUtils::TableFor(Row()); + return table ? table->AsTable() : nullptr; +} + +uint32_t +ARIAGridCellAccessible::ColIdx() const +{ + Accessible* row = Row(); + 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 +ARIAGridCellAccessible::RowIdx() const +{ + return RowIndexFor(Row()); +} + +bool +ARIAGridCellAccessible::Selected() +{ + Accessible* row = Row(); + if (!row) + return false; + + return nsAccUtils::IsARIASelected(row) || nsAccUtils::IsARIASelected(this); +} + +//////////////////////////////////////////////////////////////////////////////// +// Accessible + +void +ARIAGridCellAccessible::ApplyARIAState(uint64_t* aState) const +{ + HyperTextAccessibleWrap::ApplyARIAState(aState); + + // Return if the gridcell has aria-selected="true". + if (*aState & states::SELECTED) + return; + + // Check aria-selected="true" on the row. + Accessible* row = Parent(); + if (!row || row->Role() != roles::ROW) + return; + + nsIContent *rowContent = row->GetContent(); + if (nsAccUtils::HasDefinedARIAToken(rowContent, + nsGkAtoms::aria_selected) && + !rowContent->AttrValueIs(kNameSpaceID_None, + nsGkAtoms::aria_selected, + nsGkAtoms::_false, eCaseMatters)) + *aState |= states::SELECTABLE | states::SELECTED; +} + +already_AddRefed +ARIAGridCellAccessible::NativeAttributes() +{ + nsCOMPtr attributes = + HyperTextAccessibleWrap::NativeAttributes(); + + // Expose "table-cell-index" attribute. + Accessible* thisRow = Row(); + if (!thisRow) + return attributes.forget(); + + int32_t colIdx = 0, colCount = 0; + uint32_t childCount = thisRow->ChildCount(); + for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) { + Accessible* child = thisRow->GetChildAt(childIdx); + if (child == this) + colIdx = colCount; + + roles::Role role = child->Role(); + if (role == roles::CELL || role == roles::GRID_CELL || + role == roles::ROWHEADER || role == roles::COLUMNHEADER) + colCount++; + } + + int32_t rowIdx = RowIndexFor(thisRow); + + nsAutoString stringIdx; + stringIdx.AppendInt(rowIdx * colCount + colIdx); + nsAccUtils::SetAccAttr(attributes, nsGkAtoms::tableCellIndex, stringIdx); + +#ifdef DEBUG + nsAutoString unused; + attributes->SetStringProperty(NS_LITERAL_CSTRING("cppclass"), + NS_LITERAL_STRING("ARIAGridCellAccessible"), + unused); +#endif + + return attributes.forget(); +} + +GroupPos +ARIAGridCellAccessible::GroupPosition() +{ + int32_t count = 0, index = 0; + TableAccessible* table = Table(); + if (table && nsCoreUtils::GetUIntAttr(table->AsAccessible()->GetContent(), + nsGkAtoms::aria_colcount, &count) && + nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_colindex, &index)) { + return GroupPos(0, index, count); + } + + return GroupPos(); +} diff --git a/accessible/generic/ARIAGridAccessible.h b/accessible/generic/ARIAGridAccessible.h new file mode 100644 index 000000000..c9a36cc6e --- /dev/null +++ b/accessible/generic/ARIAGridAccessible.h @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#ifndef MOZILLA_A11Y_ARIAGridAccessible_h_ +#define MOZILLA_A11Y_ARIAGridAccessible_h_ + +#include "HyperTextAccessibleWrap.h" +#include "TableAccessible.h" +#include "TableCellAccessible.h" + +namespace mozilla { +namespace a11y { + +/** + * Accessible for ARIA grid and treegrid. + */ +class ARIAGridAccessible : public AccessibleWrap, + public TableAccessible +{ +public: + ARIAGridAccessible(nsIContent* aContent, DocAccessible* aDoc); + + NS_DECL_ISUPPORTS_INHERITED + + // Accessible + virtual TableAccessible* AsTable() override { return this; } + + // TableAccessible + virtual uint32_t ColCount() override; + virtual uint32_t RowCount() override; + virtual Accessible* CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) override; + virtual bool IsColSelected(uint32_t aColIdx) override; + virtual bool IsRowSelected(uint32_t aRowIdx) override; + virtual bool IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) override; + virtual uint32_t SelectedCellCount() override; + virtual uint32_t SelectedColCount() override; + virtual uint32_t SelectedRowCount() override; + virtual void SelectedCells(nsTArray* aCells) override; + virtual void SelectedCellIndices(nsTArray* aCells) override; + virtual void SelectedColIndices(nsTArray* aCols) override; + virtual void SelectedRowIndices(nsTArray* aRows) override; + virtual void SelectCol(uint32_t aColIdx) override; + virtual void SelectRow(uint32_t aRowIdx) override; + virtual void UnselectCol(uint32_t aColIdx) override; + virtual void UnselectRow(uint32_t aRowIdx) override; + virtual Accessible* AsAccessible() override { return this; } + +protected: + virtual ~ARIAGridAccessible() {} + + /** + * Return row accessible at the given row index. + */ + Accessible* GetRowAt(int32_t aRow); + + /** + * Return cell accessible at the given column index in the row. + */ + Accessible* GetCellInRowAt(Accessible* aRow, int32_t aColumn); + + /** + * Set aria-selected attribute value on DOM node of the given accessible. + * + * @param aAccessible [in] accessible + * @param aIsSelected [in] new value of aria-selected attribute + * @param aNotify [in, optional] specifies if DOM should be notified + * about attribute change (used internally). + */ + nsresult SetARIASelected(Accessible* aAccessible, bool aIsSelected, + bool aNotify = true); +}; + + +/** + * Accessible for ARIA row. + */ +class ARIARowAccessible : public AccessibleWrap +{ +public: + ARIARowAccessible(nsIContent* aContent, DocAccessible* aDoc); + + NS_DECL_ISUPPORTS_INHERITED + + // Accessible + virtual mozilla::a11y::GroupPos GroupPosition() override; + +protected: + virtual ~ARIARowAccessible() {} +}; + + +/** + * Accessible for ARIA gridcell and rowheader/columnheader. + */ +class ARIAGridCellAccessible : public HyperTextAccessibleWrap, + public TableCellAccessible +{ +public: + ARIAGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc); + + NS_DECL_ISUPPORTS_INHERITED + + // Accessible + virtual TableCellAccessible* AsTableCell() override { return this; } + virtual void ApplyARIAState(uint64_t* aState) const override; + virtual already_AddRefed NativeAttributes() override; + virtual mozilla::a11y::GroupPos GroupPosition() override; + +protected: + virtual ~ARIAGridCellAccessible() {} + + /** + * Return a containing row. + */ + Accessible* Row() const + { + Accessible* row = Parent(); + return row && row->IsTableRow() ? row : nullptr; + } + + /** + * Return index of the given row. + */ + int32_t RowIndexFor(Accessible* aRow) const; + + // TableCellAccessible + virtual TableAccessible* Table() const override; + virtual uint32_t ColIdx() const override; + virtual uint32_t RowIdx() const override; + virtual bool Selected() override; +}; + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/generic/Accessible-inl.h b/accessible/generic/Accessible-inl.h new file mode 100644 index 000000000..f80056479 --- /dev/null +++ b/accessible/generic/Accessible-inl.h @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* 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/. */ + +#ifndef mozilla_a11y_Accessible_inl_h_ +#define mozilla_a11y_Accessible_inl_h_ + +#include "DocAccessible.h" +#include "ARIAMap.h" +#include "nsCoreUtils.h" + +#ifdef A11Y_LOG +#include "Logging.h" +#endif + +namespace mozilla { +namespace a11y { + +inline mozilla::a11y::role +Accessible::Role() +{ + const nsRoleMapEntry* roleMapEntry = ARIARoleMap(); + if (!roleMapEntry || roleMapEntry->roleRule != kUseMapRole) + return ARIATransformRole(NativeRole()); + + return ARIATransformRole(roleMapEntry->role); +} + +inline bool +Accessible::HasARIARole() const +{ + return mRoleMapEntryIndex != aria::NO_ROLE_MAP_ENTRY_INDEX; +} + +inline bool +Accessible::IsARIARole(nsIAtom* aARIARole) const +{ + const nsRoleMapEntry* roleMapEntry = ARIARoleMap(); + return roleMapEntry && roleMapEntry->Is(aARIARole); +} + +inline bool +Accessible::HasStrongARIARole() const +{ + const nsRoleMapEntry* roleMapEntry = ARIARoleMap(); + return roleMapEntry && roleMapEntry->roleRule == kUseMapRole; +} + +inline const nsRoleMapEntry* +Accessible::ARIARoleMap() const +{ + return aria::GetRoleMapFromIndex(mRoleMapEntryIndex); +} + +inline mozilla::a11y::role +Accessible::ARIARole() +{ + const nsRoleMapEntry* roleMapEntry = ARIARoleMap(); + if (!roleMapEntry || roleMapEntry->roleRule != kUseMapRole) + return mozilla::a11y::roles::NOTHING; + + return ARIATransformRole(roleMapEntry->role); +} + +inline void +Accessible::SetRoleMapEntry(const nsRoleMapEntry* aRoleMapEntry) +{ + mRoleMapEntryIndex = aria::GetIndexFromRoleMap(aRoleMapEntry); +} + +inline bool +Accessible::IsSearchbox() const +{ + const nsRoleMapEntry* roleMapEntry = ARIARoleMap(); + return (roleMapEntry && roleMapEntry->Is(nsGkAtoms::searchbox)) || + (mContent->IsHTMLElement(nsGkAtoms::input) && + mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type, + nsGkAtoms::textInputType, eCaseMatters)); +} + +inline bool +Accessible::HasGenericType(AccGenericType aType) const +{ + const nsRoleMapEntry* roleMapEntry = ARIARoleMap(); + return (mGenericTypes & aType) || + (roleMapEntry && roleMapEntry->IsOfType(aType)); +} + +inline bool +Accessible::HasNumericValue() const +{ + if (mStateFlags & eHasNumericValue) + return true; + + const nsRoleMapEntry* roleMapEntry = ARIARoleMap(); + return roleMapEntry && roleMapEntry->valueRule != eNoValue; +} + +inline void +Accessible::ScrollTo(uint32_t aHow) const +{ + if (mContent) + nsCoreUtils::ScrollTo(mDoc->PresShell(), mContent, aHow); +} + +inline bool +Accessible::InsertAfter(Accessible* aNewChild, Accessible* aRefChild) +{ + MOZ_ASSERT(aNewChild, "No new child to insert"); + + if (aRefChild && aRefChild->Parent() != this) { +#ifdef A11Y_LOG + logging::TreeInfo("broken accessible tree", 0, + "parent", this, "prev sibling parent", + aRefChild->Parent(), "child", aNewChild, nullptr); + if (logging::IsEnabled(logging::eVerbose)) { + logging::Tree("TREE", "Document tree", mDoc); + logging::DOMTree("TREE", "DOM document tree", mDoc); + } +#endif + MOZ_ASSERT_UNREACHABLE("Broken accessible tree"); + mDoc->UnbindFromDocument(aNewChild); + return false; + } + + return InsertChildAt(aRefChild ? aRefChild->IndexInParent() + 1 : 0, + aNewChild); +} + +} // namespace a11y +} // namespace mozilla + +#endif diff --git a/accessible/generic/Accessible.cpp b/accessible/generic/Accessible.cpp new file mode 100644 index 000000000..7ff2f8283 --- /dev/null +++ b/accessible/generic/Accessible.cpp @@ -0,0 +1,2856 @@ +/* -*- Mode: C++; tab-width: 2; 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 "Accessible-inl.h" + +#include "nsIXBLAccessible.h" + +#include "EmbeddedObjCollector.h" +#include "AccGroupInfo.h" +#include "AccIterator.h" +#include "nsAccUtils.h" +#include "nsAccessibilityService.h" +#include "ApplicationAccessible.h" +#include "NotificationController.h" +#include "nsEventShell.h" +#include "nsTextEquivUtils.h" +#include "DocAccessibleChild.h" +#include "EventTree.h" +#include "Relation.h" +#include "Role.h" +#include "RootAccessible.h" +#include "States.h" +#include "StyleInfo.h" +#include "TableAccessible.h" +#include "TableCellAccessible.h" +#include "TreeWalker.h" + +#include "nsIDOMElement.h" +#include "nsIDOMNodeFilter.h" +#include "nsIDOMHTMLElement.h" +#include "nsIDOMKeyEvent.h" +#include "nsIDOMTreeWalker.h" +#include "nsIDOMXULButtonElement.h" +#include "nsIDOMXULDocument.h" +#include "nsIDOMXULElement.h" +#include "nsIDOMXULLabelElement.h" +#include "nsIDOMXULSelectCntrlEl.h" +#include "nsIDOMXULSelectCntrlItemEl.h" +#include "nsPIDOMWindow.h" + +#include "nsIDocument.h" +#include "nsIContent.h" +#include "nsIForm.h" +#include "nsIFormControl.h" + +#include "nsDeckFrame.h" +#include "nsLayoutUtils.h" +#include "nsIPresShell.h" +#include "nsIStringBundle.h" +#include "nsPresContext.h" +#include "nsIFrame.h" +#include "nsView.h" +#include "nsIDocShellTreeItem.h" +#include "nsIScrollableFrame.h" +#include "nsFocusManager.h" + +#include "nsXPIDLString.h" +#include "nsUnicharUtils.h" +#include "nsReadableUtils.h" +#include "prdtoa.h" +#include "nsIAtom.h" +#include "nsIURI.h" +#include "nsArrayUtils.h" +#include "nsIMutableArray.h" +#include "nsIObserverService.h" +#include "nsIServiceManager.h" +#include "nsWhitespaceTokenizer.h" +#include "nsAttrName.h" + +#ifdef DEBUG +#include "nsIDOMCharacterData.h" +#endif + +#include "mozilla/Assertions.h" +#include "mozilla/BasicEvents.h" +#include "mozilla/EventStates.h" +#include "mozilla/FloatingPoint.h" +#include "mozilla/MouseEvents.h" +#include "mozilla/Unused.h" +#include "mozilla/Preferences.h" +#include "mozilla/dom/CanvasRenderingContext2D.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/HTMLCanvasElement.h" +#include "mozilla/dom/HTMLBodyElement.h" +#include "mozilla/dom/TreeWalker.h" + +using namespace mozilla; +using namespace mozilla::a11y; + + +//////////////////////////////////////////////////////////////////////////////// +// Accessible: nsISupports and cycle collection + +NS_IMPL_CYCLE_COLLECTION_CLASS(Accessible) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Accessible) + tmp->Shutdown(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Accessible) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent, mDoc) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Accessible) + if (aIID.Equals(NS_GET_IID(Accessible))) + foundInterface = this; + else + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, Accessible) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(Accessible) +NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_DESTROY(Accessible, LastRelease()) + +Accessible::Accessible(nsIContent* aContent, DocAccessible* aDoc) : + mContent(aContent), mDoc(aDoc), + mParent(nullptr), mIndexInParent(-1), + mRoleMapEntryIndex(aria::NO_ROLE_MAP_ENTRY_INDEX), + mStateFlags(0), mContextFlags(0), mType(0), mGenericTypes(0), + mReorderEventTarget(false), mShowEventTarget(false), mHideEventTarget(false) +{ + mBits.groupInfo = nullptr; + mInt.mIndexOfEmbeddedChild = -1; +} + +Accessible::~Accessible() +{ + NS_ASSERTION(!mDoc, "LastRelease was never called!?!"); +} + +ENameValueFlag +Accessible::Name(nsString& aName) +{ + aName.Truncate(); + + if (!HasOwnContent()) + return eNameOK; + + ARIAName(aName); + if (!aName.IsEmpty()) + return eNameOK; + + nsCOMPtr xblAccessible(do_QueryInterface(mContent)); + if (xblAccessible) { + xblAccessible->GetAccessibleName(aName); + if (!aName.IsEmpty()) + return eNameOK; + } + + ENameValueFlag nameFlag = NativeName(aName); + if (!aName.IsEmpty()) + return nameFlag; + + // In the end get the name from tooltip. + if (mContent->IsHTMLElement()) { + if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aName)) { + aName.CompressWhitespace(); + return eNameFromTooltip; + } + } else if (mContent->IsXULElement()) { + if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aName)) { + aName.CompressWhitespace(); + return eNameFromTooltip; + } + } else if (mContent->IsSVGElement()) { + // If user agents need to choose among multiple ‘desc’ or ‘title’ elements + // for processing, the user agent shall choose the first one. + for (nsIContent* childElm = mContent->GetFirstChild(); childElm; + childElm = childElm->GetNextSibling()) { + if (childElm->IsSVGElement(nsGkAtoms::desc)) { + nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, &aName); + return eNameFromTooltip; + } + } + } + + if (nameFlag != eNoNameOnPurpose) + aName.SetIsVoid(true); + + return nameFlag; +} + +void +Accessible::Description(nsString& aDescription) +{ + // There are 4 conditions that make an accessible have no accDescription: + // 1. it's a text node; or + // 2. It has no DHTML describedby property + // 3. it doesn't have an accName; or + // 4. its title attribute already equals to its accName nsAutoString name; + + if (!HasOwnContent() || mContent->IsNodeOfType(nsINode::eTEXT)) + return; + + nsTextEquivUtils:: + GetTextEquivFromIDRefs(this, nsGkAtoms::aria_describedby, + aDescription); + + if (aDescription.IsEmpty()) { + NativeDescription(aDescription); + + if (aDescription.IsEmpty()) { + // Keep the Name() method logic. + if (mContent->IsHTMLElement()) { + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aDescription); + } else if (mContent->IsXULElement()) { + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aDescription); + } else if (mContent->IsSVGElement()) { + for (nsIContent* childElm = mContent->GetFirstChild(); childElm; + childElm = childElm->GetNextSibling()) { + if (childElm->IsSVGElement(nsGkAtoms::desc)) { + nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, + &aDescription); + break; + } + } + } + } + } + + if (!aDescription.IsEmpty()) { + aDescription.CompressWhitespace(); + nsAutoString name; + Name(name); + // Don't expose a description if it is the same as the name. + if (aDescription.Equals(name)) + aDescription.Truncate(); + } +} + +KeyBinding +Accessible::AccessKey() const +{ + if (!HasOwnContent()) + return KeyBinding(); + + uint32_t key = nsCoreUtils::GetAccessKeyFor(mContent); + if (!key && mContent->IsElement()) { + Accessible* label = nullptr; + + // Copy access key from label node. + if (mContent->IsHTMLElement()) { + // Unless it is labeled via an ancestor