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