Commit 3ae311d8 authored by Dominic Mazzoni's avatar Dominic Mazzoni Committed by Commit Bot

Add support for accessible tables with missing/bad data.

Previously we relied on Blink to correctly fill in the
row and column index of every cell in a table. This
tends to be expensive to do in Blink because it
requires invalidating and reserializing the entire table
if any cell changes.

Instead, try to defer as much of those calculations to
downstream to be computed when AT actually requests
table attributes.

This is more efficient, because Blink accessibility code
needs to run any time the page is updated, like when a
table is being built dynamically using JS - whereas AT
typically only queries table attributes when users
explore a table explicitly, so it makes sense to defer
computation until then.

This is also more accurate and less error-prone, as it
allows us to completely validate the table in a single
pass and fix any errors in table indexes.

Finally, a potential added benefit is that this makes it
easier to handle tables from Views or Arc++ that
don't have all of the table attributes set, we can
compute them automatically.

A follow-up change will remove the code that computes
some of these table attributes from Blink.

Bug: 832289

Change-Id: I252a592c854e47cf6d6e5bd6b7c4bc5d51775e72
Reviewed-on: https://chromium-review.googlesource.com/c/1307840Reviewed-by: default avatarAaron Leventhal <aleventhal@chromium.org>
Commit-Queue: Dominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#606940}
parent fabe78ea
......@@ -199,6 +199,22 @@ int32_t AXNode::GetTableRowCount() const {
return table_info->row_count;
}
int32_t AXNode::GetTableAriaColCount() const {
AXTableInfo* table_info = tree_->GetTableInfo(this);
if (!table_info)
return 0;
return table_info->aria_col_count;
}
int32_t AXNode::GetTableAriaRowCount() const {
AXTableInfo* table_info = tree_->GetTableInfo(this);
if (!table_info)
return 0;
return table_info->aria_row_count;
}
int32_t AXNode::GetTableCellCount() const {
AXTableInfo* table_info = tree_->GetTableInfo(this);
if (!table_info)
......@@ -319,17 +335,27 @@ int32_t AXNode::GetTableCellIndex() const {
}
int32_t AXNode::GetTableCellColIndex() const {
// TODO(dmazzoni): Compute from AXTableInfo. http://crbug.com/832289
int32_t col_index = 0;
GetIntAttribute(ax::mojom::IntAttribute::kTableCellColumnIndex, &col_index);
return col_index;
AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return 0;
int32_t index = GetTableCellIndex();
if (index == -1)
return 0;
return table_info->cell_data_vector[index].col_index;
}
int32_t AXNode::GetTableCellRowIndex() const {
// TODO(dmazzoni): Compute from AXTableInfo. http://crbug.com/832289
int32_t row_index = 0;
GetIntAttribute(ax::mojom::IntAttribute::kTableCellRowIndex, &row_index);
return row_index;
AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return 0;
int32_t index = GetTableCellIndex();
if (index == -1)
return 0;
return table_info->cell_data_vector[index].row_index;
}
int32_t AXNode::GetTableCellColSpan() const {
......@@ -360,15 +386,27 @@ int32_t AXNode::GetTableCellRowSpan() const {
}
int32_t AXNode::GetTableCellAriaColIndex() const {
int32_t col_index = 0;
GetIntAttribute(ax::mojom::IntAttribute::kAriaCellColumnIndex, &col_index);
return col_index;
AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return -0;
int32_t index = GetTableCellIndex();
if (index == -1)
return 0;
return table_info->cell_data_vector[index].aria_col_index;
}
int32_t AXNode::GetTableCellAriaRowIndex() const {
int32_t row_index = 0;
GetIntAttribute(ax::mojom::IntAttribute::kAriaCellRowIndex, &row_index);
return row_index;
AXTableInfo* table_info = GetAncestorTableInfo();
if (!table_info)
return -0;
int32_t index = GetTableCellIndex();
if (index == -1)
return 0;
return table_info->cell_data_vector[index].aria_row_index;
}
void AXNode::GetTableCellColHeaderNodeIds(
......
......@@ -191,14 +191,22 @@ class AX_EXPORT AXNode final {
// Most of these functions construct and cache an AXTableInfo behind
// the scenes to infer many properties of tables.
//
// TODO(dmazzoni): Make these const - not trivial because AXTableInfo
// does need to modify the AXTree.
// These interfaces use attributes provided by the source of the
// AX tree where possible, but fills in missing details and ignores
// specified attributes when they're bad or inconsistent. That way
// you're guaranteed to get a valid, consistent table when using these
// interfaces.
//
// Table-like nodes (including grids).
// Table-like nodes (including grids). All indices are 0-based except
// ARIA indices are all 1-based. In other words, the top-left corner
// of the table is row 0, column 0, cell index 0 - but that same cell
// has a minimum ARIA row index of 1 and column index of 1.
bool IsTable() const;
int32_t GetTableColCount() const;
int32_t GetTableRowCount() const;
int32_t GetTableAriaColCount() const;
int32_t GetTableAriaRowCount() const;
int32_t GetTableCellCount() const;
AXNode* GetTableCellFromIndex(int32_t index) const;
AXNode* GetTableCellFromCoords(int32_t row_index, int32_t col_index) const;
......
This diff is collapsed.
......@@ -19,6 +19,17 @@ class AXNode;
// This helper class computes info about tables and grids in AXTrees.
class AX_EXPORT AXTableInfo {
public:
struct CellData {
AXNode* cell;
int32_t cell_id;
int32_t col_index;
int32_t row_index;
int32_t col_span;
int32_t row_span;
int32_t aria_col_index;
int32_t aria_row_index;
};
// Returns nullptr if the node is not a valid table or grid node.
static AXTableInfo* Create(AXTree* tree, AXNode* table_node);
......@@ -57,6 +68,9 @@ class AX_EXPORT AXTableInfo {
// really is missing from the table.
std::vector<std::vector<int32_t>> cell_ids;
// Array of cell data for every unique cell in the table.
std::vector<CellData> cell_data_vector;
// Set of all unique cell node IDs in the table.
std::vector<int32_t> unique_cell_ids;
......@@ -68,9 +82,19 @@ class AX_EXPORT AXTableInfo {
// Map from each cell's node ID to its index in unique_cell_ids.
base::hash_map<int32_t, int32_t> cell_id_to_index;
// The ARIA row count and column count, if any ARIA table or grid
// attributes are used in the table at all.
int32_t aria_row_count = 0;
int32_t aria_col_count = 0;
private:
AXTableInfo(AXTree* tree, AXNode* table_node);
void ClearVectors();
void BuildCellDataVectorFromRowAndCellNodes(
const std::vector<AXNode*>& row_nodes,
const std::vector<std::vector<AXNode*>>& cell_nodes_per_row);
void BuildCellAndHeaderVectorsFromCellData();
void UpdateExtraMacNodes();
void ClearExtraMacNodes();
AXNode* CreateExtraMacColumnNode(int col_index);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment