• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "ui/accessibility/ax_tree.h"
6 
7 #include <set>
8 
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "ui/accessibility/ax_node.h"
12 
13 namespace ui {
14 
AXTree()15 AXTree::AXTree()
16     : root_(NULL) {
17   AXNodeData root;
18   root.id = 0;
19   root.role = AX_ROLE_ROOT_WEB_AREA;
20 
21   AXTreeUpdate initial_state;
22   initial_state.nodes.push_back(root);
23   CHECK(Unserialize(initial_state)) << error();
24 }
25 
AXTree(const AXTreeUpdate & initial_state)26 AXTree::AXTree(const AXTreeUpdate& initial_state)
27     : root_(NULL) {
28   CHECK(Unserialize(initial_state)) << error();
29 }
30 
~AXTree()31 AXTree::~AXTree() {
32   if (root_)
33     DestroyNodeAndSubtree(root_);
34 }
35 
GetRoot() const36 AXNode* AXTree::GetRoot() const {
37   return root_;
38 }
39 
GetFromId(int32 id) const40 AXNode* AXTree::GetFromId(int32 id) const {
41   base::hash_map<int32, AXNode*>::const_iterator iter = id_map_.find(id);
42   return iter != id_map_.end() ? (iter->second) : NULL;
43 }
44 
Unserialize(const AXTreeUpdate & update)45 bool AXTree::Unserialize(const AXTreeUpdate& update) {
46   std::set<AXNode*> pending_nodes;
47 
48   if (update.node_id_to_clear != 0) {
49     AXNode* node = GetFromId(update.node_id_to_clear);
50     if (!node) {
51       error_ = base::StringPrintf("Bad node_id_to_clear: %d",
52                                   update.node_id_to_clear);
53       return false;
54     }
55     if (node == root_) {
56       DestroyNodeAndSubtree(root_);
57       root_ = NULL;
58     } else {
59       for (int i = 0; i < node->child_count(); ++i)
60         DestroyNodeAndSubtree(node->ChildAtIndex(i));
61       std::vector<AXNode*> children;
62       node->SwapChildren(children);
63       pending_nodes.insert(node);
64     }
65   }
66 
67   for (size_t i = 0; i < update.nodes.size(); ++i) {
68     if (!UpdateNode(update.nodes[i], &pending_nodes))
69       return false;
70   }
71 
72   if (!pending_nodes.empty()) {
73     error_ = "Nodes left pending by the update:";
74     for (std::set<AXNode*>::iterator iter = pending_nodes.begin();
75          iter != pending_nodes.end(); ++iter) {
76       error_ += base::StringPrintf(" %d", (*iter)->id());
77     }
78     return false;
79   }
80 
81   return true;
82 }
83 
CreateNode(AXNode * parent,int32 id,int32 index_in_parent)84 AXNode* AXTree::CreateNode(AXNode* parent, int32 id, int32 index_in_parent) {
85   return new AXNode(parent, id, index_in_parent);
86 }
87 
UpdateNode(const AXNodeData & src,std::set<AXNode * > * pending_nodes)88 bool AXTree::UpdateNode(
89     const AXNodeData& src, std::set<AXNode*>* pending_nodes) {
90   // This method updates one node in the tree based on serialized data
91   // received in an AXTreeUpdate. See AXTreeUpdate for pre and post
92   // conditions.
93 
94   // Look up the node by id. If it's not found, then either the root
95   // of the tree is being swapped, or we're out of sync with the source
96   // and this is a serious error.
97   AXNode* node = GetFromId(src.id);
98   if (node) {
99     pending_nodes->erase(node);
100   } else {
101     if (src.role != AX_ROLE_ROOT_WEB_AREA) {
102       error_ = base::StringPrintf(
103           "%d is not in the tree and not the new root", src.id);
104       return false;
105     }
106     node = CreateAndInitializeNode(NULL, src.id, 0);
107   }
108 
109   // Set the node's data.
110   node->SetData(src);
111 
112   // First, delete nodes that used to be children of this node but aren't
113   // anymore.
114   if (!DeleteOldChildren(node, src.child_ids))
115     return false;
116 
117   // Now build a new children vector, reusing nodes when possible,
118   // and swap it in.
119   std::vector<AXNode*> new_children;
120   bool success = CreateNewChildVector(
121       node, src.child_ids, &new_children, pending_nodes);
122   node->SwapChildren(new_children);
123 
124   // Update the root of the tree if needed.
125   if (src.role == AX_ROLE_ROOT_WEB_AREA &&
126       (!root_ || root_->id() != src.id)) {
127     if (root_)
128       DestroyNodeAndSubtree(root_);
129     root_ = node;
130     OnRootChanged();
131   }
132 
133   return success;
134 }
135 
OnRootChanged()136 void AXTree::OnRootChanged() {
137 }
138 
CreateAndInitializeNode(AXNode * parent,int32 id,int32 index_in_parent)139 AXNode* AXTree::CreateAndInitializeNode(
140     AXNode* parent, int32 id, int32 index_in_parent) {
141   AXNode* node = CreateNode(parent, id, index_in_parent);
142   id_map_[node->id()] = node;
143   return node;
144 }
145 
DestroyNodeAndSubtree(AXNode * node)146 void AXTree::DestroyNodeAndSubtree(AXNode* node) {
147   id_map_.erase(node->id());
148   for (int i = 0; i < node->child_count(); ++i)
149     DestroyNodeAndSubtree(node->ChildAtIndex(i));
150   node->Destroy();
151 }
152 
DeleteOldChildren(AXNode * node,const std::vector<int32> new_child_ids)153 bool AXTree::DeleteOldChildren(AXNode* node,
154                                const std::vector<int32> new_child_ids) {
155   // Create a set of child ids in |src| for fast lookup, and return false
156   // if a duplicate is found;
157   std::set<int32> new_child_id_set;
158   for (size_t i = 0; i < new_child_ids.size(); ++i) {
159     if (new_child_id_set.find(new_child_ids[i]) != new_child_id_set.end()) {
160       error_ = base::StringPrintf("Node %d has duplicate child id %d",
161                                   node->id(), new_child_ids[i]);
162       return false;
163     }
164     new_child_id_set.insert(new_child_ids[i]);
165   }
166 
167   // Delete the old children.
168   const std::vector<AXNode*>& old_children = node->children();
169   for (size_t i = 0; i < old_children.size(); ++i) {
170     int old_id = old_children[i]->id();
171     if (new_child_id_set.find(old_id) == new_child_id_set.end())
172       DestroyNodeAndSubtree(old_children[i]);
173   }
174 
175   return true;
176 }
177 
CreateNewChildVector(AXNode * node,const std::vector<int32> new_child_ids,std::vector<AXNode * > * new_children,std::set<AXNode * > * pending_nodes)178 bool AXTree::CreateNewChildVector(AXNode* node,
179                                   const std::vector<int32> new_child_ids,
180                                   std::vector<AXNode*>* new_children,
181                                   std::set<AXNode*>* pending_nodes) {
182   bool success = true;
183   for (size_t i = 0; i < new_child_ids.size(); ++i) {
184     int32 child_id = new_child_ids[i];
185     int32 index_in_parent = static_cast<int32>(i);
186     AXNode* child = GetFromId(child_id);
187     if (child) {
188       if (child->parent() != node) {
189         // This is a serious error - nodes should never be reparented.
190         // If this case occurs, continue so this node isn't left in an
191         // inconsistent state, but return failure at the end.
192         error_ = base::StringPrintf(
193             "Node %d reparented from %d to %d",
194             child->id(),
195             child->parent() ? child->parent()->id() : 0,
196             node->id());
197         success = false;
198         continue;
199       }
200       child->SetIndexInParent(index_in_parent);
201     } else {
202       child = CreateAndInitializeNode(node, child_id, index_in_parent);
203       pending_nodes->insert(child);
204     }
205     new_children->push_back(child);
206   }
207 
208   return success;
209 }
210 
211 }  // namespace ui
212