Flutter Engine
The Flutter Engine
Classes | Public Types | Public Member Functions | Static Public Member Functions | Static Public Attributes | Protected Member Functions | List of all members
ui::AXPosition< AXPositionType, AXNodeType > Class Template Referenceabstract

#include <ax_position.h>

Classes

struct  SerializedPosition
 

Public Types

using AXPositionInstance = std::unique_ptr< AXPosition< AXPositionType, AXNodeType > >
 
using AXRangeType = AXRange< AXPosition< AXPositionType, AXNodeType > >
 
typedef bool BoundaryConditionPredicate(const AXPositionInstance &)
 
typedef std::vector< int32_t > BoundaryTextOffsetsFunc(const AXPositionInstance &)
 

Public Member Functions

virtual ~AXPosition ()=default
 
AXPositionoperator= (const AXPosition &other)
 
virtual AXPositionInstance Clone () const =0
 
SerializedPosition Serialize ()
 
std::string ToString () const
 
AXTreeID tree_id () const
 
AXNode::AXID anchor_id () const
 
AXNodeType * GetAnchor () const
 
AXPositionKind kind () const
 
int child_index () const
 
int text_offset () const
 
ax::mojom::TextAffinity affinity () const
 
bool IsIgnored () const
 
bool IsNullPosition () const
 
bool IsTreePosition () const
 
bool IsLeafTreePosition () const
 
bool IsTextPosition () const
 
bool IsLeafTextPosition () const
 
bool IsLeaf () const
 
bool IsValid () const
 
bool AtStartOfAnchor () const
 
bool AtEndOfAnchor () const
 
bool AtStartOfWord () const
 
bool AtEndOfWord () const
 
bool AtStartOfLine () const
 
bool AtEndOfLine () const
 
bool AtStartOfParagraph () const
 
bool AtEndOfParagraph () const
 
bool AtStartOfPage () const
 
bool AtEndOfPage () const
 
bool AtStartOfAXTree () const
 
bool AtEndOfAXTree () const
 
AXBoundaryType GetFormatStartBoundaryType () const
 
bool AtStartOfFormat () const
 
AXBoundaryType GetFormatEndBoundaryType () const
 
bool AtEndOfFormat () const
 
bool AtStartOfInlineBlock () const
 
bool AtStartOfDocument () const
 
bool AtEndOfDocument () const
 
bool AtLastNodeInTree () const
 
AXNodeType * LowestCommonAnchor (const AXPosition &second) const
 
AXPositionInstance LowestCommonAncestor (const AXPosition &second) const
 
AXPositionInstance CreateAncestorPosition (const AXNodeType *ancestor_anchor, ax::mojom::MoveDirection move_direction=ax::mojom::MoveDirection::kForward) const
 
AXPositionInstance AsValidPosition () const
 
AXPositionInstance AsTreePosition () const
 
AXPositionInstance AsLeafTreePosition () const
 
AXPositionInstance AsTextPosition () const
 
AXPositionInstance AsLeafTextPosition () const
 
AXPositionInstance AsUnignoredPosition (AXPositionAdjustmentBehavior adjustment_behavior) const
 
AXRangeType ExpandToEnclosingTextBoundary (ax::mojom::TextBoundary boundary, AXRangeExpandBehavior expand_behavior) const
 
AXPositionInstance CreatePositionAtTextBoundary (ax::mojom::TextBoundary boundary, ax::mojom::MoveDirection direction, AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreatePositionAtStartOfAnchor () const
 
AXPositionInstance CreatePositionAtEndOfAnchor () const
 
AXPositionInstance CreatePositionAtStartOfAXTree () const
 
AXPositionInstance CreatePositionAtEndOfAXTree () const
 
AXPositionInstance CreatePositionAtStartOfDocument () const
 
AXPositionInstance CreatePositionAtEndOfDocument () const
 
AXPositionInstance CreateChildPositionAt (int child_index) const
 
AXPositionInstance CreateParentPosition (ax::mojom::MoveDirection move_direction=ax::mojom::MoveDirection::kForward) const
 
AXPositionInstance CreateNextLeafTreePosition () const
 
AXPositionInstance CreatePreviousLeafTreePosition () const
 
AXPositionInstance CreateNextLeafTextPosition (bool *crossed_line_breaking_object=nullptr) const
 
AXPositionInstance CreatePreviousLeafTextPosition () const
 
AXPositionInstance AsLeafTextPositionBeforeCharacter () const
 
AXPositionInstance AsLeafTextPositionAfterCharacter () const
 
AXPositionInstance CreateNextCharacterPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreatePreviousCharacterPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreateNextWordStartPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreatePreviousWordStartPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreateNextWordEndPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreatePreviousWordEndPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreateNextLineStartPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreatePreviousLineStartPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreateNextLineEndPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreatePreviousLineEndPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreatePreviousFormatStartPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreateNextFormatEndPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreateNextParagraphStartPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreatePreviousParagraphStartPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreateNextParagraphEndPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreatePreviousParagraphEndPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreateNextPageStartPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreatePreviousPageStartPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreateNextPageEndPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreatePreviousPageEndPosition (AXBoundaryBehavior boundary_behavior) const
 
AXPositionInstance CreateBoundaryStartPosition (AXBoundaryBehavior boundary_behavior, ax::mojom::MoveDirection move_direction, BoundaryConditionPredicate at_start_condition, BoundaryConditionPredicate at_end_condition, BoundaryTextOffsetsFunc get_start_offsets={}) const
 
AXPositionInstance CreateBoundaryEndPosition (AXBoundaryBehavior boundary_behavior, ax::mojom::MoveDirection move_direction, BoundaryConditionPredicate at_start_condition, BoundaryConditionPredicate at_end_condition, BoundaryTextOffsetsFunc get_end_offsets={}) const
 
AXPositionInstance CreateNextAnchorPosition () const
 
AXPositionInstance CreatePreviousAnchorPosition () const
 
std::optional< intCompareTo (const AXPosition &other) const
 
std::optional< intSlowCompareTo (const AXPosition &other) const
 
void SnapToMaxTextOffsetIfBeyond ()
 
bool IsEmptyObjectReplacedByCharacter () const
 
bool IsInDescendantOfEmptyObject () const
 
AXNodeType * GetEmptyObjectAncestorNode () const
 
void swap (AXPosition &other)
 
virtual std::u16string GetText () const =0
 
virtual bool IsInLineBreak () const =0
 
virtual bool IsInTextObject () const =0
 
virtual bool IsInWhiteSpace () const =0
 
virtual int MaxTextOffset () const
 

Static Public Member Functions

static AXPositionInstance CreateNullPosition ()
 
static AXPositionInstance CreateTreePosition (AXTreeID tree_id, AXNode::AXID anchor_id, int child_index)
 
static AXPositionInstance CreateTextPosition (AXTreeID tree_id, AXNode::AXID anchor_id, int text_offset, ax::mojom::TextAffinity affinity)
 
static AXPositionInstance Unserialize (const SerializedPosition &serialization)
 

Static Public Attributes

static const int BEFORE_TEXT = -1
 
static const int INVALID_INDEX = -2
 
static const int INVALID_OFFSET = -1
 
static constexpr char16_t kEmbeddedCharacter = L'\xfffc'
 

Protected Member Functions

 AXPosition ()
 
 AXPosition (const AXPosition &other)
 
int AnchorTextOffsetInParent () const
 
void Initialize (AXPositionKind kind, AXTreeID tree_id, int32_t anchor_id, int child_index, int text_offset, ax::mojom::TextAffinity affinity)
 
virtual void AnchorChild (int child_index, AXTreeID *tree_id, int32_t *child_id) const =0
 
virtual int AnchorChildCount () const =0
 
virtual int AnchorUnignoredChildCount () const =0
 
virtual int AnchorIndexInParent () const =0
 
virtual int AnchorSiblingCount () const =0
 
virtual std::stack< AXNodeType * > GetAncestorAnchors () const =0
 
virtual AXNodeType * GetLowestUnignoredAncestor () const =0
 
virtual void AnchorParent (AXTreeID *tree_id, int32_t *parent_id) const =0
 
virtual AXNodeType * GetNodeInTree (AXTreeID tree_id, int32_t node_id) const =0
 
virtual int32_t GetAnchorID (AXNodeType *node) const =0
 
virtual AXTreeID GetTreeID (AXNodeType *node) const =0
 
int MaxTextOffsetInParent () const
 
virtual bool IsEmbeddedObjectInParent () const =0
 
virtual bool IsInLineBreakingObject () const =0
 
virtual ax::mojom::Role GetAnchorRole () const =0
 
virtual ax::mojom::Role GetRole (AXNodeType *node) const =0
 
virtual AXNodeTextStyles GetTextStyles () const =0
 
virtual std::vector< int32_t > GetWordStartOffsets () const =0
 
virtual std::vector< int32_t > GetWordEndOffsets () const =0
 
virtual int32_t GetNextOnLineID (int32_t node_id) const =0
 
virtual int32_t GetPreviousOnLineID (int32_t node_id) const =0
 

Detailed Description

template<class AXPositionType, class AXNodeType>
class ui::AXPosition< AXPositionType, AXNodeType >

Definition at line 160 of file ax_position.h.

Member Typedef Documentation

◆ AXPositionInstance

template<class AXPositionType , class AXNodeType >
using ui::AXPosition< AXPositionType, AXNodeType >::AXPositionInstance = std::unique_ptr<AXPosition<AXPositionType, AXNodeType> >

Definition at line 162 of file ax_position.h.

◆ AXRangeType

template<class AXPositionType , class AXNodeType >
using ui::AXPosition< AXPositionType, AXNodeType >::AXRangeType = AXRange<AXPosition<AXPositionType, AXNodeType> >

Definition at line 165 of file ax_position.h.

◆ BoundaryConditionPredicate

template<class AXPositionType , class AXNodeType >
typedef bool ui::AXPosition< AXPositionType, AXNodeType >::BoundaryConditionPredicate(const AXPositionInstance &)

Definition at line 167 of file ax_position.h.

◆ BoundaryTextOffsetsFunc

template<class AXPositionType , class AXNodeType >
typedef std::vector< int32_t > ui::AXPosition< AXPositionType, AXNodeType >::BoundaryTextOffsetsFunc(const AXPositionInstance &)

Definition at line 169 of file ax_position.h.

Constructor & Destructor Documentation

◆ ~AXPosition()

template<class AXPositionType , class AXNodeType >
virtual ui::AXPosition< AXPositionType, AXNodeType >::~AXPosition ( )
virtualdefault

◆ AXPosition() [1/2]

template<class AXPositionType , class AXNodeType >
ui::AXPosition< AXPositionType, AXNodeType >::AXPosition ( )
inlineprotected

Definition at line 3214 of file ax_position.h.

3216 tree_id_(AXTreeIDUnknown()),
3217 anchor_id_(AXNode::kInvalidAXID),
3218 child_index_(INVALID_INDEX),
3219 text_offset_(INVALID_OFFSET),
static constexpr AXID kInvalidAXID
Definition: ax_node.h:41
static const int INVALID_OFFSET
Definition: ax_position.h:174
static const int INVALID_INDEX
Definition: ax_position.h:173
const AXTreeID & AXTreeIDUnknown()
Definition: ax_tree_id.cc:103

◆ AXPosition() [2/2]

template<class AXPositionType , class AXNodeType >
ui::AXPosition< AXPositionType, AXNodeType >::AXPosition ( const AXPosition< AXPositionType, AXNodeType > &  other)
inlineprotected

Definition at line 3223 of file ax_position.h.

3224 : kind_(other.kind_),
3225 tree_id_(other.tree_id_),
3226 anchor_id_(other.anchor_id_),
3227 child_index_(other.child_index_),
3228 text_offset_(other.text_offset_),
3229 affinity_(other.affinity_) {}

Member Function Documentation

◆ affinity()

template<class AXPositionType , class AXNodeType >
ax::mojom::TextAffinity ui::AXPosition< AXPositionType, AXNodeType >::affinity ( ) const
inline

Definition at line 328 of file ax_position.h.

328{ return affinity_; }

◆ anchor_id()

template<class AXPositionType , class AXNodeType >
AXNode::AXID ui::AXPosition< AXPositionType, AXNodeType >::anchor_id ( ) const
inline

Definition at line 317 of file ax_position.h.

317{ return anchor_id_; }

◆ AnchorChild()

template<class AXPositionType , class AXNodeType >
virtual void ui::AXPosition< AXPositionType, AXNodeType >::AnchorChild ( int  child_index,
AXTreeID tree_id,
int32_t *  child_id 
) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ AnchorChildCount()

template<class AXPositionType , class AXNodeType >
virtual int ui::AXPosition< AXPositionType, AXNodeType >::AnchorChildCount ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ AnchorIndexInParent()

template<class AXPositionType , class AXNodeType >
virtual int ui::AXPosition< AXPositionType, AXNodeType >::AnchorIndexInParent ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ AnchorParent()

template<class AXPositionType , class AXNodeType >
virtual void ui::AXPosition< AXPositionType, AXNodeType >::AnchorParent ( AXTreeID tree_id,
int32_t *  parent_id 
) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ AnchorSiblingCount()

template<class AXPositionType , class AXNodeType >
virtual int ui::AXPosition< AXPositionType, AXNodeType >::AnchorSiblingCount ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ AnchorTextOffsetInParent()

template<class AXPositionType , class AXNodeType >
int ui::AXPosition< AXPositionType, AXNodeType >::AnchorTextOffsetInParent ( ) const
inlineprotected

Definition at line 3233 of file ax_position.h.

3233 {
3234 if (IsNullPosition())
3235 return INVALID_OFFSET;
3236
3237 // Calculate how much text there is to the left of this anchor.
3238 AXPositionInstance tree_position = AsTreePosition();
3239 BASE_DCHECK(tree_position);
3240 AXPositionInstance parent_position = tree_position->CreateParentPosition();
3241 BASE_DCHECK(parent_position);
3242 if (parent_position->IsNullPosition())
3243 return 0;
3244
3245 int offset_in_parent = 0;
3246 for (int i = 0; i < parent_position->child_index(); ++i) {
3247 AXPositionInstance child = parent_position->CreateChildPositionAt(i);
3248 BASE_DCHECK(child);
3249 offset_in_parent += child->MaxTextOffsetInParent();
3250 }
3251 return offset_in_parent;
3252 }
AXPositionInstance AsTreePosition() const
Definition: ax_position.h:1130
std::unique_ptr< AXPosition< AXPositionType, AXNodeType > > AXPositionInstance
Definition: ax_position.h:163
bool IsNullPosition() const
Definition: ax_position.h:393
#define BASE_DCHECK(condition)
Definition: logging.h:63

◆ AnchorUnignoredChildCount()

template<class AXPositionType , class AXNodeType >
virtual int ui::AXPosition< AXPositionType, AXNodeType >::AnchorUnignoredChildCount ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ AsLeafTextPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::AsLeafTextPosition ( ) const
inline

Definition at line 1301 of file ax_position.h.

1301 {
1302 if (IsNullPosition() || IsLeaf()) {
1303 return AsTextPosition();
1304 }
1305
1306 // Adjust the text offset.
1307 // No need to check for "before text" positions here because they are only
1308 // present on leaf anchor nodes.
1309 AXPositionInstance text_position = AsTextPosition();
1310 int adjusted_offset = text_position->text_offset_;
1311 do {
1312 AXPositionInstance child_position =
1313 text_position->CreateChildPositionAt(0);
1314 BASE_DCHECK(child_position);
1315
1316 // If the text offset corresponds to multiple child positions because some
1317 // of the children have empty text, the condition "adjusted_offset > 0"
1318 // below ensures that the first child will be chosen.
1319 for (int i = 1;
1320 i < text_position->AnchorChildCount() && adjusted_offset > 0; ++i) {
1321 const int max_text_offset_in_parent =
1322 child_position->MaxTextOffsetInParent();
1323 if (adjusted_offset < max_text_offset_in_parent) {
1324 break;
1325 }
1326 if (affinity_ == ax::mojom::TextAffinity::kUpstream &&
1327 adjusted_offset == max_text_offset_in_parent) {
1328 // Maintain upstream affinity so that we'll be able to choose the
1329 // correct leaf anchor if the text offset is right on the boundary
1330 // between two leaves.
1331 child_position->affinity_ = ax::mojom::TextAffinity::kUpstream;
1332 break;
1333 }
1334 child_position = std::move(text_position->CreateChildPositionAt(i));
1335 adjusted_offset -= max_text_offset_in_parent;
1336 }
1337
1338 text_position = std::move(child_position);
1339 } while (!text_position->IsLeaf());
1340
1341 BASE_DCHECK(text_position);
1342 BASE_DCHECK(text_position->IsLeafTextPosition());
1343 text_position->text_offset_ = adjusted_offset;
1344 // A leaf Text position is always downstream since there is no ambiguity as
1345 // to whether it refers to the end of the current or the start of the next
1346 // line.
1347 text_position->affinity_ = ax::mojom::TextAffinity::kDownstream;
1348 return text_position;
1349 }
AXPositionInstance AsTextPosition() const
Definition: ax_position.h:1232
bool IsLeaf() const
Definition: ax_position.h:409

◆ AsLeafTextPositionAfterCharacter()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::AsLeafTextPositionAfterCharacter ( ) const
inline

Definition at line 2100 of file ax_position.h.

2100 {
2101 if (IsNullPosition())
2102 return Clone();
2103
2104 AXPositionInstance text_position = AsTextPosition();
2105 // Temporarily set the affinity to upstream.
2106 //
2107 // This is to ensure that when we find the equivalent leaf text position, it
2108 // will be at the end of anchor if the original position is anchored to a
2109 // node higher up in the tree and pointing to a text offset that falls on
2110 // the boundary between two leaf nodes. In other words, the returned
2111 // position will always be "after character".
2112 text_position->affinity_ = ax::mojom::TextAffinity::kUpstream;
2113 text_position = text_position->AsLeafTextPosition();
2114 BASE_DCHECK(!text_position->IsNullPosition())
2115 << "Adjusting to a leaf position should never turn a non-null position "
2116 "into a null one.";
2117 if (!text_position->IsIgnored() && !text_position->AtStartOfAnchor()) {
2118 // The following situation should not be possible but there are existing
2119 // crashes in the field.
2120 //
2121 // TODO(nektar): Remove this workaround as soon as the source of the bug
2122 // is identified.
2123 BASE_DCHECK(text_position->text_offset_ >= 0);
2124 // TODO(chunhtai): handles grapheme.
2125
2126 // Reset the affinity to downstream, because an upstream affinity doesn't
2127 // make sense on a leaf anchor.
2128 text_position->affinity_ = ax::mojom::TextAffinity::kDownstream;
2129 return text_position;
2130 }
2131 text_position = text_position->CreatePreviousLeafTextPosition();
2132 while (!text_position->IsNullPosition() &&
2133 (text_position->IsIgnored() || !text_position->MaxTextOffset())) {
2134 text_position = text_position->CreatePreviousLeafTextPosition();
2135 }
2136 return text_position->CreatePositionAtEndOfAnchor();
2137 }
virtual AXPositionInstance Clone() const =0

◆ AsLeafTextPositionBeforeCharacter()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::AsLeafTextPositionBeforeCharacter ( ) const
inline

Definition at line 2066 of file ax_position.h.

2066 {
2067 if (IsNullPosition())
2068 return Clone();
2069
2070 AXPositionInstance text_position = AsTextPosition();
2071 // In case the input affinity is upstream, reset it to downstream.
2072 //
2073 // This is to ensure that when we find the equivalent leaf text position, it
2074 // will be at the start of anchor if the original position is anchored to a
2075 // node higher up in the tree and pointing to a text offset that falls on
2076 // the boundary between two leaf nodes. In other words, the returned
2077 // position will always be "before character".
2078 text_position->affinity_ = ax::mojom::TextAffinity::kDownstream;
2079 text_position = text_position->AsLeafTextPosition();
2080 BASE_DCHECK(!text_position->IsNullPosition())
2081 << "Adjusting to a leaf position should never turn a non-null position "
2082 "into a null one.";
2083 if (!text_position->IsIgnored() && !text_position->AtEndOfAnchor()) {
2084 BASE_DCHECK(text_position->text_offset_ >= 0);
2085 return text_position;
2086 }
2087
2088 text_position = text_position->CreateNextLeafTextPosition();
2089 while (!text_position->IsNullPosition() &&
2090 (text_position->IsIgnored() || !text_position->MaxTextOffset())) {
2091 text_position = text_position->CreateNextLeafTextPosition();
2092 }
2093 return text_position;
2094 }

◆ AsLeafTreePosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::AsLeafTreePosition ( ) const
inline

Definition at line 1197 of file ax_position.h.

1197 {
1198 if (IsNullPosition() || IsLeaf())
1199 return AsTreePosition();
1200
1201 // If our text offset is greater than 0, or if our affinity is set to
1202 // upstream, we need to ensure that text offset and affinity will be taken
1203 // into consideration during our descend to the leaves. Switching to a tree
1204 // position early in this case will potentially lose information, so we
1205 // descend using a text position instead.
1206 //
1207 // We purposely don't check whether this position is a text position, to
1208 // allow for the possibility that this position has recently been converted
1209 // from a text to a tree position and text offset or affinity information
1210 // has been left intact.
1211 if (text_offset_ > 0 || affinity_ == ax::mojom::TextAffinity::kUpstream)
1212 return AsLeafTextPosition()->AsTreePosition();
1213
1214 AXPositionInstance tree_position = AsTreePosition();
1215 do {
1216 if (tree_position->child_index_ == tree_position->AnchorChildCount()) {
1217 tree_position =
1218 tree_position
1219 ->CreateChildPositionAt(tree_position->child_index_ - 1)
1220 ->CreatePositionAtEndOfAnchor();
1221 } else {
1222 tree_position =
1223 tree_position->CreateChildPositionAt(tree_position->child_index_);
1224 }
1225 BASE_DCHECK(tree_position && !tree_position->IsNullPosition());
1226 } while (!tree_position->IsLeaf());
1227
1228 BASE_DCHECK(tree_position && tree_position->IsLeafTreePosition());
1229 return tree_position;
1230 }
AXPositionInstance AsLeafTextPosition() const
Definition: ax_position.h:1301

◆ AsTextPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::AsTextPosition ( ) const
inline

Definition at line 1232 of file ax_position.h.

1232 {
1233 if (IsNullPosition() || IsTextPosition())
1234 return Clone();
1235
1238 // Check if it is a "before text" position.
1239 if (copy->child_index_ == BEFORE_TEXT) {
1240 // "Before text" positions can only appear on leaf nodes.
1241 BASE_DCHECK(copy->IsLeaf());
1242 // If the current text offset is valid, we don't touch it to potentially
1243 // allow converting from a text position to a tree position and back
1244 // without losing information.
1245 //
1246 // We test for INVALID_OFFSET first, due to the possible performance
1247 // implications of calling MaxTextOffset().
1248 BASE_DCHECK(copy->text_offset_ >= INVALID_OFFSET);
1249 if (copy->text_offset_ == INVALID_OFFSET ||
1250 (copy->text_offset_ > 0 &&
1251 copy->text_offset_ >= copy->MaxTextOffset())) {
1252 copy->text_offset_ = 0;
1253 }
1254 } else if (copy->child_index_ == copy->AnchorChildCount()) {
1255 copy->text_offset_ = copy->MaxTextOffset();
1256 } else {
1257 BASE_DCHECK(copy->child_index_ >= 0);
1258 BASE_DCHECK(copy->child_index_ < copy->AnchorChildCount());
1259 int new_offset = 0;
1260 for (int i = 0; i <= child_index_; ++i) {
1261 AXPositionInstance child = copy->CreateChildPositionAt(i);
1262 BASE_DCHECK(child);
1263 // If the current text offset is valid, we don't touch it to
1264 // potentially allow converting from a text position to a tree
1265 // position and back without losing information. Otherwise, if the
1266 // text_offset is invalid, equals to 0 or is smaller than
1267 // |new_offset|, we reset it to the beginning of the current child
1268 // node.
1269 if (i == child_index_ && copy->text_offset_ <= new_offset) {
1270 copy->text_offset_ = new_offset;
1271 break;
1272 }
1273
1274 int child_length = child->MaxTextOffsetInParent();
1275 // Same comment as above: we don't touch the text offset if it's
1276 // already valid.
1277 if (i == child_index_ &&
1278 (copy->text_offset_ > (new_offset + child_length) ||
1279 // When the text offset is equal to the text's length but this is
1280 // not an "after text" position.
1281 (!copy->AtEndOfAnchor() &&
1282 copy->text_offset_ == (new_offset + child_length)))) {
1283 copy->text_offset_ = new_offset;
1284 break;
1285 }
1286
1287 new_offset += child_length;
1288 }
1289 }
1290
1291 // Affinity should always be left as downstream. The only case when the
1292 // resulting text position is at the end of the line is when we get an
1293 // "after text" leaf position, but even in this case downstream is
1294 // appropriate because there is no ambiguity whetehr the position is at the
1295 // end of the current line vs. the start of the next line. It would always
1296 // be the former.
1298 return copy;
1299 }
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
Definition: SkSwizzler.cpp:31
bool IsTextPosition() const
Definition: ax_position.h:403
static const int BEFORE_TEXT
Definition: ax_position.h:172
Definition: copy.py:1

◆ AsTreePosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::AsTreePosition ( ) const
inline

Definition at line 1130 of file ax_position.h.

1130 {
1131 if (IsNullPosition() || IsTreePosition())
1132 return Clone();
1133
1136 BASE_DCHECK(copy->text_offset_ >= 0);
1137 if (copy->IsLeaf()) {
1138 const int max_text_offset = copy->MaxTextOffset();
1139 copy->child_index_ =
1140 (max_text_offset != 0 && copy->text_offset_ != max_text_offset)
1141 ? BEFORE_TEXT
1142 : 0;
1144 return copy;
1145 }
1146
1147 // We stop at the last child that we can reach with the current text offset
1148 // and ignore any remaining children. This is for defensive programming
1149 // purposes, in case "MaxTextOffset" doesn't match the total length of all
1150 // our children. This may happen if, for example, there is a bug in the
1151 // internal accessibility tree we get from the renderer. In contrast, the
1152 // current offset could not be greater than the length of all our children
1153 // because the position would have been invalid.
1154 int current_offset = 0;
1155 int child_index = 0;
1156 for (; child_index < copy->AnchorChildCount(); ++child_index) {
1157 AXPositionInstance child = copy->CreateChildPositionAt(child_index);
1158 BASE_DCHECK(child);
1159 int child_length = child->MaxTextOffsetInParent();
1160 // If the text offset falls on the boundary between two adjacent children,
1161 // we look at the affinity to decide whether to place the tree position on
1162 // the first child vs. the second child. Upstream affinity would always
1163 // choose the first child, whilst downstream affinity the second. This
1164 // also has implications when converting the resulting tree position back
1165 // to a text position. In that case, maintaining an upstream affinity
1166 // would place the text position at the end of the first child, whilst
1167 // maintaining a downstream affinity will place the text position at the
1168 // beginning of the second child.
1169 //
1170 // This is vital for text positions on soft line breaks, as well as text
1171 // positions before and after character, to work properly.
1172 //
1173 // See also `CreateLeafTextPositionBeforeCharacter` and
1174 // `CreateLeafTextPositionAfterCharacter`.
1175 if (copy->text_offset_ >= current_offset &&
1176 (copy->text_offset_ < (current_offset + child_length) ||
1178 copy->text_offset_ == (current_offset + child_length)))) {
1179 break;
1180 }
1181
1182 current_offset += child_length;
1183 }
1184
1185 copy->child_index_ = child_index;
1187 return copy;
1188 }
int child_index() const
Definition: ax_position.h:326
bool IsTreePosition() const
Definition: ax_position.h:397

◆ AsUnignoredPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::AsUnignoredPosition ( AXPositionAdjustmentBehavior  adjustment_behavior) const
inline

Definition at line 1367 of file ax_position.h.

1368 {
1369 if (IsNullPosition() || !IsIgnored())
1370 return Clone();
1371
1372 AXPositionInstance leaf_tree_position = AsLeafTreePosition();
1373
1374 // If this is a text position, first try moving up to a parent equivalent
1375 // position and check if the resulting position is still ignored. This
1376 // won't result in the loss of any information. We can't do that in the
1377 // case of tree positions, because we would be better off to move to the
1378 // next or previous position within the same anchor, as this would lose
1379 // less information than moving to a parent equivalent position.
1380 //
1381 // Text positions are considered ignored if either the current anchor is
1382 // ignored, or if the equivalent leaf tree position is ignored.
1383 // If this position is a leaf text position, or the equivalent leaf tree
1384 // position is ignored, then it's not possible to create an ancestor text
1385 // position that is unignored.
1386 if (IsTextPosition() && !IsLeafTextPosition() &&
1387 !leaf_tree_position->IsIgnored()) {
1388 AXPositionInstance unignored_position = CreateParentPosition();
1389 while (!unignored_position->IsNullPosition()) {
1390 // Since the equivalent leaf tree position is unignored, search for the
1391 // first unignored ancestor anchor and return that text position.
1392 if (!unignored_position->GetAnchor()->IsIgnored()) {
1393 BASE_DCHECK(!unignored_position->IsIgnored());
1394 return unignored_position;
1395 }
1396 unignored_position = unignored_position->CreateParentPosition();
1397 }
1398 }
1399
1400 // There is a possibility that the position became unignored by moving to a
1401 // leaf equivalent position. Otherwise, we have no choice but to move to the
1402 // next or previous position and lose some information in the process.
1403 while (leaf_tree_position->IsIgnored()) {
1404 switch (adjustment_behavior) {
1406 leaf_tree_position = leaf_tree_position->CreateNextLeafTreePosition();
1407 break;
1409 leaf_tree_position =
1410 leaf_tree_position->CreatePreviousLeafTreePosition();
1411 // in case the unignored leaf node contains some text, ensure that the
1412 // resulting position is an "after text" position, as such a position
1413 // would be the closest to the ignored one, given the fact that we are
1414 // moving backwards through the tree.
1415 leaf_tree_position =
1416 leaf_tree_position->CreatePositionAtEndOfAnchor();
1417 break;
1418 }
1419 }
1420
1421 if (IsTextPosition())
1422 return leaf_tree_position->AsTextPosition();
1423 return leaf_tree_position;
1424 }
AXPositionInstance AsLeafTreePosition() const
Definition: ax_position.h:1197
bool IsLeafTextPosition() const
Definition: ax_position.h:407
AXPositionInstance CreateParentPosition(ax::mojom::MoveDirection move_direction=ax::mojom::MoveDirection::kForward) const
Definition: ax_position.h:1874
bool IsIgnored() const
Definition: ax_position.h:330

◆ AsValidPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::AsValidPosition ( ) const
inline

Definition at line 1060 of file ax_position.h.

1060 {
1061 AXPositionInstance position = Clone();
1062 switch (position->kind_) {
1064 // We avoid cloning to ensure that all fields will be valid.
1065 return CreateNullPosition();
1067 if (!position->GetAnchor())
1068 return CreateNullPosition();
1069
1070 if (AXNodeType* empty_object_node = GetEmptyObjectAncestorNode()) {
1071 // In this class and on certain platforms, we define the empty object
1072 // as one that doesn't expose its underlying content. Its content is
1073 // replaced by the empty object character (string of length 1). A
1074 // position on a descendant of an empty object is invalid. To make it
1075 // valid we move the position from the descendant to the empty object
1076 // node itself.
1077 return CreateTreePosition(
1078 position->tree_id(), GetAnchorID(empty_object_node),
1079 position->child_index() == BEFORE_TEXT ? BEFORE_TEXT : 0);
1080 }
1081
1082 if (position->child_index_ == BEFORE_TEXT)
1083 return position;
1084
1085 if (position->child_index_ < 0)
1086 position->child_index_ = 0;
1087 else if (position->child_index_ > position->AnchorChildCount())
1088 position->child_index_ = position->AnchorChildCount();
1089 break;
1090 }
1092 if (!position->GetAnchor())
1093 return CreateNullPosition();
1094
1095 if (AXNodeType* empty_object_node = GetEmptyObjectAncestorNode()) {
1096 // This is needed because an empty object as defined in this class and
1097 // on certain platforms can have descendants that should not be
1098 // exposed. See comment above in similar implementation for
1099 // AXPositionKind::TREE_POSITION.
1100 //
1101 // We set the |text_offset_| to either 0 or 1 here because the
1102 // MaxTextOffset of an empty object is 1 (the empty object character,
1103 // a string of length 1). If the invalid position was already at the
1104 // start of the node, we set it to 0.
1105 return CreateTextPosition(position->tree_id(),
1106 GetAnchorID(empty_object_node),
1107 position->text_offset() > 0 ? 1 : 0,
1109 }
1110
1111 if (position->text_offset_ <= 0) {
1112 // 0 is always a valid offset, so skip calling MaxTextOffset in that
1113 // case.
1114 position->text_offset_ = 0;
1115 position->affinity_ = ax::mojom::TextAffinity::kDownstream;
1116 } else {
1117 int max_text_offset = position->MaxTextOffset();
1118 if (position->text_offset_ > max_text_offset) {
1119 position->text_offset_ = max_text_offset;
1120 position->affinity_ = ax::mojom::TextAffinity::kDownstream;
1121 }
1122 }
1123 break;
1124 }
1125 }
1126 BASE_DCHECK(position->IsValid());
1127 return position;
1128 }
AXNodeType * GetEmptyObjectAncestorNode() const
Definition: ax_position.h:3138
static AXPositionInstance CreateNullPosition()
Definition: ax_position.h:183
static AXPositionInstance CreateTreePosition(AXTreeID tree_id, AXNode::AXID anchor_id, int child_index)
Definition: ax_position.h:191
static AXPositionInstance CreateTextPosition(AXTreeID tree_id, AXNode::AXID anchor_id, int text_offset, ax::mojom::TextAffinity affinity)
Definition: ax_position.h:201
virtual int32_t GetAnchorID(AXNodeType *node) const =0

◆ AtEndOfAnchor()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtEndOfAnchor ( ) const
inline

Definition at line 464 of file ax_position.h.

464 {
465 if (!GetAnchor())
466 return false;
467 switch (kind_) {
469 return false;
471 return child_index_ == AnchorChildCount();
473 return text_offset_ == MaxTextOffset();
474 }
475 }
virtual int MaxTextOffset() const
Definition: ax_position.h:3207
virtual int AnchorChildCount() const =0
AXNodeType * GetAnchor() const
Definition: ax_position.h:319

◆ AtEndOfAXTree()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtEndOfAXTree ( ) const
inline

Definition at line 859 of file ax_position.h.

859 {
860 if (IsNullPosition())
861 return false;
862
863 if (AtEndOfAnchor()) {
865
866 // Consider the end of the document as the end of an AXTree.
867 if (next_anchor->IsNullPosition())
868 return true;
869 else
870 return next_anchor->tree_id() != tree_id();
871 }
872 return false;
873 }
AXTreeID tree_id() const
Definition: ax_position.h:316
AXPositionInstance CreateNextAnchorPosition() const
Definition: ax_position.h:2814
bool AtEndOfAnchor() const
Definition: ax_position.h:464

◆ AtEndOfDocument()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtEndOfDocument ( ) const
inline

Definition at line 991 of file ax_position.h.

991 {
992 if (IsNullPosition())
993 return false;
994 return AtLastNodeInTree() && AtEndOfAnchor();
995 }
bool AtLastNodeInTree() const
Definition: ax_position.h:997

◆ AtEndOfFormat()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtEndOfFormat ( ) const
inline

Definition at line 937 of file ax_position.h.

937 {
939 }
AXBoundaryType GetFormatEndBoundaryType() const
Definition: ax_position.h:908

◆ AtEndOfLine()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtEndOfLine ( ) const
inline

Definition at line 556 of file ax_position.h.

556 {
557 AXPositionInstance text_position = AsLeafTextPosition();
558 switch (text_position->kind_) {
560 return false;
563 return false;
565 // Text positions on objects with no text should not be considered at
566 // end of line because the empty position may share a text offset with
567 // a non-empty text position in which case the end of line iterators
568 // must move to the line end of the non-empty content. Specified next
569 // line IDs are ignored.
570 if (!text_position->MaxTextOffset())
571 return false;
572
573 // If affinity has been used to specify whether the caret is at the end
574 // of a line or at the start of the next one, this should have been
575 // reflected in the leaf text position we got via "AsLeafTextPosition".
576 // If affinity had been set to upstream, the leaf text position should
577 // be pointing to the end of the inline text box that ends the first
578 // line. If it had been set to downstream, the leaf text position should
579 // be pointing to the start of the inline text box that starts the
580 // second line.
581 //
582 // In other cases, we assume that white space, including but not limited
583 // to hard line breaks, might be used to separate lines. For example, an
584 // inline text box with just a single space character inside it can be
585 // used to represent a soft line break. If an inline text box containing
586 // white space separates two lines, it should always be connected to the
587 // first line via "kPreviousOnLineId". This is guaranteed by the
588 // renderer. If there are multiple line breaks separating the two lines,
589 // then only the first line break is connected to the first line via
590 // "kPreviousOnLineId".
591 //
592 // We don't treat a position that is at the start of white space that is
593 // on a line by itself as being at the end of the line. This is in order
594 // to enable screen readers to recognize and announce blank lines
595 // correctly. However, we do treat positions at the start of white space
596 // that end a line of text as being at the end of that line. We also
597 // treat positions at the end of white space that is on a line by
598 // itself, i.e. on a blank line, as being at the end of that line.
599 //
600 // Sometimes there might be an inline text box with a single space in it
601 // at the end of a text field. We should mark positions that are at the
602 // end of text fields, or in general at the end of an anchor with no
603 // "kNextOnLineId", as being at end of line, except when that anchor is
604 // an inline text box that is in the middle of a text span. Note that
605 // in most but not all cases, the parent of an inline text box is a
606 // static text object, whose end signifies the end of the text span. One
607 // exception is line breaks.
608 if (GetNextOnLineID(text_position->anchor_id_) ==
610 return (!text_position->AtEndOfTextSpan() &&
611 text_position->IsInWhiteSpace() &&
612 GetPreviousOnLineID(text_position->anchor_id_) !=
614 ? text_position->AtStartOfAnchor()
615 : text_position->AtEndOfAnchor();
616 }
617
618 // The current anchor might be followed by a soft line break.
619 return text_position->AtEndOfAnchor() &&
620 text_position->CreateNextLeafTextPosition()->AtEndOfLine();
621 }
622 }
virtual int32_t GetNextOnLineID(int32_t node_id) const =0
virtual int32_t GetPreviousOnLineID(int32_t node_id) const =0
#define BASE_UNREACHABLE()
Definition: logging.h:69

◆ AtEndOfPage()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtEndOfPage ( ) const
inline

Definition at line 817 of file ax_position.h.

817 {
818 AXPositionInstance text_position = AsLeafTextPosition();
819 switch (text_position->kind_) {
821 return false;
824 return false;
826 if (!text_position->AtEndOfAnchor())
827 return false;
828
829 // Search for the next text position within the current page,
830 // using the page boundary abort predicate.
831 // If a valid position was found, then this position cannot be
832 // the end of a page.
833 // This will return a null position when an anchor movement would
834 // cross a page boundary, or the end of document was reached.
835 AXPositionInstance next_text_position =
836 text_position->CreateNextTextAnchorPosition(
837 AbortMoveAtPageBoundary);
838 return next_text_position->IsNullPosition();
839 }
840 }
841 }

◆ AtEndOfParagraph()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtEndOfParagraph ( ) const
inline

Definition at line 718 of file ax_position.h.

718 {
719 AXPositionInstance text_position = AsLeafTextPosition();
720 switch (text_position->kind_) {
722 return false;
725 return false;
727 // 1. The current leaf text position must be an unignored position at
728 // the end of an anchor.
729 if (text_position->IsIgnored() || !text_position->AtEndOfAnchor())
730 return false;
731
732 // 2. Either (a) the current leaf text position is the last leaf text
733 // position in the document, or (b) there are no line breaking
734 // objects between it and the next leaf text position except when
735 // the next leaf text position is whitespace only since whitespace
736 // must be collapsed.
737 //
738 // Search for the next text position within the current paragraph,
739 // using the paragraph boundary abort predicate.
740 // If a null position was found, then this position must be the end of
741 // a paragraph.
742 // |CreateNextTextAnchorPosition| + |AbortMoveAtParagraphBoundary|
743 // will return a null position when an anchor movement would
744 // cross a paragraph boundary and there is no doubt that it is the end
745 // of a paragraph, or the end of document was reached.
746 // There are some fringe cases related to whitespace collapse that
747 // cannot be handled easily with only |AbortMoveAtParagraphBoundary|.
748 bool crossed_line_breaking_object_token = false;
749 auto abort_move_predicate =
750 [&crossed_line_breaking_object_token](
751 const AXPosition& move_from, const AXPosition& move_to,
752 const AXMoveType type, const AXMoveDirection direction) {
753 return AbortMoveAtParagraphBoundary(
754 crossed_line_breaking_object_token, move_from, move_to, type,
755 direction);
756 };
757
758 AXPositionInstance next_text_position = text_position->Clone();
759 do {
760 next_text_position = next_text_position->CreateNextTextAnchorPosition(
761 abort_move_predicate);
762 } while (next_text_position->IsIgnored());
763 if (next_text_position->IsNullPosition())
764 return true;
765
766 // 3. If there is a next leaf text position then it must not be
767 // whitespace only.
768 if (next_text_position->IsInWhiteSpace())
769 return false;
770
771 // 4. If there is a next leaf text position and it is not whitespace
772 // only, it must also be the start of a paragraph for the current
773 // position to be the end of a paragraph.
774 //
775 // Consider the following example :
776 // ++{1} kStaticText "First Paragraph"
777 // ++++{2} kInlineTextBox "First Paragraph"
778 // ++{3} kStaticText "\n Second Paragraph"
779 // ++++{4} kInlineTextBox "\n" kIsLineBreakingObject
780 // ++++{5} kInlineTextBox " "
781 // ++++{6} kInlineTextBox "Second Paragraph"
782 // A position at the end of {5} is the end of a paragraph, because
783 // the first paragraph must collapse trailing whitespace and contain
784 // leaf text anchors {2, 4, 5}. The second paragraph is only {6}.
785 return next_text_position->CreatePositionAtStartOfAnchor()
786 ->AtStartOfParagraph();
787 }
788 }
789 }
GLenum type

◆ AtEndOfWord()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtEndOfWord ( ) const
inline

Definition at line 494 of file ax_position.h.

494 {
495 AXPositionInstance text_position = AsLeafTextPosition();
496 switch (text_position->kind_) {
498 return false;
501 return false;
503 const std::vector<int32_t> word_ends =
504 text_position->GetWordEndOffsets();
505 return base::Contains(word_ends, int32_t{text_position->text_offset_});
506 }
507 }
508 }
bool Contains(const Container &container, const Value &value)

◆ AtLastNodeInTree()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtLastNodeInTree ( ) const
inline

Definition at line 997 of file ax_position.h.

997 {
998 if (IsNullPosition())
999 return false;
1000
1001 // Avoid a potentionally expensive MaxTextOffset call by only using tree
1002 // positions. The only thing that matters is whether our anchor_id_ is at
1003 // the last anchor of the document, so we're free to ignore text_offset_.
1004 AXPositionInstance tree_position =
1005 CreateTreePosition(tree_id_, anchor_id_, 0);
1006 return tree_position->CreateNextAnchorPosition()->IsNullPosition();
1007 }

◆ AtStartOfAnchor()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtStartOfAnchor ( ) const
inline

Definition at line 447 of file ax_position.h.

447 {
448 if (!GetAnchor())
449 return false;
450 switch (kind_) {
452 return false;
454 if (text_offset_ > 0)
455 return false;
456 if (!IsLeaf() || text_offset_ == 0)
457 return child_index_ == 0;
458 return child_index_ == BEFORE_TEXT;
460 return text_offset_ == 0;
461 }
462 }

◆ AtStartOfAXTree()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtStartOfAXTree ( ) const
inline

Definition at line 843 of file ax_position.h.

843 {
844 if (IsNullPosition())
845 return false;
846
847 if (AtStartOfAnchor()) {
849
850 // Consider the start of the document as the start of an AXTree.
851 if (previous_anchor->IsNullPosition())
852 return true;
853 else
854 return previous_anchor->tree_id() != tree_id();
855 }
856 return false;
857 }
AXPositionInstance CreatePreviousAnchorPosition() const
Definition: ax_position.h:2819
bool AtStartOfAnchor() const
Definition: ax_position.h:447

◆ AtStartOfDocument()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtStartOfDocument ( ) const
inline

Definition at line 985 of file ax_position.h.

985 {
986 if (IsNullPosition())
987 return false;
989 }
virtual ax::mojom::Role GetAnchorRole() const =0
bool IsDocument(const ax::mojom::Role role)

◆ AtStartOfFormat()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtStartOfFormat ( ) const
inline

Definition at line 904 of file ax_position.h.

904 {
906 }
AXBoundaryType GetFormatStartBoundaryType() const
Definition: ax_position.h:875

◆ AtStartOfInlineBlock()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtStartOfInlineBlock ( ) const
inline

Definition at line 941 of file ax_position.h.

941 {
942 AXPositionInstance text_position = AsLeafTextPosition();
943 switch (text_position->kind_) {
945 return false;
948 return false;
950 if (text_position->AtStartOfAnchor()) {
951 AXPositionInstance previous_position =
952 text_position->CreatePreviousLeafTreePosition();
953
954 // Check that this position is not the start of the first anchor.
955 if (!previous_position->IsNullPosition()) {
956 previous_position = text_position->CreatePreviousLeafTreePosition(
957 &AbortMoveAtStartOfInlineBlock);
958
959 // If we get a null position here it means we have crossed an inline
960 // block's start, thus this position is located at such start.
961 if (previous_position->IsNullPosition())
962 return true;
963 }
964 }
965 if (text_position->AtEndOfAnchor()) {
966 AXPositionInstance next_position =
967 text_position->CreateNextLeafTreePosition();
968
969 // Check that this position is not the end of the last anchor.
970 if (!next_position->IsNullPosition()) {
971 next_position = text_position->CreateNextLeafTreePosition(
972 &AbortMoveAtStartOfInlineBlock);
973
974 // If we get a null position here it means we have crossed an inline
975 // block's start, thus this position is located at such start.
976 if (next_position->IsNullPosition())
977 return true;
978 }
979 }
980 return false;
981 }
982 }
983 }

◆ AtStartOfLine()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtStartOfLine ( ) const
inline

Definition at line 510 of file ax_position.h.

510 {
511 AXPositionInstance text_position = AsLeafTextPosition();
512 switch (text_position->kind_) {
514 return false;
517 return false;
519 // We treat a position after some white space that is not connected to
520 // any node after it via "next on line ID", to be equivalent to a
521 // position before the next line, and therefore as being at start of
522 // line.
523 //
524 // We assume that white space, including but not limited to hard line
525 // breaks, might be used to separate lines. For example, an inline text
526 // box with just a single space character inside it can be used to
527 // represent a soft line break. If an inline text box containing white
528 // space separates two lines, it should always be connected to the first
529 // line via "kPreviousOnLineId". This is guaranteed by the renderer. If
530 // there are multiple line breaks separating the two lines, then only
531 // the first line break is connected to the first line via
532 // "kPreviousOnLineId".
533 //
534 // Sometimes there might be an inline text box with a single space in it
535 // at the end of a text field. We should not mark positions that are at
536 // the end of text fields, or in general at the end of their anchor, as
537 // being at the start of line, except when that anchor is an inline text
538 // box that is in the middle of a text span. Note that in most but not
539 // all cases, the parent of an inline text box is a static text object,
540 // whose end signifies the end of the text span. One exception is line
541 // breaks.
542 if (text_position->AtEndOfAnchor() &&
543 !text_position->AtEndOfTextSpan() &&
544 text_position->IsInWhiteSpace() &&
545 GetNextOnLineID(text_position->anchor_id_) ==
547 return true;
548 }
549
550 return GetPreviousOnLineID(text_position->anchor_id_) ==
552 text_position->AtStartOfAnchor();
553 }
554 }

◆ AtStartOfPage()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtStartOfPage ( ) const
inline

Definition at line 791 of file ax_position.h.

791 {
792 AXPositionInstance text_position = AsLeafTextPosition();
793 switch (text_position->kind_) {
795 return false;
798 return false;
800 if (!text_position->AtStartOfAnchor())
801 return false;
802
803 // Search for the previous text position within the current page,
804 // using the page boundary abort predicate.
805 // If a valid position was found, then this position cannot be
806 // the start of a page.
807 // This will return a null position when an anchor movement would
808 // cross a page boundary, or the start of document was reached.
809 AXPositionInstance previous_text_position =
810 text_position->CreatePreviousTextAnchorPosition(
811 AbortMoveAtPageBoundary);
812 return previous_text_position->IsNullPosition();
813 }
814 }
815 }

◆ AtStartOfParagraph()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtStartOfParagraph ( ) const
inline

Definition at line 639 of file ax_position.h.

639 {
640 AXPositionInstance text_position = AsLeafTextPosition();
641 switch (text_position->kind_) {
643 return false;
646 return false;
648 // 1. The current leaf text position must be an unignored position at
649 // the start of an anchor.
650 if (text_position->IsIgnored() || !text_position->AtStartOfAnchor())
651 return false;
652
653 // 2. The current position is not whitespace only, unless it is also
654 // the first leaf text position within the document.
655 if (text_position->IsInWhiteSpace()) {
656 return text_position->CreatePreviousLeafTextPosition()
657 ->IsNullPosition();
658 }
659
660 // 3. Either (a) the current leaf text position is the first leaf text
661 // position in the document, or (b) there are no line breaking
662 // objects between it and the previous non-whitespace leaf text
663 // position.
664 //
665 // Search for the previous text position within the current paragraph,
666 // using the paragraph boundary abort predicate.
667 // If a valid position was found, then this position cannot be
668 // the start of a paragraph.
669 // This will return a null position when an anchor movement would
670 // cross a paragraph boundary, or the start of document was reached.
671 bool crossed_line_breaking_object_token = false;
672 auto abort_move_predicate =
673 [&crossed_line_breaking_object_token](
674 const AXPosition& move_from, const AXPosition& move_to,
675 const AXMoveType type, const AXMoveDirection direction) {
676 return AbortMoveAtParagraphBoundary(
677 crossed_line_breaking_object_token, move_from, move_to, type,
678 direction);
679 };
680
681 AXPositionInstance previous_text_position = text_position->Clone();
682 do {
683 previous_text_position =
684 previous_text_position->CreatePreviousTextAnchorPosition(
685 abort_move_predicate);
686 // If the previous position is whitespace, then continue searching
687 // until a non-whitespace leaf text position is found within the
688 // current paragraph because whitespace is supposed to be collapsed.
689 // There's a chance that |CreatePreviousTextAnchorPosition| will
690 // return whitespace that should be appended to a previous paragraph
691 // rather than separating two pieces of the current paragraph.
692 } while (previous_text_position->IsInWhiteSpace() ||
693 previous_text_position->IsIgnored());
694 return previous_text_position->IsNullPosition();
695 }
696 }
697 }

◆ AtStartOfWord()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::AtStartOfWord ( ) const
inline

Definition at line 477 of file ax_position.h.

477 {
478 AXPositionInstance text_position = AsLeafTextPosition();
479 switch (text_position->kind_) {
481 return false;
484 return false;
486 const std::vector<int32_t> word_starts =
487 text_position->GetWordStartOffsets();
488 return base::Contains(word_starts,
489 int32_t{text_position->text_offset_});
490 }
491 }
492 }

◆ child_index()

template<class AXPositionType , class AXNodeType >
int ui::AXPosition< AXPositionType, AXNodeType >::child_index ( ) const
inline

Definition at line 326 of file ax_position.h.

326{ return child_index_; }

◆ Clone()

template<class AXPositionType , class AXNodeType >
virtual AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::Clone ( ) const
pure virtual

Implemented in ui::AXNodePosition.

◆ CompareTo()

template<class AXPositionType , class AXNodeType >
std::optional< int > ui::AXPosition< AXPositionType, AXNodeType >::CompareTo ( const AXPosition< AXPositionType, AXNodeType > &  other) const
inline

Definition at line 2833 of file ax_position.h.

2833 {
2834 if (this->IsNullPosition() && other.IsNullPosition())
2835 return std::optional<int>(0);
2836 if (this->IsNullPosition() || other.IsNullPosition())
2837 return std::optional<int>(std::nullopt);
2838
2839 // If both positions share an anchor and are of the same type, we can do a
2840 // straight compare of text offsets or child indices.
2841 if (GetAnchor() == other.GetAnchor()) {
2842 if (IsTextPosition() && other.IsTextPosition())
2843 return text_offset() - other.text_offset();
2844 if (IsTreePosition() && other.IsTreePosition())
2845 return child_index() - other.child_index();
2846 }
2847
2848 // Ancestor positions are expensive to compute. If possible, we will avoid
2849 // doing so by computing the ancestor chain of the two positions' anchors.
2850 // If the lowest common ancestor is neither position's anchor, we can use
2851 // the order of the first uncommon ancestors as a proxy for the order of the
2852 // positions.
2853 //
2854 // In order to do that, we need to normalize text positions at the end of an
2855 // anchor to equivalent positions at the start of the next anchor. Ignored
2856 // positions are a special case in that they need to be shifted to the
2857 // nearest unignored position in order to be normalized. That shifting can
2858 // change the comparison result, so if we have an ignored position, we must
2859 // use the slow path.
2860 if (IsIgnored() || other.IsIgnored())
2861 return SlowCompareTo(other);
2862
2863 // Normalize any text positions at the end of an anchor to equivalent
2864 // positions at the start of the next anchor.
2865 AXPositionInstance normalized_this_position = Clone();
2866 if (normalized_this_position->IsTextPosition()) {
2867 normalized_this_position =
2868 normalized_this_position->AsLeafTextPositionBeforeCharacter();
2869 }
2870
2871 AXPositionInstance normalized_other_position = other.Clone();
2872 if (normalized_other_position->IsTextPosition()) {
2873 normalized_other_position =
2874 normalized_other_position->AsLeafTextPositionBeforeCharacter();
2875 }
2876
2877 if (normalized_this_position->IsNullPosition()) {
2878 if (normalized_other_position->IsNullPosition()) {
2879 // Both positions normalized to a position past the end of the document.
2880 BASE_DCHECK(SlowCompareTo(other).value() == 0);
2881 return 0;
2882 }
2883 // |this| normalized to a position past the end of the document.
2884 BASE_DCHECK(SlowCompareTo(other).value() > 0);
2885 return 1;
2886 } else if (normalized_other_position->IsNullPosition()) {
2887 // |other| normalized to a position past the end of the document.
2888 BASE_DCHECK(SlowCompareTo(other).value() < 0);
2889 return -1;
2890 }
2891
2892 // Compute the ancestor stacks of both positions and walk them ourselves
2893 // rather than calling LowestCommonAnchor(). That way, we can discover the
2894 // first uncommon ancestors.
2895 const AXNodeType* common_anchor = nullptr;
2896 std::stack<AXNodeType*> our_ancestors =
2897 normalized_this_position->GetAncestorAnchors();
2898 std::stack<AXNodeType*> other_ancestors =
2899 normalized_other_position->GetAncestorAnchors();
2900 while (!our_ancestors.empty() && !other_ancestors.empty() &&
2901 our_ancestors.top() == other_ancestors.top()) {
2902 common_anchor = our_ancestors.top();
2903 our_ancestors.pop();
2904 other_ancestors.pop();
2905 }
2906
2907 if (!common_anchor)
2908 return std::optional<int>(std::nullopt);
2909
2910 // If each position has an uncommon ancestor node, we can compare those
2911 // instead of needing to compute ancestor positions.
2912 if (!our_ancestors.empty() && !other_ancestors.empty()) {
2913 AXPositionInstance this_uncommon_tree_position = CreateTreePosition(
2914 GetTreeID(our_ancestors.top()), GetAnchorID(our_ancestors.top()),
2915 0 /*child_index*/);
2916 int this_uncommon_ancestor_index =
2917 this_uncommon_tree_position->AnchorIndexInParent();
2918 AXPositionInstance other_uncommon_tree_position = CreateTreePosition(
2919 GetTreeID(other_ancestors.top()), GetAnchorID(other_ancestors.top()),
2920 0 /*child_index*/);
2921 int other_uncommon_ancestor_index =
2922 other_uncommon_tree_position->AnchorIndexInParent();
2923 BASE_DCHECK(this_uncommon_ancestor_index !=
2924 other_uncommon_ancestor_index);
2925 int result = this_uncommon_ancestor_index - other_uncommon_ancestor_index;
2926
2927 // On platforms that support embedded objects, if a text position is
2928 // within an embedded object and if it is not at the start of that object,
2929 // the resulting ancestor position should be adjusted to point after the
2930 // embedded object. Otherwise, assistive software will not be able to get
2931 // out of the embedded object if its text is not editable when navigating
2932 // by character.
2933 //
2934 // For example, look at the following accessibility tree and the two
2935 // example text positions together with their equivalent ancestor
2936 // positions.
2937 // ++1 kRootWebArea
2938 // ++++2 kTextField "Before<embedded_object>after"
2939 // ++++++3 kStaticText "Before"
2940 // ++++++++4 kInlineTextBox "Before"
2941 // ++++++5 kImage "Test image"
2942 // ++++++6 kStaticText "after"
2943 // ++++++++7 kInlineTextBox "after"
2944 //
2945 // Note that the alt text of an image cannot be navigated with cursor
2946 // left/right, even when the rest of the contents are in a
2947 // contenteditable.
2948 //
2949 // Ancestor position should not be adjusted:
2950 // TextPosition anchor_id=kImage text_offset=0 affinity=downstream
2951 // annotated_text=<T>est image AncestorTextPosition anchor_id=kTextField
2952 // text_offset=6 affinity=downstream
2953 // annotated_text=Before<embedded_object>after
2954 //
2955 // Ancestor position should be adjusted:
2956 // TextPosition anchor_id=kImage text_offset=1 affinity=downstream
2957 // annotated_text=T<e>st image AncestorTextPosition anchor_id=kTextField
2958 // text_offset=7 affinity=downstream
2959 // annotated_text=Beforeembedded_object<a>fter
2960 //
2961 // Note that since the adjustment to the distance between the ancestor
2962 // positions could at most be by one, we skip doing this check if the
2963 // ancestor positions have a distance of more than one since it can never
2964 // change the outcome of the comparison. Note too that if both ancestor
2965 // positions need to be adjusted, the adjustments will cancel out.
2966 if (abs(result) == 1) {
2967 if (!normalized_this_position->AtStartOfAnchor() &&
2968 this_uncommon_tree_position->IsEmbeddedObjectInParent()) {
2969 result += 1;
2970 }
2971 if (!normalized_other_position->AtStartOfAnchor() &&
2972 other_uncommon_tree_position->IsEmbeddedObjectInParent()) {
2973 result -= 1;
2974 }
2975 }
2976
2977#ifndef NDEBUG
2978 // Validate the optimization.
2979 int slow_result = SlowCompareTo(other).value();
2980 BASE_DCHECK((result == 0 && slow_result == 0) ||
2981 (result < 0 && slow_result < 0) ||
2982 (result > 0 && slow_result > 0));
2983#endif
2984
2985 return result;
2986 }
2987
2988 return SlowCompareTo(other);
2989 }
virtual AXTreeID GetTreeID(AXNodeType *node) const =0
std::optional< int > SlowCompareTo(const AXPosition &other) const
Definition: ax_position.h:2991
int text_offset() const
Definition: ax_position.h:327
uint8_t value
GAsyncResult * result
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition: SkVx.h:707

◆ CreateAncestorPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateAncestorPosition ( const AXNodeType *  ancestor_anchor,
ax::mojom::MoveDirection  move_direction = ax::mojom::MoveDirection::kForward 
) const
inline

Definition at line 1041 of file ax_position.h.

1044 {
1045 if (!ancestor_anchor) {
1046 return CreateNullPosition();
1047 }
1048
1049 AXPositionInstance ancestor_position = Clone();
1050 while (!ancestor_position->IsNullPosition() &&
1051 ancestor_position->GetAnchor() != ancestor_anchor) {
1052 ancestor_position =
1053 ancestor_position->CreateParentPosition(move_direction);
1054 }
1055 return ancestor_position;
1056 }

◆ CreateBoundaryEndPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateBoundaryEndPosition ( AXBoundaryBehavior  boundary_behavior,
ax::mojom::MoveDirection  move_direction,
BoundaryConditionPredicate  at_start_condition,
BoundaryConditionPredicate  at_end_condition,
BoundaryTextOffsetsFunc  get_end_offsets = {} 
) const
inline

Definition at line 2675 of file ax_position.h.

2680 {}) const {
2681 AXPositionInstance text_position = AsLeafTextPosition();
2682 if (text_position->IsNullPosition())
2683 return text_position;
2684
2685 if (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary) {
2686 text_position =
2687 text_position->CreateAdjacentLeafTextPosition(move_direction);
2688 if (text_position->IsNullPosition()) {
2689 // There is no adjacent position to move to; in such case, CrossBoundary
2690 // behavior shall return a null position, while any other behavior shall
2691 // fallback to return the initial position.
2692 if (boundary_behavior == AXBoundaryBehavior::CrossBoundary)
2693 return text_position;
2694 return Clone();
2695 }
2696 }
2697
2698 if (!at_end_condition(text_position)) {
2699 text_position = text_position->CreatePositionAtNextOffsetBoundary(
2700 move_direction, get_end_offsets);
2701
2702 while (!at_end_condition(text_position)) {
2703 AXPositionInstance next_position;
2704 if (move_direction == ax::mojom::MoveDirection::kForward) {
2705 if (text_position->AtEndOfAnchor()) {
2706 next_position = text_position->CreateNextLeafTextPosition();
2707 } else {
2708 text_position = text_position->CreatePositionAtEndOfAnchor();
2709 BASE_DCHECK(!text_position->IsNullPosition());
2710 continue;
2711 }
2712 } else {
2713 next_position = text_position->CreatePreviousLeafTextPosition()
2714 ->CreatePositionAtEndOfAnchor();
2715 }
2716
2717 if (next_position->IsNullPosition()) {
2718 if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
2719 switch (move_direction) {
2721 return CreatePositionAtEndOfAnchor()->AsUnignoredPosition(
2724 return CreatePositionAtStartOfAnchor()->AsUnignoredPosition(
2726 }
2727 }
2728
2729 if (boundary_behavior ==
2731 // We can't simply return the following position; break and after
2732 // this loop we'll try to do some adjustments to text_position.
2733 switch (move_direction) {
2735 text_position = text_position->CreatePositionAtEndOfAnchor();
2736 break;
2738 text_position = text_position->CreatePositionAtStartOfAnchor();
2739 break;
2740 }
2741
2742 break;
2743 }
2744
2745 return next_position->AsUnignoredPosition(
2746 AdjustmentBehaviorFromBoundaryDirection(move_direction));
2747 }
2748
2749 // Continue searching for the next boundary end in the specified
2750 // direction until the next logical text position is reached.
2751 text_position = next_position->CreatePositionAtFirstOffsetBoundary(
2752 move_direction, get_end_offsets);
2753 }
2754 }
2755
2756 // If the boundary is in the same subtree, return a position rooted at this
2757 // position's anchor. This is necessary because we don't want to return a
2758 // position that might be in the shadow DOM when this position is not.
2759 const AXNodeType* common_anchor = text_position->LowestCommonAnchor(*this);
2760 if (GetAnchor() == common_anchor) {
2761 text_position =
2762 text_position->CreateAncestorPosition(common_anchor, move_direction);
2763 } else if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
2764 switch (move_direction) {
2766 return CreatePositionAtEndOfAnchor()->AsUnignoredPosition(
2769 return CreatePositionAtStartOfAnchor()->AsUnignoredPosition(
2771 }
2772 }
2773
2774 // If there is no ambiguity as to whether the position is at the end of
2775 // the current boundary or the start of the next boundary, an upstream
2776 // affinity should be reset to downstream in order to get consistent output
2777 // from this method, regardless of input affinity.
2778 //
2779 // Note that there could be no ambiguity if the boundary is either at the
2780 // start or the end of the current anchor, so we should always reset to
2781 // downstream affinity in those cases.
2782 if (text_position->affinity_ == ax::mojom::TextAffinity::kUpstream) {
2783 AXPositionInstance downstream_position = text_position->Clone();
2784 downstream_position->affinity_ = ax::mojom::TextAffinity::kDownstream;
2785 if (downstream_position->AtStartOfAnchor() ||
2786 downstream_position->AtEndOfAnchor() ||
2787 !at_start_condition(downstream_position)) {
2788 text_position->affinity_ = ax::mojom::TextAffinity::kDownstream;
2789 }
2790 }
2791
2792 if (IsTreePosition())
2793 text_position = text_position->AsTreePosition();
2794 AXPositionInstance unignored_position = text_position->AsUnignoredPosition(
2795 AdjustmentBehaviorFromBoundaryDirection(move_direction));
2796 // If there are no unignored positions in |move_direction| then
2797 // |text_position| is anchored in ignored content at the start or end
2798 // of the document.
2799 // For StopAtLastAnchorBoundary, try to adjust in the opposite direction
2800 // to return a position within the document just before crossing into
2801 // the ignored content. This will be the last unignored anchor boundary.
2802 if (unignored_position->IsNullPosition() &&
2803 boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary) {
2804 unignored_position =
2805 text_position->AsUnignoredPosition(OppositeAdjustmentBehavior(
2806 AdjustmentBehaviorFromBoundaryDirection(move_direction)));
2807 }
2808 return unignored_position;
2809 }
AXPositionInstance CreatePositionAtStartOfAnchor() const
Definition: ax_position.h:1698
AXPositionInstance CreatePositionAtEndOfAnchor() const
Definition: ax_position.h:1713

◆ CreateBoundaryStartPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateBoundaryStartPosition ( AXBoundaryBehavior  boundary_behavior,
ax::mojom::MoveDirection  move_direction,
BoundaryConditionPredicate  at_start_condition,
BoundaryConditionPredicate  at_end_condition,
BoundaryTextOffsetsFunc  get_start_offsets = {} 
) const
inline

Definition at line 2555 of file ax_position.h.

2560 {}) const {
2561 AXPositionInstance text_position = AsLeafTextPosition();
2562 if (text_position->IsNullPosition())
2563 return text_position;
2564
2565 if (boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary) {
2566 text_position =
2567 text_position->CreateAdjacentLeafTextPosition(move_direction);
2568 if (text_position->IsNullPosition()) {
2569 // There is no adjacent position to move to; in such case, CrossBoundary
2570 // behavior shall return a null position, while any other behavior shall
2571 // fallback to return the initial position.
2572 if (boundary_behavior == AXBoundaryBehavior::CrossBoundary)
2573 return text_position;
2574 return Clone();
2575 }
2576 }
2577
2578 if (!at_start_condition(text_position)) {
2579 text_position = text_position->CreatePositionAtNextOffsetBoundary(
2580 move_direction, get_start_offsets);
2581
2582 while (!at_start_condition(text_position)) {
2583 AXPositionInstance next_position;
2584 if (move_direction == ax::mojom::MoveDirection::kForward) {
2585 next_position = text_position->CreateNextLeafTextPosition();
2586 } else {
2587 if (text_position->AtStartOfAnchor()) {
2588 next_position = text_position->CreatePreviousLeafTextPosition();
2589 } else {
2590 text_position = text_position->CreatePositionAtStartOfAnchor();
2591 BASE_DCHECK(!text_position->IsNullPosition());
2592 continue;
2593 }
2594 }
2595
2596 if (next_position->IsNullPosition()) {
2597 if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
2598 switch (move_direction) {
2600 return CreatePositionAtEndOfAnchor()->AsUnignoredPosition(
2603 return CreatePositionAtStartOfAnchor()->AsUnignoredPosition(
2605 }
2606 }
2607
2608 if (boundary_behavior ==
2610 // We can't simply return the following position; break and after
2611 // this loop we'll try to do some adjustments to text_position.
2612 switch (move_direction) {
2614 text_position = text_position->CreatePositionAtEndOfAnchor();
2615 break;
2617 text_position = text_position->CreatePositionAtStartOfAnchor();
2618 break;
2619 }
2620
2621 break;
2622 }
2623
2624 return next_position->AsUnignoredPosition(
2625 AdjustmentBehaviorFromBoundaryDirection(move_direction));
2626 }
2627
2628 // Continue searching for the next boundary start in the specified
2629 // direction until the next logical text position is reached.
2630 text_position = next_position->CreatePositionAtFirstOffsetBoundary(
2631 move_direction, get_start_offsets);
2632 }
2633 }
2634
2635 // If the boundary is in the same subtree, return a position rooted at this
2636 // position's anchor. This is necessary because we don't want to return a
2637 // position that might be in the shadow DOM when this position is not.
2638 const AXNodeType* common_anchor = text_position->LowestCommonAnchor(*this);
2639 if (GetAnchor() == common_anchor) {
2640 text_position =
2641 text_position->CreateAncestorPosition(common_anchor, move_direction);
2642 } else if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
2643 switch (move_direction) {
2645 return CreatePositionAtEndOfAnchor()->AsUnignoredPosition(
2648 return CreatePositionAtStartOfAnchor()->AsUnignoredPosition(
2650 }
2651 }
2652
2653 // Affinity is only upstream at the end of a line, and so a start boundary
2654 // will never have an upstream affinity.
2655 text_position->affinity_ = ax::mojom::TextAffinity::kDownstream;
2656 if (IsTreePosition())
2657 text_position = text_position->AsTreePosition();
2658 AXPositionInstance unignored_position = text_position->AsUnignoredPosition(
2659 AdjustmentBehaviorFromBoundaryDirection(move_direction));
2660 // If there are no unignored positions in |move_direction| then
2661 // |text_position| is anchored in ignored content at the start or end
2662 // of the document.
2663 // For StopAtLastAnchorBoundary, try to adjust in the opposite direction
2664 // to return a position within the document just before crossing into
2665 // the ignored content. This will be the last unignored anchor boundary.
2666 if (unignored_position->IsNullPosition() &&
2667 boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary) {
2668 unignored_position =
2669 text_position->AsUnignoredPosition(OppositeAdjustmentBehavior(
2670 AdjustmentBehaviorFromBoundaryDirection(move_direction)));
2671 }
2672 return unignored_position;
2673 }

◆ CreateChildPositionAt()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateChildPositionAt ( int  child_index) const
inline

Definition at line 1820 of file ax_position.h.

1820 {
1821 if (IsNullPosition() || IsLeaf())
1822 return CreateNullPosition();
1823
1824 if (child_index < 0 || child_index >= AnchorChildCount())
1825 return CreateNullPosition();
1826
1827 AXTreeID tree_id = AXTreeIDUnknown();
1829 AnchorChild(child_index, &tree_id, &child_id);
1831 BASE_DCHECK(child_id != AXNode::kInvalidAXID);
1832 switch (kind_) {
1835 return CreateNullPosition();
1837 AXPositionInstance child_position =
1838 CreateTreePosition(tree_id, child_id, 0 /* child_index */);
1839 // If the child's anchor is a leaf node, make this a "before text"
1840 // position.
1841 if (child_position->IsLeaf())
1842 child_position->child_index_ = BEFORE_TEXT;
1843 return child_position;
1844 }
1846 return CreateTextPosition(tree_id, child_id, 0 /* text_offset */,
1848 }
1849
1850 return CreateNullPosition();
1851 }
int32_t AXID
Definition: ax_node.h:36
virtual void AnchorChild(int child_index, AXTreeID *tree_id, int32_t *child_id) const =0

◆ CreateNextAnchorPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextAnchorPosition ( ) const
inline

Definition at line 2814 of file ax_position.h.

2814 {
2815 return CreateNextAnchorPosition(&DefaultAbortMovePredicate);
2816 }

◆ CreateNextCharacterPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextCharacterPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2148 of file ax_position.h.

2149 {
2150 if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary &&
2151 AtEndOfAnchor()) {
2152 return Clone();
2153 }
2154
2155 // There is no next character position.
2157 if (text_position->IsNullPosition()) {
2158 if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary ||
2159 boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary) {
2160 text_position = Clone();
2161 }
2162 return text_position;
2163 }
2164
2165 if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
2166 *text_position == *this) {
2167 return Clone();
2168 }
2169 BASE_DCHECK(text_position->text_offset_ < text_position->MaxTextOffset());
2170 // TODO(chunhtai): Need to consider grapheme cluster.
2171 ++text_position->text_offset_;
2172 BASE_DCHECK(text_position->text_offset_ > 0);
2173 BASE_DCHECK(text_position->text_offset_ <= text_position->MaxTextOffset());
2174 // If the character boundary is in the same subtree, return a position
2175 // rooted at this position's anchor. This is necessary because we don't want
2176 // to return a position that might be in the shadow DOM when this position
2177 // is not.
2178 const AXNodeType* common_anchor = text_position->LowestCommonAnchor(*this);
2179 if (GetAnchor() == common_anchor) {
2180 text_position = text_position->CreateAncestorPosition(
2181 common_anchor, ax::mojom::MoveDirection::kForward);
2182 } else if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
2183 // If the next character position crosses the current anchor boundary
2184 // with StopAtAnchorBoundary, snap to the end of the current anchor.
2186 }
2187 // Even if the resulting position is right on a soft line break, affinity is
2188 // defaulted to downstream so that this method will always produce the same
2189 // result regardless of the direction of motion or the input affinity.
2190 text_position->affinity_ = ax::mojom::TextAffinity::kDownstream;
2191 if (IsTreePosition())
2192 return text_position->AsTreePosition();
2193 return text_position;
2194 }
AXPositionInstance AsLeafTextPositionBeforeCharacter() const
Definition: ax_position.h:2066

◆ CreateNextFormatEndPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextFormatEndPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2378 of file ax_position.h.

2379 {
2380 if (IsNullPosition())
2381 return Clone();
2382
2383 AXBoundaryType boundary_type = GetFormatEndBoundaryType();
2384 if (boundary_type != AXBoundaryType::kNone) {
2385 if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary ||
2386 (boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary &&
2387 boundary_type == AXBoundaryType::kDocumentEnd)) {
2388 AXPositionInstance clone = Clone();
2389 // In order to make equality checks simpler, affinity should be reset so
2390 // that we would get consistent output from this function regardless of
2391 // input affinity.
2392 clone->affinity_ = ax::mojom::TextAffinity::kDownstream;
2393 return clone;
2394 } else if (boundary_behavior == AXBoundaryBehavior::CrossBoundary &&
2395 boundary_type == AXBoundaryType::kDocumentEnd) {
2396 // If we're at a format boundary and there are no more text positions
2397 // to traverse, return a null position for cross-boundary moves.
2398 return CreateNullPosition();
2399 }
2400 }
2401
2402 AXPositionInstance tree_position =
2403 AsTreePosition()->CreatePositionAtEndOfAnchor();
2404 AXPositionInstance next_tree_position =
2405 tree_position->CreateNextLeafTreePosition()
2406 ->CreatePositionAtEndOfAnchor();
2407
2408 // If moving to the end of the current anchor hasn't changed our original
2409 // position, we need to test the next leaf tree position.
2410 if (AtEndOfAnchor() &&
2411 boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary) {
2412 tree_position = std::move(next_tree_position);
2413 next_tree_position = tree_position->CreateNextLeafTreePosition()
2414 ->CreatePositionAtEndOfAnchor();
2415 }
2416
2417 // The last position in the document is also a format end boundary, so we
2418 // should not return NullPosition unless we started from that location.
2419 while (boundary_type != AXBoundaryType::kDocumentEnd &&
2420 !next_tree_position->IsNullPosition() &&
2421 !tree_position->AtEndOfFormat()) {
2422 tree_position = std::move(next_tree_position);
2423 next_tree_position = tree_position->CreateNextLeafTreePosition()
2424 ->CreatePositionAtEndOfAnchor();
2425 }
2426
2427 // If the format boundary is in the same subtree, return a position
2428 // rooted at the current position.
2429 // This is necessary because we don't want to return any position that might
2430 // be in the shadow DOM if the original position was not.
2431 const AXNodeType* common_anchor = tree_position->LowestCommonAnchor(*this);
2432 if (GetAnchor() == common_anchor) {
2433 tree_position = tree_position->CreateAncestorPosition(
2434 common_anchor, ax::mojom::MoveDirection::kForward);
2435 } else if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
2437 }
2438
2439 if (IsTextPosition())
2440 return tree_position->AsTextPosition();
2441 return tree_position;
2442 }
AXBoundaryType
Definition: ax_position.h:53

◆ CreateNextLeafTextPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextLeafTextPosition ( bool *  crossed_line_breaking_object = nullptr) const
inline

Definition at line 2009 of file ax_position.h.

2010 {
2011 if (crossed_line_breaking_object)
2012 *crossed_line_breaking_object = false;
2013
2014 // If this is an ancestor text position, resolve to its leaf text position.
2015 if (IsTextPosition() && !IsLeaf())
2016 return AsLeafTextPosition();
2017 std::function<AbortMovePredicate> abort_move_predicate;
2018 if (crossed_line_breaking_object) {
2019 abort_move_predicate = [crossed_line_breaking_object](
2020 const AXPosition& move_from,
2021 const AXPosition& move_to,
2022 const AXMoveType type,
2023 const AXMoveDirection direction) {
2024 return UpdateCrossedLineBreakingObjectToken(
2025 *crossed_line_breaking_object, move_from, move_to, type, direction);
2026 };
2027 } else {
2028 abort_move_predicate =
2029 [](const AXPosition& move_from, const AXPosition& move_to,
2030 const AXMoveType type, const AXMoveDirection direction) {
2031 return AXPosition::DefaultAbortMovePredicate(move_from, move_to,
2032 type, direction);
2033 };
2034 }
2035 return CreateNextLeafTreePosition(abort_move_predicate)->AsTextPosition();
2036 }
AXPositionInstance CreateNextLeafTreePosition() const
Definition: ax_position.h:1994

◆ CreateNextLeafTreePosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextLeafTreePosition ( ) const
inline

Definition at line 1994 of file ax_position.h.

1994 {
1995 return CreateNextLeafTreePosition(&DefaultAbortMovePredicate);
1996 }

◆ CreateNextLineEndPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextLineEndPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2298 of file ax_position.h.

2299 {
2301 boundary_behavior, ax::mojom::MoveDirection::kForward,
2302 &AtStartOfLinePredicate, &AtEndOfLinePredicate);
2303 }
AXPositionInstance CreateBoundaryEndPosition(AXBoundaryBehavior boundary_behavior, ax::mojom::MoveDirection move_direction, BoundaryConditionPredicate at_start_condition, BoundaryConditionPredicate at_end_condition, BoundaryTextOffsetsFunc get_end_offsets={}) const
Definition: ax_position.h:2675

◆ CreateNextLineStartPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextLineStartPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2282 of file ax_position.h.

2283 {
2285 boundary_behavior, ax::mojom::MoveDirection::kForward,
2286 &AtStartOfLinePredicate, &AtEndOfLinePredicate);
2287 }
AXPositionInstance CreateBoundaryStartPosition(AXBoundaryBehavior boundary_behavior, ax::mojom::MoveDirection move_direction, BoundaryConditionPredicate at_start_condition, BoundaryConditionPredicate at_end_condition, BoundaryTextOffsetsFunc get_start_offsets={}) const
Definition: ax_position.h:2555

◆ CreateNextPageEndPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextPageEndPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2541 of file ax_position.h.

2542 {
2544 boundary_behavior, ax::mojom::MoveDirection::kForward,
2545 &AtStartOfPagePredicate, &AtEndOfPagePredicate);
2546 }

◆ CreateNextPageStartPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextPageStartPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2527 of file ax_position.h.

2528 {
2530 boundary_behavior, ax::mojom::MoveDirection::kForward,
2531 &AtStartOfPagePredicate, &AtEndOfPagePredicate);
2532 }

◆ CreateNextParagraphEndPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextParagraphEndPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2458 of file ax_position.h.

2459 {
2461 boundary_behavior, ax::mojom::MoveDirection::kForward,
2462 &AtStartOfParagraphPredicate, &AtEndOfParagraphPredicate);
2463 }

◆ CreateNextParagraphStartPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextParagraphStartPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2444 of file ax_position.h.

2445 {
2447 boundary_behavior, ax::mojom::MoveDirection::kForward,
2448 &AtStartOfParagraphPredicate, &AtEndOfParagraphPredicate);
2449 }

◆ CreateNextWordEndPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextWordEndPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2267 of file ax_position.h.

2268 {
2270 boundary_behavior, ax::mojom::MoveDirection::kForward,
2271 &AtStartOfWordPredicate, &AtEndOfWordPredicate, &GetWordEndOffsetsFunc);
2272 }

◆ CreateNextWordStartPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNextWordStartPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2250 of file ax_position.h.

2251 {
2253 boundary_behavior, ax::mojom::MoveDirection::kForward,
2254 &AtStartOfWordPredicate, &AtEndOfWordPredicate,
2255 &GetWordStartOffsetsFunc);
2256 }

◆ CreateNullPosition()

template<class AXPositionType , class AXNodeType >
static AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateNullPosition ( )
inlinestatic

Definition at line 183 of file ax_position.h.

183 {
184 AXPositionInstance new_position(new AXPositionType());
185 new_position->Initialize(
188 return new_position;
189 }

◆ CreateParentPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateParentPosition ( ax::mojom::MoveDirection  move_direction = ax::mojom::MoveDirection::kForward) const
inline

Definition at line 1874 of file ax_position.h.

1876 {
1877 if (IsNullPosition())
1878 return CreateNullPosition();
1879
1880 AXTreeID tree_id = AXTreeIDUnknown();
1882 AnchorParent(&tree_id, &parent_id);
1883 if (tree_id == AXTreeIDUnknown() || parent_id == AXNode::kInvalidAXID)
1884 return CreateNullPosition();
1885
1886 switch (kind_) {
1889 return CreateNullPosition();
1891 return CreateTreePosition(tree_id, parent_id, AnchorIndexInParent());
1893 // On some platforms, such as Android, Mac and Chrome OS, the inner text
1894 // of a node is made up by concatenating the text of child nodes. On
1895 // other platforms, such as Windows IA2 and Linux ATK, child nodes are
1896 // represented by a single embedded object character.
1897 //
1898 // If our parent's inner text is a concatenation of all its children's
1899 // text, we need to maintain the affinity and compute the corresponding
1900 // text offset. Otherwise, we have no choice but to return a position
1901 // that is either before or after this child, losing some information in
1902 // the process. Regardless to whether our parent contains all our text,
1903 // we always recompute the affinity when the position is after the
1904 // child.
1905 //
1906 // Recomputing the affinity in the latter situation is important because
1907 // even though a text position might unambiguously be at the end of a
1908 // line, its parent position might be the same as the parent position of
1909 // a position that represents the start of the next line. For example:
1910 //
1911 // staticText name='Line oneLine two'
1912 // ++inlineTextBox name='Line one'
1913 // ++inlineTextBox name='Line two'
1914 //
1915 // If the original position is at the end of the inline text box for
1916 // "Line one", then the resulting parent equivalent position would be
1917 // the same as the one that would have been computed if the original
1918 // position were at the start of the inline text box for "Line two".
1919 const int max_text_offset = MaxTextOffset();
1920 int max_text_offset_in_parent =
1921 IsEmbeddedObjectInParent() ? 1 : max_text_offset;
1922 int parent_offset = AnchorTextOffsetInParent();
1923 ax::mojom::TextAffinity parent_affinity = affinity_;
1924 if (max_text_offset == max_text_offset_in_parent) {
1925 // Our parent contains all our text. No information would be lost when
1926 // moving to a parent equivalent position.
1927 parent_offset += text_offset_;
1928 } else if (text_offset_ > 0) {
1929 // If "text_offset_" == 0, then the child position is clearly before
1930 // any embedded object character. No information would be lost when
1931 // moving to a parent equivalent position, including affinity
1932 // information. Otherwise, we should decide whether to set the parent
1933 // position to be before or after the child, based on the direction of
1934 // motion, and also reset the affinity.
1935 switch (move_direction) {
1937 // Keep the offset to be right before the embedded object
1938 // character.
1939 break;
1941 // Set the offset to be after the embedded object character.
1942 parent_offset += max_text_offset_in_parent;
1943 break;
1944 }
1945
1946 // The original affinity doesn't apply any more. In most cases, it
1947 // should be downstream, unless there is an ambiguity as to whether
1948 // the parent position is between the end of one line and the start of
1949 // the next. We perform this check below.
1950 parent_affinity = ax::mojom::TextAffinity::kDownstream;
1951 }
1952
1953 // This dummy position serves to retrieve the max text offset of the
1954 // anchor-node in which we want to create the parent position.
1955 AXPositionInstance dummy_position =
1956 CreateTextPosition(tree_id, parent_id, 0, parent_affinity);
1957 max_text_offset_in_parent = dummy_position->MaxTextOffset();
1958 if (parent_offset > max_text_offset_in_parent) {
1959 parent_offset = max_text_offset_in_parent;
1960 }
1961 AXPositionInstance parent_position = CreateTextPosition(
1962 tree_id, parent_id, parent_offset, parent_affinity);
1963
1964 // If the current position is pointing at the end of its anchor, we need
1965 // to check if the parent position has introduced ambiguity as to
1966 // whether it refers to the end of a line or the start of the next.
1967 // Ambiguity is only present when the parent position points to a text
1968 // offset that is neither at the start nor at the end of its anchor. We
1969 // check for ambiguity by creating the parent position and testing if it
1970 // is erroneously at the start of the next line. Given that the current
1971 // position, by the nature of being at the end of its anchor, could only
1972 // be at end of line, the fact that the parent position is also
1973 // determined to be at start of line demonstrates the presence of
1974 // ambiguity which is resolved by setting its affinity to upstream.
1975 //
1976 // We could not have
1977 // checked if the child was at the end of the line, because our
1978 // "AtEndOfLine" predicate takes into account trailing line breaks,
1979 // which would create false positives.
1980 if (text_offset_ == max_text_offset &&
1981 !parent_position->AtEndOfAnchor() &&
1982 parent_position->AtStartOfLine()) {
1983 parent_position->affinity_ = ax::mojom::TextAffinity::kUpstream;
1984 }
1985 return parent_position;
1986 }
1987 }
1988
1989 return CreateNullPosition();
1990 }
virtual bool IsEmbeddedObjectInParent() const =0
virtual void AnchorParent(AXTreeID *tree_id, int32_t *parent_id) const =0
virtual int AnchorIndexInParent() const =0
int AnchorTextOffsetInParent() const
Definition: ax_position.h:3233

◆ CreatePositionAtEndOfAnchor()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePositionAtEndOfAnchor ( ) const
inline

Definition at line 1713 of file ax_position.h.

1713 {
1714 switch (kind_) {
1716 return CreateNullPosition();
1718 return CreateTreePosition(
1719 tree_id_, anchor_id_,
1722 return CreateTextPosition(tree_id_, anchor_id_, MaxTextOffset(),
1724 }
1725 return CreateNullPosition();
1726 }
bool IsEmptyObjectReplacedByCharacter() const
Definition: ax_position.h:3094

◆ CreatePositionAtEndOfAXTree()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePositionAtEndOfAXTree ( ) const
inline

Definition at line 1751 of file ax_position.h.

1751 {
1752 if (IsNullPosition() || AtEndOfAXTree())
1753 return Clone();
1754
1755 // First check for positions on nodes which are AXTree boundaries, but where
1756 // the text position on that node is not at the end of the anchor.
1759
1760 // Iterate over tree positions until a boundary is reached.
1761 AXPositionInstance next_position = AsTreePosition();
1762 do {
1763 next_position = next_position->CreateNextAnchorPosition()
1764 ->CreatePositionAtEndOfAnchor();
1765 } while (!next_position->AtEndOfAXTree());
1766
1767 // This method should not cross tree boundaries.
1768 BASE_DCHECK(next_position->tree_id() == tree_id());
1769
1770 if (IsTextPosition())
1771 next_position = next_position->AsTextPosition();
1772 return next_position->CreatePositionAtEndOfAnchor();
1773 }
bool AtEndOfAXTree() const
Definition: ax_position.h:859

◆ CreatePositionAtEndOfDocument()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePositionAtEndOfDocument ( ) const
inline

Definition at line 1805 of file ax_position.h.

1805 {
1806 AXPositionInstance position =
1807 AsTreePosition()->CreateDocumentAncestorPosition();
1808 if (!position->IsNullPosition()) {
1809 while (!position->IsLeaf()) {
1810 position =
1811 position->CreateChildPositionAt(position->AnchorChildCount() - 1);
1812 }
1813 position = position->CreatePositionAtEndOfAnchor();
1814 if (IsTextPosition())
1815 position = position->AsTextPosition();
1816 }
1817 return position;
1818 }

◆ CreatePositionAtStartOfAnchor()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePositionAtStartOfAnchor ( ) const
inline

Definition at line 1698 of file ax_position.h.

1698 {
1699 switch (kind_) {
1701 return CreateNullPosition();
1703 if (IsLeaf())
1704 return CreateTreePosition(tree_id_, anchor_id_, BEFORE_TEXT);
1705 return CreateTreePosition(tree_id_, anchor_id_, 0 /* child_index */);
1707 return CreateTextPosition(tree_id_, anchor_id_, 0 /* text_offset */,
1709 }
1710 return CreateNullPosition();
1711 }

◆ CreatePositionAtStartOfAXTree()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePositionAtStartOfAXTree ( ) const
inline

Definition at line 1728 of file ax_position.h.

1728 {
1730 return Clone();
1731
1732 // First check for positions on nodes which are AXTree boundaries, but where
1733 // the text position on that node is not at the start of the anchor.
1736
1737 // Iterate over tree positions until a boundary is reached.
1738 AXPositionInstance previous_position = AsTreePosition();
1739 do {
1740 previous_position = previous_position->CreatePreviousAnchorPosition();
1741 } while (!previous_position->AtStartOfAXTree());
1742
1743 // This method should not cross tree boundaries.
1744 BASE_DCHECK(previous_position->tree_id() == tree_id());
1745
1746 if (IsTextPosition())
1747 previous_position = previous_position->AsTextPosition();
1748 return previous_position;
1749 }
bool AtStartOfAXTree() const
Definition: ax_position.h:843

◆ CreatePositionAtStartOfDocument()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePositionAtStartOfDocument ( ) const
inline

Definition at line 1785 of file ax_position.h.

1785 {
1786 AXPositionInstance position =
1787 AsTreePosition()->CreateDocumentAncestorPosition();
1788 if (!position->IsNullPosition()) {
1789 position = position->CreatePositionAtStartOfAnchor();
1790 if (IsTextPosition())
1791 position = position->AsTextPosition();
1792 }
1793 return position;
1794 }

◆ CreatePositionAtTextBoundary()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePositionAtTextBoundary ( ax::mojom::TextBoundary  boundary,
ax::mojom::MoveDirection  direction,
AXBoundaryBehavior  boundary_behavior 
) const
inline

Definition at line 1475 of file ax_position.h.

1478 {
1479 AXPositionInstance resulting_position = CreateNullPosition();
1480 switch (boundary) {
1482 switch (direction) {
1484 resulting_position =
1485 CreatePreviousCharacterPosition(boundary_behavior);
1486 break;
1488 resulting_position = CreateNextCharacterPosition(boundary_behavior);
1489 break;
1490 }
1491 break;
1492
1494 switch (direction) {
1496 resulting_position =
1497 CreatePreviousFormatStartPosition(boundary_behavior);
1498 break;
1500 resulting_position = CreateNextFormatEndPosition(boundary_behavior);
1501 break;
1502 }
1503 break;
1504
1506 switch (direction) {
1508 resulting_position =
1509 CreatePreviousLineEndPosition(boundary_behavior);
1510 break;
1512 resulting_position = CreateNextLineEndPosition(boundary_behavior);
1513 break;
1514 }
1515 break;
1516
1518 switch (direction) {
1520 resulting_position =
1521 CreatePreviousLineStartPosition(boundary_behavior);
1522 break;
1524 resulting_position = CreateNextLineStartPosition(boundary_behavior);
1525 break;
1526 }
1527 break;
1528
1530 switch (direction) {
1532 resulting_position =
1533 CreatePreviousLineStartPosition(boundary_behavior);
1534 break;
1536 resulting_position = CreateNextLineEndPosition(boundary_behavior);
1537 break;
1538 }
1539 break;
1540
1542 switch (direction) {
1544 resulting_position = CreatePositionAtStartOfAnchor();
1545 break;
1547 resulting_position = CreatePositionAtEndOfAnchor();
1548 break;
1549 }
1550 break;
1551
1553 switch (direction) {
1555 resulting_position =
1556 CreatePreviousPageEndPosition(boundary_behavior);
1557 break;
1559 resulting_position = CreateNextPageEndPosition(boundary_behavior);
1560 break;
1561 }
1562 break;
1563
1565 switch (direction) {
1567 resulting_position =
1568 CreatePreviousPageStartPosition(boundary_behavior);
1569 break;
1571 resulting_position = CreateNextPageStartPosition(boundary_behavior);
1572 break;
1573 }
1574 break;
1575
1577 switch (direction) {
1579 resulting_position =
1580 CreatePreviousPageStartPosition(boundary_behavior);
1581 break;
1583 resulting_position = CreateNextPageEndPosition(boundary_behavior);
1584 break;
1585 }
1586 break;
1587
1589 switch (direction) {
1591 resulting_position =
1592 CreatePreviousParagraphEndPosition(boundary_behavior);
1593 break;
1595 resulting_position =
1596 CreateNextParagraphEndPosition(boundary_behavior);
1597 break;
1598 }
1599 break;
1600
1602 switch (direction) {
1604 resulting_position =
1605 CreatePreviousParagraphStartPosition(boundary_behavior);
1606 break;
1608 resulting_position =
1609 CreateNextParagraphStartPosition(boundary_behavior);
1610 break;
1611 }
1612 break;
1613
1615 switch (direction) {
1617 resulting_position =
1618 CreatePreviousParagraphStartPosition(boundary_behavior);
1619 break;
1621 resulting_position =
1622 CreateNextParagraphEndPosition(boundary_behavior);
1623 break;
1624 }
1625 break;
1626
1628 BASE_LOG() << "Sentence boundaries are not yet supported.";
1630 return CreateNullPosition();
1631
1633 BASE_LOG() << "Sentence boundaries are not yet supported.";
1635 return CreateNullPosition();
1636
1638 BASE_LOG() << "Sentence boundaries are not yet supported.";
1640 return CreateNullPosition();
1641
1643 if (boundary_behavior != AXBoundaryBehavior::CrossBoundary) {
1644 BASE_LOG() << "We can't reach the start of the document if we "
1645 "are disallowed "
1646 "from crossing boundaries.";
1648 }
1649 switch (direction) {
1651 resulting_position = CreatePositionAtStartOfDocument();
1652 break;
1654 resulting_position = CreatePositionAtEndOfDocument();
1655 break;
1656 }
1657 break;
1658
1660 switch (direction) {
1662 resulting_position =
1663 CreatePreviousWordEndPosition(boundary_behavior);
1664 break;
1666 resulting_position = CreateNextWordEndPosition(boundary_behavior);
1667 break;
1668 }
1669 break;
1670
1672 switch (direction) {
1674 resulting_position =
1675 CreatePreviousWordStartPosition(boundary_behavior);
1676 break;
1678 resulting_position = CreateNextWordStartPosition(boundary_behavior);
1679 break;
1680 }
1681 break;
1682
1684 switch (direction) {
1686 resulting_position =
1687 CreatePreviousWordStartPosition(boundary_behavior);
1688 break;
1690 resulting_position = CreateNextWordEndPosition(boundary_behavior);
1691 break;
1692 }
1693 break;
1694 }
1695 return resulting_position;
1696 }
AXPositionInstance CreatePreviousParagraphEndPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2465
AXPositionInstance CreateNextWordStartPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2250
AXPositionInstance CreatePreviousLineStartPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2289
AXPositionInstance CreateNextParagraphEndPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2458
AXPositionInstance CreateNextWordEndPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2267
AXPositionInstance CreateNextFormatEndPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2378
AXPositionInstance CreatePreviousWordEndPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2275
AXPositionInstance CreatePreviousCharacterPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2202
AXPositionInstance CreatePreviousPageStartPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2534
AXPositionInstance CreateNextPageStartPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2527
AXPositionInstance CreatePreviousLineEndPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2307
AXPositionInstance CreateNextLineEndPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2298
AXPositionInstance CreatePreviousPageEndPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2548
AXPositionInstance CreateNextLineStartPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2282
AXPositionInstance CreateNextCharacterPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2148
AXPositionInstance CreatePreviousFormatStartPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2314
AXPositionInstance CreateNextPageEndPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2541
AXPositionInstance CreatePreviousWordStartPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2258
AXPositionInstance CreatePositionAtEndOfDocument() const
Definition: ax_position.h:1805
AXPositionInstance CreateNextParagraphStartPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2444
AXPositionInstance CreatePositionAtStartOfDocument() const
Definition: ax_position.h:1785
AXPositionInstance CreatePreviousParagraphStartPosition(AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:2451
#define BASE_LOG()
Definition: logging.h:54

◆ CreatePreviousAnchorPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousAnchorPosition ( ) const
inline

Definition at line 2819 of file ax_position.h.

2819 {
2820 return CreatePreviousAnchorPosition(&DefaultAbortMovePredicate);
2821 }

◆ CreatePreviousCharacterPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousCharacterPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2202 of file ax_position.h.

2203 {
2204 if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary &&
2205 AtStartOfAnchor()) {
2206 return Clone();
2207 }
2208
2209 // There is no previous character position.
2211 if (text_position->IsNullPosition()) {
2212 if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary ||
2213 boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary) {
2214 text_position = Clone();
2215 }
2216 return text_position;
2217 }
2218
2219 if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary &&
2220 *text_position == *this) {
2221 return Clone();
2222 }
2223 BASE_DCHECK(text_position->text_offset_ > 0);
2224 // TODO(chunhtai): Need to consider grapheme cluster.
2225 --text_position->text_offset_;
2226 BASE_DCHECK(text_position->text_offset_ >= 0);
2227 BASE_DCHECK(text_position->text_offset_ < text_position->MaxTextOffset());
2228 // The character boundary should be in the same subtree. Return a position
2229 // rooted at this position's anchor. This is necessary because we don't want
2230 // to return a position that might be in the shadow DOM when this position
2231 // is not.
2232 const AXNodeType* common_anchor = text_position->LowestCommonAnchor(*this);
2233 if (GetAnchor() == common_anchor) {
2234 text_position = text_position->CreateAncestorPosition(
2236 } else if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
2237 // If the previous character position crosses the current anchor boundary
2238 // with StopAtAnchorBoundary, snap to the start of the current anchor.
2240 }
2241 // Even if the resulting position is right on a soft line break, affinity is
2242 // defaulted to downstream so that this method will always produce the same
2243 // result regardless of the direction of motion or the input affinity.
2244 text_position->affinity_ = ax::mojom::TextAffinity::kDownstream;
2245 if (IsTreePosition())
2246 return text_position->AsTreePosition();
2247 return text_position;
2248 }
AXPositionInstance AsLeafTextPositionAfterCharacter() const
Definition: ax_position.h:2100

◆ CreatePreviousFormatStartPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousFormatStartPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2314 of file ax_position.h.

2315 {
2316 if (IsNullPosition())
2317 return Clone();
2318
2320 if (boundary_type != AXBoundaryType::kNone) {
2321 if (boundary_behavior == AXBoundaryBehavior::StopIfAlreadyAtBoundary ||
2322 (boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary &&
2323 boundary_type == AXBoundaryType::kDocumentStart)) {
2324 AXPositionInstance clone = Clone();
2325 // In order to make equality checks simpler, affinity should be reset so
2326 // that we would get consistent output from this function regardless of
2327 // input affinity.
2328 clone->affinity_ = ax::mojom::TextAffinity::kDownstream;
2329 return clone;
2330 } else if (boundary_behavior == AXBoundaryBehavior::CrossBoundary &&
2331 boundary_type == AXBoundaryType::kDocumentStart) {
2332 // If we're at a format boundary and there are no more text positions
2333 // to traverse, return a null position for cross-boundary moves.
2334 return CreateNullPosition();
2335 }
2336 }
2337
2338 AXPositionInstance tree_position =
2339 AsTreePosition()->CreatePositionAtStartOfAnchor();
2340 AXPositionInstance previous_tree_position =
2341 tree_position->CreatePreviousLeafTreePosition();
2342
2343 // If moving to the start of the current anchor hasn't changed our position
2344 // from the original position, we need to test the previous leaf tree
2345 // position.
2346 if (AtStartOfAnchor() &&
2347 boundary_behavior != AXBoundaryBehavior::StopIfAlreadyAtBoundary) {
2348 tree_position = std::move(previous_tree_position);
2349 previous_tree_position = tree_position->CreatePreviousLeafTreePosition();
2350 }
2351
2352 // The first position in the document is also a format start boundary, so we
2353 // should not return NullPosition unless we started from that location.
2354 while (boundary_type != AXBoundaryType::kDocumentStart &&
2355 !previous_tree_position->IsNullPosition() &&
2356 !tree_position->AtStartOfFormat()) {
2357 tree_position = std::move(previous_tree_position);
2358 previous_tree_position = tree_position->CreatePreviousLeafTreePosition();
2359 }
2360
2361 // If the format boundary is in the same subtree, return a position rooted
2362 // at the current position.
2363 // This is necessary because we don't want to return any position that might
2364 // be in the shadow DOM if the original position was not.
2365 const AXNodeType* common_anchor = tree_position->LowestCommonAnchor(*this);
2366 if (GetAnchor() == common_anchor) {
2367 tree_position = tree_position->CreateAncestorPosition(
2369 } else if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary) {
2371 }
2372
2373 if (IsTextPosition())
2374 return tree_position->AsTextPosition();
2375 return tree_position;
2376 }

◆ CreatePreviousLeafTextPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousLeafTextPosition ( ) const
inline

Definition at line 2040 of file ax_position.h.

2040 {
2041 return CreatePreviousTextAnchorPosition(DefaultAbortMovePredicate);
2042 }

◆ CreatePreviousLeafTreePosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousLeafTreePosition ( ) const
inline

Definition at line 2000 of file ax_position.h.

2000 {
2001 return CreatePreviousLeafTreePosition(&DefaultAbortMovePredicate);
2002 }
AXPositionInstance CreatePreviousLeafTreePosition() const
Definition: ax_position.h:2000

◆ CreatePreviousLineEndPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousLineEndPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2307 of file ax_position.h.

2308 {
2310 boundary_behavior, ax::mojom::MoveDirection::kBackward,
2311 &AtStartOfLinePredicate, &AtEndOfLinePredicate);
2312 }

◆ CreatePreviousLineStartPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousLineStartPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2289 of file ax_position.h.

2290 {
2292 boundary_behavior, ax::mojom::MoveDirection::kBackward,
2293 &AtStartOfLinePredicate, &AtEndOfLinePredicate);
2294 }

◆ CreatePreviousPageEndPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousPageEndPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2548 of file ax_position.h.

2549 {
2551 boundary_behavior, ax::mojom::MoveDirection::kBackward,
2552 &AtStartOfPagePredicate, &AtEndOfPagePredicate);
2553 }

◆ CreatePreviousPageStartPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousPageStartPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2534 of file ax_position.h.

2535 {
2537 boundary_behavior, ax::mojom::MoveDirection::kBackward,
2538 &AtStartOfPagePredicate, &AtEndOfPagePredicate);
2539 }

◆ CreatePreviousParagraphEndPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousParagraphEndPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2465 of file ax_position.h.

2466 {
2468 boundary_behavior, ax::mojom::MoveDirection::kBackward,
2469 &AtStartOfParagraphPredicate, &AtEndOfParagraphPredicate);
2470 if (boundary_behavior == AXBoundaryBehavior::CrossBoundary ||
2471 boundary_behavior == AXBoundaryBehavior::StopAtLastAnchorBoundary) {
2472 // This is asymmetric with CreateNextParagraphEndPosition due to
2473 // asymmetries in text anchor movement. Consider:
2474 //
2475 // ++1 rootWebArea
2476 // ++++2 staticText name="FIRST"
2477 // ++++3 genericContainer isLineBreakingObject=true
2478 // ++++++4 genericContainer isLineBreakingObject=true
2479 // ++++++5 staticText name="SECOND"
2480 //
2481 // Node 2 offset 5 FIRST<> is a paragraph end since node 3 is a line-
2482 // breaking object that's not collapsible (since it's not a leaf). When
2483 // looking for the next text anchor position from there, we advance to
2484 // sibling node 3, then since that node has descendants, we convert to a
2485 // tree position to find the leaf node that maps to "node 3 offset 0".
2486 // Since node 4 has no text, we skip it and land on node 5. We end up at
2487 // node 5 offset 6 SECOND<> as our next paragraph end.
2488 //
2489 // The set of paragraph ends should be consistent when moving in the
2490 // reverse direction. But starting from node 5 offset 6, the previous text
2491 // anchor position is previous sibling node 4. We'll consider that a
2492 // paragraph end since it's a leaf line-breaking object and stop.
2493 //
2494 // Essentially, we have two consecutive line-breaking objects, each of
2495 // which stops movement in the "outward" direction, for different reasons.
2496 //
2497 // We handle this by looking back one more step after finding a candidate
2498 // for previous paragraph end, then testing a forward step from the look-
2499 // back position. That will land us on the candidate position if it's a
2500 // valid paragraph boundary.
2501 //
2502 while (!previous_position->IsNullPosition()) {
2503 AXPositionInstance look_back_position =
2504 previous_position->AsLeafTextPosition()
2505 ->CreatePreviousLeafTextPosition()
2506 ->CreatePositionAtEndOfAnchor();
2507 if (look_back_position->IsNullPosition()) {
2508 // Nowhere to look back to, so our candidate must be a valid paragraph
2509 // boundary.
2510 break;
2511 }
2512 AXPositionInstance forward_step_position =
2513 look_back_position->CreateNextLeafTextPosition()
2514 ->CreatePositionAtEndOfAnchor();
2515 if (*forward_step_position == *previous_position)
2516 break;
2517
2518 previous_position = previous_position->CreateBoundaryEndPosition(
2519 boundary_behavior, ax::mojom::MoveDirection::kBackward,
2520 &AtStartOfParagraphPredicate, &AtEndOfParagraphPredicate);
2521 }
2522 }
2523
2524 return previous_position;
2525 }

◆ CreatePreviousParagraphStartPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousParagraphStartPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2451 of file ax_position.h.

2452 {
2454 boundary_behavior, ax::mojom::MoveDirection::kBackward,
2455 &AtStartOfParagraphPredicate, &AtEndOfParagraphPredicate);
2456 }

◆ CreatePreviousWordEndPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousWordEndPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2275 of file ax_position.h.

2276 {
2278 boundary_behavior, ax::mojom::MoveDirection::kBackward,
2279 &AtStartOfWordPredicate, &AtEndOfWordPredicate, &GetWordEndOffsetsFunc);
2280 }

◆ CreatePreviousWordStartPosition()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreatePreviousWordStartPosition ( AXBoundaryBehavior  boundary_behavior) const
inline

Definition at line 2258 of file ax_position.h.

2259 {
2261 boundary_behavior, ax::mojom::MoveDirection::kBackward,
2262 &AtStartOfWordPredicate, &AtEndOfWordPredicate,
2263 &GetWordStartOffsetsFunc);
2264 }

◆ CreateTextPosition()

template<class AXPositionType , class AXNodeType >
static AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateTextPosition ( AXTreeID  tree_id,
AXNode::AXID  anchor_id,
int  text_offset,
ax::mojom::TextAffinity  affinity 
)
inlinestatic

Definition at line 201 of file ax_position.h.

205 {
206 AXPositionInstance new_position(new AXPositionType());
207 new_position->Initialize(AXPositionKind::TEXT_POSITION, tree_id, anchor_id,
209 return new_position;
210 }
AXNode::AXID anchor_id() const
Definition: ax_position.h:317
ax::mojom::TextAffinity affinity() const
Definition: ax_position.h:328

◆ CreateTreePosition()

template<class AXPositionType , class AXNodeType >
static AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::CreateTreePosition ( AXTreeID  tree_id,
AXNode::AXID  anchor_id,
int  child_index 
)
inlinestatic

Definition at line 191 of file ax_position.h.

193 {
194 AXPositionInstance new_position(new AXPositionType());
195 new_position->Initialize(AXPositionKind::TREE_POSITION, tree_id, anchor_id,
198 return new_position;
199 }

◆ ExpandToEnclosingTextBoundary()

template<class AXPositionType , class AXNodeType >
AXRangeType ui::AXPosition< AXPositionType, AXNodeType >::ExpandToEnclosingTextBoundary ( ax::mojom::TextBoundary  boundary,
AXRangeExpandBehavior  expand_behavior 
) const
inline

Definition at line 1439 of file ax_position.h.

1441 {
1442 AXBoundaryBehavior boundary_behavior =
1444 if (boundary == ax::mojom::TextBoundary::kWebPage)
1445 boundary_behavior = AXBoundaryBehavior::CrossBoundary;
1446
1447 switch (expand_behavior) {
1450 boundary, ax::mojom::MoveDirection::kBackward, boundary_behavior);
1451 AXPositionInstance right_position =
1452 left_position->CreatePositionAtTextBoundary(
1454 boundary_behavior);
1455 return AXRangeType(std::move(left_position), std::move(right_position));
1456 }
1459 boundary, ax::mojom::MoveDirection::kForward, boundary_behavior);
1460 AXPositionInstance left_position =
1461 right_position->CreatePositionAtTextBoundary(
1463 boundary_behavior);
1464 return AXRangeType(std::move(left_position), std::move(right_position));
1465 }
1466 }
1467 }
AXRange< AXPosition< AXPositionType, AXNodeType > > AXRangeType
Definition: ax_position.h:165
AXPositionInstance CreatePositionAtTextBoundary(ax::mojom::TextBoundary boundary, ax::mojom::MoveDirection direction, AXBoundaryBehavior boundary_behavior) const
Definition: ax_position.h:1475
AXBoundaryBehavior
Definition: ax_position.h:43

◆ GetAncestorAnchors()

template<class AXPositionType , class AXNodeType >
virtual std::stack< AXNodeType * > ui::AXPosition< AXPositionType, AXNodeType >::GetAncestorAnchors ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ GetAnchor()

template<class AXPositionType , class AXNodeType >
AXNodeType * ui::AXPosition< AXPositionType, AXNodeType >::GetAnchor ( ) const
inline

Definition at line 319 of file ax_position.h.

319 {
320 if (tree_id_ == AXTreeIDUnknown() || anchor_id_ == AXNode::kInvalidAXID)
321 return nullptr;
322 return GetNodeInTree(tree_id_, anchor_id_);
323 }
virtual AXNodeType * GetNodeInTree(AXTreeID tree_id, int32_t node_id) const =0

◆ GetAnchorID()

template<class AXPositionType , class AXNodeType >
virtual int32_t ui::AXPosition< AXPositionType, AXNodeType >::GetAnchorID ( AXNodeType *  node) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ GetAnchorRole()

template<class AXPositionType , class AXNodeType >
virtual ax::mojom::Role ui::AXPosition< AXPositionType, AXNodeType >::GetAnchorRole ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ GetEmptyObjectAncestorNode()

template<class AXPositionType , class AXNodeType >
AXNodeType * ui::AXPosition< AXPositionType, AXNodeType >::GetEmptyObjectAncestorNode ( ) const
inline

Definition at line 3138 of file ax_position.h.

3138 {
3141 !GetAnchor()) {
3142 return nullptr;
3143 }
3144
3145 if (!GetAnchor()->IsIgnored()) {
3146 // The only case where a descendant of an empty object can be unignored is
3147 // when we are inside of a collapsed popup button parent of a menu list
3148 // popup.
3149 if (AXNodeType* popup_button =
3150 GetAnchor()->GetCollapsedMenuListPopUpButtonAncestor()) {
3151 return popup_button;
3152 }
3153 return nullptr;
3154 }
3155
3156 // The first unignored ancestor is necessarily the empty object if this node
3157 // is the descendant of an empty object.
3158 AXNodeType* ancestor_node = GetLowestUnignoredAncestor();
3159 if (!ancestor_node)
3160 return nullptr;
3161
3163 tree_id_, GetAnchorID(ancestor_node), 0 /* text_offset */,
3165 if (position && position->IsEmptyObjectReplacedByCharacter())
3166 return ancestor_node;
3167
3168 return nullptr;
3169 }
virtual AXNodeType * GetLowestUnignoredAncestor() const =0
AXEmbeddedObjectBehavior g_ax_embedded_object_behavior

◆ GetFormatEndBoundaryType()

template<class AXPositionType , class AXNodeType >
AXBoundaryType ui::AXPosition< AXPositionType, AXNodeType >::GetFormatEndBoundaryType ( ) const
inline

Definition at line 908 of file ax_position.h.

908 {
909 // Since formats are stored on text anchors, the end of a format break must
910 // be at the end of an anchor.
911 if (IsNullPosition() || !AtEndOfAnchor())
913
914 // Treat the last iterable node as a format boundary
917
918 // Ignored positions cannot be format boundaries.
919 if (IsIgnored())
921
922 // Iterate over anchors until a format boundary is found. This will return a
923 // null position upon crossing a boundary. Make sure the next position is
924 // not on an ignored node.
925 AXPositionInstance next_position = Clone();
926 do {
927 next_position =
928 next_position->CreateNextLeafTreePosition(AbortMoveAtFormatBoundary);
929 } while (next_position->IsIgnored());
930
931 if (next_position->IsNullPosition())
933
935 }

◆ GetFormatStartBoundaryType()

template<class AXPositionType , class AXNodeType >
AXBoundaryType ui::AXPosition< AXPositionType, AXNodeType >::GetFormatStartBoundaryType ( ) const
inline

Definition at line 875 of file ax_position.h.

875 {
876 // Since formats are stored on text anchors, the start of a format boundary
877 // must be at the start of an anchor.
880
881 // Treat the first iterable node as a format boundary.
884
885 // Ignored positions cannot be format boundaries.
886 if (IsIgnored())
888
889 // Iterate over anchors until a format boundary is found. This will return a
890 // null position upon crossing a boundary. Make sure the previous position
891 // is not on an ignored node.
892 AXPositionInstance previous_position = Clone();
893 do {
894 previous_position = previous_position->CreatePreviousLeafTreePosition(
895 AbortMoveAtFormatBoundary);
896 } while (previous_position->IsIgnored());
897
898 if (previous_position->IsNullPosition())
900
902 }

◆ GetLowestUnignoredAncestor()

template<class AXPositionType , class AXNodeType >
virtual AXNodeType * ui::AXPosition< AXPositionType, AXNodeType >::GetLowestUnignoredAncestor ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ GetNextOnLineID()

template<class AXPositionType , class AXNodeType >
virtual int32_t ui::AXPosition< AXPositionType, AXNodeType >::GetNextOnLineID ( int32_t  node_id) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ GetNodeInTree()

template<class AXPositionType , class AXNodeType >
virtual AXNodeType * ui::AXPosition< AXPositionType, AXNodeType >::GetNodeInTree ( AXTreeID  tree_id,
int32_t  node_id 
) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ GetPreviousOnLineID()

template<class AXPositionType , class AXNodeType >
virtual int32_t ui::AXPosition< AXPositionType, AXNodeType >::GetPreviousOnLineID ( int32_t  node_id) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ GetRole()

template<class AXPositionType , class AXNodeType >
virtual ax::mojom::Role ui::AXPosition< AXPositionType, AXNodeType >::GetRole ( AXNodeType *  node) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ GetText()

template<class AXPositionType , class AXNodeType >
virtual std::u16string ui::AXPosition< AXPositionType, AXNodeType >::GetText ( ) const
pure virtual

Implemented in ui::AXNodePosition.

◆ GetTextStyles()

template<class AXPositionType , class AXNodeType >
virtual AXNodeTextStyles ui::AXPosition< AXPositionType, AXNodeType >::GetTextStyles ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ GetTreeID()

template<class AXPositionType , class AXNodeType >
virtual AXTreeID ui::AXPosition< AXPositionType, AXNodeType >::GetTreeID ( AXNodeType *  node) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ GetWordEndOffsets()

template<class AXPositionType , class AXNodeType >
virtual std::vector< int32_t > ui::AXPosition< AXPositionType, AXNodeType >::GetWordEndOffsets ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ GetWordStartOffsets()

template<class AXPositionType , class AXNodeType >
virtual std::vector< int32_t > ui::AXPosition< AXPositionType, AXNodeType >::GetWordStartOffsets ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ Initialize()

template<class AXPositionType , class AXNodeType >
void ui::AXPosition< AXPositionType, AXNodeType >::Initialize ( AXPositionKind  kind,
AXTreeID  tree_id,
int32_t  anchor_id,
int  child_index,
int  text_offset,
ax::mojom::TextAffinity  affinity 
)
inlineprotected

Definition at line 3254 of file ax_position.h.

3259 {
3260 kind_ = kind;
3261 tree_id_ = tree_id;
3262 anchor_id_ = anchor_id;
3263 child_index_ = child_index;
3264 text_offset_ = text_offset;
3265 affinity_ = affinity;
3266
3267 if (!IsValid()) {
3268 // Reset to the null position.
3270 tree_id_ = AXTreeIDUnknown();
3271 anchor_id_ = AXNode::kInvalidAXID;
3272 child_index_ = INVALID_INDEX;
3273 text_offset_ = INVALID_OFFSET;
3275 }
3276 }
AXPositionKind kind() const
Definition: ax_position.h:325
bool IsValid() const
Definition: ax_position.h:418

◆ IsEmbeddedObjectInParent()

template<class AXPositionType , class AXNodeType >
virtual bool ui::AXPosition< AXPositionType, AXNodeType >::IsEmbeddedObjectInParent ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ IsEmptyObjectReplacedByCharacter()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::IsEmptyObjectReplacedByCharacter ( ) const
inline

Definition at line 3094 of file ax_position.h.

3094 {
3097 IsNullPosition()) {
3098 return false;
3099 }
3100
3101 // A collapsed popup button that contains a menu list popup (i.e, the exact
3102 // subtree representation we get from a collapsed <select> element on
3103 // Windows) should not expose its children even though they are not ignored.
3104 if (GetAnchor()->IsCollapsedMenuListPopUpButton())
3105 return true;
3106
3107 // All other elements that have unignored descendants should not be treated
3108 // as empty objects.
3110 return false;
3111
3112 // All unignored leaf nodes in the AXTree except document and text
3113 // nodes should be replaced by the embedded object character. Also, nodes
3114 // that only have ignored children (e.g., a button that contains only an
3115 // empty div) need to be treated as leaf nodes.
3116 //
3117 // Calling AXPosition::IsIgnored here is not possible as it would create an
3118 // infinite loop. However, GetAnchor()->IsIgnored() is sufficient here
3119 // because we know that the anchor at this position doesn't have an
3120 // unignored child, making this a leaf tree or text position.
3121 return !GetAnchor()->IsIgnored() && !IsDocument(GetAnchorRole()) &&
3123 }
virtual bool IsInTextObject() const =0
virtual int AnchorUnignoredChildCount() const =0
bool IsIframe(ax::mojom::Role role)

◆ IsIgnored()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::IsIgnored ( ) const
inline

Definition at line 330 of file ax_position.h.

330 {
331 if (IsNullPosition())
332 return false;
333
335 // If this position is anchored to an ignored node, then consider this
336 // position to be ignored.
337 if (GetAnchor()->IsIgnored()) {
338 return true;
339 }
340
341 switch (kind_) {
344 return false;
346 // If this is a "before text" or an "after text" tree position, it's
347 // pointing to the anchor itself, which we've determined to be
348 // unignored.
349 BASE_DCHECK(!IsLeaf() || child_index_ == BEFORE_TEXT ||
350 child_index_ == 0)
351 << "\"Before text\" and \"after text\" tree positions are only "
352 "valid on leaf nodes.";
353 if (child_index_ == BEFORE_TEXT || IsLeaf())
354 return false;
355
356 // If this position is an "after children" position, consider the
357 // position to be ignored if the last child is ignored. This is because
358 // the last child will not be visible in the unignored tree. If the
359 // position is not adjusted, the resulting position would erroneously
360 // point before the second child in the unignored subtree rooted at the
361 // last child.
362 //
363 // 1 kRootWebArea
364 // ++2 kGenericContainer ignored
365 // ++++3 kStaticText "Line 1."
366 // ++++4 kStaticText "Line 2."
367 //
368 // Tree position anchor=kGenericContainer, child_index=1.
369 //
370 // Alternatively, if there is a node at the position pointed to by
371 // "child_index_", i.e. this position is neither a leaf position nor an
372 // "after children" position, consider this tree position to be ignored
373 // if the child node is ignored.
374 int adjusted_child_index = child_index_ != AnchorChildCount()
375 ? child_index_
376 : child_index_ - 1;
377 AXPositionInstance child_position =
378 CreateChildPositionAt(adjusted_child_index);
379 BASE_DCHECK(child_position && !child_position->IsNullPosition());
380 return child_position->GetAnchor()->IsIgnored();
381 }
383 // If the corresponding leaf position is ignored, the current text
384 // offset will point to ignored text. Therefore, consider this position
385 // to be ignored.
386 if (!IsLeaf()) {
387 return AsLeafTreePosition()->IsIgnored();
388 }
389 return false;
390 }
391 }
AXPositionInstance CreateChildPositionAt(int child_index) const
Definition: ax_position.h:1820

◆ IsInDescendantOfEmptyObject()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::IsInDescendantOfEmptyObject ( ) const
inline

Definition at line 3125 of file ax_position.h.

3125 {
3128 IsNullPosition()) {
3129 return false;
3130 }
3131
3132 // Empty objects are only possible on a collapsed popup button parent of a
3133 // menu list popup or a node that only has ignored descendants. If it has no
3134 // empty object ancestor, it can't be inside of an empty object.
3136 }

◆ IsInLineBreak()

template<class AXPositionType , class AXNodeType >
virtual bool ui::AXPosition< AXPositionType, AXNodeType >::IsInLineBreak ( ) const
pure virtual

Implemented in ui::AXNodePosition.

◆ IsInLineBreakingObject()

template<class AXPositionType , class AXNodeType >
virtual bool ui::AXPosition< AXPositionType, AXNodeType >::IsInLineBreakingObject ( ) const
protectedpure virtual

Implemented in ui::AXNodePosition.

◆ IsInTextObject()

template<class AXPositionType , class AXNodeType >
virtual bool ui::AXPosition< AXPositionType, AXNodeType >::IsInTextObject ( ) const
pure virtual

Implemented in ui::AXNodePosition.

◆ IsInWhiteSpace()

template<class AXPositionType , class AXNodeType >
virtual bool ui::AXPosition< AXPositionType, AXNodeType >::IsInWhiteSpace ( ) const
pure virtual

Implemented in ui::AXNodePosition.

◆ IsLeaf()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::IsLeaf ( ) const
inline

Definition at line 409 of file ax_position.h.

409 {
410 if (IsNullPosition())
411 return false;
412
414 }

◆ IsLeafTextPosition()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::IsLeafTextPosition ( ) const
inline

Definition at line 407 of file ax_position.h.

407{ return IsTextPosition() && IsLeaf(); }

◆ IsLeafTreePosition()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::IsLeafTreePosition ( ) const
inline

Definition at line 401 of file ax_position.h.

401{ return IsTreePosition() && IsLeaf(); }

◆ IsNullPosition()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::IsNullPosition ( ) const
inline

Definition at line 393 of file ax_position.h.

393 {
394 return kind_ == AXPositionKind::NULL_POSITION || !GetAnchor();
395 }

◆ IsTextPosition()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::IsTextPosition ( ) const
inline

Definition at line 403 of file ax_position.h.

403 {
404 return GetAnchor() && kind_ == AXPositionKind::TEXT_POSITION;
405 }

◆ IsTreePosition()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::IsTreePosition ( ) const
inline

Definition at line 397 of file ax_position.h.

397 {
398 return GetAnchor() && kind_ == AXPositionKind::TREE_POSITION;
399 }

◆ IsValid()

template<class AXPositionType , class AXNodeType >
bool ui::AXPosition< AXPositionType, AXNodeType >::IsValid ( ) const
inline

Definition at line 418 of file ax_position.h.

418 {
419 switch (kind_) {
421 return tree_id_ == AXTreeIDUnknown() &&
422 anchor_id_ == AXNode::kInvalidAXID &&
423 child_index_ == INVALID_INDEX &&
424 text_offset_ == INVALID_OFFSET &&
427 return GetAnchor() &&
428 (child_index_ == BEFORE_TEXT ||
429 (child_index_ >= 0 && child_index_ <= AnchorChildCount())) &&
433 return false;
434 }
435
436 // For performance reasons we skip any validation of the text offset
437 // that involves retrieving the anchor's text, if the offset is set to
438 // 0, because 0 is frequently used and always valid regardless of the
439 // actual text.
440 return text_offset_ == 0 ||
441 (text_offset_ > 0 && text_offset_ <= MaxTextOffset());
442 }
443 }
bool IsInDescendantOfEmptyObject() const
Definition: ax_position.h:3125

◆ kind()

template<class AXPositionType , class AXNodeType >
AXPositionKind ui::AXPosition< AXPositionType, AXNodeType >::kind ( ) const
inline

Definition at line 325 of file ax_position.h.

325{ return kind_; }

◆ LowestCommonAncestor()

template<class AXPositionType , class AXNodeType >
AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::LowestCommonAncestor ( const AXPosition< AXPositionType, AXNodeType > &  second) const
inline

Definition at line 1035 of file ax_position.h.

1035 {
1037 }
AXPositionInstance CreateAncestorPosition(const AXNodeType *ancestor_anchor, ax::mojom::MoveDirection move_direction=ax::mojom::MoveDirection::kForward) const
Definition: ax_position.h:1041
AXNodeType * LowestCommonAnchor(const AXPosition &second) const
Definition: ax_position.h:1010

◆ LowestCommonAnchor()

template<class AXPositionType , class AXNodeType >
AXNodeType * ui::AXPosition< AXPositionType, AXNodeType >::LowestCommonAnchor ( const AXPosition< AXPositionType, AXNodeType > &  second) const
inline

Definition at line 1010 of file ax_position.h.

1010 {
1011 if (IsNullPosition() || second.IsNullPosition())
1012 return nullptr;
1013 if (GetAnchor() == second.GetAnchor())
1014 return GetAnchor();
1015
1016 std::stack<AXNodeType*> our_ancestors = GetAncestorAnchors();
1017 std::stack<AXNodeType*> other_ancestors = second.GetAncestorAnchors();
1018
1019 AXNodeType* common_anchor = nullptr;
1020 while (!our_ancestors.empty() && !other_ancestors.empty() &&
1021 our_ancestors.top() == other_ancestors.top()) {
1022 common_anchor = our_ancestors.top();
1023 our_ancestors.pop();
1024 other_ancestors.pop();
1025 }
1026 return common_anchor;
1027 }
virtual std::stack< AXNodeType * > GetAncestorAnchors() const =0

◆ MaxTextOffset()

template<class AXPositionType , class AXNodeType >
virtual int ui::AXPosition< AXPositionType, AXNodeType >::MaxTextOffset ( ) const
inlinevirtual

Reimplemented in ui::AXNodePosition.

Definition at line 3207 of file ax_position.h.

3207 {
3208 if (IsNullPosition())
3209 return INVALID_OFFSET;
3210 return static_cast<int>(GetText().length());
3211 }
virtual std::u16string GetText() const =0

◆ MaxTextOffsetInParent()

template<class AXPositionType , class AXNodeType >
int ui::AXPosition< AXPositionType, AXNodeType >::MaxTextOffsetInParent ( ) const
inlineprotected

Definition at line 3305 of file ax_position.h.

3305 {
3306 return IsEmbeddedObjectInParent() ? 1 : MaxTextOffset();
3307 }

◆ operator=()

template<class AXPositionType , class AXNodeType >
AXPosition & ui::AXPosition< AXPositionType, AXNodeType >::operator= ( const AXPosition< AXPositionType, AXNodeType > &  other)
inline

Definition at line 215 of file ax_position.h.

215 {
216 AXPositionInstance clone = other.Clone();
217 swap(*clone);
218 return *this;
219 }
void swap(AXPosition &other)
Definition: ax_position.h:3171

◆ Serialize()

template<class AXPositionType , class AXNodeType >
SerializedPosition ui::AXPosition< AXPositionType, AXNodeType >::Serialize ( )
inline

Definition at line 238 of file ax_position.h.

238 {
239 SerializedPosition result;
240 result.kind = kind_;
241
242 // A tree ID can be serialized as a 32-byte string.
243 std::string tree_id_string = tree_id_.ToString();
244 BASE_DCHECK(tree_id_string.size() <= 32U);
245 strncpy(result.tree_id, tree_id_string.c_str(), 32);
246 result.tree_id[32] = 0;
247
248 result.anchor_id = anchor_id_;
249 result.child_index = child_index_;
250 result.text_offset = text_offset_;
251 result.affinity = affinity_;
252 return result;
253 }
std::string ToString() const
Definition: ax_tree_id.cc:53

◆ SlowCompareTo()

template<class AXPositionType , class AXNodeType >
std::optional< int > ui::AXPosition< AXPositionType, AXNodeType >::SlowCompareTo ( const AXPosition< AXPositionType, AXNodeType > &  other) const
inline

Definition at line 2991 of file ax_position.h.

2991 {
2992 // It is potentially costly to compute the parent position of a text
2993 // position, whilst computing the parent position of a tree position is
2994 // really inexpensive. In order to find the lowest common ancestor,
2995 // especially if that ancestor is all the way up to the root of the tree,
2996 // this will need to be done repeatedly. We avoid the performance hit by
2997 // converting both positions to tree positions and only falling back to text
2998 // positions if both are text positions and the lowest common ancestor is
2999 // not one of their anchors. Essentially, the question we need to answer is:
3000 // "When are two non equivalent positions going to have the same lowest
3001 // common ancestor position when converted to tree positions?" The answer is
3002 // when they are both text positions and they either have the same anchor,
3003 // or one is the ancestor of the other.
3004 const AXNodeType* common_anchor = this->LowestCommonAnchor(other);
3005 if (!common_anchor)
3006 return std::optional<int>(std::nullopt);
3007
3008 // Attempt to avoid recomputing the lowest common ancestor because we may
3009 // already have its anchor in which case just find the text offset.
3010 if (this->IsTextPosition() && other.IsTextPosition()) {
3011 // This text position's anchor is the common ancestor of the other text
3012 // position's anchor.
3013 if (this->GetAnchor() == common_anchor) {
3014 AXPositionInstance other_text_position =
3015 other.CreateAncestorPosition(common_anchor);
3016 return std::optional<int>(this->text_offset_ -
3017 other_text_position->text_offset_);
3018 }
3019
3020 // The other text position's anchor is the common ancestor of this text
3021 // position's anchor.
3022 if (other.GetAnchor() == common_anchor) {
3023 AXPositionInstance this_text_position =
3024 this->CreateAncestorPosition(common_anchor);
3025 return std::optional<int>(this_text_position->text_offset_ -
3026 other.text_offset_);
3027 }
3028
3029 // All optimizations failed. Fall back to comparing text positions with
3030 // the common text position ancestor.
3031 AXPositionInstance this_text_position_ancestor =
3032 this->CreateAncestorPosition(common_anchor);
3033 AXPositionInstance other_text_position_ancestor =
3034 other.CreateAncestorPosition(common_anchor);
3035 BASE_DCHECK(this_text_position_ancestor->IsTextPosition());
3036 BASE_DCHECK(other_text_position_ancestor->IsTextPosition());
3037 BASE_DCHECK(common_anchor == this_text_position_ancestor->GetAnchor());
3038 BASE_DCHECK(common_anchor == other_text_position_ancestor->GetAnchor());
3039
3040 // TODO - This does not take into account |affinity_|, so we may return
3041 // a false positive when comparing at the end of a line.
3042 // For example :
3043 // ++1 kRootWebArea
3044 // ++++2 kTextField "Line 1\nLine 2"
3045 // ++++++3 kStaticText "Line 1"
3046 // ++++++++4 kInlineTextBox "Line 1"
3047 // ++++++5 kLineBreak "\n"
3048 // ++++++6 kStaticText "Line 2"
3049 // ++++++++7 kInlineTextBox "Line 2"
3050 //
3051 // TextPosition anchor_id=5 text_offset=1
3052 // affinity=downstream annotated_text=\n<>
3053 //
3054 // TextPosition anchor_id=7 text_offset=0
3055 // affinity=downstream annotated_text=<L>ine 2
3056 //
3057 // |LowestCommonAncestor| for both will be :
3058 // TextPosition anchor_id=2 text_offset=7
3059 // ... except anchor_id=5 creates a kUpstream position, while
3060 // anchor_id=7 creates a kDownstream position.
3061 return std::optional<int>(this_text_position_ancestor->text_offset_ -
3062 other_text_position_ancestor->text_offset_);
3063 }
3064
3065 // All optimizations failed. Fall back to comparing child index with
3066 // the common tree position ancestor.
3067 AXPositionInstance this_tree_position_ancestor =
3068 this->AsTreePosition()->CreateAncestorPosition(common_anchor);
3069 AXPositionInstance other_tree_position_ancestor =
3070 other.AsTreePosition()->CreateAncestorPosition(common_anchor);
3071 BASE_DCHECK(this_tree_position_ancestor->IsTreePosition());
3072 BASE_DCHECK(other_tree_position_ancestor->IsTreePosition());
3073 BASE_DCHECK(common_anchor == this_tree_position_ancestor->GetAnchor());
3074 BASE_DCHECK(common_anchor == other_tree_position_ancestor->GetAnchor());
3075
3076 return std::optional<int>(this_tree_position_ancestor->child_index() -
3077 other_tree_position_ancestor->child_index());
3078 }

◆ SnapToMaxTextOffsetIfBeyond()

template<class AXPositionType , class AXNodeType >
void ui::AXPosition< AXPositionType, AXNodeType >::SnapToMaxTextOffsetIfBeyond ( )
inline

Definition at line 3084 of file ax_position.h.

3084 {
3085 int max_text_offset = MaxTextOffset();
3086 if (text_offset_ > max_text_offset)
3087 text_offset_ = max_text_offset;
3088 }

◆ swap()

template<class AXPositionType , class AXNodeType >
void ui::AXPosition< AXPositionType, AXNodeType >::swap ( AXPosition< AXPositionType, AXNodeType > &  other)
inline

Definition at line 3171 of file ax_position.h.

3171 {
3172 std::swap(kind_, other.kind_);
3173 std::swap(tree_id_, other.tree_id_);
3174 std::swap(anchor_id_, other.anchor_id_);
3175 std::swap(child_index_, other.child_index_);
3176 std::swap(text_offset_, other.text_offset_);
3177 std::swap(affinity_, other.affinity_);
3178 }
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341

◆ text_offset()

template<class AXPositionType , class AXNodeType >
int ui::AXPosition< AXPositionType, AXNodeType >::text_offset ( ) const
inline

Definition at line 327 of file ax_position.h.

327{ return text_offset_; }

◆ ToString()

template<class AXPositionType , class AXNodeType >
std::string ui::AXPosition< AXPositionType, AXNodeType >::ToString ( ) const
inline

Definition at line 265 of file ax_position.h.

265 {
266 std::string str;
267 switch (kind_) {
269 return "NullPosition";
271 std::string str_child_index;
272 if (child_index_ == BEFORE_TEXT) {
273 str_child_index = "before_text";
274 } else if (child_index_ == INVALID_INDEX) {
275 str_child_index = "invalid";
276 } else {
277 str_child_index = base::NumberToString(child_index_);
278 }
279 str = "TreePosition tree_id=" + tree_id_.ToString() +
280 " anchor_id=" + base::NumberToString(anchor_id_) +
281 " child_index=" + str_child_index;
282 break;
283 }
285 std::string str_text_offset;
286 if (text_offset_ == INVALID_OFFSET) {
287 str_text_offset = "invalid";
288 } else {
289 str_text_offset = base::NumberToString(text_offset_);
290 }
291 str = "TextPosition anchor_id=" + base::NumberToString(anchor_id_) +
292 " text_offset=" + str_text_offset + " affinity=" +
293 ui::ToString(static_cast<ax::mojom::TextAffinity>(affinity_));
294 break;
295 }
296 }
297
298 if (!IsTextPosition() || text_offset_ > MaxTextOffset())
299 return str;
300
301 std::u16string text = GetText();
302 BASE_DCHECK(text_offset_ >= 0);
303 int max_text_offset = MaxTextOffset();
304 BASE_DCHECK(text_offset_ <= max_text_offset);
305 std::u16string annotated_text;
306 if (text_offset_ == max_text_offset) {
307 annotated_text = text + u"<>";
308 } else {
309 annotated_text = text.substr(0, text_offset_) + u"<" +
310 text[text_offset_] + u">" +
311 text.substr(text_offset_ + 1);
312 }
313 return str + " annotated_text=" + base::UTF16ToUTF8(annotated_text);
314 }
std::u16string text
std::string UTF16ToUTF8(std::u16string src)
Definition: string_utils.cc:71
std::string NumberToString(int32_t number)
Definition: string_utils.cc:91
const char * ToString(ax::mojom::Event event)
Definition: ax_enum_util.cc:9

◆ tree_id()

template<class AXPositionType , class AXNodeType >
AXTreeID ui::AXPosition< AXPositionType, AXNodeType >::tree_id ( ) const
inline

Definition at line 316 of file ax_position.h.

316{ return tree_id_; }

◆ Unserialize()

template<class AXPositionType , class AXNodeType >
static AXPositionInstance ui::AXPosition< AXPositionType, AXNodeType >::Unserialize ( const SerializedPosition serialization)
inlinestatic

Definition at line 255 of file ax_position.h.

256 {
257 AXPositionInstance new_position(new AXPositionType());
258 new_position->Initialize(serialization.kind,
259 ui::AXTreeID::FromString(serialization.tree_id),
260 serialization.anchor_id, serialization.child_index,
261 serialization.text_offset, serialization.affinity);
262 return new_position;
263 }
static AXTreeID FromString(const std::string &string)
Definition: ax_tree_id.cc:37

Member Data Documentation

◆ BEFORE_TEXT

template<class AXPositionType , class AXNodeType >
const int ui::AXPosition< AXPositionType, AXNodeType >::BEFORE_TEXT = -1
static

Definition at line 172 of file ax_position.h.

◆ INVALID_INDEX

template<class AXPositionType , class AXNodeType >
const int ui::AXPosition< AXPositionType, AXNodeType >::INVALID_INDEX = -2
static

Definition at line 173 of file ax_position.h.

◆ INVALID_OFFSET

template<class AXPositionType , class AXNodeType >
const int ui::AXPosition< AXPositionType, AXNodeType >::INVALID_OFFSET = -1
static

Definition at line 174 of file ax_position.h.

◆ kEmbeddedCharacter

template<class AXPositionType , class AXNodeType >
constexpr char16_t ui::AXPosition< AXPositionType, AXNodeType >::kEmbeddedCharacter = L'\xfffc'
staticconstexpr

Definition at line 181 of file ax_position.h.


The documentation for this class was generated from the following file: