25std::string TreeToStringHelper(
const AXNode* node,
int indent) {
29 return std::accumulate(
30 node->children().cbegin(), node->children().cend(),
31 std::string(2 * indent,
' ') + node->data().ToString() +
"\n",
32 [indent](
const std::string& str,
const auto* child) {
33 return str + TreeToStringHelper(child, indent + 1);
37template <
typename K,
typename V>
38bool KeyValuePairsKeysMatch(std::vector<std::pair<K, V>> pairs1,
39 std::vector<std::pair<K, V>> pairs2) {
40 if (pairs1.size() != pairs2.size())
42 for (
size_t i = 0;
i < pairs1.size(); ++
i) {
43 if (pairs1[
i].first != pairs2[
i].first)
49template <
typename K,
typename V>
50std::map<K, V> MapFromKeyValuePairs(std::vector<std::pair<K, V>> pairs) {
52 for (
size_t i = 0;
i < pairs.size(); ++
i)
53 result[pairs[
i].first] = pairs[
i].second;
62template <
typename K,
typename V,
typename F>
63void CallIfAttributeValuesChanged(
const std::vector<std::pair<K, V>>& pairs1,
64 const std::vector<std::pair<K, V>>& pairs2,
68 if (KeyValuePairsKeysMatch(pairs1, pairs2)) {
69 for (
size_t i = 0;
i < pairs1.size(); ++
i) {
70 if (pairs1[
i].second != pairs2[
i].second)
71 callback(pairs1[
i].first, pairs1[
i].second, pairs2[
i].second);
79 auto map1 = MapFromKeyValuePairs(pairs1);
80 auto map2 = MapFromKeyValuePairs(pairs2);
81 for (
size_t i = 0;
i < pairs1.size(); ++
i) {
82 const auto& new_iter = map2.find(pairs1[
i].first);
83 if (pairs1[
i].second != empty_value && new_iter == map2.end())
84 callback(pairs1[
i].first, pairs1[
i].second, empty_value);
87 for (
size_t i = 0;
i < pairs2.size(); ++
i) {
88 const auto& iter = map1.find(pairs2[
i].first);
89 if (iter == map1.end())
90 callback(pairs2[
i].first, empty_value, pairs2[
i].second);
91 else if (iter->second != pairs2[
i].second)
92 callback(pairs2[
i].first, iter->second, pairs2[
i].second);
96bool IsCollapsed(
const AXNode* node) {
273 <<
"This method should not be called before pending changes have "
274 "finished computing.";
294 BASE_LOG() <<
"This method should only be called while computing "
296 "before updates are made to the tree.";
300 return data &&
data->DoesNodeRequireInit();
306 BASE_LOG() <<
"This method should only be called while computing "
308 "before updates are made to the tree.";
314 return data->parent_node_id;
320 BASE_LOG() <<
"This method should only be called while computing "
322 "before updates are made to the tree.";
325 return GetOrCreatePendingStructureChanges(node_id)->
node_exists;
331 BASE_LOG() <<
"This method should only be called while computing "
333 "before updates are made to the tree.";
338 return (
data &&
data->last_known_data) ? *
data->last_known_data
345 BASE_LOG() <<
"This method should only be called while computing "
347 "before updates are made to the tree.";
350 GetOrCreatePendingStructureChanges(node_id)->
last_known_data =
nullptr;
356 BASE_LOG() <<
"This method should only be called while computing "
358 "before updates are made to the tree.";
370 <<
"This method should not be called before pending changes have "
371 "finished computing.";
375 return data->destroy_subtree_count;
384 BASE_LOG() <<
"This method should only be called while computing "
386 "before updates are made to the tree.";
390 if (!
data->node_exists)
393 ++
data->destroy_subtree_count;
402 <<
"This method should not be called before pending changes have "
403 "finished computing.";
408 --
data->destroy_subtree_count;
417 <<
"This method should not be called before pending changes have "
418 "finished computing.";
422 return data->destroy_node_count;
431 BASE_LOG() <<
"This method should only be called while computing "
433 "before updates are made to the tree.";
437 if (!
data->node_exists)
440 ++
data->destroy_node_count;
441 data->node_exists =
false;
442 data->last_known_data =
nullptr;
443 data->parent_node_id = std::nullopt;
454 <<
"This method should not be called before pending changes have "
455 "finished computing.";
460 --
data->destroy_node_count;
469 <<
"This method should not be called before pending changes have "
470 "finished computing.";
474 return data->create_node_count;
483 std::optional<AXNode::AXID> parent_node_id) {
485 BASE_LOG() <<
"This method should only be called while computing "
487 "before updates are made to the tree.";
491 if (
data->node_exists)
494 ++
data->create_node_count;
495 data->node_exists =
true;
496 data->parent_node_id = parent_node_id;
505 <<
"This method should not be called before pending changes have "
506 "finished computing.";
511 --
data->create_node_count;
525 BASE_LOG() <<
"This method should only be called while computing "
527 "before updates are made to the tree.";
530 std::optional<AXNode::AXID> parent_node_id =
532 if (parent_node_id) {
575 std::map<AXNode::AXID, std::unique_ptr<PendingStructureChanges>>
600 .emplace(std::make_pair(
601 node_id, std::make_unique<PendingStructureChanges>(node)))
604 return iter->second.get();
612AXTree::NodeSetSizePosInSetInfo::NodeSetSizePosInSetInfo() =
default;
613AXTree::NodeSetSizePosInSetInfo::~NodeSetSizePosInSetInfo() =
default;
659 if (!sets_list.empty()) {
661 ordered_set_content.
set_items_.push_back(item);
670 std::vector<OrderedSetContent>& sets_list =
items_map_.begin()->second;
671 if (sets_list.empty())
674 return &(sets_list.front());
681 std::map<std::optional<int32_t>, std::vector<OrderedSetContent>>
items_map_;
709 observers_.push_back(observer);
713 return std::find(observers_.begin(), observers_.end(), observer) !=
718 const auto it =
std::find(observers_.begin(), observers_.end(), observer);
719 if (it == observers_.end())
721 observers_.erase(it);
729 auto iter = id_map_.find(
id);
730 return iter != id_map_.end() ? iter->second :
nullptr;
734 table_info_map_.clear();
736 RecursivelyNotifyNodeDeletedForTreeTeardown(root_);
739 DestroyNodeAndSubtree(root_,
nullptr);
745 if (data_ == new_data)
751 observer->OnTreeDataChanged(
this, old_data, new_data);
758 bool allow_recursion)
const {
773 bool ignore_offscreen;
774 gfx::RectF child_bounds = RelativeToTreeBoundsInternal(
775 child,
gfx::RectF(), &ignore_offscreen, clip_bounds,
777 bounds.Union(child_bounds);
788 const AXNode* original_node = node;
789 while (node !=
nullptr) {
795 const AXNode* container =
797 if (!container && container !=
root())
799 if (!container || container == node)
802 gfx::RectF container_bounds = container->data().relative_bounds.bounds;
803 bounds.Offset(container_bounds.
x(), container_bounds.
y());
811 bounds.Offset(-scroll_x, -scroll_y);
816 intersection.
Intersect(container_bounds);
821 if (container->data().GetBoolAttribute(
825 clipped = intersection;
829 if (clipped.
x() >= container_bounds.
width()) {
832 }
else if (clipped.
x() + clipped.
width() <= 0) {
833 clipped.
set_x(container_bounds.
x());
836 if (clipped.
y() >= container_bounds.
height()) {
839 }
else if (clipped.
y() + clipped.
height() <= 0) {
840 clipped.
set_y(container_bounds.
y());
849 if (container->data().GetBoolAttribute(
859 if (offscreen !=
nullptr)
875 const AXNode* ancestor = original_node->
parent();
878 ancestor_bounds = ancestor->data().relative_bounds.bounds;
879 if (ancestor_bounds.
width() > 0 || ancestor_bounds.
height() > 0)
881 ancestor = ancestor->parent();
884 if (ancestor && allow_recursion) {
885 bool ignore_offscreen;
886 bool allow_recursion =
false;
887 ancestor_bounds = RelativeToTreeBoundsInternal(
888 ancestor,
gfx::RectF(), &ignore_offscreen, clip_bounds,
891 gfx::RectF original_bounds = original_node->data().relative_bounds.bounds;
892 if (original_bounds.
x() == 0 && original_bounds.
y() == 0) {
899 if (offscreen !=
nullptr)
910 bool clip_bounds)
const {
911 bool allow_recursion =
true;
912 return RelativeToTreeBoundsInternal(node,
bounds, offscreen, clip_bounds,
918 bool clip_bounds)
const {
923 int32_t dst_id)
const {
928 const auto& attr_relations = int_reverse_relations_.find(attr);
929 if (attr_relations != int_reverse_relations_.end()) {
930 const auto&
result = attr_relations->second.find(dst_id);
931 if (
result != attr_relations->second.end())
934 return std::set<int32_t>();
938 int32_t dst_id)
const {
943 const auto& attr_relations = intlist_reverse_relations_.find(attr);
944 if (attr_relations != intlist_reverse_relations_.end()) {
945 const auto&
result = attr_relations->second.find(dst_id);
946 if (
result != attr_relations->second.end())
949 return std::set<int32_t>();
956 const auto&
result = child_tree_id_reverse_map_.find(child_tree_id);
957 if (
result != child_tree_id_reverse_map_.end())
959 return std::set<int32_t>();
963 std::set<AXTreeID>
result;
964 for (
auto entry : child_tree_id_reverse_map_)
965 result.insert(entry.first);
976 if (!ComputePendingChanges(
update, &update_state))
983 const std::unique_ptr<PendingStructureChanges>&
data = pair.second;
984 if (
data->DoesNodeExpectSubtreeOrNodeWillBeDestroyed()) {
986 if (
data->DoesNodeExpectSubtreeWillBeDestroyed())
987 NotifySubtreeWillBeReparentedOrDeleted(node, &update_state);
988 if (
data->DoesNodeExpectNodeWillBeDestroyed())
989 NotifyNodeWillBeReparentedOrDeleted(node, &update_state);
999 std::set<int32_t> notified_node_data_will_change;
1000 for (
size_t i =
update.nodes.size();
i-- > 0;) {
1002 const bool is_new_root =
1006 if (node && notified_node_data_will_change.insert(new_data.
id).second)
1007 NotifyNodeDataWillChange(node->
data(), new_data);
1022 bool root_updated =
false;
1026 if (cleared_node == root_) {
1030 if (
update.root_id != old_root_id) {
1033 AXNode* old_root = root_;
1035 DestroySubtree(old_root, &update_state);
1039 root_updated =
true;
1046 for (
auto* child : cleared_node->
children())
1047 DestroySubtree(child, &update_state);
1048 std::vector<AXNode*> children;
1049 cleared_node->SwapChildren(&children);
1059 if (
update.has_tree_data && data_ !=
update.tree_data) {
1061 data_ =
update.tree_data;
1065 for (
size_t i = 0;
i <
update.nodes.size(); ++
i) {
1068 if (!UpdateNode(
update.nodes[
i], is_new_root, &update_state))
1073 error_ =
"Tree has no root.";
1077 if (!ValidatePendingChangesComplete(update_state))
1084 std::set<int32_t> table_ids_checked;
1085 for (
size_t i = 0;
i <
update.nodes.size(); ++
i) {
1088 if (table_ids_checked.find(node->
id()) != table_ids_checked.end())
1091 const auto& table_info_entry = table_info_map_.find(node->
id());
1092 if (table_info_entry != table_info_map_.end())
1093 table_info_entry->second->Invalidate();
1094 table_ids_checked.insert(node->
id());
1100 node_set_size_pos_in_set_info_map_.clear();
1102 std::vector<AXTreeObserver::Change> changes;
1103 changes.reserve(
update.nodes.size());
1104 std::set<AXNode::AXID> visited_observer_changes;
1105 for (
size_t i = 0;
i <
update.nodes.size(); ++
i) {
1107 if (!node || !visited_observer_changes.emplace(
update.nodes[
i].id).second)
1115 if (is_reparented_node) {
1120 bool is_subtree = !node->
parent() ||
1122 (node->
parent() == root_ && root_updated);
1130 bool is_subtree = !node->
parent() ||
1133 (node->
parent() == root_ && root_updated);
1144 std::set<AXNode::AXID> updated_unignored_cached_values_ids;
1150 if (node && updated_unignored_cached_values_ids.insert(node->
id()).second)
1162 observer->OnTreeDataChanged(
this, *update_state.
old_tree_data, data_);
1169 NotifyNodeHasBeenDeleted(node_id);
1175 NotifyNodeHasBeenReparentedOrCreated(
GetFromId(node_id), &update_state);
1186 node_data_changed_id ==
update.root_id;
1190 const AXNodeData& old_node_data = it->second;
1191 NotifyNodeDataHasBeenChanged(node, old_node_data, node->
data());
1197 observer->OnNodeChanged(
this, node);
1201 observer->OnAtomicUpdateFinished(
this, root_->
id() != old_root_id, changes);
1212 AXNode* table_node =
const_cast<AXNode*
>(const_table_node);
1216 const auto& cached = table_info_map_.find(table_node->
id());
1217 if (cached != table_info_map_.end()) {
1221 if (!table_info->
valid()) {
1222 if (!table_info->
Update()) {
1225 table_info_map_.erase(table_node->
id());
1236 table_info_map_[table_node->
id()] = std::unique_ptr<AXTableInfo>(table_info);
1241 return "AXTree" + data_.
ToString() +
"\n" + TreeToStringHelper(root_, 0);
1246 size_t index_in_parent,
1261 AXNode* new_node =
new AXNode(
this, parent,
id, index_in_parent,
1262 parent ? 0 : index_in_parent);
1263 id_map_[new_node->
id()] = new_node;
1268 AXTreeUpdateState* update_state) {
1270 update_state->pending_update_status) {
1271 BASE_LOG() <<
"Pending changes have already started being computed.";
1274 update_state->pending_update_status =
1278 &update_state->pending_root_id,
1279 root_ ? std::optional<AXNode::AXID>{root_->id()} : std::nullopt);
1289 if (cleared_node == root_ &&
1290 update.root_id != update_state->pending_root_id) {
1294 MarkSubtreeForDestruction(*update_state->pending_root_id, update_state);
1299 if (update_state->ShouldPendingNodeExistInTree(root_->
id())) {
1300 update_state->invalidate_unignored_cached_values_ids.insert(
1301 cleared_node->id());
1302 update_state->ClearLastKnownPendingNodeData(cleared_node->id());
1303 for (AXNode* child : cleared_node->children()) {
1304 MarkSubtreeForDestruction(child->
id(), update_state);
1310 update_state->root_will_be_created =
1312 !update_state->ShouldPendingNodeExistInTree(
update.root_id);
1316 for (
const AXNodeData& new_data :
update.nodes) {
1318 update_state->root_will_be_created && new_data.
id ==
update.root_id;
1319 if (!ComputePendingChangesToNode(new_data, is_new_root, update_state)) {
1320 update_state->pending_update_status =
1330bool AXTree::ComputePendingChangesToNode(
const AXNodeData& new_data,
1332 AXTreeUpdateState* update_state) {
1336 for (
size_t j = 0; j < new_data.child_ids.size(); j++) {
1337 AXNode* node =
GetFromId(new_data.child_ids[j]);
1338 if (node && node->GetIndexInParent() != j)
1339 update_state->InvalidateParentNodeUnignoredCacheValues(node->id());
1344 if (!update_state->ShouldPendingNodeExistInTree(new_data.id)) {
1347 "%d will not be in the tree and is not the new root", new_data.id);
1353 if (!update_state->IncrementPendingCreateNodeCount(new_data.id,
1356 "Node %d is already pending for creation, cannot be the new root",
1360 if (update_state->pending_root_id) {
1361 MarkSubtreeForDestruction(*update_state->pending_root_id, update_state);
1363 update_state->pending_root_id = new_data.id;
1368 std::set<AXNode::AXID> new_child_id_set;
1372 new_data.id, new_child_id);
1375 new_child_id_set.insert(new_child_id);
1381 if (update_state->DoesPendingNodeRequireInit(new_data.id)) {
1382 update_state->invalidate_unignored_cached_values_ids.insert(new_data.id);
1386 update_state->InvalidateParentNodeUnignoredCacheValues(new_data.id);
1391 update_state->invalidate_unignored_cached_values_ids.insert(child_id);
1392 if (!update_state->IncrementPendingCreateNodeCount(child_id,
1395 "Node %d is already pending for creation, cannot be a new child",
1401 update_state->SetLastKnownPendingNodeData(&new_data);
1405 const AXNodeData& old_data =
1406 update_state->GetLastKnownPendingNodeData(new_data.id);
1410 std::set<AXNode::AXID> old_child_id_set(old_data.child_ids.cbegin(),
1411 old_data.child_ids.cend());
1413 std::vector<AXNode::AXID> create_or_destroy_ids;
1414 std::set_symmetric_difference(
1415 old_child_id_set.cbegin(), old_child_id_set.cend(),
1416 new_child_id_set.cbegin(), new_child_id_set.cend(),
1417 std::back_inserter(create_or_destroy_ids));
1421 const bool ignored_changed = old_data.IsIgnored() != new_data.IsIgnored();
1422 if (!create_or_destroy_ids.empty() || ignored_changed) {
1423 update_state->invalidate_unignored_cached_values_ids.insert(new_data.id);
1426 update_state->InvalidateParentNodeUnignoredCacheValues(new_data.id);
1435 if (update_state->ShouldPendingNodeExistInTree(child_id)) {
1437 "Node %d is not marked for destruction, would be reparented to %d",
1438 child_id, new_data.id);
1444 update_state->invalidate_unignored_cached_values_ids.insert(child_id);
1445 if (!update_state->IncrementPendingCreateNodeCount(child_id,
1448 "Node %d is already pending for creation, cannot be a new child",
1455 MarkSubtreeForDestruction(child_id, update_state);
1459 update_state->SetLastKnownPendingNodeData(&new_data);
1463bool AXTree::UpdateNode(
const AXNodeData&
src,
1465 AXTreeUpdateState* update_state) {
1476 update_state->pending_nodes.erase(node->id());
1477 UpdateReverseRelations(node,
src);
1478 if (!update_state->IsCreatedNode(node) ||
1479 update_state->IsReparentedNode(node)) {
1480 update_state->old_node_id_to_data.insert(
1481 std::make_pair(node->id(), node->TakeData()));
1491 node = CreateNode(
nullptr,
src.id, 0, update_state);
1492 UpdateReverseRelations(node,
src);
1498 has_pagination_support_ =
true;
1500 update_state->node_data_changed_ids.insert(node->id());
1504 DeleteOldChildren(node,
src.child_ids, update_state);
1508 std::vector<AXNode*> new_children;
1510 CreateNewChildVector(node,
src.child_ids, &new_children, update_state);
1511 node->SwapChildren(&new_children);
1517 AXNode* old_root = root_;
1519 if (old_root && old_root != node)
1520 DestroySubtree(old_root, update_state);
1526void AXTree::NotifySubtreeWillBeReparentedOrDeleted(
1528 const AXTreeUpdateState* update_state) {
1533 for (AXTreeObserver* observer : observers_) {
1534 if (update_state->IsReparentedNode(node)) {
1535 observer->OnSubtreeWillBeReparented(
this, node);
1537 observer->OnSubtreeWillBeDeleted(
this, node);
1542void AXTree::NotifyNodeWillBeReparentedOrDeleted(
1544 const AXTreeUpdateState* update_state) {
1551 table_info_map_.erase(
id);
1553 for (AXTreeObserver* observer : observers_) {
1554 if (update_state->IsReparentedNode(node)) {
1555 observer->OnNodeWillBeReparented(
this, node);
1557 observer->OnNodeWillBeDeleted(
this, node);
1561 if (table_info_map_.find(
id) != table_info_map_.end()) {
1562 BASE_LOG() <<
"Table info should never be recreated during node deletion";
1567void AXTree::RecursivelyNotifyNodeDeletedForTreeTeardown(AXNode* node) {
1572 for (AXTreeObserver* observer : observers_)
1573 observer->OnNodeDeleted(
this, node->id());
1574 for (
auto* child : node->children())
1575 RecursivelyNotifyNodeDeletedForTreeTeardown(child);
1578void AXTree::NotifyNodeHasBeenDeleted(
AXNode::AXID node_id) {
1584 for (AXTreeObserver* observer : observers_)
1585 observer->OnNodeDeleted(
this, node_id);
1588void AXTree::NotifyNodeHasBeenReparentedOrCreated(
1590 const AXTreeUpdateState* update_state) {
1595 for (AXTreeObserver* observer : observers_) {
1596 if (update_state->IsReparentedNode(node)) {
1597 observer->OnNodeReparented(
this, node);
1599 observer->OnNodeCreated(
this, node);
1604void AXTree::NotifyNodeDataWillChange(
const AXNodeData& old_data,
1605 const AXNodeData& new_data) {
1610 for (AXTreeObserver* observer : observers_)
1611 observer->OnNodeDataWillChange(
this, old_data, new_data);
1614void AXTree::NotifyNodeDataHasBeenChanged(AXNode* node,
1615 const AXNodeData& old_data,
1616 const AXNodeData& new_data) {
1621 for (AXTreeObserver* observer : observers_)
1622 observer->OnNodeDataChanged(
this, old_data, new_data);
1624 if (old_data.role != new_data.role) {
1625 for (AXTreeObserver* observer : observers_)
1626 observer->OnRoleChanged(
this, node, old_data.role, new_data.role);
1629 if (old_data.state != new_data.state) {
1633 if (old_data.HasState(
state) != new_data.HasState(
state)) {
1634 for (AXTreeObserver* observer : observers_)
1635 observer->OnStateChanged(
this, node,
state, new_data.HasState(
state));
1641 const std::string& old_string,
1642 const std::string& new_string) {
1643 for (AXTreeObserver* observer : observers_) {
1644 observer->OnStringAttributeChanged(
this, node, attr, old_string,
1648 CallIfAttributeValuesChanged(old_data.string_attributes,
1649 new_data.string_attributes, std::string(),
1653 const bool& old_bool,
1654 const bool& new_bool) {
1655 for (AXTreeObserver* observer : observers_)
1656 observer->OnBoolAttributeChanged(
this, node, attr, new_bool);
1658 CallIfAttributeValuesChanged(old_data.bool_attributes,
1659 new_data.bool_attributes,
false, bool_callback);
1662 const float& old_float,
1663 const float& new_float) {
1664 for (AXTreeObserver* observer : observers_)
1665 observer->OnFloatAttributeChanged(
this, node, attr, old_float, new_float);
1667 CallIfAttributeValuesChanged(old_data.float_attributes,
1668 new_data.float_attributes, 0.0f, float_callback);
1671 const int& old_int,
const int& new_int) {
1672 for (AXTreeObserver* observer : observers_)
1673 observer->OnIntAttributeChanged(
this, node, attr, old_int, new_int);
1675 CallIfAttributeValuesChanged(old_data.int_attributes, new_data.int_attributes,
1678 auto intlist_callback = [
this, node](
1680 const std::vector<int32_t>& old_intlist,
1681 const std::vector<int32_t>& new_intlist) {
1682 for (AXTreeObserver* observer : observers_)
1683 observer->OnIntListAttributeChanged(
this, node, attr, old_intlist,
1686 CallIfAttributeValuesChanged(old_data.intlist_attributes,
1687 new_data.intlist_attributes,
1688 std::vector<int32_t>(), intlist_callback);
1690 auto stringlist_callback =
1692 const std::vector<std::string>& old_stringlist,
1693 const std::vector<std::string>& new_stringlist) {
1694 for (AXTreeObserver* observer : observers_)
1695 observer->OnStringListAttributeChanged(
1696 this, node, attr, old_stringlist, new_stringlist);
1698 CallIfAttributeValuesChanged(old_data.stringlist_attributes,
1699 new_data.stringlist_attributes,
1700 std::vector<std::string>(), stringlist_callback);
1703void AXTree::UpdateReverseRelations(AXNode* node,
const AXNodeData& new_data) {
1705 const AXNodeData& old_data = node->data();
1706 int id = new_data.id;
1708 const int& old_id,
const int& new_id) {
1714 auto&
map = int_reverse_relations_[attr];
1715 if (
map.find(old_id) !=
map.end()) {
1716 map[old_id].erase(
id);
1724 map[new_id].insert(
id);
1726 CallIfAttributeValuesChanged(old_data.int_attributes, new_data.int_attributes,
1730 const std::vector<int32_t>& old_idlist,
1731 const std::vector<int32_t>& new_idlist) {
1735 auto&
map = intlist_reverse_relations_[attr];
1736 for (int32_t old_id : old_idlist) {
1737 if (
map.find(old_id) !=
map.end()) {
1738 map[old_id].erase(
id);
1743 for (int32_t new_id : new_idlist)
1744 intlist_reverse_relations_[attr][new_id].insert(
id);
1746 CallIfAttributeValuesChanged(old_data.intlist_attributes,
1747 new_data.intlist_attributes,
1748 std::vector<int32_t>(), intlist_callback);
1751 const std::string& old_string,
1752 const std::string& new_string) {
1757 if (child_tree_id_reverse_map_.find(old_ax_tree_id) !=
1758 child_tree_id_reverse_map_.end()) {
1759 child_tree_id_reverse_map_[old_ax_tree_id].erase(
id);
1760 if (child_tree_id_reverse_map_[old_ax_tree_id].
empty())
1761 child_tree_id_reverse_map_.erase(old_ax_tree_id);
1766 if (!new_string.empty()) {
1768 child_tree_id_reverse_map_[new_ax_tree_id].insert(
id);
1773 CallIfAttributeValuesChanged(old_data.string_attributes,
1774 new_data.string_attributes, std::string(),
1778bool AXTree::ValidatePendingChangesComplete(
1779 const AXTreeUpdateState& update_state) {
1780 if (!update_state.pending_nodes.empty()) {
1781 error_ =
"Nodes left pending by the update:";
1782 for (
const AXNode::AXID pending_id : update_state.pending_nodes) {
1788 if (!update_state.node_id_to_pending_data.empty()) {
1789 std::string destroy_subtree_ids;
1790 std::string destroy_node_ids;
1791 std::string create_node_ids;
1793 bool has_pending_changes =
false;
1794 for (
auto&& pair : update_state.node_id_to_pending_data) {
1796 const std::unique_ptr<PendingStructureChanges>&
data = pair.second;
1797 if (
data->DoesNodeExpectAnyStructureChanges()) {
1798 if (
data->DoesNodeExpectSubtreeWillBeDestroyed())
1800 if (
data->DoesNodeExpectNodeWillBeDestroyed())
1802 if (
data->DoesNodeExpectNodeWillBeCreated())
1804 has_pending_changes =
true;
1807 if (has_pending_changes) {
1808 std::ostringstream stringStream;
1809 stringStream <<
"Changes left pending by the update; destroy subtrees: "
1810 << destroy_subtree_ids.c_str()
1811 <<
", destroy nodes: " << destroy_node_ids.c_str()
1812 <<
", create nodes: " << create_node_ids.c_str();
1813 error_ = stringStream.str();
1815 return !has_pending_changes;
1821void AXTree::MarkSubtreeForDestruction(
AXNode::AXID node_id,
1822 AXTreeUpdateState* update_state) {
1823 update_state->IncrementPendingDestroySubtreeCount(node_id);
1824 MarkNodesForDestructionRecursive(node_id, update_state);
1827void AXTree::MarkNodesForDestructionRecursive(
AXNode::AXID node_id,
1828 AXTreeUpdateState* update_state) {
1831 if (!update_state->ShouldPendingNodeExistInTree(node_id))
1834 const AXNodeData& last_known_data =
1835 update_state->GetLastKnownPendingNodeData(node_id);
1837 update_state->IncrementPendingDestroyNodeCount(node_id);
1838 for (
AXNode::AXID child_id : last_known_data.child_ids) {
1839 MarkNodesForDestructionRecursive(child_id, update_state);
1843void AXTree::DestroySubtree(AXNode* node, AXTreeUpdateState* update_state) {
1849 BASE_DCHECK(update_state->GetPendingDestroySubtreeCount(node->id()) > 0);
1850 BASE_DCHECK(!node->parent() || update_state->InvalidatesUnignoredCachedValues(
1851 node->parent()->id()));
1852 update_state->DecrementPendingDestroySubtreeCount(node->id());
1853 DestroyNodeAndSubtree(node, update_state);
1856void AXTree::DestroyNodeAndSubtree(AXNode* node,
1857 AXTreeUpdateState* update_state) {
1860 update_state->GetPendingDestroyNodeCount(node->id()) > 0);
1863 AXNodeData empty_data;
1864 empty_data.id = node->id();
1865 UpdateReverseRelations(node, empty_data);
1867 id_map_.erase(node->id());
1868 for (
auto* child : node->children())
1869 DestroyNodeAndSubtree(child, update_state);
1871 update_state->pending_nodes.erase(node->id());
1872 update_state->DecrementPendingDestroyNodeCount(node->id());
1873 update_state->removed_node_ids.insert(node->id());
1874 update_state->new_node_ids.erase(node->id());
1875 update_state->node_data_changed_ids.erase(node->id());
1876 if (update_state->IsReparentedNode(node)) {
1877 update_state->old_node_id_to_data.emplace(
1878 std::make_pair(node->id(), node->TakeData()));
1884void AXTree::DeleteOldChildren(AXNode* node,
1885 const std::vector<int32_t>& new_child_ids,
1886 AXTreeUpdateState* update_state) {
1892 std::set<int32_t> new_child_id_set(new_child_ids.begin(),
1893 new_child_ids.end());
1896 for (AXNode* child : node->children()) {
1898 DestroySubtree(child, update_state);
1902bool AXTree::CreateNewChildVector(AXNode* node,
1903 const std::vector<int32_t>& new_child_ids,
1904 std::vector<AXNode*>* new_children,
1905 AXTreeUpdateState* update_state) {
1907 bool success =
true;
1908 for (
size_t i = 0;
i < new_child_ids.size(); ++
i) {
1909 int32_t child_id = new_child_ids[
i];
1912 if (child->parent() != node) {
1917 "Node %d reparented from %d to %d", child->id(),
1918 child->parent() ? child->parent()->id() : 0, node->id());
1922 child->SetIndexInParent(
i);
1924 child = CreateNode(node, child_id,
i, update_state);
1925 update_state->pending_nodes.insert(child->id());
1927 new_children->push_back(child);
1934 if (enable_extra_mac_nodes_ == enabled)
1936 if (enable_extra_mac_nodes_ && !enabled) {
1938 <<
"We don't support disabling the extra Mac nodes once enabled.";
1944 enable_extra_mac_nodes_ = enabled;
1948 int32_t return_value = next_negative_internal_node_id_;
1949 next_negative_internal_node_id_--;
1950 if (next_negative_internal_node_id_ > 0)
1951 next_negative_internal_node_id_ = -1;
1952 return return_value;
1955void AXTree::PopulateOrderedSetItemsMap(
1956 const AXNode& original_node,
1957 const AXNode* ordered_set,
1958 OrderedSetItemsMap* items_map_to_be_populated)
const {
1969 std::optional<int> ordered_set_min_level =
1975 std::optional<int> child_level = child->GetHierarchicalLevel();
1977 ordered_set_min_level = ordered_set_min_level
1978 ?
std::min(child_level, ordered_set_min_level)
1983 RecursivelyPopulateOrderedSetItemsMap(original_node, ordered_set, ordered_set,
1984 ordered_set_min_level, std::nullopt,
1985 items_map_to_be_populated);
1994 if (&original_node == ordered_set &&
1995 !items_map_to_be_populated->HierarchicalLevelExists(
1996 ordered_set_min_level)) {
1997 items_map_to_be_populated->Add(ordered_set_min_level,
1998 OrderedSetContent(&original_node));
2002void AXTree::RecursivelyPopulateOrderedSetItemsMap(
2003 const AXNode& original_node,
2004 const AXNode* ordered_set,
2005 const AXNode* local_parent,
2006 std::optional<int> ordered_set_min_level,
2007 std::optional<int> prev_level,
2008 OrderedSetItemsMap* items_map_to_be_populated)
const {
2022 if (ordered_set->data().role == local_parent->data().role &&
2023 ordered_set != local_parent)
2027 local_parent->UnignoredChildrenBegin();
2028 itr != local_parent->UnignoredChildrenEnd(); ++itr) {
2029 const AXNode* child = itr.get();
2038 !IsCollapsed(local_parent) && !IsCollapsed(local_parent->parent())) {
2042 std::optional<int> curr_level = child->GetHierarchicalLevel();
2051 child->SetRoleMatchesItemRole(ordered_set))) {
2060 if (!curr_level && child->GetUnignoredParent() == ordered_set)
2061 curr_level = ordered_set_min_level;
2065 if (!items_map_to_be_populated->HierarchicalLevelExists(curr_level)) {
2066 bool use_ordered_set = child->SetRoleMatchesItemRole(ordered_set) &&
2067 ordered_set_min_level == curr_level;
2068 const AXNode* child_ordered_set =
2069 use_ordered_set ? ordered_set :
nullptr;
2070 items_map_to_be_populated->Add(curr_level,
2071 OrderedSetContent(child_ordered_set));
2074 items_map_to_be_populated->AddItemToBack(curr_level, child);
2080 if (child->IsIgnoredContainerForOrderedSet()) {
2081 RecursivelyPopulateOrderedSetItemsMap(original_node, ordered_set, child,
2082 ordered_set_min_level, curr_level,
2083 items_map_to_be_populated);
2107 if (child->SetRoleMatchesItemRole(ordered_set) && curr_level < prev_level)
2108 items_map_to_be_populated->Add(prev_level, OrderedSetContent());
2110 prev_level = curr_level;
2117void AXTree::ComputeSetSizePosInSetAndCache(
const AXNode& node,
2118 const AXNode* ordered_set) {
2125 !node.SetRoleMatchesItemRole(ordered_set) && !
IsSetLike(node.data().role))
2129 OrderedSetItemsMap items_map_to_be_populated;
2130 PopulateOrderedSetItemsMap(node, ordered_set, &items_map_to_be_populated);
2137 node.GetUnignoredChildCount() > 0) {
2142 OrderedSetContent* set_content =
2143 items_map_to_be_populated.GetFirstOrderedSetContent();
2144 if (set_content && set_content->set_items_.size() == 1) {
2145 const AXNode* menu_list_popup = set_content->set_items_.front();
2147 items_map_to_be_populated.Clear();
2148 PopulateOrderedSetItemsMap(node, menu_list_popup,
2149 &items_map_to_be_populated);
2150 set_content = items_map_to_be_populated.GetFirstOrderedSetContent();
2155 set_content->ordered_set_ = &node;
2163 for (
auto element : items_map_to_be_populated.items_map_) {
2164 for (
const OrderedSetContent& ordered_set_content : element.second) {
2165 ComputeSetSizePosInSetAndCacheHelper(ordered_set_content);
2170void AXTree::ComputeSetSizePosInSetAndCacheHelper(
2171 const OrderedSetContent& ordered_set_content) {
2173 int32_t num_elements = 0;
2175 int32_t max_item_set_size_from_attribute = 0;
2177 for (
const AXNode* item : ordered_set_content.set_items_) {
2180 int32_t pos_in_set_value =
2188 if (item->GetHierarchicalLevel() &&
2193 num_elements = pos_in_set_value;
2196 node_set_size_pos_in_set_info_map_[item->id()] = NodeSetSizePosInSetInfo();
2197 node_set_size_pos_in_set_info_map_[item->id()].pos_in_set =
2201 max_item_set_size_from_attribute =
2202 std::max(max_item_set_size_from_attribute,
2211 int32_t set_size_value =
2212 std::max(num_elements, max_item_set_size_from_attribute);
2216 if (
const AXNode* ordered_set = ordered_set_content.ordered_set_) {
2222 std::optional<int> ordered_set_level = ordered_set->GetHierarchicalLevel();
2223 if (node_set_size_pos_in_set_info_map_.find(ordered_set->id()) ==
2224 node_set_size_pos_in_set_info_map_.end()) {
2225 node_set_size_pos_in_set_info_map_[ordered_set->id()] =
2226 NodeSetSizePosInSetInfo();
2227 node_set_size_pos_in_set_info_map_[ordered_set->id()]
2228 .lowest_hierarchical_level = ordered_set_level;
2229 }
else if (node_set_size_pos_in_set_info_map_[ordered_set->id()]
2230 .lowest_hierarchical_level > ordered_set_level) {
2231 node_set_size_pos_in_set_info_map_[ordered_set->id()]
2232 .lowest_hierarchical_level = ordered_set_level;
2235 node_set_size_pos_in_set_info_map_[ordered_set->id()].set_size =
2240 for (
const AXNode* item : ordered_set_content.set_items_) {
2243 if (item->GetHierarchicalLevel() &&
2245 node_set_size_pos_in_set_info_map_[item->id()].set_size =
2248 node_set_size_pos_in_set_info_map_[item->id()].set_size = set_size_value;
2259 if (node_set_size_pos_in_set_info_map_.find(node.
id()) !=
2260 node_set_size_pos_in_set_info_map_.end()) {
2262 return node_set_size_pos_in_set_info_map_[node.
id()].pos_in_set;
2266 return std::nullopt;
2271 return std::nullopt;
2275 return std::nullopt;
2278 ComputeSetSizePosInSetAndCache(node, ordered_set);
2279 std::optional<int> pos_in_set =
2280 node_set_size_pos_in_set_info_map_[node.
id()].pos_in_set;
2281 if (pos_in_set.has_value() && pos_in_set.value() < 1)
2282 return std::nullopt;
2294 if (node_set_size_pos_in_set_info_map_.find(node.
id()) !=
2295 node_set_size_pos_in_set_info_map_.end()) {
2297 return node_set_size_pos_in_set_info_map_[node.
id()].set_size;
2301 return std::nullopt;
2308 return std::nullopt;
2313 const AXNode* ordered_set = &node;
2317 return std::nullopt;
2324 if (controls_ids.size() == 1 &&
GetFromId(controls_ids[0]) &&
2325 controls_ids[0] != node.
id()) {
2328 std::optional<int> controlled_item_set_size =
GetSetSize(controlled_item);
2329 node_set_size_pos_in_set_info_map_[node.
id()].set_size =
2330 controlled_item_set_size;
2331 return controlled_item_set_size;
2336 ComputeSetSizePosInSetAndCache(node, ordered_set);
2337 std::optional<int> set_size =
2338 node_set_size_pos_in_set_info_map_[node.
id()].set_size;
2339 if (set_size.has_value() && set_size.value() < 0)
2340 return std::nullopt;
2356 data().sel_anchor_offset,
2357 data().sel_anchor_affinity)
2361 if (anchor_position->IsIgnored()) {
2362 anchor_position = anchor_position->AsUnignoredPosition(
2368 if (anchor_position->IsLeafTreePosition())
2369 anchor_position = anchor_position->AsTextPosition();
2374 if (anchor_position->IsTextPosition() &&
2375 anchor_position->GetAnchor()->data().role ==
2377 anchor_position = anchor_position->CreateParentPosition();
2380 switch (anchor_position->kind()) {
2392 return unignored_selection;
2395 unignored_selection.
anchor_offset = anchor_position->child_index();
2401 unignored_selection.
anchor_offset = anchor_position->text_offset();
2410 data().sel_focus_affinity)
2414 if (focus_position->IsIgnored()) {
2415 focus_position = focus_position->AsUnignoredPosition(
2421 if (focus_position->IsLeafTreePosition())
2422 focus_position = focus_position->AsTextPosition();
2427 if (focus_position->IsTextPosition() &&
2428 focus_position->GetAnchor()->data().role ==
2430 focus_position = focus_position->CreateParentPosition();
2433 switch (focus_position->kind()) {
2445 return unignored_selection;
2448 unignored_selection.
focus_offset = focus_position->child_index();
2454 unignored_selection.
focus_offset = focus_position->text_offset();
2460 return unignored_selection;
2464 return tree_update_in_progress_;
2468 tree_update_in_progress_ = set_tree_update_value;
2472 return has_pagination_support_;
int find(T *array, int N, T item)
constexpr float y() const
constexpr float width() const
constexpr float height() const
void Intersect(const RectF &rect)
constexpr float right() const
void set_width(float width)
constexpr float bottom() const
void set_height(float height)
constexpr float x() const
static AXPositionInstance CreatePosition(const AXNode &node, int child_index_or_text_offset, ax::mojom::TextAffinity affinity=ax::mojom::TextAffinity::kDownstream)
void UpdateUnignoredCachedValues()
size_t GetUnignoredChildCount() const
ChildIteratorBase< AXNode, &AXNode::GetNextUnignoredSibling, &AXNode::GetPreviousUnignoredSibling, &AXNode::GetFirstUnignoredChild, &AXNode::GetLastUnignoredChild > UnignoredChildIterator
UnignoredChildIterator UnignoredChildrenEnd() const
bool IsOrderedSetItem() const
bool IsEmbeddedGroup() const
bool HasIntAttribute(ax::mojom::IntAttribute attribute) const
static constexpr AXID kInvalidAXID
const std::vector< AXNode * > & children() const
std::optional< int > GetHierarchicalLevel() const
UnignoredChildIterator UnignoredChildrenBegin() const
int GetIntAttribute(ax::mojom::IntAttribute attribute) const
bool IsOrderedSet() const
AXNode * GetOrderedSet() const
const AXNodeData & data() const
std::unique_ptr< AXPosition< AXNodePosition, AXNode > > AXPositionInstance
static AXPositionInstance CreateNullPosition()
static AXTableInfo * Create(AXTree *tree, AXNode *table_node)
static AXTreeID FromString(const std::string &string)
void SetTreeUpdateInProgressState(bool set_tree_update_value)
std::string ToString() const
gfx::RectF GetTreeBounds(const AXNode *node, bool *offscreen=nullptr, bool clip_bounds=true) const
AXTreeID GetAXTreeID() const override
const std::string & error() const
const AXTreeData & data() const
virtual bool Unserialize(const AXTreeUpdate &update)
bool GetTreeUpdateInProgressState() const override
std::set< int32_t > GetReverseRelations(ax::mojom::IntAttribute attr, int32_t dst_id) const
AXNode * GetFromId(int32_t id) const override
std::optional< int > GetSetSize(const AXNode &node) override
void AddObserver(AXTreeObserver *observer)
void RemoveObserver(AXTreeObserver *observer)
bool HasPaginationSupport() const override
std::optional< int > GetPosInSet(const AXNode &node) override
const std::set< AXTreeID > GetAllChildTreeIds() const
gfx::RectF RelativeToTreeBounds(const AXNode *node, gfx::RectF node_bounds, bool *offscreen=nullptr, bool clip_bounds=true) const
int32_t GetNextNegativeInternalNodeId()
Selection GetUnignoredSelection() const override
void SetEnableExtraMacNodes(bool enabled)
virtual void UpdateData(const AXTreeData &data)
std::set< int32_t > GetNodeIdsForChildTreeId(AXTreeID child_tree_id) const
bool HasObserver(AXTreeObserver *observer)
EMSCRIPTEN_KEEPALIVE void empty()
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
static float max(float r, float g, float b)
static float min(float r, float g, float b)
T __attribute__((ext_vector_type(N))) V
Optional< SkRect > bounds
std::string StringPrintf(const std::string &format, Args... args)
bool Contains(const Container &container, const Value &value)
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
AXTreeUpdateBase< AXNodeData, AXTreeData > AXTreeUpdate
bool IsNodeIdIntAttribute(ax::mojom::IntAttribute attr)
AXTreePendingStructureStatus
bool IsItemLike(const ax::mojom::Role role)
bool IsNodeIdIntListAttribute(ax::mojom::IntListAttribute attr)
bool IsSetLike(const ax::mojom::Role role)
AXRelativeBounds relative_bounds
const std::vector< int32_t > & GetIntListAttribute(ax::mojom::IntListAttribute attribute) const
ax::mojom::TextAffinity focus_affinity
ax::mojom::TextAffinity anchor_affinity
std::unique_ptr< gfx::Transform > transform
int32_t offset_container_id
virtual std::string ToString() const
AXNode::AXID sel_anchor_object_id
ax::mojom::TextAffinity sel_focus_affinity
AXNode::AXID sel_focus_object_id
ax::mojom::TextAffinity sel_anchor_affinity
int32_t sel_anchor_offset
std::vector< AXNodeData > nodes
AXTreePendingStructureStatus pending_update_status
void SetLastKnownPendingNodeData(const AXNodeData *node_data)
bool InvalidatesUnignoredCachedValues(AXNode::AXID node_id)
bool DoesPendingNodeRequireInit(AXNode::AXID node_id) const
bool IsCreatedNode(AXNode::AXID node_id) const
std::optional< AXNode::AXID > GetParentIdForPendingNode(AXNode::AXID node_id)
std::map< AXNode::AXID, std::unique_ptr< PendingStructureChanges > > node_id_to_pending_data
std::optional< AXTreeData > old_tree_data
int32_t GetPendingDestroySubtreeCount(AXNode::AXID node_id) const
const AXNodeData & GetLastKnownPendingNodeData(AXNode::AXID node_id) const
bool IsCreatedNode(const AXNode *node) const
std::set< AXNode::AXID > new_node_ids
AXTreeUpdateState(const AXTree &tree)
void InvalidateParentNodeUnignoredCacheValues(AXNode::AXID node_id)
bool IncrementPendingDestroyNodeCount(AXNode::AXID node_id)
bool ShouldPendingNodeExistInTree(AXNode::AXID node_id)
void DecrementPendingDestroyNodeCount(AXNode::AXID node_id)
void ClearLastKnownPendingNodeData(AXNode::AXID node_id)
void DecrementPendingDestroySubtreeCount(AXNode::AXID node_id)
bool IsReparentedNode(const AXNode *node) const
std::optional< AXNode::AXID > pending_root_id
bool IncrementPendingDestroySubtreeCount(AXNode::AXID node_id)
std::set< AXNode::AXID > node_data_changed_ids
std::set< AXNode::AXID > invalidate_unignored_cached_values_ids
bool root_will_be_created
std::map< AXNode::AXID, AXNodeData > old_node_id_to_data
int32_t GetPendingCreateNodeCount(AXNode::AXID node_id) const
std::set< AXNode::AXID > removed_node_ids
void DecrementPendingCreateNodeCount(AXNode::AXID node_id)
std::set< AXNode::AXID > pending_nodes
bool IncrementPendingCreateNodeCount(AXNode::AXID node_id, std::optional< AXNode::AXID > parent_node_id)
bool IsRemovedNode(const AXNode *node) const
int32_t GetPendingDestroyNodeCount(AXNode::AXID node_id) const
std::vector< const AXNode * > set_items_
const AXNode * ordered_set_
OrderedSetContent(const AXNode *ordered_set=nullptr)
~OrderedSetContent()=default
std::map< std::optional< int32_t >, std::vector< OrderedSetContent > > items_map_
void AddItemToBack(std::optional< int > level, const AXNode *item)
~OrderedSetItemsMap()=default
void Add(std::optional< int > level, const OrderedSetContent &ordered_set_content)
bool HierarchicalLevelExists(std::optional< int > level)
OrderedSetItemsMap()=default
OrderedSetContent * GetFirstOrderedSetContent()
bool DoesNodeExpectSubtreeOrNodeWillBeDestroyed() const
bool DoesNodeExpectSubtreeWillBeDestroyed() const
PendingStructureChanges(const AXNode *node)
std::optional< AXNode::AXID > parent_node_id
bool DoesNodeExpectNodeWillBeDestroyed() const
int32_t create_node_count
bool DoesNodeRequireInit() const
int32_t destroy_node_count
int32_t destroy_subtree_count
const AXNodeData * last_known_data
bool DoesNodeExpectAnyStructureChanges() const
bool DoesNodeExpectNodeWillBeCreated() const
std::shared_ptr< const fml::Mapping > data
#define BASE_DCHECK(condition)
#define BASE_UNREACHABLE()