Revert "Fix broken channel icon in chrome://help on CrOS" and try again
[chromium-blink-merge.git] / ui / accessibility / ax_tree_serializer.h
blob64521988d49ad84c0afee20af9213506bcfb7ba1
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_export.h"
14 #include "ui/accessibility/ax_tree_source.h"
15 #include "ui/accessibility/ax_tree_update.h"
17 namespace ui {
19 struct ClientTreeNode;
21 // AXTreeSerializer is a helper class that serializes incremental
22 // updates to an AXTreeSource as a AXTreeUpdate struct.
23 // These structs can be unserialized by a client object such as an
24 // AXTree. An AXTreeSerializer keeps track of the tree of node ids that its
25 // client is aware of so that it will never generate an AXTreeUpdate that
26 // results in an invalid tree.
28 // Every node in the source tree must have an id that's a unique positive
29 // integer, the same node must not appear twice.
31 // Usage:
33 // You must call SerializeChanges() every time a node in the tree changes,
34 // and send the generated AXTreeUpdate to the client.
36 // If a node is added, call SerializeChanges on its parent.
37 // If a node is removed, call SerializeChanges on its parent.
38 // If a whole new subtree is added, just call SerializeChanges on its root.
39 // If the root of the tree changes, call SerializeChanges on the new root.
41 // AXTreeSerializer will avoid re-serializing nodes that do not change.
42 // For example, if node 1 has children 2, 3, 4, 5 and then child 2 is
43 // removed and a new child 6 is added, the AXTreeSerializer will only
44 // update nodes 1 and 6 (and any children of node 6 recursively). It will
45 // assume that nodes 3, 4, and 5 are not modified unless you explicitly
46 // call SerializeChanges() on them.
48 // As long as the source tree has unique ids for every node and no loops,
49 // and as long as every update is applied to the client tree, AXTreeSerializer
50 // will continue to work. If the source tree makes a change but fails to
51 // call SerializeChanges properly, the trees may get out of sync - but
52 // because AXTreeSerializer always keeps track of what updates it's sent,
53 // it will never send an invalid update and the client tree will not break,
54 // it just may not contain all of the changes.
55 template<typename AXSourceNode, typename AXNodeData>
56 class AXTreeSerializer {
57 public:
58 explicit AXTreeSerializer(AXTreeSource<AXSourceNode, AXNodeData>* tree);
59 ~AXTreeSerializer();
61 // Throw out the internal state that keeps track of the nodes the client
62 // knows about. This has the effect that the next update will send the
63 // entire tree over because it assumes the client knows nothing.
64 void Reset();
66 // Sets the maximum number of nodes that will be serialized, or zero
67 // for no maximum. This is not a hard maximum - once it hits or
68 // exceeds this maximum it stops walking the children of nodes, but
69 // it may exceed this value a bit in order to create a consistent
70 // tree.
71 void set_max_node_count(size_t max_node_count) {
72 max_node_count_ = max_node_count;
75 // Serialize all changes to |node| and append them to |out_update|.
76 void SerializeChanges(AXSourceNode node,
77 AXTreeUpdate<AXNodeData>* out_update);
79 // Delete the client subtree for this node, ensuring that the subtree
80 // is re-serialized.
81 void DeleteClientSubtree(AXSourceNode node);
83 // Only for unit testing. Normally this class relies on getting a call
84 // to SerializeChanges() every time the source tree changes. For unit
85 // testing, it's convenient to create a static AXTree for the initial
86 // state and then call ChangeTreeSourceForTesting and then SerializeChanges
87 // to simulate the changes you'd get if a tree changed from the initial
88 // state to the second tree's state.
89 void ChangeTreeSourceForTesting(
90 AXTreeSource<AXSourceNode, AXNodeData>* new_tree);
92 private:
93 // Return the least common ancestor of a node in the source tree
94 // and a node in the client tree, or NULL if there is no such node.
95 // The least common ancestor is the closest ancestor to |node| (which
96 // may be |node| itself) that's in both the source tree and client tree,
97 // and for which both the source and client tree agree on their ancestor
98 // chain up to the root.
100 // Example 1:
102 // Client Tree Source tree |
103 // 1 1 |
104 // / \ / \ |
105 // 2 3 2 4 |
107 // LCA(source node 2, client node 2) is node 2.
108 // LCA(source node 3, client node 4) is node 1.
110 // Example 2:
112 // Client Tree Source tree |
113 // 1 1 |
114 // / \ / \ |
115 // 2 3 2 3 |
116 // / \ / / |
117 // 4 7 8 4 |
118 // / \ / \ |
119 // 5 6 5 6 |
121 // LCA(source node 8, client node 7) is node 2.
122 // LCA(source node 5, client node 5) is node 1.
123 // It's not node 5, because the two trees disagree on the parent of
124 // node 4, so the LCA is the first ancestor both trees agree on.
125 AXSourceNode LeastCommonAncestor(AXSourceNode node,
126 ClientTreeNode* client_node);
128 // Return the least common ancestor of |node| that's in the client tree.
129 // This just walks up the ancestors of |node| until it finds a node that's
130 // also in the client tree, and then calls LeastCommonAncestor on the
131 // source node and client node.
132 AXSourceNode LeastCommonAncestor(AXSourceNode node);
134 // Walk the subtree rooted at |node| and return true if any nodes that
135 // would be updated are being reparented. If so, update |out_lca| to point
136 // to the least common ancestor of the previous LCA and the previous
137 // parent of the node being reparented.
138 bool AnyDescendantWasReparented(AXSourceNode node,
139 AXSourceNode* out_lca);
141 ClientTreeNode* ClientTreeNodeById(int32 id);
143 // Delete the given client tree node and recursively delete all of its
144 // descendants.
145 void DeleteClientSubtree(ClientTreeNode* client_node);
147 // Helper function, called recursively with each new node to serialize.
148 void SerializeChangedNodes(AXSourceNode node,
149 AXTreeUpdate<AXNodeData>* out_update);
151 // Visit all of the descendants of |node| once.
152 void WalkAllDescendants(AXSourceNode node);
154 // The tree source.
155 AXTreeSource<AXSourceNode, AXNodeData>* tree_;
157 // Our representation of the client tree.
158 ClientTreeNode* client_root_;
160 // A map from IDs to nodes in the client tree.
161 base::hash_map<int32, ClientTreeNode*> client_id_map_;
163 // The maximum number of nodes to serialize in a given call to
164 // SerializeChanges, or 0 if there's no maximum.
165 size_t max_node_count_;
168 // In order to keep track of what nodes the client knows about, we keep a
169 // representation of the client tree - just IDs and parent/child
170 // relationships.
171 struct AX_EXPORT ClientTreeNode {
172 ClientTreeNode();
173 virtual ~ClientTreeNode();
174 int32 id;
175 ClientTreeNode* parent;
176 std::vector<ClientTreeNode*> children;
179 template<typename AXSourceNode, typename AXNodeData>
180 AXTreeSerializer<AXSourceNode, AXNodeData>::AXTreeSerializer(
181 AXTreeSource<AXSourceNode, AXNodeData>* tree)
182 : tree_(tree),
183 client_root_(NULL),
184 max_node_count_(0) {
187 template<typename AXSourceNode, typename AXNodeData>
188 AXTreeSerializer<AXSourceNode, AXNodeData>::~AXTreeSerializer() {
189 Reset();
192 template<typename AXSourceNode, typename AXNodeData>
193 void AXTreeSerializer<AXSourceNode, AXNodeData>::Reset() {
194 if (!client_root_)
195 return;
197 DeleteClientSubtree(client_root_);
198 client_id_map_.erase(client_root_->id);
199 delete client_root_;
200 client_root_ = NULL;
203 template<typename AXSourceNode, typename AXNodeData>
204 void AXTreeSerializer<AXSourceNode, AXNodeData>::ChangeTreeSourceForTesting(
205 AXTreeSource<AXSourceNode, AXNodeData>* new_tree) {
206 tree_ = new_tree;
209 template<typename AXSourceNode, typename AXNodeData>
210 AXSourceNode AXTreeSerializer<AXSourceNode, AXNodeData>::LeastCommonAncestor(
211 AXSourceNode node, ClientTreeNode* client_node) {
212 if (!tree_->IsValid(node) || client_node == NULL)
213 return tree_->GetNull();
215 std::vector<AXSourceNode> ancestors;
216 while (tree_->IsValid(node)) {
217 ancestors.push_back(node);
218 node = tree_->GetParent(node);
221 std::vector<ClientTreeNode*> client_ancestors;
222 while (client_node) {
223 client_ancestors.push_back(client_node);
224 client_node = client_node->parent;
227 // Start at the root. Keep going until the source ancestor chain and
228 // client ancestor chain disagree. The last node before they disagree
229 // is the LCA.
230 AXSourceNode lca = tree_->GetNull();
231 int source_index = static_cast<int>(ancestors.size() - 1);
232 int client_index = static_cast<int>(client_ancestors.size() - 1);
233 while (source_index >= 0 && client_index >= 0) {
234 if (tree_->GetId(ancestors[source_index]) !=
235 client_ancestors[client_index]->id) {
236 return lca;
238 lca = ancestors[source_index];
239 source_index--;
240 client_index--;
242 return lca;
245 template<typename AXSourceNode, typename AXNodeData>
246 AXSourceNode AXTreeSerializer<AXSourceNode, AXNodeData>::LeastCommonAncestor(
247 AXSourceNode node) {
248 // Walk up the tree until the source node's id also exists in the
249 // client tree, then call LeastCommonAncestor on those two nodes.
250 ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
251 while (tree_->IsValid(node) && !client_node) {
252 node = tree_->GetParent(node);
253 if (tree_->IsValid(node))
254 client_node = ClientTreeNodeById(tree_->GetId(node));
256 return LeastCommonAncestor(node, client_node);
259 template<typename AXSourceNode, typename AXNodeData>
260 bool AXTreeSerializer<AXSourceNode, AXNodeData>::AnyDescendantWasReparented(
261 AXSourceNode node, AXSourceNode* out_lca) {
262 bool result = false;
263 int id = tree_->GetId(node);
264 std::vector<AXSourceNode> children;
265 tree_->GetChildren(node, &children);
266 for (size_t i = 0; i < children.size(); ++i) {
267 AXSourceNode& child = children[i];
268 int child_id = tree_->GetId(child);
269 ClientTreeNode* client_child = ClientTreeNodeById(child_id);
270 if (client_child) {
271 if (!client_child->parent) {
272 // If the client child has no parent, it must have been the
273 // previous root node, so there is no LCA and we can exit early.
274 *out_lca = tree_->GetNull();
275 return true;
276 } else if (client_child->parent->id != id) {
277 // If the client child's parent is not this node, update the LCA
278 // and return true (reparenting was found).
279 *out_lca = LeastCommonAncestor(*out_lca, client_child);
280 result = true;
281 } else {
282 // This child is already in the client tree, we won't
283 // recursively serialize it so we don't need to check this
284 // subtree recursively for reparenting.
285 continue;
289 // This is a new child or reparented child, check it recursively.
290 if (AnyDescendantWasReparented(child, out_lca))
291 result = true;
293 return result;
296 template<typename AXSourceNode, typename AXNodeData>
297 ClientTreeNode*
298 AXTreeSerializer<AXSourceNode, AXNodeData>::ClientTreeNodeById(int32 id) {
299 base::hash_map<int32, ClientTreeNode*>::iterator iter =
300 client_id_map_.find(id);
301 if (iter != client_id_map_.end())
302 return iter->second;
303 else
304 return NULL;
307 template<typename AXSourceNode, typename AXNodeData>
308 void AXTreeSerializer<AXSourceNode, AXNodeData>::SerializeChanges(
309 AXSourceNode node,
310 AXTreeUpdate<AXNodeData>* out_update) {
311 // If the node isn't in the client tree, we need to serialize starting
312 // with the LCA.
313 AXSourceNode lca = LeastCommonAncestor(node);
315 // This loop computes the least common ancestor that includes the old
316 // and new parents of any nodes that have been reparented, and clears the
317 // whole client subtree of that LCA if necessary. If we do end up clearing
318 // any client nodes, keep looping because we have to search for more
319 // nodes that may have been reparented from this new LCA.
320 bool need_delete;
321 do {
322 need_delete = false;
323 if (client_root_) {
324 if (tree_->IsValid(lca)) {
325 // Check for any reparenting within this subtree - if there is
326 // any, we need to delete and reserialize the whole subtree
327 // that contains the old and new parents of the reparented node.
328 if (AnyDescendantWasReparented(lca, &lca))
329 need_delete = true;
332 if (!tree_->IsValid(lca)) {
333 // If there's no LCA, just tell the client to destroy the whole
334 // tree and then we'll serialize everything from the new root.
335 out_update->node_id_to_clear = client_root_->id;
336 Reset();
337 } else if (need_delete) {
338 // Otherwise, if we need to reserialize a subtree, first we need
339 // to delete those nodes in our client tree so that
340 // SerializeChangedNodes() will be sure to send them again.
341 out_update->node_id_to_clear = tree_->GetId(lca);
342 ClientTreeNode* client_lca = ClientTreeNodeById(tree_->GetId(lca));
343 CHECK(client_lca);
344 DeleteClientSubtree(client_lca);
347 } while (need_delete);
349 // Serialize from the LCA, or from the root if there isn't one.
350 if (!tree_->IsValid(lca))
351 lca = tree_->GetRoot();
353 // Work around flaky source trees where nodes don't figure out their
354 // correct parent/child relationships until you walk the whole tree once.
355 // Covered by this test in the content_browsertests suite:
356 // DumpAccessibilityTreeTest.AccessibilityAriaOwns.
357 WalkAllDescendants(lca);
359 SerializeChangedNodes(lca, out_update);
362 template<typename AXSourceNode, typename AXNodeData>
363 void AXTreeSerializer<AXSourceNode, AXNodeData>::DeleteClientSubtree(
364 AXSourceNode node) {
365 ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
366 if (client_node)
367 DeleteClientSubtree(client_node);
370 template<typename AXSourceNode, typename AXNodeData>
371 void AXTreeSerializer<AXSourceNode, AXNodeData>::DeleteClientSubtree(
372 ClientTreeNode* client_node) {
373 for (size_t i = 0; i < client_node->children.size(); ++i) {
374 client_id_map_.erase(client_node->children[i]->id);
375 DeleteClientSubtree(client_node->children[i]);
376 delete client_node->children[i];
378 client_node->children.clear();
381 template<typename AXSourceNode, typename AXNodeData>
382 void AXTreeSerializer<AXSourceNode, AXNodeData>::SerializeChangedNodes(
383 AXSourceNode node,
384 AXTreeUpdate<AXNodeData>* out_update) {
385 // This method has three responsibilities:
386 // 1. Serialize |node| into an AXNodeData, and append it to
387 // the AXTreeUpdate to be sent to the client.
388 // 2. Determine if |node| has any new children that the client doesn't
389 // know about yet, and call SerializeChangedNodes recursively on those.
390 // 3. Update our internal data structure that keeps track of what nodes
391 // the client knows about.
393 // First, find the ClientTreeNode for this id in our data structure where
394 // we keep track of what accessibility objects the client already knows
395 // about. If we don't find it, then this must be the new root of the
396 // accessibility tree.
397 int id = tree_->GetId(node);
398 ClientTreeNode* client_node = ClientTreeNodeById(id);
399 if (!client_node) {
400 Reset();
401 client_root_ = new ClientTreeNode();
402 client_node = client_root_;
403 client_node->id = id;
404 client_node->parent = NULL;
405 client_id_map_[client_node->id] = client_node;
408 // Iterate over the ids of the children of |node|.
409 // Create a set of the child ids so we can quickly look
410 // up which children are new and which ones were there before.
411 // If we've hit the maximum number of serialized nodes, pretend
412 // this node has no children but keep going so that we get
413 // consistent results.
414 base::hash_set<int32> new_child_ids;
415 std::vector<AXSourceNode> children;
416 if (max_node_count_ == 0 || out_update->nodes.size() < max_node_count_) {
417 tree_->GetChildren(node, &children);
418 } else if (max_node_count_ > 0) {
419 static bool logged_once = false;
420 if (!logged_once) {
421 LOG(WARNING) << "Warning: not serializing AX nodes after a max of "
422 << max_node_count_;
423 logged_once = true;
426 for (size_t i = 0; i < children.size(); ++i) {
427 AXSourceNode& child = children[i];
428 int new_child_id = tree_->GetId(child);
429 new_child_ids.insert(new_child_id);
431 // This is a sanity check - there shouldn't be any reparenting
432 // because we've already handled it above.
433 ClientTreeNode* client_child = client_id_map_[new_child_id];
434 CHECK(!client_child || client_child->parent == client_node);
437 // Go through the old children and delete subtrees for child
438 // ids that are no longer present, and create a map from
439 // id to ClientTreeNode for the rest. It's important to delete
440 // first in a separate pass so that nodes that are reparented
441 // don't end up children of two different parents in the middle
442 // of an update, which can lead to a double-free.
443 base::hash_map<int32, ClientTreeNode*> client_child_id_map;
444 std::vector<ClientTreeNode*> old_children;
445 old_children.swap(client_node->children);
446 for (size_t i = 0; i < old_children.size(); ++i) {
447 ClientTreeNode* old_child = old_children[i];
448 int old_child_id = old_child->id;
449 if (new_child_ids.find(old_child_id) == new_child_ids.end()) {
450 client_id_map_.erase(old_child_id);
451 DeleteClientSubtree(old_child);
452 delete old_child;
453 } else {
454 client_child_id_map[old_child_id] = old_child;
458 // Serialize this node. This fills in all of the fields in
459 // AXNodeData except child_ids, which we handle below.
460 size_t serialized_node_index = out_update->nodes.size();
461 out_update->nodes.push_back(AXNodeData());
463 // Take the address of an element in a vector only within a limited
464 // scope because otherwise the pointer can become invalid if the
465 // vector is resized.
466 AXNodeData* serialized_node = &out_update->nodes[serialized_node_index];
468 tree_->SerializeNode(node, serialized_node);
469 // TODO(dmazzoni/dtseng): Make the serializer not depend on roles to
470 // identify the root.
471 if (serialized_node->id == client_root_->id && !serialized_node->IsRoot())
472 serialized_node->SetRoot();
475 // Iterate over the children, serialize them, and update the ClientTreeNode
476 // data structure to reflect the new tree.
477 std::vector<int32> actual_serialized_node_child_ids;
478 client_node->children.reserve(children.size());
479 for (size_t i = 0; i < children.size(); ++i) {
480 AXSourceNode& child = children[i];
481 int child_id = tree_->GetId(child);
483 // Skip if the child isn't valid.
484 if (!tree_->IsValid(child))
485 continue;
487 // Skip if the same child is included more than once.
488 if (new_child_ids.find(child_id) == new_child_ids.end())
489 continue;
491 new_child_ids.erase(child_id);
492 actual_serialized_node_child_ids.push_back(child_id);
493 if (client_child_id_map.find(child_id) != client_child_id_map.end()) {
494 ClientTreeNode* reused_child = client_child_id_map[child_id];
495 client_node->children.push_back(reused_child);
496 } else {
497 ClientTreeNode* new_child = new ClientTreeNode();
498 new_child->id = child_id;
499 new_child->parent = client_node;
500 client_node->children.push_back(new_child);
501 client_id_map_[child_id] = new_child;
502 SerializeChangedNodes(child, out_update);
506 // Finally, update the child ids of this node to reflect the actual child
507 // ids that were valid during serialization.
508 out_update->nodes[serialized_node_index].child_ids.swap(
509 actual_serialized_node_child_ids);
512 template<typename AXSourceNode, typename AXNodeData>
513 void AXTreeSerializer<AXSourceNode, AXNodeData>::WalkAllDescendants(
514 AXSourceNode node) {
515 std::vector<AXSourceNode> children;
516 tree_->GetChildren(node, &children);
517 for (size_t i = 0; i < children.size(); ++i)
518 WalkAllDescendants(children[i]);
521 } // namespace ui
523 #endif // UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_