#include <tuple>
#include "build/build_config.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_tree.h"
ax::mojom::Role GetInterestingTableRole(unsigned char byte) {
switch (byte % 16) {
default:
case 0:
case 1:
case 2:
case 3:
return ax::mojom::Role::kCell;
case 4:
case 5:
return ax::mojom::Role::kRow;
case 6:
return ax::mojom::Role::kTable;
case 7:
return ax::mojom::Role::kGrid;
case 8:
return ax::mojom::Role::kColumnHeader;
case 9:
return ax::mojom::Role::kRowHeader;
case 10:
return ax::mojom::Role::kGenericContainer;
case 11:
return ax::mojom::Role::kNone;
case 12:
return ax::mojom::Role::kLayoutTable;
case 13:
return ax::mojom::Role::kLayoutTableCell;
case 14:
return ax::mojom::Role::kLayoutTableRow;
case 15:
return ax::mojom::Role::kMain;
}
}
ax::mojom::IntAttribute GetInterestingTableAttribute(unsigned char byte) {
switch (byte % 10) {
case 0:
default:
return ax::mojom::IntAttribute::kTableCellRowIndex;
case 1:
return ax::mojom::IntAttribute::kTableCellColumnIndex;
case 2:
return ax::mojom::IntAttribute::kTableRowCount;
case 3:
return ax::mojom::IntAttribute::kTableColumnCount;
case 4:
return ax::mojom::IntAttribute::kAriaRowCount;
case 5:
return ax::mojom::IntAttribute::kAriaColumnCount;
case 6:
return ax::mojom::IntAttribute::kTableCellRowSpan;
case 7:
return ax::mojom::IntAttribute::kTableCellColumnSpan;
case 8:
return ax::mojom::IntAttribute::kAriaCellRowIndex;
case 9:
return ax::mojom::IntAttribute::kAriaCellColumnIndex;
}
}
void TestTableAPIs(const ui::AXNode* node) {
std::ignore = node->IsTable();
std::ignore = node->GetTableColCount();
std::ignore = node->GetTableRowCount();
std::ignore = node->GetTableAriaColCount();
std::ignore = node->GetTableAriaRowCount();
std::ignore = node->GetTableCellCount();
std::ignore = node->GetTableCaption();
for (int i = 0; i < 8; i++)
std::ignore = node->GetTableCellFromIndex(i);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
std::ignore = node->GetTableCellFromCoords(i, j);
std::vector<ui::AXNodeID> ids;
for (int i = 0; i < 3; i++) {
std::vector<ui::AXNodeID> col_header_node_ids =
node->GetTableColHeaderNodeIds(i);
ids.insert(ids.end(), col_header_node_ids.begin(),
col_header_node_ids.end());
std::vector<ui::AXNodeID> row_header_node_ids =
node->GetTableRowHeaderNodeIds(i);
ids.insert(ids.end(), row_header_node_ids.begin(),
row_header_node_ids.end());
}
std::vector<ui::AXNodeID> unique_cell_ids = node->GetTableUniqueCellIds();
ids.insert(ids.end(), unique_cell_ids.begin(), unique_cell_ids.end());
std::ignore = node->IsTableRow();
std::ignore = node->GetTableRowRowIndex();
#if BUILDFLAG(IS_APPLE)
std::ignore = node->IsTableColumn();
std::ignore = node->GetTableColColIndex();
#endif
std::ignore = node->IsTableCellOrHeader();
std::ignore = node->GetTableCellIndex();
std::ignore = node->GetTableCellColIndex();
std::ignore = node->GetTableCellRowIndex();
std::ignore = node->GetTableCellColSpan();
std::ignore = node->GetTableCellRowSpan();
std::ignore = node->GetTableCellAriaColIndex();
std::ignore = node->GetTableCellAriaRowIndex();
std::vector<ui::AXNodeID> cell_col_header_node_ids =
node->GetTableCellColHeaderNodeIds();
ids.insert(ids.end(), cell_col_header_node_ids.begin(),
cell_col_header_node_ids.end());
std::vector<ui::AXNodeID> cell_row_header_node_ids =
node->GetTableCellRowHeaderNodeIds();
ids.insert(ids.end(), cell_row_header_node_ids.begin(),
cell_row_header_node_ids.end());
std::vector<ui::AXNode*> headers;
node->GetTableCellColHeaders(&headers);
node->GetTableCellRowHeaders(&headers);
for (const auto* child : node->children())
TestTableAPIs(child);
}
extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
ui::AXTreeUpdate initial_state;
initial_state.root_id = 1;
size_t i = 0;
ui::AXNodeData root;
root.id = 1;
if (i < size)
root.role = GetInterestingTableRole(data[i++]);
root.child_ids.push_back(2);
initial_state.nodes.push_back(root);
ui::AXNodeData table;
table.id = 2;
table.role = ax::mojom::Role::kTable;
if (i < size) {
size_t child_count = data[i++] % 8;
for (size_t j = 0; j < child_count && i < size; j++)
table.child_ids.push_back(3 + data[i++] % 32);
}
initial_state.nodes.push_back(table);
int next_id = 3;
while (i < size) {
ui::AXNodeData node;
node.id = next_id++;
if (i < size)
node.role = GetInterestingTableRole(data[i++]);
if (i < size) {
int attr_count = data[i++] % 6;
for (int j = 0; j < attr_count && i + 1 < size; j++) {
unsigned char attr = data[i++];
int32_t value = static_cast<int32_t>(data[i++]) - 2;
node.AddIntAttribute(GetInterestingTableAttribute(attr), value);
}
}
if (i < size) {
size_t child_count = data[i++] % 8;
for (size_t j = 0; j < child_count && i < size; j++)
node.child_ids.push_back(4 + data[i++] % 32);
}
initial_state.nodes.push_back(node);
}
VLOG(1) << "Input accessibility tree:\n" << initial_state.ToString();
ui::AXTree tree;
if (tree.Unserialize(initial_state))
TestTableAPIs(tree.root());
return 0;
}