blob: 2b454d776dea582f7cf882ffe2661854eabab619 [file] [log] [blame]
[email protected]4b02bbca2013-11-22 08:59:031// 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#ifndef UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
6#define UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
7
avi9c81217b2015-12-24 23:40:058#include <stddef.h>
9#include <stdint.h>
10
thestigcf9519fa2016-08-30 05:50:5411#include <vector>
[email protected]4b02bbca2013-11-22 08:59:0312
13#include "base/containers/hash_tables.h"
14#include "base/logging.h"
dmazzoniac6cdd02015-08-04 21:07:0615#include "ui/accessibility/ax_export.h"
[email protected]4b02bbca2013-11-22 08:59:0316#include "ui/accessibility/ax_tree_source.h"
17#include "ui/accessibility/ax_tree_update.h"
18
19namespace ui {
20
21struct ClientTreeNode;
22
23// AXTreeSerializer is a helper class that serializes incremental
[email protected]d4e273462013-12-04 04:37:5824// updates to an AXTreeSource as a AXTreeUpdate struct.
25// These structs can be unserialized by a client object such as an
26// AXTree. An AXTreeSerializer keeps track of the tree of node ids that its
27// client is aware of so that it will never generate an AXTreeUpdate that
28// results in an invalid tree.
[email protected]4b02bbca2013-11-22 08:59:0329//
[email protected]d4e273462013-12-04 04:37:5830// Every node in the source tree must have an id that's a unique positive
31// integer, the same node must not appear twice.
[email protected]4b02bbca2013-11-22 08:59:0332//
[email protected]d4e273462013-12-04 04:37:5833// Usage:
34//
35// You must call SerializeChanges() every time a node in the tree changes,
dmazzoni329fd012015-10-22 20:05:3536// and send the generated AXTreeUpdate to the client. Changes to the
37// AXTreeData, if any, are also automatically included in the AXTreeUpdate.
[email protected]d4e273462013-12-04 04:37:5838//
39// If a node is added, call SerializeChanges on its parent.
40// If a node is removed, call SerializeChanges on its parent.
41// If a whole new subtree is added, just call SerializeChanges on its root.
42// If the root of the tree changes, call SerializeChanges on the new root.
43//
44// AXTreeSerializer will avoid re-serializing nodes that do not change.
45// For example, if node 1 has children 2, 3, 4, 5 and then child 2 is
46// removed and a new child 6 is added, the AXTreeSerializer will only
47// update nodes 1 and 6 (and any children of node 6 recursively). It will
48// assume that nodes 3, 4, and 5 are not modified unless you explicitly
49// call SerializeChanges() on them.
50//
51// As long as the source tree has unique ids for every node and no loops,
52// and as long as every update is applied to the client tree, AXTreeSerializer
53// will continue to work. If the source tree makes a change but fails to
54// call SerializeChanges properly, the trees may get out of sync - but
55// because AXTreeSerializer always keeps track of what updates it's sent,
56// it will never send an invalid update and the client tree will not break,
57// it just may not contain all of the changes.
dmazzoni329fd012015-10-22 20:05:3558template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
[email protected]4b02bbca2013-11-22 08:59:0359class AXTreeSerializer {
60 public:
dmazzoni329fd012015-10-22 20:05:3561 explicit AXTreeSerializer(
62 AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree);
[email protected]d4e273462013-12-04 04:37:5863 ~AXTreeSerializer();
[email protected]4b02bbca2013-11-22 08:59:0364
65 // Throw out the internal state that keeps track of the nodes the client
66 // knows about. This has the effect that the next update will send the
67 // entire tree over because it assumes the client knows nothing.
68 void Reset();
69
dmazzonia91a911b2015-07-16 21:11:5870 // Sets the maximum number of nodes that will be serialized, or zero
71 // for no maximum. This is not a hard maximum - once it hits or
72 // exceeds this maximum it stops walking the children of nodes, but
73 // it may exceed this value a bit in order to create a consistent
74 // tree.
75 void set_max_node_count(size_t max_node_count) {
76 max_node_count_ = max_node_count;
77 }
78
[email protected]4b02bbca2013-11-22 08:59:0379 // Serialize all changes to |node| and append them to |out_update|.
dmazzoni8f5c3342016-02-16 20:11:1680 // Returns true on success. On failure, returns false and calls Reset();
81 // this only happens when the source tree has a problem like duplicate
82 // ids or changing during serialization.
83 bool SerializeChanges(AXSourceNode node,
dmazzoni329fd012015-10-22 20:05:3584 AXTreeUpdateBase<AXNodeData, AXTreeData>* out_update);
[email protected]4b02bbca2013-11-22 08:59:0385
[email protected]e736e81b2014-02-24 07:15:5886 // Delete the client subtree for this node, ensuring that the subtree
87 // is re-serialized.
88 void DeleteClientSubtree(AXSourceNode node);
89
[email protected]d4e273462013-12-04 04:37:5890 // Only for unit testing. Normally this class relies on getting a call
91 // to SerializeChanges() every time the source tree changes. For unit
92 // testing, it's convenient to create a static AXTree for the initial
93 // state and then call ChangeTreeSourceForTesting and then SerializeChanges
94 // to simulate the changes you'd get if a tree changed from the initial
95 // state to the second tree's state.
dmazzoniac6cdd02015-08-04 21:07:0696 void ChangeTreeSourceForTesting(
dmazzoni329fd012015-10-22 20:05:3597 AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* new_tree);
[email protected]d4e273462013-12-04 04:37:5898
[email protected]4b02bbca2013-11-22 08:59:0399 private:
[email protected]d4e273462013-12-04 04:37:58100 // Return the least common ancestor of a node in the source tree
101 // and a node in the client tree, or NULL if there is no such node.
102 // The least common ancestor is the closest ancestor to |node| (which
103 // may be |node| itself) that's in both the source tree and client tree,
104 // and for which both the source and client tree agree on their ancestor
105 // chain up to the root.
106 //
107 // Example 1:
108 //
[email protected]eef789582013-12-04 05:15:31109 // Client Tree Source tree |
110 // 1 1 |
111 // / \ / \ |
112 // 2 3 2 4 |
[email protected]d4e273462013-12-04 04:37:58113 //
114 // LCA(source node 2, client node 2) is node 2.
115 // LCA(source node 3, client node 4) is node 1.
116 //
117 // Example 2:
118 //
[email protected]eef789582013-12-04 05:15:31119 // Client Tree Source tree |
120 // 1 1 |
121 // / \ / \ |
122 // 2 3 2 3 |
123 // / \ / / |
124 // 4 7 8 4 |
125 // / \ / \ |
126 // 5 6 5 6 |
[email protected]d4e273462013-12-04 04:37:58127 //
128 // LCA(source node 8, client node 7) is node 2.
129 // LCA(source node 5, client node 5) is node 1.
130 // It's not node 5, because the two trees disagree on the parent of
131 // node 4, so the LCA is the first ancestor both trees agree on.
[email protected]e736e81b2014-02-24 07:15:58132 AXSourceNode LeastCommonAncestor(AXSourceNode node,
133 ClientTreeNode* client_node);
[email protected]d4e273462013-12-04 04:37:58134
135 // Return the least common ancestor of |node| that's in the client tree.
136 // This just walks up the ancestors of |node| until it finds a node that's
137 // also in the client tree, and then calls LeastCommonAncestor on the
138 // source node and client node.
[email protected]e736e81b2014-02-24 07:15:58139 AXSourceNode LeastCommonAncestor(AXSourceNode node);
[email protected]d4e273462013-12-04 04:37:58140
141 // Walk the subtree rooted at |node| and return true if any nodes that
[email protected]e736e81b2014-02-24 07:15:58142 // would be updated are being reparented. If so, update |out_lca| to point
[email protected]d4e273462013-12-04 04:37:58143 // to the least common ancestor of the previous LCA and the previous
144 // parent of the node being reparented.
[email protected]e736e81b2014-02-24 07:15:58145 bool AnyDescendantWasReparented(AXSourceNode node,
146 AXSourceNode* out_lca);
[email protected]d4e273462013-12-04 04:37:58147
avi9c81217b2015-12-24 23:40:05148 ClientTreeNode* ClientTreeNodeById(int32_t id);
[email protected]d4e273462013-12-04 04:37:58149
[email protected]4b02bbca2013-11-22 08:59:03150 // Delete the given client tree node and recursively delete all of its
151 // descendants.
152 void DeleteClientSubtree(ClientTreeNode* client_node);
153
[email protected]d4e273462013-12-04 04:37:58154 // Helper function, called recursively with each new node to serialize.
dmazzoni8f5c3342016-02-16 20:11:16155 bool SerializeChangedNodes(
dmazzoni329fd012015-10-22 20:05:35156 AXSourceNode node,
157 AXTreeUpdateBase<AXNodeData, AXTreeData>* out_update);
[email protected]4b02bbca2013-11-22 08:59:03158
dmazzonif3bcf1be2015-06-22 22:37:11159 // Visit all of the descendants of |node| once.
160 void WalkAllDescendants(AXSourceNode node);
161
[email protected]4b02bbca2013-11-22 08:59:03162 // The tree source.
dmazzoni329fd012015-10-22 20:05:35163 AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree_;
164
165 // The tree data most recently sent to the client.
166 AXTreeData client_tree_data_;
[email protected]4b02bbca2013-11-22 08:59:03167
168 // Our representation of the client tree.
169 ClientTreeNode* client_root_;
170
171 // A map from IDs to nodes in the client tree.
avi9c81217b2015-12-24 23:40:05172 base::hash_map<int32_t, ClientTreeNode*> client_id_map_;
dmazzonia91a911b2015-07-16 21:11:58173
174 // The maximum number of nodes to serialize in a given call to
175 // SerializeChanges, or 0 if there's no maximum.
176 size_t max_node_count_;
[email protected]4b02bbca2013-11-22 08:59:03177};
178
179// In order to keep track of what nodes the client knows about, we keep a
180// representation of the client tree - just IDs and parent/child
181// relationships.
182struct AX_EXPORT ClientTreeNode {
183 ClientTreeNode();
184 virtual ~ClientTreeNode();
avi9c81217b2015-12-24 23:40:05185 int32_t id;
[email protected]4b02bbca2013-11-22 08:59:03186 ClientTreeNode* parent;
187 std::vector<ClientTreeNode*> children;
188};
189
dmazzoni329fd012015-10-22 20:05:35190template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
191AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::AXTreeSerializer(
192 AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* tree)
193 : tree_(tree), client_root_(NULL), max_node_count_(0) {}
[email protected]4b02bbca2013-11-22 08:59:03194
dmazzoni329fd012015-10-22 20:05:35195template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
196AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::~AXTreeSerializer() {
[email protected]d4e273462013-12-04 04:37:58197 Reset();
198}
199
dmazzoni329fd012015-10-22 20:05:35200template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
201void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::Reset() {
202 client_tree_data_ = AXTreeData();
[email protected]949df1c2014-04-03 15:25:30203 if (!client_root_)
204 return;
205
206 DeleteClientSubtree(client_root_);
207 client_id_map_.erase(client_root_->id);
208 delete client_root_;
209 client_root_ = NULL;
[email protected]4b02bbca2013-11-22 08:59:03210}
211
dmazzoni329fd012015-10-22 20:05:35212template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
213void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
214 ChangeTreeSourceForTesting(
215 AXTreeSource<AXSourceNode, AXNodeData, AXTreeData>* new_tree) {
[email protected]d4e273462013-12-04 04:37:58216 tree_ = new_tree;
217}
218
dmazzoni329fd012015-10-22 20:05:35219template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
220AXSourceNode
221AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::LeastCommonAncestor(
222 AXSourceNode node,
223 ClientTreeNode* client_node) {
[email protected]e736e81b2014-02-24 07:15:58224 if (!tree_->IsValid(node) || client_node == NULL)
225 return tree_->GetNull();
[email protected]d4e273462013-12-04 04:37:58226
[email protected]e736e81b2014-02-24 07:15:58227 std::vector<AXSourceNode> ancestors;
228 while (tree_->IsValid(node)) {
[email protected]d4e273462013-12-04 04:37:58229 ancestors.push_back(node);
230 node = tree_->GetParent(node);
231 }
232
233 std::vector<ClientTreeNode*> client_ancestors;
234 while (client_node) {
235 client_ancestors.push_back(client_node);
236 client_node = client_node->parent;
237 }
238
239 // Start at the root. Keep going until the source ancestor chain and
240 // client ancestor chain disagree. The last node before they disagree
241 // is the LCA.
[email protected]e736e81b2014-02-24 07:15:58242 AXSourceNode lca = tree_->GetNull();
[email protected]d4e273462013-12-04 04:37:58243 int source_index = static_cast<int>(ancestors.size() - 1);
244 int client_index = static_cast<int>(client_ancestors.size() - 1);
245 while (source_index >= 0 && client_index >= 0) {
246 if (tree_->GetId(ancestors[source_index]) !=
247 client_ancestors[client_index]->id) {
248 return lca;
249 }
250 lca = ancestors[source_index];
251 source_index--;
252 client_index--;
253 }
254 return lca;
255}
256
dmazzoni329fd012015-10-22 20:05:35257template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
258AXSourceNode
259AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::LeastCommonAncestor(
[email protected]e736e81b2014-02-24 07:15:58260 AXSourceNode node) {
[email protected]d4e273462013-12-04 04:37:58261 // Walk up the tree until the source node's id also exists in the
262 // client tree, then call LeastCommonAncestor on those two nodes.
263 ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
[email protected]e736e81b2014-02-24 07:15:58264 while (tree_->IsValid(node) && !client_node) {
[email protected]d4e273462013-12-04 04:37:58265 node = tree_->GetParent(node);
[email protected]e736e81b2014-02-24 07:15:58266 if (tree_->IsValid(node))
[email protected]d4e273462013-12-04 04:37:58267 client_node = ClientTreeNodeById(tree_->GetId(node));
268 }
269 return LeastCommonAncestor(node, client_node);
270}
271
dmazzoni329fd012015-10-22 20:05:35272template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
273bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
274 AnyDescendantWasReparented(AXSourceNode node, AXSourceNode* out_lca) {
[email protected]d4e273462013-12-04 04:37:58275 bool result = false;
276 int id = tree_->GetId(node);
[email protected]e736e81b2014-02-24 07:15:58277 std::vector<AXSourceNode> children;
278 tree_->GetChildren(node, &children);
279 for (size_t i = 0; i < children.size(); ++i) {
280 AXSourceNode& child = children[i];
[email protected]d4e273462013-12-04 04:37:58281 int child_id = tree_->GetId(child);
282 ClientTreeNode* client_child = ClientTreeNodeById(child_id);
283 if (client_child) {
284 if (!client_child->parent) {
285 // If the client child has no parent, it must have been the
286 // previous root node, so there is no LCA and we can exit early.
[email protected]e736e81b2014-02-24 07:15:58287 *out_lca = tree_->GetNull();
[email protected]d4e273462013-12-04 04:37:58288 return true;
289 } else if (client_child->parent->id != id) {
290 // If the client child's parent is not this node, update the LCA
291 // and return true (reparenting was found).
[email protected]e736e81b2014-02-24 07:15:58292 *out_lca = LeastCommonAncestor(*out_lca, client_child);
[email protected]d4e273462013-12-04 04:37:58293 result = true;
294 } else {
295 // This child is already in the client tree, we won't
296 // recursively serialize it so we don't need to check this
297 // subtree recursively for reparenting.
298 continue;
299 }
300 }
301
302 // This is a new child or reparented child, check it recursively.
[email protected]e736e81b2014-02-24 07:15:58303 if (AnyDescendantWasReparented(child, out_lca))
[email protected]d4e273462013-12-04 04:37:58304 result = true;
305 }
306 return result;
307}
308
dmazzoni329fd012015-10-22 20:05:35309template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
dmazzoniac6cdd02015-08-04 21:07:06310ClientTreeNode*
dmazzoni329fd012015-10-22 20:05:35311AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::ClientTreeNodeById(
avi9c81217b2015-12-24 23:40:05312 int32_t id) {
313 base::hash_map<int32_t, ClientTreeNode*>::iterator iter =
[email protected]d4e273462013-12-04 04:37:58314 client_id_map_.find(id);
315 if (iter != client_id_map_.end())
316 return iter->second;
317 else
318 return NULL;
319}
320
dmazzoni329fd012015-10-22 20:05:35321template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
dmazzoni8f5c3342016-02-16 20:11:16322bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::SerializeChanges(
[email protected]e736e81b2014-02-24 07:15:58323 AXSourceNode node,
dmazzoni329fd012015-10-22 20:05:35324 AXTreeUpdateBase<AXNodeData, AXTreeData>* out_update) {
325 // Send the tree data if it's changed since the last update.
dmazzonia6bc51332016-06-17 03:42:46326 AXTreeData new_tree_data;
327 if (tree_->GetTreeData(&new_tree_data) &&
328 new_tree_data != client_tree_data_) {
dmazzoni329fd012015-10-22 20:05:35329 out_update->has_tree_data = true;
330 out_update->tree_data = new_tree_data;
331 client_tree_data_ = new_tree_data;
332 }
333
[email protected]d4e273462013-12-04 04:37:58334 // If the node isn't in the client tree, we need to serialize starting
335 // with the LCA.
[email protected]e736e81b2014-02-24 07:15:58336 AXSourceNode lca = LeastCommonAncestor(node);
[email protected]d4e273462013-12-04 04:37:58337
dmazzoni7a6d7e72015-03-02 07:39:06338 // This loop computes the least common ancestor that includes the old
339 // and new parents of any nodes that have been reparented, and clears the
340 // whole client subtree of that LCA if necessary. If we do end up clearing
341 // any client nodes, keep looping because we have to search for more
342 // nodes that may have been reparented from this new LCA.
343 bool need_delete;
344 do {
345 need_delete = false;
346 if (client_root_) {
347 if (tree_->IsValid(lca)) {
348 // Check for any reparenting within this subtree - if there is
349 // any, we need to delete and reserialize the whole subtree
350 // that contains the old and new parents of the reparented node.
351 if (AnyDescendantWasReparented(lca, &lca))
352 need_delete = true;
[email protected]d4e273462013-12-04 04:37:58353 }
dmazzoni7a6d7e72015-03-02 07:39:06354
355 if (!tree_->IsValid(lca)) {
356 // If there's no LCA, just tell the client to destroy the whole
357 // tree and then we'll serialize everything from the new root.
358 out_update->node_id_to_clear = client_root_->id;
359 Reset();
360 } else if (need_delete) {
361 // Otherwise, if we need to reserialize a subtree, first we need
362 // to delete those nodes in our client tree so that
363 // SerializeChangedNodes() will be sure to send them again.
364 out_update->node_id_to_clear = tree_->GetId(lca);
365 ClientTreeNode* client_lca = ClientTreeNodeById(tree_->GetId(lca));
366 CHECK(client_lca);
367 DeleteClientSubtree(client_lca);
368 }
[email protected]d4e273462013-12-04 04:37:58369 }
dmazzoni7a6d7e72015-03-02 07:39:06370 } while (need_delete);
[email protected]d4e273462013-12-04 04:37:58371
372 // Serialize from the LCA, or from the root if there isn't one.
[email protected]e736e81b2014-02-24 07:15:58373 if (!tree_->IsValid(lca))
[email protected]d4e273462013-12-04 04:37:58374 lca = tree_->GetRoot();
dmazzonif3bcf1be2015-06-22 22:37:11375
376 // Work around flaky source trees where nodes don't figure out their
377 // correct parent/child relationships until you walk the whole tree once.
378 // Covered by this test in the content_browsertests suite:
379 // DumpAccessibilityTreeTest.AccessibilityAriaOwns.
380 WalkAllDescendants(lca);
381
dmazzoni8f5c3342016-02-16 20:11:16382 return SerializeChangedNodes(lca, out_update);
[email protected]4b02bbca2013-11-22 08:59:03383}
384
dmazzoni329fd012015-10-22 20:05:35385template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
386void AXTreeSerializer<AXSourceNode,
387 AXNodeData,
388 AXTreeData>::DeleteClientSubtree(AXSourceNode node) {
[email protected]e736e81b2014-02-24 07:15:58389 ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node));
390 if (client_node)
391 DeleteClientSubtree(client_node);
392}
393
dmazzoni329fd012015-10-22 20:05:35394template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
395void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
396 DeleteClientSubtree(ClientTreeNode* client_node) {
[email protected]4b02bbca2013-11-22 08:59:03397 for (size_t i = 0; i < client_node->children.size(); ++i) {
398 client_id_map_.erase(client_node->children[i]->id);
399 DeleteClientSubtree(client_node->children[i]);
[email protected]949df1c2014-04-03 15:25:30400 delete client_node->children[i];
[email protected]4b02bbca2013-11-22 08:59:03401 }
402 client_node->children.clear();
403}
404
dmazzoni329fd012015-10-22 20:05:35405template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
dmazzoni8f5c3342016-02-16 20:11:16406bool AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::
dmazzoni329fd012015-10-22 20:05:35407 SerializeChangedNodes(
408 AXSourceNode node,
409 AXTreeUpdateBase<AXNodeData, AXTreeData>* out_update) {
[email protected]4b02bbca2013-11-22 08:59:03410 // This method has three responsibilities:
411 // 1. Serialize |node| into an AXNodeData, and append it to
412 // the AXTreeUpdate to be sent to the client.
413 // 2. Determine if |node| has any new children that the client doesn't
414 // know about yet, and call SerializeChangedNodes recursively on those.
415 // 3. Update our internal data structure that keeps track of what nodes
416 // the client knows about.
417
418 // First, find the ClientTreeNode for this id in our data structure where
419 // we keep track of what accessibility objects the client already knows
420 // about. If we don't find it, then this must be the new root of the
421 // accessibility tree.
[email protected]d4e273462013-12-04 04:37:58422 int id = tree_->GetId(node);
423 ClientTreeNode* client_node = ClientTreeNodeById(id);
424 if (!client_node) {
[email protected]949df1c2014-04-03 15:25:30425 Reset();
[email protected]4b02bbca2013-11-22 08:59:03426 client_root_ = new ClientTreeNode();
427 client_node = client_root_;
428 client_node->id = id;
429 client_node->parent = NULL;
430 client_id_map_[client_node->id] = client_node;
431 }
432
433 // Iterate over the ids of the children of |node|.
434 // Create a set of the child ids so we can quickly look
435 // up which children are new and which ones were there before.
dmazzonia91a911b2015-07-16 21:11:58436 // If we've hit the maximum number of serialized nodes, pretend
437 // this node has no children but keep going so that we get
438 // consistent results.
avi9c81217b2015-12-24 23:40:05439 base::hash_set<int32_t> new_child_ids;
[email protected]e736e81b2014-02-24 07:15:58440 std::vector<AXSourceNode> children;
dmazzonia91a911b2015-07-16 21:11:58441 if (max_node_count_ == 0 || out_update->nodes.size() < max_node_count_) {
442 tree_->GetChildren(node, &children);
443 } else if (max_node_count_ > 0) {
444 static bool logged_once = false;
445 if (!logged_once) {
446 LOG(WARNING) << "Warning: not serializing AX nodes after a max of "
447 << max_node_count_;
448 logged_once = true;
449 }
450 }
[email protected]e736e81b2014-02-24 07:15:58451 for (size_t i = 0; i < children.size(); ++i) {
452 AXSourceNode& child = children[i];
[email protected]4b02bbca2013-11-22 08:59:03453 int new_child_id = tree_->GetId(child);
454 new_child_ids.insert(new_child_id);
455
dmazzoni8f5c3342016-02-16 20:11:16456 // There shouldn't be any reparenting because we've already handled it
457 // above. If this happens, reset and return an error.
[email protected]4b02bbca2013-11-22 08:59:03458 ClientTreeNode* client_child = client_id_map_[new_child_id];
dmazzoni8f5c3342016-02-16 20:11:16459 if (client_child && client_child->parent != client_node) {
460 Reset();
461 return false;
462 }
[email protected]4b02bbca2013-11-22 08:59:03463 }
464
465 // Go through the old children and delete subtrees for child
466 // ids that are no longer present, and create a map from
467 // id to ClientTreeNode for the rest. It's important to delete
468 // first in a separate pass so that nodes that are reparented
469 // don't end up children of two different parents in the middle
470 // of an update, which can lead to a double-free.
avi9c81217b2015-12-24 23:40:05471 base::hash_map<int32_t, ClientTreeNode*> client_child_id_map;
[email protected]4b02bbca2013-11-22 08:59:03472 std::vector<ClientTreeNode*> old_children;
473 old_children.swap(client_node->children);
474 for (size_t i = 0; i < old_children.size(); ++i) {
475 ClientTreeNode* old_child = old_children[i];
476 int old_child_id = old_child->id;
477 if (new_child_ids.find(old_child_id) == new_child_ids.end()) {
478 client_id_map_.erase(old_child_id);
479 DeleteClientSubtree(old_child);
[email protected]949df1c2014-04-03 15:25:30480 delete old_child;
[email protected]4b02bbca2013-11-22 08:59:03481 } else {
482 client_child_id_map[old_child_id] = old_child;
483 }
484 }
485
486 // Serialize this node. This fills in all of the fields in
487 // AXNodeData except child_ids, which we handle below.
dmazzoni8dc07f02015-06-04 00:24:59488 size_t serialized_node_index = out_update->nodes.size();
[email protected]4b02bbca2013-11-22 08:59:03489 out_update->nodes.push_back(AXNodeData());
dmazzoni8dc07f02015-06-04 00:24:59490 {
491 // Take the address of an element in a vector only within a limited
492 // scope because otherwise the pointer can become invalid if the
493 // vector is resized.
494 AXNodeData* serialized_node = &out_update->nodes[serialized_node_index];
[email protected]4b02bbca2013-11-22 08:59:03495
dmazzoni8dc07f02015-06-04 00:24:59496 tree_->SerializeNode(node, serialized_node);
dmazzoni67b4db22016-04-23 00:40:04497 if (serialized_node->id == client_root_->id)
498 out_update->root_id = serialized_node->id;
dmazzoni8dc07f02015-06-04 00:24:59499 }
500
501 // Iterate over the children, serialize them, and update the ClientTreeNode
[email protected]4b02bbca2013-11-22 08:59:03502 // data structure to reflect the new tree.
avi9c81217b2015-12-24 23:40:05503 std::vector<int32_t> actual_serialized_node_child_ids;
[email protected]e736e81b2014-02-24 07:15:58504 client_node->children.reserve(children.size());
505 for (size_t i = 0; i < children.size(); ++i) {
506 AXSourceNode& child = children[i];
[email protected]4b02bbca2013-11-22 08:59:03507 int child_id = tree_->GetId(child);
508
dmazzoni8dc07f02015-06-04 00:24:59509 // Skip if the child isn't valid.
510 if (!tree_->IsValid(child))
511 continue;
512
513 // Skip if the same child is included more than once.
[email protected]4b02bbca2013-11-22 08:59:03514 if (new_child_ids.find(child_id) == new_child_ids.end())
515 continue;
516
517 new_child_ids.erase(child_id);
dmazzoni8dc07f02015-06-04 00:24:59518 actual_serialized_node_child_ids.push_back(child_id);
[email protected]4b02bbca2013-11-22 08:59:03519 if (client_child_id_map.find(child_id) != client_child_id_map.end()) {
520 ClientTreeNode* reused_child = client_child_id_map[child_id];
521 client_node->children.push_back(reused_child);
522 } else {
523 ClientTreeNode* new_child = new ClientTreeNode();
524 new_child->id = child_id;
525 new_child->parent = client_node;
526 client_node->children.push_back(new_child);
527 client_id_map_[child_id] = new_child;
dmazzoni8f5c3342016-02-16 20:11:16528 if (!SerializeChangedNodes(child, out_update))
529 return false;
[email protected]4b02bbca2013-11-22 08:59:03530 }
531 }
532
dmazzoni8dc07f02015-06-04 00:24:59533 // Finally, update the child ids of this node to reflect the actual child
534 // ids that were valid during serialization.
535 out_update->nodes[serialized_node_index].child_ids.swap(
536 actual_serialized_node_child_ids);
dmazzoni8f5c3342016-02-16 20:11:16537
538 return true;
[email protected]4b02bbca2013-11-22 08:59:03539}
540
dmazzoni329fd012015-10-22 20:05:35541template <typename AXSourceNode, typename AXNodeData, typename AXTreeData>
542void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::WalkAllDescendants(
dmazzonif3bcf1be2015-06-22 22:37:11543 AXSourceNode node) {
544 std::vector<AXSourceNode> children;
545 tree_->GetChildren(node, &children);
546 for (size_t i = 0; i < children.size(); ++i)
547 WalkAllDescendants(children[i]);
548}
549
[email protected]4b02bbca2013-11-22 08:59:03550} // namespace ui
551
552#endif // UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_