File: ax_node_position.cc

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (127 lines) | stat: -rw-r--r-- 4,903 bytes parent folder | download
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
// Copyright 2016 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_node_position.h"

#include "build/build_config.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/base/buildflags.h"

namespace ui {

// On some platforms, most objects are represented in the text of their parents
// with a special "embedded object character" and not with their actual text
// contents. Also on the same platforms, if a node has only ignored descendants,
// i.e., it appears to be empty to assistive software, we need to treat it as a
// character and a word boundary.
AXEmbeddedObjectBehavior g_ax_embedded_object_behavior =
#if BUILDFLAG(IS_WIN) || BUILDFLAG(USE_ATK)
    AXEmbeddedObjectBehavior::kExposeCharacterForHypertext;
#else
    AXEmbeddedObjectBehavior::kSuppressCharacter;
#endif  // BUILDFLAG(IS_WIN) || BUILDFLAG(USE_ATK)

ScopedAXEmbeddedObjectBehaviorSetter::ScopedAXEmbeddedObjectBehaviorSetter(
    AXEmbeddedObjectBehavior behavior) {
  prev_behavior_ = g_ax_embedded_object_behavior;
  g_ax_embedded_object_behavior = behavior;
}

ScopedAXEmbeddedObjectBehaviorSetter::~ScopedAXEmbeddedObjectBehaviorSetter() {
  g_ax_embedded_object_behavior = prev_behavior_;
}

std::string ToString(const AXPositionKind kind) {
  static constexpr auto kKindToString =
      base::MakeFixedFlatMap<AXPositionKind, const char*>(
          {{AXPositionKind::NULL_POSITION, "NullPosition"},
           {AXPositionKind::TREE_POSITION, "TreePosition"},
           {AXPositionKind::TEXT_POSITION, "TextPosition"}});

  const auto* iter = kKindToString.find(kind);
  if (iter == std::end(kKindToString))
    return std::string();
  return iter->second;
}

// static
AXNodePosition::AXPositionInstance AXNodePosition::CreatePosition(
    const AXNode& node,
    int child_index_or_text_offset,
    ax::mojom::TextAffinity affinity) {
  if (!node.tree())
    return CreateNullPosition();

  if (IsTextPositionAnchor(node)) {
    // TODO(accessibility) It is a mistake for the to caller try to create a
    // text position with BEFORE_TEXT as the text offset. Correct the callers
    // that are doing this.
    // DCHECK_NE(child_index_or_text_offset, BEFORE_TEXT)
    // << "Creating a text position with BEFORE_TEXT as the offset is illegal "
    //    "and disallowed.";
    int text_offset = child_index_or_text_offset == BEFORE_TEXT
                          ? 0
                          : child_index_or_text_offset;
    return CreateTextPosition(node, text_offset, affinity);
  }

  DCHECK_LE(child_index_or_text_offset,
            static_cast<int>(node.GetChildCountCrossingTreeBoundary()))
      << "\n* Trying to create a tree position with a child index that is too "
         "large. Maybe a text position should have been created instead?\n"
      << "\n* Anchor node: " << node << "\n* IsLeaf(): " << node.IsLeaf()
      << "\n* Child offset: " << child_index_or_text_offset
      << "\n* IsLeafNodeForTreePosition(): " << IsLeafNodeForTreePosition(node)
      << "\n* Tree: " << node.tree()->ToString();

  return CreateTreePosition(node, child_index_or_text_offset);
}

// static
bool AXNodePosition::IsTextPositionAnchor(const AXNode& node) {
  // TODO(accessibility) Simplify. Not actually sure if this is the correct
  // thing for the case where IsLeaf() == false but IsLeafNodeForTreePosition()
  // is true.
  if (node.IsLeaf())
    return true;

  // TODO(accessibility) Try to remove this condition. Text positions for a
  // selection operation should only be created inside selectable text.
  // A list marker for example is not selectable text: it would either be
  // selected as a whole or not selected, and you can't select half of it.
  if (IsLeafNodeForTreePosition(node))
    return true;

  if (node.GetRole() == ax::mojom::Role::kSpinButton) {
    // TODO(benjamin.beaudry) Please look into whether this code needs to
    // remain, or can be simplified.
    return true;
  }

  // Ignored atomic text fields and spin buttons are not considered leaves by
  // AXNode::IsLeaf(), but should always use a text position.
  if (node.data().IsAtomicTextField()) {
    // Ignored atomic text fields and spin buttons are not considered leaves by
    // AXNode::IsLeaf(), but should always use a text position.
    // TODO(accessibility) Nobody should be creating a text position on an
    // ignored text field.
    DCHECK(node.IsIgnored()) << "Returned false from IsLeaf(): " << node;
    return true;
  }

  return false;
}

AXNodePosition::AXNodePosition() = default;

AXNodePosition::~AXNodePosition() = default;

AXNodePosition::AXNodePosition(const AXNodePosition& other)
    : AXPosition<AXNodePosition, AXNode>(other) {}

AXNodePosition::AXPositionInstance AXNodePosition::Clone() const {
  return AXPositionInstance(new AXNodePosition(*this));
}

}  // namespace ui