| OLD | NEW |
| 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2017 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 "content/browser/accessibility/browser_accessibility_com_win.h" | 5 #include "content/browser/accessibility/browser_accessibility_com_win.h" |
| 6 | 6 |
| 7 #include <UIAutomationClient.h> | 7 #include <UIAutomationClient.h> |
| 8 #include <UIAutomationCoreApi.h> | 8 #include <UIAutomationCoreApi.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 #include "ui/base/win/accessibility_misc_utils.h" | 32 #include "ui/base/win/accessibility_misc_utils.h" |
| 33 #include "ui/base/win/atl_module.h" | 33 #include "ui/base/win/atl_module.h" |
| 34 | 34 |
| 35 // There is no easy way to decouple |kScreenReader| and |kHTML| accessibility | 35 // There is no easy way to decouple |kScreenReader| and |kHTML| accessibility |
| 36 // modes when Windows screen readers are used. For example, certain roles use | 36 // modes when Windows screen readers are used. For example, certain roles use |
| 37 // the HTML tag name. Input fields require their type attribute to be exposed. | 37 // the HTML tag name. Input fields require their type attribute to be exposed. |
| 38 const uint32_t kScreenReaderAndHTMLAccessibilityModes = | 38 const uint32_t kScreenReaderAndHTMLAccessibilityModes = |
| 39 content::AccessibilityMode::kScreenReader | | 39 content::AccessibilityMode::kScreenReader | |
| 40 content::AccessibilityMode::kHTML; | 40 content::AccessibilityMode::kHTML; |
| 41 | 41 |
| 42 const WCHAR* const IA2_RELATION_DETAILS = L"details"; | |
| 43 const WCHAR* const IA2_RELATION_DETAILS_FOR = L"detailsFor"; | |
| 44 const WCHAR* const IA2_RELATION_ERROR_MESSAGE = L"errorMessage"; | |
| 45 | |
| 46 namespace content { | 42 namespace content { |
| 47 | 43 |
| 48 using AXPlatformPositionInstance = AXPlatformPosition::AXPositionInstance; | 44 using AXPlatformPositionInstance = AXPlatformPosition::AXPositionInstance; |
| 49 using AXPlatformRange = ui::AXRange<AXPlatformPositionInstance::element_type>; | 45 using AXPlatformRange = ui::AXRange<AXPlatformPositionInstance::element_type>; |
| 50 | 46 |
| 51 // These nonstandard GUIDs are taken directly from the Mozilla sources | 47 // These nonstandard GUIDs are taken directly from the Mozilla sources |
| 52 // (accessible/src/msaa/nsAccessNodeWrap.cpp); some documentation is here: | 48 // (accessible/src/msaa/nsAccessNodeWrap.cpp); some documentation is here: |
| 53 // http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/
MSAA | 49 // http://developer.mozilla.org/en/Accessibility/AT-APIs/ImplementationFeatures/
MSAA |
| 54 const GUID GUID_ISimpleDOM = {0x0c539790, | 50 const GUID GUID_ISimpleDOM = {0x0c539790, |
| 55 0x12e4, | 51 0x12e4, |
| 56 0x11cf, | 52 0x11cf, |
| 57 {0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8}}; | 53 {0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8}}; |
| 58 const GUID GUID_IAccessibleContentDocument = { | 54 const GUID GUID_IAccessibleContentDocument = { |
| 59 0xa5d8e1f3, | 55 0xa5d8e1f3, |
| 60 0x3571, | 56 0x3571, |
| 61 0x4d8f, | 57 0x4d8f, |
| 62 {0x95, 0x21, 0x07, 0xed, 0x28, 0xfb, 0x07, 0x2e}}; | 58 {0x95, 0x21, 0x07, 0xed, 0x28, 0xfb, 0x07, 0x2e}}; |
| 63 | 59 |
| 64 const base::char16 BrowserAccessibilityComWin::kEmbeddedCharacter = L'\xfffc'; | 60 const base::char16 BrowserAccessibilityComWin::kEmbeddedCharacter = L'\xfffc'; |
| 65 | 61 |
| 66 void AddAccessibilityModeFlags(AccessibilityMode mode_flags) { | 62 void AddAccessibilityModeFlags(AccessibilityMode mode_flags) { |
| 67 BrowserAccessibilityStateImpl::GetInstance()->AddAccessibilityModeFlags( | 63 BrowserAccessibilityStateImpl::GetInstance()->AddAccessibilityModeFlags( |
| 68 mode_flags); | 64 mode_flags); |
| 69 } | 65 } |
| 70 | 66 |
| 71 // | 67 // |
| 72 // BrowserAccessibilityRelation | |
| 73 // | |
| 74 // A simple implementation of IAccessibleRelation, used to represent | |
| 75 // a relationship between two accessible nodes in the tree. | |
| 76 // | |
| 77 | |
| 78 class BrowserAccessibilityRelation | |
| 79 : public CComObjectRootEx<CComMultiThreadModel>, | |
| 80 public IAccessibleRelation { | |
| 81 BEGIN_COM_MAP(BrowserAccessibilityRelation) | |
| 82 COM_INTERFACE_ENTRY(IAccessibleRelation) | |
| 83 END_COM_MAP() | |
| 84 | |
| 85 CONTENT_EXPORT BrowserAccessibilityRelation() {} | |
| 86 CONTENT_EXPORT virtual ~BrowserAccessibilityRelation() {} | |
| 87 | |
| 88 CONTENT_EXPORT void Initialize(BrowserAccessibilityComWin* owner, | |
| 89 const base::string16& type); | |
| 90 CONTENT_EXPORT void AddTarget(int target_id); | |
| 91 CONTENT_EXPORT void RemoveTarget(int target_id); | |
| 92 | |
| 93 // Accessors. | |
| 94 const base::string16& get_type() const { return type_; } | |
| 95 const std::vector<int>& get_target_ids() const { return target_ids_; } | |
| 96 | |
| 97 // IAccessibleRelation methods. | |
| 98 CONTENT_EXPORT STDMETHODIMP get_relationType(BSTR* relation_type) override; | |
| 99 CONTENT_EXPORT STDMETHODIMP get_nTargets(long* n_targets) override; | |
| 100 CONTENT_EXPORT STDMETHODIMP get_target(long target_index, | |
| 101 IUnknown** target) override; | |
| 102 CONTENT_EXPORT STDMETHODIMP get_targets(long max_targets, | |
| 103 IUnknown** targets, | |
| 104 long* n_targets) override; | |
| 105 | |
| 106 // IAccessibleRelation methods not implemented. | |
| 107 CONTENT_EXPORT STDMETHODIMP | |
| 108 get_localizedRelationType(BSTR* relation_type) override { | |
| 109 return E_NOTIMPL; | |
| 110 } | |
| 111 | |
| 112 private: | |
| 113 base::string16 type_; | |
| 114 base::win::ScopedComPtr<BrowserAccessibilityComWin> owner_; | |
| 115 std::vector<int> target_ids_; | |
| 116 }; | |
| 117 | |
| 118 void BrowserAccessibilityRelation::Initialize(BrowserAccessibilityComWin* owner, | |
| 119 const base::string16& type) { | |
| 120 owner_ = owner; | |
| 121 type_ = type; | |
| 122 } | |
| 123 | |
| 124 void BrowserAccessibilityRelation::AddTarget(int target_id) { | |
| 125 target_ids_.push_back(target_id); | |
| 126 } | |
| 127 | |
| 128 void BrowserAccessibilityRelation::RemoveTarget(int target_id) { | |
| 129 target_ids_.erase( | |
| 130 std::remove(target_ids_.begin(), target_ids_.end(), target_id), | |
| 131 target_ids_.end()); | |
| 132 } | |
| 133 | |
| 134 STDMETHODIMP BrowserAccessibilityRelation::get_relationType( | |
| 135 BSTR* relation_type) { | |
| 136 if (!relation_type) | |
| 137 return E_INVALIDARG; | |
| 138 | |
| 139 if (!owner_->owner()) | |
| 140 return E_FAIL; | |
| 141 | |
| 142 *relation_type = SysAllocString(type_.c_str()); | |
| 143 DCHECK(*relation_type); | |
| 144 return S_OK; | |
| 145 } | |
| 146 | |
| 147 STDMETHODIMP BrowserAccessibilityRelation::get_nTargets(long* n_targets) { | |
| 148 if (!n_targets) | |
| 149 return E_INVALIDARG; | |
| 150 | |
| 151 if (!owner_->owner()) | |
| 152 return E_FAIL; | |
| 153 | |
| 154 *n_targets = static_cast<long>(target_ids_.size()); | |
| 155 | |
| 156 for (long i = *n_targets - 1; i >= 0; --i) { | |
| 157 BrowserAccessibilityComWin* result = owner_->GetFromID(target_ids_[i]); | |
| 158 if (!result || !result->owner()) { | |
| 159 *n_targets = 0; | |
| 160 break; | |
| 161 } | |
| 162 } | |
| 163 return S_OK; | |
| 164 } | |
| 165 | |
| 166 STDMETHODIMP BrowserAccessibilityRelation::get_target(long target_index, | |
| 167 IUnknown** target) { | |
| 168 if (!target) | |
| 169 return E_INVALIDARG; | |
| 170 | |
| 171 if (!owner_->owner()) | |
| 172 return E_FAIL; | |
| 173 | |
| 174 auto* manager = owner_->Manager(); | |
| 175 if (!manager) | |
| 176 return E_FAIL; | |
| 177 | |
| 178 if (target_index < 0 || | |
| 179 target_index >= static_cast<long>(target_ids_.size())) { | |
| 180 return E_INVALIDARG; | |
| 181 } | |
| 182 | |
| 183 BrowserAccessibility* result = manager->GetFromID(target_ids_[target_index]); | |
| 184 if (!result || !result->instance_active()) | |
| 185 return E_FAIL; | |
| 186 | |
| 187 *target = static_cast<IAccessible*>( | |
| 188 ToBrowserAccessibilityComWin(result)->NewReference()); | |
| 189 return S_OK; | |
| 190 } | |
| 191 | |
| 192 STDMETHODIMP BrowserAccessibilityRelation::get_targets(long max_targets, | |
| 193 IUnknown** targets, | |
| 194 long* n_targets) { | |
| 195 if (!targets || !n_targets) | |
| 196 return E_INVALIDARG; | |
| 197 | |
| 198 if (!owner_->owner()) | |
| 199 return E_FAIL; | |
| 200 | |
| 201 long count = static_cast<long>(target_ids_.size()); | |
| 202 if (count > max_targets) | |
| 203 count = max_targets; | |
| 204 | |
| 205 *n_targets = count; | |
| 206 if (count == 0) | |
| 207 return S_FALSE; | |
| 208 | |
| 209 for (long i = 0; i < count; ++i) { | |
| 210 HRESULT result = get_target(i, &targets[i]); | |
| 211 if (result != S_OK) | |
| 212 return result; | |
| 213 } | |
| 214 | |
| 215 return S_OK; | |
| 216 } | |
| 217 | |
| 218 // | |
| 219 // BrowserAccessibilityComWin::WinAttributes | 68 // BrowserAccessibilityComWin::WinAttributes |
| 220 // | 69 // |
| 221 | 70 |
| 222 BrowserAccessibilityComWin::WinAttributes::WinAttributes() | 71 BrowserAccessibilityComWin::WinAttributes::WinAttributes() |
| 223 : ia_role(0), ia_state(0), ia2_role(0), ia2_state(0) {} | 72 : ia_role(0), ia_state(0), ia2_role(0), ia2_state(0) {} |
| 224 | 73 |
| 225 BrowserAccessibilityComWin::WinAttributes::~WinAttributes() {} | 74 BrowserAccessibilityComWin::WinAttributes::~WinAttributes() {} |
| 226 | 75 |
| 227 // | 76 // |
| 228 // BrowserAccessibilityComWin | 77 // BrowserAccessibilityComWin |
| 229 // | 78 // |
| 230 BrowserAccessibilityComWin::BrowserAccessibilityComWin() | 79 BrowserAccessibilityComWin::BrowserAccessibilityComWin() |
| 231 : owner_(nullptr), | 80 : owner_(nullptr), |
| 232 win_attributes_(new WinAttributes()), | 81 win_attributes_(new WinAttributes()), |
| 233 previous_scroll_x_(0), | 82 previous_scroll_x_(0), |
| 234 previous_scroll_y_(0) {} | 83 previous_scroll_y_(0) {} |
| 235 | 84 |
| 236 BrowserAccessibilityComWin::~BrowserAccessibilityComWin() { | 85 BrowserAccessibilityComWin::~BrowserAccessibilityComWin() { |
| 237 for (BrowserAccessibilityRelation* relation : relations_) | |
| 238 relation->Release(); | |
| 239 } | 86 } |
| 240 | 87 |
| 241 // | 88 // |
| 242 // IAccessible overrides: | 89 // IAccessible overrides: |
| 243 // | 90 // |
| 244 | 91 |
| 245 STDMETHODIMP BrowserAccessibilityComWin::get_accDefaultAction( | 92 STDMETHODIMP BrowserAccessibilityComWin::get_accDefaultAction( |
| 246 VARIANT var_id, | 93 VARIANT var_id, |
| 247 BSTR* def_action) { | 94 BSTR* def_action) { |
| 248 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); | 95 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 if (!index_in_parent) | 166 if (!index_in_parent) |
| 320 return E_INVALIDARG; | 167 return E_INVALIDARG; |
| 321 | 168 |
| 322 *index_in_parent = GetIndexInParent(); | 169 *index_in_parent = GetIndexInParent(); |
| 323 return S_OK; | 170 return S_OK; |
| 324 } | 171 } |
| 325 | 172 |
| 326 STDMETHODIMP BrowserAccessibilityComWin::get_nRelations(LONG* n_relations) { | 173 STDMETHODIMP BrowserAccessibilityComWin::get_nRelations(LONG* n_relations) { |
| 327 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_N_RELATIONS); | 174 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_N_RELATIONS); |
| 328 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); | 175 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); |
| 329 if (!owner()) | 176 return AXPlatformNodeWin::get_nRelations(n_relations); |
| 330 return E_FAIL; | |
| 331 | |
| 332 if (!n_relations) | |
| 333 return E_INVALIDARG; | |
| 334 | |
| 335 *n_relations = relations_.size(); | |
| 336 return S_OK; | |
| 337 } | 177 } |
| 338 | 178 |
| 339 STDMETHODIMP BrowserAccessibilityComWin::get_relation( | 179 STDMETHODIMP BrowserAccessibilityComWin::get_relation( |
| 340 LONG relation_index, | 180 LONG relation_index, |
| 341 IAccessibleRelation** relation) { | 181 IAccessibleRelation** relation) { |
| 342 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_RELATION); | 182 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_RELATION); |
| 343 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); | 183 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); |
| 344 if (!owner()) | 184 return AXPlatformNodeWin::get_relation(relation_index, relation); |
| 345 return E_FAIL; | |
| 346 | |
| 347 if (relation_index < 0 || | |
| 348 relation_index >= static_cast<long>(relations_.size())) { | |
| 349 return E_INVALIDARG; | |
| 350 } | |
| 351 | |
| 352 if (!relation) | |
| 353 return E_INVALIDARG; | |
| 354 | |
| 355 relations_[relation_index]->AddRef(); | |
| 356 *relation = relations_[relation_index]; | |
| 357 return S_OK; | |
| 358 } | 185 } |
| 359 | 186 |
| 360 STDMETHODIMP BrowserAccessibilityComWin::get_relations( | 187 STDMETHODIMP BrowserAccessibilityComWin::get_relations( |
| 361 LONG max_relations, | 188 LONG max_relations, |
| 362 IAccessibleRelation** relations, | 189 IAccessibleRelation** relations, |
| 363 LONG* n_relations) { | 190 LONG* n_relations) { |
| 364 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_RELATIONS); | 191 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_GET_RELATIONS); |
| 365 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); | 192 AddAccessibilityModeFlags(kScreenReaderAndHTMLAccessibilityModes); |
| 366 if (!owner()) | 193 return AXPlatformNodeWin::get_relations(max_relations, relations, |
| 367 return E_FAIL; | 194 n_relations); |
| 368 | |
| 369 if (!relations || !n_relations) | |
| 370 return E_INVALIDARG; | |
| 371 | |
| 372 long count = static_cast<long>(relations_.size()); | |
| 373 *n_relations = count; | |
| 374 if (count == 0) | |
| 375 return S_FALSE; | |
| 376 | |
| 377 for (long i = 0; i < count; ++i) { | |
| 378 relations_[i]->AddRef(); | |
| 379 relations[i] = relations_[i]; | |
| 380 } | |
| 381 | |
| 382 return S_OK; | |
| 383 } | 195 } |
| 384 | 196 |
| 385 STDMETHODIMP BrowserAccessibilityComWin::scrollTo(IA2ScrollType scroll_type) { | 197 STDMETHODIMP BrowserAccessibilityComWin::scrollTo(IA2ScrollType scroll_type) { |
| 386 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_IA2_SCROLL_TO); | 198 WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_IA2_SCROLL_TO); |
| 387 if (!owner()) | 199 if (!owner()) |
| 388 return E_FAIL; | 200 return E_FAIL; |
| 389 | 201 |
| 390 auto* manager = Manager(); | 202 auto* manager = Manager(); |
| 391 | 203 |
| 392 if (!manager) | 204 if (!manager) |
| (...skipping 2240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2633 value = base::UTF8ToUTF16(Manager()->GetTreeData().url); | 2445 value = base::UTF8ToUTF16(Manager()->GetTreeData().url); |
| 2634 } | 2446 } |
| 2635 // If this doesn't have a value and is linked then set its value to the url | 2447 // If this doesn't have a value and is linked then set its value to the url |
| 2636 // attribute. This allows screen readers to read an empty link's | 2448 // attribute. This allows screen readers to read an empty link's |
| 2637 // destination. | 2449 // destination. |
| 2638 if (value.empty() && (MSAAState() & STATE_SYSTEM_LINKED)) | 2450 if (value.empty() && (MSAAState() & STATE_SYSTEM_LINKED)) |
| 2639 value = owner()->GetString16Attribute(ui::AX_ATTR_URL); | 2451 value = owner()->GetString16Attribute(ui::AX_ATTR_URL); |
| 2640 | 2452 |
| 2641 win_attributes_->value = value; | 2453 win_attributes_->value = value; |
| 2642 | 2454 |
| 2643 ClearOwnRelations(); | 2455 CalculateRelationships(); |
| 2644 AddBidirectionalRelations(IA2_RELATION_CONTROLLER_FOR, | |
| 2645 IA2_RELATION_CONTROLLED_BY, | |
| 2646 ui::AX_ATTR_CONTROLS_IDS); | |
| 2647 AddBidirectionalRelations(IA2_RELATION_DESCRIBED_BY, | |
| 2648 IA2_RELATION_DESCRIPTION_FOR, | |
| 2649 ui::AX_ATTR_DESCRIBEDBY_IDS); | |
| 2650 AddBidirectionalRelations(IA2_RELATION_FLOWS_TO, IA2_RELATION_FLOWS_FROM, | |
| 2651 ui::AX_ATTR_FLOWTO_IDS); | |
| 2652 AddBidirectionalRelations(IA2_RELATION_LABELLED_BY, IA2_RELATION_LABEL_FOR, | |
| 2653 ui::AX_ATTR_LABELLEDBY_IDS); | |
| 2654 | |
| 2655 int32_t details_id; | |
| 2656 if (GetIntAttribute(ui::AX_ATTR_DETAILS_ID, &details_id)) { | |
| 2657 std::vector<int32_t> details_ids; | |
| 2658 details_ids.push_back(details_id); | |
| 2659 AddBidirectionalRelations(IA2_RELATION_DETAILS, IA2_RELATION_DETAILS_FOR, | |
| 2660 details_ids); | |
| 2661 } | |
| 2662 | |
| 2663 int member_of_id; | |
| 2664 if (owner()->GetIntAttribute(ui::AX_ATTR_MEMBER_OF_ID, &member_of_id)) | |
| 2665 AddRelation(IA2_RELATION_MEMBER_OF, member_of_id); | |
| 2666 | |
| 2667 int error_message_id; | |
| 2668 if (owner()->GetIntAttribute(ui::AX_ATTR_ERRORMESSAGE_ID, &error_message_id)) | |
| 2669 AddRelation(IA2_RELATION_ERROR_MESSAGE, error_message_id); | |
| 2670 } | 2456 } |
| 2671 | 2457 |
| 2672 void BrowserAccessibilityComWin::UpdateStep2ComputeHypertext() { | 2458 void BrowserAccessibilityComWin::UpdateStep2ComputeHypertext() { |
| 2673 if (owner()->IsSimpleTextControl()) { | 2459 if (owner()->IsSimpleTextControl()) { |
| 2674 win_attributes_->hypertext = value(); | 2460 win_attributes_->hypertext = value(); |
| 2675 return; | 2461 return; |
| 2676 } | 2462 } |
| 2677 | 2463 |
| 2678 if (!owner()->PlatformChildCount()) { | 2464 if (!owner()->PlatformChildCount()) { |
| 2679 if (owner()->IsRichTextControl()) { | 2465 if (owner()->IsRichTextControl()) { |
| (...skipping 911 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3591 } | 3377 } |
| 3592 | 3378 |
| 3593 if (role == ui::AX_ROLE_MENU_LIST_OPTION && | 3379 if (role == ui::AX_ROLE_MENU_LIST_OPTION && |
| 3594 parent_role == ui::AX_ROLE_MENU_LIST_POPUP) { | 3380 parent_role == ui::AX_ROLE_MENU_LIST_POPUP) { |
| 3595 return true; | 3381 return true; |
| 3596 } | 3382 } |
| 3597 | 3383 |
| 3598 return false; | 3384 return false; |
| 3599 } | 3385 } |
| 3600 | 3386 |
| 3601 void BrowserAccessibilityComWin::AddRelation( | |
| 3602 const base::string16& relation_type, | |
| 3603 int target_id) { | |
| 3604 // Reflexive relations don't need to be exposed through IA2. | |
| 3605 if (target_id == owner()->GetId()) | |
| 3606 return; | |
| 3607 | |
| 3608 CComObject<BrowserAccessibilityRelation>* relation; | |
| 3609 HRESULT hr = | |
| 3610 CComObject<BrowserAccessibilityRelation>::CreateInstance(&relation); | |
| 3611 DCHECK(SUCCEEDED(hr)); | |
| 3612 relation->AddRef(); | |
| 3613 relation->Initialize(this, relation_type); | |
| 3614 relation->AddTarget(target_id); | |
| 3615 relations_.push_back(relation); | |
| 3616 } | |
| 3617 | |
| 3618 void BrowserAccessibilityComWin::AddBidirectionalRelations( | |
| 3619 const base::string16& relation_type, | |
| 3620 const base::string16& reverse_relation_type, | |
| 3621 ui::AXIntListAttribute attribute) { | |
| 3622 if (!owner()->HasIntListAttribute(attribute)) | |
| 3623 return; | |
| 3624 | |
| 3625 const std::vector<int32_t>& target_ids = | |
| 3626 owner()->GetIntListAttribute(attribute); | |
| 3627 AddBidirectionalRelations(relation_type, reverse_relation_type, target_ids); | |
| 3628 } | |
| 3629 | |
| 3630 void BrowserAccessibilityComWin::AddBidirectionalRelations( | |
| 3631 const base::string16& relation_type, | |
| 3632 const base::string16& reverse_relation_type, | |
| 3633 const std::vector<int32_t>& target_ids) { | |
| 3634 // Reflexive relations don't need to be exposed through IA2. | |
| 3635 std::vector<int32_t> filtered_target_ids; | |
| 3636 int32_t current_id = owner()->GetId(); | |
| 3637 std::copy_if(target_ids.begin(), target_ids.end(), | |
| 3638 std::back_inserter(filtered_target_ids), | |
| 3639 [current_id](int32_t id) { return id != current_id; }); | |
| 3640 if (filtered_target_ids.empty()) | |
| 3641 return; | |
| 3642 | |
| 3643 CComObject<BrowserAccessibilityRelation>* relation; | |
| 3644 HRESULT hr = | |
| 3645 CComObject<BrowserAccessibilityRelation>::CreateInstance(&relation); | |
| 3646 DCHECK(SUCCEEDED(hr)); | |
| 3647 relation->AddRef(); | |
| 3648 relation->Initialize(this, relation_type); | |
| 3649 | |
| 3650 for (int target_id : filtered_target_ids) { | |
| 3651 BrowserAccessibilityComWin* target = | |
| 3652 GetFromID(static_cast<int32_t>(target_id)); | |
| 3653 if (!target || !target->owner()) | |
| 3654 continue; | |
| 3655 relation->AddTarget(target_id); | |
| 3656 target->AddRelation(reverse_relation_type, owner()->GetId()); | |
| 3657 } | |
| 3658 | |
| 3659 relations_.push_back(relation); | |
| 3660 } | |
| 3661 | |
| 3662 // Clears all the forward relations from this object to any other object and the | |
| 3663 // associated reverse relations on the other objects, but leaves any reverse | |
| 3664 // relations on this object alone. | |
| 3665 void BrowserAccessibilityComWin::ClearOwnRelations() { | |
| 3666 RemoveBidirectionalRelationsOfType(IA2_RELATION_CONTROLLER_FOR, | |
| 3667 IA2_RELATION_CONTROLLED_BY); | |
| 3668 RemoveBidirectionalRelationsOfType(IA2_RELATION_DESCRIBED_BY, | |
| 3669 IA2_RELATION_DESCRIPTION_FOR); | |
| 3670 RemoveBidirectionalRelationsOfType(IA2_RELATION_FLOWS_TO, | |
| 3671 IA2_RELATION_FLOWS_FROM); | |
| 3672 RemoveBidirectionalRelationsOfType(IA2_RELATION_LABELLED_BY, | |
| 3673 IA2_RELATION_LABEL_FOR); | |
| 3674 | |
| 3675 relations_.erase( | |
| 3676 std::remove_if(relations_.begin(), relations_.end(), | |
| 3677 [](BrowserAccessibilityRelation* relation) { | |
| 3678 if (relation->get_type() == IA2_RELATION_MEMBER_OF) { | |
| 3679 relation->Release(); | |
| 3680 return true; | |
| 3681 } | |
| 3682 return false; | |
| 3683 }), | |
| 3684 relations_.end()); | |
| 3685 } | |
| 3686 | |
| 3687 void BrowserAccessibilityComWin::RemoveBidirectionalRelationsOfType( | |
| 3688 const base::string16& relation_type, | |
| 3689 const base::string16& reverse_relation_type) { | |
| 3690 for (auto iter = relations_.begin(); iter != relations_.end();) { | |
| 3691 BrowserAccessibilityRelation* relation = *iter; | |
| 3692 DCHECK(relation); | |
| 3693 if (relation->get_type() == relation_type) { | |
| 3694 for (int target_id : relation->get_target_ids()) { | |
| 3695 BrowserAccessibilityComWin* target = | |
| 3696 GetFromID(static_cast<int32_t>(target_id)); | |
| 3697 if (!target || !target->owner()) | |
| 3698 continue; | |
| 3699 DCHECK_NE(target, this); | |
| 3700 target->RemoveTargetFromRelation(reverse_relation_type, | |
| 3701 owner()->GetId()); | |
| 3702 } | |
| 3703 iter = relations_.erase(iter); | |
| 3704 relation->Release(); | |
| 3705 } else { | |
| 3706 ++iter; | |
| 3707 } | |
| 3708 } | |
| 3709 } | |
| 3710 | |
| 3711 void BrowserAccessibilityComWin::RemoveTargetFromRelation( | |
| 3712 const base::string16& relation_type, | |
| 3713 int target_id) { | |
| 3714 for (auto iter = relations_.begin(); iter != relations_.end();) { | |
| 3715 BrowserAccessibilityRelation* relation = *iter; | |
| 3716 DCHECK(relation); | |
| 3717 if (relation->get_type() == relation_type) { | |
| 3718 // If |target_id| is not present, |RemoveTarget| will do nothing. | |
| 3719 relation->RemoveTarget(target_id); | |
| 3720 } | |
| 3721 if (relation->get_target_ids().empty()) { | |
| 3722 iter = relations_.erase(iter); | |
| 3723 relation->Release(); | |
| 3724 } else { | |
| 3725 ++iter; | |
| 3726 } | |
| 3727 } | |
| 3728 } | |
| 3729 | |
| 3730 void BrowserAccessibilityComWin::FireNativeEvent(LONG win_event_type) const { | 3387 void BrowserAccessibilityComWin::FireNativeEvent(LONG win_event_type) const { |
| 3731 (new BrowserAccessibilityEventWin(BrowserAccessibilityEvent::FromTreeChange, | 3388 (new BrowserAccessibilityEventWin(BrowserAccessibilityEvent::FromTreeChange, |
| 3732 ui::AX_EVENT_NONE, win_event_type, owner())) | 3389 ui::AX_EVENT_NONE, win_event_type, owner())) |
| 3733 ->Fire(); | 3390 ->Fire(); |
| 3734 } | 3391 } |
| 3735 | 3392 |
| 3736 BrowserAccessibilityComWin* ToBrowserAccessibilityComWin( | 3393 BrowserAccessibilityComWin* ToBrowserAccessibilityComWin( |
| 3737 BrowserAccessibility* obj) { | 3394 BrowserAccessibility* obj) { |
| 3738 if (!obj || !obj->IsNative()) | 3395 if (!obj || !obj->IsNative()) |
| 3739 return nullptr; | 3396 return nullptr; |
| 3740 auto* result = static_cast<BrowserAccessibilityWin*>(obj)->GetCOM(); | 3397 auto* result = static_cast<BrowserAccessibilityWin*>(obj)->GetCOM(); |
| 3741 return result; | 3398 return result; |
| 3742 } | 3399 } |
| 3743 | 3400 |
| 3744 } // namespace content | 3401 } // namespace content |
| OLD | NEW |