Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Side by Side Diff: ui/accessibility/ax_tree_serializer.h

Issue 67283004: First step to move common accessibility code out of content. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Git rid of AX_EXPORT from templatized function Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/accessibility/ax_tree.cc ('k') | ui/accessibility/ax_tree_serializer.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 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 "ui/accessibility/ax_tree_source.h"
13 #include "ui/accessibility/ax_tree_update.h"
14
15 namespace ui {
16
17 struct ClientTreeNode;
18
19 // AXTreeSerializer is a helper class that serializes incremental
20 // updates to an AXTreeSource as a vector of AXNodeData structs.
21 // These structs can be unserialized by an AXTree. An AXTreeSerializer
22 // keeps track of the tree of node ids that its client is aware of, so
23 // it will automatically include, as part of any update, any additional nodes
24 // that the client is not aware of yet.
25 //
26 // When the AXTreeSource changes, call SerializeChanges to serialize the
27 // changes to the tree as an AXTreeUpdate. If a single node has changed,
28 // pass that node to SerializeChanges. If a node has been added or removed,
29 // pass the parent of that node to SerializeChanges and it will automatically
30 // handle changes to its set of children.
31 //
32 // TODO(dmazzoni): add sample usage code.
33 template<class AXSourceNode>
34 class AXTreeSerializer {
35 public:
36 explicit AXTreeSerializer(AXTreeSource<AXSourceNode>* tree);
37
38 // Throw out the internal state that keeps track of the nodes the client
39 // knows about. This has the effect that the next update will send the
40 // entire tree over because it assumes the client knows nothing.
41 void Reset();
42
43 // Serialize all changes to |node| and append them to |out_update|.
44 void SerializeChanges(const AXSourceNode* node,
45 AXTreeUpdate* out_update);
46
47 private:
48 // Delete the given client tree node and recursively delete all of its
49 // descendants.
50 void DeleteClientSubtree(ClientTreeNode* client_node);
51
52 void SerializeChangedNodes(const AXSourceNode* node,
53 std::set<int>* ids_serialized,
54 AXTreeUpdate* out_update);
55
56 // The tree source.
57 AXTreeSource<AXSourceNode>* tree_;
58
59 // Our representation of the client tree.
60 ClientTreeNode* client_root_;
61
62 // A map from IDs to nodes in the client tree.
63 base::hash_map<int32, ClientTreeNode*> client_id_map_;
64 };
65
66 // In order to keep track of what nodes the client knows about, we keep a
67 // representation of the client tree - just IDs and parent/child
68 // relationships.
69 struct AX_EXPORT ClientTreeNode {
70 ClientTreeNode();
71 virtual ~ClientTreeNode();
72 int32 id;
73 ClientTreeNode* parent;
74 std::vector<ClientTreeNode*> children;
75 };
76
77 template<class AXSourceNode>
78 AXTreeSerializer<AXSourceNode>::AXTreeSerializer(
79 AXTreeSource<AXSourceNode>* tree)
80 : tree_(tree),
81 client_root_(NULL) {
82 }
83
84 template<class AXSourceNode>
85 void AXTreeSerializer<AXSourceNode>::Reset() {
86 if (client_root_) {
87 DeleteClientSubtree(client_root_);
88 client_root_ = NULL;
89 }
90 }
91
92 template<class AXSourceNode>
93 void AXTreeSerializer<AXSourceNode>::SerializeChanges(
94 const AXSourceNode* node,
95 AXTreeUpdate* out_update) {
96 std::set<int> ids_serialized;
97 SerializeChangedNodes(node, &ids_serialized, out_update);
98 }
99
100 template<class AXSourceNode>
101 void AXTreeSerializer<AXSourceNode>::DeleteClientSubtree(
102 ClientTreeNode* client_node) {
103 for (size_t i = 0; i < client_node->children.size(); ++i) {
104 client_id_map_.erase(client_node->children[i]->id);
105 DeleteClientSubtree(client_node->children[i]);
106 }
107 client_node->children.clear();
108 }
109
110 template<class AXSourceNode>
111 void AXTreeSerializer<AXSourceNode>::SerializeChangedNodes(
112 const AXSourceNode* node,
113 std::set<int>* ids_serialized,
114 AXTreeUpdate* out_update) {
115 int id = tree_->GetId(node);
116 if (ids_serialized->find(id) != ids_serialized->end())
117 return;
118 ids_serialized->insert(id);
119
120 // This method has three responsibilities:
121 // 1. Serialize |node| into an AXNodeData, and append it to
122 // the AXTreeUpdate to be sent to the client.
123 // 2. Determine if |node| has any new children that the client doesn't
124 // know about yet, and call SerializeChangedNodes recursively on those.
125 // 3. Update our internal data structure that keeps track of what nodes
126 // the client knows about.
127
128 // First, find the ClientTreeNode for this id in our data structure where
129 // we keep track of what accessibility objects the client already knows
130 // about. If we don't find it, then this must be the new root of the
131 // accessibility tree.
132 //
133 // TODO(dmazzoni): handle the case where the root changes.
134 ClientTreeNode* client_node = NULL;
135 base::hash_map<int32, ClientTreeNode*>::iterator iter =
136 client_id_map_.find(id);
137 if (iter != client_id_map_.end()) {
138 client_node = iter->second;
139 } else {
140 if (client_root_) {
141 client_id_map_.erase(client_root_->id);
142 DeleteClientSubtree(client_root_);
143 }
144 client_root_ = new ClientTreeNode();
145 client_node = client_root_;
146 client_node->id = id;
147 client_node->parent = NULL;
148 client_id_map_[client_node->id] = client_node;
149 }
150
151 // Iterate over the ids of the children of |node|.
152 // Create a set of the child ids so we can quickly look
153 // up which children are new and which ones were there before.
154 // Also catch the case where a child is already in the client tree
155 // data structure with a different parent, and make sure the old parent
156 // clears this node first.
157 base::hash_set<int32> new_child_ids;
158 int child_count = tree_->GetChildCount(node);
159 for (int i = 0; i < child_count; ++i) {
160 AXSourceNode* child = tree_->GetChildAtIndex(node, i);
161 int new_child_id = tree_->GetId(child);
162 new_child_ids.insert(new_child_id);
163
164 ClientTreeNode* client_child = client_id_map_[new_child_id];
165 if (client_child && client_child->parent != client_node) {
166 // The child is being reparented. Find the source tree node
167 // corresponding to the old parent, or the closest ancestor
168 // still in the tree.
169 ClientTreeNode* client_parent = client_child->parent;
170 AXSourceNode* parent = NULL;
171 while (client_parent) {
172 parent = tree_->GetFromId(client_parent->id);
173 if (parent)
174 break;
175 client_parent = client_parent->parent;
176 }
177 CHECK(parent);
178
179 // Call SerializeChangedNodes recursively on the old parent,
180 // so that the update that clears |child| from its old parent
181 // occurs stricly before the update that adds |child| to its
182 // new parent.
183 SerializeChangedNodes(parent, ids_serialized, out_update);
184 }
185 }
186
187 // Go through the old children and delete subtrees for child
188 // ids that are no longer present, and create a map from
189 // id to ClientTreeNode for the rest. It's important to delete
190 // first in a separate pass so that nodes that are reparented
191 // don't end up children of two different parents in the middle
192 // of an update, which can lead to a double-free.
193 base::hash_map<int32, ClientTreeNode*> client_child_id_map;
194 std::vector<ClientTreeNode*> old_children;
195 old_children.swap(client_node->children);
196 for (size_t i = 0; i < old_children.size(); ++i) {
197 ClientTreeNode* old_child = old_children[i];
198 int old_child_id = old_child->id;
199 if (new_child_ids.find(old_child_id) == new_child_ids.end()) {
200 client_id_map_.erase(old_child_id);
201 DeleteClientSubtree(old_child);
202 } else {
203 client_child_id_map[old_child_id] = old_child;
204 }
205 }
206
207 // Serialize this node. This fills in all of the fields in
208 // AXNodeData except child_ids, which we handle below.
209 out_update->nodes.push_back(AXNodeData());
210 AXNodeData* serialized_node = &out_update->nodes.back();
211 tree_->SerializeNode(node, serialized_node);
212 if (serialized_node->id == client_root_->id)
213 serialized_node->role = AX_ROLE_ROOT_WEB_AREA;
214 serialized_node->child_ids.clear();
215
216 // Iterate over the children, make note of the ones that are new
217 // and need to be serialized, and update the ClientTreeNode
218 // data structure to reflect the new tree.
219 std::vector<AXSourceNode*> children_to_serialize;
220 client_node->children.reserve(child_count);
221 for (int i = 0; i < child_count; ++i) {
222 AXSourceNode* child = tree_->GetChildAtIndex(node, i);
223 int child_id = tree_->GetId(child);
224
225 // No need to do anything more with children that aren't new;
226 // the client will reuse its existing object.
227 if (new_child_ids.find(child_id) == new_child_ids.end())
228 continue;
229
230 new_child_ids.erase(child_id);
231 serialized_node->child_ids.push_back(child_id);
232 if (client_child_id_map.find(child_id) != client_child_id_map.end()) {
233 ClientTreeNode* reused_child = client_child_id_map[child_id];
234 client_node->children.push_back(reused_child);
235 } else {
236 ClientTreeNode* new_child = new ClientTreeNode();
237 new_child->id = child_id;
238 new_child->parent = client_node;
239 client_node->children.push_back(new_child);
240 client_id_map_[child_id] = new_child;
241 children_to_serialize.push_back(child);
242 }
243 }
244
245 // Serialize all of the new children, recursively.
246 for (size_t i = 0; i < children_to_serialize.size(); ++i)
247 SerializeChangedNodes(children_to_serialize[i], ids_serialized, out_update);
248 }
249
250 } // namespace ui
251
252 #endif // UI_ACCESSIBILITY_AX_TREE_SERIALIZER_H_
OLDNEW
« no previous file with comments | « ui/accessibility/ax_tree.cc ('k') | ui/accessibility/ax_tree_serializer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698