File: ax_tree.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 (586 lines) | stat: -rw-r--r-- 24,684 bytes parent folder | download | duplicates (2)
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
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
// Copyright 2013 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_AX_TREE_H_
#define UI_ACCESSIBILITY_AX_TREE_H_

#include <stdint.h>

#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>

#include "base/dcheck_is_on.h"
#include "base/debug/crash_logging.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "ui/accessibility/ax_common.h"
#include "ui/accessibility/ax_enums.mojom-forward.h"
#include "ui/accessibility/ax_export.h"
#include "ui/accessibility/ax_tree_data.h"
#include "ui/accessibility/ax_tree_update.h"

namespace ui {

struct AXEvent;
class AXLanguageDetectionManager;
class AXNode;
struct AXNodeData;
class AXTableInfo;
class AXTreeObserver;
struct AXTreeUpdateState;
class AXSelection;

// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(AXTreeUnserializeError)
enum class AXTreeUnserializeError {
  // Tree has no root.
  kNoRoot = 0,
  // Node will not be in the tree and is not the new root.
  kNotInTree = 1,
  // Node is already pending for creation, cannot be the new root
  kCreationPending = 2,
  // Node has duplicate child.
  kDuplicateChild = 3,
  // Node is already pending for creation, cannot be a new child.
  kCreationPendingForChild = 4,
  // Node is not marked for destruction, would be reparented.
  kReparent = 5,
  // Nodes are left pending by the update.
  kPendingNodes = 6,
  // Changes left pending by the update;
  kPendingChanges = 7,
  // This must always be the last enum. It's okay for its value to
  // increase, but none of the other enum values may change.
  kMaxValue = kPendingChanges
};
// LINT.ThenChange(/tools/metrics/histograms/metadata/accessibility/enums.xml:AccessibilityTreeUnserializeError)

#if BUILDFLAG(IS_LINUX)
// To support AriaNotify on older versions of ATK, we need to use the ATK
// signal "Text::text-insert". This signal requires a node that is a
// text type, and it needs to have aria-live properties set in order for
// Orca to make announcements. We create 2 extra "dummy" nodes that can be
// used for firing these signals when there is an AriaNotify event. One node
// will have `aria-live: assertive` and the other will have `aria-live:
// polite`.
class ExtraAnnouncementNodes {
 public:
  explicit ExtraAnnouncementNodes(AXNode* root);
  ~ExtraAnnouncementNodes();

  AXNode& AssertiveNode() const { return *assertive_node_; }
  AXNode& PoliteNode() const { return *polite_node_; }
  int Count() const {
    return (assertive_node_ ? 1 : 0) + (polite_node_ ? 1 : 0);
  }

  static constexpr int kHighPriorityIndex = 0;
  static constexpr int kNormalPriorityIndex = 1;

 private:
  std::unique_ptr<AXNode> CreateNode(const std::string& live_status,
                                     AXNode* root);

  std::unique_ptr<AXNode> assertive_node_;
  std::unique_ptr<AXNode> polite_node_;
};
#endif  // BUILDFLAG(IS_LINUX)

// AXTree is a live, managed tree of AXNode objects that can receive
// updates from another AXTreeSource via AXTreeUpdates, and it can be
// used as a source for sending updates to another client tree.
// It's designed to be subclassed to implement support for native
// accessibility APIs on a specific platform.
class AX_EXPORT AXTree {
 public:
  using IntReverseRelationMap =
      std::map<ax::mojom::IntAttribute, std::map<AXNodeID, std::set<AXNodeID>>>;
  using IntListReverseRelationMap =
      std::map<ax::mojom::IntListAttribute,
               std::map<AXNodeID, std::set<AXNodeID>>>;

  // If called, the focused node in this tree will never be ignored, even if it
  // has the ignored state set. For now, this boolean will be set to false for
  // all trees except in test scenarios, in order to thoroughly test the
  // relevant code without causing any potential regressions. Ultimately, we
  // want to expose all focused nodes so that a user of an assistive technology
  // will be able to interact with the application / website, even if there is
  // an authoring error, e.g. the aria-hidden attribute has been applied to the
  // focused element.
  // TODO(nektar): Removed once the feature has been fully tested.
  static void SetFocusedNodeShouldNeverBeIgnored();

  // Determines the ignored state of a node, given information about the node
  // and the tree.
  static bool ComputeNodeIsIgnored(const AXTreeData* optional_tree_data,
                                   const AXNodeData& node_data);

  // Determines whether a node has flipped its ignored state, given information
  // about the previous and current state of the node / tree.
  static bool ComputeNodeIsIgnoredChanged(
      const AXTreeData* optional_old_tree_data,
      const AXNodeData& old_node_data,
      const AXTreeData* optional_new_tree_data,
      const AXNodeData& new_node_data);

  AXTree();
  explicit AXTree(const AXTreeUpdate& initial_state);
  virtual ~AXTree();

  // AXTree owns pointers so copying is non-trivial.
  AXTree(const AXTree&) = delete;
  AXTree& operator=(const AXTree&) = delete;

  void AddObserver(AXTreeObserver* observer);
  bool HasObserver(AXTreeObserver* observer);
  void RemoveObserver(AXTreeObserver* observer);

  base::ObserverList<AXTreeObserver>& observers() { return observers_; }

  AXNode* root() const { return root_; }

  const AXTreeData& data() const;

  // Destroys the tree and notifies all observers.
  void Destroy();

  // Returns the globally unique ID of this accessibility tree.
  const AXTreeID& GetAXTreeID() const;

  // Given a node in this accessibility tree that corresponds to a table
  // or grid, return an object containing information about the
  // table structure. This object is computed lazily on-demand and
  // cached until the next time the tree is updated. Clients should
  // not retain this pointer, they should just request it every time
  // it's needed.
  //
  // Returns nullptr if the node is not a valid table.
  AXTableInfo* GetTableInfo(const AXNode* table_node) const;

  // Returns the AXNode with the given |id| if it is part of this AXTree.
  AXNode* GetFromId(AXNodeID id) const;

  // Returns true on success. If it returns false, it's a fatal error
  // and this tree should be destroyed, and the source of the tree update
  // should not be trusted any longer.
  virtual bool Unserialize(const AXTreeUpdate& update);

  // Used by tests to update the tree data without changing any of the nodes in
  // the tree, notifying all tree observers in the process.
  virtual void UpdateDataForTesting(const AXTreeData& data);

  // Convert any rectangle from the local coordinate space of one node in
  // the tree, to bounds in the coordinate space of the tree.
  // If set, updates |offscreen| boolean to be true if the node is offscreen
  // relative to its rootWebArea. Callers should initialize |offscreen|
  // to false: this method may get called multiple times in a row and
  // |offscreen| will be propagated.
  // If |clip_bounds| is true, result bounds will be clipped.
  gfx::RectF RelativeToTreeBounds(const AXNode* node,
                                  gfx::RectF node_bounds,
                                  bool* offscreen = nullptr,
                                  bool clip_bounds = true,
                                  bool skip_container_offset = false) const;

  // Get the bounds of a node in the coordinate space of the tree.
  // If set, updates |offscreen| boolean to be true if the node is offscreen
  // relative to its rootWebArea. Callers should initialize |offscreen|
  // to false: this method may get called multiple times in a row and
  // |offscreen| will be propagated.
  // If |clip_bounds| is true, result bounds will be clipped.
  gfx::RectF GetTreeBounds(const AXNode* node,
                           bool* offscreen = nullptr,
                           bool clip_bounds = true) const;

  // Given a node ID attribute (one where IsNodeIdIntAttribute is true),
  // and a destination node ID, return a set of all source node IDs that
  // have that relationship attribute between them and the destination.
  std::set<AXNodeID> GetReverseRelations(ax::mojom::IntAttribute attr,
                                         AXNodeID dst_id) const;

  // Given a node ID list attribute (one where
  // IsNodeIdIntListAttribute is true), and a destination node ID,
  // return a set of all source node IDs that have that relationship
  // attribute between them and the destination.
  std::set<AXNodeID> GetReverseRelations(ax::mojom::IntListAttribute attr,
                                         AXNodeID dst_id) const;

  // Given a child tree ID, return the node IDs of all nodes in the tree who
  // have a kChildTreeId int attribute with that value.
  //
  // TODO(accessibility): There should really be only one host node per child
  // tree, so the return value should not be a set but a single node ID or
  // `kInvalidAXNodeID`.
  std::set<AXNodeID> GetNodeIdsForChildTreeId(AXTreeID child_tree_id) const;

  // Get all of the child tree IDs referenced by any node in this tree.
  const std::set<AXTreeID> GetAllChildTreeIds() const;

  // Map from a relation attribute to a map from a target id to source ids.
  const IntReverseRelationMap& int_reverse_relations() {
    return int_reverse_relations_;
  }
  const IntListReverseRelationMap& intlist_reverse_relations() {
    return intlist_reverse_relations_;
  }

  // Return a multi-line indented string representation, for logging.
  std::string ToString(bool verbose = true) const;

  // A string describing the error from an unsuccessful Unserialize,
  // for testing and debugging.
  const std::string& error() const { return error_; }

  int size() { return static_cast<int>(id_map_.size()); }

  // Return a negative number that's suitable to use for a node ID for
  // internal nodes created automatically by an AXTree, so as not to
  // conflict with positive-numbered node IDs from tree sources.
  AXNodeID GetNextNegativeInternalNodeId();

  // Returns the PosInSet of |node|. Looks in node_set_size_pos_in_set_info_map_
  // for cached value. Calls |ComputeSetSizePosInSetAndCache|if no value is
  // present in the cache.
  std::optional<int> GetPosInSet(const AXNode& node);

  // Returns the SetSize of |node|. Looks in node_set_size_pos_in_set_info_map_
  // for cached value. Calls |ComputeSetSizePosInSetAndCache|if no value is
  // present in the cache.
  std::optional<int> GetSetSize(const AXNode& node);

  // Returns the part of the current selection that falls within this
  // accessibility tree, if any.
  AXSelection GetSelection() const;

  // Returns the part of the current selection that falls within this
  // accessibility tree, if any, adjusting its endpoints to be within unignored
  // nodes. (An "ignored" node is a node that is not exposed to platform APIs:
  // See `AXNode::IsIgnored`.)
  AXSelection GetUnignoredSelection() const;

  bool GetTreeUpdateInProgressState() const;

  // Returns true if the tree represents a paginated document
  bool HasPaginationSupport() const;

  // Language detection manager, entry point to language detection features.
  // TODO(chrishall): Should this be stored by pointer or value?
  //                  When should we initialize this?
  std::unique_ptr<AXLanguageDetectionManager> language_detection_manager;

  // Event metadata while applying a tree update during unserialization.
  AXEvent* event_data() const { return event_data_.get(); }

  // Notify the delegate that the tree manager for |previous_tree_id| will be
  // removed from the AXTreeManagerMap. Because we sometimes remove the tree
  // manager after the tree's id has been modified, we need to pass the (old)
  // tree id associated with the manager we are removing even though it is the
  // same tree.
  void NotifyTreeManagerWillBeRemoved(AXTreeID previous_tree_id);

  void NotifyChildTreeConnectionChanged(AXNode* node, AXTree* child_tree);

#if BUILDFLAG(IS_LINUX)
  void ClearExtraAnnouncementNodes();
  void CreateExtraAnnouncementNodes();
  ExtraAnnouncementNodes* extra_announcement_nodes() const {
    return extra_announcement_nodes_.get();
  }
#endif  // BUILDFLAG(IS_LINUX)

 private:
  friend class ScopedTreeUpdateInProgressStateSetter;
  friend class AXTableInfoTest;

  // Indicates if the node with the focus should never be ignored, (see
  // `SetFocusedNodeShouldNeverBeIgnored` above).
  static bool is_focused_node_always_unignored_;

#if AX_FAIL_FAST_BUILD()
  void CheckTreeConsistency(const AXTreeUpdate& update);
#endif

  // Accumulate errors as there can be more than one before Chrome is crashed
  // via UnrecoverableAccessibilityError();
  // In an AX_FAIL_FAST_BUILD or if |is_fatal|, will assert/crash immediately.
  void RecordError(const AXTreeUpdateState& update_state,
                   std::string new_error,
                   bool is_fatal = false);

  AXNode* CreateNode(AXNode* parent,
                     AXNodeID id,
                     size_t index_in_parent,
                     AXTreeUpdateState* update_state);

  // Accumulates the work that will be required to update the AXTree.
  // This allows us to notify observers of structure changes when the
  // tree is still in a stable and unchanged state.
  bool ComputePendingChanges(const AXTreeUpdate& update,
                             AXTreeUpdateState* update_state);

  // Populates |update_state| with information about actions that will
  // be performed on the tree during the update, such as adding or
  // removing nodes in the tree. Returns true on success.
  // Nothing within this call should modify tree structure or node data.
  bool ComputePendingChangesToNode(const AXNodeData& new_data,
                                   bool is_new_root,
                                   AXTreeUpdateState* update_state);

  // This is called from within Unserialize(), it returns true on success.
  bool UpdateNode(const AXNodeData& src,
                  bool is_new_root,
                  AXTreeUpdateState* update_state);

  // Notify the delegate that the subtree rooted at |node| will be
  // destroyed or reparented.
  void NotifySubtreeWillBeReparentedOrDeleted(
      AXNode* node,
      const AXTreeUpdateState* update_state);

  // Notify the delegate that |node| will be destroyed or reparented.
  void NotifyNodeWillBeReparentedOrDeleted(
      AXNode& node,
      const AXTreeUpdateState& update_state);

  // Notify the delegate that |node| and all of its descendants will be
  // destroyed. This function is called during AXTree teardown.
  void RecursivelyNotifyNodeWillBeDeletedForTreeTeardown(
      AXNode& node,
      std::set<AXNodeID>& deleted_nodes);

  // Notify the delegate that the node marked by |node_id| has been deleted.
  // We are passing the node id instead of ax node is because by the time this
  // function is called, the ax node in the tree will already have been
  // destroyed.
  void NotifyNodeHasBeenDeleted(AXNodeID node_id);

  // Notify the delegate that |node| has been created or reparented.
  void NotifyNodeHasBeenReparentedOrCreated(
      AXNode* node,
      const AXTreeUpdateState* update_state);

  // Notify the delegate that `node` will change its data attributes, including
  // its ignored state.
  void NotifyNodeAttributesWillChange(AXNode* node,
                                      AXTreeUpdateState& update_state,
                                      const AXTreeData* optional_old_tree_data,
                                      const AXNodeData& old_data,
                                      const AXTreeData* new_tree_data,
                                      const AXNodeData& new_data);

  // Notify the delegate that `node` will change its its ignored state.
  void NotifyNodeIgnoredStateWillChange(
      AXNode* node,
      const AXTreeData* optional_old_tree_data,
      const AXNodeData& old_data,
      const AXTreeData* new_tree_data,
      const AXNodeData& new_data);

  // Notify the delegate that `node` has changed its data attributes, including
  // its ignored state.
  void NotifyNodeAttributesHaveBeenChanged(
      AXNode* node,
      AXTreeUpdateState& update_state,
      const AXTreeData* optional_old_tree_data,
      const AXNodeData& old_data,
      const AXTreeData* new_tree_data,
      const AXNodeData& new_data);

  // Update maps that track which relations are pointing to |node|.
  void UpdateReverseRelations(AXNode* node,
                              const AXNodeData& new_data,
                              bool is_new_node = false);

  // Sets a flag indicating whether the tree is currently being updated or not.
  // If the tree is being updated, then its internal pointers might be invalid
  // and the tree should not be traversed.
  void SetTreeUpdateInProgressState(bool set_tree_update_value);

  // Returns true if all pending changes in the |update_state| have been
  // handled. If this returns false, the |error_| message will be populated.
  // It's a fatal error to have pending changes after exhausting
  // the AXTreeUpdate.
  bool ValidatePendingChangesComplete(const AXTreeUpdateState& update_state);

  // Modifies |update_state| so that it knows what subtree and nodes are
  // going to be destroyed for the subtree rooted at |node|.
  void MarkSubtreeForDestruction(AXNodeID node_id,
                                 AXTreeUpdateState* update_state);

  // Modifies |update_state| so that it knows what nodes are
  // going to be destroyed for the subtree rooted at |node|.
  void MarkNodesForDestructionRecursive(AXNodeID node_id,
                                        AXTreeUpdateState* update_state);

  // Validates that destroying the subtree rooted at |node| has required
  // information in |update_state|, then calls DestroyNodeAndSubtree on it.
  void DestroySubtree(AXNode* node, AXTreeUpdateState* update_state);

  // Call Destroy() on |node|, and delete it from the id map, and then
  // call recursively on all nodes in its subtree.
  void DestroyNodeAndSubtree(AXNode* node, AXTreeUpdateState* update_state);

  // Iterate over the children of |node| and for each child, destroy the
  // child and its subtree if its id is not in |new_child_ids|.
  void DeleteOldChildren(AXNode* node,
                         const std::vector<AXNodeID>& new_child_ids,
                         AXTreeUpdateState* update_state);

  // Iterate over |new_child_ids| and populate |new_children| with
  // pointers to child nodes, reusing existing nodes already in the tree
  // if they exist, and creating otherwise. Reparenting is disallowed, so
  // if the id already exists as the child of another node, that's an
  // error. Returns true on success, false on fatal error.
  bool CreateNewChildVector(
      AXNode* node,
      const std::vector<AXNodeID>& new_child_ids,
      std::vector<raw_ptr<AXNode, VectorExperimental>>* new_children,
      AXTreeUpdateState* update_state);

  // Returns the lowest unignored ancestor of the node with the given ID. If the
  // node is not ignored, it returns the node.
  AXNode* GetUnignoredAncestorFromId(AXNodeID node_id) const;

  // Internal implementation of RelativeToTreeBounds. It calls itself
  // recursively but ensures that it can only do so exactly once!
  gfx::RectF RelativeToTreeBoundsInternal(const AXNode* node,
                                          gfx::RectF node_bounds,
                                          bool* offscreen,
                                          bool clip_bounds,
                                          bool skip_container_offset,
                                          bool allow_recursion) const;

  base::ObserverList<AXTreeObserver> observers_;
  raw_ptr<AXNode> root_ = nullptr;
  std::unordered_map<AXNodeID, std::unique_ptr<AXNode>> id_map_;
  std::string error_;
  AXTreeData data_;

  // Map from an int attribute (if IsNodeIdIntAttribute is true) to
  // a reverse mapping from target nodes to source nodes.
  IntReverseRelationMap int_reverse_relations_;
  // Map from an int list attribute (if IsNodeIdIntListAttribute is true) to
  // a reverse mapping from target nodes to source nodes.
  IntListReverseRelationMap intlist_reverse_relations_;
  // Map from child tree ID to the set of node IDs that contain that attribute.
  std::map<AXTreeID, std::set<AXNodeID>> child_tree_id_reverse_map_;

  // Map from node ID to cached table info, if the given node is a table.
  // Invalidated every time the tree is updated.
  mutable std::unordered_map<AXNodeID, std::unique_ptr<AXTableInfo>>
      table_info_map_;

  // The next negative node ID to use for internal nodes.
  AXNodeID next_negative_internal_node_id_ = -1;

  // Contains pos_in_set and set_size data for an AXNode.
  struct NodeSetSizePosInSetInfo {
    NodeSetSizePosInSetInfo();
    ~NodeSetSizePosInSetInfo();

    std::optional<int> pos_in_set;
    std::optional<int> set_size;
    std::optional<int> lowest_hierarchical_level;
  };

  // Represents the content of an ordered set which includes the ordered set
  // items and the ordered set container if it exists.
  struct OrderedSetContent;

  // Maps a particular hierarchical level to a list of OrderedSetContents.
  // Represents all ordered set items/container on a particular hierarchical
  // level.
  struct OrderedSetItemsMap;

  // Populates |items_map_to_be_populated| with all items associated with
  // |original_node| and within |ordered_set|. Only items whose roles match the
  // role of the |ordered_set| will be added.
  void PopulateOrderedSetItemsMap(
      const AXNode& original_node,
      const AXNode* ordered_set,
      OrderedSetItemsMap* items_map_to_be_populated) const;

  // Helper function for recursively populating ordered sets items map with
  // all items associated with |original_node| and |ordered_set|. |local_parent|
  // tracks the recursively passed in child nodes of |ordered_set|.
  void RecursivelyPopulateOrderedSetItemsMap(
      const AXNode& original_node,
      const AXNode* ordered_set,
      const AXNode* local_parent,
      std::optional<int> ordered_set_min_level,
      std::optional<int> prev_level,
      OrderedSetItemsMap* items_map_to_be_populated) const;

  // Computes the pos_in_set and set_size values of all items in ordered_set and
  // caches those values. Called by GetPosInSet and GetSetSize.
  void ComputeSetSizePosInSetAndCache(const AXNode& node,
                                      const AXNode* ordered_set);

  // Helper for ComputeSetSizePosInSetAndCache. Computes and caches the
  // pos_in_set and set_size values for a given OrderedSetContent.
  void ComputeSetSizePosInSetAndCacheHelper(
      const OrderedSetContent& ordered_set_content);

  // Map from node ID to OrderedSetInfo.
  // Item-like and ordered-set-like objects will map to populated OrderedSetInfo
  // objects.
  // All other objects will map to default-constructed OrderedSetInfo objects.
  // Invalidated every time the tree is updated.
  mutable std::unordered_map<AXNodeID, NodeSetSizePosInSetInfo>
      node_set_size_pos_in_set_info_map_;

  // Indicates if the tree is updating.
  bool tree_update_in_progress_ = false;

  // Indicates if the tree represents a paginated document
  bool has_pagination_support_ = false;

#if DCHECK_IS_ON()
  bool is_destroyed_ = false;
  int unserialize_count_ = 0;
#endif

  std::unique_ptr<AXEvent> event_data_;

#if BUILDFLAG(IS_LINUX)
  std::unique_ptr<ExtraAnnouncementNodes> extra_announcement_nodes_ = nullptr;
#endif  // BUILDFLAG(IS_LINUX)
};

// Sets the flag that indicates whether the accessibility tree is currently
// being updated, and ensures that it is reset to its previous value when the
// instance is destructed. An accessibility tree that is being updated is
// unstable and should not be traversed.
class AX_EXPORT ScopedTreeUpdateInProgressStateSetter {
 public:
  explicit ScopedTreeUpdateInProgressStateSetter(AXTree& tree)
      : tree_(&tree),
        last_tree_update_in_progress_(tree.GetTreeUpdateInProgressState()) {
    tree_->SetTreeUpdateInProgressState(true);
  }

  ~ScopedTreeUpdateInProgressStateSetter() {
    tree_->SetTreeUpdateInProgressState(last_tree_update_in_progress_);
  }

  ScopedTreeUpdateInProgressStateSetter(
      const ScopedTreeUpdateInProgressStateSetter&) = delete;
  ScopedTreeUpdateInProgressStateSetter& operator=(
      const ScopedTreeUpdateInProgressStateSetter&) = delete;

 private:
  const raw_ptr<AXTree> tree_;
  bool last_tree_update_in_progress_;
};

}  // namespace ui

#endif  // UI_ACCESSIBILITY_AX_TREE_H_