diff -Nru firefox-esr-115.3.1esr+build1/accessible/atk/AccessibleWrap.cpp firefox-esr-115.4.0esr+build1/accessible/atk/AccessibleWrap.cpp
--- firefox-esr-115.3.1esr+build1/accessible/atk/AccessibleWrap.cpp 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/atk/AccessibleWrap.cpp 2023-10-17 05:45:43.000000000 +0000
@@ -16,8 +16,8 @@
#include "RemoteAccessible.h"
#include "DocAccessibleParent.h"
#include "RootAccessible.h"
-#include "mozilla/a11y/TableAccessibleBase.h"
-#include "mozilla/a11y/TableCellAccessibleBase.h"
+#include "mozilla/a11y/TableAccessible.h"
+#include "mozilla/a11y/TableCellAccessible.h"
#include "nsMai.h"
#include "nsMaiHyperlink.h"
#include "nsString.h"
@@ -1442,7 +1442,7 @@
}
// static
-Accessible* AccessibleWrap::GetColumnHeader(TableAccessibleBase* aAccessible,
+Accessible* AccessibleWrap::GetColumnHeader(TableAccessible* aAccessible,
int32_t aColIdx) {
if (!aAccessible) {
return nullptr;
@@ -1460,7 +1460,7 @@
}
// otherwise get column header for the data cell at the first row.
- TableCellAccessibleBase* tableCell = cell->AsTableCellBase();
+ TableCellAccessible* tableCell = cell->AsTableCell();
if (!tableCell) {
return nullptr;
}
@@ -1475,7 +1475,7 @@
}
// static
-Accessible* AccessibleWrap::GetRowHeader(TableAccessibleBase* aAccessible,
+Accessible* AccessibleWrap::GetRowHeader(TableAccessible* aAccessible,
int32_t aRowIdx) {
if (!aAccessible) {
return nullptr;
@@ -1493,7 +1493,7 @@
}
// otherwise get row header for the data cell at the first column.
- TableCellAccessibleBase* tableCell = cell->AsTableCellBase();
+ TableCellAccessible* tableCell = cell->AsTableCell();
if (!tableCell) {
return nullptr;
}
diff -Nru firefox-esr-115.3.1esr+build1/accessible/atk/AccessibleWrap.h firefox-esr-115.4.0esr+build1/accessible/atk/AccessibleWrap.h
--- firefox-esr-115.3.1esr+build1/accessible/atk/AccessibleWrap.h 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/atk/AccessibleWrap.h 2023-10-17 05:45:43.000000000 +0000
@@ -73,9 +73,9 @@
static void GetKeyBinding(Accessible* aAccessible, nsAString& aResult);
- static Accessible* GetColumnHeader(TableAccessibleBase* aAccessible,
+ static Accessible* GetColumnHeader(TableAccessible* aAccessible,
int32_t aColIdx);
- static Accessible* GetRowHeader(TableAccessibleBase* aAccessible,
+ static Accessible* GetRowHeader(TableAccessible* aAccessible,
int32_t aRowIdx);
protected:
diff -Nru firefox-esr-115.3.1esr+build1/accessible/atk/nsMaiInterfaceTableCell.cpp firefox-esr-115.4.0esr+build1/accessible/atk/nsMaiInterfaceTableCell.cpp
--- firefox-esr-115.3.1esr+build1/accessible/atk/nsMaiInterfaceTableCell.cpp 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/atk/nsMaiInterfaceTableCell.cpp 2023-10-17 05:45:43.000000000 +0000
@@ -6,8 +6,8 @@
#include "InterfaceInitFuncs.h"
-#include "mozilla/a11y/TableAccessibleBase.h"
-#include "mozilla/a11y/TableCellAccessibleBase.h"
+#include "mozilla/a11y/TableAccessible.h"
+#include "mozilla/a11y/TableCellAccessible.h"
#include "nsAccessibilityService.h"
#include "nsMai.h"
#include "RemoteAccessible.h"
@@ -24,7 +24,7 @@
if (!acc) {
return 0;
}
- return static_cast(acc->AsTableCellBase()->ColExtent());
+ return static_cast(acc->AsTableCell()->ColExtent());
}
static gint GetRowSpanCB(AtkTableCell* aCell) {
@@ -32,7 +32,7 @@
if (!acc) {
return 0;
}
- return static_cast(acc->AsTableCellBase()->RowExtent());
+ return static_cast(acc->AsTableCell()->RowExtent());
}
static gboolean GetPositionCB(AtkTableCell* aCell, gint* aRow, gint* aCol) {
@@ -40,7 +40,7 @@
if (!acc) {
return false;
}
- TableCellAccessibleBase* cell = acc->AsTableCellBase();
+ TableCellAccessible* cell = acc->AsTableCell();
if (!cell) {
return false;
}
@@ -55,7 +55,7 @@
if (!acc) {
return false;
}
- TableCellAccessibleBase* cellAcc = acc->AsTableCellBase();
+ TableCellAccessible* cellAcc = acc->AsTableCell();
if (!cellAcc) {
return false;
}
@@ -71,7 +71,11 @@
if (!acc) {
return nullptr;
}
- TableAccessibleBase* table = acc->AsTableCellBase()->Table();
+ TableCellAccessible* cell = acc->AsTableCell();
+ if (!cell) {
+ return nullptr;
+ }
+ TableAccessible* table = cell->Table();
if (!table) {
return nullptr;
}
@@ -84,8 +88,12 @@
if (!acc) {
return nullptr;
}
+ TableCellAccessible* cell = acc->AsTableCell();
+ if (!cell) {
+ return nullptr;
+ }
AutoTArray headers;
- acc->AsTableCellBase()->ColHeaderCells(&headers);
+ cell->ColHeaderCells(&headers);
if (headers.IsEmpty()) {
return nullptr;
}
@@ -105,8 +113,12 @@
if (!acc) {
return nullptr;
}
+ TableCellAccessible* cell = acc->AsTableCell();
+ if (!cell) {
+ return nullptr;
+ }
AutoTArray headers;
- acc->AsTableCellBase()->RowHeaderCells(&headers);
+ cell->RowHeaderCells(&headers);
if (headers.IsEmpty()) {
return nullptr;
}
diff -Nru firefox-esr-115.3.1esr+build1/accessible/atk/nsMaiInterfaceTable.cpp firefox-esr-115.4.0esr+build1/accessible/atk/nsMaiInterfaceTable.cpp
--- firefox-esr-115.3.1esr+build1/accessible/atk/nsMaiInterfaceTable.cpp 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/atk/nsMaiInterfaceTable.cpp 2023-10-17 05:45:43.000000000 +0000
@@ -7,7 +7,7 @@
#include "InterfaceInitFuncs.h"
#include "AccessibleWrap.h"
-#include "mozilla/a11y/TableAccessibleBase.h"
+#include "mozilla/a11y/TableAccessible.h"
#include "nsAccessibilityService.h"
#include "nsMai.h"
#include "RemoteAccessible.h"
@@ -29,7 +29,7 @@
if (!acc) {
return nullptr;
}
- Accessible* cell = acc->AsTableBase()->CellAt(aRowIdx, aColIdx);
+ Accessible* cell = acc->AsTable()->CellAt(aRowIdx, aColIdx);
if (!cell) {
return nullptr;
}
@@ -52,7 +52,7 @@
if (!acc) {
return -1;
}
- return static_cast(acc->AsTableBase()->CellIndexAt(aRowIdx, aColIdx));
+ return static_cast(acc->AsTable()->CellIndexAt(aRowIdx, aColIdx));
}
static gint getColumnAtIndexCB(AtkTable* aTable, gint aIdx) {
@@ -64,7 +64,7 @@
if (!acc) {
return -1;
}
- return static_cast(acc->AsTableBase()->ColIndexAt(aIdx));
+ return static_cast(acc->AsTable()->ColIndexAt(aIdx));
}
static gint getRowAtIndexCB(AtkTable* aTable, gint aIdx) {
@@ -76,7 +76,7 @@
if (!acc) {
return -1;
}
- return static_cast(acc->AsTableBase()->RowIndexAt(aIdx));
+ return static_cast(acc->AsTable()->RowIndexAt(aIdx));
}
static gint getColumnCountCB(AtkTable* aTable) {
@@ -84,7 +84,7 @@
if (!acc) {
return -1;
}
- return static_cast(acc->AsTableBase()->ColCount());
+ return static_cast(acc->AsTable()->ColCount());
}
static gint getRowCountCB(AtkTable* aTable) {
@@ -92,7 +92,7 @@
if (!acc) {
return -1;
}
- return static_cast(acc->AsTableBase()->RowCount());
+ return static_cast(acc->AsTable()->RowCount());
}
static gint getColumnExtentAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
@@ -104,7 +104,7 @@
if (!acc) {
return -1;
}
- return static_cast(acc->AsTableBase()->ColExtentAt(aRowIdx, aColIdx));
+ return static_cast(acc->AsTable()->ColExtentAt(aRowIdx, aColIdx));
}
static gint getRowExtentAtCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
@@ -112,7 +112,7 @@
if (!acc) {
return -1;
}
- return static_cast(acc->AsTableBase()->RowExtentAt(aRowIdx, aColIdx));
+ return static_cast(acc->AsTable()->RowExtentAt(aRowIdx, aColIdx));
}
static AtkObject* getCaptionCB(AtkTable* aTable) {
@@ -120,7 +120,7 @@
if (!acc) {
return nullptr;
}
- Accessible* caption = acc->AsTableBase()->Caption();
+ Accessible* caption = acc->AsTable()->Caption();
return caption ? GetWrapperFor(caption) : nullptr;
}
@@ -130,7 +130,7 @@
return nullptr;
}
nsAutoString autoStr;
- acc->AsTableBase()->ColDescription(aColumn, autoStr);
+ acc->AsTable()->ColDescription(aColumn, autoStr);
return AccessibleWrap::ReturnString(autoStr);
}
@@ -139,8 +139,7 @@
if (!acc) {
return nullptr;
}
- Accessible* header =
- AccessibleWrap::GetColumnHeader(acc->AsTableBase(), aColIdx);
+ Accessible* header = AccessibleWrap::GetColumnHeader(acc->AsTable(), aColIdx);
return header ? GetWrapperFor(header) : nullptr;
}
@@ -150,7 +149,7 @@
return nullptr;
}
nsAutoString autoStr;
- acc->AsTableBase()->RowDescription(aRow, autoStr);
+ acc->AsTable()->RowDescription(aRow, autoStr);
return AccessibleWrap::ReturnString(autoStr);
}
@@ -159,8 +158,7 @@
if (!acc) {
return nullptr;
}
- Accessible* header =
- AccessibleWrap::GetRowHeader(acc->AsTableBase(), aRowIdx);
+ Accessible* header = AccessibleWrap::GetRowHeader(acc->AsTable(), aRowIdx);
return header ? GetWrapperFor(header) : nullptr;
}
@@ -180,7 +178,7 @@
return 0;
}
AutoTArray cols;
- acc->AsTableBase()->SelectedColIndices(&cols);
+ acc->AsTable()->SelectedColIndices(&cols);
if (cols.IsEmpty()) return 0;
@@ -201,7 +199,7 @@
return 0;
}
AutoTArray rows;
- acc->AsTableBase()->SelectedRowIndices(&rows);
+ acc->AsTable()->SelectedRowIndices(&rows);
gint* atkRows = g_new(gint, rows.Length());
if (!atkRows) {
@@ -219,7 +217,7 @@
if (!acc) {
return FALSE;
}
- return static_cast(acc->AsTableBase()->IsColSelected(aColIdx));
+ return static_cast(acc->AsTable()->IsColSelected(aColIdx));
}
static gboolean isRowSelectedCB(AtkTable* aTable, gint aRowIdx) {
@@ -227,7 +225,7 @@
if (!acc) {
return FALSE;
}
- return static_cast(acc->AsTableBase()->IsRowSelected(aRowIdx));
+ return static_cast(acc->AsTable()->IsRowSelected(aRowIdx));
}
static gboolean isCellSelectedCB(AtkTable* aTable, gint aRowIdx, gint aColIdx) {
@@ -236,7 +234,7 @@
return FALSE;
}
return static_cast(
- acc->AsTableBase()->IsCellSelected(aRowIdx, aColIdx));
+ acc->AsTable()->IsCellSelected(aRowIdx, aColIdx));
}
}
diff -Nru firefox-esr-115.3.1esr+build1/accessible/base/AccGroupInfo.cpp firefox-esr-115.4.0esr+build1/accessible/base/AccGroupInfo.cpp
--- firefox-esr-115.3.1esr+build1/accessible/base/AccGroupInfo.cpp 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/base/AccGroupInfo.cpp 2023-10-17 05:45:44.000000000 +0000
@@ -4,7 +4,7 @@
#include "AccGroupInfo.h"
#include "mozilla/a11y/Accessible.h"
-#include "mozilla/a11y/TableAccessibleBase.h"
+#include "mozilla/a11y/TableAccessible.h"
#include "nsAccUtils.h"
#include "nsIAccessiblePivot.h"
@@ -14,8 +14,6 @@
using namespace mozilla::a11y;
-static bool IsGenericContainer(role aRole);
-static Accessible* GetRelevantParent(const Accessible* aAcc);
static role BaseRole(role aRole);
// This rule finds candidate siblings for compound widget children.
@@ -37,7 +35,7 @@
// Ignore generic accessibles, but keep searching through the subtree for
// siblings.
- if (IsGenericContainer(accRole)) {
+ if (aAcc->IsGeneric()) {
return nsIAccessibleTraversalRule::FILTER_IGNORE;
}
@@ -57,7 +55,7 @@
void AccGroupInfo::Update() {
mParent = nullptr;
- Accessible* parent = GetRelevantParent(mItem);
+ Accessible* parent = mItem->GetNonGenericParent();
if (!parent) {
return;
}
@@ -173,7 +171,7 @@
if (mRole == roles::OUTLINEITEM) {
// Find the relevant grandparent of the item. Use that parent as the root
// and find the previous outline item sibling within that root.
- Accessible* grandParent = GetRelevantParent(parent);
+ Accessible* grandParent = parent->GetNonGenericParent();
MOZ_ASSERT(grandParent);
Pivot pivot{grandParent};
CompoundWidgetSiblingRule parentSiblingRule{mRole};
@@ -188,7 +186,7 @@
// the parent of the item will be a group and containing item of the group is
// a conceptual parent of the item.
if (mRole == roles::LISTITEM || mRole == roles::OUTLINEITEM) {
- Accessible* grandParent = GetRelevantParent(parent);
+ Accessible* grandParent = parent->GetNonGenericParent();
if (grandParent && grandParent->Role() == mRole) {
mParent = grandParent;
}
@@ -271,7 +269,7 @@
return *val;
}
}
- if (TableAccessibleBase* tableAcc = aContainer->AsTableBase()) {
+ if (TableAccessible* tableAcc = aContainer->AsTable()) {
return tableAcc->RowCount();
}
break;
@@ -282,7 +280,7 @@
return *val;
}
}
- if (TableAccessibleBase* tableAcc = table->AsTableBase()) {
+ if (TableAccessible* tableAcc = table->AsTable()) {
return tableAcc->ColCount();
}
}
@@ -373,23 +371,6 @@
return aAccessible->GetLevel(true);
}
-static bool IsGenericContainer(role aRole) {
- return aRole == roles::TEXT || aRole == roles::TEXT_CONTAINER ||
- aRole == roles::SECTION;
-}
-
-static Accessible* GetRelevantParent(const Accessible* aAcc) {
- MOZ_ASSERT(aAcc);
-
- // Search through ancestors until we find a relevant parent, skipping generic
- // accessibles.
- Accessible* parent = aAcc->Parent();
- while (parent && IsGenericContainer(parent->Role())) {
- parent = parent->Parent();
- }
- return parent;
-}
-
static role BaseRole(role aRole) {
if (aRole == roles::CHECK_MENU_ITEM || aRole == roles::PARENT_MENUITEM ||
aRole == roles::RADIO_MENU_ITEM) {
diff -Nru firefox-esr-115.3.1esr+build1/accessible/base/CachedTableAccessible.cpp firefox-esr-115.4.0esr+build1/accessible/base/CachedTableAccessible.cpp
--- firefox-esr-115.3.1esr+build1/accessible/base/CachedTableAccessible.cpp 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/base/CachedTableAccessible.cpp 2023-10-17 05:45:43.000000000 +0000
@@ -8,6 +8,7 @@
#include "AccIterator.h"
#include "DocAccessibleParent.h"
+#include "HTMLTableAccessible.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/UniquePtr.h"
@@ -15,8 +16,6 @@
#include "nsIAccessiblePivot.h"
#include "Pivot.h"
#include "RemoteAccessible.h"
-#include "TableAccessible.h"
-#include "TableCellAccessible.h"
namespace mozilla::a11y {
@@ -216,44 +215,14 @@
return mCells[cellIdx].Acc(mAcc);
}
-void CachedTableAccessible::SelectCol(uint32_t aColIdx) {
- if (LocalAccessible* localAcc = mAcc->AsLocal()) {
- TableAccessible* table = localAcc->AsTable();
- table->SelectCol(aColIdx);
- }
- // XXX Implement support for RemoteAccessible.
-}
-
-void CachedTableAccessible::UnselectCol(uint32_t aColIdx) {
- if (LocalAccessible* localAcc = mAcc->AsLocal()) {
- TableAccessible* table = localAcc->AsTable();
- table->UnselectCol(aColIdx);
- }
- // XXX Implement support for RemoteAccessible.
-}
-
-void CachedTableAccessible::SelectRow(uint32_t aRowIdx) {
- if (LocalAccessible* localAcc = mAcc->AsLocal()) {
- TableAccessible* table = localAcc->AsTable();
- table->SelectRow(aRowIdx);
- }
- // XXX Implement support for RemoteAccessible.
-}
-
-void CachedTableAccessible::UnselectRow(uint32_t aRowIdx) {
- if (LocalAccessible* localAcc = mAcc->AsLocal()) {
- TableAccessible* table = localAcc->AsTable();
- table->UnselectRow(aRowIdx);
- }
- // XXX Implement support for RemoteAccessible.
-}
-
bool CachedTableAccessible::IsProbablyLayoutTable() {
if (RemoteAccessible* remoteAcc = mAcc->AsRemote()) {
return remoteAcc->TableIsProbablyForLayout();
}
- TableAccessible* localTable = mAcc->AsLocal()->AsTable();
- return localTable->IsProbablyLayoutTable();
+ if (auto* localTable = HTMLTableAccessible::GetFrom(mAcc->AsLocal())) {
+ return localTable->IsProbablyLayoutTable();
+ }
+ return false;
}
/* static */
@@ -261,8 +230,7 @@
Accessible* aAcc) {
MOZ_ASSERT(aAcc->IsTableCell());
for (Accessible* parent = aAcc; parent; parent = parent->Parent()) {
- if (auto* table =
- static_cast(parent->AsTableBase())) {
+ if (auto* table = static_cast(parent->AsTable())) {
if (auto cellIdx = table->mAccToCellIdx.Lookup(aAcc)) {
return &table->mCells[*cellIdx];
}
@@ -278,12 +246,11 @@
return acc;
}
-TableAccessibleBase* CachedTableCellAccessible::Table() const {
+TableAccessible* CachedTableCellAccessible::Table() const {
for (const Accessible* acc = mAcc; acc; acc = acc->Parent()) {
// Since the caller has this cell, the table is already created, so it's
// okay to ignore the const restriction here.
- if (TableAccessibleBase* table =
- const_cast(acc)->AsTableBase()) {
+ if (TableAccessible* table = const_cast(acc)->AsTable()) {
return table;
}
}
@@ -299,13 +266,11 @@
return *colSpan;
}
}
- } else if (LocalAccessible* localAcc = mAcc->AsLocal()) {
+ } else if (auto* cell = HTMLTableCellAccessible::GetFrom(mAcc->AsLocal())) {
// For HTML table cells, we must use the HTMLTableCellAccessible
// GetColExtent method rather than using the DOM attributes directly.
// This is because of things like rowspan="0" which depend on knowing
// about thead, tbody, etc., which is info we don't have in the a11y tree.
- TableCellAccessible* cell = localAcc->AsTableCell();
- MOZ_ASSERT(cell);
uint32_t colExtent = cell->ColExtent();
MOZ_ASSERT(colExtent > 0);
if (colExtent > 0) {
@@ -324,13 +289,11 @@
return *rowSpan;
}
}
- } else if (LocalAccessible* localAcc = mAcc->AsLocal()) {
+ } else if (auto* cell = HTMLTableCellAccessible::GetFrom(mAcc->AsLocal())) {
// For HTML table cells, we must use the HTMLTableCellAccessible
// GetRowExtent method rather than using the DOM attributes directly.
// This is because of things like rowspan="0" which depend on knowing
// about thead, tbody, etc., which is info we don't have in the a11y tree.
- TableCellAccessible* cell = localAcc->AsTableCell();
- MOZ_ASSERT(cell);
uint32_t rowExtent = cell->RowExtent();
MOZ_ASSERT(rowExtent > 0);
if (rowExtent > 0) {
diff -Nru firefox-esr-115.3.1esr+build1/accessible/base/CachedTableAccessible.h firefox-esr-115.4.0esr+build1/accessible/base/CachedTableAccessible.h
--- firefox-esr-115.3.1esr+build1/accessible/base/CachedTableAccessible.h 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/base/CachedTableAccessible.h 2023-10-17 05:45:43.000000000 +0000
@@ -7,8 +7,8 @@
#ifndef CACHED_TABLE_ACCESSIBLE_H
#define CACHED_TABLE_ACCESSIBLE_H
-#include "mozilla/a11y/TableAccessibleBase.h"
-#include "mozilla/a11y/TableCellAccessibleBase.h"
+#include "mozilla/a11y/TableAccessible.h"
+#include "mozilla/a11y/TableCellAccessible.h"
#include "mozilla/UniquePtr.h"
#include "nsTHashMap.h"
@@ -20,11 +20,11 @@
class CachedTableAccessible;
-class CachedTableCellAccessible final : public TableCellAccessibleBase {
+class CachedTableCellAccessible final : public TableCellAccessible {
public:
static CachedTableCellAccessible* GetFrom(Accessible* aAcc);
- virtual TableAccessibleBase* Table() const override;
+ virtual TableAccessible* Table() const override;
virtual uint32_t ColIdx() const override {
return static_cast(mColIdx);
@@ -76,7 +76,7 @@
/**
* TableAccessible implementation which builds and queries a cache.
*/
-class CachedTableAccessible final : public TableAccessibleBase {
+class CachedTableAccessible final : public TableAccessible {
public:
static CachedTableAccessible* GetFrom(Accessible* aAcc);
@@ -256,11 +256,6 @@
}
}
- 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 mAcc; }
virtual bool IsProbablyLayoutTable() override;
diff -Nru firefox-esr-115.3.1esr+build1/accessible/base/HTMLMarkupMap.h firefox-esr-115.4.0esr+build1/accessible/base/HTMLMarkupMap.h
--- firefox-esr-115.3.1esr+build1/accessible/base/HTMLMarkupMap.h 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/base/HTMLMarkupMap.h 2023-10-17 05:45:43.000000000 +0000
@@ -349,28 +349,9 @@
MARKUPMAP(
table,
[](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
- if (!aElement->GetPrimaryFrame() ||
- aElement->GetPrimaryFrame()->AccessibleType() != eHTMLTableType) {
- return new ARIAGridAccessible(aElement, aContext->Document());
- }
-
- // Make sure that our children are proper layout table parts
- for (nsIContent* child = aElement->GetFirstChild(); child;
- child = child->GetNextSibling()) {
- if (child->IsAnyOfHTMLElements(nsGkAtoms::thead, nsGkAtoms::tfoot,
- nsGkAtoms::tbody, nsGkAtoms::tr)) {
- // These children elements need to participate in the layout table
- // and need table row(group) frames.
- nsIFrame* childFrame = child->GetPrimaryFrame();
- if (childFrame && (!childFrame->IsTableRowGroupFrame() &&
- !childFrame->IsTableRowFrame())) {
- return new ARIAGridAccessible(aElement, aContext->Document());
- }
- }
- }
- return nullptr;
+ return new HTMLTableAccessible(aElement, aContext->Document());
},
- 0)
+ roles::TABLE)
MARKUPMAP(time, New_HyperText, 0, Attr(xmlroles, time),
AttrFromDOM(datetime, datetime))
@@ -380,24 +361,14 @@
MARKUPMAP(
td,
[](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
- if (aContext->IsTableRow() &&
- aContext->GetContent() == aElement->GetParent()) {
- // If HTML:td element is part of its HTML:table, which has CSS
- // display style other than 'table', then create a generic table
- // cell accessible, because there's no underlying table layout and
- // thus native HTML table cell class doesn't work. The same is
- // true if the cell itself has CSS display:block;.
- if (!aContext->IsHTMLTableRow() || !aElement->GetPrimaryFrame() ||
- aElement->GetPrimaryFrame()->AccessibleType() !=
- eHTMLTableCellType) {
- return new ARIAGridCellAccessible(aElement, aContext->Document());
- }
- if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::scope)) {
- return new HTMLTableHeaderCellAccessible(aElement,
- aContext->Document());
- }
+ if (!aContext->IsHTMLTableRow()) {
+ return nullptr;
}
- return nullptr;
+ if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::scope)) {
+ return new HTMLTableHeaderCellAccessible(aElement,
+ aContext->Document());
+ }
+ return new HTMLTableCellAccessible(aElement, aContext->Document());
},
0)
@@ -406,22 +377,10 @@
MARKUPMAP(
th,
[](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
- if (aContext->IsTableRow() &&
- aContext->GetContent() == aElement->GetParent()) {
- // If HTML:th element is part of its HTML:table, which has CSS
- // display style other than 'table', then create a generic table
- // cell accessible, because there's no underlying table layout and
- // thus native HTML table cell class doesn't work. The same is
- // true if the cell itself has CSS display:block;.
- if (!aContext->IsHTMLTableRow() || !aElement->GetPrimaryFrame() ||
- aElement->GetPrimaryFrame()->AccessibleType() !=
- eHTMLTableCellType) {
- return new ARIAGridCellAccessible(aElement, aContext->Document());
- }
- return new HTMLTableHeaderCellAccessible(aElement,
- aContext->Document());
+ if (!aContext->IsHTMLTableRow()) {
+ return nullptr;
}
- return nullptr;
+ return new HTMLTableHeaderCellAccessible(aElement, aContext->Document());
},
0)
@@ -430,37 +389,21 @@
MARKUPMAP(
tr,
[](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
- // If HTML:tr element is part of its HTML:table, which has CSS
- // display style other than 'table', then create a generic table row
- // accessible, because there's no underlying table layout and thus
- // native HTML table row class doesn't work. Refer to
- // CreateAccessibleByFrameType dual logic.
- LocalAccessible* table = aContext->IsTable() ? aContext : nullptr;
- if (!table && aContext->LocalParent() &&
- aContext->LocalParent()->IsTable()) {
- table = aContext->LocalParent();
- }
- if (table) {
- nsIContent* parentContent = aElement->GetParent();
- nsIFrame* parentFrame = parentContent->GetPrimaryFrame();
- if (!parentFrame || !parentFrame->IsTableWrapperFrame()) {
- parentContent = parentContent->GetParent();
- // parentContent can be null if this tr is at the top level of a
- // shadow root (with the table outside the shadow root).
- parentFrame =
- parentContent ? parentContent->GetPrimaryFrame() : nullptr;
- if (table->GetContent() == parentContent &&
- ((!parentFrame || !parentFrame->IsTableWrapperFrame()) ||
- !aElement->GetPrimaryFrame() ||
- aElement->GetPrimaryFrame()->AccessibleType() !=
- eHTMLTableRowType)) {
- return new ARIARowAccessible(aElement, aContext->Document());
- }
- }
+ if (aContext->IsTableRow()) {
+ // A within a row isn't valid.
+ return nullptr;
+ }
+ // Check if this
is within a table. We check the grandparent because
+ // it might be inside a rowgroup. We don't specifically check for an HTML
+ // table because there are cases where there is a
inside a
+ // such as Monorail.
+ if (aContext->IsTable() ||
+ (aContext->LocalParent() && aContext->LocalParent()->IsTable())) {
+ return new HTMLTableRowAccessible(aElement, aContext->Document());
}
return nullptr;
},
- 0)
+ roles::ROW)
MARKUPMAP(
ul,
diff -Nru firefox-esr-115.3.1esr+build1/accessible/base/MathMLMarkupMap.h firefox-esr-115.4.0esr+build1/accessible/base/MathMLMarkupMap.h
--- firefox-esr-115.3.1esr+build1/accessible/base/MathMLMarkupMap.h 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/base/MathMLMarkupMap.h 2023-10-17 05:45:44.000000000 +0000
@@ -59,12 +59,6 @@
MARKUPMAP(
mtable_,
[](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
- // If we're not a table according to layout, use a generic accessible.
- if (!aElement->GetPrimaryFrame() ||
- aElement->GetPrimaryFrame()->AccessibleType() != eHTMLTableType) {
- return new ARIAGridAccessible(aElement, aContext->Document());
- }
-
return new HTMLTableAccessible(aElement, aContext->Document());
},
roles::MATHML_TABLE, AttrFromDOM(align, align),
@@ -80,40 +74,16 @@
MARKUPMAP(
mtr_,
[](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
- if (aContext->IsHTMLTable() && aElement->GetPrimaryFrame() &&
- aElement->GetPrimaryFrame()->AccessibleType() == eHTMLTableRowType) {
- return new HTMLTableRowAccessible(aElement, aContext->Document());
- }
-
- // If the mtr element in a MathML table has a display style other than
- // 'table', create a generic table row accessible, since there's no
- // underlying table layout.
- if (aContext->IsTable()) {
- return new ARIARowAccessible(aElement, aContext->Document());
- }
-
- return nullptr;
+ return new HTMLTableRowAccessible(aElement, aContext->Document());
},
roles::MATHML_TABLE_ROW)
MARKUPMAP(
mtd_,
[](Element* aElement, LocalAccessible* aContext) -> LocalAccessible* {
- if (aContext->IsHTMLTableRow() && aElement->GetPrimaryFrame() &&
- aElement->GetPrimaryFrame()->AccessibleType() == eHTMLTableCellType) {
- return new HTMLTableCellAccessible(aElement, aContext->Document());
- }
-
- // If the mtd element in a MathML table has a display style other than
- // 'table', create a generic table cell accessible, since there's no
- // underlying table layout.
- if (aContext->IsTableRow()) {
- return new ARIAGridCellAccessible(aElement, aContext->Document());
- }
-
- return nullptr;
+ return new HTMLTableCellAccessible(aElement, aContext->Document());
},
- roles::MATHML_CELL)
+ 0)
MARKUPMAP(maction_, New_HyperText, roles::MATHML_ACTION,
AttrFromDOM(actiontype_, actiontype_),
diff -Nru firefox-esr-115.3.1esr+build1/accessible/base/nsAccessibilityService.cpp firefox-esr-115.4.0esr+build1/accessible/base/nsAccessibilityService.cpp
--- firefox-esr-115.3.1esr+build1/accessible/base/nsAccessibilityService.cpp 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/base/nsAccessibilityService.cpp 2023-10-17 05:45:43.000000000 +0000
@@ -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"
@@ -61,6 +62,7 @@
#include "nsTreeBodyFrame.h"
#include "nsTreeColumns.h"
#include "nsTreeUtils.h"
+#include "mozilla/a11y/AccTypes.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/dom/DOMStringList.h"
#include "mozilla/dom/EventTarget.h"
@@ -68,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"
@@ -97,39 +100,38 @@
////////////////////////////////////////////////////////////////////////////////
/**
- * 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()) {
- return new ARIAGridCellAccessible(aContent, aDocument);
+ 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;
+ }
}
- } 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);
+ if (parent->IsTable()) {
+ return new ARIAGridCellAccessible(aContent, aDocument);
}
- } else if (aRoleMapEntry->IsOfType(eTable)) {
- return new ARIAGridAccessible(aContent, aDocument);
}
return nullptr;
}
@@ -181,16 +183,27 @@
* marked presentational with role="presentation", etc. MustBeAccessible causes
* an Accessible to be created as if it weren't marked presentational at all;
* e.g.
will expose roles::TABLE and
- * support TableAccessibleBase. In contrast, this function causes a generic
+ * support TableAccessible. In contrast, this function causes a generic
* Accessible to be created; e.g. will expose roles::TEXT_CONTAINER and will not support
- * TableAccessibleBase. This is necessary in certain cases for the
+ * TableAccessible. This is necessary in certain cases for the
* RemoteAccessible cache.
*/
static bool MustBeGenericAccessible(nsIContent* aContent,
DocAccessible* aDocument) {
+ if (aContent->IsInNativeAnonymousSubtree() || aContent->IsSVGElement()) {
+ // We should not force create accs for anonymous content.
+ // This is an issue for inputs, which have an intermediate
+ // container with relevant overflow styling between the input
+ // and its internal input content.
+ // We should also avoid this for SVG elements (ie. ``s
+ // which have default overflow:hidden styling).
+ return false;
+ }
nsIFrame* frame = aContent->GetPrimaryFrame();
MOZ_ASSERT(frame);
+ nsAutoCString overflow;
+ frame->Style()->GetComputedPropertyValue(eCSSProperty_overflow, overflow);
// If the frame has been transformed, and the content has any children, we
// should create an Accessible so that we can account for the transform when
// calculating the Accessible's bounds using the parent process cache.
@@ -203,7 +216,9 @@
((aContent->HasChildren() && frame->IsTransformed()) ||
frame->IsStickyPositioned() ||
(frame->StyleDisplay()->mPosition == StylePositionProperty::Fixed &&
- nsLayoutUtils::IsReallyFixedPos(frame)));
+ nsLayoutUtils::IsReallyFixedPos(frame)) ||
+ overflow.Equals("auto"_ns) || overflow.Equals("scroll"_ns) ||
+ overflow.Equals("hidden"_ns));
}
/**
@@ -517,12 +532,14 @@
// If the content has children and its frame has a transform, create an
// Accessible so that we can account for the transform when calculating
// the Accessible's bounds using the parent process cache. Ditto for
- // position: fixed/sticky.
+ // position: fixed/sticky and content with overflow styling (hidden, auto,
+ // scroll)
if (const nsIFrame* frame = aContent->GetPrimaryFrame()) {
const auto& disp = *frame->StyleDisplay();
if (disp.HasTransform(frame) ||
disp.mPosition == StylePositionProperty::Fixed ||
- disp.mPosition == StylePositionProperty::Sticky) {
+ disp.mPosition == StylePositionProperty::Sticky ||
+ disp.IsScrollableOverflow()) {
document->ContentInserted(aContent, aContent->GetNextSibling());
}
}
@@ -1058,28 +1075,25 @@
} 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 newAcc;
- if (markupMap && markupMap->new_func) {
- newAcc = markupMap->new_func(content->AsElement(), aContext);
+ const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(content->AsElement());
+ RefPtr 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
@@ -1214,14 +1228,14 @@
}
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 =
@@ -1235,15 +1249,6 @@
}
}
- // 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()) {
@@ -1595,56 +1600,14 @@
newAcc = new HTMLSpinnerAccessible(aContent, document);
break;
case eHTMLTableType:
- if (aContent->IsHTMLElement(nsGkAtoms::table)) {
- newAcc = new HTMLTableAccessible(aContent, document);
- } else {
- newAcc = new HyperTextAccessibleWrap(aContent, document);
- }
- break;
case eHTMLTableCellType:
- // LocalAccessible HTML table cell should be a child of accessible HTML
- // table or its row (CSS HTML tables are polite to the used markup at
- // certain degree).
- // Otherwise create a generic text accessible to avoid text jamming
- // when reading by AT.
- if (aContext->IsHTMLTableRow() || aContext->IsHTMLTable()) {
- newAcc = new HTMLTableCellAccessible(aContent, document);
- } else {
- newAcc = new HyperTextAccessibleWrap(aContent, document);
- }
+ // We handle markup and ARIA tables elsewhere. If we reach here, this is
+ // a CSS table part. Just create a generic text container.
+ newAcc = new HyperTextAccessibleWrap(aContent, document);
break;
-
- case eHTMLTableRowType: {
- // LocalAccessible HTML table row may be a child of tbody/tfoot/thead of
- // accessible HTML table or a direct child of accessible of HTML table.
- LocalAccessible* table = aContext->IsTable() ? aContext : nullptr;
- if (!table && aContext->LocalParent() &&
- aContext->LocalParent()->IsTable()) {
- table = aContext->LocalParent();
- }
-
- if (table) {
- nsIContent* parentContent =
- aContent->GetParentOrShadowHostNode()->AsContent();
- nsIFrame* parentFrame = nullptr;
- if (parentContent) {
- parentFrame = parentContent->GetPrimaryFrame();
- if (!parentFrame || !parentFrame->IsTableWrapperFrame()) {
- parentContent =
- parentContent->GetParentOrShadowHostNode()->AsContent();
- if (parentContent) {
- parentFrame = parentContent->GetPrimaryFrame();
- }
- }
- }
-
- if (parentFrame && parentFrame->IsTableWrapperFrame() &&
- table->GetContent() == parentContent) {
- newAcc = new HTMLTableRowAccessible(aContent, document);
- }
- }
+ case eHTMLTableRowType:
+ // This is a CSS table row. Don't expose it at all.
break;
- }
case eHTMLTextFieldType:
newAcc = new HTMLTextFieldAccessible(aContent, document);
break;
diff -Nru firefox-esr-115.3.1esr+build1/accessible/base/nsAccUtils.h firefox-esr-115.4.0esr+build1/accessible/base/nsAccUtils.h
--- firefox-esr-115.3.1esr+build1/accessible/base/nsAccUtils.h 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/base/nsAccUtils.h 2023-10-17 05:45:43.000000000 +0000
@@ -106,6 +106,10 @@
static Accessible* TableFor(Accessible* aRow);
static LocalAccessible* TableFor(LocalAccessible* aRow);
+ static const LocalAccessible* TableFor(const LocalAccessible* aAcc) {
+ return TableFor(const_cast(aAcc));
+ }
+
/**
* Return true if the DOM node of a given accessible has a given attribute
* with a value of "true".
diff -Nru firefox-esr-115.3.1esr+build1/accessible/basetypes/Accessible.h firefox-esr-115.4.0esr+build1/accessible/basetypes/Accessible.h
--- firefox-esr-115.3.1esr+build1/accessible/basetypes/Accessible.h 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/basetypes/Accessible.h 2023-10-17 05:45:43.000000000 +0000
@@ -29,8 +29,8 @@
class Relation;
enum class RelationType;
class RemoteAccessible;
-class TableAccessibleBase;
-class TableCellAccessibleBase;
+class TableAccessible;
+class TableCellAccessible;
/**
* Name type flags.
@@ -475,20 +475,19 @@
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); }
@@ -532,6 +531,7 @@
bool IsHTMLRadioButton() const { return mType == eHTMLRadioButtonType; }
bool IsHTMLTable() const { return mType == eHTMLTableType; }
+ bool IsHTMLTableCell() const { return mType == eHTMLTableCellType; }
bool IsHTMLTableRow() const { return mType == eHTMLTableRowType; }
bool IsImageMap() const { return mType == eImageMapType; }
@@ -579,6 +579,28 @@
virtual bool HasNumericValue() const = 0;
/**
+ * Returns true if this is a generic container element that has no meaning on
+ * its own.
+ */
+ bool IsGeneric() const {
+ role accRole = Role();
+ return accRole == roles::TEXT || accRole == roles::TEXT_CONTAINER ||
+ accRole == roles::SECTION;
+ }
+
+ /**
+ * Returns the nearest ancestor which is not a generic element.
+ */
+ Accessible* GetNonGenericParent() const {
+ for (Accessible* parent = Parent(); parent; parent = parent->Parent()) {
+ if (!parent->IsGeneric()) {
+ return parent;
+ }
+ }
+ return nullptr;
+ }
+
+ /**
* Return true if the link is valid (e. g. points to a valid URL).
*/
bool IsLinkValid();
@@ -608,8 +630,8 @@
virtual HyperTextAccessibleBase* AsHyperTextBase() { return nullptr; }
- virtual TableAccessibleBase* AsTableBase() { return nullptr; }
- virtual TableCellAccessibleBase* AsTableCellBase() { return nullptr; }
+ virtual TableAccessible* AsTable() { return nullptr; }
+ virtual TableCellAccessible* AsTableCell() { return nullptr; }
#ifdef A11Y_LOG
/**
diff -Nru firefox-esr-115.3.1esr+build1/accessible/basetypes/HyperTextAccessibleBase.cpp firefox-esr-115.4.0esr+build1/accessible/basetypes/HyperTextAccessibleBase.cpp
--- firefox-esr-115.3.1esr+build1/accessible/basetypes/HyperTextAccessibleBase.cpp 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/basetypes/HyperTextAccessibleBase.cpp 2023-10-17 05:45:43.000000000 +0000
@@ -292,6 +292,19 @@
nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordType, thisAcc);
if (!thisAcc->Bounds().Contains(coords.x, coords.y)) {
// The requested point does not exist in this accessible.
+ // Check if we used fuzzy hittesting to get here and, if
+ // so, return 0 to indicate this text leaf is a valid match.
+ LayoutDeviceIntPoint p(aX, aY);
+ if (aCoordType != nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE) {
+ p = nsAccUtils::ConvertToScreenCoords(aX, aY, aCoordType, thisAcc);
+ }
+ if (Accessible* doc = nsAccUtils::DocumentFor(thisAcc)) {
+ Accessible* hittestMatch = doc->ChildAtPoint(
+ p.x, p.y, Accessible::EWhichChildAtPoint::DeepestChild);
+ if (hittestMatch && thisAcc == hittestMatch->Parent()) {
+ return 0;
+ }
+ }
return -1;
}
diff -Nru firefox-esr-115.3.1esr+build1/accessible/basetypes/moz.build firefox-esr-115.4.0esr+build1/accessible/basetypes/moz.build
--- firefox-esr-115.3.1esr+build1/accessible/basetypes/moz.build 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/basetypes/moz.build 2023-10-17 05:45:44.000000000 +0000
@@ -7,8 +7,8 @@
EXPORTS.mozilla.a11y += [
"Accessible.h",
"HyperTextAccessibleBase.h",
- "TableAccessibleBase.h",
- "TableCellAccessibleBase.h",
+ "TableAccessible.h",
+ "TableCellAccessible.h",
]
UNIFIED_SOURCES += [
diff -Nru firefox-esr-115.3.1esr+build1/accessible/basetypes/TableAccessibleBase.h firefox-esr-115.4.0esr+build1/accessible/basetypes/TableAccessibleBase.h
--- firefox-esr-115.3.1esr+build1/accessible/basetypes/TableAccessibleBase.h 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/basetypes/TableAccessibleBase.h 1970-01-01 00:00:00.000000000 +0000
@@ -1,192 +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 TABLE_ACCESSIBLE_BASE_H
-#define TABLE_ACCESSIBLE_BASE_H
-
-#include "nsString.h"
-#include "nsTArray.h"
-
-namespace mozilla {
-namespace a11y {
-
-class Accessible;
-
-/**
- * Accessible table interface.
- */
-class TableAccessibleBase {
- public:
- /**
- * Return the caption accessible if any for this table.
- */
- virtual Accessible* Caption() const { return nullptr; }
-
- /**
- * Get the summary for this table.
- */
- virtual void Summary(nsString& aSummary) { aSummary.Truncate(); }
-
- /**
- * Return the number of columns in the table.
- */
- virtual uint32_t ColCount() const { return 0; }
-
- /**
- * Return the number of rows in the table.
- */
- virtual uint32_t RowCount() { return 0; }
-
- /**
- * Return the accessible for the cell at the given row and column indices.
- */
- virtual Accessible* CellAt(uint32_t aRowIdx, uint32_t aColIdx) {
- return nullptr;
- }
-
- /**
- * Return the index of the cell at the given row and column.
- */
- virtual int32_t CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) { return -1; }
-
- /**
- * Return the column index of the cell with the given index.
- * This returns -1 if the column count is 0 or an invalid index is being
- * passed in.
- */
- virtual int32_t ColIndexAt(uint32_t aCellIdx) { return -1; }
-
- /**
- * Return the row index of the cell with the given index.
- * This returns -1 if the column count is 0 or an invalid index is being
- * passed in.
- */
- virtual int32_t RowIndexAt(uint32_t aCellIdx) { return -1; }
-
- /**
- * Get the row and column indices for the cell at the given index.
- * This returns -1 for both output parameters if the column count is 0 or an
- * invalid index is being passed in.
- */
- virtual void RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx,
- int32_t* aColIdx) {
- *aRowIdx = -1;
- *aColIdx = -1;
- }
-
- /**
- * Return the number of columns occupied by the cell at the given row and
- * column indices.
- */
- virtual uint32_t ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx) { return 1; }
-
- /**
- * Return the number of rows occupied by the cell at the given row and column
- * indices.
- */
- virtual uint32_t RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx) { return 1; }
-
- /**
- * Get the description of the given column.
- */
- virtual void ColDescription(uint32_t aColIdx, nsString& aDescription) {
- aDescription.Truncate();
- }
-
- /**
- * Get the description for the given row.
- */
- virtual void RowDescription(uint32_t aRowIdx, nsString& aDescription) {
- aDescription.Truncate();
- }
-
- /**
- * Return true if the given column is selected.
- */
- virtual bool IsColSelected(uint32_t aColIdx) { return false; }
-
- /**
- * Return true if the given row is selected.
- */
- virtual bool IsRowSelected(uint32_t aRowIdx) { return false; }
-
- /**
- * Return true if the given cell is selected.
- */
- virtual bool IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) {
- return false;
- }
-
- /**
- * Return the number of selected cells.
- */
- virtual uint32_t SelectedCellCount() { return 0; }
-
- /**
- * Return the number of selected columns.
- */
- virtual uint32_t SelectedColCount() { return 0; }
-
- /**
- * Return the number of selected rows.
- */
- virtual uint32_t SelectedRowCount() { return 0; }
-
- /**
- * Get the set of selected cells.
- */
- virtual void SelectedCells(nsTArray* aCells) {}
-
- /**
- * Get the set of selected cell indices.
- */
- virtual void SelectedCellIndices(nsTArray* aCells) {}
-
- /**
- * Get the set of selected column indices.
- */
- virtual void SelectedColIndices(nsTArray* aCols) {}
-
- /**
- * Get the set of selected row indices.
- */
- virtual void SelectedRowIndices(nsTArray* aRows) {}
-
- /**
- * Select the given column unselecting any other selected columns.
- */
- virtual void SelectCol(uint32_t aColIdx) {}
-
- /**
- * Select the given row unselecting all other previously selected rows.
- */
- virtual void SelectRow(uint32_t aRowIdx) {}
-
- /**
- * Unselect the given column leaving other selected columns selected.
- */
- virtual void UnselectCol(uint32_t aColIdx) {}
-
- /**
- * Unselect the given row leaving other selected rows selected.
- */
- virtual void UnselectRow(uint32_t aRowIdx) {}
-
- /**
- * Return true if the table is probably for layout.
- */
- virtual bool IsProbablyLayoutTable() { return false; }
-
- /**
- * Convert the table to an Accessible*.
- */
- virtual Accessible* AsAccessible() = 0;
-};
-
-} // namespace a11y
-} // namespace mozilla
-
-#endif
diff -Nru firefox-esr-115.3.1esr+build1/accessible/basetypes/TableAccessible.h firefox-esr-115.4.0esr+build1/accessible/basetypes/TableAccessible.h
--- firefox-esr-115.3.1esr+build1/accessible/basetypes/TableAccessible.h 1970-01-01 00:00:00.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/basetypes/TableAccessible.h 2023-10-17 05:45:44.000000000 +0000
@@ -0,0 +1,172 @@
+/* -*- 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 TABLE_ACCESSIBLE_H
+#define TABLE_ACCESSIBLE_H
+
+#include "nsString.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace a11y {
+
+class Accessible;
+
+/**
+ * Accessible table interface.
+ */
+class TableAccessible {
+ public:
+ /**
+ * Return the caption accessible if any for this table.
+ */
+ virtual Accessible* Caption() const { return nullptr; }
+
+ /**
+ * Get the summary for this table.
+ */
+ virtual void Summary(nsString& aSummary) { aSummary.Truncate(); }
+
+ /**
+ * Return the number of columns in the table.
+ */
+ virtual uint32_t ColCount() const { return 0; }
+
+ /**
+ * Return the number of rows in the table.
+ */
+ virtual uint32_t RowCount() { return 0; }
+
+ /**
+ * Return the accessible for the cell at the given row and column indices.
+ */
+ virtual Accessible* CellAt(uint32_t aRowIdx, uint32_t aColIdx) {
+ return nullptr;
+ }
+
+ /**
+ * Return the index of the cell at the given row and column.
+ */
+ virtual int32_t CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) { return -1; }
+
+ /**
+ * Return the column index of the cell with the given index.
+ * This returns -1 if the column count is 0 or an invalid index is being
+ * passed in.
+ */
+ virtual int32_t ColIndexAt(uint32_t aCellIdx) { return -1; }
+
+ /**
+ * Return the row index of the cell with the given index.
+ * This returns -1 if the column count is 0 or an invalid index is being
+ * passed in.
+ */
+ virtual int32_t RowIndexAt(uint32_t aCellIdx) { return -1; }
+
+ /**
+ * Get the row and column indices for the cell at the given index.
+ * This returns -1 for both output parameters if the column count is 0 or an
+ * invalid index is being passed in.
+ */
+ virtual void RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx,
+ int32_t* aColIdx) {
+ *aRowIdx = -1;
+ *aColIdx = -1;
+ }
+
+ /**
+ * Return the number of columns occupied by the cell at the given row and
+ * column indices.
+ */
+ virtual uint32_t ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx) { return 1; }
+
+ /**
+ * Return the number of rows occupied by the cell at the given row and column
+ * indices.
+ */
+ virtual uint32_t RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx) { return 1; }
+
+ /**
+ * Get the description of the given column.
+ */
+ virtual void ColDescription(uint32_t aColIdx, nsString& aDescription) {
+ aDescription.Truncate();
+ }
+
+ /**
+ * Get the description for the given row.
+ */
+ virtual void RowDescription(uint32_t aRowIdx, nsString& aDescription) {
+ aDescription.Truncate();
+ }
+
+ /**
+ * Return true if the given column is selected.
+ */
+ virtual bool IsColSelected(uint32_t aColIdx) { return false; }
+
+ /**
+ * Return true if the given row is selected.
+ */
+ virtual bool IsRowSelected(uint32_t aRowIdx) { return false; }
+
+ /**
+ * Return true if the given cell is selected.
+ */
+ virtual bool IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) {
+ return false;
+ }
+
+ /**
+ * Return the number of selected cells.
+ */
+ virtual uint32_t SelectedCellCount() { return 0; }
+
+ /**
+ * Return the number of selected columns.
+ */
+ virtual uint32_t SelectedColCount() { return 0; }
+
+ /**
+ * Return the number of selected rows.
+ */
+ virtual uint32_t SelectedRowCount() { return 0; }
+
+ /**
+ * Get the set of selected cells.
+ */
+ virtual void SelectedCells(nsTArray* aCells) {}
+
+ /**
+ * Get the set of selected cell indices.
+ */
+ virtual void SelectedCellIndices(nsTArray* aCells) {}
+
+ /**
+ * Get the set of selected column indices.
+ */
+ virtual void SelectedColIndices(nsTArray* aCols) {}
+
+ /**
+ * Get the set of selected row indices.
+ */
+ virtual void SelectedRowIndices(nsTArray* aRows) {}
+
+ /**
+ * Return true if the table is probably for layout.
+ */
+ virtual bool IsProbablyLayoutTable() { return false; }
+
+ /**
+ * Convert the table to an Accessible*.
+ */
+ virtual Accessible* AsAccessible() = 0;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif
diff -Nru firefox-esr-115.3.1esr+build1/accessible/basetypes/TableCellAccessibleBase.h firefox-esr-115.4.0esr+build1/accessible/basetypes/TableCellAccessibleBase.h
--- firefox-esr-115.3.1esr+build1/accessible/basetypes/TableCellAccessibleBase.h 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/basetypes/TableCellAccessibleBase.h 1970-01-01 00:00:00.000000000 +0000
@@ -1,68 +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_TableCellAccessibleBase_h__
-#define mozilla_a11y_TableCellAccessibleBase_h__
-
-#include "nsTArray.h"
-#include
-
-namespace mozilla {
-namespace a11y {
-
-class Accessible;
-class TableAccessibleBase;
-
-/**
- * Abstract interface implemented by table cell accessibles.
- */
-class TableCellAccessibleBase {
- public:
- /**
- * Return the table this cell is in.
- */
- virtual TableAccessibleBase* Table() const = 0;
-
- /**
- * Return the column of the table this cell is in.
- */
- virtual uint32_t ColIdx() const = 0;
-
- /**
- * Return the row of the table this cell is in.
- */
- virtual uint32_t RowIdx() const = 0;
-
- /**
- * Return the column extent of this cell.
- */
- virtual uint32_t ColExtent() const { return 1; }
-
- /**
- * Return the row extent of this cell.
- */
- virtual uint32_t RowExtent() const { return 1; }
-
- /**
- * Return the column header cells for this cell.
- */
- virtual void ColHeaderCells(nsTArray* aCells) = 0;
-
- /**
- * Return the row header cells for this cell.
- */
- virtual void RowHeaderCells(nsTArray* aCells) = 0;
-
- /**
- * Returns true if this cell is selected.
- */
- virtual bool Selected() = 0;
-};
-
-} // namespace a11y
-} // namespace mozilla
-
-#endif // mozilla_a11y_TableCellAccessibleBase_h__
diff -Nru firefox-esr-115.3.1esr+build1/accessible/basetypes/TableCellAccessible.h firefox-esr-115.4.0esr+build1/accessible/basetypes/TableCellAccessible.h
--- firefox-esr-115.3.1esr+build1/accessible/basetypes/TableCellAccessible.h 1970-01-01 00:00:00.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/basetypes/TableCellAccessible.h 2023-10-17 05:45:44.000000000 +0000
@@ -0,0 +1,68 @@
+/* -*- 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_TableCellAccessible_h__
+#define mozilla_a11y_TableCellAccessible_h__
+
+#include "nsTArray.h"
+#include
+
+namespace mozilla {
+namespace a11y {
+
+class Accessible;
+class TableAccessible;
+
+/**
+ * Abstract interface implemented by table cell accessibles.
+ */
+class TableCellAccessible {
+ public:
+ /**
+ * Return the table this cell is in.
+ */
+ virtual TableAccessible* Table() const = 0;
+
+ /**
+ * Return the column of the table this cell is in.
+ */
+ virtual uint32_t ColIdx() const = 0;
+
+ /**
+ * Return the row of the table this cell is in.
+ */
+ virtual uint32_t RowIdx() const = 0;
+
+ /**
+ * Return the column extent of this cell.
+ */
+ virtual uint32_t ColExtent() const { return 1; }
+
+ /**
+ * Return the row extent of this cell.
+ */
+ virtual uint32_t RowExtent() const { return 1; }
+
+ /**
+ * Return the column header cells for this cell.
+ */
+ virtual void ColHeaderCells(nsTArray* aCells) = 0;
+
+ /**
+ * Return the row header cells for this cell.
+ */
+ virtual void RowHeaderCells(nsTArray* aCells) = 0;
+
+ /**
+ * Returns true if this cell is selected.
+ */
+ virtual bool Selected() = 0;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+#endif // mozilla_a11y_TableCellAccessible_h__
diff -Nru firefox-esr-115.3.1esr+build1/accessible/generic/ARIAGridAccessible.cpp firefox-esr-115.4.0esr+build1/accessible/generic/ARIAGridAccessible.cpp
--- firefox-esr-115.3.1esr+build1/accessible/generic/ARIAGridAccessible.cpp 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/generic/ARIAGridAccessible.cpp 2023-10-17 05:45:43.000000000 +0000
@@ -3,509 +3,24 @@
* 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
#include "LocalAccessible-inl.h"
#include "AccAttributes.h"
#include "AccIterator.h"
+#include "mozilla/a11y/TableAccessible.h"
+#include "mozilla/a11y/TableCellAccessible.h"
+#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
+#include "nsGkAtoms.h"
#include "Role.h"
#include "States.h"
-#include "mozilla/dom/Element.h"
-#include "nsComponentManagerUtils.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 ARIAGridAccessible::NativeAttributes() {
- RefPtr 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 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* 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* 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* 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 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* 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);
- }
-}
-
-void ARIAGridAccessible::SelectRow(uint32_t aRowIdx) {
- if (IsARIARole(nsGkAtoms::table)) return;
-
- AccIterator rowIter(this, filters::GetRow);
-
- LocalAccessible* 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);
-
- LocalAccessible* 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.
- LocalAccessible* cell = CellInRowAt(row, aColIdx);
- if (cell) SetARIASelected(cell, true);
- }
-}
-
-void ARIAGridAccessible::UnselectRow(uint32_t aRowIdx) {
- if (IsARIARole(nsGkAtoms::table)) return;
-
- LocalAccessible* row = RowAt(aRowIdx);
- if (row) SetARIASelected(row, false);
-}
-
-void ARIAGridAccessible::UnselectCol(uint32_t aColIdx) {
- if (IsARIARole(nsGkAtoms::table)) return;
-
- AccIterator rowIter(this, filters::GetRow);
-
- LocalAccessible* row = nullptr;
- while ((row = rowIter.Next())) {
- LocalAccessible* cell = CellInRowAt(row, aColIdx);
- if (cell) SetARIASelected(cell, false);
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Protected
-
-nsresult ARIAGridAccessible::SetARIASelected(LocalAccessible* 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 (content->IsElement()) {
- if (aIsSelected) {
- rv = content->AsElement()->SetAttr(
- kNameSpaceID_None, nsGkAtoms::aria_selected, u"true"_ns, aNotify);
- } else {
- rv = content->AsElement()->SetAttr(
- kNameSpaceID_None, nsGkAtoms::aria_selected, u"false"_ns, 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);
- LocalAccessible* 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) {
- LocalAccessible* row = aAccessible->LocalParent();
-
- if (row && row->Role() == roles::ROW && nsAccUtils::IsARIASelected(row)) {
- rv = SetARIASelected(row, false, false);
- NS_ENSURE_SUCCESS(rv, rv);
-
- AccIterator cellIter(row, filters::GetCell);
- LocalAccessible* 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)
- : 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
////////////////////////////////////////////////////////////////////////////////
@@ -518,53 +33,6 @@
mGenericTypes |= eTableCell;
}
-role ARIAGridCellAccessible::NativeRole() const {
- const a11y::role r = GetAccService()->MarkupRole(mContent);
- if (r != role::NOTHING) {
- return r;
- }
-
- // Special case to handle th elements mapped to ARIA grid cells.
- if (GetContent() && GetContent()->IsHTMLElement(nsGkAtoms::th)) {
- return GetHeaderCellRole(this);
- }
-
- 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
@@ -591,35 +59,21 @@
RefPtr 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 TableCellAccessible* cell = AsTableCell()) {
+ TableAccessible* 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 cppClass = NS_Atomize(u"cppclass"_ns);
- attributes->SetAttributeStringCopy(cppClass, u"ARIAGridCellAccessible"_ns);
-#endif
-
return attributes.forget();
}
diff -Nru firefox-esr-115.3.1esr+build1/accessible/generic/ARIAGridAccessible.h firefox-esr-115.4.0esr+build1/accessible/generic/ARIAGridAccessible.h
--- firefox-esr-115.3.1esr+build1/accessible/generic/ARIAGridAccessible.h 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/generic/ARIAGridAccessible.h 2023-10-17 05:45:43.000000000 +0000
@@ -7,90 +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 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* 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 LocalAccessible* AsAccessible() override { return this; }
-
- protected:
- virtual ~ARIAGridAccessible() {}
-
- /**
- * 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(LocalAccessible* aAccessible, bool aIsSelected,
- bool aNotify = true);
-};
-
-/**
- * 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);
@@ -98,33 +22,11 @@
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 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
diff -Nru firefox-esr-115.3.1esr+build1/accessible/generic/ARIAGridAccessible-inl.h firefox-esr-115.4.0esr+build1/accessible/generic/ARIAGridAccessible-inl.h
--- firefox-esr-115.3.1esr+build1/accessible/generic/ARIAGridAccessible-inl.h 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/generic/ARIAGridAccessible-inl.h 1970-01-01 00:00:00.000000000 +0000
@@ -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
diff -Nru firefox-esr-115.3.1esr+build1/accessible/generic/LocalAccessible.cpp firefox-esr-115.4.0esr+build1/accessible/generic/LocalAccessible.cpp
--- firefox-esr-115.3.1esr+build1/accessible/generic/LocalAccessible.cpp 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/generic/LocalAccessible.cpp 2023-10-17 05:45:44.000000000 +0000
@@ -6,6 +6,7 @@
#include "AccEvent.h"
#include "LocalAccessible-inl.h"
+#include
#include "EmbeddedObjCollector.h"
#include "AccAttributes.h"
#include "AccGroupInfo.h"
@@ -14,6 +15,8 @@
#include "CachedTableAccessible.h"
#include "DocAccessible-inl.h"
#include "mozilla/a11y/AccAttributes.h"
+#include "mozilla/a11y/TableAccessible.h"
+#include "mozilla/a11y/TableCellAccessible.h"
#include "nsAccUtils.h"
#include "nsAccessibilityService.h"
#include "ApplicationAccessible.h"
@@ -33,14 +36,14 @@
#include "StyleInfo.h"
#include "TextLeafRange.h"
#include "TextRange.h"
-#include "TableAccessible.h"
-#include "TableCellAccessible.h"
#include "TreeWalker.h"
#include "HTMLElementAccessibles.h"
#include "HTMLSelectAccessible.h"
+#include "HTMLTableAccessible.h"
#include "ImageAccessible.h"
#include "nsComputedDOMStyle.h"
+#include "nsGkAtoms.h"
#include "nsIDOMXULButtonElement.h"
#include "nsIDOMXULSelectCntrlEl.h"
#include "nsIDOMXULSelectCntrlItemEl.h"
@@ -1624,16 +1627,15 @@
if ((roleMapEntry->Is(nsGkAtoms::gridcell) ||
roleMapEntry->Is(nsGkAtoms::columnheader) ||
roleMapEntry->Is(nsGkAtoms::rowheader)) &&
+ // Don't recurse infinitely for an authoring error like
+ // . Without this check, we'd call TableFor(this)
+ // below, which would return this.
+ !IsTable() &&
!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;
}
}
}
@@ -1820,12 +1822,9 @@
// 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;
}
}
@@ -3325,6 +3324,7 @@
}
bool boundsChanged = false;
+ nsIFrame* frame = GetFrame();
if (aCacheDomain & CacheDomain::Bounds) {
nsRect newBoundsRect = ParentRelativeBounds();
@@ -3374,6 +3374,12 @@
fields->SetAttribute(nsGkAtoms::relativeBounds, std::move(boundsArray));
}
+
+ if (frame && frame->ScrollableOverflowRect().IsEmpty()) {
+ fields->SetAttribute(nsGkAtoms::clip_rule, true);
+ } else if (aUpdateType != CacheUpdateType::Initial) {
+ fields->SetAttribute(nsGkAtoms::clip_rule, DeleteEntry());
+ }
}
if (aCacheDomain & CacheDomain::Text) {
@@ -3407,7 +3413,6 @@
}
}
- nsIFrame* frame = GetFrame();
if (aCacheDomain & (CacheDomain::Text | CacheDomain::Bounds) &&
!HasChildren()) {
// We cache line start offsets for both text and non-text leaf Accessibles
@@ -3630,16 +3635,27 @@
} else if (aUpdateType != CacheUpdateType::Initial) {
fields->SetAttribute(nsGkAtoms::position, DeleteEntry());
}
+
+ if (frame) {
+ nsAutoCString overflow;
+ frame->Style()->GetComputedPropertyValue(eCSSProperty_overflow, overflow);
+ RefPtr overflowAtom = NS_Atomize(overflow);
+ if (overflowAtom == nsGkAtoms::hidden) {
+ fields->SetAttribute(nsGkAtoms::overflow, nsGkAtoms::hidden);
+ } else if (aUpdateType != CacheUpdateType::Initial) {
+ fields->SetAttribute(nsGkAtoms::overflow, DeleteEntry());
+ }
+ }
}
if (aCacheDomain & CacheDomain::Table) {
- if (TableAccessible* table = AsTable()) {
+ if (auto* table = HTMLTableAccessible::GetFrom(this)) {
if (table->IsProbablyLayoutTable()) {
fields->SetAttribute(nsGkAtoms::layout_guess, true);
} else if (aUpdateType == CacheUpdateType::Update) {
fields->SetAttribute(nsGkAtoms::layout_guess, DeleteEntry());
}
- } else if (TableCellAccessible* cell = AsTableCell()) {
+ } else if (auto* cell = HTMLTableCellAccessible::GetFrom(this)) {
// For HTML table cells, we must use the HTMLTableCellAccessible
// GetRow/ColExtent methods rather than using the DOM attributes directly.
// This is because of things like rowspan="0" which depend on knowing
@@ -3836,6 +3852,19 @@
if (nsIFrame* frame = GetFrame()) {
const ComputedStyle* newStyle = frame->Style();
+ nsAutoCString oldOverflow, newOverflow;
+ mOldComputedStyle->GetComputedPropertyValue(eCSSProperty_overflow,
+ oldOverflow);
+ newStyle->GetComputedPropertyValue(eCSSProperty_overflow, newOverflow);
+
+ if (oldOverflow != newOverflow) {
+ RefPtr oldAtom = NS_Atomize(oldOverflow);
+ RefPtr newAtom = NS_Atomize(newOverflow);
+ if (oldAtom == nsGkAtoms::hidden || newAtom == nsGkAtoms::hidden) {
+ mDoc->QueueCacheUpdate(this, CacheDomain::Style);
+ }
+ }
+
nsAutoCString oldDisplay, newDisplay;
mOldComputedStyle->GetComputedPropertyValue(eCSSProperty_display,
oldDisplay);
@@ -4011,18 +4040,18 @@
"LocalAccessible::mContextFlags was oversized by eLastContextFlag!");
}
-TableAccessibleBase* LocalAccessible::AsTableBase() {
+TableAccessible* LocalAccessible::AsTable() {
if (IsTable() && !mContent->IsXULElement()) {
return CachedTableAccessible::GetFrom(this);
}
- return AsTable();
+ return nullptr;
}
-TableCellAccessibleBase* LocalAccessible::AsTableCellBase() {
+TableCellAccessible* LocalAccessible::AsTableCell() {
if (IsTableCell() && !mContent->IsXULElement()) {
return CachedTableCellAccessible::GetFrom(this);
}
- return AsTableCell();
+ return nullptr;
}
Maybe LocalAccessible::GetIntARIAAttr(nsAtom* aAttrName) const {
diff -Nru firefox-esr-115.3.1esr+build1/accessible/generic/LocalAccessible.h firefox-esr-115.4.0esr+build1/accessible/generic/LocalAccessible.h
--- firefox-esr-115.3.1esr+build1/accessible/generic/LocalAccessible.h 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/generic/LocalAccessible.h 2023-10-17 05:45:44.000000000 +0000
@@ -53,9 +53,7 @@
class Relation;
class RootAccessible;
class TableAccessible;
-class TableAccessibleBase;
class TableCellAccessible;
-class TableCellAccessibleBase;
class TextLeafAccessible;
class XULLabelAccessible;
class XULTreeAccessible;
@@ -464,15 +462,8 @@
a11y::RootAccessible* AsRoot();
- virtual TableAccessible* AsTable() { return nullptr; }
-
- virtual TableCellAccessible* AsTableCell() { return nullptr; }
- const TableCellAccessible* AsTableCell() const {
- return const_cast(this)->AsTableCell();
- }
-
- virtual TableAccessibleBase* AsTableBase() override;
- virtual TableCellAccessibleBase* AsTableCellBase() override;
+ virtual TableAccessible* AsTable() override;
+ virtual TableCellAccessible* AsTableCell() override;
TextLeafAccessible* AsTextLeaf();
diff -Nru firefox-esr-115.3.1esr+build1/accessible/generic/moz.build firefox-esr-115.4.0esr+build1/accessible/generic/moz.build
--- firefox-esr-115.3.1esr+build1/accessible/generic/moz.build 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/generic/moz.build 2023-10-17 05:45:43.000000000 +0000
@@ -22,8 +22,6 @@
"LocalAccessible.cpp",
"OuterDocAccessible.cpp",
"RootAccessible.cpp",
- "TableAccessible.cpp",
- "TableCellAccessible.cpp",
"TextLeafAccessible.cpp",
]
diff -Nru firefox-esr-115.3.1esr+build1/accessible/generic/TableAccessible.cpp firefox-esr-115.4.0esr+build1/accessible/generic/TableAccessible.cpp
--- firefox-esr-115.3.1esr+build1/accessible/generic/TableAccessible.cpp 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/generic/TableAccessible.cpp 1970-01-01 00:00:00.000000000 +0000
@@ -1,316 +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/. */
-
-#include "TableAccessible.h"
-
-#include "LocalAccessible-inl.h"
-#include "AccIterator.h"
-
-#include "nsTableCellFrame.h"
-#include "nsTableWrapperFrame.h"
-#include "TableCellAccessible.h"
-
-using namespace mozilla;
-using namespace mozilla::a11y;
-
-bool TableAccessible::IsProbablyLayoutTable() {
- // Implement a heuristic to determine if table is most likely used for layout.
-
- // XXX do we want to look for rowspan or colspan, especialy that span all but
- // a couple cells at the beginning or end of a row/col, and especially when
- // they occur at the edge of a table?
-
- // XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC
- // This will allow release trunk builds to be used by testers to refine
- // the algorithm. Integrate it into Logging.
- // Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release
-#ifdef SHOW_LAYOUT_HEURISTIC
-# define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \
- { \
- mLayoutHeuristic = isLayout \
- ? nsLiteralString(u"layout table: " heuristic) \
- : nsLiteralString(u"data table: " heuristic); \
- return isLayout; \
- }
-#else
-# define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \
- { return isLayout; }
-#endif
-
- LocalAccessible* thisacc = AsAccessible();
-
- MOZ_ASSERT(!thisacc->IsDefunct(), "Table accessible should not be defunct");
-
- // Need to see all elements while document is being edited.
- if (thisacc->Document()->State() & states::EDITABLE) {
- RETURN_LAYOUT_ANSWER(false, "In editable document");
- }
-
- // Check to see if an ARIA role overrides the role from native markup,
- // but for which we still expose table semantics (treegrid, for example).
- if (thisacc->HasARIARole()) {
- RETURN_LAYOUT_ANSWER(false, "Has role attribute");
- }
-
- dom::Element* el = thisacc->Elm();
- if (el->IsMathMLElement(nsGkAtoms::mtable_)) {
- RETURN_LAYOUT_ANSWER(false, "MathML matrix");
- }
-
- MOZ_ASSERT(el->IsHTMLElement(nsGkAtoms::table),
- "Table should not be built by CSS display:table style");
-
- // Check if datatable attribute has "0" value.
- if (el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::datatable, u"0"_ns,
- eCaseMatters)) {
- RETURN_LAYOUT_ANSWER(true, "Has datatable = 0 attribute, it's for layout");
- }
-
- // Check for legitimate data table attributes.
- if (el->Element::HasNonEmptyAttr(nsGkAtoms::summary)) {
- RETURN_LAYOUT_ANSWER(false, "Has summary -- legitimate table structures");
- }
-
- // Check for legitimate data table elements.
- LocalAccessible* caption = thisacc->LocalFirstChild();
- if (caption && caption->IsHTMLCaption() && caption->HasChildren()) {
- RETURN_LAYOUT_ANSWER(false,
- "Not empty caption -- legitimate table structures");
- }
-
- for (nsIContent* childElm = el->GetFirstChild(); childElm;
- childElm = childElm->GetNextSibling()) {
- if (!childElm->IsHTMLElement()) continue;
-
- if (childElm->IsAnyOfHTMLElements(nsGkAtoms::col, nsGkAtoms::colgroup,
- nsGkAtoms::tfoot, nsGkAtoms::thead)) {
- RETURN_LAYOUT_ANSWER(
- false,
- "Has col, colgroup, tfoot or thead -- legitimate table structures");
- }
-
- if (childElm->IsHTMLElement(nsGkAtoms::tbody)) {
- for (nsIContent* rowElm = childElm->GetFirstChild(); rowElm;
- rowElm = rowElm->GetNextSibling()) {
- if (rowElm->IsHTMLElement(nsGkAtoms::tr)) {
- if (LocalAccessible* row =
- thisacc->Document()->GetAccessible(rowElm)) {
- if (const nsRoleMapEntry* roleMapEntry = row->ARIARoleMap()) {
- if (roleMapEntry->role != roles::ROW) {
- RETURN_LAYOUT_ANSWER(true, "Repurposed tr with different role");
- }
- }
- }
-
- for (nsIContent* cellElm = rowElm->GetFirstChild(); cellElm;
- cellElm = cellElm->GetNextSibling()) {
- if (cellElm->IsHTMLElement()) {
- if (cellElm->NodeInfo()->Equals(nsGkAtoms::th)) {
- RETURN_LAYOUT_ANSWER(false,
- "Has th -- legitimate table structures");
- }
-
- if (cellElm->AsElement()->HasAttr(kNameSpaceID_None,
- nsGkAtoms::headers) ||
- cellElm->AsElement()->HasAttr(kNameSpaceID_None,
- nsGkAtoms::scope) ||
- cellElm->AsElement()->HasAttr(kNameSpaceID_None,
- nsGkAtoms::abbr)) {
- RETURN_LAYOUT_ANSWER(false,
- "Has headers, scope, or abbr attribute -- "
- "legitimate table structures");
- }
-
- if (LocalAccessible* cell =
- thisacc->Document()->GetAccessible(cellElm)) {
- if (const nsRoleMapEntry* roleMapEntry = cell->ARIARoleMap()) {
- if (roleMapEntry->role != roles::CELL &&
- roleMapEntry->role != roles::COLUMNHEADER &&
- roleMapEntry->role != roles::ROWHEADER &&
- roleMapEntry->role != roles::GRID_CELL) {
- RETURN_LAYOUT_ANSWER(true,
- "Repurposed cell with different role");
- }
- }
- if (cell->ChildCount() == 1 &&
- cell->LocalFirstChild()->IsAbbreviation()) {
- RETURN_LAYOUT_ANSWER(
- false, "has abbr -- legitimate table structures");
- }
- }
- }
- }
- }
- }
- }
- }
-
- // Check for nested tables.
- nsCOMPtr nestedTables =
- el->GetElementsByTagName(u"table"_ns);
- if (nestedTables->Length() > 0) {
- RETURN_LAYOUT_ANSWER(true, "Has a nested table within it");
- }
-
- // If only 1 column or only 1 row, it's for layout.
- auto colCount = ColCount();
- if (colCount <= 1) {
- RETURN_LAYOUT_ANSWER(true, "Has only 1 column");
- }
- auto rowCount = RowCount();
- if (rowCount <= 1) {
- RETURN_LAYOUT_ANSWER(true, "Has only 1 row");
- }
-
- // Check for many columns.
- if (colCount >= 5) {
- RETURN_LAYOUT_ANSWER(false, ">=5 columns");
- }
-
- // Now we know there are 2-4 columns and 2 or more rows. Check to see if
- // there are visible borders on the cells.
- // XXX currently, we just check the first cell -- do we really need to do
- // more?
- nsTableWrapperFrame* tableFrame = do_QueryFrame(el->GetPrimaryFrame());
- if (!tableFrame) {
- RETURN_LAYOUT_ANSWER(false, "table with no frame!");
- }
-
- nsIFrame* cellFrame = tableFrame->GetCellFrameAt(0, 0);
- if (!cellFrame) {
- RETURN_LAYOUT_ANSWER(false, "table's first cell has no frame!");
- }
-
- nsMargin border = cellFrame->StyleBorder()->GetComputedBorder();
- if (border.top && border.bottom && border.left && border.right) {
- RETURN_LAYOUT_ANSWER(false, "Has nonzero border-width on table cell");
- }
-
- // Rules for non-bordered tables with 2-4 columns and 2+ rows from here on
- // forward.
-
- // Check for styled background color across rows (alternating background
- // color is a common feature for data tables).
- auto childCount = thisacc->ChildCount();
- nscolor rowColor = 0;
- nscolor prevRowColor;
- for (auto childIdx = 0U; childIdx < childCount; childIdx++) {
- LocalAccessible* child = thisacc->LocalChildAt(childIdx);
- if (child->IsHTMLTableRow()) {
- prevRowColor = rowColor;
- nsIFrame* rowFrame = child->GetFrame();
- MOZ_ASSERT(rowFrame, "Table hierarchy got screwed up");
- if (!rowFrame) {
- RETURN_LAYOUT_ANSWER(false, "Unexpected table hierarchy");
- }
-
- rowColor = rowFrame->StyleBackground()->BackgroundColor(rowFrame);
-
- if (childIdx > 0 && prevRowColor != rowColor) {
- RETURN_LAYOUT_ANSWER(false,
- "2 styles of row background color, non-bordered");
- }
- }
- }
-
- // Check for many rows.
- const uint32_t kMaxLayoutRows = 20;
- if (rowCount > kMaxLayoutRows) { // A ton of rows, this is probably for data
- RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered");
- }
-
- // Check for very wide table.
- nsIFrame* documentFrame = thisacc->Document()->GetFrame();
- nsSize documentSize = documentFrame->GetSize();
- if (documentSize.width > 0) {
- nsSize tableSize = thisacc->GetFrame()->GetSize();
- int32_t percentageOfDocWidth = (100 * tableSize.width) / documentSize.width;
- if (percentageOfDocWidth > 95) {
- // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
- // Probably for layout
- RETURN_LAYOUT_ANSWER(
- true, "<= 4 columns, table width is 95% of document width");
- }
- }
-
- // Two column rules.
- if (rowCount * colCount <= 10) {
- RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered");
- }
-
- static const nsLiteralString tags[] = {u"embed"_ns, u"object"_ns,
- u"iframe"_ns};
- for (auto& tag : tags) {
- nsCOMPtr descendants = el->GetElementsByTagName(tag);
- if (descendants->Length() > 0) {
- RETURN_LAYOUT_ANSWER(true,
- "Has no borders, and has iframe, object or embed, "
- "typical of advertisements");
- }
- }
-
- RETURN_LAYOUT_ANSWER(false,
- "No layout factor strong enough, so will guess data");
-}
-
-LocalAccessible* TableAccessible::RowAt(int32_t aRow) {
- int32_t rowIdx = aRow;
-
- AccIterator rowIter(this->AsAccessible(), filters::GetRow);
-
- LocalAccessible* row = rowIter.Next();
- while (rowIdx != 0 && (row = rowIter.Next())) {
- rowIdx--;
- }
-
- return row;
-}
-
-LocalAccessible* TableAccessible::CellInRowAt(LocalAccessible* aRow,
- int32_t aColumn) {
- int32_t colIdx = aColumn;
-
- AccIterator cellIter(aRow, filters::GetCell);
- LocalAccessible* cell = nullptr;
-
- while (colIdx >= 0 && (cell = cellIter.Next())) {
- MOZ_ASSERT(cell->IsTableCell(), "No table or grid cell!");
- colIdx -= cell->AsTableCell()->ColExtent();
- }
-
- return cell;
-}
-
-int32_t TableAccessible::ColIndexAt(uint32_t aCellIdx) {
- uint32_t colCount = ColCount();
- if (colCount < 1 || aCellIdx >= colCount * RowCount()) {
- return -1; // Error: column count is 0 or index out of bounds.
- }
-
- return aCellIdx % colCount;
-}
-
-int32_t TableAccessible::RowIndexAt(uint32_t aCellIdx) {
- uint32_t colCount = ColCount();
- if (colCount < 1 || aCellIdx >= colCount * RowCount()) {
- return -1; // Error: column count is 0 or index out of bounds.
- }
-
- return aCellIdx / colCount;
-}
-
-void TableAccessible::RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx,
- int32_t* aColIdx) {
- uint32_t colCount = ColCount();
- if (colCount < 1 || aCellIdx >= colCount * RowCount()) {
- *aRowIdx = -1;
- *aColIdx = -1;
- return; // Error: column count is 0 or index out of bounds.
- }
-
- *aRowIdx = aCellIdx / colCount;
- *aColIdx = aCellIdx % colCount;
-}
diff -Nru firefox-esr-115.3.1esr+build1/accessible/generic/TableAccessible.h firefox-esr-115.4.0esr+build1/accessible/generic/TableAccessible.h
--- firefox-esr-115.3.1esr+build1/accessible/generic/TableAccessible.h 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/generic/TableAccessible.h 1970-01-01 00:00:00.000000000 +0000
@@ -1,72 +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 TABLE_ACCESSIBLE_H
-#define TABLE_ACCESSIBLE_H
-
-#include "LocalAccessible.h"
-#include "mozilla/a11y/TableAccessibleBase.h"
-#include "mozilla/a11y/TableCellAccessibleBase.h"
-#include "nsPointerHashKeys.h"
-#include "nsRefPtrHashtable.h"
-
-namespace mozilla {
-namespace a11y {
-
-/**
- * Base class for LocalAccessible table implementations.
- */
-class TableAccessible : public TableAccessibleBase {
- public:
- virtual LocalAccessible* Caption() const override { return nullptr; }
-
- virtual LocalAccessible* CellAt(uint32_t aRowIdx, uint32_t aColIdx) override {
- return nullptr;
- }
-
- virtual int32_t CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) override {
- return ColCount() * aRowIdx + aColIdx;
- }
-
- virtual int32_t ColIndexAt(uint32_t aCellIdx) override;
- virtual int32_t RowIndexAt(uint32_t aCellIdx) override;
- virtual void RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx,
- int32_t* aColIdx) override;
- virtual bool IsProbablyLayoutTable() override;
- virtual LocalAccessible* AsAccessible() override = 0;
-
- using HeaderCache =
- nsRefPtrHashtable,
- LocalAccessible>;
-
- /**
- * Get the header cache, which maps a TableCellAccessible to its previous
- * header.
- * Although this data is only used in TableCellAccessible, it is stored on
- * TableAccessible so the cache can be easily invalidated when the table
- * is mutated.
- */
- HeaderCache& GetHeaderCache() { return mHeaderCache; }
-
- protected:
- /**
- * Return row accessible at the given row index.
- */
- LocalAccessible* RowAt(int32_t aRow);
-
- /**
- * Return cell accessible at the given column index in the row.
- */
- LocalAccessible* CellInRowAt(LocalAccessible* aRow, int32_t aColumn);
-
- private:
- HeaderCache mHeaderCache;
-};
-
-} // namespace a11y
-} // namespace mozilla
-
-#endif
diff -Nru firefox-esr-115.3.1esr+build1/accessible/generic/TableCellAccessible.cpp firefox-esr-115.4.0esr+build1/accessible/generic/TableCellAccessible.cpp
--- firefox-esr-115.3.1esr+build1/accessible/generic/TableCellAccessible.cpp 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/generic/TableCellAccessible.cpp 1970-01-01 00:00:00.000000000 +0000
@@ -1,165 +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/. */
-
-#include "TableCellAccessible.h"
-
-#include "LocalAccessible-inl.h"
-#include "TableAccessible.h"
-
-using namespace mozilla;
-using namespace mozilla::a11y;
-
-void TableCellAccessible::RowHeaderCells(nsTArray* aCells) {
- uint32_t rowIdx = RowIdx(), colIdx = ColIdx();
- TableAccessible* table = Table();
- if (!table) return;
-
- // Move to the left to find row header cells
- for (uint32_t curColIdx = colIdx - 1; curColIdx < colIdx; curColIdx--) {
- LocalAccessible* cell = table->CellAt(rowIdx, curColIdx);
- if (!cell) continue;
-
- // CellAt should always return a TableCellAccessible (XXX Bug 587529)
- TableCellAccessible* tableCell = cell->AsTableCell();
- NS_ASSERTION(tableCell, "cell should be a table cell!");
- if (!tableCell) continue;
-
- // Avoid addding cells multiple times, if this cell spans more columns
- // we'll get it later.
- if (tableCell->ColIdx() == curColIdx && cell->Role() == roles::ROWHEADER) {
- aCells->AppendElement(cell);
- }
- }
-}
-
-LocalAccessible* TableCellAccessible::PrevColHeader() {
- TableAccessible* table = Table();
- if (!table) {
- return nullptr;
- }
-
- TableAccessible::HeaderCache& cache = table->GetHeaderCache();
- bool inCache = false;
- LocalAccessible* cachedHeader = cache.GetWeak(this, &inCache);
- if (inCache) {
- // Cached but null means we know there is no previous column header.
- // if defunct, the cell was removed, so behave as if there is no cached
- // value.
- if (!cachedHeader || !cachedHeader->IsDefunct()) {
- return cachedHeader;
- }
- }
-
- uint32_t rowIdx = RowIdx(), colIdx = ColIdx();
- for (uint32_t curRowIdx = rowIdx - 1; curRowIdx < rowIdx; curRowIdx--) {
- LocalAccessible* cell = table->CellAt(curRowIdx, colIdx);
- if (!cell) {
- continue;
- }
- // CellAt should always return a TableCellAccessible (XXX Bug 587529)
- TableCellAccessible* tableCell = cell->AsTableCell();
- MOZ_ASSERT(tableCell, "cell should be a table cell!");
- if (!tableCell) {
- continue;
- }
-
- // Check whether the previous table cell has a cached value.
- cachedHeader = cache.GetWeak(tableCell, &inCache);
- if (
- // We check the cache first because even though we might not use it,
- // it's faster than the other conditions.
- inCache &&
- // Only use the cached value if:
- // 1. cell is a table cell which is not a column header. In that case,
- // cell is the previous header and cachedHeader is the one before that.
- // We will return cell later.
- cell->Role() != roles::COLUMNHEADER &&
- // 2. cell starts in this column. If it starts in a previous column and
- // extends into this one, its header will be for the starting column,
- // which is wrong for this cell.
- // ColExtent is faster than ColIdx, so check that first.
- (tableCell->ColExtent() == 1 || tableCell->ColIdx() == colIdx)) {
- if (!cachedHeader || !cachedHeader->IsDefunct()) {
- // Cache it for this cell.
- cache.InsertOrUpdate(this, RefPtr(cachedHeader));
- return cachedHeader;
- }
- }
-
- // Avoid addding cells multiple times, if this cell spans more rows
- // we'll get it later.
- if (cell->Role() != roles::COLUMNHEADER ||
- tableCell->RowIdx() != curRowIdx) {
- continue;
- }
-
- // Cache the header we found.
- cache.InsertOrUpdate(this, RefPtr(cell));
- return cell;
- }
-
- // There's no header, so cache that fact.
- cache.InsertOrUpdate(this, RefPtr(nullptr));
- return nullptr;
-}
-
-void TableCellAccessible::ColHeaderCells(nsTArray* aCells) {
- for (LocalAccessible* cell = PrevColHeader(); cell;
- cell = cell->AsTableCell()->PrevColHeader()) {
- aCells->AppendElement(cell);
- }
-}
-
-a11y::role TableCellAccessible::GetHeaderCellRole(
- const LocalAccessible* aAcc) const {
- if (!aAcc || !aAcc->GetContent() || !aAcc->GetContent()->IsElement()) {
- return roles::NOTHING;
- }
-
- MOZ_ASSERT(aAcc->IsTableCell());
-
- // Check value of @scope attribute.
- static mozilla::dom::Element::AttrValuesArray scopeValues[] = {
- nsGkAtoms::col, nsGkAtoms::colgroup, nsGkAtoms::row, nsGkAtoms::rowgroup,
- nullptr};
- int32_t valueIdx = aAcc->GetContent()->AsElement()->FindAttrValueIn(
- kNameSpaceID_None, nsGkAtoms::scope, scopeValues, eCaseMatters);
-
- switch (valueIdx) {
- case 0:
- case 1:
- return roles::COLUMNHEADER;
- case 2:
- case 3:
- return roles::ROWHEADER;
- }
-
- TableAccessible* table = Table();
- if (!table) {
- return roles::NOTHING;
- }
-
- // If the cell next to this one is not a header cell then assume this cell is
- // a row header for it.
- uint32_t rowIdx = RowIdx(), colIdx = ColIdx();
- LocalAccessible* cell = table->CellAt(rowIdx, colIdx + ColExtent());
- if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent())) {
- return roles::ROWHEADER;
- }
-
- // If the cell below this one is not a header cell then assume this cell is
- // a column header for it.
- uint32_t rowExtent = RowExtent();
- cell = table->CellAt(rowIdx + rowExtent, colIdx);
- if (cell && !nsCoreUtils::IsHTMLTableHeader(cell->GetContent())) {
- return roles::COLUMNHEADER;
- }
-
- // Otherwise if this cell is surrounded by header cells only then make a guess
- // based on its cell spanning. In other words if it is row spanned then assume
- // it's a row header, otherwise it's a column header.
- return rowExtent > 1 ? roles::ROWHEADER : roles::COLUMNHEADER;
-}
diff -Nru firefox-esr-115.3.1esr+build1/accessible/generic/TableCellAccessible.h firefox-esr-115.4.0esr+build1/accessible/generic/TableCellAccessible.h
--- firefox-esr-115.3.1esr+build1/accessible/generic/TableCellAccessible.h 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/generic/TableCellAccessible.h 1970-01-01 00:00:00.000000000 +0000
@@ -1,40 +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_TableCellAccessible_h__
-#define mozilla_a11y_TableCellAccessible_h__
-
-#include "mozilla/a11y/TableCellAccessibleBase.h"
-#include "TableAccessible.h"
-
-namespace mozilla {
-namespace a11y {
-
-class LocalAccessible;
-
-/**
- * Base class for LocalAccessible table cell implementations.
- */
-class TableCellAccessible : public TableCellAccessibleBase {
- public:
- virtual TableAccessible* Table() const override = 0;
- virtual void ColHeaderCells(nsTArray* aCells) override;
- virtual void RowHeaderCells(nsTArray* aCells) override;
-
- protected:
- // Get the proper role for the given header cell accessible. The given acc
- // must be either an ARIA grid cell accessible for a th element or a true
- // table header cell accessible for the result to be valid.
- a11y::role GetHeaderCellRole(const LocalAccessible* aAcc) const;
-
- private:
- LocalAccessible* PrevColHeader();
-};
-
-} // namespace a11y
-} // namespace mozilla
-
-#endif // mozilla_a11y_TableCellAccessible_h__
diff -Nru firefox-esr-115.3.1esr+build1/accessible/html/HTMLTableAccessible.cpp firefox-esr-115.4.0esr+build1/accessible/html/HTMLTableAccessible.cpp
--- firefox-esr-115.3.1esr+build1/accessible/html/HTMLTableAccessible.cpp 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/html/HTMLTableAccessible.cpp 2023-10-17 05:45:44.000000000 +0000
@@ -5,11 +5,12 @@
#include "HTMLTableAccessible.h"
+#include
#include "mozilla/DebugOnly.h"
#include "nsAccessibilityService.h"
-#include "nsAccUtils.h"
#include "AccAttributes.h"
+#include "ARIAMap.h"
#include "CacheConstants.h"
#include "DocAccessible.h"
#include "LocalAccessible-inl.h"
@@ -17,18 +18,29 @@
#include "Relation.h"
#include "Role.h"
#include "States.h"
-#include "TreeWalker.h"
#include "mozilla/PresShell.h"
+#include "mozilla/a11y/TableAccessible.h"
+#include "mozilla/a11y/TableCellAccessible.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLTableElement.h"
+#include "mozilla/dom/NameSpaceConstants.h"
+#include "nsCaseTreatment.h"
+#include "nsColor.h"
+#include "nsCOMPtr.h"
+#include "nsCoreUtils.h"
+#include "nsDebug.h"
#include "nsIHTMLCollection.h"
-#include "mozilla/dom/Document.h"
#include "nsITableCellLayout.h"
#include "nsFrameSelection.h"
#include "nsError.h"
-#include "nsArrayUtils.h"
-#include "nsComponentManagerUtils.h"
-#include "nsNameSpaceManager.h"
+#include "nsGkAtoms.h"
+#include "nsLiteralString.h"
+#include "nsMargin.h"
+#include "nsQueryFrame.h"
+#include "nsSize.h"
+#include "nsStringFwd.h"
#include "nsTableCellFrame.h"
#include "nsTableWrapperFrame.h"
@@ -51,6 +63,10 @@
// HTMLTableCellAccessible: LocalAccessible implementation
role HTMLTableCellAccessible::NativeRole() const {
+ // We implement this rather than using the markup maps because we only want
+ // this role to be returned if this is a valid cell. An invalid cell (e.g. if
+ // the table has role="none") won't use this class, so it will get a generic
+ // role, since the markup map doesn't specify a role.
if (mContent->IsMathMLElement(nsGkAtoms::mtd_)) {
return roles::MATHML_CELL;
}
@@ -78,21 +94,22 @@
RefPtr attributes =
HyperTextAccessibleWrap::NativeAttributes();
- // table-cell-index attribute
- TableAccessible* table = Table();
- if (!table) {
- return attributes.forget();
- }
-
- int32_t rowIdx = -1, colIdx = -1;
- nsresult rv = GetCellIndexes(rowIdx, colIdx);
- if (NS_FAILED(rv)) {
- return attributes.forget();
+ // 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 TableCellAccessible* cell = AsTableCell()) {
+ TableAccessible* 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,
- table->CellIndexAt(rowIdx, colIdx));
-
// abbr attribute
// Pick up object attribute from abbr DOM element (a child of the cell) or
@@ -124,11 +141,6 @@
attributes->SetAttribute(nsGkAtoms::axis, std::move(axisText));
}
-#ifdef DEBUG
- RefPtr cppClass = NS_Atomize(u"cppclass"_ns);
- attributes->SetAttributeStringCopy(cppClass, u"HTMLTableCellAccessible"_ns);
-#endif
-
return attributes.forget();
}
@@ -144,61 +156,52 @@
aAttribute == nsGkAtoms::scope) {
mDoc->FireDelayedEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
this);
- if (TableAccessible* table = Table()) {
+ if (HTMLTableAccessible* table = Table()) {
// Modifying these attributes can also modify our table's classification
// as either a layout or data table. Queue an update on the table itself
// to re-compute our "layout guess"
- mDoc->QueueCacheUpdate(table->AsAccessible(), CacheDomain::Table);
+ mDoc->QueueCacheUpdate(table, CacheDomain::Table);
}
mDoc->QueueCacheUpdate(this, CacheDomain::Table);
} else if (aAttribute == nsGkAtoms::rowspan ||
aAttribute == nsGkAtoms::colspan) {
- if (TableAccessible* table = Table()) {
+ if (HTMLTableAccessible* table = Table()) {
// Modifying these attributes can also modify our table's classification
// as either a layout or data table. Queue an update on the table itself
// to re-compute our "layout guess"
- mDoc->QueueCacheUpdate(table->AsAccessible(), CacheDomain::Table);
+ mDoc->QueueCacheUpdate(table, CacheDomain::Table);
}
mDoc->QueueCacheUpdate(this, CacheDomain::Table);
}
}
////////////////////////////////////////////////////////////////////////////////
-// HTMLTableCellAccessible: TableCellAccessible implementation
+// HTMLTableCellAccessible implementation
-TableAccessible* HTMLTableCellAccessible::Table() const {
+HTMLTableAccessible* HTMLTableCellAccessible::Table() const {
LocalAccessible* parent = const_cast(this);
while ((parent = parent->LocalParent())) {
- if (parent->IsTable()) {
- return parent->AsTable();
+ if (parent->IsHTMLTable()) {
+ return HTMLTableAccessible::GetFrom(parent);
}
}
return nullptr;
}
-uint32_t HTMLTableCellAccessible::ColIdx() const {
- nsTableCellFrame* cellFrame = GetCellFrame();
- NS_ENSURE_TRUE(cellFrame, 0);
- return cellFrame->ColIndex();
-}
-
-uint32_t HTMLTableCellAccessible::RowIdx() const {
- nsTableCellFrame* cellFrame = GetCellFrame();
- NS_ENSURE_TRUE(cellFrame, 0);
- return cellFrame->RowIndex();
-}
-
uint32_t HTMLTableCellAccessible::ColExtent() const {
int32_t rowIdx = -1, colIdx = -1;
if (NS_FAILED(GetCellIndexes(rowIdx, colIdx))) {
- return 0;
+ // This probably isn't a table according to the layout engine; e.g. it has
+ // display: block.
+ return 1;
}
- TableAccessible* table = Table();
- NS_ASSERTION(table, "cell not in a table!");
- if (!table) {
- return 0;
+ HTMLTableAccessible* table = Table();
+ if (NS_WARN_IF(!table)) {
+ // This can happen where there is a inside a such as
+ // in Monorail.
+ return 1;
}
return table->ColExtentAt(rowIdx, colIdx);
@@ -207,72 +210,21 @@
uint32_t HTMLTableCellAccessible::RowExtent() const {
int32_t rowIdx = -1, colIdx = -1;
if (NS_FAILED(GetCellIndexes(rowIdx, colIdx))) {
- return 0;
+ // This probably isn't a table according to the layout engine; e.g. it has
+ // display: block.
+ return 1;
}
- TableAccessible* table = Table();
- NS_ASSERTION(table, "cell not in atable!");
- if (!table) {
- return 0;
+ HTMLTableAccessible* table = Table();
+ if (NS_WARN_IF(!table)) {
+ // This can happen where there is a
inside a such as
+ // in Monorail.
+ return 1;
}
return table->RowExtentAt(rowIdx, colIdx);
}
-void HTMLTableCellAccessible::ColHeaderCells(nsTArray
* aCells) {
- IDRefsIterator itr(mDoc, mContent, nsGkAtoms::headers);
- while (LocalAccessible* cell = itr.Next()) {
- a11y::role cellRole = cell->Role();
- if (cellRole == roles::COLUMNHEADER) {
- aCells->AppendElement(cell);
- } else if (cellRole != roles::ROWHEADER) {
- // If referred table cell is at the same column then treat it as a column
- // header.
- TableCellAccessible* tableCell = cell->AsTableCell();
- if (tableCell && tableCell->ColIdx() == ColIdx()) {
- aCells->AppendElement(cell);
- }
- }
- }
-
- if (aCells->IsEmpty()) {
- TableCellAccessible::ColHeaderCells(aCells);
- }
-}
-
-void HTMLTableCellAccessible::RowHeaderCells(nsTArray* aCells) {
- IDRefsIterator itr(mDoc, mContent, nsGkAtoms::headers);
- while (LocalAccessible* cell = itr.Next()) {
- a11y::role cellRole = cell->Role();
- if (cellRole == roles::ROWHEADER) {
- aCells->AppendElement(cell);
- } else if (cellRole != roles::COLUMNHEADER) {
- // If referred table cell is at the same row then treat it as a column
- // header.
- TableCellAccessible* tableCell = cell->AsTableCell();
- if (tableCell && tableCell->RowIdx() == RowIdx()) {
- aCells->AppendElement(cell);
- }
- }
- }
-
- if (aCells->IsEmpty()) {
- TableCellAccessible::RowHeaderCells(aCells);
- }
-}
-
-bool HTMLTableCellAccessible::Selected() {
- int32_t rowIdx = -1, colIdx = -1;
- if (NS_FAILED(GetCellIndexes(rowIdx, colIdx))) {
- return false;
- }
-
- TableAccessible* table = Table();
- NS_ENSURE_TRUE(table, false);
-
- return table->IsCellSelected(rowIdx, colIdx);
-}
-
////////////////////////////////////////////////////////////////////////////////
// HTMLTableCellAccessible: protected implementation
@@ -280,10 +232,6 @@
return do_QueryFrame(mContent->GetPrimaryFrame());
}
-nsTableCellFrame* HTMLTableCellAccessible::GetCellFrame() const {
- return do_QueryFrame(mContent->GetPrimaryFrame());
-}
-
nsresult HTMLTableCellAccessible::GetCellIndexes(int32_t& aRowIdx,
int32_t& aColIdx) const {
nsITableCellLayout* cellLayout = GetCellLayout();
@@ -304,22 +252,74 @@
// HTMLTableHeaderCellAccessible: LocalAccessible implementation
role HTMLTableHeaderCellAccessible::NativeRole() const {
- return GetHeaderCellRole(this);
+ dom::Element* el = Elm();
+ if (!el) {
+ return roles::NOTHING;
+ }
+
+ // Check value of @scope attribute.
+ static mozilla::dom::Element::AttrValuesArray scopeValues[] = {
+ nsGkAtoms::col, nsGkAtoms::colgroup, nsGkAtoms::row, nsGkAtoms::rowgroup,
+ nullptr};
+ int32_t valueIdx = el->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::scope,
+ scopeValues, eCaseMatters);
+
+ switch (valueIdx) {
+ case 0:
+ case 1:
+ return roles::COLUMNHEADER;
+ case 2:
+ case 3:
+ return roles::ROWHEADER;
+ }
+
+ dom::Element* nextEl = el->GetNextElementSibling();
+ dom::Element* prevEl = el->GetPreviousElementSibling();
+ // If this is the only cell in its row, it's a column header.
+ if (!nextEl && !prevEl) {
+ return roles::COLUMNHEADER;
+ }
+ const bool nextIsHeader = nextEl && nsCoreUtils::IsHTMLTableHeader(nextEl);
+ const bool prevIsHeader = prevEl && nsCoreUtils::IsHTMLTableHeader(prevEl);
+ // If this has a header on both sides, it is a column header.
+ if (prevIsHeader && nextIsHeader) {
+ return roles::COLUMNHEADER;
+ }
+ // If this has a header on one side and only a single normal cell on the
+ // other, it's a column header.
+ if (nextIsHeader && prevEl && !prevEl->GetPreviousElementSibling()) {
+ return roles::COLUMNHEADER;
+ }
+ if (prevIsHeader && nextEl && !nextEl->GetNextElementSibling()) {
+ return roles::COLUMNHEADER;
+ }
+ // If this has a normal cell next to it, it 's a row header.
+ if ((nextEl && !nextIsHeader) || (prevEl && !prevIsHeader)) {
+ return roles::ROWHEADER;
+ }
+ // If this has a row span, it could be a row header.
+ if (RowExtent() > 1) {
+ // It isn't a row header if it has 1 or more consecutive headers next to it.
+ if (prevIsHeader &&
+ (!prevEl->GetPreviousElementSibling() ||
+ nsCoreUtils::IsHTMLTableHeader(prevEl->GetPreviousElementSibling()))) {
+ return roles::COLUMNHEADER;
+ }
+ if (nextIsHeader &&
+ (!nextEl->GetNextElementSibling() ||
+ nsCoreUtils::IsHTMLTableHeader(nextEl->GetNextElementSibling()))) {
+ return roles::COLUMNHEADER;
+ }
+ return roles::ROWHEADER;
+ }
+ // Otherwise, assume it's a column header.
+ return roles::COLUMNHEADER;
}
////////////////////////////////////////////////////////////////////////////////
// HTMLTableRowAccessible
////////////////////////////////////////////////////////////////////////////////
-role HTMLTableRowAccessible::NativeRole() const {
- if (mContent->IsMathMLElement(nsGkAtoms::mtr_)) {
- return roles::MATHML_TABLE_ROW;
- } else if (mContent->IsMathMLElement(nsGkAtoms::mlabeledtr_)) {
- return roles::MATHML_LABELED_ROW;
- }
- return roles::ROW;
-}
-
// LocalAccessible protected
ENameValueFlag HTMLTableRowAccessible::NativeName(nsString& aName) const {
// For table row accessibles, we only want to calculate the name from the
@@ -348,13 +348,6 @@
aChild->IsHTMLCaption() ? 0 : aIndex, aChild);
}
-role HTMLTableAccessible::NativeRole() const {
- if (mContent->IsMathMLElement(nsGkAtoms::mtable_)) {
- return roles::MATHML_TABLE;
- }
- return roles::TABLE;
-}
-
uint64_t HTMLTableAccessible::NativeState() const {
return LocalAccessible::NativeState() | states::READONLY;
}
@@ -450,14 +443,6 @@
: nullptr;
}
-void HTMLTableAccessible::Summary(nsString& aSummary) {
- dom::HTMLTableElement* table = dom::HTMLTableElement::FromNode(mContent);
-
- if (table) {
- table->GetSummary(aSummary);
- }
-}
-
uint32_t HTMLTableAccessible::ColCount() const {
nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
return tableFrame ? tableFrame->GetColCount() : 0;
@@ -468,374 +453,262 @@
return tableFrame ? tableFrame->GetRowCount() : 0;
}
-uint32_t HTMLTableAccessible::SelectedCellCount() {
+uint32_t HTMLTableAccessible::ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx) {
nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
if (!tableFrame) {
- return 0;
+ return 1;
}
- uint32_t count = 0, rowCount = RowCount(), colCount = ColCount();
- for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
- for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
- nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
- if (!cellFrame || !cellFrame->IsSelected()) {
- continue;
- }
-
- uint32_t startRow = cellFrame->RowIndex();
- uint32_t startCol = cellFrame->ColIndex();
- if (startRow == rowIdx && startCol == colIdx) {
- count++;
- }
- }
- }
-
- return count;
+ return tableFrame->GetEffectiveColSpanAt(aRowIdx, aColIdx);
}
-uint32_t HTMLTableAccessible::SelectedColCount() {
- uint32_t count = 0, colCount = ColCount();
-
- for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
- if (IsColSelected(colIdx)) {
- count++;
- }
+uint32_t HTMLTableAccessible::RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx) {
+ nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
+ if (!tableFrame) {
+ return 1;
}
- return count;
+ return tableFrame->GetEffectiveRowSpanAt(aRowIdx, aColIdx);
}
-uint32_t HTMLTableAccessible::SelectedRowCount() {
- uint32_t count = 0, rowCount = RowCount();
+bool HTMLTableAccessible::IsProbablyLayoutTable() {
+ // Implement a heuristic to determine if table is most likely used for layout.
- for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
- if (IsRowSelected(rowIdx)) {
- count++;
- }
- }
+ // XXX do we want to look for rowspan or colspan, especialy that span all but
+ // a couple cells at the beginning or end of a row/col, and especially when
+ // they occur at the edge of a table?
+
+ // XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC
+ // This will allow release trunk builds to be used by testers to refine
+ // the algorithm. Integrate it into Logging.
+ // Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release
+#ifdef SHOW_LAYOUT_HEURISTIC
+# define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \
+ { \
+ mLayoutHeuristic = isLayout \
+ ? nsLiteralString(u"layout table: " heuristic) \
+ : nsLiteralString(u"data table: " heuristic); \
+ return isLayout; \
+ }
+#else
+# define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \
+ { return isLayout; }
+#endif
- return count;
-}
+ MOZ_ASSERT(!IsDefunct(), "Table accessible should not be defunct");
-void HTMLTableAccessible::SelectedCells(nsTArray* aCells) {
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
- if (!tableFrame) {
- return;
+ // Need to see all elements while document is being edited.
+ if (Document()->State() & states::EDITABLE) {
+ RETURN_LAYOUT_ANSWER(false, "In editable document");
}
- uint32_t rowCount = RowCount(), colCount = ColCount();
- for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
- for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
- nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
- if (!cellFrame || !cellFrame->IsSelected()) {
- continue;
- }
-
- uint32_t startRow = cellFrame->RowIndex();
- uint32_t startCol = cellFrame->ColIndex();
- if (startRow != rowIdx || startCol != colIdx) {
- continue;
- }
-
- LocalAccessible* cell = mDoc->GetAccessible(cellFrame->GetContent());
- aCells->AppendElement(cell);
- }
+ // Check to see if an ARIA role overrides the role from native markup,
+ // but for which we still expose table semantics (treegrid, for example).
+ if (HasARIARole()) {
+ RETURN_LAYOUT_ANSWER(false, "Has role attribute");
}
-}
-void HTMLTableAccessible::SelectedCellIndices(nsTArray* aCells) {
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
- if (!tableFrame) {
- return;
+ dom::Element* el = Elm();
+ if (el->IsMathMLElement(nsGkAtoms::mtable_)) {
+ RETURN_LAYOUT_ANSWER(false, "MathML matrix");
}
- uint32_t rowCount = RowCount(), colCount = ColCount();
- for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
- for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
- nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
- if (!cellFrame || !cellFrame->IsSelected()) {
- continue;
- }
+ MOZ_ASSERT(el->IsHTMLElement(nsGkAtoms::table),
+ "Table should not be built by CSS display:table style");
- uint32_t startCol = cellFrame->ColIndex();
- uint32_t startRow = cellFrame->RowIndex();
- if (startRow == rowIdx && startCol == colIdx) {
- aCells->AppendElement(CellIndexAt(rowIdx, colIdx));
- }
- }
+ // Check if datatable attribute has "0" value.
+ if (el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::datatable, u"0"_ns,
+ eCaseMatters)) {
+ RETURN_LAYOUT_ANSWER(true, "Has datatable = 0 attribute, it's for layout");
}
-}
-void HTMLTableAccessible::SelectedColIndices(nsTArray* aCols) {
- uint32_t colCount = ColCount();
- for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
- if (IsColSelected(colIdx)) {
- aCols->AppendElement(colIdx);
- }
+ // Check for legitimate data table attributes.
+ if (el->Element::HasNonEmptyAttr(nsGkAtoms::summary)) {
+ RETURN_LAYOUT_ANSWER(false, "Has summary -- legitimate table structures");
}
-}
-void HTMLTableAccessible::SelectedRowIndices(nsTArray* aRows) {
- uint32_t rowCount = RowCount();
- for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
- if (IsRowSelected(rowIdx)) {
- aRows->AppendElement(rowIdx);
- }
+ // Check for legitimate data table elements.
+ LocalAccessible* caption = LocalFirstChild();
+ if (caption && caption->IsHTMLCaption() && caption->HasChildren()) {
+ RETURN_LAYOUT_ANSWER(false,
+ "Not empty caption -- legitimate table structures");
}
-}
-LocalAccessible* HTMLTableAccessible::CellAt(uint32_t aRowIdx,
- uint32_t aColIdx) {
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
- if (!tableFrame) {
- return nullptr;
- }
+ for (nsIContent* childElm = el->GetFirstChild(); childElm;
+ childElm = childElm->GetNextSibling()) {
+ if (!childElm->IsHTMLElement()) continue;
- nsIContent* cellContent = tableFrame->GetCellAt(aRowIdx, aColIdx);
- LocalAccessible* cell = mDoc->GetAccessible(cellContent);
+ if (childElm->IsAnyOfHTMLElements(nsGkAtoms::col, nsGkAtoms::colgroup,
+ nsGkAtoms::tfoot, nsGkAtoms::thead)) {
+ RETURN_LAYOUT_ANSWER(
+ false,
+ "Has col, colgroup, tfoot or thead -- legitimate table structures");
+ }
- // Sometimes, the accessible returned here is a row accessible instead of
- // a cell accessible, for example when a cell has CSS display:block; set.
- // In such cases, iterate through the cells in this row differently to find
- // it.
- if (cell && cell->IsTableRow()) {
- return CellInRowAt(cell, aColIdx);
- }
+ if (childElm->IsHTMLElement(nsGkAtoms::tbody)) {
+ for (nsIContent* rowElm = childElm->GetFirstChild(); rowElm;
+ rowElm = rowElm->GetNextSibling()) {
+ if (rowElm->IsHTMLElement(nsGkAtoms::tr)) {
+ if (LocalAccessible* row = Document()->GetAccessible(rowElm)) {
+ if (const nsRoleMapEntry* roleMapEntry = row->ARIARoleMap()) {
+ if (roleMapEntry->role != roles::ROW) {
+ RETURN_LAYOUT_ANSWER(true, "Repurposed tr with different role");
+ }
+ }
+ }
- // XXX bug 576838: bizarre tables (like table6 in tables/test_table2.html) may
- // return itself as a cell what makes Orca hang.
- return cell == this ? nullptr : cell;
-}
+ for (nsIContent* cellElm = rowElm->GetFirstChild(); cellElm;
+ cellElm = cellElm->GetNextSibling()) {
+ if (cellElm->IsHTMLElement()) {
+ if (cellElm->NodeInfo()->Equals(nsGkAtoms::th)) {
+ RETURN_LAYOUT_ANSWER(false,
+ "Has th -- legitimate table structures");
+ }
-int32_t HTMLTableAccessible::CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) {
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
- if (!tableFrame) {
- return -1;
- }
+ if (cellElm->AsElement()->HasAttr(kNameSpaceID_None,
+ nsGkAtoms::headers) ||
+ cellElm->AsElement()->HasAttr(kNameSpaceID_None,
+ nsGkAtoms::scope) ||
+ cellElm->AsElement()->HasAttr(kNameSpaceID_None,
+ nsGkAtoms::abbr)) {
+ RETURN_LAYOUT_ANSWER(false,
+ "Has headers, scope, or abbr attribute -- "
+ "legitimate table structures");
+ }
- int32_t cellIndex = tableFrame->GetIndexByRowAndColumn(aRowIdx, aColIdx);
- if (cellIndex == -1) {
- // Sometimes, the accessible returned here is a row accessible instead of
- // a cell accessible, for example when a cell has CSS display:block; set.
- // In such cases, iterate through the cells in this row differently to find
- // it.
- nsIContent* cellContent = tableFrame->GetCellAt(aRowIdx, aColIdx);
- LocalAccessible* cell = mDoc->GetAccessible(cellContent);
- if (cell && cell->IsTableRow()) {
- return TableAccessible::CellIndexAt(aRowIdx, aColIdx);
+ if (LocalAccessible* cell = Document()->GetAccessible(cellElm)) {
+ if (const nsRoleMapEntry* roleMapEntry = cell->ARIARoleMap()) {
+ if (roleMapEntry->role != roles::CELL &&
+ roleMapEntry->role != roles::COLUMNHEADER &&
+ roleMapEntry->role != roles::ROWHEADER &&
+ roleMapEntry->role != roles::GRID_CELL) {
+ RETURN_LAYOUT_ANSWER(true,
+ "Repurposed cell with different role");
+ }
+ }
+ if (cell->ChildCount() == 1 &&
+ cell->LocalFirstChild()->IsAbbreviation()) {
+ RETURN_LAYOUT_ANSWER(
+ false, "has abbr -- legitimate table structures");
+ }
+ }
+ }
+ }
+ }
+ }
}
}
- return cellIndex;
-}
-
-int32_t HTMLTableAccessible::ColIndexAt(uint32_t aCellIdx) {
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
- if (!tableFrame) {
- return -1;
- }
-
- int32_t rowIdx = -1, colIdx = -1;
- tableFrame->GetRowAndColumnByIndex(aCellIdx, &rowIdx, &colIdx);
-
- if (colIdx == -1) {
- // Sometimes, the index returned indicates that this is not a regular
- // cell, for example when a cell has CSS display:block; set.
- // In such cases, try the super class method to find it.
- return TableAccessible::ColIndexAt(aCellIdx);
+ // Check for nested tables.
+ nsCOMPtr nestedTables =
+ el->GetElementsByTagName(u"table"_ns);
+ if (nestedTables->Length() > 0) {
+ RETURN_LAYOUT_ANSWER(true, "Has a nested table within it");
}
- return colIdx;
-}
-
-int32_t HTMLTableAccessible::RowIndexAt(uint32_t aCellIdx) {
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
- if (!tableFrame) {
- return -1;
+ // If only 1 column or only 1 row, it's for layout.
+ auto colCount = ColCount();
+ if (colCount <= 1) {
+ RETURN_LAYOUT_ANSWER(true, "Has only 1 column");
}
-
- int32_t rowIdx = -1, colIdx = -1;
- tableFrame->GetRowAndColumnByIndex(aCellIdx, &rowIdx, &colIdx);
-
- if (rowIdx == -1) {
- // Sometimes, the index returned indicates that this is not a regular
- // cell, for example when a cell has CSS display:block; set.
- // In such cases, try the super class method to find it.
- return TableAccessible::RowIndexAt(aCellIdx);
+ auto rowCount = RowCount();
+ if (rowCount <= 1) {
+ RETURN_LAYOUT_ANSWER(true, "Has only 1 row");
}
- return rowIdx;
-}
-
-void HTMLTableAccessible::RowAndColIndicesAt(uint32_t aCellIdx,
- int32_t* aRowIdx,
- int32_t* aColIdx) {
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
- if (tableFrame) {
- tableFrame->GetRowAndColumnByIndex(aCellIdx, aRowIdx, aColIdx);
- if (*aRowIdx == -1 || *aColIdx == -1) {
- // Sometimes, the index returned indicates that this is not a regular
- // cell, for example when a cell has CSS display:block; set.
- // In such cases, try the super class method to find it.
- TableAccessible::RowAndColIndicesAt(aCellIdx, aRowIdx, aColIdx);
- }
+ // Check for many columns.
+ if (colCount >= 5) {
+ RETURN_LAYOUT_ANSWER(false, ">=5 columns");
}
-}
-uint32_t HTMLTableAccessible::ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx) {
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
+ // Now we know there are 2-4 columns and 2 or more rows. Check to see if
+ // there are visible borders on the cells.
+ // XXX currently, we just check the first cell -- do we really need to do
+ // more?
+ nsTableWrapperFrame* tableFrame = do_QueryFrame(el->GetPrimaryFrame());
if (!tableFrame) {
- return 0;
+ RETURN_LAYOUT_ANSWER(false, "table with no frame!");
}
- uint32_t colExtent = tableFrame->GetEffectiveColSpanAt(aRowIdx, aColIdx);
- if (colExtent == 0) {
- nsIContent* cellContent = tableFrame->GetCellAt(aRowIdx, aColIdx);
- LocalAccessible* cell = mDoc->GetAccessible(cellContent);
- if (cell && cell->IsTableRow()) {
- return TableAccessible::ColExtentAt(aRowIdx, aColIdx);
- }
+ nsIFrame* cellFrame = tableFrame->GetCellFrameAt(0, 0);
+ if (!cellFrame) {
+ RETURN_LAYOUT_ANSWER(false, "table's first cell has no frame!");
}
- return colExtent;
-}
-
-uint32_t HTMLTableAccessible::RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx) {
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
- if (!tableFrame) {
- return 0;
+ nsMargin border = cellFrame->StyleBorder()->GetComputedBorder();
+ if (border.top && border.bottom && border.left && border.right) {
+ RETURN_LAYOUT_ANSWER(false, "Has nonzero border-width on table cell");
}
- return tableFrame->GetEffectiveRowSpanAt(aRowIdx, aColIdx);
-}
+ // Rules for non-bordered tables with 2-4 columns and 2+ rows from here on
+ // forward.
-bool HTMLTableAccessible::IsColSelected(uint32_t aColIdx) {
- bool isSelected = false;
-
- uint32_t rowCount = RowCount();
- for (uint32_t rowIdx = 0; rowIdx < rowCount; rowIdx++) {
- isSelected = IsCellSelected(rowIdx, aColIdx);
- if (!isSelected) {
- return false;
- }
- }
-
- return isSelected;
-}
+ // Check for styled background color across rows (alternating background
+ // color is a common feature for data tables).
+ auto childCount = ChildCount();
+ nscolor rowColor = 0;
+ nscolor prevRowColor;
+ for (auto childIdx = 0U; childIdx < childCount; childIdx++) {
+ LocalAccessible* child = LocalChildAt(childIdx);
+ if (child->IsHTMLTableRow()) {
+ prevRowColor = rowColor;
+ nsIFrame* rowFrame = child->GetFrame();
+ MOZ_ASSERT(rowFrame, "Table hierarchy got screwed up");
+ if (!rowFrame) {
+ RETURN_LAYOUT_ANSWER(false, "Unexpected table hierarchy");
+ }
-bool HTMLTableAccessible::IsRowSelected(uint32_t aRowIdx) {
- bool isSelected = false;
+ rowColor = rowFrame->StyleBackground()->BackgroundColor(rowFrame);
- uint32_t colCount = ColCount();
- for (uint32_t colIdx = 0; colIdx < colCount; colIdx++) {
- isSelected = IsCellSelected(aRowIdx, colIdx);
- if (!isSelected) {
- return false;
+ if (childIdx > 0 && prevRowColor != rowColor) {
+ RETURN_LAYOUT_ANSWER(false,
+ "2 styles of row background color, non-bordered");
+ }
}
}
- return isSelected;
-}
-
-bool HTMLTableAccessible::IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) {
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
- if (!tableFrame) {
- return false;
+ // Check for many rows.
+ const uint32_t kMaxLayoutRows = 20;
+ if (rowCount > kMaxLayoutRows) { // A ton of rows, this is probably for data
+ RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered");
}
- nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(aRowIdx, aColIdx);
- return cellFrame ? cellFrame->IsSelected() : false;
-}
-
-void HTMLTableAccessible::SelectRow(uint32_t aRowIdx) {
- DebugOnly rv =
- RemoveRowsOrColumnsFromSelection(aRowIdx, TableSelectionMode::Row, true);
- NS_ASSERTION(NS_SUCCEEDED(rv),
- "RemoveRowsOrColumnsFromSelection() Shouldn't fail!");
-
- AddRowOrColumnToSelection(aRowIdx, TableSelectionMode::Row);
-}
-
-void HTMLTableAccessible::SelectCol(uint32_t aColIdx) {
- DebugOnly rv = RemoveRowsOrColumnsFromSelection(
- aColIdx, TableSelectionMode::Column, true);
- NS_ASSERTION(NS_SUCCEEDED(rv),
- "RemoveRowsOrColumnsFromSelection() Shouldn't fail!");
-
- AddRowOrColumnToSelection(aColIdx, TableSelectionMode::Column);
-}
-
-void HTMLTableAccessible::UnselectRow(uint32_t aRowIdx) {
- RemoveRowsOrColumnsFromSelection(aRowIdx, TableSelectionMode::Row, false);
-}
-
-void HTMLTableAccessible::UnselectCol(uint32_t aColIdx) {
- RemoveRowsOrColumnsFromSelection(aColIdx, TableSelectionMode::Column, false);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// HTMLTableAccessible: protected implementation
-
-nsresult HTMLTableAccessible::AddRowOrColumnToSelection(
- int32_t aIndex, TableSelectionMode aTarget) {
- bool doSelectRow = (aTarget == TableSelectionMode::Row);
-
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
- if (!tableFrame) {
- return NS_OK;
+ // Check for very wide table.
+ nsIFrame* documentFrame = Document()->GetFrame();
+ nsSize documentSize = documentFrame->GetSize();
+ if (documentSize.width > 0) {
+ nsSize tableSize = GetFrame()->GetSize();
+ int32_t percentageOfDocWidth = (100 * tableSize.width) / documentSize.width;
+ if (percentageOfDocWidth > 95) {
+ // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
+ // Probably for layout
+ RETURN_LAYOUT_ANSWER(
+ true, "<= 4 columns, table width is 95% of document width");
+ }
}
- uint32_t count = 0;
- if (doSelectRow) {
- count = ColCount();
- } else {
- count = RowCount();
+ // Two column rules.
+ if (rowCount * colCount <= 10) {
+ RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered");
}
- PresShell* presShell = mDoc->PresShellPtr();
- RefPtr tableSelection =
- const_cast(presShell->ConstFrameSelection());
-
- for (uint32_t idx = 0; idx < count; idx++) {
- int32_t rowIdx = doSelectRow ? aIndex : idx;
- int32_t colIdx = doSelectRow ? idx : aIndex;
- nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(rowIdx, colIdx);
- if (cellFrame && !cellFrame->IsSelected()) {
- nsresult rv = tableSelection->SelectCellElement(cellFrame->GetContent());
- NS_ENSURE_SUCCESS(rv, rv);
+ static const nsLiteralString tags[] = {u"embed"_ns, u"object"_ns,
+ u"iframe"_ns};
+ for (const auto& tag : tags) {
+ nsCOMPtr descendants = el->GetElementsByTagName(tag);
+ if (descendants->Length() > 0) {
+ RETURN_LAYOUT_ANSWER(true,
+ "Has no borders, and has iframe, object or embed, "
+ "typical of advertisements");
}
}
- return NS_OK;
+ RETURN_LAYOUT_ANSWER(false,
+ "No layout factor strong enough, so will guess data");
}
-nsresult HTMLTableAccessible::RemoveRowsOrColumnsFromSelection(
- int32_t aIndex, TableSelectionMode aTarget, bool aIsOuter) {
- nsTableWrapperFrame* tableFrame = GetTableWrapperFrame();
- if (!tableFrame) {
- return NS_OK;
- }
-
- PresShell* presShell = mDoc->PresShellPtr();
- RefPtr tableSelection =
- const_cast(presShell->ConstFrameSelection());
-
- bool doUnselectRow = (aTarget == TableSelectionMode::Row);
- uint32_t count = doUnselectRow ? ColCount() : RowCount();
-
- int32_t startRowIdx = doUnselectRow ? aIndex : 0;
- int32_t endRowIdx = doUnselectRow ? aIndex : count - 1;
- int32_t startColIdx = doUnselectRow ? 0 : aIndex;
- int32_t endColIdx = doUnselectRow ? count - 1 : aIndex;
-
- if (aIsOuter) {
- return tableSelection->RestrictCellsToSelection(
- mContent, startRowIdx, startColIdx, endRowIdx, endColIdx);
- }
-
- return tableSelection->RemoveCellsFromSelection(
- mContent, startRowIdx, startColIdx, endRowIdx, endColIdx);
-}
+////////////////////////////////////////////////////////////////////////////////
+// HTMLTableAccessible: protected implementation
void HTMLTableAccessible::Description(nsString& aDescription) const {
// Helpful for debugging layout vs. data tables
diff -Nru firefox-esr-115.3.1esr+build1/accessible/html/HTMLTableAccessible.h firefox-esr-115.4.0esr+build1/accessible/html/HTMLTableAccessible.h
--- firefox-esr-115.3.1esr+build1/accessible/html/HTMLTableAccessible.h 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/html/HTMLTableAccessible.h 2023-10-17 05:45:44.000000000 +0000
@@ -7,8 +7,6 @@
#define mozilla_a11y_HTMLTableAccessible_h__
#include "HyperTextAccessibleWrap.h"
-#include "TableAccessible.h"
-#include "TableCellAccessible.h"
class nsITableCellLayout;
class nsTableCellFrame;
@@ -16,15 +14,14 @@
namespace mozilla {
-enum class TableSelectionMode : uint32_t;
-
namespace a11y {
+class HTMLTableAccessible;
+
/**
* HTML table cell accessible (html:td).
*/
-class HTMLTableCellAccessible : public HyperTextAccessibleWrap,
- public TableCellAccessible {
+class HTMLTableCellAccessible : public HyperTextAccessibleWrap {
public:
HTMLTableCellAccessible(nsIContent* aContent, DocAccessible* aDoc);
@@ -33,7 +30,6 @@
HyperTextAccessibleWrap)
// LocalAccessible
- virtual TableCellAccessible* AsTableCell() override { return this; }
virtual a11y::role NativeRole() const override;
virtual uint64_t NativeState() const override;
virtual uint64_t NativeInteractiveState() const override;
@@ -44,16 +40,18 @@
int32_t aModType,
const nsAttrValue* aOldValue,
uint64_t aOldState) override;
- // TableCellAccessible
+ // HTMLTableCellAccessible
public:
- virtual TableAccessible* Table() const override;
- virtual uint32_t ColIdx() const override;
- virtual uint32_t RowIdx() const override;
- virtual uint32_t ColExtent() const override;
- virtual uint32_t RowExtent() const override;
- virtual void ColHeaderCells(nsTArray* aCells) override;
- virtual void RowHeaderCells(nsTArray* aCells) override;
- virtual bool Selected() override;
+ HTMLTableAccessible* Table() const;
+ uint32_t ColExtent() const;
+ uint32_t RowExtent() const;
+
+ static HTMLTableCellAccessible* GetFrom(LocalAccessible* aAcc) {
+ if (aAcc->IsHTMLTableCell()) {
+ return static_cast(aAcc);
+ }
+ return nullptr;
+ }
protected:
virtual ~HTMLTableCellAccessible() {}
@@ -64,11 +62,6 @@
nsITableCellLayout* GetCellLayout() const;
/**
- * Return the table cell frame.
- */
- nsTableCellFrame* GetCellFrame() const;
-
- /**
* Return row and column indices of the cell.
*/
nsresult GetCellIndexes(int32_t& aRowIdx, int32_t& aColIdx) const;
@@ -99,9 +92,6 @@
NS_INLINE_DECL_REFCOUNTING_INHERITED(HTMLTableRowAccessible,
HyperTextAccessibleWrap)
- // LocalAccessible
- virtual a11y::role NativeRole() const override;
-
protected:
virtual ~HTMLTableRowAccessible() {}
@@ -118,8 +108,7 @@
// data vs. layout heuristic
// #define SHOW_LAYOUT_HEURISTIC
-class HTMLTableAccessible : public HyperTextAccessibleWrap,
- public TableAccessible {
+class HTMLTableAccessible : public HyperTextAccessibleWrap {
public:
HTMLTableAccessible(nsIContent* aContent, DocAccessible* aDoc)
: HyperTextAccessibleWrap(aContent, aDoc) {
@@ -130,40 +119,23 @@
NS_INLINE_DECL_REFCOUNTING_INHERITED(HTMLTableAccessible,
HyperTextAccessibleWrap)
- // TableAccessible
- virtual LocalAccessible* Caption() const override;
- virtual void Summary(nsString& aSummary) override;
- virtual uint32_t ColCount() const override;
- virtual uint32_t RowCount() override;
- virtual LocalAccessible* CellAt(uint32_t aRowIndex,
- uint32_t aColumnIndex) override;
- virtual int32_t CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) override;
- virtual int32_t ColIndexAt(uint32_t aCellIdx) override;
- virtual int32_t RowIndexAt(uint32_t aCellIdx) override;
- virtual void RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx,
- int32_t* aColIdx) override;
- virtual uint32_t ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx) override;
- virtual uint32_t RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx) 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 LocalAccessible* AsAccessible() override { return this; }
+ // HTMLTableAccessible
+ LocalAccessible* Caption() const;
+ uint32_t ColCount() const;
+ uint32_t RowCount();
+ uint32_t ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx);
+ uint32_t RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx);
+ bool IsProbablyLayoutTable();
+
+ static HTMLTableAccessible* GetFrom(LocalAccessible* aAcc) {
+ if (aAcc->IsHTMLTable()) {
+ return static_cast(aAcc);
+ }
+ return nullptr;
+ }
// LocalAccessible
- virtual TableAccessible* AsTable() override { return this; }
virtual void Description(nsString& aDescription) const override;
- virtual a11y::role NativeRole() const override;
virtual uint64_t NativeState() const override;
virtual already_AddRefed NativeAttributes() override;
virtual Relation RelationByType(RelationType aRelationType) const override;
@@ -183,29 +155,6 @@
// HTMLTableAccessible
- /**
- * Add row or column to selection.
- *
- * @param aIndex [in] index of row or column to be selected
- * @param aTarget [in] indicates what should be selected, either row or
- * column (see nsFrameSelection)
- */
- nsresult AddRowOrColumnToSelection(int32_t aIndex,
- TableSelectionMode aTarget);
-
- /**
- * Removes rows or columns at the given index or outside it from selection.
- *
- * @param aIndex [in] row or column index
- * @param aTarget [in] indicates whether row or column should unselected
- * @param aIsOuter [in] indicates whether all rows or column excepting
- * the given one should be unselected or the given one
- * should be unselected only
- */
- nsresult RemoveRowsOrColumnsFromSelection(int32_t aIndex,
- TableSelectionMode aTarget,
- bool aIsOuter);
-
#ifdef SHOW_LAYOUT_HEURISTIC
nsString mLayoutHeuristic;
#endif
diff -Nru firefox-esr-115.3.1esr+build1/accessible/interfaces/nsIAccessibleTable.idl firefox-esr-115.4.0esr+build1/accessible/interfaces/nsIAccessibleTable.idl
--- firefox-esr-115.3.1esr+build1/accessible/interfaces/nsIAccessibleTable.idl 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/interfaces/nsIAccessibleTable.idl 2023-10-17 05:45:43.000000000 +0000
@@ -181,34 +181,6 @@
Array getSelectedRowIndices();
/**
- * Select a row and unselects all previously selected rows.
- *
- * @param rowIndex [in] the row index to select
- */
- void selectRow(in long rowIndex);
-
- /**
- * Select a column and unselects all previously selected columns.
- *
- * @param columnIndex [in] the column index to select
- */
- void selectColumn(in long columnIndex);
-
- /**
- * Unselect the given row, leaving other selected rows selected (if any).
- *
- * @param rowIndex [in] the row index to select
- */
- void unselectRow(in long rowIndex);
-
- /**
- * Unselect the given column, leaving other selected columns selected (if any).
- *
- * @param columnIndex [in] the column index to select
- */
- void unselectColumn(in long columnIndex);
-
- /**
* Use heuristics to determine if table is most likely used for layout.
*/
boolean isProbablyForLayout();
diff -Nru firefox-esr-115.3.1esr+build1/accessible/ipc/RemoteAccessibleBase.cpp firefox-esr-115.4.0esr+build1/accessible/ipc/RemoteAccessibleBase.cpp
--- firefox-esr-115.3.1esr+build1/accessible/ipc/RemoteAccessibleBase.cpp 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/ipc/RemoteAccessibleBase.cpp 2023-10-17 05:45:44.000000000 +0000
@@ -7,12 +7,15 @@
#include "ARIAMap.h"
#include "CachedTableAccessible.h"
#include "DocAccessible.h"
+#include "RemoteAccessibleBase.h"
#include "mozilla/a11y/DocAccessibleParent.h"
#include "mozilla/a11y/DocManager.h"
#include "mozilla/a11y/Platform.h"
#include "mozilla/a11y/RemoteAccessibleBase.h"
#include "mozilla/a11y/RemoteAccessible.h"
#include "mozilla/a11y/Role.h"
+#include "mozilla/a11y/TableAccessible.h"
+#include "mozilla/a11y/TableCellAccessible.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/BrowserParent.h"
@@ -412,6 +415,60 @@
}
template
+RemoteAccessible* RemoteAccessibleBase::DoFuzzyHittesting() {
+ uint32_t childCount = ChildCount();
+ if (!childCount) {
+ return nullptr;
+ }
+ // Check if this match has a clipped child.
+ // This usually indicates invisible text, and we're
+ // interested in returning the inner text content
+ // even if it doesn't contain the point we're hittesting.
+ RemoteAccessible* clippedContainer = nullptr;
+ for (uint32_t i = 0; i < childCount; i++) {
+ RemoteAccessible* child = RemoteChildAt(i);
+ if (child->Role() == roles::TEXT_CONTAINER) {
+ if (child->IsClipped()) {
+ clippedContainer = child;
+ break;
+ }
+ }
+ }
+ // If we found a clipped container, descend it in search of
+ // meaningful text leaves. Ignore non-text-leaf/text-container
+ // siblings.
+ RemoteAccessible* container = clippedContainer;
+ while (container) {
+ RemoteAccessible* textLeaf = nullptr;
+ bool continueSearch = false;
+ childCount = container->ChildCount();
+ for (uint32_t i = 0; i < childCount; i++) {
+ RemoteAccessible* child = container->RemoteChildAt(i);
+ if (child->Role() == roles::TEXT_CONTAINER) {
+ container = child;
+ continueSearch = true;
+ break;
+ }
+ if (child->IsTextLeaf()) {
+ textLeaf = child;
+ // Don't break here -- it's possible a text container
+ // exists as another sibling, and we should descend as
+ // deep as possible.
+ }
+ }
+ if (textLeaf) {
+ return textLeaf;
+ }
+ if (!continueSearch) {
+ // We didn't find anything useful in this set of siblings.
+ // Don't keep searching
+ break;
+ }
+ }
+ return nullptr;
+}
+
+template
Accessible* RemoteAccessibleBase::ChildAtPoint(
int32_t aX, int32_t aY, LocalAccessible::EWhichChildAtPoint aWhichChild) {
// Elements that are partially on-screen should have their bounds masked by
@@ -484,6 +541,13 @@
// this call shouldn't pass the boundary defined by
// the acc this call originated on. If we hit `this`,
// return our most recent match.
+ if (!lastMatch &&
+ BoundsWithOffset(Nothing(), hitTesting).Contains(aX, aY)) {
+ // If we haven't found a match, but `this` contains the point we're
+ // looking for, set it as our temp last match so we can
+ // (potentially) do fuzzy hittesting on it below.
+ lastMatch = acc;
+ }
break;
}
@@ -495,6 +559,10 @@
break;
}
}
+ if (lastMatch) {
+ RemoteAccessible* fuzzyMatch = lastMatch->DoFuzzyHittesting();
+ lastMatch = fuzzyMatch ? fuzzyMatch : lastMatch;
+ }
}
}
@@ -653,6 +721,27 @@
}
template
+bool RemoteAccessibleBase::IsOverflowHidden() const {
+ MOZ_ASSERT(mCachedFields);
+ if (auto maybeOverflow =
+ mCachedFields->GetAttribute>(nsGkAtoms::overflow)) {
+ return *maybeOverflow == nsGkAtoms::hidden;
+ }
+
+ return false;
+}
+
+template
+bool RemoteAccessibleBase::IsClipped() const {
+ MOZ_ASSERT(mCachedFields);
+ if (mCachedFields->GetAttribute(nsGkAtoms::clip_rule)) {
+ return true;
+ }
+
+ return false;
+}
+
+template
LayoutDeviceIntRect RemoteAccessibleBase::BoundsWithOffset(
Maybe aOffset, bool aBoundsAreForHittesting) const {
Maybe maybeBounds = RetrieveCachedBounds();
@@ -728,11 +817,12 @@
// that the bounds we've calculated so far are constrained to the
// bounds of the scroll area. Without this, we'll "hit" the off-screen
// portions of accs that are are partially (but not fully) within the
- // scroll area.
- if (aBoundsAreForHittesting && hasScrollArea) {
- nsRect selfRelativeScrollBounds(0, 0, remoteBounds.width,
- remoteBounds.height);
- bounds = bounds.SafeIntersect(selfRelativeScrollBounds);
+ // scroll area. This is also a problem for accs with overflow:hidden;
+ if (aBoundsAreForHittesting &&
+ (hasScrollArea || remoteAcc->IsOverflowHidden())) {
+ nsRect selfRelativeVisibleBounds(0, 0, remoteBounds.width,
+ remoteBounds.height);
+ bounds = bounds.SafeIntersect(selfRelativeVisibleBounds);
}
}
if (remoteAcc->IsDoc()) {
@@ -1386,8 +1476,8 @@
attributes->SetAttribute(nsGkAtoms::display, display);
}
- if (TableCellAccessibleBase* cell = AsTableCellBase()) {
- TableAccessibleBase* table = cell->Table();
+ if (TableCellAccessible* cell = AsTableCell()) {
+ TableAccessible* table = cell->Table();
uint32_t row = cell->RowIdx();
uint32_t col = cell->ColIdx();
int32_t cellIdx = table->CellIndexAt(row, col);
@@ -1899,7 +1989,7 @@
}
template
-TableAccessibleBase* RemoteAccessibleBase::AsTableBase() {
+TableAccessible* RemoteAccessibleBase::AsTable() {
if (IsTable()) {
return CachedTableAccessible::GetFrom(this);
}
@@ -1907,7 +1997,7 @@
}
template
-TableCellAccessibleBase* RemoteAccessibleBase::AsTableCellBase() {
+TableCellAccessible* RemoteAccessibleBase::AsTableCell() {
if (IsTableCell()) {
return CachedTableCellAccessible::GetFrom(this);
}
diff -Nru firefox-esr-115.3.1esr+build1/accessible/ipc/RemoteAccessibleBase.h firefox-esr-115.4.0esr+build1/accessible/ipc/RemoteAccessibleBase.h
--- firefox-esr-115.3.1esr+build1/accessible/ipc/RemoteAccessibleBase.h 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/ipc/RemoteAccessibleBase.h 2023-10-17 05:45:43.000000000 +0000
@@ -393,8 +393,8 @@
: nullptr;
}
- virtual TableAccessibleBase* AsTableBase() override;
- virtual TableCellAccessibleBase* AsTableCellBase() override;
+ virtual TableAccessible* AsTable() override;
+ virtual TableCellAccessible* AsTableCell() override;
virtual void DOMNodeID(nsString& aID) const override;
@@ -452,6 +452,24 @@
LayoutDeviceIntRect BoundsWithOffset(
Maybe aOffset, bool aBoundsAreForHittesting = false) const;
bool IsFixedPos() const;
+ bool IsOverflowHidden() const;
+
+ /**
+ * Returns true if an accessible's frame has no scrollable overflow, and
+ * false otherwise.
+ * Does not return true for partially clipped accessibles.
+ */
+ bool IsClipped() const;
+
+ /**
+ * Checks if our hittesting match has any clipped children and, if so
+ * descends it and subsequent TEXT_CONTAINERs in search of a text leaf.
+ * We do this because some sites use clipping to hide text that is only
+ * visible to a11y, while displaying a visual version of the same text on
+ * the web page. We want a hittest of the visible text to resolve to the
+ * hidden, a11y-only text node.
+ */
+ RemoteAccessible* DoFuzzyHittesting();
// This function is used exclusively for hit testing.
bool ContainsPoint(int32_t aX, int32_t aY);
diff -Nru firefox-esr-115.3.1esr+build1/accessible/mac/mozAccessible.mm firefox-esr-115.4.0esr+build1/accessible/mac/mozAccessible.mm
--- firefox-esr-115.3.1esr+build1/accessible/mac/mozAccessible.mm 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/mac/mozAccessible.mm 2023-10-17 05:45:44.000000000 +0000
@@ -22,7 +22,6 @@
#include "Relation.h"
#include "Role.h"
#include "RootAccessible.h"
-#include "TableAccessible.h"
#include "mozilla/a11y/PDocAccessible.h"
#include "mozilla/dom/BrowserParent.h"
#include "OuterDocAccessible.h"
diff -Nru firefox-esr-115.3.1esr+build1/accessible/mac/mozTableAccessible.mm firefox-esr-115.4.0esr+build1/accessible/mac/mozTableAccessible.mm
--- firefox-esr-115.3.1esr+build1/accessible/mac/mozTableAccessible.mm 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/mac/mozTableAccessible.mm 2023-10-17 05:45:44.000000000 +0000
@@ -11,8 +11,8 @@
#include "AccIterator.h"
#include "LocalAccessible.h"
-#include "mozilla/a11y/TableAccessibleBase.h"
-#include "mozilla/a11y/TableCellAccessibleBase.h"
+#include "mozilla/a11y/TableAccessible.h"
+#include "mozilla/a11y/TableCellAccessible.h"
#include "nsAccessibilityService.h"
#include "XULTreeAccessible.h"
#include "Pivot.h"
@@ -48,7 +48,7 @@
mChildren = [[NSMutableArray alloc] init];
- TableAccessibleBase* table = [mParent geckoAccessible]->AsTableBase();
+ TableAccessible* table = [mParent geckoAccessible]->AsTable();
MOZ_ASSERT(table, "Got null table when fetching column children!");
uint32_t numRows = table->RowCount();
@@ -137,7 +137,7 @@
}
// For LocalAccessible and cached RemoteAccessible, we could use
- // AsTableBase()->IsProbablyLayoutTable(). However, if the cache is enabled,
+ // AsTable()->IsProbablyLayoutTable(). However, if the cache is enabled,
// that would build the table cache, which is pointless for layout tables on
// Mac because layout tables are AXGroups and do not expose table properties
// like AXRows, AXColumns, etc.
@@ -174,13 +174,13 @@
- (NSNumber*)moxRowCount {
MOZ_ASSERT(mGeckoAccessible);
- return @(mGeckoAccessible->AsTableBase()->RowCount());
+ return @(mGeckoAccessible->AsTable()->RowCount());
}
- (NSNumber*)moxColumnCount {
MOZ_ASSERT(mGeckoAccessible);
- return @(mGeckoAccessible->AsTableBase()->ColCount());
+ return @(mGeckoAccessible->AsTable()->ColCount());
}
- (NSArray*)moxRows {
@@ -221,7 +221,7 @@
mColContainers = [[NSMutableArray alloc] init];
uint32_t numCols = 0;
- numCols = mGeckoAccessible->AsTableBase()->ColCount();
+ numCols = mGeckoAccessible->AsTable()->ColCount();
for (uint32_t i = 0; i < numCols; i++) {
mozColumnContainer* container =
[[mozColumnContainer alloc] initWithIndex:i andParent:self];
@@ -244,9 +244,9 @@
MOZ_ASSERT(mGeckoAccessible);
uint32_t numCols = 0;
- TableAccessibleBase* table = nullptr;
+ TableAccessible* table = nullptr;
- table = mGeckoAccessible->AsTableBase();
+ table = mGeckoAccessible->AsTable();
numCols = table->ColCount();
NSMutableArray* colHeaders =
[[[NSMutableArray alloc] initWithCapacity:numCols] autorelease];
@@ -272,7 +272,7 @@
MOZ_ASSERT(mGeckoAccessible);
- Accessible* cell = mGeckoAccessible->AsTableBase()->CellAt(row, col);
+ Accessible* cell = mGeckoAccessible->AsTable()->CellAt(row, col);
if (!cell) {
return nil;
}
@@ -338,7 +338,7 @@
- (NSValue*)moxRowIndexRange {
MOZ_ASSERT(mGeckoAccessible);
- TableCellAccessibleBase* cell = mGeckoAccessible->AsTableCellBase();
+ TableCellAccessible* cell = mGeckoAccessible->AsTableCell();
return
[NSValue valueWithRange:NSMakeRange(cell->RowIdx(), cell->RowExtent())];
}
@@ -346,7 +346,7 @@
- (NSValue*)moxColumnIndexRange {
MOZ_ASSERT(mGeckoAccessible);
- TableCellAccessibleBase* cell = mGeckoAccessible->AsTableCellBase();
+ TableCellAccessible* cell = mGeckoAccessible->AsTableCell();
return
[NSValue valueWithRange:NSMakeRange(cell->ColIdx(), cell->ColExtent())];
}
@@ -354,7 +354,7 @@
- (NSArray*)moxRowHeaderUIElements {
MOZ_ASSERT(mGeckoAccessible);
- TableCellAccessibleBase* cell = mGeckoAccessible->AsTableCellBase();
+ TableCellAccessible* cell = mGeckoAccessible->AsTableCell();
AutoTArray headerCells;
if (cell) {
cell->RowHeaderCells(&headerCells);
@@ -365,7 +365,7 @@
- (NSArray*)moxColumnHeaderUIElements {
MOZ_ASSERT(mGeckoAccessible);
- TableCellAccessibleBase* cell = mGeckoAccessible->AsTableCellBase();
+ TableCellAccessible* cell = mGeckoAccessible->AsTableCell();
AutoTArray headerCells;
if (cell) {
cell->ColHeaderCells(&headerCells);
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/browser/e10s/browser_caching_table.js firefox-esr-115.4.0esr+build1/accessible/tests/browser/e10s/browser_caching_table.js
--- firefox-esr-115.3.1esr+build1/accessible/tests/browser/e10s/browser_caching_table.js 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/browser/e10s/browser_caching_table.js 2023-10-17 05:45:43.000000000 +0000
@@ -427,15 +427,11 @@
`,
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,
@@ -496,3 +492,15 @@
},
{ topLevel: true }
);
+
+/**
+ * Verify that we don't crash for authoring error like .
+ */
+addAccessibleTask(
+ ``,
+ async function (browser, docAcc) {
+ const table = findAccessibleChildByID(docAcc, "table");
+ ok(table, "Retrieved table Accessible");
+ },
+ { chrome: true, topLevel: true }
+);
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/browser/events/browser_test_panel.js firefox-esr-115.4.0esr+build1/accessible/tests/browser/events/browser_test_panel.js
--- firefox-esr-115.3.1esr+build1/accessible/tests/browser/events/browser_test_panel.js 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/browser/events/browser_test_panel.js 2023-10-17 05:45:44.000000000 +0000
@@ -31,9 +31,13 @@
ok(isAccessible(PopupNotifications.panel), "Popup panel is accessible");
testAccessibleTree(PopupNotifications.panel, {
ALERT: [
- { LABEL: [{ TEXT_LEAF: [] }] },
- { PUSHBUTTON: [] },
- { PUSHBUTTON: [] },
+ {
+ TEXT_CONTAINER: [
+ { LABEL: [{ TEXT_LEAF: [] }] },
+ { PUSHBUTTON: [] },
+ { PUSHBUTTON: [] },
+ ],
+ },
],
});
// Verify the popup panel is associated with the chrome window.
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/browser/hittest/browser_test_general.js firefox-esr-115.4.0esr+build1/accessible/tests/browser/hittest/browser_test_general.js
--- firefox-esr-115.3.1esr+build1/accessible/tests/browser/hittest/browser_test_general.js 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/browser/hittest/browser_test_general.js 2023-10-17 05:45:43.000000000 +0000
@@ -232,3 +232,108 @@
iframeAttrs: { style: "width: 600px; height: 600px; padding: 10px;" },
}
);
+
+/**
+ * Verify that hit testing returns the proper accessible when one acc content
+ * is partially hidden due to overflow:hidden;
+ */
+addAccessibleTask(
+ `
+
+ `,
+ async function (browser, docAcc) {
+ const container = findAccessibleChildByID(docAcc, "container");
+ const aNode = findAccessibleChildByID(docAcc, "aNode");
+ const fNode = findAccessibleChildByID(docAcc, "fNode");
+ const dpr = await getContentDPR(browser);
+ const [, , containerWidth] = Layout.getBounds(container, dpr);
+ const [, , aNodeWidth] = Layout.getBounds(aNode, dpr);
+
+ await testChildAtPoint(
+ dpr,
+ containerWidth - 1,
+ 1,
+ container,
+ aNode,
+ aNode.firstChild
+ );
+ await testChildAtPoint(
+ dpr,
+ containerWidth - aNodeWidth - 1,
+ 1,
+ container,
+ fNode,
+ fNode.firstChild
+ );
+ },
+ { chrome: true, iframe: true, remoteIframe: true }
+);
+
+/**
+ * Verify that hit testing is appropriately fuzzy when working with generics.
+ * If we match on a generic which contains additional generics and a single text
+ * leaf, we should return the text leaf as the deepest match instead of the
+ * generic itself.
+ */
+addAccessibleTask(
+ `
+
+ I am some visible textI am some invisible text
+ `,
+ async function (browser, docAcc) {
+ const link = findAccessibleChildByID(docAcc, "link");
+ const generic = findAccessibleChildByID(docAcc, "generic");
+ const invisible = findAccessibleChildByID(docAcc, "invisible");
+ const dpr = await getContentDPR(browser);
+
+ await testChildAtPoint(
+ dpr,
+ 1,
+ 1,
+ link,
+ generic, // Direct Child
+ invisible.firstChild // Deepest Child
+ );
+
+ await testOffsetAtPoint(
+ findAccessibleChildByID(docAcc, "invisible", [Ci.nsIAccessibleText]),
+ 1,
+ 1,
+ COORDTYPE_PARENT_RELATIVE,
+ 0
+ );
+ },
+ { chrome: false, iframe: true, remoteIframe: true }
+);
+
+/**
+ * Verify that hit testing is appropriately fuzzy when working with generics with siblings.
+ * We should return the deepest text leaf as the deepest match instead of the generic itself.
+ */
+addAccessibleTask(
+ `
+Mozillahello world
I am some other text
`,
+ async function (browser, docAcc) {
+ const generic = findAccessibleChildByID(docAcc, "generic");
+ const invisible = findAccessibleChildByID(docAcc, "invisible");
+ const dpr = await getContentDPR(browser);
+
+ await testChildAtPoint(
+ dpr,
+ 1,
+ 1,
+ generic,
+ invisible, // Direct Child
+ invisible.firstChild // Deepest Child
+ );
+ },
+ { chrome: false, iframe: true, remoteIframe: true }
+);
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/browser/hittest/head.js firefox-esr-115.4.0esr+build1/accessible/tests/browser/hittest/head.js
--- firefox-esr-115.3.1esr+build1/accessible/tests/browser/hittest/head.js 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/browser/hittest/head.js 2023-10-17 05:45:43.000000000 +0000
@@ -47,6 +47,7 @@
await untilCacheIs(
() => {
actual = getChildAtPoint(container, x, y, false);
+ info(`Got direct child match of ${CommonUtils.prettyName(actual)}`);
return actual;
},
child,
@@ -60,6 +61,7 @@
await untilCacheIs(
() => {
actual = getChildAtPoint(container, x, y, true);
+ info(`Got deepest child match of ${CommonUtils.prettyName(actual)}`);
return actual;
},
grandChild,
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/browser/mac/browser_table.js firefox-esr-115.4.0esr+build1/accessible/tests/browser/mac/browser_table.js
--- firefox-esr-115.3.1esr+build1/accessible/tests/browser/mac/browser_table.js 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/browser/mac/browser_table.js 2023-10-17 05:45:43.000000000 +0000
@@ -363,12 +363,12 @@
// after abbr is set we should have a data table again
await testIsLayout(
table,
- "cellOne",
+ "cellThree",
EVENT_OBJECT_ATTRIBUTE_CHANGED,
async () => {
await SpecialPowers.spawn(browser, [], () => {
content.document
- .getElementById("cellOne")
+ .getElementById("cellThree")
.setAttribute("abbr", "hello world");
});
},
@@ -379,11 +379,11 @@
// after abbr is removed we should have a layout table again
await testIsLayout(
table,
- "cellOne",
+ "cellThree",
EVENT_OBJECT_ATTRIBUTE_CHANGED,
async () => {
await SpecialPowers.spawn(browser, [], () => {
- content.document.getElementById("cellOne").removeAttribute("abbr");
+ content.document.getElementById("cellThree").removeAttribute("abbr");
});
},
true
@@ -393,12 +393,12 @@
// after scope is set we should have a data table again
await testIsLayout(
table,
- "cellOne",
+ "cellThree",
EVENT_OBJECT_ATTRIBUTE_CHANGED,
async () => {
await SpecialPowers.spawn(browser, [], () => {
content.document
- .getElementById("cellOne")
+ .getElementById("cellThree")
.setAttribute("scope", "col");
});
},
@@ -409,11 +409,11 @@
// remove scope should give layout
await testIsLayout(
table,
- "cellOne",
+ "cellThree",
EVENT_OBJECT_ATTRIBUTE_CHANGED,
async () => {
await SpecialPowers.spawn(browser, [], () => {
- content.document.getElementById("cellOne").removeAttribute("scope");
+ content.document.getElementById("cellThree").removeAttribute("scope");
});
},
true
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/browser/tree/browser_general.js firefox-esr-115.4.0esr+build1/accessible/tests/browser/tree/browser_general.js
--- firefox-esr-115.3.1esr+build1/accessible/tests/browser/tree/browser_general.js 1970-01-01 00:00:00.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/browser/tree/browser_general.js 2023-10-17 05:45:43.000000000 +0000
@@ -0,0 +1,128 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* import-globals-from ../../mochitest/role.js */
+loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
+
+/**
+ * Verify adding `overflow:hidden;` styling to a div causes it to
+ * get an accessible.
+ */
+addAccessibleTask(`hello world
`, async function (browser, docAcc) {
+ const originalTree = { DOCUMENT: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }] };
+
+ testAccessibleTree(docAcc, originalTree);
+ info("Adding div element");
+ await contentSpawnMutation(
+ browser,
+ { unexpected: [[EVENT_REORDER, docAcc]] },
+ function () {
+ const d = content.document.createElement("div");
+ content.document.body.appendChild(d);
+ }
+ );
+
+ testAccessibleTree(docAcc, originalTree);
+ info("Adding overflow:hidden styling to div");
+ await contentSpawnMutation(
+ browser,
+ { expected: [[EVENT_REORDER, docAcc]] },
+ function () {
+ content.document.body.lastElementChild.setAttribute(
+ "style",
+ "overflow:hidden;"
+ );
+ }
+ );
+
+ testAccessibleTree(docAcc, {
+ DOCUMENT: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }, { TEXT_CONTAINER: [] }],
+ });
+});
+
+/**
+ * Verify adding `overflow:scroll;` styling to a div causes
+ * it to get an accessible.
+ */
+addAccessibleTask(`hello world
`, async function (browser, docAcc) {
+ const originalTree = { DOCUMENT: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }] };
+
+ testAccessibleTree(docAcc, originalTree);
+ info("Adding div element");
+ await contentSpawnMutation(
+ browser,
+ { unexpected: [[EVENT_REORDER, docAcc]] },
+ function () {
+ const d = content.document.createElement("div");
+ content.document.body.appendChild(d);
+ }
+ );
+
+ testAccessibleTree(docAcc, originalTree);
+ info("Adding overflow:scroll styling to div");
+ await contentSpawnMutation(
+ browser,
+ { expected: [[EVENT_REORDER, docAcc]] },
+ function () {
+ content.document.body.lastElementChild.setAttribute(
+ "style",
+ "overflow:scroll;"
+ );
+ }
+ );
+
+ testAccessibleTree(docAcc, {
+ DOCUMENT: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }, { TEXT_CONTAINER: [] }],
+ });
+});
+
+/**
+ * Verify adding `overflow:auto;` styling to a div causes
+ * it to get an accessible, but `overflow:visible` does not.
+ */
+addAccessibleTask(`hello world
`, async function (browser, docAcc) {
+ const originalTree = { DOCUMENT: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }] };
+
+ testAccessibleTree(docAcc, originalTree);
+ info("Adding div element");
+ await contentSpawnMutation(
+ browser,
+ { unexpected: [[EVENT_REORDER, docAcc]] },
+ function () {
+ const d = content.document.createElement("div");
+ content.document.body.appendChild(d);
+ }
+ );
+
+ testAccessibleTree(docAcc, originalTree);
+ info("Adding overflow:visible styling to div");
+ await contentSpawnMutation(
+ browser,
+ { unexpected: [[EVENT_REORDER, docAcc]] },
+ function () {
+ content.document.body.lastElementChild.setAttribute(
+ "style",
+ "overflow:visible;"
+ );
+ }
+ );
+
+ testAccessibleTree(docAcc, originalTree);
+ info("Adding overflow:auto styling to div");
+ await contentSpawnMutation(
+ browser,
+ { expected: [[EVENT_REORDER, docAcc]] },
+ function () {
+ content.document.body.lastElementChild.setAttribute(
+ "style",
+ "overflow:auto;"
+ );
+ }
+ );
+
+ testAccessibleTree(docAcc, {
+ DOCUMENT: [{ PARAGRAPH: [{ TEXT_LEAF: [] }] }, { TEXT_CONTAINER: [] }],
+ });
+});
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/browser/tree/browser.ini firefox-esr-115.4.0esr+build1/accessible/tests/browser/tree/browser.ini
--- firefox-esr-115.3.1esr+build1/accessible/tests/browser/tree/browser.ini 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/browser/tree/browser.ini 2023-10-17 05:45:43.000000000 +0000
@@ -12,6 +12,7 @@
skip-if = true || (verify && !debug && (os == 'linux')) #Bug 1445513
[browser_browser_element.js]
[browser_css_content_visibility.js]
+[browser_general.js]
[browser_lazy_tabs.js]
[browser_searchbar.js]
[browser_shadowdom.js]
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/elm/test_shadowroot_subframe.html firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/elm/test_shadowroot_subframe.html
--- firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/elm/test_shadowroot_subframe.html 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/elm/test_shadowroot_subframe.html 2023-10-17 05:45:43.000000000 +0000
@@ -61,8 +61,8 @@
var table = document.getElementById("table");
shadow = table.attachShadow({mode: "open"});
- shadow.innerHTML = "" +
- "
hi
" +
+ shadow.innerHTML = "
";
-
+
cell1 |
cell2 |
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/table/test_sels_ariagrid.html firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/table/test_sels_ariagrid.html
--- firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/table/test_sels_ariagrid.html 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/table/test_sels_ariagrid.html 2023-10-17 05:45:43.000000000 +0000
@@ -33,10 +33,6 @@
];
testTableSelection("table", cellsArray);
- testUnselectTableColumn("table", 3, cellsArray);
- testUnselectTableRow("table", 3, cellsArray);
- testSelectTableColumn("table", 0, cellsArray);
- testSelectTableRow("table", 0, cellsArray);
// ////////////////////////////////////////////////////////////////////////
// a bit strange ARIA grid
@@ -47,10 +43,6 @@
];
testTableSelection("grid2", cellsArray);
- testSelectTableColumn("grid2", 0, cellsArray);
- testSelectTableRow("grid2", 0, cellsArray);
- testUnselectTableColumn("grid2", 0, cellsArray);
- testUnselectTableRow("grid2", 0, cellsArray);
// ////////////////////////////////////////////////////////////////////////
// ARIA grid (column and row headers)
@@ -62,10 +54,6 @@
];
testTableSelection("grid3", cellsArray);
- testSelectTableColumn("grid3", 0, cellsArray);
- testSelectTableRow("grid3", 0, cellsArray);
- testUnselectTableColumn("grid3", 0, cellsArray);
- testUnselectTableRow("grid3", 0, cellsArray);
SimpleTest.finish();
}
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/table/test_sels_table.html firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/table/test_sels_table.html
--- firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/table/test_sels_table.html 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/table/test_sels_table.html 2023-10-17 05:45:43.000000000 +0000
@@ -33,24 +33,6 @@
testTableSelection("table", cellsArray);
- var rowCount = 4;
- for (let rowIdx = 0; rowIdx < rowCount; rowIdx++)
- testSelectTableRow("table", rowIdx, cellsArray);
-
- for (let rowIdx = 0; rowIdx < rowCount; rowIdx++) {
- testSelectTableRow("table", rowIdx, cellsArray);
- testUnselectTableRow("table", rowIdx, cellsArray);
- }
-
- var columsCount = 8;
- for (let colIdx = 0; colIdx < columsCount; colIdx++)
- testSelectTableColumn("table", colIdx, cellsArray);
-
- for (let colIdx = 0; colIdx < columsCount; colIdx++) {
- testSelectTableColumn("table", colIdx, cellsArray);
- testUnselectTableColumn("table", colIdx, cellsArray);
- }
-
var accTable = getAccessible("table", [nsIAccessibleTable]);
ok(!accTable.isProbablyForLayout(), "table is not for layout");
@@ -88,11 +70,6 @@
Mozilla Bug 501635
- Mozilla Bug 417929
-
-
Mozilla Bug 501659
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/table/test_sels_tree.xhtml firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/table/test_sels_tree.xhtml
--- firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/table/test_sels_tree.xhtml 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/table/test_sels_tree.xhtml 2023-10-17 05:45:43.000000000 +0000
@@ -39,8 +39,6 @@
];
testTableSelection("tree", cellsArray);
- testSelectTableRow("tree", 0, cellsArray);
- testUnselectTableRow("tree", 0, cellsArray);
SimpleTest.finish();
}
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/table.js firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/table.js
--- firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/table.js 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/table.js 2023-10-17 05:45:43.000000000 +0000
@@ -745,189 +745,6 @@
}
/**
- * Test unselectColumn method of accessible table.
- */
-function testUnselectTableColumn(aIdentifier, aColIdx, aCellsArray) {
- var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
- if (!acc) {
- return;
- }
-
- var rowCount = aCellsArray.length;
- for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
- // Unselect origin cell.
- var [origRowIdx, origColIdx] = getOrigRowAndColumn(
- aCellsArray,
- rowIdx,
- aColIdx
- );
- aCellsArray[origRowIdx][origColIdx] = false;
- }
-
- acc.unselectColumn(aColIdx);
- testTableSelection(
- aIdentifier,
- aCellsArray,
- "Unselect " + aColIdx + " column: "
- );
-}
-
-/**
- * Test selectColumn method of accessible table.
- */
-function testSelectTableColumn(aIdentifier, aColIdx, aCellsArray) {
- var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
- if (!acc) {
- return;
- }
-
- var rowCount = aCellsArray.length;
- var colsCount = aCellsArray[0].length;
-
- for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
- for (var colIdx = 0; colIdx < colsCount; colIdx++) {
- var cellState = aCellsArray[rowIdx][colIdx];
-
- if (colIdx == aColIdx) {
- // select target column
- if (!(cellState & kSpanned)) {
- // Select the cell if it is origin.
- aCellsArray[rowIdx][colIdx] = true;
- } else {
- // If the cell is spanned then search origin cell and select it.
- var [origRowIdx, origColIdx] = getOrigRowAndColumn(
- aCellsArray,
- rowIdx,
- colIdx
- );
- aCellsArray[origRowIdx][origColIdx] = true;
- }
- } else if (!(cellState & kSpanned)) {
- // unselect other columns
- if (colIdx > aColIdx) {
- // Unselect the cell if traversed column index is greater than column
- // index of target cell.
- aCellsArray[rowIdx][colIdx] = false;
- } else if (!(aCellsArray[rowIdx][aColIdx] & kColSpanned)) {
- // Unselect the cell if the target cell is not row spanned.
- aCellsArray[rowIdx][colIdx] = false;
- } else {
- // Unselect the cell if it is not spanned to the target cell.
- for (
- var spannedColIdx = colIdx + 1;
- spannedColIdx < aColIdx;
- spannedColIdx++
- ) {
- var spannedCellState = aCellsArray[rowIdx][spannedColIdx];
- if (!(spannedCellState & kRowSpanned)) {
- aCellsArray[rowIdx][colIdx] = false;
- break;
- }
- }
- }
- }
- }
- }
-
- acc.selectColumn(aColIdx);
- testTableSelection(
- aIdentifier,
- aCellsArray,
- "Select " + aColIdx + " column: "
- );
-}
-
-/**
- * Test unselectRow method of accessible table.
- */
-function testUnselectTableRow(aIdentifier, aRowIdx, aCellsArray) {
- var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
- if (!acc) {
- return;
- }
-
- var colsCount = aCellsArray[0].length;
- for (var colIdx = 0; colIdx < colsCount; colIdx++) {
- // Unselect origin cell.
- var [origRowIdx, origColIdx] = getOrigRowAndColumn(
- aCellsArray,
- aRowIdx,
- colIdx
- );
- aCellsArray[origRowIdx][origColIdx] = false;
- }
-
- acc.unselectRow(aRowIdx);
- testTableSelection(
- aIdentifier,
- aCellsArray,
- "Unselect " + aRowIdx + " row: "
- );
-}
-
-/**
- * Test selectRow method of accessible table.
- */
-function testSelectTableRow(aIdentifier, aRowIdx, aCellsArray) {
- var acc = getAccessible(aIdentifier, [nsIAccessibleTable]);
- if (!acc) {
- return;
- }
-
- var rowCount = aCellsArray.length;
- var colsCount = aCellsArray[0].length;
-
- for (var rowIdx = 0; rowIdx < rowCount; rowIdx++) {
- for (var colIdx = 0; colIdx < colsCount; colIdx++) {
- var cellState = aCellsArray[rowIdx][colIdx];
-
- if (rowIdx == aRowIdx) {
- // select the given row
- if (!(cellState & kSpanned)) {
- // Select the cell if it is origin.
- aCellsArray[rowIdx][colIdx] = true;
- } else {
- // If the cell is spanned then search origin cell and select it.
- var [origRowIdx, origColIdx] = getOrigRowAndColumn(
- aCellsArray,
- rowIdx,
- colIdx
- );
-
- aCellsArray[origRowIdx][origColIdx] = true;
- }
- } else if (!(cellState & kSpanned)) {
- // unselect other rows
- if (rowIdx > aRowIdx) {
- // Unselect the cell if traversed row index is greater than row
- // index of target cell.
- aCellsArray[rowIdx][colIdx] = false;
- } else if (!(aCellsArray[aRowIdx][colIdx] & kRowSpanned)) {
- // Unselect the cell if the target cell is not row spanned.
- aCellsArray[rowIdx][colIdx] = false;
- } else {
- // Unselect the cell if it is not spanned to the target cell.
- for (
- var spannedRowIdx = rowIdx + 1;
- spannedRowIdx < aRowIdx;
- spannedRowIdx++
- ) {
- var spannedCellState = aCellsArray[spannedRowIdx][colIdx];
- if (!(spannedCellState & kRowSpanned)) {
- aCellsArray[rowIdx][colIdx] = false;
- break;
- }
- }
- }
- }
- }
- }
-
- acc.selectRow(aRowIdx);
- testTableSelection(aIdentifier, aCellsArray, "Select " + aRowIdx + " row: ");
-}
-
-/**
* Test columnHeaderCells and rowHeaderCells of accessible table.
*/
function testHeaderCells(aHeaderInfoMap) {
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/tree/test_table_2.html firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/tree/test_table_2.html
--- firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/tree/test_table_2.html 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/tree/test_table_2.html 2023-10-17 05:45:44.000000000 +0000
@@ -150,14 +150,16 @@
name: "Top 10 Grossing Animated Films of All Time",
},
] },
- { ROW: [
- { role: COLHEADER, name: "Film Title" },
- { role: COLHEADER, name: "Released" },
- { role: COLHEADER, name: "Studio" },
- { role: COLHEADER, name: "Worldwide Gross" },
- { role: COLHEADER, name: "Domestic Gross" },
- { role: COLHEADER, name: "Foreign Gross" },
- { role: COLHEADER, name: "Budget" },
+ { TEXT_CONTAINER: [
+ { ROW: [
+ { role: COLHEADER, name: "Film Title" },
+ { role: COLHEADER, name: "Released" },
+ { role: COLHEADER, name: "Studio" },
+ { role: COLHEADER, name: "Worldwide Gross" },
+ { role: COLHEADER, name: "Domestic Gross" },
+ { role: COLHEADER, name: "Foreign Gross" },
+ { role: COLHEADER, name: "Budget" },
+ ] },
] },
{ ROW: [
{ role: CELL },
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/tree/test_table_3.html firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/tree/test_table_3.html
--- firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/tree/test_table_3.html 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/tree/test_table_3.html 2023-10-17 05:45:44.000000000 +0000
@@ -116,14 +116,16 @@
name: "Top 10 Grossing Animated Films of All Time",
},
] },
- { ROW: [
- { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Film Title" } ] },
- { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Released" } ] },
- { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Studio" } ] },
- { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Worldwide Gross" } ] },
- { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Domestic Gross" } ] },
- { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Foreign Gross" } ] },
- { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Budget" } ] },
+ { TEXT_CONTAINER: [
+ { ROW: [
+ { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Film Title" } ] },
+ { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Released" } ] },
+ { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Studio" } ] },
+ { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Worldwide Gross" } ] },
+ { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Domestic Gross" } ] },
+ { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Foreign Gross" } ] },
+ { COLUMNHEADER: [ { role: TEXT_LEAF, name: "Budget" } ] },
+ ] },
] },
{ ROW: [
{ role: CELL },
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/tree/test_table.html firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/tree/test_table.html
--- firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/tree/test_table.html 2023-09-29 10:59:37.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/tree/test_table.html 2023-10-17 05:45:43.000000000 +0000
@@ -422,7 +422,7 @@
-
+
bla |
@@ -482,8 +482,8 @@
-
-
+
+
static colheader |
relative colheader |
absolute colheader |
diff -Nru firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/treeupdate/test_cssoverflow.html firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/treeupdate/test_cssoverflow.html
--- firefox-esr-115.3.1esr+build1/accessible/tests/mochitest/treeupdate/test_cssoverflow.html 2023-09-29 10:59:36.000000000 +0000
+++ firefox-esr-115.4.0esr+build1/accessible/tests/mochitest/treeupdate/test_cssoverflow.html 2023-10-17 05:45:43.000000000 +0000
@@ -61,7 +61,7 @@
}
/**
- * Change scrollbar styles from hidden to auto to make the scroll area focusable.
+ * Change scrollbar styles from visible to auto to make the scroll area focusable.
* That causes us to create an accessible for it.
* Make sure the tree stays intact.
* The scroll area has no ID on purpose to make it inaccessible initially.
@@ -120,7 +120,7 @@
gQueue = new eventQueue();
gQueue.push(new changeScrollRange("container", "scrollarea"));
- gQueue.push(new makeFocusableByScrollbarStyles("container3"));
+ gQueue.push(new makeFocusableByScrollbarStyles("container2"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
@@ -144,7 +144,6 @@
-
-
+