File: ax_platform_node_auralinux.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (428 lines) | stat: -rw-r--r-- 16,506 bytes parent folder | download | duplicates (4)
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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_AURALINUX_H_
#define UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_AURALINUX_H_

#include <atk/atk.h>

#include <memory>
#include <optional>
#include <string>
#include <utility>

#include "base/component_export.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/no_destructor.h"
#include "base/strings/utf_offset_string_conversions.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
#include "ui/accessibility/platform/ax_platform_node_base.h"

// This deleter is used in order to ensure that we properly always free memory
// used by AtkAttributeSet.
struct AtkAttributeSetDeleter {
  void operator()(AtkAttributeSet* attributes) {
    atk_attribute_set_free(attributes);
  }
};

// Internal replication of the Atk.Live enum
// https://docs.gtk.org/atk/enum.Live.html
// TODO(https://crbug.com/404172321): We replicated this due to build issues
// likely due to the newness of this enum in the Atk library. Remove this in
// favor of the Atk library enum when Atk headers are updated internally.
enum AriaNotificationAtkLive {
  kNone,
  kPolite,
  kAssertive,
};

using AtkAttributes = std::unique_ptr<AtkAttributeSet, AtkAttributeSetDeleter>;

// Some ATK interfaces require returning a (const gchar*), use
// this macro to make it safe to return a pointer to a temporary
// string.
#define ATK_AURALINUX_RETURN_STRING(str_expr)      \
  {                                                \
    static base::NoDestructor<std::string> result; \
    *result = (str_expr);                          \
    return result->c_str();                        \
  }

namespace ui {

struct FindInPageResultInfo {
  raw_ptr<AtkObject> node;
  int start_offset;
  int end_offset;

  bool operator==(const FindInPageResultInfo& other) const {
    return (node == other.node) && (start_offset == other.start_offset) &&
           (end_offset == other.end_offset);
  }
};

// This class with an enum is used to generate a bitmask which tracks the ATK
// interfaces that an AXPlatformNodeAuraLinux's ATKObject implements.
class ImplementedAtkInterfaces {
 public:
  enum class Value {
    kDefault = 1 << 1,
    kDocument = 1 << 1,
    kHyperlink = 1 << 2,
    kHypertext = 1 << 3,
    kImage = 1 << 4,
    kSelection = 1 << 5,
    kTableCell = 1 << 6,
    kTable = 1 << 7,
    kText = 1 << 8,
    kValue = 1 << 9,
    kWindow = 1 << 10,
  };

  bool Implements(Value interface) const {
    return value_ & static_cast<int>(interface);
  }

  void Add(Value other) { value_ |= static_cast<int>(other); }

  friend bool operator==(const ImplementedAtkInterfaces&,
                         const ImplementedAtkInterfaces&) = default;

  int value() const { return value_; }

 private:
  int value_ = static_cast<int>(Value::kDefault);
};

// Implements accessibility on Aura Linux using ATK.
class COMPONENT_EXPORT(AX_PLATFORM) AXPlatformNodeAuraLinux
    : public AXPlatformNodeBase {
 public:
  AXPlatformNodeAuraLinux(const AXPlatformNodeAuraLinux&) = delete;
  AXPlatformNodeAuraLinux& operator=(const AXPlatformNodeAuraLinux&) = delete;

  static AXPlatformNodeAuraLinux* FromAtkObject(const AtkObject*);

  // Set or get the root-level Application object that's the parent of all
  // top-level windows.
  static void SetApplication(AXPlatformNode* application);
  static AXPlatformNode* application();

  static void EnsureGTypeInit();

  // Do asynchronous static initialization.
  static void StaticInitialize();

  // EnsureAtkObjectIsValid will destroy and recreate |atk_object_| if the
  // interface mask is different. This partially relies on looking at the tree's
  // structure. This must not be called when the tree is unstable e.g. in the
  // middle of being unserialized.
  void EnsureAtkObjectIsValid();
  void Destroy() override;

  AtkRole GetAtkRole() const;
  void GetAtkState(AtkStateSet* state_set);
  AtkRelationSet* GetAtkRelations();
  void GetExtents(gint* x, gint* y, gint* width, gint* height,
                  AtkCoordType coord_type);
  void GetPosition(gint* x, gint* y, AtkCoordType coord_type);
  void GetSize(gint* width, gint* height);
  gfx::NativeViewAccessible HitTestSync(gint x,
                                        gint y,
                                        AtkCoordType coord_type);
  bool GrabFocus();
  bool FocusFirstFocusableAncestorInWebContent();
  bool GrabFocusOrSetSequentialFocusNavigationStartingPointAtOffset(int offset);
  bool GrabFocusOrSetSequentialFocusNavigationStartingPoint();
  bool SetSequentialFocusNavigationStartingPoint();
  const gchar* GetDefaultActionName();
  AtkAttributeSet* GetAtkAttributes();

  gfx::Vector2d GetParentOriginInScreenCoordinates() const;
  gfx::Vector2d GetParentFrameOriginInScreenCoordinates() const;
  gfx::Rect GetExtentsRelativeToAtkCoordinateType(
      AtkCoordType coord_type) const;

  // AtkDocument helpers
  const gchar* GetDocumentAttributeValue(const gchar* attribute) const;
  AtkAttributeSet* GetDocumentAttributes() const;

  // AtkHyperlink helpers
  AtkHyperlink* GetAtkHyperlink();

#if defined(ATK_CHECK_VERSION) && ATK_CHECK_VERSION(2, 30, 0)
  void ScrollToPoint(AtkCoordType atk_coord_type, int x, int y);
  void ScrollNodeRectIntoView(gfx::Rect rect, AtkScrollType atk_scroll_type);
  void ScrollNodeIntoView(AtkScrollType atk_scroll_type);
#endif  // defined(ATK_CHECK_VERSION) && ATK_CHECK_VERSION(2, 30, 0)

#if defined(ATK_CHECK_VERSION) && ATK_CHECK_VERSION(2, 32, 0)
  std::optional<gfx::Rect> GetUnclippedHypertextRangeBoundsRect(
      int start_offset,
      int end_offset);
  bool ScrollSubstringIntoView(AtkScrollType atk_scroll_type,
                               int start_offset,
                               int end_offset);
  bool ScrollSubstringToPoint(int start_offset,
                              int end_offset,
                              AtkCoordType atk_coord_type,
                              int x,
                              int y);
#endif  // defined(ATK_CHECK_VERSION) && ATK_CHECK_VERSION(2, 32, 0)

  // Misc helpers
  void GetFloatAttributeInGValue(ax::mojom::FloatAttribute attr, GValue* value);

  // Event helpers
  void OnBusyStateChanged(bool is_busy);
  void OnCheckedStateChanged();
  void OnEnabledChanged();
  void OnExpandedStateChanged(bool is_expanded);
  void OnShowingStateChanged(bool is_showing);
  void OnFocused();
  void OnWindowActivated();
  void OnWindowDeactivated();
  void OnMenuPopupStart();
  void OnMenuPopupEnd();
  void OnAllMenusEnded();
  void OnSelected();
  void OnSelectedChildrenChanged();
  void OnTextAttributesChanged();
  void OnTextSelectionChanged();
  void OnValueChanged();
  void OnNameChanged();
  void OnDescriptionChanged();
  void OnSortDirectionChanged();
  void OnInvalidStatusChanged();
  void OnAriaCurrentChanged();
  void OnAriaNotificationPosted(
      const std::string& announcement,
      ax::mojom::AriaNotificationPriority priority_property);
  void OnDocumentTitleChanged();
  void OnSubtreeCreated();
  void OnSubtreeWillBeDeleted();
  void OnParentChanged();
  void OnReadonlyChanged();
  void OnWindowVisibilityChanged();
  void OnScrolledToAnchor();
  void OnAlertShown();
  void RunPostponedEvents();

  void ResendFocusSignalsForCurrentlyFocusedNode();
  void SetAsCurrentlyFocusedNode();
  bool SupportsSelectionWithAtkSelection();
  void SetActiveViewsDialog();

  // AXPlatformNode overrides.
  // This has a side effect of creating the AtkObject if one does not already
  // exist.
  gfx::NativeViewAccessible GetNativeViewAccessible() override;
  void NotifyAccessibilityEvent(ax::mojom::Event event_type) override;

  // AXPlatformNodeBase overrides.
  bool IsPlatformCheckable() const override;
  std::optional<size_t> GetIndexInParent() override;

  bool IsNameExposed();

  void UpdateHypertext();
  const AXLegacyHypertext& GetAXHypertext();
  const base::OffsetAdjuster::Adjustments& GetHypertextAdjustments();
  size_t UTF16ToUnicodeOffsetInText(size_t utf16_offset);
  size_t UnicodeToUTF16OffsetInText(int unicode_offset);
  int GetTextOffsetAtPoint(int x, int y, AtkCoordType atk_coord_type);

  // Called on a toplevel frame to set the document parent, which is the parent
  // of the toplevel document. This is used to properly express the ATK embeds
  // relationship between a toplevel frame and its embedded document.
  void SetDocumentParent(AtkObject* new_document_parent);

  int GetCaretOffset();
  bool SetCaretOffset(int offset);
  bool SetTextSelectionForAtkText(int start_offset, int end_offset);
  bool HasSelection();

  void GetSelectionExtents(int* start_offset, int* end_offset);
  gchar* GetSelectionWithText(int* start_offset, int* end_offset);

  // Return the text attributes for this node given an offset. The start
  // and end attributes will be assigned to the start_offset and end_offset
  // pointers if they are non-null. The return value AtkAttributeSet should
  // be freed with atk_attribute_set_free.
  const TextAttributeList& GetTextAttributes(int offset,
                                             int* start_offset,
                                             int* end_offset);

  // Return the default text attributes for this node. The default text
  // attributes are the ones that apply to the entire node. Attributes found at
  // a given offset can be thought of as overriding the default attribute.
  // The return value AtkAttributeSet should be freed with
  // atk_attribute_set_free.
  const TextAttributeList& GetDefaultTextAttributes();

  void ActivateFindInPageResult(int start_offset, int end_offset);
  void TerminateFindInPage();

  // If there is a find in page result for the toplevel document of this node,
  // return it, otherwise return std::nullopt;
  std::optional<FindInPageResultInfo> GetSelectionOffsetsFromFindInPage();

  std::pair<int, int> GetSelectionOffsetsForAtk();

  // Get the embedded object ("hyperlink") indices for this object in the
  // parent. If this object doesn't have a parent or isn't embedded, return
  // nullopt.
  std::optional<std::pair<int, int>> GetEmbeddedObjectIndices();

  AXPlatformNodeAuraLinux* GetFromNodeID(int32_t node_id);

  std::string accessible_name_;

 protected:
  AXPlatformNodeAuraLinux();
  ~AXPlatformNodeAuraLinux() override;

  // AXPlatformNode overrides.
  void Init(AXPlatformNodeDelegate& delegate) override;

  // Offsets for the AtkText API are calculated in UTF-16 code point offsets,
  // but the ATK APIs want all offsets to be in "characters," which we
  // understand to be Unicode character offsets. We keep a lazily generated set
  // of Adjustments to convert between UTF-16 and Unicode character offsets.
  std::optional<base::OffsetAdjuster::Adjustments> text_unicode_adjustments_ =
      std::nullopt;

  void AddAttributeToList(const char* name,
                          const char* value,
                          PlatformAttributeList* attributes) override;

 private:
  // This is static to ensure that we aren't trying to access the rest of the
  // accessibility tree during node initialization.
  static ImplementedAtkInterfaces GetGTypeInterfaceMask(const AXNodeData& data);

  GType GetAccessibilityGType();
  AtkObject* CreateAtkObject();
  // Get or Create AtkObject. Note that it could return nullptr except
  // ax::mojom::Role::kApplication when the mode is not enabled.
  gfx::NativeViewAccessible GetOrCreateAtkObject();
  void DestroyAtkObjects();
  void AddRelationToSet(AtkRelationSet*,
                        AtkRelationType,
                        AXPlatformNode* target);
  bool IsInLiveRegion();
  std::optional<std::pair<int, int>> GetEmbeddedObjectIndicesForId(int id);

  void ComputeStylesIfNeeded();
  int FindStartOfStyle(int start_offset, ax::mojom::MoveDirection direction);

  // Reset any find in page operations for the toplevel document of this node.
  void ForgetCurrentFindInPageResult();

  // Activate a find in page result for the toplevel document of this node.
  void ActivateFindInPageInParent(int start_offset, int end_offset);

  // If this node is the toplevel document node, find its parent and set it on
  // the toplevel frame which contains the node.
  void SetDocumentParentOnFrameIfNecessary();

  // Find the child which is a document containing the primary web content.
  AtkObject* FindPrimaryWebContentDocument();

  // Returns true if it is a web content for the relations.
  bool IsWebDocumentForRelations();

  // If a selection that intersects this node get the full selection
  // including start and end node ids.
  void GetFullSelection(int32_t* anchor_node_id,
                        int* anchor_offset,
                        int32_t* focus_node_id,
                        int* focus_offset);

  // Returns true if this node's AtkObject is suitable for emitting AtkText
  // signals. ATs don't expect static text objects to emit AtkText signals.
  bool EmitsAtkTextEvents() const;

  // Find the first ancestor which is an editable root or a document. This node
  // will be one which contains a single selection.
  AXPlatformNodeAuraLinux& FindEditableRootOrDocument();

  // Find the first common ancestor between this node and a given node.
  AXPlatformNodeAuraLinux* FindCommonAncestor(AXPlatformNodeAuraLinux* other);

  // Update the selection information stored in this node. This should be
  // called on the editable root, the root node of the accessibility tree, or
  // the document (ie the node returned by FindEditableRootOrDocument()).
  void UpdateSelectionInformation(int32_t anchor_node_id,
                                  int anchor_offset,
                                  int32_t focus_node_id,
                                  int focus_offset);

  // Emit a GObject signal indicating a selection change.
  void EmitSelectionChangedSignal(bool had_selection);

  // Emit a GObject signal indicating that the caret has moved.
  void EmitCaretChangedSignal();

  bool HadNonZeroWidthSelection() const { return had_nonzero_width_selection; }
  std::pair<int32_t, int> GetCurrentCaret() const { return current_caret_; }

  // If the given argument can be found as a child of this node, return its
  // hypertext extents, otherwise return std::nullopt;
  std::optional<std::pair<int, int>> GetHypertextExtentsOfChild(
      AXPlatformNodeAuraLinux* child);

  // The AtkStateType for a checkable node can vary depending on the role.
  AtkStateType GetAtkStateTypeForCheckableNode();

  gfx::Point ConvertPointToScreenCoordinates(const gfx::Point& point,
                                             AtkCoordType atk_coord_type);

  // Keep information of latest ImplementedAtkInterfaces mask to rebuild the
  // ATK object accordingly when the platform node changes.
  ImplementedAtkInterfaces interface_mask_;

  // We own a reference to these ref-counted objects.
  raw_ptr<AtkObject, DanglingUntriaged> atk_object_ = nullptr;
  raw_ptr<AtkHyperlink, DanglingUntriaged> atk_hyperlink_ = nullptr;

  // A weak pointer which help us track the ATK embeds relation.
  // RAW_PTR_EXCLUSION: #addr-of and not much we can do about it (see
  // crbug.com/346693629).
  RAW_PTR_EXCLUSION AtkObject* document_parent_ = nullptr;

  // Whether or not this node (if it is a frame or a window) was
  // minimized the last time it's visibility changed.
  bool was_minimized_ = false;

  // Information about the selection meant to be stored on the return value of
  // FindEditableRootOrDocument().
  //
  // Whether or not we previously had a selection where the anchor and focus
  // were not equal. This is what ATK consider a "selection."
  bool had_nonzero_width_selection = false;

  // Information about the current caret location (a node id and an offset).
  // This is used to track when the caret actually moves during a selection
  // change.
  std::pair<int32_t, int> current_caret_ = {-1, -1};

  // A map which converts between an offset in the node's hypertext and the
  // ATK text attributes at that offset.
  TextAttributeMap offset_to_text_attributes_;

  // The default ATK text attributes for this node.
  TextAttributeList default_text_attributes_;

  bool window_activate_event_postponed_ = false;

  friend AXPlatformNode::Pointer AXPlatformNode::Create(
      AXPlatformNodeDelegate& delegate);
};

}  // namespace ui

#endif  // UI_ACCESSIBILITY_PLATFORM_AX_PLATFORM_NODE_AURALINUX_H_