Flutter Engine
The Flutter Engine
ax_platform_relation_win.cc
Go to the documentation of this file.
1// Copyright 2017 The Chromium Authors. All rights reserved.
2// 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/platform/ax_platform_relation_win.h"
6
7#include <wrl/client.h>
8
9#include <algorithm>
10#include <vector>
11
12#include "base/lazy_instance.h"
13#include "base/strings/string_number_conversions.h"
14#include "base/strings/string_util.h"
15#include "base/strings/utf_string_conversions.h"
18#include "third_party/iaccessible2/ia2_api_all.h"
20#include "ui/accessibility/ax_action_data.h"
21#include "ui/accessibility/ax_mode_observer.h"
22#include "ui/accessibility/ax_node_data.h"
23#include "ui/accessibility/ax_role_properties.h"
24#include "ui/accessibility/ax_text_utils.h"
25#include "ui/accessibility/ax_tree_data.h"
26#include "ui/accessibility/platform/ax_platform_node_base.h"
27#include "ui/accessibility/platform/ax_platform_node_delegate.h"
28#include "ui/accessibility/platform/ax_unique_id.h"
29#include "ui/base/win/atl_module.h"
30#include "ui/gfx/geometry/rect_conversions.h"
31
32namespace ui {
33
36}
37
39
41 switch (attribute) {
43 return IA2_RELATION_MEMBER_OF;
45 return IA2_RELATION_ERROR;
47 // Map "popup for" to "controlled by".
48 // Unlike ATK there is no special IA2 popup-for relationship, but it can
49 // be exposed via the controlled by relation, which is also computed for
50 // content as the reverse of the controls relationship.
51 return IA2_RELATION_CONTROLLED_BY;
52 default:
53 break;
54 }
55 return base::string16();
56}
57
60 switch (attribute) {
62 return IA2_RELATION_CONTROLLER_FOR;
64 return IA2_RELATION_DESCRIBED_BY;
66 return IA2_RELATION_DETAILS;
68 return IA2_RELATION_FLOWS_TO;
70 return IA2_RELATION_LABELLED_BY;
71 default:
72 break;
73 }
74 return base::string16();
75}
76
78 ax::mojom::IntAttribute attribute) {
79 switch (attribute) {
81 return IA2_RELATION_ERROR_FOR;
82 default:
83 break;
84 }
85 return base::string16();
86}
87
90 switch (attribute) {
92 return IA2_RELATION_CONTROLLED_BY;
94 return IA2_RELATION_DESCRIPTION_FOR;
96 return IA2_RELATION_DETAILS_FOR;
98 return IA2_RELATION_FLOWS_FROM;
100 return IA2_RELATION_LABEL_FOR;
101 default:
102 break;
103 }
104 return base::string16();
105}
106
107// static
109 AXPlatformNodeBase* node,
110 int desired_index,
111 const base::string16& desired_ia2_relation,
112 base::string16* out_ia2_relation,
113 std::set<AXPlatformNode*>* out_targets) {
114 const AXNodeData& node_data = node->GetData();
115 AXPlatformNodeDelegate* delegate = node->GetDelegate();
116
117 // The first time this is called, populate vectors with all of the
118 // int attributes and intlist attributes that have reverse relations
119 // we care about on Windows. Computing these by calling
120 // GetIA2ReverseRelationFrom{Int|IntList}Attr on every possible attribute
121 // simplifies the work needed to support an additional relation
122 // attribute in the future.
123 static std::vector<ax::mojom::IntAttribute>
124 int_attributes_with_reverse_relations;
125 static std::vector<ax::mojom::IntListAttribute>
126 intlist_attributes_with_reverse_relations;
127 static bool first_time = true;
128 if (first_time) {
129 for (int32_t attr_index =
130 static_cast<int32_t>(ax::mojom::IntAttribute::kNone);
131 attr_index <= static_cast<int32_t>(ax::mojom::IntAttribute::kMaxValue);
132 ++attr_index) {
133 auto attr = static_cast<ax::mojom::IntAttribute>(attr_index);
134 if (!GetIA2ReverseRelationFromIntAttr(attr).empty())
135 int_attributes_with_reverse_relations.push_back(attr);
136 }
137 for (int32_t attr_index =
138 static_cast<int32_t>(ax::mojom::IntListAttribute::kNone);
139 attr_index <=
140 static_cast<int32_t>(ax::mojom::IntListAttribute::kMaxValue);
141 ++attr_index) {
142 auto attr = static_cast<ax::mojom::IntListAttribute>(attr_index);
143 if (!GetIA2ReverseRelationFromIntListAttr(attr).empty())
144 intlist_attributes_with_reverse_relations.push_back(attr);
145 }
146 first_time = false;
147 }
148
149 // Enumerate all of the relations and reverse relations that
150 // are exposed via IAccessible2 on Windows. We do this with a series
151 // of loops. Every time we encounter one, we check if the caller
152 // requested that particular relation by index, and return it.
153 // Otherwise we build up and return the total number of relations found.
154 int total_count = 0;
155
156 // Iterate over all int attributes on this node to check the ones
157 // that correspond to IAccessible2 relations.
158 for (size_t i = 0; i < node_data.int_attributes.size(); ++i) {
159 ax::mojom::IntAttribute int_attribute = node_data.int_attributes[i].first;
160 base::string16 relation = GetIA2RelationFromIntAttr(int_attribute);
161 if (!relation.empty() &&
162 (desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
163 // Skip reflexive relations
164 if (node_data.int_attributes[i].second == node_data.id)
165 continue;
166 if (desired_index == total_count) {
167 *out_ia2_relation = relation;
168 out_targets->insert(
169 delegate->GetFromNodeID(node_data.int_attributes[i].second));
170 return 1;
171 }
172 total_count++;
173 }
174 }
175
176 // Iterate over all of the int attributes that have reverse relations
177 // in IAccessible2, and query AXTree to see if the reverse relation exists.
178 for (ax::mojom::IntAttribute int_attribute :
179 int_attributes_with_reverse_relations) {
180 base::string16 relation = GetIA2ReverseRelationFromIntAttr(int_attribute);
181 std::set<AXPlatformNode*> targets =
182 delegate->GetReverseRelations(int_attribute);
183 // Erase reflexive relations.
184 targets.erase(node);
185 if (targets.size()) {
186 if (!relation.empty() &&
187 (desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
188 if (desired_index == total_count) {
189 *out_ia2_relation = relation;
190 *out_targets = targets;
191 return 1;
192 }
193 total_count++;
194 }
195 }
196 }
197
198 // Iterate over all intlist attributes on this node to check the ones
199 // that correspond to IAccessible2 relations.
200 for (size_t i = 0; i < node_data.intlist_attributes.size(); ++i) {
201 ax::mojom::IntListAttribute intlist_attribute =
202 node_data.intlist_attributes[i].first;
203 base::string16 relation = GetIA2RelationFromIntListAttr(intlist_attribute);
204 if (!relation.empty() &&
205 (desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
206 if (desired_index == total_count) {
207 *out_ia2_relation = relation;
208 for (int32_t target_id : node_data.intlist_attributes[i].second) {
209 // Skip reflexive relations
210 if (target_id == node_data.id)
211 continue;
212 out_targets->insert(delegate->GetFromNodeID(target_id));
213 }
214 if (out_targets->size() == 0)
215 continue;
216 return 1;
217 }
218 total_count++;
219 }
220 }
221
222 // Iterate over all of the intlist attributes that have reverse relations
223 // in IAccessible2, and query AXTree to see if the reverse relation exists.
224 for (ax::mojom::IntListAttribute intlist_attribute :
225 intlist_attributes_with_reverse_relations) {
226 base::string16 relation =
227 GetIA2ReverseRelationFromIntListAttr(intlist_attribute);
228 std::set<AXPlatformNode*> targets =
229 delegate->GetReverseRelations(intlist_attribute);
230 // Erase reflexive relations.
231 targets.erase(node);
232 if (targets.size()) {
233 if (!relation.empty() &&
234 (desired_ia2_relation.empty() || desired_ia2_relation == relation)) {
235 if (desired_index == total_count) {
236 *out_ia2_relation = relation;
237 *out_targets = targets;
238 return 1;
239 }
240 total_count++;
241 }
242 }
243 }
244
245 return total_count;
246}
247
248void AXPlatformRelationWin::Initialize(const base::string16& type) {
249 type_ = type;
250}
251
253 targets_.clear();
254}
255
256void AXPlatformRelationWin::AddTarget(AXPlatformNodeWin* target) {
257 targets_.push_back(target);
258}
259
260IFACEMETHODIMP AXPlatformRelationWin::get_relationType(BSTR* relation_type) {
261 if (!relation_type)
262 return E_INVALIDARG;
263
264 *relation_type = SysAllocString(type_.c_str());
265 DCHECK(*relation_type);
266 return S_OK;
267}
268
269IFACEMETHODIMP AXPlatformRelationWin::get_nTargets(LONG* n_targets) {
270 if (!n_targets)
271 return E_INVALIDARG;
272
273 *n_targets = static_cast<LONG>(targets_.size());
274 return S_OK;
275}
276
277IFACEMETHODIMP AXPlatformRelationWin::get_target(LONG target_index,
278 IUnknown** target) {
279 if (!target)
280 return E_INVALIDARG;
281
282 if (target_index < 0 || target_index >= static_cast<LONG>(targets_.size())) {
283 return E_INVALIDARG;
284 }
285
286 *target = static_cast<IAccessible*>(targets_[target_index].Get());
287 (*target)->AddRef();
288 return S_OK;
289}
290
291IFACEMETHODIMP AXPlatformRelationWin::get_targets(LONG max_targets,
292 IUnknown** targets,
293 LONG* n_targets) {
294 if (!targets || !n_targets)
295 return E_INVALIDARG;
296
297 LONG count = static_cast<LONG>(targets_.size());
298 if (count > max_targets)
299 count = max_targets;
300
301 *n_targets = count;
302 if (count == 0)
303 return S_FALSE;
304
305 for (LONG i = 0; i < count; ++i) {
306 HRESULT result = get_target(i, &targets[i]);
307 if (result != S_OK)
308 return result;
309 }
310
311 return S_OK;
312}
313
314IFACEMETHODIMP
316 return E_NOTIMPL;
317}
318
319} // namespace ui
int count
Definition: FontMgrTest.cpp:50
GLenum type
AXPlatformNodeDelegate * GetDelegate() const override
const AXNodeData & GetData() const
virtual AXPlatformNode * GetFromNodeID(int32_t id)=0
virtual std::set< AXPlatformNode * > GetReverseRelations(ax::mojom::IntAttribute attr)=0
IFACEMETHODIMP get_relationType(BSTR *relation_type) override
IFACEMETHODIMP get_localizedRelationType(BSTR *relation_type) override
IFACEMETHODIMP get_target(LONG target_index, IUnknown **target) override
void Initialize(const base::string16 &type)
IFACEMETHODIMP get_nTargets(LONG *n_targets) override
static int EnumerateRelationships(AXPlatformNodeBase *node, int desired_index, const base::string16 &desired_ia2_relation, base::string16 *out_ia2_relation, std::set< AXPlatformNode * > *out_targets)
void AddTarget(AXPlatformNodeWin *target)
IFACEMETHODIMP get_targets(LONG max_targets, IUnknown **targets, LONG *n_targets) override
GAsyncResult * result
uint32_t * target
IntListAttribute
Definition: ax_enums.h:799
void CreateATLModuleIfNeeded()
Definition: atl_module.h:22
base::string16 GetIA2ReverseRelationFromIntAttr(ax::mojom::IntAttribute attribute)
base::string16 GetIA2RelationFromIntAttr(ax::mojom::IntAttribute attribute)
base::string16 GetIA2RelationFromIntListAttr(ax::mojom::IntListAttribute attribute)
base::string16 GetIA2ReverseRelationFromIntListAttr(ax::mojom::IntListAttribute attribute)
std::vector< std::pair< ax::mojom::IntAttribute, int32_t > > int_attributes
Definition: ax_node_data.h:282
std::vector< std::pair< ax::mojom::IntListAttribute, std::vector< int32_t > > > intlist_attributes
Definition: ax_node_data.h:286
long LONG
Definition: windows_types.h:23