blob: f676fb4c781fa85b93d0f20cdc4ea5cde6c92314 [file] [log] [blame]
Avi Drissman3e1a26c2022-09-15 20:26:031// Copyright 2016 The Chromium Authors
nektar9de71d42016-10-21 21:57:002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/accessibility/ax_node_position.h"
6
Benjamin Beaudry0a4cf91d2020-01-06 23:57:047#include "build/build_config.h"
Dominic Mazzonidcef1b732018-01-26 17:57:048#include "ui/accessibility/ax_enums.mojom.h"
Nektarios Paisios88d7a912021-02-03 16:45:289#include "ui/base/buildflags.h"
nektar9de71d42016-10-21 21:57:0010
11namespace ui {
12
Nektarios Paisios88d7a912021-02-03 16:45:2813// On some platforms, most objects are represented in the text of their parents
14// with a special "embedded object character" and not with their actual text
15// contents. Also on the same platforms, if a node has only ignored descendants,
16// i.e., it appears to be empty to assistive software, we need to treat it as a
17// character and a word boundary.
Benjamin Beaudry0a4cf91d2020-01-06 23:57:0418AXEmbeddedObjectBehavior g_ax_embedded_object_behavior =
Xiaohan Wangaa4b1a3b2022-01-20 21:32:1919#if BUILDFLAG(IS_WIN) || BUILDFLAG(USE_ATK)
Benjamin Beaudry0a4cf91d2020-01-06 23:57:0420 AXEmbeddedObjectBehavior::kExposeCharacter;
21#else
22 AXEmbeddedObjectBehavior::kSuppressCharacter;
Xiaohan Wangaa4b1a3b2022-01-20 21:32:1923#endif // BUILDFLAG(IS_WIN) || BUILDFLAG(USE_ATK)
Benjamin Beaudry0a4cf91d2020-01-06 23:57:0424
David Bienvenub10c69e2021-05-11 22:52:1125ScopedAXEmbeddedObjectBehaviorSetter::ScopedAXEmbeddedObjectBehaviorSetter(
26 AXEmbeddedObjectBehavior behavior) {
27 prev_behavior_ = g_ax_embedded_object_behavior;
28 g_ax_embedded_object_behavior = behavior;
29}
30
31ScopedAXEmbeddedObjectBehaviorSetter::~ScopedAXEmbeddedObjectBehaviorSetter() {
32 g_ax_embedded_object_behavior = prev_behavior_;
33}
34
Nektarios Paisiosaaa44982022-02-03 08:58:1935std::string ToString(const AXPositionKind kind) {
36 static constexpr auto kKindToString =
37 base::MakeFixedFlatMap<AXPositionKind, const char*>(
38 {{AXPositionKind::NULL_POSITION, "NullPosition"},
39 {AXPositionKind::TREE_POSITION, "TreePosition"},
40 {AXPositionKind::TEXT_POSITION, "TextPosition"}});
41
42 const auto* iter = kKindToString.find(kind);
43 if (iter == std::end(kKindToString))
44 return std::string();
45 return iter->second;
46}
47
Nektarios Paisiosd88553dd2019-12-10 02:25:0048// static
49AXNodePosition::AXPositionInstance AXNodePosition::CreatePosition(
50 const AXNode& node,
51 int child_index_or_text_offset,
52 ax::mojom::TextAffinity affinity) {
53 if (!node.tree())
54 return CreateNullPosition();
55
56 AXTreeID tree_id = node.tree()->GetAXTreeID();
Aaron Leventhal496a51b2022-09-30 16:17:4557 if (IsTextPositionAnchor(node)) {
58 // TODO(accessibility) It is a mistake for the to caller try to create a
59 // text position with BEFORE_TEXT as the text offset. Correct the callers
60 // that are doing this.
61 // DCHECK_NE(child_index_or_text_offset, BEFORE_TEXT)
62 // << "Creating a text position with BEFORE_TEXT as the offset is illegal "
63 // "and disallowed.";
64 int text_offset = child_index_or_text_offset == BEFORE_TEXT
65 ? 0
66 : child_index_or_text_offset;
Alexander Surkov22737692022-10-21 18:16:3067 return CreateTextPosition(node, text_offset, affinity);
Nektarios Paisios993145d42020-05-29 13:55:2868 }
Nektarios Paisiosd88553dd2019-12-10 02:25:0069
Aaron Leventhal496a51b2022-09-30 16:17:4570 DCHECK_LE(child_index_or_text_offset,
71 static_cast<int>(node.GetChildCountCrossingTreeBoundary()))
72 << "\n* Trying to create a tree position with a child index that is too "
73 "large. Maybe a text position should have been created instead?\n"
74 << "\n* Anchor node: " << node << "\n* IsLeaf(): " << node.IsLeaf()
75 << "\n* Child offset: " << child_index_or_text_offset
76 << "\n* IsLeafNodeForTreePosition(): " << IsLeafNodeForTreePosition(node)
77 << "\n* Tree: " << node.tree()->ToString();
78
Alexander Surkov29889c7f2022-10-21 11:35:3579 return CreateTreePosition(node, child_index_or_text_offset);
Nektarios Paisiosd88553dd2019-12-10 02:25:0080}
81
Aaron Leventhal496a51b2022-09-30 16:17:4582// static
83bool AXNodePosition::IsTextPositionAnchor(const AXNode& node) {
84 // TODO(accessibility) Simplify. Not actually sure if this is the correct
85 // thing for the case where IsLeaf() == false but IsLeafNodeForTreePosition()
86 // is true.
87 if (node.IsLeaf())
88 return true;
89
90 // TODO(accessibility) Try to remove this condition. Text positions for a
91 // selection operation should only be created inside selectable text.
92 // A list marker for example is not selectable text: it would either be
93 // selected as a whole or not selected, and you can't select half of it.
94 if (IsLeafNodeForTreePosition(node))
95 return true;
96
97 if (node.GetRole() == ax::mojom::Role::kSpinButton) {
98 // TODO(benjamin.beaudry) Please look into whether this code needs to
99 // remain, or can be simplified.
100 return true;
101 }
102
103 // Ignored atomic text fields and spin buttons are not considered leaves by
104 // AXNode::IsLeaf(), but should always use a text position.
105 if (node.data().IsAtomicTextField()) {
106 // Ignored atomic text fields and spin buttons are not considered leaves by
107 // AXNode::IsLeaf(), but should always use a text position.
108 // TODO(accessibility) Nobody should be creating a text position on an
109 // ignored text field.
110 DCHECK(node.IsIgnored()) << "Returned false from IsLeaf(): " << node;
111 return true;
112 }
113
114 return false;
115}
116
Nektarios Paisios376c84c42019-11-02 09:56:02117AXNodePosition::AXNodePosition() = default;
nektar9de71d42016-10-21 21:57:00118
Nektarios Paisios376c84c42019-11-02 09:56:02119AXNodePosition::~AXNodePosition() = default;
120
121AXNodePosition::AXNodePosition(const AXNodePosition& other)
122 : AXPosition<AXNodePosition, AXNode>(other) {}
nektar9de71d42016-10-21 21:57:00123
nektar491c6732016-12-14 00:14:30124AXNodePosition::AXPositionInstance AXNodePosition::Clone() const {
125 return AXPositionInstance(new AXNodePosition(*this));
126}
127
nektar9de71d42016-10-21 21:57:00128} // namespace ui