Index: ui/accessibility/ax_tree_serializer.h |
diff --git a/ui/accessibility/ax_tree_serializer.h b/ui/accessibility/ax_tree_serializer.h |
index 53e515aaa484a99ed9b2d6cdc28bcb166c07f80b..5435bbe2bae702eb274fcfc18b160a2fee67fe49 100644 |
--- a/ui/accessibility/ax_tree_serializer.h |
+++ b/ui/accessibility/ax_tree_serializer.h |
@@ -417,34 +417,42 @@ void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes( |
// Serialize this node. This fills in all of the fields in |
// AXNodeData except child_ids, which we handle below. |
+ size_t serialized_node_index = out_update->nodes.size(); |
out_update->nodes.push_back(AXNodeData()); |
- AXNodeData* serialized_node = &out_update->nodes.back(); |
- tree_->SerializeNode(node, serialized_node); |
- // 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; |
+ { |
+ // Take the address of an element in a vector only within a limited |
+ // scope because otherwise the pointer can become invalid if the |
+ // vector is resized. |
+ AXNodeData* serialized_node = &out_update->nodes[serialized_node_index]; |
+ |
+ tree_->SerializeNode(node, serialized_node); |
+ // 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 |
+ // Iterate over the children, serialize them, and update the ClientTreeNode |
// data structure to reflect the new tree. |
- std::vector<AXSourceNode> children_to_serialize; |
+ std::vector<int32> actual_serialized_node_child_ids; |
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; |
- // the client will reuse its existing object. |
+ // Skip if the child isn't valid. |
+ if (!tree_->IsValid(child)) |
+ continue; |
+ |
+ // Skip if the same child is included more than once. |
if (new_child_ids.find(child_id) == new_child_ids.end()) |
continue; |
new_child_ids.erase(child_id); |
- serialized_node->child_ids.push_back(child_id); |
+ actual_serialized_node_child_ids.push_back(child_id); |
if (client_child_id_map.find(child_id) != client_child_id_map.end()) { |
ClientTreeNode* reused_child = client_child_id_map[child_id]; |
client_node->children.push_back(reused_child); |
@@ -454,13 +462,14 @@ void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes( |
new_child->parent = client_node; |
client_node->children.push_back(new_child); |
client_id_map_[child_id] = new_child; |
- children_to_serialize.push_back(child); |
+ SerializeChangedNodes(child, out_update); |
} |
} |
- // Serialize all of the new children, recursively. |
- for (size_t i = 0; i < children_to_serialize.size(); ++i) |
- SerializeChangedNodes(children_to_serialize[i], out_update); |
+ // Finally, update the child ids of this node to reflect the actual child |
+ // ids that were valid during serialization. |
+ out_update->nodes[serialized_node_index].child_ids.swap( |
+ actual_serialized_node_child_ids); |
} |
} // namespace ui |