OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |