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

Side by Side Diff: content/common/ax_tree_impl.cc

Issue 67283004: First step to move common accessibility code out of content. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Moved out of public api Created 7 years, 1 month 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
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 #include "content/common/ax_tree_impl.h"
6
7 #include <set>
8
9 #include "content/common/ax_node_impl.h"
10
11 namespace content {
12
13 // static
14 AXTree* AXTree::Create() {
15 return new AXTreeImpl();
16 }
17
18 // static
19 AXTree* AXTree::Create(const AXTreeUpdate& initial_state) {
20 return new AXTreeImpl(initial_state);
21 }
22
23 AXTreeImpl::AXTreeImpl()
24 : root_(NULL) {
25 AXNodeData root;
26 root.id = 0;
27 root.role = WebKit::WebAXRoleRootWebArea;
28
29 AXTreeUpdate initial_state;
30 initial_state.nodes.push_back(root);
31 Unserialize(initial_state);
32 }
33
34 AXTreeImpl::AXTreeImpl(const AXTreeUpdate& initial_state)
35 : root_(NULL) {
36 Unserialize(initial_state);
37 }
38
39 AXTreeImpl::~AXTreeImpl() {
40 if (root_)
41 root_->Destroy();
42 }
43
44 AXNode* AXTreeImpl::GetRoot() const {
45 return root_;
46 }
47
48 int32 AXTreeImpl::GetRootId() const {
49 return root_->GetId();
50 }
51
52 AXNode* AXTreeImpl::GetFromId(int32 id) const {
53 base::hash_map<int32, AXNodeImpl*>::const_iterator iter = id_map_.find(id);
54 return iter != id_map_.end() ? (iter->second) : NULL;
55 }
56
57 int32 AXTreeImpl::GetId(const AXNode* node) const {
aboxhall 2013/11/11 18:20:35 What is the purpose of this and the below two meth
dmazzoni 2013/11/12 00:03:04 This is because AXSourceTree is an abstraction of
David Tseng 2013/11/13 18:08:11 I don't entirely understand this; the methods dupl
58 return node->GetId();
59 }
60
61 int AXTreeImpl::GetChildCount(const AXNode* node) const {
62 return node->GetChildCount();
63 }
64
65 AXNode* AXTreeImpl::GetChildAtIndex(const AXNode* node, int index) const {
66 return node->ChildAtIndex(index);
67 }
68
69 int32 AXTreeImpl::GetParentId(const AXNode* node) const {
70 return node->GetParent() ? node->GetParent()->GetId() : 0;
71 }
72
73 void AXTreeImpl::Serialize(const AXNode* node, AXNodeData* out_data) const {
74 *out_data = node->data();
75 }
76
77 bool AXTreeImpl::Unserialize(const AXTreeUpdate& update) {
78 for (size_t i = 0; i < update.nodes.size(); i++) {
David Tseng 2013/11/11 19:27:18 nit: ++i
dmazzoni 2013/11/12 00:03:04 Done.
79 if (!UpdateNode(update.nodes[i]))
80 return false;
David Tseng 2013/11/11 19:27:18 DCHECK? Is this ever acceptable?
dmazzoni 2013/11/12 00:03:04 It's not acceptable, but what we're currently doin
81 }
82
83 return true;
84 }
85
86 void AXTreeImpl::NodeWasDestroyed(AXNodeImpl* node) {
87 id_map_.erase(node->GetId());
88 }
89
90 AXNodeImpl* AXTreeImpl::CreateNode() {
91 return new AXNodeImpl();
92 }
93
94 bool AXTreeImpl::UpdateNode(const AXNodeData& src) {
95 // This method updates one node in the tree based on serialized data
96 // received in an AXTreeUpdate. See AXTreeUpdate for pre and post
97 // conditions.
98
99 // Create a set of child ids in |src| for fast lookup. If a duplicate id is
100 // found, exit now with a fatal error before changing anything else.
101 std::set<int32> new_child_ids;
102 for (size_t i = 0; i < src.child_ids.size(); ++i) {
David Tseng 2013/11/11 19:27:18 ditto
dmazzoni 2013/11/12 00:03:04 ?
103 if (new_child_ids.find(src.child_ids[i]) != new_child_ids.end())
104 return false;
David Tseng 2013/11/11 19:27:18 DCHECK?
dmazzoni 2013/11/12 00:03:04 Same
105 new_child_ids.insert(src.child_ids[i]);
106 }
107
108 // Look up the node by id. If it's not found, then either the root
109 // of the tree is being swapped, or we're out of sync with the source
110 // and this is a serious error.
111 AXNodeImpl* node = static_cast<AXNodeImpl*>(GetFromId(src.id));
112 if (!node) {
113 if (src.role != WebKit::WebAXRoleRootWebArea)
114 return false;
115 node = CreateAndInitializeNode(NULL, src.id, 0);
116 }
117
118 // Set the node's data.
119 node->SetData(src);
120
121 //
122 // Update the children in three steps:
David Tseng 2013/11/11 19:27:18 This huge comment block indicates that the below s
dmazzoni 2013/11/12 07:48:23 Refactored. More comprehensive unit tests coming.
123 //
124 // 1. Iterate over the old children and delete nodes that are no longer
125 // in the tree.
126 // 2. Build up a vector of new children, reusing children that haven't
127 // changed (but may have been reordered) and adding new empty
128 // objects for new children.
129 // 3. Swap in the new children vector for the old one.
130
131 // Delete any previous children of this node that are no longer
aboxhall 2013/11/11 18:20:35 Suggestion: // (1) Delete ... (to refer back to st
dmazzoni 2013/11/12 07:48:23 Refactored, please take a look.
132 // children first. We make a deletion-only pass first to prevent a
133 // node that's being reparented from being the child of both its old
134 // parent and new parent, which could lead to a double-free.
135 // If a node is reparented, the source will always send us a fresh
136 // copy of the node.
137 const std::vector<AXNodeImpl*>& old_children = node->children();
138 for (size_t i = 0; i < old_children.size(); ++i) {
139 int old_id = old_children[i]->GetId();
140 if (new_child_ids.find(old_id) == new_child_ids.end())
141 old_children[i]->Destroy();
142 }
143
144 // Now build a vector of new children, reusing objects that were already
145 // children of this node before.
146 std::vector<AXNodeImpl*> new_children;
147 bool success = true;
148 for (size_t i = 0; i < src.child_ids.size(); i++) {
149 int32 child_id = src.child_ids[i];
150 int32 index_in_parent = static_cast<int32>(i);
151 AXNodeImpl* child = static_cast<AXNodeImpl*>(GetFromId(child_id));
152 if (child) {
153 if (child->GetParent() != node) {
154 // This is a serious error - nodes should never be reparented.
155 // If this case occurs, continue so this node isn't left in an
156 // inconsistent state, but return failure at the end.
157 success = false;
158 continue;
159 }
160 child->UpdateIndexInParent(index_in_parent);
161 } else {
162 child = CreateAndInitializeNode(node, child_id, index_in_parent);
163 }
164 new_children.push_back(child);
165 }
166
167 // Finally, swap in the new children vector for the old.
168 node->SwapChildren(new_children);
169
170 // Handle the case where this node is the new root of the tree.
David Tseng 2013/11/11 19:27:18 And perhaps a separate method for this as well. (i
dmazzoni 2013/11/12 07:48:23 I thought this was fine here now that everything e
171 if (src.role == WebKit::WebAXRoleRootWebArea &&
172 (!root_ || root_->GetId() != src.id)) {
173 if (root_)
174 root_->Destroy();
175 root_ = node;
176 OnRootChanged();
177 }
178
179 return success;
180 }
181
182 void AXTreeImpl::OnRootChanged() {
183 }
184
185 AXNodeImpl* AXTreeImpl::CreateAndInitializeNode(
186 AXNodeImpl* parent, int32 id, int32 index_in_parent) {
187 AXNodeImpl* node = CreateNode();
188 node->Init(this, parent, id, index_in_parent);
189 id_map_[node->GetId()] = node;
190 return node;
191 }
192
193 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698