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 |