Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(400)

Side by Side Diff: ui/accessibility/platform/ax_platform_node_win.cc

Issue 2981073002: Move BrowserAccessibilityRelation code to the ui/accessibility/ (Closed)
Patch Set: Force tests to calculate relationships. Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <atlbase.h> 5 #include <atlbase.h>
6 #include <atlcom.h> 6 #include <atlcom.h>
7 #include <limits.h> 7 #include <limits.h>
8 #include <oleacc.h> 8 #include <oleacc.h>
9 #include <stdint.h> 9 #include <stdint.h>
10 10
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 if (!arg3) \ 128 if (!arg3) \
129 return E_INVALIDARG; \ 129 return E_INVALIDARG; \
130 if (!arg4) \ 130 if (!arg4) \
131 return E_INVALIDARG; \ 131 return E_INVALIDARG; \
132 target = GetTargetFromChildID(var_id); \ 132 target = GetTargetFromChildID(var_id); \
133 if (!target) \ 133 if (!target) \
134 return E_INVALIDARG; \ 134 return E_INVALIDARG; \
135 if (!target->delegate_) \ 135 if (!target->delegate_) \
136 return E_INVALIDARG; 136 return E_INVALIDARG;
137 137
138 const WCHAR* const IA2_RELATION_DETAILS = L"details";
139 const WCHAR* const IA2_RELATION_DETAILS_FOR = L"detailsFor";
140 const WCHAR* const IA2_RELATION_ERROR_MESSAGE = L"errorMessage";
141
138 namespace ui { 142 namespace ui {
139 143
140 namespace { 144 namespace {
141 145
142 typedef base::hash_set<AXPlatformNodeWin*> AXPlatformNodeWinSet; 146 typedef base::hash_set<AXPlatformNodeWin*> AXPlatformNodeWinSet;
143 // Set of all AXPlatformNodeWin objects that were the target of an 147 // Set of all AXPlatformNodeWin objects that were the target of an
144 // alert event. 148 // alert event.
145 base::LazyInstance<AXPlatformNodeWinSet>::DestructorAtExit g_alert_targets = 149 base::LazyInstance<AXPlatformNodeWinSet>::DestructorAtExit g_alert_targets =
146 LAZY_INSTANCE_INITIALIZER; 150 LAZY_INSTANCE_INITIALIZER;
147 151
(...skipping 12 matching lines...) Expand all
160 164
161 IAccessible2UsageObserver::~IAccessible2UsageObserver() { 165 IAccessible2UsageObserver::~IAccessible2UsageObserver() {
162 } 166 }
163 167
164 // static 168 // static
165 base::ObserverList<IAccessible2UsageObserver>& 169 base::ObserverList<IAccessible2UsageObserver>&
166 GetIAccessible2UsageObserverList() { 170 GetIAccessible2UsageObserverList() {
167 return g_iaccessible2_usage_observer_list.Get(); 171 return g_iaccessible2_usage_observer_list.Get();
168 } 172 }
169 173
174 AXPlatformNodeRelationWin::AXPlatformNodeRelationWin() {
175 ui::win::CreateATLModuleIfNeeded();
176 }
177
178 AXPlatformNodeRelationWin::~AXPlatformNodeRelationWin() {}
179
180 void AXPlatformNodeRelationWin::Initialize(AXPlatformNodeWin* owner,
181 const base::string16& type) {
182 owner_ = owner;
183 type_ = type;
184 }
185
186 void AXPlatformNodeRelationWin::AddTarget(int target_id) {
187 target_ids_.push_back(target_id);
188 }
189
190 void AXPlatformNodeRelationWin::RemoveTarget(int target_id) {
191 target_ids_.erase(
192 std::remove(target_ids_.begin(), target_ids_.end(), target_id),
193 target_ids_.end());
194 }
195
196 STDMETHODIMP AXPlatformNodeRelationWin::get_relationType(BSTR* relation_type) {
197 if (!relation_type)
198 return E_INVALIDARG;
199
200 if (!owner_->delegate_)
201 return E_FAIL;
202
203 *relation_type = SysAllocString(type_.c_str());
204 DCHECK(*relation_type);
205 return S_OK;
206 }
207
208 STDMETHODIMP AXPlatformNodeRelationWin::get_nTargets(long* n_targets) {
209 if (!n_targets)
210 return E_INVALIDARG;
211
212 if (!owner_->delegate_)
213 return E_FAIL;
214
215 *n_targets = static_cast<long>(target_ids_.size());
216
217 for (long i = *n_targets - 1; i >= 0; --i) {
218 AXPlatformNodeWin* result = static_cast<AXPlatformNodeWin*>(
219 owner_->delegate_->GetFromNodeID(target_ids_[i]));
220 if (!result || !result->delegate_) {
221 *n_targets = 0;
222 break;
223 }
224 }
225 return S_OK;
226 }
227
228 STDMETHODIMP AXPlatformNodeRelationWin::get_target(long target_index,
229 IUnknown** target) {
230 if (!target)
231 return E_INVALIDARG;
232
233 if (!owner_->delegate_)
234 return E_FAIL;
235
236 if (target_index < 0 ||
237 target_index >= static_cast<long>(target_ids_.size())) {
238 return E_INVALIDARG;
239 }
240
241 AXPlatformNodeWin* result = static_cast<AXPlatformNodeWin*>(
242 owner_->delegate_->GetFromNodeID(target_ids_[target_index]));
243 if (!result || !result->delegate_)
244 return E_FAIL;
245
246 result->AddRef();
247 *target = static_cast<IAccessible*>(result);
248 return S_OK;
249 }
250
251 STDMETHODIMP AXPlatformNodeRelationWin::get_targets(long max_targets,
252 IUnknown** targets,
253 long* n_targets) {
254 if (!targets || !n_targets)
255 return E_INVALIDARG;
256
257 if (!owner_->delegate_)
258 return E_FAIL;
259
260 long count = static_cast<long>(target_ids_.size());
261 if (count > max_targets)
262 count = max_targets;
263
264 *n_targets = count;
265 if (count == 0)
266 return S_FALSE;
267
268 for (long i = 0; i < count; ++i) {
269 HRESULT result = get_target(i, &targets[i]);
270 if (result != S_OK)
271 return result;
272 }
273
274 return S_OK;
275 }
276
277 STDMETHODIMP
278 AXPlatformNodeRelationWin::get_localizedRelationType(BSTR* relation_type) {
279 return E_NOTIMPL;
280 }
281
170 // 282 //
171 // AXPlatformNode::Create 283 // AXPlatformNode::Create
172 // 284 //
173 285
174 // static 286 // static
175 AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) { 287 AXPlatformNode* AXPlatformNode::Create(AXPlatformNodeDelegate* delegate) {
176 // Make sure ATL is initialized in this module. 288 // Make sure ATL is initialized in this module.
177 ui::win::CreateATLModuleIfNeeded(); 289 ui::win::CreateATLModuleIfNeeded();
178 290
179 CComObject<AXPlatformNodeWin>* instance = nullptr; 291 CComObject<AXPlatformNodeWin>* instance = nullptr;
(...skipping 15 matching lines...) Expand all
195 } 307 }
196 308
197 // 309 //
198 // AXPlatformNodeWin 310 // AXPlatformNodeWin
199 // 311 //
200 312
201 AXPlatformNodeWin::AXPlatformNodeWin() { 313 AXPlatformNodeWin::AXPlatformNodeWin() {
202 } 314 }
203 315
204 AXPlatformNodeWin::~AXPlatformNodeWin() { 316 AXPlatformNodeWin::~AXPlatformNodeWin() {
317 for (ui::AXPlatformNodeRelationWin* relation : relations_)
318 relation->Release();
319 }
320
321 void AXPlatformNodeWin::CalculateRelationships() {
322 ClearOwnRelations();
323 AddBidirectionalRelations(IA2_RELATION_CONTROLLER_FOR,
324 IA2_RELATION_CONTROLLED_BY,
325 ui::AX_ATTR_CONTROLS_IDS);
326 AddBidirectionalRelations(IA2_RELATION_DESCRIBED_BY,
327 IA2_RELATION_DESCRIPTION_FOR,
328 ui::AX_ATTR_DESCRIBEDBY_IDS);
329 AddBidirectionalRelations(IA2_RELATION_FLOWS_TO, IA2_RELATION_FLOWS_FROM,
330 ui::AX_ATTR_FLOWTO_IDS);
331 AddBidirectionalRelations(IA2_RELATION_LABELLED_BY, IA2_RELATION_LABEL_FOR,
332 ui::AX_ATTR_LABELLEDBY_IDS);
333
334 int32_t details_id;
335 if (GetIntAttribute(ui::AX_ATTR_DETAILS_ID, &details_id)) {
336 std::vector<int32_t> details_ids;
337 details_ids.push_back(details_id);
338 AddBidirectionalRelations(IA2_RELATION_DETAILS, IA2_RELATION_DETAILS_FOR,
339 details_ids);
340 }
341
342 int member_of_id;
343 if (GetIntAttribute(ui::AX_ATTR_MEMBER_OF_ID, &member_of_id))
344 AddRelation(IA2_RELATION_MEMBER_OF, member_of_id);
345
346 int error_message_id;
347 if (GetIntAttribute(ui::AX_ATTR_ERRORMESSAGE_ID, &error_message_id))
348 AddRelation(IA2_RELATION_ERROR_MESSAGE, error_message_id);
349 }
350
351 void AXPlatformNodeWin::AddRelation(const base::string16& relation_type,
352 int target_id) {
353 // Reflexive relations don't need to be exposed through IA2.
354 if (target_id == GetData().id)
355 return;
356
357 CComObject<ui::AXPlatformNodeRelationWin>* relation;
358 HRESULT hr =
359 CComObject<ui::AXPlatformNodeRelationWin>::CreateInstance(&relation);
360 DCHECK(SUCCEEDED(hr));
361 relation->AddRef();
362 relation->Initialize(this, relation_type);
363 relation->AddTarget(target_id);
364 relations_.push_back(relation);
365 }
366
367 void AXPlatformNodeWin::AddBidirectionalRelations(
368 const base::string16& relation_type,
369 const base::string16& reverse_relation_type,
370 ui::AXIntListAttribute attribute) {
371 if (!HasIntListAttribute(attribute))
372 return;
373
374 const std::vector<int32_t>& target_ids = GetIntListAttribute(attribute);
375 AddBidirectionalRelations(relation_type, reverse_relation_type, target_ids);
376 }
377
378 void AXPlatformNodeWin::AddBidirectionalRelations(
379 const base::string16& relation_type,
380 const base::string16& reverse_relation_type,
381 const std::vector<int32_t>& target_ids) {
382 // Reflexive relations don't need to be exposed through IA2.
383 std::vector<int32_t> filtered_target_ids;
384 int32_t current_id = GetData().id;
385 std::copy_if(target_ids.begin(), target_ids.end(),
386 std::back_inserter(filtered_target_ids),
387 [current_id](int32_t id) { return id != current_id; });
388 if (filtered_target_ids.empty())
389 return;
390
391 CComObject<ui::AXPlatformNodeRelationWin>* relation;
392 HRESULT hr =
393 CComObject<ui::AXPlatformNodeRelationWin>::CreateInstance(&relation);
394 DCHECK(SUCCEEDED(hr));
395 relation->AddRef();
396 relation->Initialize(this, relation_type);
397
398 for (int target_id : filtered_target_ids) {
399 AXPlatformNodeWin* target = static_cast<AXPlatformNodeWin*>(
400 delegate_->GetFromNodeID(static_cast<int32_t>(target_id)));
401
402 if (!target)
403 continue;
404 relation->AddTarget(target_id);
405 target->AddRelation(reverse_relation_type, GetData().id);
406 }
407
408 relations_.push_back(relation);
409 }
410
411 // Clears all the forward relations from this object to any other object and the
412 // associated reverse relations on the other objects, but leaves any reverse
413 // relations on this object alone.
414 void AXPlatformNodeWin::ClearOwnRelations() {
415 RemoveBidirectionalRelationsOfType(IA2_RELATION_CONTROLLER_FOR,
416 IA2_RELATION_CONTROLLED_BY);
417 RemoveBidirectionalRelationsOfType(IA2_RELATION_DESCRIBED_BY,
418 IA2_RELATION_DESCRIPTION_FOR);
419 RemoveBidirectionalRelationsOfType(IA2_RELATION_FLOWS_TO,
420 IA2_RELATION_FLOWS_FROM);
421 RemoveBidirectionalRelationsOfType(IA2_RELATION_LABELLED_BY,
422 IA2_RELATION_LABEL_FOR);
423
424 relations_.erase(
425 std::remove_if(relations_.begin(), relations_.end(),
426 [](ui::AXPlatformNodeRelationWin* relation) {
427 if (relation->get_type() == IA2_RELATION_MEMBER_OF) {
428 relation->Release();
429 return true;
430 }
431 return false;
432 }),
433 relations_.end());
434 }
435
436 void AXPlatformNodeWin::RemoveBidirectionalRelationsOfType(
437 const base::string16& relation_type,
438 const base::string16& reverse_relation_type) {
439 for (auto iter = relations_.begin(); iter != relations_.end();) {
440 ui::AXPlatformNodeRelationWin* relation = *iter;
441 DCHECK(relation);
442 if (relation->get_type() == relation_type) {
443 for (int target_id : relation->get_target_ids()) {
444 AXPlatformNodeWin* target = static_cast<AXPlatformNodeWin*>(
445 delegate_->GetFromNodeID(static_cast<int32_t>(target_id)));
446 if (!target)
447 continue;
448 DCHECK_NE(target, this);
449 target->RemoveTargetFromRelation(reverse_relation_type, GetData().id);
450 }
451 iter = relations_.erase(iter);
452 relation->Release();
453 } else {
454 ++iter;
455 }
456 }
457 }
458
459 void AXPlatformNodeWin::RemoveTargetFromRelation(
460 const base::string16& relation_type,
461 int target_id) {
462 for (auto iter = relations_.begin(); iter != relations_.end();) {
463 ui::AXPlatformNodeRelationWin* relation = *iter;
464 DCHECK(relation);
465 if (relation->get_type() == relation_type) {
466 // If |target_id| is not present, |RemoveTarget| will do nothing.
467 relation->RemoveTarget(target_id);
468 }
469 if (relation->get_target_ids().empty()) {
470 iter = relations_.erase(iter);
471 relation->Release();
472 } else {
473 ++iter;
474 }
475 }
205 } 476 }
206 477
207 // Static 478 // Static
208 void AXPlatformNodeWin::SanitizeStringAttributeForIA2( 479 void AXPlatformNodeWin::SanitizeStringAttributeForIA2(
209 const base::string16& input, 480 const base::string16& input,
210 base::string16* output) { 481 base::string16* output) {
211 DCHECK(output); 482 DCHECK(output);
212 // According to the IA2 Spec, these characters need to be escaped with a 483 // According to the IA2 Spec, these characters need to be escaped with a
213 // backslash: backslash, colon, comma, equals and semicolon. 484 // backslash: backslash, colon, comma, equals and semicolon.
214 // Note that backslash must be replaced first. 485 // Note that backslash must be replaced first.
(...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after
964 1235
965 STDMETHODIMP AXPlatformNodeWin::get_indexInParent(LONG* index_in_parent) { 1236 STDMETHODIMP AXPlatformNodeWin::get_indexInParent(LONG* index_in_parent) {
966 COM_OBJECT_VALIDATE_1_ARG(index_in_parent); 1237 COM_OBJECT_VALIDATE_1_ARG(index_in_parent);
967 *index_in_parent = GetIndexInParent(); 1238 *index_in_parent = GetIndexInParent();
968 if (*index_in_parent < 0) 1239 if (*index_in_parent < 0)
969 return E_FAIL; 1240 return E_FAIL;
970 1241
971 return S_OK; 1242 return S_OK;
972 } 1243 }
973 1244
1245 STDMETHODIMP AXPlatformNodeWin::get_nRelations(LONG* n_relations) {
1246 COM_OBJECT_VALIDATE_1_ARG(n_relations);
1247 *n_relations = static_cast<LONG>(relations_.size());
1248 return S_OK;
1249 }
1250
1251 STDMETHODIMP AXPlatformNodeWin::get_relation(LONG relation_index,
1252 IAccessibleRelation** relation) {
1253 COM_OBJECT_VALIDATE_1_ARG(relation);
1254 if (relation_index < 0 ||
1255 relation_index >= static_cast<long>(relations_.size())) {
1256 return E_INVALIDARG;
1257 }
1258
1259 relations_[relation_index]->AddRef();
1260 *relation = relations_[relation_index];
1261 return S_OK;
1262 }
1263
1264 STDMETHODIMP AXPlatformNodeWin::get_relations(LONG max_relations,
1265 IAccessibleRelation** relations,
1266 LONG* n_relations) {
1267 COM_OBJECT_VALIDATE_2_ARGS(relations, n_relations);
1268 long count = static_cast<long>(relations_.size());
1269 *n_relations = count;
1270 if (count == 0)
1271 return S_FALSE;
1272
1273 for (long i = 0; i < count; ++i) {
1274 relations_[i]->AddRef();
1275 relations[i] = relations_[i];
1276 }
1277
1278 return S_OK;
1279 }
1280
974 // 1281 //
975 // IAccessible2 methods not implemented. 1282 // IAccessible2 methods not implemented.
976 // 1283 //
977 1284
978 STDMETHODIMP AXPlatformNodeWin::get_attribute(BSTR name, VARIANT* attribute) { 1285 STDMETHODIMP AXPlatformNodeWin::get_attribute(BSTR name, VARIANT* attribute) {
979 return E_NOTIMPL; 1286 return E_NOTIMPL;
980 } 1287 }
981
982 STDMETHODIMP AXPlatformNodeWin::get_extendedRole(BSTR* extended_role) { 1288 STDMETHODIMP AXPlatformNodeWin::get_extendedRole(BSTR* extended_role) {
983 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_EXTENDED_ROLE);
984 return E_NOTIMPL; 1289 return E_NOTIMPL;
985 } 1290 }
986 1291
987 STDMETHODIMP AXPlatformNodeWin::get_nRelations(LONG* n_relations) {
988 return E_NOTIMPL;
989 }
990
991 STDMETHODIMP AXPlatformNodeWin::get_relation(LONG relation_index,
992 IAccessibleRelation** relation) {
993 return E_NOTIMPL;
994 }
995
996 STDMETHODIMP AXPlatformNodeWin::get_relations(LONG max_relations,
997 IAccessibleRelation** relations,
998 LONG* n_relations) {
999 return E_NOTIMPL;
1000 }
1001
1002 STDMETHODIMP AXPlatformNodeWin::scrollTo(enum IA2ScrollType scroll_type) { 1292 STDMETHODIMP AXPlatformNodeWin::scrollTo(enum IA2ScrollType scroll_type) {
1003 return E_NOTIMPL; 1293 return E_NOTIMPL;
1004 } 1294 }
1005 1295
1006 STDMETHODIMP AXPlatformNodeWin::scrollToPoint( 1296 STDMETHODIMP AXPlatformNodeWin::scrollToPoint(
1007 enum IA2CoordinateType coordinate_type, 1297 enum IA2CoordinateType coordinate_type,
1008 LONG x, 1298 LONG x,
1009 LONG y) { 1299 LONG y) {
1010 return E_NOTIMPL; 1300 return E_NOTIMPL;
1011 } 1301 }
(...skipping 2066 matching lines...) Expand 10 before | Expand all | Expand 10 after
3078 if (container && container->GetData().role == ui::AX_ROLE_GROUP) 3368 if (container && container->GetData().role == ui::AX_ROLE_GROUP)
3079 container = FromNativeViewAccessible(container->GetParent()); 3369 container = FromNativeViewAccessible(container->GetParent());
3080 3370
3081 if (!container) 3371 if (!container)
3082 return false; 3372 return false;
3083 3373
3084 return container->GetData().role == ui::AX_ROLE_TREE_GRID; 3374 return container->GetData().role == ui::AX_ROLE_TREE_GRID;
3085 } 3375 }
3086 3376
3087 } // namespace ui 3377 } // namespace ui
OLDNEW
« no previous file with comments | « ui/accessibility/platform/ax_platform_node_win.h ('k') | ui/accessibility/platform/ax_platform_node_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698