Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: ui/accessibility/ax_tree.cc

Issue 125783002: Add AXTreeDelegate and refactor other AXTree classes slightly. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed const issue Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/accessibility/ax_tree.h ('k') | ui/accessibility/ax_tree_serializer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/accessibility/ax_tree.h" 5 #include "ui/accessibility/ax_tree.h"
6 6
7 #include <set> 7 #include <set>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h" 10 #include "base/strings/stringprintf.h"
11 #include "ui/accessibility/ax_node.h" 11 #include "ui/accessibility/ax_node.h"
12 12
13 namespace ui { 13 namespace ui {
14 14
15 namespace { 15 namespace {
16 16
17 std::string TreeToStringHelper(AXNode* node, int indent) { 17 std::string TreeToStringHelper(AXNode* node, int indent) {
18 std::string result; 18 std::string result;
19 for (int i = 0; i < indent; i++) 19 for (int i = 0; i < indent; i++)
20 result += " "; 20 result += " ";
21 result += node->data().ToString() + "\n"; 21 result += node->data().ToString() + "\n";
22 for (int i = 0; i < node->child_count(); ++i) 22 for (int i = 0; i < node->child_count(); ++i)
23 result += TreeToStringHelper(node->ChildAtIndex(i), indent + 1); 23 result += TreeToStringHelper(node->ChildAtIndex(i), indent + 1);
24 return result; 24 return result;
25 } 25 }
26 26
27 } // anonymous namespace 27 } // anonymous namespace
28 28
29 // Intermediate state to keep track of during a tree update.
30 struct AXTreeUpdateState {
31 // During an update, this keeps track of all nodes that have been
32 // implicitly referenced as part of this update, but haven't been
33 // updated yet. It's an error if there are any pending nodes at the
34 // end of Unserialize.
35 std::set<AXNode*> pending_nodes;
36
37 // Keeps track of new nodes created during this update.
38 std::set<AXNode*> new_nodes;
39 };
40
41 AXTreeDelegate::AXTreeDelegate() {
42 }
43
44 AXTreeDelegate::~AXTreeDelegate() {
45 }
46
29 AXTree::AXTree() 47 AXTree::AXTree()
30 : root_(NULL) { 48 : delegate_(NULL), root_(NULL) {
31 AXNodeData root; 49 AXNodeData root;
32 root.id = 0; 50 root.id = 0;
33 root.role = AX_ROLE_ROOT_WEB_AREA; 51 root.role = AX_ROLE_ROOT_WEB_AREA;
34 52
35 AXTreeUpdate initial_state; 53 AXTreeUpdate initial_state;
36 initial_state.nodes.push_back(root); 54 initial_state.nodes.push_back(root);
37 CHECK(Unserialize(initial_state)) << error(); 55 CHECK(Unserialize(initial_state)) << error();
38 } 56 }
39 57
40 AXTree::AXTree(const AXTreeUpdate& initial_state) 58 AXTree::AXTree(const AXTreeUpdate& initial_state)
41 : root_(NULL) { 59 : delegate_(NULL), root_(NULL) {
42 CHECK(Unserialize(initial_state)) << error(); 60 CHECK(Unserialize(initial_state)) << error();
43 } 61 }
44 62
45 AXTree::~AXTree() { 63 AXTree::~AXTree() {
46 if (root_) 64 if (root_)
47 DestroyNodeAndSubtree(root_); 65 DestroyNodeAndSubtree(root_);
48 } 66 }
49 67
68 void AXTree::SetDelegate(AXTreeDelegate* delegate) {
69 delegate_ = delegate;
70 }
71
50 AXNode* AXTree::GetRoot() const { 72 AXNode* AXTree::GetRoot() const {
51 return root_; 73 return root_;
52 } 74 }
53 75
54 AXNode* AXTree::GetFromId(int32 id) const { 76 AXNode* AXTree::GetFromId(int32 id) const {
55 base::hash_map<int32, AXNode*>::const_iterator iter = id_map_.find(id); 77 base::hash_map<int32, AXNode*>::const_iterator iter = id_map_.find(id);
56 return iter != id_map_.end() ? (iter->second) : NULL; 78 return iter != id_map_.end() ? (iter->second) : NULL;
57 } 79 }
58 80
59 bool AXTree::Unserialize(const AXTreeUpdate& update) { 81 bool AXTree::Unserialize(const AXTreeUpdate& update) {
60 std::set<AXNode*> pending_nodes; 82 AXTreeUpdateState update_state;
83 int32 old_root_id = root_ ? root_->id() : 0;
61 84
62 if (update.node_id_to_clear != 0) { 85 if (update.node_id_to_clear != 0) {
63 AXNode* node = GetFromId(update.node_id_to_clear); 86 AXNode* node = GetFromId(update.node_id_to_clear);
64 if (!node) { 87 if (!node) {
65 error_ = base::StringPrintf("Bad node_id_to_clear: %d", 88 error_ = base::StringPrintf("Bad node_id_to_clear: %d",
66 update.node_id_to_clear); 89 update.node_id_to_clear);
67 return false; 90 return false;
68 } 91 }
69 if (node == root_) { 92 if (node == root_) {
70 DestroyNodeAndSubtree(root_); 93 DestroyNodeAndSubtree(root_);
71 root_ = NULL; 94 root_ = NULL;
72 } else { 95 } else {
73 for (int i = 0; i < node->child_count(); ++i) 96 for (int i = 0; i < node->child_count(); ++i)
74 DestroyNodeAndSubtree(node->ChildAtIndex(i)); 97 DestroyNodeAndSubtree(node->ChildAtIndex(i));
75 std::vector<AXNode*> children; 98 std::vector<AXNode*> children;
76 node->SwapChildren(children); 99 node->SwapChildren(children);
77 pending_nodes.insert(node); 100 update_state.pending_nodes.insert(node);
78 } 101 }
79 } 102 }
80 103
81 for (size_t i = 0; i < update.nodes.size(); ++i) { 104 for (size_t i = 0; i < update.nodes.size(); ++i) {
82 if (!UpdateNode(update.nodes[i], &pending_nodes)) 105 if (!UpdateNode(update.nodes[i], &update_state))
83 return false; 106 return false;
84 } 107 }
85 108
86 if (!pending_nodes.empty()) { 109 if (!update_state.pending_nodes.empty()) {
87 error_ = "Nodes left pending by the update:"; 110 error_ = "Nodes left pending by the update:";
88 for (std::set<AXNode*>::iterator iter = pending_nodes.begin(); 111 for (std::set<AXNode*>::iterator iter = update_state.pending_nodes.begin();
89 iter != pending_nodes.end(); ++iter) { 112 iter != update_state.pending_nodes.end(); ++iter) {
90 error_ += base::StringPrintf(" %d", (*iter)->id()); 113 error_ += base::StringPrintf(" %d", (*iter)->id());
91 } 114 }
92 return false; 115 return false;
93 } 116 }
94 117
118 if (delegate_) {
119 for (size_t i = 0; i < update.nodes.size(); ++i) {
120 AXNode* node = GetFromId(update.nodes[i].id);
121 if (update_state.new_nodes.find(node) != update_state.new_nodes.end()) {
122 delegate_->OnNodeCreated(node);
123 update_state.new_nodes.erase(node);
124 } else {
125 delegate_->OnNodeChanged(node);
126 }
127 }
128 if (root_->id() != old_root_id)
129 delegate_->OnRootChanged(root_);
130 }
131
95 return true; 132 return true;
96 } 133 }
97 134
98 std::string AXTree::ToString() const { 135 std::string AXTree::ToString() const {
99 return TreeToStringHelper(root_, 0); 136 return TreeToStringHelper(root_, 0);
100 } 137 }
101 138
102 AXNode* AXTree::CreateNode(AXNode* parent, int32 id, int32 index_in_parent) { 139 AXNode* AXTree::CreateNode(AXNode* parent, int32 id, int32 index_in_parent) {
103 return new AXNode(parent, id, index_in_parent); 140 return new AXNode(parent, id, index_in_parent);
104 } 141 }
105 142
106 bool AXTree::UpdateNode( 143 bool AXTree::UpdateNode(
107 const AXNodeData& src, std::set<AXNode*>* pending_nodes) { 144 const AXNodeData& src, AXTreeUpdateState* update_state) {
108 // This method updates one node in the tree based on serialized data 145 // This method updates one node in the tree based on serialized data
109 // received in an AXTreeUpdate. See AXTreeUpdate for pre and post 146 // received in an AXTreeUpdate. See AXTreeUpdate for pre and post
110 // conditions. 147 // conditions.
111 148
112 // Look up the node by id. If it's not found, then either the root 149 // Look up the node by id. If it's not found, then either the root
113 // of the tree is being swapped, or we're out of sync with the source 150 // of the tree is being swapped, or we're out of sync with the source
114 // and this is a serious error. 151 // and this is a serious error.
115 AXNode* node = GetFromId(src.id); 152 AXNode* node = GetFromId(src.id);
116 if (node) { 153 if (node) {
117 pending_nodes->erase(node); 154 update_state->pending_nodes.erase(node);
118 } else { 155 } else {
119 if (src.role != AX_ROLE_ROOT_WEB_AREA) { 156 if (src.role != AX_ROLE_ROOT_WEB_AREA) {
120 error_ = base::StringPrintf( 157 error_ = base::StringPrintf(
121 "%d is not in the tree and not the new root", src.id); 158 "%d is not in the tree and not the new root", src.id);
122 return false; 159 return false;
123 } 160 }
124 node = CreateAndInitializeNode(NULL, src.id, 0); 161 node = CreateAndInitializeNode(NULL, src.id, 0);
162 update_state->new_nodes.insert(node);
125 } 163 }
126 164
127 // Set the node's data. 165 // Set the node's data.
128 node->SetData(src); 166 node->SetData(src);
129 167
130 // First, delete nodes that used to be children of this node but aren't 168 // First, delete nodes that used to be children of this node but aren't
131 // anymore. 169 // anymore.
132 if (!DeleteOldChildren(node, src.child_ids)) 170 if (!DeleteOldChildren(node, src.child_ids))
133 return false; 171 return false;
134 172
135 // Now build a new children vector, reusing nodes when possible, 173 // Now build a new children vector, reusing nodes when possible,
136 // and swap it in. 174 // and swap it in.
137 std::vector<AXNode*> new_children; 175 std::vector<AXNode*> new_children;
138 bool success = CreateNewChildVector( 176 bool success = CreateNewChildVector(
139 node, src.child_ids, &new_children, pending_nodes); 177 node, src.child_ids, &new_children, update_state);
140 node->SwapChildren(new_children); 178 node->SwapChildren(new_children);
141 179
142 // Update the root of the tree if needed. 180 // Update the root of the tree if needed.
143 if (src.role == AX_ROLE_ROOT_WEB_AREA && 181 if (src.role == AX_ROLE_ROOT_WEB_AREA &&
144 (!root_ || root_->id() != src.id)) { 182 (!root_ || root_->id() != src.id)) {
145 if (root_) 183 if (root_)
146 DestroyNodeAndSubtree(root_); 184 DestroyNodeAndSubtree(root_);
147 root_ = node; 185 root_ = node;
148 OnRootChanged();
149 } 186 }
150 187
151 return success; 188 return success;
152 } 189 }
153 190
154 void AXTree::OnRootChanged() {
155 }
156
157 AXNode* AXTree::CreateAndInitializeNode( 191 AXNode* AXTree::CreateAndInitializeNode(
158 AXNode* parent, int32 id, int32 index_in_parent) { 192 AXNode* parent, int32 id, int32 index_in_parent) {
159 AXNode* node = CreateNode(parent, id, index_in_parent); 193 AXNode* node = CreateNode(parent, id, index_in_parent);
160 id_map_[node->id()] = node; 194 id_map_[node->id()] = node;
161 return node; 195 return node;
162 } 196 }
163 197
164 void AXTree::DestroyNodeAndSubtree(AXNode* node) { 198 void AXTree::DestroyNodeAndSubtree(AXNode* node) {
165 id_map_.erase(node->id()); 199 id_map_.erase(node->id());
166 for (int i = 0; i < node->child_count(); ++i) 200 for (int i = 0; i < node->child_count(); ++i)
167 DestroyNodeAndSubtree(node->ChildAtIndex(i)); 201 DestroyNodeAndSubtree(node->ChildAtIndex(i));
202 if (delegate_)
203 delegate_->OnNodeWillBeDeleted(node);
168 node->Destroy(); 204 node->Destroy();
169 } 205 }
170 206
171 bool AXTree::DeleteOldChildren(AXNode* node, 207 bool AXTree::DeleteOldChildren(AXNode* node,
172 const std::vector<int32> new_child_ids) { 208 const std::vector<int32> new_child_ids) {
173 // Create a set of child ids in |src| for fast lookup, and return false 209 // Create a set of child ids in |src| for fast lookup, and return false
174 // if a duplicate is found; 210 // if a duplicate is found;
175 std::set<int32> new_child_id_set; 211 std::set<int32> new_child_id_set;
176 for (size_t i = 0; i < new_child_ids.size(); ++i) { 212 for (size_t i = 0; i < new_child_ids.size(); ++i) {
177 if (new_child_id_set.find(new_child_ids[i]) != new_child_id_set.end()) { 213 if (new_child_id_set.find(new_child_ids[i]) != new_child_id_set.end()) {
(...skipping 11 matching lines...) Expand all
189 if (new_child_id_set.find(old_id) == new_child_id_set.end()) 225 if (new_child_id_set.find(old_id) == new_child_id_set.end())
190 DestroyNodeAndSubtree(old_children[i]); 226 DestroyNodeAndSubtree(old_children[i]);
191 } 227 }
192 228
193 return true; 229 return true;
194 } 230 }
195 231
196 bool AXTree::CreateNewChildVector(AXNode* node, 232 bool AXTree::CreateNewChildVector(AXNode* node,
197 const std::vector<int32> new_child_ids, 233 const std::vector<int32> new_child_ids,
198 std::vector<AXNode*>* new_children, 234 std::vector<AXNode*>* new_children,
199 std::set<AXNode*>* pending_nodes) { 235 AXTreeUpdateState* update_state) {
200 bool success = true; 236 bool success = true;
201 for (size_t i = 0; i < new_child_ids.size(); ++i) { 237 for (size_t i = 0; i < new_child_ids.size(); ++i) {
202 int32 child_id = new_child_ids[i]; 238 int32 child_id = new_child_ids[i];
203 int32 index_in_parent = static_cast<int32>(i); 239 int32 index_in_parent = static_cast<int32>(i);
204 AXNode* child = GetFromId(child_id); 240 AXNode* child = GetFromId(child_id);
205 if (child) { 241 if (child) {
206 if (child->parent() != node) { 242 if (child->parent() != node) {
207 // This is a serious error - nodes should never be reparented. 243 // This is a serious error - nodes should never be reparented.
208 // If this case occurs, continue so this node isn't left in an 244 // If this case occurs, continue so this node isn't left in an
209 // inconsistent state, but return failure at the end. 245 // inconsistent state, but return failure at the end.
210 error_ = base::StringPrintf( 246 error_ = base::StringPrintf(
211 "Node %d reparented from %d to %d", 247 "Node %d reparented from %d to %d",
212 child->id(), 248 child->id(),
213 child->parent() ? child->parent()->id() : 0, 249 child->parent() ? child->parent()->id() : 0,
214 node->id()); 250 node->id());
215 success = false; 251 success = false;
216 continue; 252 continue;
217 } 253 }
218 child->SetIndexInParent(index_in_parent); 254 child->SetIndexInParent(index_in_parent);
219 } else { 255 } else {
220 child = CreateAndInitializeNode(node, child_id, index_in_parent); 256 child = CreateAndInitializeNode(node, child_id, index_in_parent);
221 pending_nodes->insert(child); 257 update_state->pending_nodes.insert(child);
258 update_state->new_nodes.insert(child);
222 } 259 }
223 new_children->push_back(child); 260 new_children->push_back(child);
224 } 261 }
225 262
226 return success; 263 return success;
227 } 264 }
228 265
229 } // namespace ui 266 } // namespace ui
OLDNEW
« no previous file with comments | « ui/accessibility/ax_tree.h ('k') | ui/accessibility/ax_tree_serializer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698