Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
ax_node_position.cc
Go to the documentation of this file.
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 "ax_node_position.h"
6
8#include "ax_enums.h"
9#include "ax_node_data.h"
10#include "ax_tree_manager.h"
11#include "ax_tree_manager_map.h"
12#include "base/string_utils.h"
13
14namespace ui {
15
17#if defined(OS_WIN)
19#else
21#endif // defined(OS_WIN)
22
28
32
33// static
35 const AXNode& node,
36 int child_index_or_text_offset,
37 ax::mojom::TextAffinity affinity) {
38 if (!node.tree())
39 return CreateNullPosition();
40
41 AXTreeID tree_id = node.tree()->GetAXTreeID();
42 if (node.IsText()) {
43 return CreateTextPosition(tree_id, node.id(), child_index_or_text_offset,
44 affinity);
45 }
46
47 return CreateTreePosition(tree_id, node.id(), child_index_or_text_offset);
48}
49
51
53
56
60
61void AXNodePosition::AnchorChild(int child_index,
62 AXTreeID* tree_id,
63 AXNode::AXID* child_id) const {
65 BASE_DCHECK(child_id);
66
67 if (!GetAnchor() || child_index < 0 || child_index >= AnchorChildCount()) {
69 *child_id = AXNode::kInvalidAXID;
70 return;
71 }
72
73 AXNode* child = nullptr;
74 const AXTreeManager* child_tree_manager =
76 if (child_tree_manager) {
77 // The child node exists in a separate tree from its parent.
78 child = child_tree_manager->GetRootAsAXNode();
79 *tree_id = child_tree_manager->GetTreeID();
80 } else {
81 child = GetAnchor()->children()[static_cast<size_t>(child_index)];
82 *tree_id = this->tree_id();
83 }
84
85 BASE_DCHECK(child);
86 *child_id = child->id();
87}
88
90 if (!GetAnchor())
91 return 0;
92
93 const AXTreeManager* child_tree_manager =
95 if (child_tree_manager)
96 return 1;
97
98 return static_cast<int>(GetAnchor()->children().size());
99}
100
102 if (!GetAnchor())
103 return 0;
104
105 return static_cast<int>(GetAnchor()->GetUnignoredChildCount());
106}
107
109 return GetAnchor() ? static_cast<int>(GetAnchor()->index_in_parent())
111}
112
114 AXNode* parent = GetAnchor()->GetUnignoredParent();
115 if (parent)
116 return static_cast<int>(parent->GetUnignoredChildCount());
117
118 return 0;
119}
120
121std::stack<AXNode*> AXNodePosition::GetAncestorAnchors() const {
122 std::stack<AXNode*> anchors;
123 AXNode* current_anchor = GetAnchor();
124
125 AXNode::AXID current_anchor_id = GetAnchor()->id();
126 AXTreeID current_tree_id = tree_id();
127
128 AXNode::AXID parent_anchor_id = AXNode::kInvalidAXID;
129 AXTreeID parent_tree_id = AXTreeIDUnknown();
130
131 while (current_anchor) {
132 anchors.push(current_anchor);
133 current_anchor = GetParent(
134 current_anchor /*child*/, current_tree_id /*child_tree_id*/,
135 &parent_tree_id /*parent_tree_id*/, &parent_anchor_id /*parent_id*/);
136
137 current_anchor_id = parent_anchor_id;
138 current_tree_id = parent_tree_id;
139 }
140 return anchors;
141}
142
144 if (!GetAnchor())
145 return nullptr;
146
147 return GetAnchor()->GetUnignoredParent();
148}
149
151 AXNode::AXID* parent_id) const {
153 BASE_DCHECK(parent_id);
154
156 *parent_id = AXNode::kInvalidAXID;
157
158 if (!GetAnchor())
159 return;
160
161 AXNode* parent =
162 GetParent(GetAnchor() /*child*/, this->tree_id() /*child_tree_id*/,
163 tree_id /*parent_tree_id*/, parent_id /*parent_id*/);
164
165 if (!parent) {
167 *parent_id = AXNode::kInvalidAXID;
168 }
169}
170
172 AXNode::AXID node_id) const {
173 if (node_id == AXNode::kInvalidAXID)
174 return nullptr;
175
177 if (manager)
178 return manager->GetNodeFromTree(tree_id, node_id);
179 return nullptr;
180}
181
183 return node->id();
184}
185
187 return node->tree()->GetAXTreeID();
188}
189
190std::u16string AXNodePosition::GetText() const {
191 if (IsNullPosition())
192 return {};
193
194 std::u16string text;
197 return text;
198 }
199
200 const AXNode* anchor = GetAnchor();
201 BASE_DCHECK(anchor);
202 // TODO(nektar): Replace with PlatformChildCount when AXNodePosition and
203 // BrowserAccessibilityPosition are merged into one class.
204 if (!AnchorChildCount()) {
205 // Special case: Allows us to get text even in non-web content, e.g. in the
206 // browser's UI.
207 text =
209 if (!text.empty())
210 return text;
211 }
212
213 if (anchor->IsText()) {
214 return anchor->data().GetString16Attribute(
216 }
217
218 for (int i = 0; i < AnchorChildCount(); ++i) {
219 text += CreateChildPositionAt(i)->GetText();
220 }
221
222 return text;
223}
224
226 if (IsNullPosition())
227 return false;
229 return GetAnchor()->IsLineBreak();
230}
231
233 if (IsNullPosition())
234 return false;
236 return GetAnchor()->IsText();
237}
238
240 if (IsNullPosition())
241 return false;
243 return GetAnchor()->IsLineBreak() ||
245}
246
247// This override is an optimized version AXPosition::MaxTextOffset. Instead of
248// concatenating the strings in GetText() to then get their text length, we sum
249// the lengths of the individual strings. This is faster than concatenating the
250// strings first and then taking their length, especially when the process
251// is recursive.
253 if (IsNullPosition())
254 return INVALID_OFFSET;
255
257 return 1;
258
259 const AXNode* anchor = GetAnchor();
260 BASE_DCHECK(anchor);
261 // TODO(nektar): Replace with PlatformChildCount when AXNodePosition and
262 // BrowserAccessibilityPosition will make one.
263 if (!AnchorChildCount()) {
264 std::u16string value =
266 if (!value.empty())
267 return value.length();
268 }
269
270 if (anchor->IsText()) {
271 return anchor->data()
273 .length();
274 }
275
276 int text_length = 0;
277 for (int i = 0; i < AnchorChildCount(); ++i) {
278 text_length += CreateChildPositionAt(i)->MaxTextOffset();
279 }
280
281 return text_length;
282}
283
287 return false;
289 // We don't need to expose an "embedded object character" for textual
290 // nodes and nodes that are invisible to platform APIs. Textual nodes are
291 // represented by their actual text.
292 return !IsNullPosition() && !GetAnchor()->IsText() &&
294 }
295}
296
298 if (IsNullPosition())
299 return false;
301 return (GetAnchor()->data().GetBoolAttribute(
303 !GetAnchor()->IsInListMarker()) ||
305}
306
313
315 return node->data().role;
316}
317
319 // Check either the current anchor or its parent for text styles.
320 AXNodeTextStyles current_anchor_text_styles =
323 if (current_anchor_text_styles.IsUnset()) {
325 if (!parent->IsNullPosition())
326 return parent->GetAnchor()->data().GetTextStyles();
327 }
328 return current_anchor_text_styles;
329}
330
331std::vector<int32_t> AXNodePosition::GetWordStartOffsets() const {
332 if (IsNullPosition())
333 return std::vector<int32_t>();
335
336 // Embedded object replacement characters are not represented in |kWordStarts|
337 // attribute.
339 return {0};
340
343}
344
345std::vector<int32_t> AXNodePosition::GetWordEndOffsets() const {
346 if (IsNullPosition())
347 return std::vector<int32_t>();
349
350 // Embedded object replacement characters are not represented in |kWordEnds|
351 // attribute. Since the whole text exposed inside of an embedded object is of
352 // length 1 (the embedded object replacement character), the word end offset
353 // is positioned at 1. Because we want to treat the embedded object
354 // replacement characters as ordinary characters, it wouldn't be consistent to
355 // assume they have no length and return 0 instead of 1.
357 return {1};
358
361}
362
364 if (IsNullPosition())
366 AXNode* node = GetNodeInTree(tree_id(), node_id);
367 int next_on_line_id;
368 if (!node || !node->data().GetIntAttribute(
369 ax::mojom::IntAttribute::kNextOnLineId, &next_on_line_id)) {
371 }
372 return static_cast<AXNode::AXID>(next_on_line_id);
373}
374
376 if (IsNullPosition())
378 AXNode* node = GetNodeInTree(tree_id(), node_id);
379 int previous_on_line_id;
380 if (!node ||
382 &previous_on_line_id)) {
384 }
385 return static_cast<AXNode::AXID>(previous_on_line_id);
386}
387
388AXNode* AXNodePosition::GetParent(AXNode* child,
389 AXTreeID child_tree_id,
390 AXTreeID* parent_tree_id,
391 AXNode::AXID* parent_id) {
392 BASE_DCHECK(parent_tree_id);
393 BASE_DCHECK(parent_id);
394
395 *parent_tree_id = AXTreeIDUnknown();
396 *parent_id = AXNode::kInvalidAXID;
397
398 if (!child)
399 return nullptr;
400
401 AXNode* parent = child->parent();
402 *parent_tree_id = child_tree_id;
403
404 if (!parent) {
405 AXTreeManager* manager =
407 if (manager) {
408 parent = manager->GetParentNodeFromParentTreeAsAXNode();
409 *parent_tree_id = manager->GetParentTreeID();
410 }
411 }
412
413 if (!parent) {
414 *parent_tree_id = AXTreeIDUnknown();
415 return parent;
416 }
417
418 *parent_id = parent->id();
419 return parent;
420}
421
422} // namespace ui
AXNode * GetLowestUnignoredAncestor() const override
int AnchorIndexInParent() const override
~AXNodePosition() override
AXNode::AXID GetPreviousOnLineID(AXNode::AXID node_id) const override
int AnchorSiblingCount() const override
AXPositionInstance Clone() const override
bool IsInTextObject() const override
std::u16string GetText() const override
std::vector< int32_t > GetWordStartOffsets() const override
bool IsInLineBreakingObject() const override
AXNodeTextStyles GetTextStyles() const override
void AnchorParent(AXTreeID *tree_id, AXNode::AXID *parent_id) const override
AXNode::AXID GetNextOnLineID(AXNode::AXID node_id) const override
void AnchorChild(int child_index, AXTreeID *tree_id, AXNode::AXID *child_id) const override
AXNode::AXID GetAnchorID(AXNode *node) const override
bool IsInWhiteSpace() const override
std::vector< int32_t > GetWordEndOffsets() const override
bool IsInLineBreak() const override
ax::mojom::Role GetAnchorRole() const override
bool IsEmbeddedObjectInParent() const override
int AnchorUnignoredChildCount() const override
int AnchorChildCount() const override
AXNode * GetNodeInTree(AXTreeID tree_id, AXNode::AXID node_id) const override
int MaxTextOffset() const override
std::stack< AXNode * > GetAncestorAnchors() const override
ax::mojom::Role GetRole(AXNode *node) const override
static AXPositionInstance CreatePosition(const AXNode &node, int child_index_or_text_offset, ax::mojom::TextAffinity affinity=ax::mojom::TextAffinity::kDownstream)
AXTreeID GetTreeID(AXNode *node) const override
virtual AXTreeID GetAXTreeID() const =0
size_t GetUnignoredChildCount() const
Definition ax_node.cc:37
AXID id() const
Definition ax_node.h:110
OwnerTree * tree() const
Definition ax_node.h:109
int32_t AXID
Definition ax_node.h:36
static constexpr AXID kInvalidAXID
Definition ax_node.h:41
AXNode * GetUnignoredParent() const
Definition ax_node.cc:58
bool IsText() const
Definition ax_node.cc:356
const std::vector< AXNode * > & children() const
Definition ax_node.h:113
AXNode * parent() const
Definition ax_node.h:111
bool IsChildOfLeaf() const
Definition ax_node.cc:1078
bool IsLineBreak() const
Definition ax_node.cc:366
size_t index_in_parent() const
Definition ax_node.h:114
const AXNodeData & data() const
Definition ax_node.h:112
static constexpr char16_t kEmbeddedCharacter
AXPositionInstance CreateChildPositionAt(int child_index) const
std::unique_ptr< AXPosition< AXNodePosition, AXNode > > AXPositionInstance
static AXPositionInstance CreateNullPosition()
static AXPositionInstance CreateTreePosition(AXTreeID tree_id, AXNode::AXID anchor_id, int child_index)
ax::mojom::TextAffinity affinity() const
AXPositionInstance CreateParentPosition(ax::mojom::MoveDirection move_direction=ax::mojom::MoveDirection::kForward) const
static AXPositionInstance CreateTextPosition(AXTreeID tree_id, AXNode::AXID anchor_id, int text_offset, ax::mojom::TextAffinity affinity)
AXTreeManager * GetManagerForChildTree(const AXNode &parent_node)
AXTreeManager * GetManager(AXTreeID tree_id)
static AXTreeManagerMap & GetInstance()
virtual AXTreeID GetTreeID() const =0
virtual AXNode * GetRootAsAXNode() const =0
ScopedAXEmbeddedObjectBehaviorSetter(AXEmbeddedObjectBehavior behavior)
uint8_t value
std::u16string text
constexpr char16_t kWhitespaceUTF16
bool ContainsOnlyChars(std::u16string str, char16_t ch)
AXEmbeddedObjectBehavior
Definition ax_position.h:98
const AXTreeID & AXTreeIDUnknown()
AXEmbeddedObjectBehavior g_ax_embedded_object_behavior
AXNodeTextStyles GetTextStyles() const
ax::mojom::Role role
const std::vector< int32_t > & GetIntListAttribute(ax::mojom::IntListAttribute attribute) const
int GetIntAttribute(ax::mojom::IntAttribute attribute) const
bool GetString16Attribute(ax::mojom::StringAttribute attribute, std::u16string *value) const
#define BASE_DCHECK(condition)
Definition logging.h:63