CachedTableAccessible.h (8807B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef CACHED_TABLE_ACCESSIBLE_H 8 #define CACHED_TABLE_ACCESSIBLE_H 9 10 #include "mozilla/a11y/TableAccessible.h" 11 #include "mozilla/a11y/TableCellAccessible.h" 12 #include "mozilla/UniquePtr.h" 13 #include "nsTHashMap.h" 14 15 namespace mozilla::a11y { 16 17 const uint32_t kNoCellIdx = UINT32_MAX; 18 19 class AccIterable; 20 21 class CachedTableAccessible; 22 23 class CachedTableCellAccessible final : public TableCellAccessible { 24 public: 25 static CachedTableCellAccessible* GetFrom(Accessible* aAcc); 26 27 virtual TableAccessible* Table() const override; 28 29 virtual uint32_t ColIdx() const override { 30 return static_cast<int32_t>(mColIdx); 31 } 32 33 virtual uint32_t RowIdx() const override { 34 return static_cast<int32_t>(mRowIdx); 35 } 36 37 virtual uint32_t ColExtent() const override; 38 39 virtual uint32_t RowExtent() const override; 40 41 virtual void ColHeaderCells(nsTArray<Accessible*>* aCells) override; 42 43 virtual void RowHeaderCells(nsTArray<Accessible*>* aCells) override; 44 45 virtual bool Selected() override; 46 47 private: 48 CachedTableCellAccessible(uint64_t aAccID, Accessible* aAcc, uint32_t aRowIdx, 49 uint32_t aColIdx, uint32_t aPrevColHeaderCellIdx) 50 : mAccID(aAccID), 51 mAcc(aAcc), 52 mRowIdx(aRowIdx), 53 mColIdx(aColIdx), 54 mPrevColHeaderCellIdx(aPrevColHeaderCellIdx) {} 55 56 // Get the Accessible for this table cell given its ancestor table Accessible, 57 // verifying that the Accessible is valid. 58 Accessible* Acc(Accessible* aTableAcc) const; 59 60 UniquePtr<AccIterable> GetExplicitHeadersIterator(); 61 62 uint64_t mAccID; 63 // CachedTableAccessible methods which fetch a cell should retrieve the 64 // Accessible using Acc() rather than using mAcc. We need mAcc for some 65 // methods because we can't fetch a document by id. It's okay to use mAcc in 66 // these methods because the caller has to hold the Accessible in order to 67 // call them. 68 Accessible* mAcc; 69 uint32_t mRowIdx; 70 uint32_t mColIdx; 71 // The cell index of the previous implicit column header. 72 uint32_t mPrevColHeaderCellIdx; 73 friend class CachedTableAccessible; 74 }; 75 76 /** 77 * TableAccessible implementation which builds and queries a cache. 78 */ 79 class CachedTableAccessible final : public TableAccessible { 80 public: 81 static CachedTableAccessible* GetFrom(Accessible* aAcc); 82 83 /** 84 * This must be called whenever a table is destroyed or the structure of a 85 * table changes; e.g. cells wer added or removed. It can be called with 86 * either a table or a cell. 87 */ 88 static void Invalidate(Accessible* aAcc); 89 90 virtual Accessible* Caption() const override; 91 virtual void Summary(nsString& aSummary) override; 92 93 virtual uint32_t ColCount() const override { return mColCount; } 94 95 virtual uint32_t RowCount() override { return mRowColToCellIdx.Length(); } 96 97 virtual int32_t ColIndexAt(uint32_t aCellIdx) override { 98 if (aCellIdx < mCells.Length()) { 99 return static_cast<int32_t>(mCells[aCellIdx].mColIdx); 100 } 101 return -1; 102 } 103 104 virtual int32_t RowIndexAt(uint32_t aCellIdx) override { 105 if (aCellIdx < mCells.Length()) { 106 return static_cast<int32_t>(mCells[aCellIdx].mRowIdx); 107 } 108 return -1; 109 } 110 111 virtual void RowAndColIndicesAt(uint32_t aCellIdx, int32_t* aRowIdx, 112 int32_t* aColIdx) override { 113 if (aCellIdx < mCells.Length()) { 114 CachedTableCellAccessible& cell = mCells[aCellIdx]; 115 *aRowIdx = static_cast<int32_t>(cell.mRowIdx); 116 *aColIdx = static_cast<int32_t>(cell.mColIdx); 117 return; 118 } 119 *aRowIdx = -1; 120 *aColIdx = -1; 121 } 122 123 virtual uint32_t ColExtentAt(uint32_t aRowIdx, uint32_t aColIdx) override { 124 int32_t cellIdx = CellIndexAt(aRowIdx, aColIdx); 125 if (cellIdx == -1) { 126 return 0; 127 } 128 // Verify that the cell's Accessible is valid. 129 mCells[cellIdx].Acc(mAcc); 130 return mCells[cellIdx].ColExtent(); 131 } 132 133 virtual uint32_t RowExtentAt(uint32_t aRowIdx, uint32_t aColIdx) override { 134 int32_t cellIdx = CellIndexAt(aRowIdx, aColIdx); 135 if (cellIdx == -1) { 136 return 0; 137 } 138 // Verify that the cell's Accessible is valid. 139 mCells[cellIdx].Acc(mAcc); 140 return mCells[cellIdx].RowExtent(); 141 } 142 143 virtual int32_t CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) override { 144 if (aRowIdx < mRowColToCellIdx.Length()) { 145 auto& row = mRowColToCellIdx[aRowIdx]; 146 if (aColIdx < row.Length()) { 147 uint32_t cellIdx = row[aColIdx]; 148 if (cellIdx != kNoCellIdx) { 149 return static_cast<int32_t>(cellIdx); 150 } 151 } 152 } 153 return -1; 154 } 155 156 virtual Accessible* CellAt(uint32_t aRowIdx, uint32_t aColIdx) override; 157 158 virtual bool IsColSelected(uint32_t aColIdx) override { 159 bool selected = false; 160 for (uint32_t row = 0; row < RowCount(); ++row) { 161 selected = IsCellSelected(row, aColIdx); 162 if (!selected) { 163 break; 164 } 165 } 166 return selected; 167 } 168 169 virtual bool IsRowSelected(uint32_t aRowIdx) override { 170 bool selected = false; 171 for (uint32_t col = 0; col < mColCount; ++col) { 172 selected = IsCellSelected(aRowIdx, col); 173 if (!selected) { 174 break; 175 } 176 } 177 return selected; 178 } 179 180 virtual bool IsCellSelected(uint32_t aRowIdx, uint32_t aColIdx) override { 181 int32_t cellIdx = CellIndexAt(aRowIdx, aColIdx); 182 if (cellIdx == -1) { 183 return false; 184 } 185 // Verify that the cell's Accessible is valid. 186 mCells[cellIdx].Acc(mAcc); 187 return mCells[cellIdx].Selected(); 188 } 189 190 virtual uint32_t SelectedCellCount() override { 191 uint32_t count = 0; 192 for (auto& cell : mCells) { 193 // Verify that the cell's Accessible is valid. 194 cell.Acc(mAcc); 195 if (cell.Selected()) { 196 ++count; 197 } 198 } 199 return count; 200 } 201 202 virtual uint32_t SelectedColCount() override { 203 uint32_t count = 0; 204 for (uint32_t col = 0; col < mColCount; ++col) { 205 if (IsColSelected(col)) { 206 ++count; 207 } 208 } 209 return count; 210 } 211 212 virtual uint32_t SelectedRowCount() override { 213 uint32_t count = 0; 214 for (uint32_t row = 0; row < RowCount(); ++row) { 215 if (IsRowSelected(row)) { 216 ++count; 217 } 218 } 219 return count; 220 } 221 222 virtual void SelectedCells(nsTArray<Accessible*>* aCells) override { 223 for (auto& cell : mCells) { 224 // Verify that the cell's Accessible is valid. 225 Accessible* acc = cell.Acc(mAcc); 226 if (cell.Selected()) { 227 aCells->AppendElement(acc); 228 } 229 } 230 } 231 232 virtual void SelectedCellIndices(nsTArray<uint32_t>* aCells) override { 233 for (uint32_t idx = 0; idx < mCells.Length(); ++idx) { 234 CachedTableCellAccessible& cell = mCells[idx]; 235 // Verify that the cell's Accessible is valid. 236 cell.Acc(mAcc); 237 if (cell.Selected()) { 238 aCells->AppendElement(idx); 239 } 240 } 241 } 242 243 virtual void SelectedColIndices(nsTArray<uint32_t>* aCols) override { 244 for (uint32_t col = 0; col < mColCount; ++col) { 245 if (IsColSelected(col)) { 246 aCols->AppendElement(col); 247 } 248 } 249 } 250 251 virtual void SelectedRowIndices(nsTArray<uint32_t>* aRows) override { 252 for (uint32_t row = 0; row < RowCount(); ++row) { 253 if (IsRowSelected(row)) { 254 aRows->AppendElement(row); 255 } 256 } 257 } 258 259 virtual Accessible* AsAccessible() override { return mAcc; } 260 261 virtual bool IsProbablyLayoutTable() override; 262 263 private: 264 explicit CachedTableAccessible(Accessible* aAcc); 265 266 // Ensure that the given row exists in our data structure, creating array 267 // elements as needed. 268 void EnsureRow(uint32_t aRowIdx); 269 270 // Ensure that the given row and column coordinate exists in our data 271 // structure, creating array elements as needed. A newly created coordinate 272 // will be set to kNoCellIdx. 273 void EnsureRowCol(uint32_t aRowIdx, uint32_t aColIdx); 274 275 Accessible* mAcc; // The table Accessible. 276 // We track the column count because it might not be uniform across rows in 277 // malformed tables. 278 uint32_t mColCount = 0; 279 // An array of cell instances. A cell index is an index into this array. 280 nsTArray<CachedTableCellAccessible> mCells; 281 // Maps row and column coordinates to cell indices. 282 nsTArray<nsTArray<uint32_t>> mRowColToCellIdx; 283 // Maps Accessibles to cell indexes to facilitate retrieval of a cell 284 // instance from a cell Accessible. The Accessible* keys should only be used 285 // for lookup. They should not be dereferenced. 286 nsTHashMap<Accessible*, uint32_t> mAccToCellIdx; 287 uint64_t mCaptionAccID = 0; 288 289 friend class CachedTableCellAccessible; 290 }; 291 292 } // namespace mozilla::a11y 293 294 #endif