summaryrefslogtreecommitdiffstats
path: root/accessible/base/CachedTableAccessible.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--accessible/base/CachedTableAccessible.h294
1 files changed, 294 insertions, 0 deletions
diff --git a/accessible/base/CachedTableAccessible.h b/accessible/base/CachedTableAccessible.h
new file mode 100644
index 0000000000..7803343070
--- /dev/null
+++ b/accessible/base/CachedTableAccessible.h
@@ -0,0 +1,294 @@
+/* -*- 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 CACHED_TABLE_ACCESSIBLE_H
+#define CACHED_TABLE_ACCESSIBLE_H
+
+#include "mozilla/a11y/TableAccessible.h"
+#include "mozilla/a11y/TableCellAccessible.h"
+#include "mozilla/UniquePtr.h"
+#include "nsTHashMap.h"
+
+namespace mozilla::a11y {
+
+const uint32_t kNoCellIdx = UINT32_MAX;
+
+class AccIterable;
+
+class CachedTableAccessible;
+
+class CachedTableCellAccessible final : public TableCellAccessible {
+ public:
+ static CachedTableCellAccessible* GetFrom(Accessible* aAcc);
+
+ virtual TableAccessible* Table() const override;
+
+ virtual uint32_t ColIdx() const override {
+ return static_cast<int32_t>(mColIdx);
+ }
+
+ virtual uint32_t RowIdx() const override {
+ return static_cast<int32_t>(mRowIdx);
+ }
+
+ virtual uint32_t ColExtent() const override;
+
+ virtual uint32_t RowExtent() const override;
+
+ virtual void ColHeaderCells(nsTArray<Accessible*>* aCells) override;
+
+ virtual void RowHeaderCells(nsTArray<Accessible*>* aCells) override;
+
+ virtual bool Selected() override;
+
+ private:
+ CachedTableCellAccessible(uint64_t aAccID, Accessible* aAcc, uint32_t aRowIdx,
+ uint32_t aColIdx, uint32_t aPrevColHeaderCellIdx)
+ : mAccID(aAccID),
+ mAcc(aAcc),
+ mRowIdx(aRowIdx),
+ mColIdx(aColIdx),
+ mPrevColHeaderCellIdx(aPrevColHeaderCellIdx) {}
+
+ // Get the Accessible for this table cell given its ancestor table Accessible,
+ // verifying that the Accessible is valid.
+ Accessible* Acc(Accessible* aTableAcc) const;
+
+ UniquePtr<AccIterable> GetExplicitHeadersIterator();
+
+ uint64_t mAccID;
+ // CachedTableAccessible methods which fetch a cell should retrieve the
+ // Accessible using Acc() rather than using mAcc. We need mAcc for some
+ // methods because we can't fetch a document by id. It's okay to use mAcc in
+ // these methods because the caller has to hold the Accessible in order to
+ // call them.
+ Accessible* mAcc;
+ uint32_t mRowIdx;
+ uint32_t mColIdx;
+ // The cell index of the previous implicit column header.
+ uint32_t mPrevColHeaderCellIdx;
+ friend class CachedTableAccessible;
+};
+
+/**
+ * TableAccessible implementation which builds and queries a cache.
+ */
+class CachedTableAccessible final : public TableAccessible {
+ public:
+ static CachedTableAccessible* GetFrom(Accessible* aAcc);
+
+ /**
+ * This must be called whenever a table is destroyed or the structure of a
+ * table changes; e.g. cells wer added or removed. It can be called with
+ * either a table or a cell.
+ */
+ static void Invalidate(Accessible* aAcc);
+
+ virtual Accessible* Caption() const override;
+ virtual void Summary(nsString& aSummary) override;
+
+ virtual uint32_t ColCount() const override { return mColCount; }
+
+ virtual uint32_t RowCount() override { return mRowColToCellIdx.Length(); }
+
+ virtual int32_t ColIndexAt(uint32_t aCellIdx) override {
+ if (aCellIdx < mCells.Length()) {
+ return static_cast<int32_t>(mCells[aCellIdx].mColIdx);
+ }
+ return -1;
+ }
+
+ virtual int32_t RowIndexAt(uint32_t aCellIdx) override {
+ if (aCellIdx < mCells.Length()) {
+ return static_cast<int32_t>(mCells[aCellIdx].mRowIdx);
+ }
+ return -1;
+ }
+
+ virtual void RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx,
+ int32_t* aColIdx) override {
+ if (aCellIdx < mCells.Length()) {
+ CachedTableCellAccessible& cell = mCells[aCellIdx];
+ *aRowIdx = static_cast<int32_t>(cell.mRowIdx);
+ *aColIdx = static_cast<int32_t>(cell.mColIdx);
+ return;
+ }
+ *aRowIdx = -1;
+ *aColIdx = -1;
+ }
+
+ virtual uint32_t ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx) override {
+ int32_t cellIdx = CellIndexAt(aRowIdx, aColIdx);
+ if (cellIdx == -1) {
+ return 0;
+ }
+ // Verify that the cell's Accessible is valid.
+ mCells[cellIdx].Acc(mAcc);
+ return mCells[cellIdx].ColExtent();
+ }
+
+ virtual uint32_t RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx) override {
+ int32_t cellIdx = CellIndexAt(aRowIdx, aColIdx);
+ if (cellIdx == -1) {
+ return 0;
+ }
+ // Verify that the cell's Accessible is valid.
+ mCells[cellIdx].Acc(mAcc);
+ return mCells[cellIdx].RowExtent();
+ }
+
+ virtual int32_t CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) override {
+ if (aRowIdx < mRowColToCellIdx.Length()) {
+ auto& row = mRowColToCellIdx[aRowIdx];
+ if (aColIdx < row.Length()) {
+ uint32_t cellIdx = row[aColIdx];
+ if (cellIdx != kNoCellIdx) {
+ return static_cast<int32_t>(cellIdx);
+ }
+ }
+ }
+ return -1;
+ }
+
+ virtual Accessible* CellAt(uint32_t aRowIdx, uint32_t aColIdx) override;
+
+ virtual bool IsColSelected(uint32_t aColIdx) override {
+ bool selected = false;
+ for (uint32_t row = 0; row < RowCount(); ++row) {
+ selected = IsCellSelected(row, aColIdx);
+ if (!selected) {
+ break;
+ }
+ }
+ return selected;
+ }
+
+ virtual bool IsRowSelected(uint32_t aRowIdx) override {
+ bool selected = false;
+ for (uint32_t col = 0; col < mColCount; ++col) {
+ selected = IsCellSelected(aRowIdx, col);
+ if (!selected) {
+ break;
+ }
+ }
+ return selected;
+ }
+
+ virtual bool IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) override {
+ int32_t cellIdx = CellIndexAt(aRowIdx, aColIdx);
+ if (cellIdx == -1) {
+ return false;
+ }
+ // Verify that the cell's Accessible is valid.
+ mCells[cellIdx].Acc(mAcc);
+ return mCells[cellIdx].Selected();
+ }
+
+ virtual uint32_t SelectedCellCount() override {
+ uint32_t count = 0;
+ for (auto& cell : mCells) {
+ // Verify that the cell's Accessible is valid.
+ cell.Acc(mAcc);
+ if (cell.Selected()) {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ virtual uint32_t SelectedColCount() override {
+ uint32_t count = 0;
+ for (uint32_t col = 0; col < mColCount; ++col) {
+ if (IsColSelected(col)) {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ virtual uint32_t SelectedRowCount() override {
+ uint32_t count = 0;
+ for (uint32_t row = 0; row < RowCount(); ++row) {
+ if (IsRowSelected(row)) {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ virtual void SelectedCells(nsTArray<Accessible*>* aCells) override {
+ for (auto& cell : mCells) {
+ // Verify that the cell's Accessible is valid.
+ Accessible* acc = cell.Acc(mAcc);
+ if (cell.Selected()) {
+ aCells->AppendElement(acc);
+ }
+ }
+ }
+
+ virtual void SelectedCellIndices(nsTArray<uint32_t>* aCells) override {
+ for (uint32_t idx = 0; idx < mCells.Length(); ++idx) {
+ CachedTableCellAccessible& cell = mCells[idx];
+ // Verify that the cell's Accessible is valid.
+ cell.Acc(mAcc);
+ if (cell.Selected()) {
+ aCells->AppendElement(idx);
+ }
+ }
+ }
+
+ virtual void SelectedColIndices(nsTArray<uint32_t>* aCols) override {
+ for (uint32_t col = 0; col < mColCount; ++col) {
+ if (IsColSelected(col)) {
+ aCols->AppendElement(col);
+ }
+ }
+ }
+
+ virtual void SelectedRowIndices(nsTArray<uint32_t>* aRows) override {
+ for (uint32_t row = 0; row < RowCount(); ++row) {
+ if (IsRowSelected(row)) {
+ aRows->AppendElement(row);
+ }
+ }
+ }
+
+ virtual Accessible* AsAccessible() override { return mAcc; }
+
+ virtual bool IsProbablyLayoutTable() override;
+
+ private:
+ explicit CachedTableAccessible(Accessible* aAcc);
+
+ // Ensure that the given row exists in our data structure, creating array
+ // elements as needed.
+ void EnsureRow(uint32_t aRowIdx);
+
+ // Ensure that the given row and column coordinate exists in our data
+ // structure, creating array elements as needed. A newly created coordinate
+ // will be set to kNoCellIdx.
+ void EnsureRowCol(uint32_t aRowIdx, uint32_t aColIdx);
+
+ Accessible* mAcc; // The table Accessible.
+ // We track the column count because it might not be uniform across rows in
+ // malformed tables.
+ uint32_t mColCount = 0;
+ // An array of cell instances. A cell index is an index into this array.
+ nsTArray<CachedTableCellAccessible> mCells;
+ // Maps row and column coordinates to cell indices.
+ nsTArray<nsTArray<uint32_t>> mRowColToCellIdx;
+ // Maps Accessibles to cell indexes to facilitate retrieval of a cell
+ // instance from a cell Accessible. The Accessible* keys should only be used
+ // for lookup. They should not be dereferenced.
+ nsTHashMap<Accessible*, uint32_t> mAccToCellIdx;
+ uint64_t mCaptionAccID = 0;
+
+ friend class CachedTableCellAccessible;
+};
+
+} // namespace mozilla::a11y
+
+#endif