File: ax_selection.cc

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 (129 lines) | stat: -rw-r--r-- 5,015 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
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/accessibility/ax_selection.h"

#include "ui/accessibility/ax_node_position.h"

namespace ui {

namespace {

// Helper for GetUnignoredSelection. Creates a position using |node_id|,
// |offset| and |affinity|, and if it's ignored, updates these arguments so
// that they represent a non-null non-ignored position, according to
// |adjustment_behavior|. Returns true on success, false on failure. Note that
// if the position is initially null, it's not ignored and it's a success.
bool ComputeUnignoredSelectionEndpoint(
    const AXTree* tree,
    AXPositionAdjustmentBehavior adjustment_behavior,
    AXNodeID& node_id,
    int32_t& offset,
    ax::mojom::TextAffinity& affinity) {
  AXNode* node = tree ? tree->GetFromId(node_id) : nullptr;
  if (!node) {
    node_id = kInvalidAXNodeID;
    offset = AXNodePosition::INVALID_OFFSET;
    affinity = ax::mojom::TextAffinity::kDownstream;
    return false;
  }

  AXNodePosition::AXPositionInstance position =
      AXNodePosition::CreatePosition(*node, offset, affinity);

  // Null positions are never ignored, but must be considered successful, or
  // these Android tests would fail:
  // org.chromium.content.browser.accessibility.AssistViewStructureTest#*
  // The reason is that |position| becomes null because no AXTreeManager is
  // registered for that |tree|'s AXTreeID.
  // TODO(accessibility): investigate and fix this if needed.
  if (!position->IsIgnored()) {
    return true;  // We assume that unignored positions are already valid.
  }

  position =
      position->AsValidPosition()->AsUnignoredPosition(adjustment_behavior);

  // Moving to an unignored position might have placed the position on a leaf
  // node. Any selection endpoint that is inside a leaf node is expressed as a
  // text position in AXTreeData. (Note that in this context "leaf node" means
  // a node with no children or with only ignored children. This does not
  // refer to a platform leaf.)
  if (position->IsLeafTreePosition())
    position = position->AsTextPosition();

  // We do not expect the selection to have an endpoint on an inline text
  // box as this will create issues with parts of the code that don't use
  // inline text boxes.
  if (position->IsTextPosition() &&
      position->GetRole() == ax::mojom::Role::kInlineTextBox) {
    position = position->CreateParentPosition();
  }

  switch (position->kind()) {
    case AXPositionKind::NULL_POSITION:
      node_id = kInvalidAXNodeID;
      offset = AXNodePosition::INVALID_OFFSET;
      affinity = ax::mojom::TextAffinity::kDownstream;
      return false;
    case AXPositionKind::TREE_POSITION:
      node_id = position->anchor_id();
      offset = position->child_index();
      affinity = ax::mojom::TextAffinity::kDownstream;
      return true;
    case AXPositionKind::TEXT_POSITION:
      node_id = position->anchor_id();
      offset = position->text_offset();
      affinity = position->affinity();
      return true;
  }
}

}  // namespace

AXSelection::AXSelection() = default;
AXSelection::AXSelection(const AXSelection&) = default;

AXSelection::~AXSelection() = default;

AXSelection::AXSelection(const AXTree& tree)
    : is_backward(tree.data().sel_is_backward),
      anchor_object_id(tree.data().sel_anchor_object_id),
      anchor_offset(tree.data().sel_anchor_offset),
      anchor_affinity(tree.data().sel_anchor_affinity),
      focus_object_id(tree.data().sel_focus_object_id),
      focus_offset(tree.data().sel_focus_offset),
      focus_affinity(tree.data().sel_focus_affinity),
      tree_id_(tree.GetAXTreeID()) {}

AXSelection& AXSelection::ToUnignoredSelection() {
  // If the tree is not registered with an AXTreeManager, it
  // is a initial tree with no data, do not calculate selection.
  const AXTreeManager* manager = AXTreeManager::FromID(tree_id_);
  if (!manager)
    return *this;

  // If one of the selection endpoints is invalid, then the other endpoint
  // should also be unset.
  if (!ComputeUnignoredSelectionEndpoint(
          manager->ax_tree(),
          is_backward ? AXPositionAdjustmentBehavior::kMoveForward
                      : AXPositionAdjustmentBehavior::kMoveBackward,
          anchor_object_id, anchor_offset, anchor_affinity)) {
    focus_object_id = kInvalidAXNodeID;
    focus_offset = AXNodePosition::INVALID_OFFSET;
    focus_affinity = ax::mojom::TextAffinity::kDownstream;
  } else if (!ComputeUnignoredSelectionEndpoint(
                 manager->ax_tree(),
                 is_backward ? AXPositionAdjustmentBehavior::kMoveBackward
                             : AXPositionAdjustmentBehavior::kMoveForward,
                 focus_object_id, focus_offset, focus_affinity)) {
    anchor_object_id = kInvalidAXNodeID;
    anchor_offset = AXNodePosition::INVALID_OFFSET;
    anchor_affinity = ax::mojom::TextAffinity::kDownstream;
  }
  return *this;
}

}  // namespace ui