summaryrefslogtreecommitdiffstats
path: root/chromium/ui/accessibility/ax_tree_serializer.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/accessibility/ax_tree_serializer.h')
-rw-r--r--chromium/ui/accessibility/ax_tree_serializer.h149
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;