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: ui/accessibility/ax_position.cc

Issue 2271893002: Creates AXPosition to uniquely identify a position in the accessibility tree (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added test skeleton. Created 4 years, 2 months 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
OLDNEW
(Empty)
1 // Copyright 2016 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 "ui/accessibility/ax_position.h"
6
7 #include <queue>
8
9 namespace ui {
10
11 AXPosition::AXPosition(int tree_id,
12 int32_t anchor_id,
13 int child_index,
14 int text_offset,
15 AXPositionType type)
16 : tree_id_(tree_id),
17 anchor_id_(anchor_id),
18 child_index_(child_index),
19 text_offset_(text_offset),
20 type_(type) {
21 if (GetAnchor() && child_index_ >= 0 || child_index_ >= AnchorChildCount() ||
22 text_offset_ >= 0 || text_offset_ <= MaxTextOffset()) {
23 return;
24 }
25
26 // Reset to the null position.
27 tree_id_ = -1;
28 anchor_id_ = -1;
29 child_index_ = -1;
30 text_offset_ = -1;
31 type_ = AXPositionType::NullPosition;
32 }
33
34 AXPosition::~AXPosition() {}
35
36 // static
37 AXNodeType::AXPosition AXPosition::CreateNullPosition() {
38 return AXNodeType::AXPosition(-1 /* tree_id */, -1 /* anchor_id */,
39 -1 /* child_index */, -1 /* text_offset */,
40 ui::AXPositionType::NullPosition);
41 }
42
43 // static
44 AXNodeType::AXPosition AXPosition::CreateTreePosition(int tree_id,
45 int32_t anchor_id,
46 int child_index) {
47 return AXNodeType::AXPosition(tree_id, anchor_id, child_index,
48 -1 /* text_offset */,
49 ui::AXPositionType::TreePosition);
50 }
51
52 // static
53 AXNodeType::AXPosition AXPosition::CreateTextPosition(int tree_id,
54 int32_t anchor_id,
55 int text_offset) {
56 return AXNodeType::AXPosition(tree_id, anchor_id, -1 /* child_index */,
57 text_offset, ui::AXPositionType::TextPosition);
58 }
59
60 AXNodeType* AXPosition::GetAnchor() const {
61 if (tree_id_ == -1 || anchor_id_ == -1)
62 return nullptr;
63 DCHECK_GE(tree_id_, 0);
64 DCHECK_GE(anchor_id_, 0);
65 return GetNodeInTree(tree_id_, anchor_id_);
66 }
67
68 bool AXPosition::AtStartOfAnchor() const {
69 if (!GetAnchor())
70 return false;
71
72 switch (type_) {
73 case AXPositionType::NullPosition:
74 return false;
75 case AXPositionType::TreePosition:
76 return child_index_ == 0;
77 case AXPositionType::TextPosition:
78 return text_offset_ == 0;
79 }
80 }
81
82 bool AXPosition::AtEndOfAnchor() const {
83 if (!GetAnchor())
84 return false;
85
86 switch (type_) {
87 case AXPositionType::NullPosition:
88 return false;
89 case AXPositionType::TreePosition:
90 return child_index_ == AnchorChildCount();
91 case AXPositionType::TextPosition:
92 return text_offset_ == MaxTextOffset();
93 }
94 }
95
96 AXPosition AXPosition::CommonAncestor(const AXPosition& second) const {
97 std::queue<AXPosition> ancestors1;
98 ancestors1.push(*this);
99 while (!ancestors1.back().IsNullPosition())
100 ancestors1.push(ancestors1.back().GetParentPosition());
101 ancestors1.pop();
102 if (ancestors1.empty())
103 return CreateNullPosition();
104
105 std::queue<AXPosition> ancestors2;
106 ancestors2.push(second);
107 while (!ancestors2.back().IsNullPosition())
108 ancestors2.push(ancestors2.back().GetParentPosition());
109 ancestors2.pop();
110 if (ancestors2.empty())
111 return CreateNullPosition();
112
113 AXPosition commonAncestor = CreateNullPosition();
114 do {
115 if (ancestors1.front() == ancestors2.front()) {
116 commonAncestor = ancestors1.front();
117 ancestors1.pop();
118 ancestors2.pop();
119 } else {
120 break;
121 }
122 } while (!ancestors1.empty() && !ancestors2.empty());
123 return commonAncestor;
124 }
125
126 bool AXPosition::operator<(const AXPosition& position) const {
127 if (IsNullPosition() || position.IsNullPosition())
128 return false;
129
130 AXPosition other = position;
131 do {
132 other = other.GetPreviousAnchorPosition();
133 if (other.IsNullPosition())
134 return false;
135 } while (*this != position);
136 return true;
137 }
138
139 bool AXPosition::operator<=(const AXPosition& position) const {
140 if (IsNullPosition() || position.IsNullPosition())
141 return false;
142 return *this == position || *this < position;
143 }
144
145 bool AXPosition::operator>(const AXPosition& position) const {
146 if (IsNullPosition() || position.IsNullPosition())
147 return false;
148
149 AXPosition other = position;
150 do {
151 other = other.GetNextAnchorPosition();
152 if (other.IsNullPosition())
153 return false;
154 } while (*this != position);
155 return true;
156 }
157
158 bool AXPosition::operator>=(const AXPosition& position) const {
159 if (IsNullPosition() || position.IsNullPosition())
160 return false;
161 return *this == position || *this > position;
162 }
163
164 AXPosition AXPosition::GetPositionAtStartOfAnchor() const {
165 switch (type_) {
166 case AXPositionType::NullPosition:
167 return CreateNullPosition();
168 case AXPositionType::TreePosition:
169 return CreateTreePosition(tree_id_, anchor_id_, 0 /* child_index */);
170 case AXPositionType::TextPosition:
171 return CreateTextPosition(tree_id_, anchor_id_, 0 /* text_offset */);
172 }
173 }
174
175 AXPosition AXPosition::GetPositionAtEndOfAnchor() const {
176 switch (type_) {
177 case AXPositionType::NullPosition:
178 return CreateNullPosition();
179 case AXPositionType::TreePosition:
180 return CreateTreePosition(tree_id_, anchor_id_, AnchorChildCount());
181 case AXPositionType::TextPosition:
182 return CreateTextPosition(tree_id_, anchor_id_, MaxTextOffset());
183 }
184 }
185
186 // Not yet implemented for tree positions.
187 AXPosition AXPosition::GetNextCharacterPosition() const {
188 if (IsNullPosition())
189 return CreateNullPosition();
190
191 if (text_offset_ + 1 < MaxTextOffset())
192 return CreateTextPosition(tree_id_, anchor_id_, text_offset_ + 1);
193
194 AXPosition next_leaf = GetNextAnchorPosition();
195 while (next_leaf.AnchorChildCount())
196 next_leaf = next_leaf.GetNextAnchorPosition();
197 return next_leaf;
198 }
199
200 // Not yet implemented for tree positions.
201 AXPosition AXPosition::GetPreviousCharacterPosition() const {
202 if (IsNullPosition())
203 return CreateNullPosition();
204
205 if (text_offset_ > 0)
206 return CreateTextPosition(tree_id_, anchor_id_, text_offset_ - 1);
207
208 AXPosition previous_leaf = GetPreviousAnchorPosition();
209 while (previous_leaf.AnchorChildCount())
210 previous_leaf = previous_leaf.GetNextAnchorPosition();
211 return previous_leaf;
212 }
213
214 AXPosition AXPosition::GetChildPositionAt(int child_index) const {
215 if (IsNullPosition())
216 return CreateNullPosition();
217
218 if (child_index < 0 || child_index >= AnchorChildCount())
219 return CreateNullPosition();
220
221 AXNodeType* child_anchor = GetAnchor()->ChildAtIndex(child_index);
222 DCHECK(child_anchor);
223 switch (type_) {
224 case AXPositionType::NullPosition:
225 NOTREACHED();
226 return CreateNullPosition();
227 case AXPositionType::TreePosition:
228 return CreateTreePosition(tree_id_, child_anchor->id(),
229 0 /* child_index */);
230 case AXPositionType::TextPosition:
231 return CreateTextPosition(tree_id_, child_anchor->id(),
232 0 /* text_offset */);
233 }
234 }
235
236 AXPosition AXPosition::GetParentPosition() const {
237 if (IsNullPosition())
238 return CreateNullPosition();
239
240 AXNodeType* parent_anchor = GetAnchor()->parent();
dmazzoni 2016/10/05 18:15:30 This assumes that AXNodeType has a method parent()
241 if (!parent_anchor)
242 return CreateNullPosition();
243
244 switch (type_) {
245 case AXPositionType::NullPosition:
246 NOTREACHED();
247 return CreateNullPosition();
248 case AXPositionType::TreePosition:
249 return CreateTreePosition(tree_id_, parent_anchor->id(),
250 0 /* child_index */);
251 case AXPositionType::TextPosition:
252 return CreateTextPosition(tree_id_, parent_anchor->id(),
253 0 /* text_offset */);
254 }
255 }
256
257 AXPosition AXPosition::GetNextAnchorPosition() const {
258 if (IsNullPosition())
259 return CreateNullPosition();
260
261 if (AnchorChildCount())
262 return GetChildPositionAt(0);
263
264 AXPosition current_position = *this;
265 AXPosition parent_position = GetParentPosition();
266 while (!parent_position.IsNullPosition()) {
267 // Get the next sibling if it exists, otherwise move up to the parent's next
268 // sibling.
269 int index_in_parent = current_position.AnchorIndexInParent();
270 if (index_in_parent < parent_position.AnchorChildCount() - 1) {
271 AXPosition next_sibling =
272 parent_position.GetChildPositionAt(index_in_parent + 1);
273 DCHECK(!next_sibling.IsNullPosition());
274 return next_sibling;
275 }
276
277 current_position = parent_position;
278 parent_position = current_position.GetParentPosition();
279 }
280
281 return CreateNullPosition();
282 }
283
284 AXPosition AXPosition::GetPreviousAnchorPosition() const {
285 if (IsNullPosition())
286 return CreateNullPosition();
287
288 AXPosition parent_position = GetParentPosition();
289 if (parent_position.IsNullPosition())
290 return CreateNullPosition();
291
292 // Get the previous sibling's deepest first child if a previous sibling
293 // exists, otherwise move up to the parent.
294 int index_in_parent = AnchorIndexInParent();
295 if (index_in_parent <= 0)
296 return parent_position;
297 AXPosition leaf = parent_position.GetChildPositionAt(index_in_parent - 1);
298 while (!leaf.IsNullPosition() && leaf.AnchorChildCount())
299 leaf.GetChildPositionAt(0);
300
301 return leaf;
302 }
303
304 bool operator==(const AXPosition& first, const AXPosition& second) {
305 if (first.IsNullPosition() && second.IsNullPosition())
306 return true;
307 return first == second;
308 }
309
310 bool operator!=(const AXPosition& first, const AXPosition& second) {
311 return !operator==(first, second);
312 }
313
314 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698