123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- // Copyright 2016 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ui/accessibility/ax_tree_combiner.h"
- #include "ui/accessibility/ax_enums.mojom.h"
- #include "ui/accessibility/ax_tree.h"
- #include "ui/gfx/geometry/rect_f.h"
- namespace ui {
- AXTreeCombiner::AXTreeCombiner() {
- }
- AXTreeCombiner::~AXTreeCombiner() {
- }
- void AXTreeCombiner::AddTree(const AXTreeUpdate& tree, bool is_root) {
- if (tree.tree_data.tree_id == AXTreeIDUnknown()) {
- LOG(WARNING) << "Skipping AXTreeID because its tree ID is unknown";
- return;
- }
- trees_.push_back(tree);
- if (is_root) {
- DCHECK_EQ(root_tree_id_, AXTreeIDUnknown());
- root_tree_id_ = tree.tree_data.tree_id;
- }
- }
- bool AXTreeCombiner::Combine() {
- // First create a map from tree ID to tree update.
- for (const auto& tree : trees_) {
- AXTreeID tree_id = tree.tree_data.tree_id;
- if (tree_id_map_.find(tree_id) != tree_id_map_.end())
- return false;
- tree_id_map_[tree.tree_data.tree_id] = &tree;
- }
- // Make sure the root tree ID is in the map, otherwise fail.
- if (tree_id_map_.find(root_tree_id_) == tree_id_map_.end())
- return false;
- // Process the nodes recursively, starting with the root tree.
- const AXTreeUpdate* root = tree_id_map_.find(root_tree_id_)->second;
- ProcessTree(root);
- // Set the root id.
- combined_.root_id = combined_.nodes.size() > 0 ? combined_.nodes[0].id : 0;
- // Finally, handle the tree ID, taking into account which subtree might
- // have focus and mapping IDs from the tree data appropriately.
- combined_.has_tree_data = true;
- combined_.tree_data = root->tree_data;
- AXTreeID focused_tree_id = root->tree_data.focused_tree_id;
- const AXTreeUpdate* focused_tree = root;
- if (tree_id_map_.find(focused_tree_id) != tree_id_map_.end())
- focused_tree = tree_id_map_[focused_tree_id];
- combined_.tree_data.focus_id =
- MapId(focused_tree_id, focused_tree->tree_data.focus_id);
- combined_.tree_data.sel_is_backward =
- MapId(focused_tree_id, focused_tree->tree_data.sel_is_backward);
- combined_.tree_data.sel_anchor_object_id =
- MapId(focused_tree_id, focused_tree->tree_data.sel_anchor_object_id);
- combined_.tree_data.sel_focus_object_id =
- MapId(focused_tree_id, focused_tree->tree_data.sel_focus_object_id);
- combined_.tree_data.sel_anchor_offset =
- focused_tree->tree_data.sel_anchor_offset;
- combined_.tree_data.sel_focus_offset =
- focused_tree->tree_data.sel_focus_offset;
- // Debug-mode check that the resulting combined tree is valid.
- AXTree tree;
- DCHECK(tree.Unserialize(combined_))
- << combined_.ToString() << "\n" << tree.error();
- return true;
- }
- AXNodeID AXTreeCombiner::MapId(AXTreeID tree_id, AXNodeID node_id) {
- auto tree_id_node_id = std::make_pair(tree_id, node_id);
- if (tree_id_node_id_map_[tree_id_node_id] == 0)
- tree_id_node_id_map_[tree_id_node_id] = next_id_++;
- return tree_id_node_id_map_[tree_id_node_id];
- }
- void AXTreeCombiner::ProcessTree(const AXTreeUpdate* tree) {
- AXTreeID tree_id = tree->tree_data.tree_id;
- for (size_t i = 0; i < tree->nodes.size(); ++i) {
- AXNodeData node = tree->nodes[i];
- AXTreeID child_tree_id = AXTreeID::FromString(
- node.GetStringAttribute(ax::mojom::StringAttribute::kChildTreeId));
- // Map the node's ID.
- node.id = MapId(tree_id, node.id);
- // Map the node's child IDs.
- for (size_t j = 0; j < node.child_ids.size(); ++j)
- node.child_ids[j] = MapId(tree_id, node.child_ids[j]);
- // Map the container id.
- if (node.relative_bounds.offset_container_id > 0)
- node.relative_bounds.offset_container_id =
- MapId(tree_id, node.relative_bounds.offset_container_id);
- // Map other int attributes that refer to node IDs.
- for (size_t j = 0; j < node.int_attributes.size(); ++j) {
- auto& attr = node.int_attributes[j];
- if (IsNodeIdIntAttribute(attr.first))
- attr.second = MapId(tree_id, attr.second);
- }
- // Map other int list attributes that refer to node IDs.
- for (size_t j = 0; j < node.intlist_attributes.size(); ++j) {
- auto& attr = node.intlist_attributes[j];
- if (IsNodeIdIntListAttribute(attr.first)) {
- for (size_t k = 0; k < attr.second.size(); k++)
- attr.second[k] = MapId(tree_id, attr.second[k]);
- }
- }
- // Remove the ax::mojom::StringAttribute::kChildTreeId attribute.
- for (size_t j = 0; j < node.string_attributes.size(); ++j) {
- auto& attr = node.string_attributes[j];
- if (attr.first == ax::mojom::StringAttribute::kChildTreeId) {
- attr.first = ax::mojom::StringAttribute::kNone;
- attr.second = "";
- }
- }
- // See if this node has a child tree. As a sanity check make sure the
- // child tree lists this tree as its parent tree id.
- const AXTreeUpdate* child_tree = nullptr;
- if (tree_id_map_.find(child_tree_id) != tree_id_map_.end()) {
- child_tree = tree_id_map_.find(child_tree_id)->second;
- if (child_tree->tree_data.parent_tree_id != tree_id)
- child_tree = nullptr;
- if (child_tree && child_tree->nodes.empty())
- child_tree = nullptr;
- if (child_tree) {
- node.child_ids.push_back(MapId(child_tree_id,
- child_tree->nodes[0].id));
- }
- }
- // Put the rewritten AXNodeData into the output data structure.
- combined_.nodes.push_back(node);
- // Recurse into the child tree now, if any.
- if (child_tree)
- ProcessTree(child_tree);
- }
- }
- } // namespace ui
|