diff options
Diffstat (limited to 'chromium/ui/accessibility/ax_tree_serializer.h')
-rw-r--r-- | chromium/ui/accessibility/ax_tree_serializer.h | 149 |
1 files changed, 83 insertions, 66 deletions
diff --git a/chromium/ui/accessibility/ax_tree_serializer.h b/chromium/ui/accessibility/ax_tree_serializer.h index e6049964c76..f1cbfcea105 100644 --- a/chromium/ui/accessibility/ax_tree_serializer.h +++ b/chromium/ui/accessibility/ax_tree_serializer.h @@ -51,7 +51,7 @@ struct ClientTreeNode; // because AXTreeSerializer always keeps track of what updates it's sent, // it will never send an invalid update and the client tree will not break, // it just may not contain all of the changes. -template<class AXSourceNode> +template<typename AXSourceNode> class AXTreeSerializer { public: explicit AXTreeSerializer(AXTreeSource<AXSourceNode>* tree); @@ -63,9 +63,13 @@ class AXTreeSerializer { void Reset(); // Serialize all changes to |node| and append them to |out_update|. - void SerializeChanges(const AXSourceNode* node, + void SerializeChanges(AXSourceNode node, AXTreeUpdate* out_update); + // Delete the client subtree for this node, ensuring that the subtree + // is re-serialized. + void DeleteClientSubtree(AXSourceNode node); + // Only for unit testing. Normally this class relies on getting a call // to SerializeChanges() every time the source tree changes. For unit // testing, it's convenient to create a static AXTree for the initial @@ -107,21 +111,21 @@ class AXTreeSerializer { // LCA(source node 5, client node 5) is node 1. // It's not node 5, because the two trees disagree on the parent of // node 4, so the LCA is the first ancestor both trees agree on. - const AXSourceNode* LeastCommonAncestor(const AXSourceNode* node, - ClientTreeNode* client_node); + AXSourceNode LeastCommonAncestor(AXSourceNode node, + ClientTreeNode* client_node); // Return the least common ancestor of |node| that's in the client tree. // This just walks up the ancestors of |node| until it finds a node that's // also in the client tree, and then calls LeastCommonAncestor on the // source node and client node. - const AXSourceNode* LeastCommonAncestor(const AXSourceNode* node); + AXSourceNode LeastCommonAncestor(AXSourceNode node); // Walk the subtree rooted at |node| and return true if any nodes that - // would be updated are being reparented. If so, update |lca| to point + // would be updated are being reparented. If so, update |out_lca| to point // to the least common ancestor of the previous LCA and the previous // parent of the node being reparented. - bool AnyDescendantWasReparented(const AXSourceNode* node, - const AXSourceNode** lca); + bool AnyDescendantWasReparented(AXSourceNode node, + AXSourceNode* out_lca); ClientTreeNode* ClientTreeNodeById(int32 id); @@ -130,7 +134,7 @@ class AXTreeSerializer { void DeleteClientSubtree(ClientTreeNode* client_node); // Helper function, called recursively with each new node to serialize. - void SerializeChangedNodes(const AXSourceNode* node, + void SerializeChangedNodes(AXSourceNode node, AXTreeUpdate* out_update); // The tree source. @@ -154,40 +158,43 @@ struct AX_EXPORT ClientTreeNode { std::vector<ClientTreeNode*> children; }; -template<class AXSourceNode> +template<typename AXSourceNode> AXTreeSerializer<AXSourceNode>::AXTreeSerializer( AXTreeSource<AXSourceNode>* tree) : tree_(tree), client_root_(NULL) { } -template<class AXSourceNode> +template<typename AXSourceNode> AXTreeSerializer<AXSourceNode>::~AXTreeSerializer() { Reset(); } -template<class AXSourceNode> +template<typename AXSourceNode> void AXTreeSerializer<AXSourceNode>::Reset() { - if (client_root_) { - DeleteClientSubtree(client_root_); - client_root_ = NULL; - } + if (!client_root_) + return; + + DeleteClientSubtree(client_root_); + client_id_map_.erase(client_root_->id); + delete client_root_; + client_root_ = NULL; } -template<class AXSourceNode> +template<typename AXSourceNode> void AXTreeSerializer<AXSourceNode>::ChangeTreeSourceForTesting( AXTreeSource<AXSourceNode>* new_tree) { tree_ = new_tree; } -template<class AXSourceNode> -const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor( - const AXSourceNode* node, ClientTreeNode* client_node) { - if (node == NULL || client_node == NULL) - return NULL; +template<typename AXSourceNode> +AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor( + AXSourceNode node, ClientTreeNode* client_node) { + if (!tree_->IsValid(node) || client_node == NULL) + return tree_->GetNull(); - std::vector<const AXSourceNode*> ancestors; - while (node) { + std::vector<AXSourceNode> ancestors; + while (tree_->IsValid(node)) { ancestors.push_back(node); node = tree_->GetParent(node); } @@ -201,7 +208,7 @@ const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor( // Start at the root. Keep going until the source ancestor chain and // client ancestor chain disagree. The last node before they disagree // is the LCA. - const AXSourceNode* lca = NULL; + AXSourceNode lca = tree_->GetNull(); int source_index = static_cast<int>(ancestors.size() - 1); int client_index = static_cast<int>(client_ancestors.size() - 1); while (source_index >= 0 && client_index >= 0) { @@ -216,40 +223,41 @@ const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor( return lca; } -template<class AXSourceNode> -const AXSourceNode* AXTreeSerializer<AXSourceNode>::LeastCommonAncestor( - const AXSourceNode* node) { +template<typename AXSourceNode> +AXSourceNode AXTreeSerializer<AXSourceNode>::LeastCommonAncestor( + AXSourceNode node) { // Walk up the tree until the source node's id also exists in the // client tree, then call LeastCommonAncestor on those two nodes. ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node)); - while (node && !client_node) { + while (tree_->IsValid(node) && !client_node) { node = tree_->GetParent(node); - if (node) + if (tree_->IsValid(node)) client_node = ClientTreeNodeById(tree_->GetId(node)); } return LeastCommonAncestor(node, client_node); } -template<class AXSourceNode> +template<typename AXSourceNode> bool AXTreeSerializer<AXSourceNode>::AnyDescendantWasReparented( - const AXSourceNode* node, const AXSourceNode** lca) { + AXSourceNode node, AXSourceNode* out_lca) { bool result = false; int id = tree_->GetId(node); - int child_count = tree_->GetChildCount(node); - for (int i = 0; i < child_count; ++i) { - const AXSourceNode* child = tree_->GetChildAtIndex(node, i); + std::vector<AXSourceNode> children; + tree_->GetChildren(node, &children); + for (size_t i = 0; i < children.size(); ++i) { + AXSourceNode& child = children[i]; int child_id = tree_->GetId(child); ClientTreeNode* client_child = ClientTreeNodeById(child_id); if (client_child) { if (!client_child->parent) { // If the client child has no parent, it must have been the // previous root node, so there is no LCA and we can exit early. - *lca = NULL; + *out_lca = tree_->GetNull(); return true; } else if (client_child->parent->id != id) { // If the client child's parent is not this node, update the LCA // and return true (reparenting was found). - *lca = LeastCommonAncestor(*lca, client_child); + *out_lca = LeastCommonAncestor(*out_lca, client_child); result = true; } else { // This child is already in the client tree, we won't @@ -260,13 +268,13 @@ bool AXTreeSerializer<AXSourceNode>::AnyDescendantWasReparented( } // This is a new child or reparented child, check it recursively. - if (AnyDescendantWasReparented(child, lca)) + if (AnyDescendantWasReparented(child, out_lca)) result = true; } return result; } -template<class AXSourceNode> +template<typename AXSourceNode> ClientTreeNode* AXTreeSerializer<AXSourceNode>::ClientTreeNodeById(int32 id) { base::hash_map<int32, ClientTreeNode*>::iterator iter = client_id_map_.find(id); @@ -276,19 +284,17 @@ ClientTreeNode* AXTreeSerializer<AXSourceNode>::ClientTreeNodeById(int32 id) { return NULL; } -template<class AXSourceNode> +template<typename AXSourceNode> void AXTreeSerializer<AXSourceNode>::SerializeChanges( - const AXSourceNode* node, + AXSourceNode node, AXTreeUpdate* out_update) { // If the node isn't in the client tree, we need to serialize starting // with the LCA. - const AXSourceNode* lca = LeastCommonAncestor(node); + AXSourceNode lca = LeastCommonAncestor(node); if (client_root_) { - // If the LCA is anything other than the node itself, tell the - // client to first delete the subtree rooted at the LCA. - bool need_delete = (lca != node); - if (lca) { + bool need_delete = false; + if (tree_->IsValid(lca)) { // Check for any reparenting within this subtree - if there is // any, we need to delete and reserialize the whole subtree // that contains the old and new parents of the reparented node. @@ -296,13 +302,11 @@ void AXTreeSerializer<AXSourceNode>::SerializeChanges( need_delete = true; } - if (lca == NULL) { + if (!tree_->IsValid(lca)) { // If there's no LCA, just tell the client to destroy the whole // tree and then we'll serialize everything from the new root. out_update->node_id_to_clear = client_root_->id; - DeleteClientSubtree(client_root_); - client_id_map_.erase(client_root_->id); - client_root_ = NULL; + Reset(); } else if (need_delete) { // Otherwise, if we need to reserialize a subtree, first we need // to delete those nodes in our client tree so that @@ -313,30 +317,39 @@ void AXTreeSerializer<AXSourceNode>::SerializeChanges( for (size_t i = 0; i < client_lca->children.size(); ++i) { client_id_map_.erase(client_lca->children[i]->id); DeleteClientSubtree(client_lca->children[i]); + delete client_lca->children[i]; } client_lca->children.clear(); } } // Serialize from the LCA, or from the root if there isn't one. - if (!lca) + if (!tree_->IsValid(lca)) lca = tree_->GetRoot(); SerializeChangedNodes(lca, out_update); } -template<class AXSourceNode> +template<typename AXSourceNode> +void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree(AXSourceNode node) { + ClientTreeNode* client_node = ClientTreeNodeById(tree_->GetId(node)); + if (client_node) + DeleteClientSubtree(client_node); +} + +template<typename AXSourceNode> void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree( ClientTreeNode* client_node) { for (size_t i = 0; i < client_node->children.size(); ++i) { client_id_map_.erase(client_node->children[i]->id); DeleteClientSubtree(client_node->children[i]); + delete client_node->children[i]; } client_node->children.clear(); } -template<class AXSourceNode> +template<typename AXSourceNode> void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes( - const AXSourceNode* node, + AXSourceNode node, AXTreeUpdate* out_update) { // This method has three responsibilities: // 1. Serialize |node| into an AXNodeData, and append it to @@ -353,10 +366,7 @@ void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes( int id = tree_->GetId(node); ClientTreeNode* client_node = ClientTreeNodeById(id); if (!client_node) { - if (client_root_) { - client_id_map_.erase(client_root_->id); - DeleteClientSubtree(client_root_); - } + Reset(); client_root_ = new ClientTreeNode(); client_node = client_root_; client_node->id = id; @@ -368,9 +378,10 @@ void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes( // Create a set of the child ids so we can quickly look // up which children are new and which ones were there before. base::hash_set<int32> new_child_ids; - int child_count = tree_->GetChildCount(node); - for (int i = 0; i < child_count; ++i) { - AXSourceNode* child = tree_->GetChildAtIndex(node, i); + std::vector<AXSourceNode> children; + tree_->GetChildren(node, &children); + for (size_t i = 0; i < children.size(); ++i) { + AXSourceNode& child = children[i]; int new_child_id = tree_->GetId(child); new_child_ids.insert(new_child_id); @@ -395,6 +406,7 @@ void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes( if (new_child_ids.find(old_child_id) == new_child_ids.end()) { client_id_map_.erase(old_child_id); DeleteClientSubtree(old_child); + delete old_child; } else { client_child_id_map[old_child_id] = old_child; } @@ -405,17 +417,22 @@ void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes( out_update->nodes.push_back(AXNodeData()); AXNodeData* serialized_node = &out_update->nodes.back(); tree_->SerializeNode(node, serialized_node); - if (serialized_node->id == client_root_->id) + // TODO(dmazzoni/dtseng): Make the serializer not depend on roles to identify + // the root. + if (serialized_node->id == client_root_->id && + (serialized_node->role != AX_ROLE_ROOT_WEB_AREA && + serialized_node->role != AX_ROLE_DESKTOP)) { serialized_node->role = AX_ROLE_ROOT_WEB_AREA; + } serialized_node->child_ids.clear(); // Iterate over the children, make note of the ones that are new // and need to be serialized, and update the ClientTreeNode // data structure to reflect the new tree. - std::vector<AXSourceNode*> children_to_serialize; - client_node->children.reserve(child_count); - for (int i = 0; i < child_count; ++i) { - AXSourceNode* child = tree_->GetChildAtIndex(node, i); + std::vector<AXSourceNode> children_to_serialize; + client_node->children.reserve(children.size()); + for (size_t i = 0; i < children.size(); ++i) { + AXSourceNode& child = children[i]; int child_id = tree_->GetId(child); // No need to do anything more with children that aren't new; |