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 #ifndef UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_ 6 #define UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_ 7 8 #include <set> 9 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" 15 16 namespace ui { 17 18 struct ClientTreeNode; 19 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. 26 // 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. 29 // 30 // Usage: 31 // 32 // You must call SerializeChanges() every time a node in the tree changes, 33 // and send the generated AXTreeUpdate to the client. 34 // 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. 39 // 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. 46 // 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<class AXSourceNode> 55 class AXTreeSerializer { 56 public: 57 explicit AXTreeSerializer(AXTreeSource<AXSourceNode>* tree); 58 ~AXTreeSerializer(); 59 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(); 64 65 // Serialize all changes to |node| and append them to |out_update|. 66 void SerializeChanges(const AXSourceNode* node, 67 AXTreeUpdate* out_update); 68 69 // Only for unit testing. Normally this class relies on getting a call 70 // to SerializeChanges() every time the source tree changes. For unit 71 // testing, it's convenient to create a static AXTree for the initial 72 // state and then call ChangeTreeSourceForTesting and then SerializeChanges 73 // to simulate the changes you'd get if a tree changed from the initial 74 // state to the second tree's state. 75 void ChangeTreeSourceForTesting(AXTreeSource<AXSourceNode>* new_tree); 76 77 private: 78 // Return the least common ancestor of a node in the source tree 79 // and a node in the client tree, or NULL if there is no such node. 80 // The least common ancestor is the closest ancestor to |node| (which 81 // may be |node| itself) that's in both the source tree and client tree, 82 // and for which both the source and client tree agree on their ancestor 83 // chain up to the root. 84 // 85 // Example 1: 86 // 87 // Client Tree Source tree | 88 // 1 1 | 89 // / \ / \ | 90 // 2 3 2 4 | 91 // 92 // LCA(source node 2, client node 2) is node 2. 93 // LCA(source node 3, client node 4) is node 1. 94 // 95 // Example 2: 96 // 97 // Client Tree Source tree | 98 // 1 1 | 99 // / \ / \ | 100 // 2 3 2 3 | 101 // / \ / / | 102 // 4 7 8 4 | 103 // / \ / \ | 104 // 5 6 5 6 | 105 // 106 // LCA(source node 8, client node 7) is node 2. 107 // LCA(source node 5, client node 5) is node 1. 108 // It's not node 5, because the two trees disagree on the parent of 109 // node 4, so the LCA is the first ancestor both trees agree on. 110 const AXSourceNode* LeastCommonAncestor(const AXSourceNode* node, 111 ClientTreeNode* client_node); 112 113 // Return the least common ancestor of |node| that's in the client tree. 114 // This just walks up the ancestors of |node| until it finds a node that's 115 // also in the client tree, and then calls LeastCommonAncestor on the 116 // source node and client node. 117 const AXSourceNode* LeastCommonAncestor(const AXSourceNode* node); 118 119 // Walk the subtree rooted at |node| and return true if any nodes that 120 // would be updated are being reparented. If so, update |lca| to point 121 // to the least common ancestor of the previous LCA and the previous 122 // parent of the node being reparented. 123 bool AnyDescendantWasReparented(const AXSourceNode* node, 124 const AXSourceNode** lca); 125 126 ClientTreeNode* ClientTreeNodeById(int32 id); 127 128 // Delete the given client tree node and recursively delete all of its 129 // descendants. 130 void DeleteClientSubtree(ClientTreeNode* client_node); 131 132 // Helper function, called recursively with each new node to serialize. 133 void SerializeChangedNodes(const AXSourceNode* node, 134 AXTreeUpdate* out_update); 135 136 // The tree source. 137 AXTreeSource<AXSourceNode>* tree_; 138 139 // Our representation of the client tree. 140 ClientTreeNode* client_root_; 141 142 // A map from IDs to nodes in the client tree. 143 base::hash_map<int32, ClientTreeNode*> client_id_map_; 144 }; 145 146 // In order to keep track of what nodes the client knows about, we keep a 147 // representation of the client tree - just IDs and parent/child 148 // relationships. 149 struct AX_EXPORT ClientTreeNode { 150 ClientTreeNode(); 151 virtual ~ClientTreeNode(); 152 int32 id; 153 ClientTreeNode* parent; 154 std::vector<ClientTreeNode*> children; 155 }; 156 157 template<class AXSourceNode> 158 AXTreeSerializer<AXSourceNode>::AXTreeSerializer( 159 AXTreeSource<AXSourceNode>* tree) 160 : tree_(tree), 161 client_root_(NULL) { 162 } 163 164 template<class AXSourceNode> 165 AXTreeSerializer<AXSourceNode>::~AXTreeSerializer() { 166 Reset(); 167 } 168 169 template<class AXSourceNode> 170 void AXTreeSerializer<AXSourceNode>::Reset() { 171 if (client_root_) { 172 DeleteClientSubtree(client_root_); 173 client_root_ = NULL; 174 } 175 } 176 177 template<class AXSourceNode> 178 void AXTreeSerializer<AXSourceNode>::ChangeTreeSourceForTesting( 179 AXTreeSource<AXSourceNode>* new_tree) { 180 tree_ = new_tree; 181 } 182 183 template<class AXSourceNode> 184 const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor( 185 const AXSourceNode* node, ClientTreeNode* client_node) { 186 if (node == NULL || client_node == NULL) 187 return NULL; 188 189 std::vector<const AXSourceNode*> ancestors; 190 while (node) { 191 ancestors.push_back(node); 192 node = tree_->GetParent(node); 193 } 194 195 std::vector<ClientTreeNode*> client_ancestors; 196 while (client_node) { 197 client_ancestors.push_back(client_node); 198 client_node = client_node->parent; 199 } 200 201 // Start at the root. Keep going until the source ancestor chain and 202 // client ancestor chain disagree. The last node before they disagree 203 // is the LCA. 204 const AXSourceNode* lca = NULL; 205 int source_index = static_cast<int>(ancestors.size() - 1); 206 int client_index = static_cast<int>(client_ancestors.size() - 1); 207 while (source_index >= 0 && client_index >= 0) { 208 if (tree_->GetId(ancestors[source_index]) != 209 client_ancestors[client_index]->id) { 210 return lca; 211 } 212 lca = ancestors[source_index]; 213 source_index--; 214 client_index--; 215 } 216 return lca; 217 } 218 219 template<class AXSourceNode> 220 const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor( 221 const AXSourceNode* node) { 222 // Walk up the tree until the source node's id also exists in the 223 // client tree, then call LeastCommonAncestor on those two nodes. 224 ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node)); 225 while (node && !client_node) { 226 node = tree_->GetParent(node); 227 if (node) 228 client_node = ClientTreeNodeById(tree_->GetId(node)); 229 } 230 return LeastCommonAncestor(node, client_node); 231 } 232 233 template<class AXSourceNode> 234 bool AXTreeSerializer<AXSourceNode>::AnyDescendantWasReparented( 235 const AXSourceNode* node, const AXSourceNode** lca) { 236 bool result = false; 237 int id = tree_->GetId(node); 238 int child_count = tree_->GetChildCount(node); 239 for (int i = 0; i < child_count; ++i) { 240 const AXSourceNode* child = tree_->GetChildAtIndex(node, i); 241 int child_id = tree_->GetId(child); 242 ClientTreeNode* client_child = ClientTreeNodeById(child_id); 243 if (client_child) { 244 if (!client_child->parent) { 245 // If the client child has no parent, it must have been the 246 // previous root node, so there is no LCA and we can exit early. 247 *lca = NULL; 248 return true; 249 } else if (client_child->parent->id != id) { 250 // If the client child's parent is not this node, update the LCA 251 // and return true (reparenting was found). 252 *lca = LeastCommonAncestor(*lca, client_child); 253 result = true; 254 } else { 255 // This child is already in the client tree, we won't 256 // recursively serialize it so we don't need to check this 257 // subtree recursively for reparenting. 258 continue; 259 } 260 } 261 262 // This is a new child or reparented child, check it recursively. 263 if (AnyDescendantWasReparented(child, lca)) 264 result = true; 265 } 266 return result; 267 } 268 269 template<class AXSourceNode> 270 ClientTreeNode* AXTreeSerializer<AXSourceNode>::ClientTreeNodeById(int32 id) { 271 base::hash_map<int32, ClientTreeNode*>::iterator iter = 272 client_id_map_.find(id); 273 if (iter != client_id_map_.end()) 274 return iter->second; 275 else 276 return NULL; 277 } 278 279 template<class AXSourceNode> 280 void AXTreeSerializer<AXSourceNode>::SerializeChanges( 281 const AXSourceNode* node, 282 AXTreeUpdate* out_update) { 283 // If the node isn't in the client tree, we need to serialize starting 284 // with the LCA. 285 const AXSourceNode* lca = LeastCommonAncestor(node); 286 287 if (client_root_) { 288 // If the LCA is anything other than the node itself, tell the 289 // client to first delete the subtree rooted at the LCA. 290 bool need_delete = (lca != node); 291 if (lca) { 292 // Check for any reparenting within this subtree - if there is 293 // any, we need to delete and reserialize the whole subtree 294 // that contains the old and new parents of the reparented node. 295 if (AnyDescendantWasReparented(lca, &lca)) 296 need_delete = true; 297 } 298 299 if (lca == NULL) { 300 // If there's no LCA, just tell the client to destroy the whole 301 // tree and then we'll serialize everything from the new root. 302 out_update->node_id_to_clear = client_root_->id; 303 DeleteClientSubtree(client_root_); 304 client_id_map_.erase(client_root_->id); 305 client_root_ = NULL; 306 } else if (need_delete) { 307 // Otherwise, if we need to reserialize a subtree, first we need 308 // to delete those nodes in our client tree so that 309 // SerializeChangedNodes() will be sure to send them again. 310 out_update->node_id_to_clear = tree_->GetId(lca); 311 ClientTreeNode* client_lca = ClientTreeNodeById(tree_->GetId(lca)); 312 CHECK(client_lca); 313 for (size_t i = 0; i < client_lca->children.size(); ++i) { 314 client_id_map_.erase(client_lca->children[i]->id); 315 DeleteClientSubtree(client_lca->children[i]); 316 } 317 client_lca->children.clear(); 318 } 319 } 320 321 // Serialize from the LCA, or from the root if there isn't one. 322 if (!lca) 323 lca = tree_->GetRoot(); 324 SerializeChangedNodes(lca, out_update); 325 } 326 327 template<class AXSourceNode> 328 void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree( 329 ClientTreeNode* client_node) { 330 for (size_t i = 0; i < client_node->children.size(); ++i) { 331 client_id_map_.erase(client_node->children[i]->id); 332 DeleteClientSubtree(client_node->children[i]); 333 } 334 client_node->children.clear(); 335 } 336 337 template<class AXSourceNode> 338 void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes( 339 const AXSourceNode* node, 340 AXTreeUpdate* out_update) { 341 // This method has three responsibilities: 342 // 1. Serialize |node| into an AXNodeData, and append it to 343 // the AXTreeUpdate to be sent to the client. 344 // 2. Determine if |node| has any new children that the client doesn't 345 // know about yet, and call SerializeChangedNodes recursively on those. 346 // 3. Update our internal data structure that keeps track of what nodes 347 // the client knows about. 348 349 // First, find the ClientTreeNode for this id in our data structure where 350 // we keep track of what accessibility objects the client already knows 351 // about. If we don't find it, then this must be the new root of the 352 // accessibility tree. 353 int id = tree_->GetId(node); 354 ClientTreeNode* client_node = ClientTreeNodeById(id); 355 if (!client_node) { 356 if (client_root_) { 357 client_id_map_.erase(client_root_->id); 358 DeleteClientSubtree(client_root_); 359 } 360 client_root_ = new ClientTreeNode(); 361 client_node = client_root_; 362 client_node->id = id; 363 client_node->parent = NULL; 364 client_id_map_[client_node->id] = client_node; 365 } 366 367 // Iterate over the ids of the children of |node|. 368 // Create a set of the child ids so we can quickly look 369 // up which children are new and which ones were there before. 370 base::hash_set<int32> new_child_ids; 371 int child_count = tree_->GetChildCount(node); 372 for (int i = 0; i < child_count; ++i) { 373 AXSourceNode* child = tree_->GetChildAtIndex(node, i); 374 int new_child_id = tree_->GetId(child); 375 new_child_ids.insert(new_child_id); 376 377 // This is a sanity check - there shouldn't be any reparenting 378 // because we've already handled it above. 379 ClientTreeNode* client_child = client_id_map_[new_child_id]; 380 CHECK(!client_child || client_child->parent == client_node); 381 } 382 383 // Go through the old children and delete subtrees for child 384 // ids that are no longer present, and create a map from 385 // id to ClientTreeNode for the rest. It's important to delete 386 // first in a separate pass so that nodes that are reparented 387 // don't end up children of two different parents in the middle 388 // of an update, which can lead to a double-free. 389 base::hash_map<int32, ClientTreeNode*> client_child_id_map; 390 std::vector<ClientTreeNode*> old_children; 391 old_children.swap(client_node->children); 392 for (size_t i = 0; i < old_children.size(); ++i) { 393 ClientTreeNode* old_child = old_children[i]; 394 int old_child_id = old_child->id; 395 if (new_child_ids.find(old_child_id) == new_child_ids.end()) { 396 client_id_map_.erase(old_child_id); 397 DeleteClientSubtree(old_child); 398 } else { 399 client_child_id_map[old_child_id] = old_child; 400 } 401 } 402 403 // Serialize this node. This fills in all of the fields in 404 // AXNodeData except child_ids, which we handle below. 405 out_update->nodes.push_back(AXNodeData()); 406 AXNodeData* serialized_node = &out_update->nodes.back(); 407 tree_->SerializeNode(node, serialized_node); 408 if (serialized_node->id == client_root_->id) 409 serialized_node->role = AX_ROLE_ROOT_WEB_AREA; 410 serialized_node->child_ids.clear(); 411 412 // Iterate over the children, make note of the ones that are new 413 // and need to be serialized, and update the ClientTreeNode 414 // data structure to reflect the new tree. 415 std::vector<AXSourceNode*> children_to_serialize; 416 client_node->children.reserve(child_count); 417 for (int i = 0; i < child_count; ++i) { 418 AXSourceNode* child = tree_->GetChildAtIndex(node, i); 419 int child_id = tree_->GetId(child); 420 421 // No need to do anything more with children that aren't new; 422 // the client will reuse its existing object. 423 if (new_child_ids.find(child_id) == new_child_ids.end()) 424 continue; 425 426 new_child_ids.erase(child_id); 427 serialized_node->child_ids.push_back(child_id); 428 if (client_child_id_map.find(child_id) != client_child_id_map.end()) { 429 ClientTreeNode* reused_child = client_child_id_map[child_id]; 430 client_node->children.push_back(reused_child); 431 } else { 432 ClientTreeNode* new_child = new ClientTreeNode(); 433 new_child->id = child_id; 434 new_child->parent = client_node; 435 client_node->children.push_back(new_child); 436 client_id_map_[child_id] = new_child; 437 children_to_serialize.push_back(child); 438 } 439 } 440 441 // Serialize all of the new children, recursively. 442 for (size_t i = 0; i < children_to_serialize.size(); ++i) 443 SerializeChangedNodes(children_to_serialize[i], out_update); 444 } 445 446 } // namespace ui 447 448 #endif // UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_ 449