When serializing accessibility tree, skip invalid children.
[chromium-blink-merge.git] / ui / accessibility / ax_tree_serializer.h
blob5435bbe2bae702eb274fcfc18b160a2fee67fe49
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.
5 #ifndef UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
6 #define UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
8 #include <set>
10 #include "base/containers/hash_tables.h"
11 #include "base/logging.h"
12 #include "base/stl_util.h"
13 #include "ui/accessibility/ax_tree_source.h"
14 #include "ui/accessibility/ax_tree_update.h"
16 namespace ui {
18 struct ClientTreeNode;
20 // AXTreeSerializer is a helper class that serializes incremental
21 // updates to an AXTreeSource as a AXTreeUpdate struct.
22 // These structs can be unserialized by a client object such as an
23 // AXTree. An AXTreeSerializer keeps track of the tree of node ids that its
24 // client is aware of so that it will never generate an AXTreeUpdate that
25 // results in an invalid tree.
27 // Every node in the source tree must have an id that's a unique positive
28 // integer, the same node must not appear twice.
30 // Usage:
32 // You must call SerializeChanges() every time a node in the tree changes,
33 // and send the generated AXTreeUpdate to the client.
35 // If a node is added, call SerializeChanges on its parent.
36 // If a node is removed, call SerializeChanges on its parent.
37 // If a whole new subtree is added, just call SerializeChanges on its root.
38 // If the root of the tree changes, call SerializeChanges on the new root.
40 // AXTreeSerializer will avoid re-serializing nodes that do not change.
41 // For example, if node 1 has children 2, 3, 4, 5 and then child 2 is
42 // removed and a new child 6 is added, the AXTreeSerializer will only
43 // update nodes 1 and 6 (and any children of node 6 recursively). It will
44 // assume that nodes 3, 4, and 5 are not modified unless you explicitly
45 // call SerializeChanges() on them.
47 // As long as the source tree has unique ids for every node and no loops,
48 // and as long as every update is applied to the client tree, AXTreeSerializer
49 // will continue to work. If the source tree makes a change but fails to
50 // call SerializeChanges properly, the trees may get out of sync - but
51 // because AXTreeSerializer always keeps track of what updates it's sent,
52 // it will never send an invalid update and the client tree will not break,
53 // it just may not contain all of the changes.
54 template<typename AXSourceNode>
55 class AXTreeSerializer {
56 public:
57 explicit AXTreeSerializer(AXTreeSource<AXSourceNode>* tree);
58 ~AXTreeSerializer();
60 // Throw out the internal state that keeps track of the nodes the client
61 // knows about. This has the effect that the next update will send the
62 // entire tree over because it assumes the client knows nothing.
63 void Reset();
65 // Serialize all changes to |node| and append them to |out_update|.
66 void SerializeChanges(AXSourceNode node,
67 AXTreeUpdate* out_update);
69 // Delete the client subtree for this node, ensuring that the subtree
70 // is re-serialized.
71 void DeleteClientSubtree(AXSourceNode node);
73 // Only for unit testing. Normally this class relies on getting a call
74 // to SerializeChanges() every time the source tree changes. For unit
75 // testing, it's convenient to create a static AXTree for the initial
76 // state and then call ChangeTreeSourceForTesting and then SerializeChanges
77 // to simulate the changes you'd get if a tree changed from the initial
78 // state to the second tree's state.
79 void ChangeTreeSourceForTesting(AXTreeSource<AXSourceNode>* new_tree);
81 private:
82 // Return the least common ancestor of a node in the source tree
83 // and a node in the client tree, or NULL if there is no such node.
84 // The least common ancestor is the closest ancestor to |node| (which
85 // may be |node| itself) that's in both the source tree and client tree,
86 // and for which both the source and client tree agree on their ancestor
87 // chain up to the root.
89 // Example 1:
91 // Client Tree Source tree |
92 // 1 1 |
93 // / \ / \ |
94 // 2 3 2 4 |
96 // LCA(source node 2, client node 2) is node 2.
97 // LCA(source node 3, client node 4) is node 1.
99 // Example 2:
101 // Client Tree Source tree |
102 // 1 1 |
103 // / \ / \ |
104 // 2 3 2 3 |
105 // / \ / / |
106 // 4 7 8 4 |
107 // / \ / \ |
108 // 5 6 5 6 |
110 // LCA(source node 8, client node 7) is node 2.
111 // LCA(source node 5, client node 5) is node 1.
112 // It's not node 5, because the two trees disagree on the parent of
113 // node 4, so the LCA is the first ancestor both trees agree on.
114 AXSourceNode LeastCommonAncestor(AXSourceNode node,
115 ClientTreeNode* client_node);
117 // Return the least common ancestor of |node| that's in the client tree.
118 // This just walks up the ancestors of |node| until it finds a node that's
119 // also in the client tree, and then calls LeastCommonAncestor on the
120 // source node and client node.
121 AXSourceNode LeastCommonAncestor(AXSourceNode node);
123 // Walk the subtree rooted at |node| and return true if any nodes that
124 // would be updated are being reparented. If so, update |out_lca| to point
125 // to the least common ancestor of the previous LCA and the previous
126 // parent of the node being reparented.
127 bool AnyDescendantWasReparented(AXSourceNode node,
128 AXSourceNode* out_lca);
130 ClientTreeNode* ClientTreeNodeById(int32 id);
132 // Delete the given client tree node and recursively delete all of its
133 // descendants.
134 void DeleteClientSubtree(ClientTreeNode* client_node);
136 // Helper function, called recursively with each new node to serialize.
137 void SerializeChangedNodes(AXSourceNode node,
138 AXTreeUpdate* out_update);
140 // The tree source.
141 AXTreeSource<AXSourceNode>* tree_;
143 // Our representation of the client tree.
144 ClientTreeNode* client_root_;
146 // A map from IDs to nodes in the client tree.
147 base::hash_map<int32, ClientTreeNode*> client_id_map_;
150 // In order to keep track of what nodes the client knows about, we keep a
151 // representation of the client tree - just IDs and parent/child
152 // relationships.
153 struct AX_EXPORT ClientTreeNode {
154 ClientTreeNode();
155 virtual ~ClientTreeNode();
156 int32 id;
157 ClientTreeNode* parent;
158 std::vector<ClientTreeNode*> children;
161 template<typename AXSourceNode>
162 AXTreeSerializer<AXSourceNode>::AXTreeSerializer(
163 AXTreeSource<AXSourceNode>* tree)
164 : tree_(tree),
165 client_root_(NULL) {
168 template<typename AXSourceNode>
169 AXTreeSerializer<AXSourceNode>::~AXTreeSerializer() {
170 Reset();
173 template<typename AXSourceNode>
174 void AXTreeSerializer<AXSourceNode>::Reset() {
175 if (!client_root_)
176 return;
178 DeleteClientSubtree(client_root_);
179 client_id_map_.erase(client_root_->id);
180 delete client_root_;
181 client_root_ = NULL;
184 template<typename AXSourceNode>
185 void AXTreeSerializer<AXSourceNode>::ChangeTreeSourceForTesting(
186 AXTreeSource<AXSourceNode>* new_tree) {
187 tree_ = new_tree;
190 template<typename AXSourceNode>
191 AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
192 AXSourceNode node, ClientTreeNode* client_node) {
193 if (!tree_->IsValid(node) || client_node == NULL)
194 return tree_->GetNull();
196 std::vector<AXSourceNode> ancestors;
197 while (tree_->IsValid(node)) {
198 ancestors.push_back(node);
199 node = tree_->GetParent(node);
202 std::vector<ClientTreeNode*> client_ancestors;
203 while (client_node) {
204 client_ancestors.push_back(client_node);
205 client_node = client_node->parent;
208 // Start at the root. Keep going until the source ancestor chain and
209 // client ancestor chain disagree. The last node before they disagree
210 // is the LCA.
211 AXSourceNode lca = tree_->GetNull();
212 int source_index = static_cast<int>(ancestors.size() - 1);
213 int client_index = static_cast<int>(client_ancestors.size() - 1);
214 while (source_index >= 0 && client_index >= 0) {
215 if (tree_->GetId(ancestors[source_index]) !=
216 client_ancestors[client_index]->id) {
217 return lca;
219 lca = ancestors[source_index];
220 source_index--;
221 client_index--;
223 return lca;
226 template<typename AXSourceNode>
227 AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor(
228 AXSourceNode node) {
229 // Walk up the tree until the source node's id also exists in the
230 // client tree, then call LeastCommonAncestor on those two nodes.
231 ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
232 while (tree_->IsValid(node) && !client_node) {
233 node = tree_->GetParent(node);
234 if (tree_->IsValid(node))
235 client_node = ClientTreeNodeById(tree_->GetId(node));
237 return LeastCommonAncestor(node, client_node);
240 template<typename AXSourceNode>
241 bool AXTreeSerializer<AXSourceNode>::AnyDescendantWasReparented(
242 AXSourceNode node, AXSourceNode* out_lca) {
243 bool result = false;
244 int id = tree_->GetId(node);
245 std::vector<AXSourceNode> children;
246 tree_->GetChildren(node, &children);
247 for (size_t i = 0; i < children.size(); ++i) {
248 AXSourceNode& child = children[i];
249 int child_id = tree_->GetId(child);
250 ClientTreeNode* client_child = ClientTreeNodeById(child_id);
251 if (client_child) {
252 if (!client_child->parent) {
253 // If the client child has no parent, it must have been the
254 // previous root node, so there is no LCA and we can exit early.
255 *out_lca = tree_->GetNull();
256 return true;
257 } else if (client_child->parent->id != id) {
258 // If the client child's parent is not this node, update the LCA
259 // and return true (reparenting was found).
260 *out_lca = LeastCommonAncestor(*out_lca, client_child);
261 result = true;
262 } else {
263 // This child is already in the client tree, we won't
264 // recursively serialize it so we don't need to check this
265 // subtree recursively for reparenting.
266 continue;
270 // This is a new child or reparented child, check it recursively.
271 if (AnyDescendantWasReparented(child, out_lca))
272 result = true;
274 return result;
277 template<typename AXSourceNode>
278 ClientTreeNode* AXTreeSerializer<AXSourceNode>::ClientTreeNodeById(int32 id) {
279 base::hash_map<int32, ClientTreeNode*>::iterator iter =
280 client_id_map_.find(id);
281 if (iter != client_id_map_.end())
282 return iter->second;
283 else
284 return NULL;
287 template<typename AXSourceNode>
288 void AXTreeSerializer<AXSourceNode>::SerializeChanges(
289 AXSourceNode node,
290 AXTreeUpdate* out_update) {
291 // If the node isn't in the client tree, we need to serialize starting
292 // with the LCA.
293 AXSourceNode lca = LeastCommonAncestor(node);
295 // This loop computes the least common ancestor that includes the old
296 // and new parents of any nodes that have been reparented, and clears the
297 // whole client subtree of that LCA if necessary. If we do end up clearing
298 // any client nodes, keep looping because we have to search for more
299 // nodes that may have been reparented from this new LCA.
300 bool need_delete;
301 do {
302 need_delete = false;
303 if (client_root_) {
304 if (tree_->IsValid(lca)) {
305 // Check for any reparenting within this subtree - if there is
306 // any, we need to delete and reserialize the whole subtree
307 // that contains the old and new parents of the reparented node.
308 if (AnyDescendantWasReparented(lca, &lca))
309 need_delete = true;
312 if (!tree_->IsValid(lca)) {
313 // If there's no LCA, just tell the client to destroy the whole
314 // tree and then we'll serialize everything from the new root.
315 out_update->node_id_to_clear = client_root_->id;
316 Reset();
317 } else if (need_delete) {
318 // Otherwise, if we need to reserialize a subtree, first we need
319 // to delete those nodes in our client tree so that
320 // SerializeChangedNodes() will be sure to send them again.
321 out_update->node_id_to_clear = tree_->GetId(lca);
322 ClientTreeNode* client_lca = ClientTreeNodeById(tree_->GetId(lca));
323 CHECK(client_lca);
324 DeleteClientSubtree(client_lca);
327 } while (need_delete);
329 // Serialize from the LCA, or from the root if there isn't one.
330 if (!tree_->IsValid(lca))
331 lca = tree_->GetRoot();
332 SerializeChangedNodes(lca, out_update);
335 template<typename AXSourceNode>
336 void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree(AXSourceNode node) {
337 ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
338 if (client_node)
339 DeleteClientSubtree(client_node);
342 template<typename AXSourceNode>
343 void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree(
344 ClientTreeNode* client_node) {
345 for (size_t i = 0; i < client_node->children.size(); ++i) {
346 client_id_map_.erase(client_node->children[i]->id);
347 DeleteClientSubtree(client_node->children[i]);
348 delete client_node->children[i];
350 client_node->children.clear();
353 template<typename AXSourceNode>
354 void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes(
355 AXSourceNode node,
356 AXTreeUpdate* out_update) {
357 // This method has three responsibilities:
358 // 1. Serialize |node| into an AXNodeData, and append it to
359 // the AXTreeUpdate to be sent to the client.
360 // 2. Determine if |node| has any new children that the client doesn't
361 // know about yet, and call SerializeChangedNodes recursively on those.
362 // 3. Update our internal data structure that keeps track of what nodes
363 // the client knows about.
365 // First, find the ClientTreeNode for this id in our data structure where
366 // we keep track of what accessibility objects the client already knows
367 // about. If we don't find it, then this must be the new root of the
368 // accessibility tree.
369 int id = tree_->GetId(node);
370 ClientTreeNode* client_node = ClientTreeNodeById(id);
371 if (!client_node) {
372 Reset();
373 client_root_ = new ClientTreeNode();
374 client_node = client_root_;
375 client_node->id = id;
376 client_node->parent = NULL;
377 client_id_map_[client_node->id] = client_node;
380 // Iterate over the ids of the children of |node|.
381 // Create a set of the child ids so we can quickly look
382 // up which children are new and which ones were there before.
383 base::hash_set<int32> new_child_ids;
384 std::vector<AXSourceNode> children;
385 tree_->GetChildren(node, &children);
386 for (size_t i = 0; i < children.size(); ++i) {
387 AXSourceNode& child = children[i];
388 int new_child_id = tree_->GetId(child);
389 new_child_ids.insert(new_child_id);
391 // This is a sanity check - there shouldn't be any reparenting
392 // because we've already handled it above.
393 ClientTreeNode* client_child = client_id_map_[new_child_id];
394 CHECK(!client_child || client_child->parent == client_node);
397 // Go through the old children and delete subtrees for child
398 // ids that are no longer present, and create a map from
399 // id to ClientTreeNode for the rest. It's important to delete
400 // first in a separate pass so that nodes that are reparented
401 // don't end up children of two different parents in the middle
402 // of an update, which can lead to a double-free.
403 base::hash_map<int32, ClientTreeNode*> client_child_id_map;
404 std::vector<ClientTreeNode*> old_children;
405 old_children.swap(client_node->children);
406 for (size_t i = 0; i < old_children.size(); ++i) {
407 ClientTreeNode* old_child = old_children[i];
408 int old_child_id = old_child->id;
409 if (new_child_ids.find(old_child_id) == new_child_ids.end()) {
410 client_id_map_.erase(old_child_id);
411 DeleteClientSubtree(old_child);
412 delete old_child;
413 } else {
414 client_child_id_map[old_child_id] = old_child;
418 // Serialize this node. This fills in all of the fields in
419 // AXNodeData except child_ids, which we handle below.
420 size_t serialized_node_index = out_update->nodes.size();
421 out_update->nodes.push_back(AXNodeData());
423 // Take the address of an element in a vector only within a limited
424 // scope because otherwise the pointer can become invalid if the
425 // vector is resized.
426 AXNodeData* serialized_node = &out_update->nodes[serialized_node_index];
428 tree_->SerializeNode(node, serialized_node);
429 // TODO(dmazzoni/dtseng): Make the serializer not depend on roles to
430 // identify the root.
431 if (serialized_node->id == client_root_->id &&
432 (serialized_node->role != AX_ROLE_ROOT_WEB_AREA &&
433 serialized_node->role != AX_ROLE_DESKTOP)) {
434 serialized_node->role = AX_ROLE_ROOT_WEB_AREA;
438 // Iterate over the children, serialize them, and update the ClientTreeNode
439 // data structure to reflect the new tree.
440 std::vector<int32> actual_serialized_node_child_ids;
441 client_node->children.reserve(children.size());
442 for (size_t i = 0; i < children.size(); ++i) {
443 AXSourceNode& child = children[i];
444 int child_id = tree_->GetId(child);
446 // Skip if the child isn't valid.
447 if (!tree_->IsValid(child))
448 continue;
450 // Skip if the same child is included more than once.
451 if (new_child_ids.find(child_id) == new_child_ids.end())
452 continue;
454 new_child_ids.erase(child_id);
455 actual_serialized_node_child_ids.push_back(child_id);
456 if (client_child_id_map.find(child_id) != client_child_id_map.end()) {
457 ClientTreeNode* reused_child = client_child_id_map[child_id];
458 client_node->children.push_back(reused_child);
459 } else {
460 ClientTreeNode* new_child = new ClientTreeNode();
461 new_child->id = child_id;
462 new_child->parent = client_node;
463 client_node->children.push_back(new_child);
464 client_id_map_[child_id] = new_child;
465 SerializeChangedNodes(child, out_update);
469 // Finally, update the child ids of this node to reflect the actual child
470 // ids that were valid during serialization.
471 out_update->nodes[serialized_node_index].child_ids.swap(
472 actual_serialized_node_child_ids);
475 } // namespace ui
477 #endif // UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_