File: ax_position.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (248 lines) | stat: -rw-r--r-- 10,923 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_POSITION_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_POSITION_H_

#include <stdint.h>

#include <ostream>

#include "base/dcheck_is_on.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace blink {

class AXObject;
class ContainerNode;
class Document;
class Node;
class OffsetMapping;

// When converting to a DOM position from an |AXPosition| or vice versa, and the
// corresponding position is invalid, doesn't exist, or is inside an ignored
// object or a range of ignored objects, determines how to adjust the new
// position in order to make it valid.
enum class AXPositionAdjustmentBehavior { kMoveLeft, kMoveRight };

// Describes a position in the Blink accessibility tree.
// A position is either anchored to before or after a child object inside a
// container object, or is anchored to a character inside a text object.
// The former are called tree positions, and the latter text positions.
// Tree positions are never located on a specific |AXObject|. Rather, they are
// always between two objects, or an object and the start / end of their
// container's children, known as "before children" and "after children"
// positions respectively. They should be thought of like a caret that is always
// between two characters. Another way of calling these types of positions is
// object anchored and text anchored.
class MODULES_EXPORT AXPosition final {
  DISALLOW_NEW();

 public:
  //
  // Convert between DOM and AX positions and vice versa.
  // |Create...| and |FromPosition| methods will by default skip over any
  // ignored object and return the next unignored position to the right of that
  // object.
  //

  static const AXPosition CreatePositionBeforeObject(
      const AXObject& child,
      const AXPositionAdjustmentBehavior =
          AXPositionAdjustmentBehavior::kMoveRight);
  static const AXPosition CreatePositionAfterObject(
      const AXObject& child,
      const AXPositionAdjustmentBehavior =
          AXPositionAdjustmentBehavior::kMoveRight);
  static const AXPosition CreateFirstPositionInObject(
      const AXObject& container,
      const AXPositionAdjustmentBehavior =
          AXPositionAdjustmentBehavior::kMoveRight);
  static const AXPosition CreateLastPositionInObject(
      const AXObject& container,
      const AXPositionAdjustmentBehavior =
          AXPositionAdjustmentBehavior::kMoveRight);
  static const AXPosition CreatePositionInTextObject(
      const AXObject& container,
      const int offset,
      const TextAffinity = TextAffinity::kDownstream,
      const AXPositionAdjustmentBehavior =
          AXPositionAdjustmentBehavior::kMoveRight);
  static const AXPosition FromPosition(
      const Position&,
      const AXObjectCacheImpl& ax_object_cache,
      const TextAffinity = TextAffinity::kDownstream,
      const AXPositionAdjustmentBehavior =
          AXPositionAdjustmentBehavior::kMoveRight);
  static const AXPosition FromPosition(
      const PositionWithAffinity&,
      const AXObjectCacheImpl& ax_object_cache,
      const AXPositionAdjustmentBehavior =
          AXPositionAdjustmentBehavior::kMoveRight);

  // Creates an empty position. |IsValid| will return false.
  AXPosition();

  AXPosition(const AXPosition&) = default;
  AXPosition& operator=(const AXPosition&) = default;
  ~AXPosition() = default;

  // The |AXObject| in which the tree position is located, or in whose text the
  // text position is found.
  const AXObject* ContainerObject() const { return container_object_; }

  // Returns |nullptr| for text, and "after children" or equivalent positions.
  const AXObject* ChildAfterTreePosition() const;

  // Only valid for tree positions.
  int ChildIndex() const;

  // Only valid for text positions.
  int TextOffset() const;

  // If this is a text position, the length of the text in its container object.
  int MaxTextOffset() const;

  // When the same character offset could correspond to two possible caret
  // positions, upstream means it's on the previous line rather than the next
  // line.
  // Only valid for text positions.
  TextAffinity Affinity() const;

  // Verifies if the anchor is present and if it's set to a live object with a
  // connected node.
  bool IsValid(String* failure_reason = nullptr) const;

  operator bool() const { return IsValid(); }

  // Returns whether this is a position anchored to a character inside a text
  // object.
  bool IsTextPosition() const;

  const AXPosition CreateNextPosition() const;
  const AXPosition CreatePreviousPosition() const;

  // Returns an adjusted position by skipping over any ignored objects in the
  // case of a "before object" or "after object" position, or skipping over any
  // ignored children in the case of a "before children" or "after children"
  // position. If a text object is ignored, returns a position anchored at the
  // nearest object, which might not be a text object. If the container object
  // is ignored, tries to find if an equivalent position exists in its unignored
  // parent, since all the children of an ignored object in the accessibility
  // tree appear as children of its immediate unignored parent.
  const AXPosition AsUnignoredPosition(
      const AXPositionAdjustmentBehavior =
          AXPositionAdjustmentBehavior::kMoveRight) const;

  // Adjusts the position by skipping over any objects that don't have a
  // corresponding |node| in the DOM tree, e.g. list bullets.
  const AXPosition AsValidDOMPosition(
      const AXPositionAdjustmentBehavior =
          AXPositionAdjustmentBehavior::kMoveRight) const;

  // Converts to a DOM position.
  const PositionWithAffinity ToPositionWithAffinity(
      const AXPositionAdjustmentBehavior =
          AXPositionAdjustmentBehavior::kMoveLeft) const;
  const Position ToPosition(const AXPositionAdjustmentBehavior =
                                AXPositionAdjustmentBehavior::kMoveLeft) const;

  // Returns a string representation of this object.
  String ToString() const;

 private:
  // Only used by static Create... methods.
  explicit AXPosition(const AXObject& container);

  // Searches the DOM tree starting from a particular child node within a
  // particular container node, and in the direction indicated by the adjustment
  // behavior, until it finds a node whose corresponding AX object is not
  // ignored. Returns nullptr if an unignored object is not found within the
  // provided container node. The container node could be nullptr if the whole
  // DOM tree needs to be searched.
  static const AXObject* FindNeighboringUnignoredObject(
      const Document& document,
      const Node& child_node,
      const ContainerNode* container_node,
      const AXPositionAdjustmentBehavior adjustment_behavior,
      const AXObjectCacheImpl& ax_object_cache);

  // Returns true if `character` is not included in the accessible text.
  // Ignored characters include zero-width space and isolate characters.
  static bool IsIgnoredCharacter(UChar character);

  // Returns the number of characters before `content_offset` that are ignored.
  // OffsetMappingUnits have offsets based on characters that we may exclude
  // from the text we expose to assistive technologies, such as:
  // * break opportunities inserted after preliminary whitespace in elements
  //   with `style= "whitespace: pre-wrap;"`
  // * isolate characters inserted in the content of SVG `text` and tspan`
  //   elements when `x` coordinates are specified.
  // Examples:
  // <div contenteditable="true" style="white-space: pre-wrap;">   Bar</div>
  // * Number of characters in the accessible text: 6 ("   Bar")
  // * Number of characters in the content: 7
  //
  // <text x="0 10 20 30 40 50 60 70 80 90 100 110"
  //       y="20">Hel<tspan>lo </tspan><tspan>world</tspan>!</text>
  // * Number of characters in the accessible text: 12 ("Hello world!")
  // * Number of characters in the content: 36
  //
  // The location of these ignored characters can be identified by checking
  // the OffsetMapping for non-contiguous units. For instance, in the case of
  // the SVG text, the "H" has a content range of 1-2, the "e" next to it a
  // content range of 4-5.
  //
  // Note that `<wbr>`, whose zero-width-space character is also ignored, does
  // have a mapping unit and corresponding node. As a result, its character
  // would not be included in the count returned here. Because it has a node,
  // we are already associating its offsets with the ignored accessible object.
  int GetLeadingIgnoredCharacterCount(const OffsetMapping* mapping,
                                      const Node* node,
                                      int container_offset,
                                      int content_offset) const;

  // The |AXObject| in which the position is present.
  // Only valid during a single document lifecycle hence no need to maintain a
  // strong reference to it.
  WeakPersistent<const AXObject> container_object_;

  // If the position is anchored to before or after an object, the number of
  // child objects in |container_object_| that come before the position.
  // If this is a text position, the number of characters in the canonical text
  // of |container_object_| before the position. The canonical text is the DOM
  // node's text but with, e.g., whitespace collapsed and any transformations
  // applied.
  int text_offset_or_child_index_;

  // When the same character offset could correspond to two possible caret
  // positions.
  TextAffinity affinity_;

#if DCHECK_IS_ON()
  // TODO(nektar): Use layout tree version in place of DOM and style versions.
  uint64_t dom_tree_version_;
  uint64_t style_version_;
#endif

  friend class AXSelection;
};

MODULES_EXPORT bool operator==(const AXPosition&, const AXPosition&);
MODULES_EXPORT bool operator!=(const AXPosition&, const AXPosition&);
MODULES_EXPORT bool operator<(const AXPosition&, const AXPosition&);
MODULES_EXPORT bool operator<=(const AXPosition&, const AXPosition&);
MODULES_EXPORT bool operator>(const AXPosition&, const AXPosition&);
MODULES_EXPORT bool operator>=(const AXPosition&, const AXPosition&);
MODULES_EXPORT std::ostream& operator<<(std::ostream&, const AXPosition&);

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_ACCESSIBILITY_AX_POSITION_H_