30void FindCellsInRow(AXNode* node, std::vector<AXNode*>* cell_nodes) {
31 for (AXNode* child : node->children()) {
32 if (child->IsIgnored() ||
34 FindCellsInRow(child, cell_nodes);
36 cell_nodes->push_back(child);
48void FindRowsAndThenCells(AXNode* node,
49 std::vector<AXNode*>* row_node_list,
50 std::vector<std::vector<AXNode*>>* cell_nodes_per_row,
51 int32_t& caption_node_id) {
52 for (AXNode* child : node->children()) {
53 if (child->IsIgnored() ||
57 FindRowsAndThenCells(child, row_node_list, cell_nodes_per_row,
60 row_node_list->push_back(child);
61 cell_nodes_per_row->push_back(std::vector<AXNode*>());
62 FindCellsInRow(child, &cell_nodes_per_row->back());
64 caption_node_id = child->id();
68size_t GetSizeTAttribute(
const AXNode& node,
IntAttribute attribute) {
69 return base::saturated_cast<size_t>(node.GetIntAttribute(attribute));
82 while (node && node != tree->
root())
91 bool success =
info->Update();
103 std::vector<std::vector<AXNode*>> cell_nodes_per_row;
105 FindRowsAndThenCells(table_node_, &
row_nodes, &cell_nodes_per_row,
112 row_count = GetSizeTAttribute(*table_node_, IntAttribute::kTableRowCount);
113 col_count = GetSizeTAttribute(*table_node_, IntAttribute::kTableColumnCount);
124 BuildCellDataVectorFromRowAndCellNodes(
row_nodes, cell_nodes_per_row);
132 BuildCellAndHeaderVectorsFromCellData();
137 UpdateExtraMacNodes();
150void AXTableInfo::ClearVectors() {
160 incremental_row_col_map_.clear();
163void AXTableInfo::BuildCellDataVectorFromRowAndCellNodes(
164 const std::vector<AXNode*>& row_node_list,
165 const std::vector<std::vector<AXNode*>>& cell_nodes_per_row) {
171 size_t cell_index = 0;
172 size_t current_aria_row_index = 1;
173 size_t next_row_index = 0;
174 for (
size_t i = 0;
i < cell_nodes_per_row.size();
i++) {
175 auto& cell_nodes_in_this_row = cell_nodes_per_row[
i];
176 AXNode* row_node = row_node_list[
i];
177 bool is_first_cell_in_row =
true;
178 size_t current_col_index = 0;
179 size_t current_aria_col_index = 1;
185 GetSizeTAttribute(*row_node, IntAttribute::kTableRowIndex));
187 size_t spanned_col_index = 0;
188 for (AXNode* cell : cell_nodes_in_this_row) {
193 cell_data.cell = cell;
197 cell_data.row_index =
198 GetSizeTAttribute(*cell, IntAttribute::kTableCellRowIndex);
200 GetSizeTAttribute(*cell, IntAttribute::kTableCellRowSpan);
201 cell_data.aria_row_index =
202 GetSizeTAttribute(*cell, IntAttribute::kAriaCellRowIndex);
203 cell_data.col_index =
204 GetSizeTAttribute(*cell, IntAttribute::kTableCellColumnIndex);
205 cell_data.aria_col_index =
206 GetSizeTAttribute(*cell, IntAttribute::kAriaCellColumnIndex);
208 GetSizeTAttribute(*cell, IntAttribute::kTableCellColumnSpan);
211 cell_data.row_span =
std::max(
size_t{1}, cell_data.row_span);
212 cell_data.col_span =
std::max(
size_t{1}, cell_data.col_span);
215 cell_data.col_index =
std::max(cell_data.col_index, current_col_index);
218 spanned_col_index =
std::max(spanned_col_index, cell_data.col_index);
220 if (is_first_cell_in_row) {
221 is_first_cell_in_row =
false;
226 if (cell_data.row_index > *current_row_index) {
227 *current_row_index = cell_data.row_index;
229 cell_data.row_index = *current_row_index;
234 if (!cell_data.aria_row_index) {
235 cell_data.aria_row_index =
236 GetSizeTAttribute(*row_node, IntAttribute::kAriaCellRowIndex);
238 if (!cell_data.aria_col_index) {
239 cell_data.aria_col_index =
240 GetSizeTAttribute(*row_node, IntAttribute::kAriaCellColumnIndex);
242 cell_data.aria_row_index =
243 std::max(cell_data.aria_row_index, current_aria_row_index);
244 current_aria_row_index = cell_data.aria_row_index;
248 cell_data.row_index = *current_row_index;
249 cell_data.aria_row_index = current_aria_row_index;
257 const auto& row_it = incremental_row_col_map_.find(*current_row_index);
258 if (row_it == incremental_row_col_map_.end()) {
261 const auto& col_it = row_it->second.find(spanned_col_index);
262 if (col_it == row_it->second.end()) {
267 const CellData& spanned_cell_data = col_it->second;
269 spanned_cell_data.col_index + spanned_cell_data.col_span;
273 cell_data.col_index = spanned_col_index;
279 for (
size_t r = cell_data.row_index;
280 r < (cell_data.row_index + cell_data.row_span); r++) {
281 for (
size_t c = cell_data.col_index;
282 c < (cell_data.col_index + cell_data.col_span); c++) {
283 incremental_row_col_map_[r][c] = cell_data;
288 cell_data.aria_col_index =
289 std::max(cell_data.aria_col_index, current_aria_col_index);
290 current_aria_col_index = cell_data.aria_col_index;
301 static_cast<int>(current_aria_row_index + cell_data.row_span - 1));
306 static_cast<int>(current_aria_col_index + cell_data.col_span - 1));
311 current_col_index = cell_data.col_index + cell_data.col_span;
312 current_aria_col_index = cell_data.aria_col_index + cell_data.col_span;
313 spanned_col_index = current_col_index;
322 current_aria_row_index++;
323 next_row_index = *current_row_index + 1;
327void AXTableInfo::BuildCellAndHeaderVectorsFromCellData() {
346 const auto& row_it = incremental_row_col_map_.find(r);
347 if (row_it != incremental_row_col_map_.end()) {
348 const auto& col_it = row_it->second.find(c);
349 if (col_it != row_it->second.end())
350 cell_ids[r][c] = col_it->second.cell->id();
356 incremental_row_col_map_.clear();
360 for (
size_t r = cell_data.row_index;
361 r < cell_data.row_index + cell_data.row_span; r++) {
363 for (
size_t c = cell_data.col_index;
364 c < cell_data.col_index + cell_data.col_span; c++) {
366 AXNode* cell = cell_data.cell;
379void AXTableInfo::UpdateExtraMacNodes() {
401 ClearExtraMacNodes();
409 std::vector<AXTreeObserver::Change> changes;
410 changes.reserve(extra_node_count +
416 changes.push_back(AXTreeObserver::Change(
422 changes.push_back(AXTreeObserver::Change(
427 UpdateExtraMacColumnNodeAttributes(
i);
431 data.intlist_attributes.clear();
436 changes.push_back(AXTreeObserver::Change(
437 table_node_, AXTreeObserver::ChangeType::NODE_CHANGED));
438 for (AXTreeObserver* observer : tree_->
observers()) {
439 observer->OnAtomicUpdateFinished(tree_,
false, changes);
443AXNode* AXTableInfo::CreateExtraMacColumnNode(
size_t col_index) {
445 size_t index_in_parent = col_index + table_node_->
children().size();
446 int32_t unignored_index_in_parent =
448 AXNode* node =
new AXNode(tree_, table_node_,
id, index_in_parent,
449 unignored_index_in_parent);
454 for (AXTreeObserver* observer : tree_->
observers())
455 observer->OnNodeCreated(tree_, node);
459AXNode* AXTableInfo::CreateExtraMacTableHeaderNode() {
462 int32_t unignored_index_in_parent =
464 AXNode* node =
new AXNode(tree_, table_node_,
id, index_in_parent,
465 unignored_index_in_parent);
471 for (AXTreeObserver* observer : tree_->
observers())
472 observer->OnNodeCreated(tree_, node);
477void AXTableInfo::UpdateExtraMacColumnNodeAttributes(
size_t col_index) {
479 data.int_attributes.clear();
482 data.AddIntAttribute(IntAttribute::kTableColumnIndex,
483 static_cast<int32_t
>(col_index));
487 data.AddIntAttribute(IntAttribute::kTableColumnHeaderId,
492 data.intlist_attributes.clear();
493 std::vector<int32_t> col_nodes;
495 for (
size_t row_index = 0; row_index <
row_count; row_index++) {
496 int32_t cell_id =
cell_ids[row_index][col_index];
497 if (cell_id != 0 && cell_id != last)
498 col_nodes.push_back(cell_id);
506void AXTableInfo::ClearExtraMacNodes() {
508 for (AXTreeObserver* observer : tree_->
observers())
509 observer->OnNodeWillBeDeleted(tree_, extra_mac_node);
511 delete extra_mac_node;
512 for (AXTreeObserver* observer : tree_->
observers())
513 observer->OnNodeDeleted(tree_, deleted_id);
534 int cell_padding = padding;
536 cell_padding = padding -
static_cast<int>(log10(cell_id));
537 result += std::string(cell_padding,
' ') +
'|';
544AXTableInfo::AXTableInfo(
AXTree* tree,
AXNode* table_node)
545 : tree_(tree), table_node_(table_node) {}
549 ClearExtraMacNodes();
551 observer->OnAtomicUpdateFinished(
553 {{table_node_, AXTreeObserver::ChangeType::NODE_CHANGED}});
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
size_t GetUnignoredChildCount() const
const std::vector< AXNode * > & children() const
int GetIntAttribute(ax::mojom::IntAttribute attribute) const
const AXNodeData & data() const
static AXTableInfo * Create(AXTree *tree, AXNode *table_node)
std::vector< std::vector< int32_t > > col_headers
std::vector< CellData > cell_data_vector
std::vector< std::vector< int32_t > > cell_ids
std::unordered_map< int32_t, size_t > row_id_to_index
std::vector< AXNode * > extra_mac_nodes
std::unordered_map< int32_t, size_t > cell_id_to_index
std::vector< AXNode * > row_nodes
std::string ToString() const
std::vector< int32_t > all_headers
std::vector< std::vector< int32_t > > row_headers
std::vector< int32_t > unique_cell_ids
bool enable_extra_mac_nodes() const
int32_t GetNextNegativeInternalNodeId()
std::vector< AXTreeObserver * > & observers()
EMSCRIPTEN_KEEPALIVE void empty()
static float max(float r, float g, float b)
const int32_t kUnknownAriaColumnOrRowCount
std::string NumberToString(int32_t number)
bool IsCellOrTableHeader(const ax::mojom::Role role)
bool IsTableRow(ax::mojom::Role role)
bool IsTableLike(const ax::mojom::Role role)
std::shared_ptr< const fml::Mapping > data
#define BASE_DCHECK(condition)