Bug 1832228 part 1: Remove ARIAGridAccessible, ARIARowAccessible and most of ARIAGridCellAccessible. r=nlapre

We now use CachedTableAccessible for ARIA tables and grids, so most of the code in the ARIA table classes was unused.

1. Remove ARIAGridAccessible and ARIARowAccessible completely.
2. ARIAGridCellAccessible no longer derives from TableCellAccessible.
3. Remove most of ARIAGridCellAccessible.
4. We still use ARIAGridCellAccessible to differentiate between valid and invalid cells. Valid cells create an ARIAGridCellAccessible and ARIAGridCellAccessible::IsTableCell() returns true due to mGenericTypes. Invalid cells don't get an ARIAGridCellAccessible, so IsTableCell() returns false on those.
5. We also keep the code in ARIAGridCellAccessible to expose some states and attributes.
6. The code for creating ARIAGridCellAccessible in CreateAccessible has been refactored, both for simplification and to fix bugs. display: contents tables now properly get the table and table cell interfaces; i.e. IsTable() and IsTableCell() return true when appropriate. Walking non-generic ancestors should fix ARIA tables with intervening generics, though this will be dealt with fully in a separate bug.

Differential Revision: https://phabricator.services.mozilla.com/D179801
This commit is contained in:
James Teh 2023-06-08 09:50:28 +00:00
Родитель 9ecdad92e8
Коммит 220f6dfece
8 изменённых файлов: 95 добавлений и 650 удалений

Просмотреть файл

@ -106,6 +106,10 @@ class nsAccUtils {
static Accessible* TableFor(Accessible* aRow);
static LocalAccessible* TableFor(LocalAccessible* aRow);
static const LocalAccessible* TableFor(const LocalAccessible* aAcc) {
return TableFor(const_cast<LocalAccessible*>(aAcc));
}
/**
* Return true if the DOM node of a given accessible has a given attribute
* with a value of "true".

Просмотреть файл

@ -29,6 +29,7 @@
#include "nsDOMTokenList.h"
#include "nsCRT.h"
#include "nsEventShell.h"
#include "nsGkAtoms.h"
#include "nsIFrameInlines.h"
#include "nsServiceManagerUtils.h"
#include "nsTextFormatter.h"
@ -69,6 +70,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/PresShell.h"
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Services.h"
#include "XULAlertAccessible.h"
@ -98,39 +100,38 @@ using namespace mozilla::dom;
////////////////////////////////////////////////////////////////////////////////
/**
* Return true if the role map entry is an ARIA table part.
* If the element has an ARIA attribute that requires a specific Accessible
* class, create and return it. Otherwise, return null.
*/
static bool IsARIATablePart(const nsRoleMapEntry* aRoleMapEntry) {
return aRoleMapEntry &&
(aRoleMapEntry->accTypes & (eTableCell | eTableRow | eTable));
}
/**
* Create and return an Accessible for the given content depending on which
* table part we think it is.
*/
static LocalAccessible* CreateARIATablePartAcc(
static LocalAccessible* MaybeCreateSpecificARIAAccessible(
const nsRoleMapEntry* aRoleMapEntry, const LocalAccessible* aContext,
nsIContent* aContent, DocAccessible* aDocument) {
// In case of ARIA grid or table use table-specific classes if it's not
// native table based.
if ((aRoleMapEntry->accTypes & eTableCell)) {
if (aContext->IsTableRow()) {
if (aRoleMapEntry && aRoleMapEntry->accTypes & eTableCell) {
if (aContent->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th) &&
aContext->IsHTMLTableRow()) {
// Don't use ARIAGridCellAccessible for a valid td/th because
// HTMLTableCellAccessible can provide additional info; e.g. row/col span
// from the layout engine.
return nullptr;
}
// A cell must be in a row.
if (aContext->Role() != roles::ROW) {
return nullptr;
}
// That row must be in a table, though there may be an intervening rowgroup.
Accessible* parent = aContext->GetNonGenericParent();
if (!parent) {
return nullptr;
}
if (!parent->IsTable() && parent->Role() == roles::GROUPING) {
parent = parent->GetNonGenericParent();
if (!parent) {
return nullptr;
}
}
if (parent->IsTable()) {
return new ARIAGridCellAccessible(aContent, aDocument);
}
} else if (aRoleMapEntry->IsOfType(eTableRow)) {
if (aContext->IsTable() ||
// There can be an Accessible between a row and its table, but it
// can only be a row group or a generic container. This is
// consistent with Filters::GetRow and CachedTableAccessible's
// TablePartRule.
((aContext->Role() == roles::GROUPING ||
(aContext->IsGenericHyperText() && !aContext->ARIARoleMap())) &&
aContext->LocalParent() && aContext->LocalParent()->IsTable())) {
return new ARIARowAccessible(aContent, aDocument);
}
} else if (aRoleMapEntry->IsOfType(eTable)) {
return new ARIAGridAccessible(aContent, aDocument);
}
return nullptr;
}
@ -1090,28 +1091,25 @@ LocalAccessible* nsAccessibilityService::CreateAccessible(
} else if (nsCoreUtils::CanCreateAccessibleWithoutFrame(content)) {
// display:contents element doesn't have a frame, but retains the
// semantics. All its children are unaffected.
const MarkupMapInfo* markupMap = GetMarkupMapInfoFor(content);
RefPtr<LocalAccessible> newAcc;
if (markupMap && markupMap->new_func) {
newAcc = markupMap->new_func(content->AsElement(), aContext);
const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(content->AsElement());
RefPtr<LocalAccessible> newAcc = MaybeCreateSpecificARIAAccessible(
roleMapEntry, aContext, content, document);
const MarkupMapInfo* markupMap = nullptr;
if (!newAcc) {
markupMap = GetMarkupMapInfoFor(content);
if (markupMap && markupMap->new_func) {
newAcc = markupMap->new_func(content->AsElement(), aContext);
}
}
// Check whether this element has an ARIA role or attribute that requires
// us to create an Accessible.
const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(content->AsElement());
const bool hasNonPresentationalARIARole =
roleMapEntry && !roleMapEntry->Is(nsGkAtoms::presentation) &&
!roleMapEntry->Is(nsGkAtoms::none);
if (!newAcc && (hasNonPresentationalARIARole ||
AttributesMustBeAccessible(content, document))) {
// If this element is an ARIA table part, create the proper table part
// Accessible. Otherwise, create a generic HyperTextAccessible.
if (IsARIATablePart(roleMapEntry)) {
newAcc =
CreateARIATablePartAcc(roleMapEntry, aContext, content, document);
} else {
newAcc = new HyperTextAccessibleWrap(content, document);
}
newAcc = new HyperTextAccessibleWrap(content, document);
}
// If there's still no Accessible but we do have an entry in the markup
@ -1246,14 +1244,14 @@ LocalAccessible* nsAccessibilityService::CreateAccessible(
}
if (!newAcc && content->IsHTMLElement()) { // HTML accessibles
const bool isARIATablePart = IsARIATablePart(roleMapEntry);
// We should always use OuterDocAccessible for OuterDocs, even if there's a
// specific ARIA class we would otherwise use.
if (frame->AccessibleType() != eOuterDocType) {
newAcc = MaybeCreateSpecificARIAAccessible(roleMapEntry, aContext,
content, document);
}
if (!isARIATablePart || frame->AccessibleType() == eHTMLTableCellType ||
frame->AccessibleType() == eHTMLTableRowType ||
frame->AccessibleType() == eHTMLTableType ||
// We should always use OuterDocAccessible for OuterDocs, even for
// ARIA table roles.
frame->AccessibleType() == eOuterDocType) {
if (!newAcc) {
// Prefer to use markup to decide if and what kind of accessible to
// create,
const MarkupMapInfo* markupMap =
@ -1267,15 +1265,6 @@ LocalAccessible* nsAccessibilityService::CreateAccessible(
}
}
// In case of ARIA grid or table use table-specific classes if it's not
// native table based.
if (isARIATablePart && (!newAcc || newAcc->IsGenericHyperText())) {
if (LocalAccessible* tablePartAcc = CreateARIATablePartAcc(
roleMapEntry, aContext, content, document)) {
newAcc = tablePartAcc;
}
}
// If table has strong ARIA role then all table descendants shouldn't
// expose their native roles.
if (!roleMapEntry && newAcc && aContext->HasStrongARIARole()) {

Просмотреть файл

@ -475,20 +475,19 @@ class Accessible {
bool IsDoc() const { return HasGenericType(eDocument); }
/**
* Note: The eTable* types defined in the ARIA map are used in
* nsAccessibilityService::CreateAccessible to determine which ARIAGrid*
* classes to use for accessible object creation. However, an invalid table
* structure might cause these classes not to be used after all.
*
* To make sure we're really dealing with a table/row/cell, only check the
* generic type defined by the class, not the type defined in the ARIA map.
*/
bool IsTableRow() const { return mGenericTypes & eTableRow; }
bool IsTableRow() const { return HasGenericType(eTableRow); }
bool IsTableCell() const { return mGenericTypes & eTableCell; }
bool IsTableCell() const {
// The eTableCell type defined in the ARIA map is used in
// nsAccessibilityService::CreateAccessible to specify when
// ARIAGridCellAccessible should be used for object creation. However, an
// invalid table structure might cause this class not to be used after all.
// To make sure we're really dealing with a cell, only check the generic
// type defined by the class, not the type defined in the ARIA map.
return mGenericTypes & eTableCell;
}
bool IsTable() const { return mGenericTypes & eTable; }
bool IsTable() const { return HasGenericType(eTable); }
bool IsHyperText() const { return HasGenericType(eHyperText); }

Просмотреть файл

@ -1,36 +0,0 @@
/* -*- 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(
LocalAccessible* aRow) const {
LocalAccessible* table = nsAccUtils::TableFor(aRow);
if (table) {
int32_t rowIdx = 0;
LocalAccessible* 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

Просмотреть файл

@ -3,386 +3,23 @@
* 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 "ARIAGridAccessible.h"
#include <stdint.h>
#include "LocalAccessible-inl.h"
#include "AccAttributes.h"
#include "AccIterator.h"
#include "mozilla/a11y/TableAccessibleBase.h"
#include "mozilla/a11y/TableCellAccessibleBase.h"
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "nsGkAtoms.h"
#include "Role.h"
#include "States.h"
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// ARIAGridAccessible
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Constructor
ARIAGridAccessible::ARIAGridAccessible(nsIContent* aContent,
DocAccessible* aDoc)
: HyperTextAccessibleWrap(aContent, aDoc) {
mGenericTypes |= eTable;
}
role ARIAGridAccessible::NativeRole() const {
a11y::role r = GetAccService()->MarkupRole(mContent);
return r != roles::NOTHING ? r : roles::TABLE;
}
already_AddRefed<AccAttributes> ARIAGridAccessible::NativeAttributes() {
RefPtr<AccAttributes> attributes = AccessibleWrap::NativeAttributes();
if (IsProbablyLayoutTable()) {
attributes->SetAttribute(nsGkAtoms::layout_guess, true);
}
return attributes.forget();
}
////////////////////////////////////////////////////////////////////////////////
// Table
uint32_t ARIAGridAccessible::ColCount() const {
AccIterator rowIter(this, filters::GetRow);
LocalAccessible* row = rowIter.Next();
if (!row) return 0;
AccIterator cellIter(row, filters::GetCell);
LocalAccessible* cell = nullptr;
uint32_t colCount = 0;
while ((cell = cellIter.Next())) {
MOZ_ASSERT(cell->IsTableCell(), "No table or grid cell!");
colCount += cell->AsTableCell()->ColExtent();
}
return colCount;
}
uint32_t ARIAGridAccessible::RowCount() {
uint32_t rowCount = 0;
AccIterator rowIter(this, filters::GetRow);
while (rowIter.Next()) rowCount++;
return rowCount;
}
LocalAccessible* ARIAGridAccessible::CellAt(uint32_t aRowIndex,
uint32_t aColumnIndex) {
LocalAccessible* row = RowAt(aRowIndex);
if (!row) return nullptr;
return CellInRowAt(row, aColumnIndex);
}
bool ARIAGridAccessible::IsColSelected(uint32_t aColIdx) {
if (IsARIARole(nsGkAtoms::table)) return false;
AccIterator rowIter(this, filters::GetRow);
LocalAccessible* row = rowIter.Next();
if (!row) return false;
do {
if (!nsAccUtils::IsARIASelected(row)) {
LocalAccessible* cell = CellInRowAt(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;
LocalAccessible* row = RowAt(aRowIdx);
if (!row) return false;
if (!nsAccUtils::IsARIASelected(row)) {
AccIterator cellIter(row, filters::GetCell);
LocalAccessible* 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;
LocalAccessible* row = RowAt(aRowIdx);
if (!row) return false;
if (!nsAccUtils::IsARIASelected(row)) {
LocalAccessible* cell = CellInRowAt(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);
LocalAccessible* row = nullptr;
while ((row = rowIter.Next())) {
if (nsAccUtils::IsARIASelected(row)) {
count += colCount;
continue;
}
AccIterator cellIter(row, filters::GetCell);
LocalAccessible* 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);
LocalAccessible* row = rowIter.Next();
if (!row) return 0;
nsTArray<bool> 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);
LocalAccessible* 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);
LocalAccessible* row = nullptr;
while ((row = rowIter.Next())) {
if (nsAccUtils::IsARIASelected(row)) {
count++;
continue;
}
AccIterator cellIter(row, filters::GetCell);
LocalAccessible* 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<Accessible*>* aCells) {
if (IsARIARole(nsGkAtoms::table)) return;
AccIterator rowIter(this, filters::GetRow);
LocalAccessible* row = nullptr;
while ((row = rowIter.Next())) {
AccIterator cellIter(row, filters::GetCell);
LocalAccessible* 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<uint32_t>* aCells) {
if (IsARIARole(nsGkAtoms::table)) return;
uint32_t colCount = ColCount();
AccIterator rowIter(this, filters::GetRow);
LocalAccessible* 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);
LocalAccessible* cell = nullptr;
for (uint32_t colIdx = 0; (cell = cellIter.Next()); colIdx++) {
if (nsAccUtils::IsARIASelected(cell)) {
aCells->AppendElement(rowIdx * colCount + colIdx);
}
}
}
}
void ARIAGridAccessible::SelectedColIndices(nsTArray<uint32_t>* aCols) {
if (IsARIARole(nsGkAtoms::table)) return;
uint32_t colCount = ColCount();
if (!colCount) return;
AccIterator rowIter(this, filters::GetRow);
LocalAccessible* row = rowIter.Next();
if (!row) return;
nsTArray<bool> isColSelArray(colCount);
isColSelArray.AppendElements(colCount);
memset(isColSelArray.Elements(), true, colCount * sizeof(bool));
do {
if (nsAccUtils::IsARIASelected(row)) continue;
AccIterator cellIter(row, filters::GetCell);
LocalAccessible* 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<uint32_t>* aRows) {
if (IsARIARole(nsGkAtoms::table)) return;
AccIterator rowIter(this, filters::GetRow);
LocalAccessible* row = nullptr;
for (uint32_t rowIdx = 0; (row = rowIter.Next()); rowIdx++) {
if (nsAccUtils::IsARIASelected(row)) {
aRows->AppendElement(rowIdx);
continue;
}
AccIterator cellIter(row, filters::GetCell);
LocalAccessible* 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);
}
}
////////////////////////////////////////////////////////////////////////////////
// ARIARowAccessible
////////////////////////////////////////////////////////////////////////////////
ARIARowAccessible::ARIARowAccessible(nsIContent* aContent, DocAccessible* aDoc)
: HyperTextAccessibleWrap(aContent, aDoc) {
mGenericTypes |= eTableRow;
}
role ARIARowAccessible::NativeRole() const {
a11y::role r = GetAccService()->MarkupRole(mContent);
return r != roles::NOTHING ? r : roles::ROW;
}
GroupPos ARIARowAccessible::GroupPosition() {
int32_t count = 0, index = 0;
LocalAccessible* table = nsAccUtils::TableFor(this);
if (table) {
if (nsCoreUtils::GetUIntAttr(table->GetContent(), nsGkAtoms::aria_rowcount,
&count) &&
nsCoreUtils::GetUIntAttr(mContent, nsGkAtoms::aria_rowindex, &index)) {
return GroupPos(0, index, count);
}
// Deal with the special case here that tables and grids can have rows
// which are wrapped in generic text container elements. Exclude tree grids
// because these are dealt with elsewhere.
if (table->Role() == roles::TABLE) {
LocalAccessible* row = nullptr;
AccIterator rowIter(table, filters::GetRow);
while ((row = rowIter.Next())) {
index++;
if (row == this) {
break;
}
}
if (row) {
count = table->AsTable()->RowCount();
return GroupPos(0, index, count);
}
}
}
return AccessibleWrap::GroupPosition();
}
// LocalAccessible protected
ENameValueFlag ARIARowAccessible::NativeName(nsString& aName) const {
// We want to calculate the name from content only if an ARIA role is
// present. ARIARowAccessible might also be used by tables with
// display:block; styling, in which case we do not want the name from
// content.
if (HasStrongARIARole()) {
return AccessibleWrap::NativeName(aName);
}
return eNameOK;
}
////////////////////////////////////////////////////////////////////////////////
// ARIAGridCellAccessible
////////////////////////////////////////////////////////////////////////////////
@ -396,47 +33,6 @@ ARIAGridCellAccessible::ARIAGridCellAccessible(nsIContent* aContent,
mGenericTypes |= eTableCell;
}
role ARIAGridCellAccessible::NativeRole() const {
const a11y::role r = GetAccService()->MarkupRole(mContent);
if (r != role::NOTHING) {
return r;
}
return role::CELL;
}
////////////////////////////////////////////////////////////////////////////////
// TableCell
TableAccessible* ARIAGridCellAccessible::Table() const {
LocalAccessible* table = nsAccUtils::TableFor(Row());
return table ? table->AsTable() : nullptr;
}
uint32_t ARIAGridCellAccessible::ColIdx() const {
LocalAccessible* row = Row();
if (!row) return 0;
int32_t indexInRow = IndexInParent();
uint32_t colIdx = 0;
for (int32_t idx = 0; idx < indexInRow; idx++) {
LocalAccessible* cell = row->LocalChildAt(idx);
if (cell->IsTableCell()) {
colIdx += cell->AsTableCell()->ColExtent();
}
}
return colIdx;
}
uint32_t ARIAGridCellAccessible::RowIdx() const { return RowIndexFor(Row()); }
bool ARIAGridCellAccessible::Selected() {
LocalAccessible* row = Row();
if (!row) return false;
return nsAccUtils::IsARIASelected(row) || nsAccUtils::IsARIASelected(this);
}
////////////////////////////////////////////////////////////////////////////////
// LocalAccessible
@ -463,35 +59,21 @@ already_AddRefed<AccAttributes> ARIAGridCellAccessible::NativeAttributes() {
RefPtr<AccAttributes> attributes =
HyperTextAccessibleWrap::NativeAttributes();
// Expose "table-cell-index" attribute.
LocalAccessible* thisRow = Row();
if (!thisRow) return attributes.forget();
int32_t rowIdx = RowIndexFor(thisRow);
if (rowIdx == -1) { // error
return attributes.forget();
}
int32_t colIdx = 0, colCount = 0;
uint32_t childCount = thisRow->ChildCount();
for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
LocalAccessible* child = thisRow->LocalChildAt(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++;
// We only need to expose table-cell-index to clients. If we're in the content
// process, we don't need this, so building a CachedTableAccessible is very
// wasteful. This will be exposed by RemoteAccessible in the parent process
// instead.
if (!IPCAccessibilityActive()) {
if (const TableCellAccessibleBase* cell = AsTableCellBase()) {
TableAccessibleBase* table = cell->Table();
const uint32_t row = cell->RowIdx();
const uint32_t col = cell->ColIdx();
const int32_t cellIdx = table->CellIndexAt(row, col);
if (cellIdx != -1) {
attributes->SetAttribute(nsGkAtoms::tableCellIndex, cellIdx);
}
}
}
attributes->SetAttribute(nsGkAtoms::tableCellIndex,
rowIdx * colCount + colIdx);
#ifdef DEBUG
RefPtr<nsAtom> cppClass = NS_Atomize(u"cppclass"_ns);
attributes->SetAttributeStringCopy(cppClass, u"ARIAGridCellAccessible"_ns);
#endif
return attributes.forget();
}

Просмотреть файл

@ -7,75 +7,14 @@
#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 HyperTextAccessibleWrap,
public TableAccessible {
public:
ARIAGridAccessible(nsIContent* aContent, DocAccessible* aDoc);
NS_INLINE_DECL_REFCOUNTING_INHERITED(ARIAGridAccessible,
HyperTextAccessibleWrap)
// LocalAccessible
virtual a11y::role NativeRole() const override;
virtual already_AddRefed<AccAttributes> NativeAttributes() override;
virtual TableAccessible* AsTable() override { return this; }
// TableAccessible
virtual uint32_t ColCount() const override;
virtual uint32_t RowCount() override;
virtual LocalAccessible* 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<Accessible*>* aCells) override;
virtual void SelectedCellIndices(nsTArray<uint32_t>* aCells) override;
virtual void SelectedColIndices(nsTArray<uint32_t>* aCols) override;
virtual void SelectedRowIndices(nsTArray<uint32_t>* aRows) override;
virtual LocalAccessible* AsAccessible() override { return this; }
protected:
virtual ~ARIAGridAccessible() {}
};
/**
* Accessible for ARIA row.
*/
class ARIARowAccessible : public HyperTextAccessibleWrap {
public:
ARIARowAccessible(nsIContent* aContent, DocAccessible* aDoc);
NS_INLINE_DECL_REFCOUNTING_INHERITED(ARIARowAccessible,
HyperTextAccessibleWrap)
// LocalAccessible
virtual a11y::role NativeRole() const override;
virtual mozilla::a11y::GroupPos GroupPosition() override;
protected:
virtual ~ARIARowAccessible() {}
// LocalAccessible
virtual ENameValueFlag NativeName(nsString& aName) const override;
};
/**
* Accessible for ARIA gridcell and rowheader/columnheader.
*/
class ARIAGridCellAccessible : public HyperTextAccessibleWrap,
public TableCellAccessible {
class ARIAGridCellAccessible : public HyperTextAccessibleWrap {
public:
ARIAGridCellAccessible(nsIContent* aContent, DocAccessible* aDoc);
@ -83,33 +22,11 @@ class ARIAGridCellAccessible : public HyperTextAccessibleWrap,
HyperTextAccessibleWrap)
// LocalAccessible
virtual a11y::role NativeRole() const override;
virtual TableCellAccessible* AsTableCell() override { return this; }
virtual void ApplyARIAState(uint64_t* aState) const override;
virtual already_AddRefed<AccAttributes> NativeAttributes() override;
protected:
virtual ~ARIAGridCellAccessible() {}
/**
* Return a containing row.
*/
LocalAccessible* Row() const {
LocalAccessible* row = LocalParent();
return row && row->IsTableRow() ? row : nullptr;
}
/**
* Return index of the given row.
* Returns -1 upon error.
*/
int32_t RowIndexFor(LocalAccessible* 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

Просмотреть файл

@ -6,6 +6,7 @@
#include "AccEvent.h"
#include "LocalAccessible-inl.h"
#include <stdint.h>
#include "EmbeddedObjCollector.h"
#include "AccAttributes.h"
#include "AccGroupInfo.h"
@ -42,6 +43,7 @@
#include "ImageAccessible.h"
#include "nsComputedDOMStyle.h"
#include "nsGkAtoms.h"
#include "nsIDOMXULButtonElement.h"
#include "nsIDOMXULSelectCntrlEl.h"
#include "nsIDOMXULSelectCntrlItemEl.h"
@ -1608,15 +1610,10 @@ void LocalAccessible::ApplyARIAState(uint64_t* aState) const {
roleMapEntry->Is(nsGkAtoms::columnheader) ||
roleMapEntry->Is(nsGkAtoms::rowheader)) &&
!nsAccUtils::HasDefinedARIAToken(mContent, nsGkAtoms::aria_readonly)) {
const TableCellAccessible* cell = AsTableCell();
if (cell) {
TableAccessible* table = cell->Table();
if (table) {
LocalAccessible* grid = table->AsAccessible();
uint64_t gridState = 0;
grid->ApplyARIAState(&gridState);
*aState |= gridState & states::READONLY;
}
if (const LocalAccessible* grid = nsAccUtils::TableFor(this)) {
uint64_t gridState = 0;
grid->ApplyARIAState(&gridState);
*aState |= gridState & states::READONLY;
}
}
}
@ -1803,12 +1800,9 @@ role LocalAccessible::ARIATransformRole(role aRole) const {
// A cell inside an ancestor table element that has a grid role needs a
// gridcell role
// (https://www.w3.org/TR/html-aam-1.0/#html-element-role-mappings).
const TableCellAccessible* cell = AsTableCell();
if (cell) {
TableAccessible* table = cell->Table();
if (table && table->AsAccessible()->IsARIARole(nsGkAtoms::grid)) {
return roles::GRID_CELL;
}
const LocalAccessible* table = nsAccUtils::TableFor(this);
if (table && table->IsARIARole(nsGkAtoms::grid)) {
return roles::GRID_CELL;
}
}

Просмотреть файл

@ -427,15 +427,11 @@ addAccessibleTask(
</div>
`,
async function (browser, docAcc) {
// XXX We don't create a TableAccessible in this case (bug 1494196). For
// now, just ensure we don't crash (bug 1793073).
const table = findAccessibleChildByID(docAcc, "table");
let queryOk = false;
try {
table.QueryInterface(nsIAccessibleTable);
queryOk = true;
} catch (e) {}
todo(queryOk, "Got nsIAccessibleTable");
const table = findAccessibleChildByID(docAcc, "table", [
nsIAccessibleTable,
]);
is(table.rowCount, 1, "table rowCount correct");
is(table.columnCount, 1, "table columnCount correct");
},
{
chrome: true,