зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1735970 part 9: Support explicitly associated headers for both local and remote cells. r=morgan
Headers are associated using the headers DOM attribute, which is a list of DOM node ids. For the cache, we send and store these as Accessible ids. Differential Revision: https://phabricator.services.mozilla.com/D141212
This commit is contained in:
Родитель
ed3aeb2201
Коммит
1a56a1b78a
|
@ -6,8 +6,11 @@
|
|||
|
||||
#include "CachedTableAccessible.h"
|
||||
|
||||
#include "AccIterator.h"
|
||||
#include "DocAccessibleParent.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsAccUtils.h"
|
||||
#include "nsIAccessiblePivot.h"
|
||||
#include "Pivot.h"
|
||||
|
@ -42,6 +45,31 @@ class TablePartRule : public PivotRule {
|
|||
}
|
||||
};
|
||||
|
||||
// Iterates through headers explicitly associated with a remote table cell via
|
||||
// the headers DOM attribute. These are cached as Accessible ids.
|
||||
class RemoteExplicitHeadersIterator : public AccIterable {
|
||||
public:
|
||||
RemoteExplicitHeadersIterator(const nsTArray<uint64_t>& aHeaders,
|
||||
Accessible* aDoc)
|
||||
: mHeaders(aHeaders), mDoc(aDoc), mIndex(0) {}
|
||||
|
||||
virtual Accessible* Next() override {
|
||||
while (mIndex < mHeaders.Length()) {
|
||||
uint64_t id = mHeaders[mIndex++];
|
||||
Accessible* acc = nsAccUtils::GetAccessibleByID(mDoc, id);
|
||||
if (acc) {
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
const nsTArray<uint64_t>& mHeaders;
|
||||
Accessible* mDoc;
|
||||
uint32_t mIndex;
|
||||
};
|
||||
|
||||
// The Accessible* keys should only be used for lookup. They should not be
|
||||
// dereferenced.
|
||||
using CachedTablesMap = nsTHashMap<Accessible*, CachedTableAccessible>;
|
||||
|
@ -298,12 +326,47 @@ uint32_t CachedTableCellAccessible::RowExtent() const {
|
|||
return 1;
|
||||
}
|
||||
|
||||
UniquePtr<AccIterable> CachedTableCellAccessible::GetExplicitHeadersIterator() {
|
||||
if (RemoteAccessible* remoteAcc = mAcc->AsRemote()) {
|
||||
if (remoteAcc->mCachedFields) {
|
||||
if (auto headers =
|
||||
remoteAcc->mCachedFields->GetAttribute<nsTArray<uint64_t>>(
|
||||
nsGkAtoms::headers)) {
|
||||
return MakeUnique<RemoteExplicitHeadersIterator>(*headers,
|
||||
remoteAcc->Document());
|
||||
}
|
||||
}
|
||||
} else if (LocalAccessible* localAcc = mAcc->AsLocal()) {
|
||||
return MakeUnique<IDRefsIterator>(
|
||||
localAcc->Document(), localAcc->GetContent(), nsGkAtoms::headers);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CachedTableCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aCells) {
|
||||
// XXX Support explicitly associated headers.
|
||||
auto* table = static_cast<CachedTableAccessible*>(Table());
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
if (auto iter = GetExplicitHeadersIterator()) {
|
||||
while (Accessible* header = iter->Next()) {
|
||||
role headerRole = header->Role();
|
||||
if (headerRole == roles::COLUMNHEADER) {
|
||||
aCells->AppendElement(header);
|
||||
} else if (headerRole != roles::ROWHEADER) {
|
||||
// Treat this cell as a column header only if it's in the same column.
|
||||
if (auto cellIdx = table->mAccToCellIdx.Lookup(header)) {
|
||||
CachedTableCellAccessible& cell = table->mCells[*cellIdx];
|
||||
if (cell.ColIdx() == ColIdx()) {
|
||||
aCells->AppendElement(header);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!aCells->IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Accessible* doc = nsAccUtils::DocumentFor(table->AsAccessible());
|
||||
// Each cell stores its previous implicit column header, effectively forming a
|
||||
// linked list. We traverse that to get all the headers.
|
||||
|
@ -319,11 +382,29 @@ void CachedTableCellAccessible::ColHeaderCells(nsTArray<Accessible*>* aCells) {
|
|||
}
|
||||
|
||||
void CachedTableCellAccessible::RowHeaderCells(nsTArray<Accessible*>* aCells) {
|
||||
// XXX Support explicitly associated headers.
|
||||
TableAccessibleBase* table = Table();
|
||||
auto* table = static_cast<CachedTableAccessible*>(Table());
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
if (auto iter = GetExplicitHeadersIterator()) {
|
||||
while (Accessible* header = iter->Next()) {
|
||||
role headerRole = header->Role();
|
||||
if (headerRole == roles::ROWHEADER) {
|
||||
aCells->AppendElement(header);
|
||||
} else if (headerRole != roles::COLUMNHEADER) {
|
||||
// Treat this cell as a row header only if it's in the same row.
|
||||
if (auto cellIdx = table->mAccToCellIdx.Lookup(header)) {
|
||||
CachedTableCellAccessible& cell = table->mCells[*cellIdx];
|
||||
if (cell.RowIdx() == RowIdx()) {
|
||||
aCells->AppendElement(header);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!aCells->IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// We don't cache implicit row headers because there are usually not that many
|
||||
// cells per row. Get all the row headers on the row before this cell.
|
||||
uint32_t row = RowIdx();
|
||||
|
|
|
@ -9,12 +9,15 @@
|
|||
|
||||
#include "mozilla/a11y/TableAccessibleBase.h"
|
||||
#include "mozilla/a11y/TableCellAccessibleBase.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 TableCellAccessibleBase {
|
||||
|
@ -54,6 +57,8 @@ class CachedTableCellAccessible final : public TableCellAccessibleBase {
|
|||
// 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
|
||||
|
|
|
@ -3355,6 +3355,19 @@ already_AddRefed<AccAttributes> LocalAccessible::BundleFieldsForCache(
|
|||
} else if (aUpdateType == CacheUpdateType::Update) {
|
||||
fields->SetAttribute(nsGkAtoms::colspan, DeleteEntry());
|
||||
}
|
||||
if (mContent->AsElement()->HasAttr(kNameSpaceID_None,
|
||||
nsGkAtoms::headers)) {
|
||||
nsTArray<uint64_t> headers;
|
||||
IDRefsIterator iter(mDoc, mContent, nsGkAtoms::headers);
|
||||
while (LocalAccessible* cell = iter.Next()) {
|
||||
if (cell->IsTableCell()) {
|
||||
headers.AppendElement(cell->ID());
|
||||
}
|
||||
}
|
||||
fields->SetAttribute(nsGkAtoms::headers, std::move(headers));
|
||||
} else {
|
||||
fields->SetAttribute(nsGkAtoms::headers, DeleteEntry());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче