OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ui/views/accessibility/native_view_accessibility_win.h" | 5 #include "ui/views/accessibility/native_view_accessibility_win.h" |
6 | 6 |
7 #include <UIAutomationClient.h> | 7 #include <UIAutomationClient.h> |
8 #include <oleacc.h> | 8 #include <oleacc.h> |
9 | 9 |
10 #include <set> | 10 #include <set> |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "base/memory/singleton.h" | 13 #include "base/memory/singleton.h" |
| 14 #include "base/strings/utf_string_conversions.h" |
14 #include "base/win/windows_version.h" | 15 #include "base/win/windows_version.h" |
15 #include "third_party/iaccessible2/ia2_api_all.h" | 16 #include "third_party/iaccessible2/ia2_api_all.h" |
16 #include "ui/base/accessibility/accessible_text_utils.h" | 17 #include "ui/base/accessibility/accessible_text_utils.h" |
17 #include "ui/base/accessibility/accessible_view_state.h" | 18 #include "ui/base/accessibility/accessible_view_state.h" |
18 #include "ui/base/win/accessibility_ids_win.h" | 19 #include "ui/base/win/accessibility_ids_win.h" |
19 #include "ui/base/win/accessibility_misc_utils.h" | 20 #include "ui/base/win/accessibility_misc_utils.h" |
20 #include "ui/base/win/atl_module.h" | 21 #include "ui/base/win/atl_module.h" |
21 #include "ui/views/controls/button/custom_button.h" | 22 #include "ui/views/controls/button/custom_button.h" |
22 #include "ui/views/focus/focus_manager.h" | 23 #include "ui/views/focus/focus_manager.h" |
23 #include "ui/views/focus/view_storage.h" | 24 #include "ui/views/focus/view_storage.h" |
24 #include "ui/views/win/hwnd_util.h" | 25 #include "ui/views/win/hwnd_util.h" |
25 | 26 |
26 using ui::AccessibilityTypes; | 27 using ui::AccessibilityTypes; |
27 | 28 |
28 namespace views { | 29 namespace views { |
29 namespace { | 30 namespace { |
30 | 31 |
31 class AccessibleWebViewRegistry { | 32 class AccessibleWebViewRegistry { |
32 public: | 33 public: |
33 static AccessibleWebViewRegistry* GetInstance(); | 34 static AccessibleWebViewRegistry* GetInstance(); |
34 | 35 |
35 void RegisterWebView(AccessibleWebView* web_view); | 36 void RegisterWebView(View* web_view); |
36 | 37 |
37 void UnregisterWebView(AccessibleWebView* web_view); | 38 void UnregisterWebView(View* web_view); |
38 | 39 |
39 // Given the view that received the request for the accessible | 40 // Given the view that received the request for the accessible |
40 // id in |top_view|, and the child id requested, return the native | 41 // id in |top_view|, and the child id requested, return the native |
41 // accessible object with that child id from one of the WebViews in | 42 // accessible object with that child id from one of the WebViews in |
42 // |top_view|'s view hierarchy, if any. | 43 // |top_view|'s view hierarchy, if any. |
43 IAccessible* GetAccessibleFromWebView(View* top_view, long child_id); | 44 IAccessible* GetAccessibleFromWebView(View* top_view, long child_id); |
44 | 45 |
45 private: | 46 private: |
46 friend struct DefaultSingletonTraits<AccessibleWebViewRegistry>; | 47 friend struct DefaultSingletonTraits<AccessibleWebViewRegistry>; |
47 AccessibleWebViewRegistry(); | 48 AccessibleWebViewRegistry(); |
48 ~AccessibleWebViewRegistry() {} | 49 ~AccessibleWebViewRegistry() {} |
49 | 50 |
| 51 IAccessible* AccessibleObjectFromChildId(View* web_view, long child_id); |
| 52 |
50 // Set of all web views. We check whether each one is contained in a | 53 // Set of all web views. We check whether each one is contained in a |
51 // top view dynamically rather than keeping track of a map. | 54 // top view dynamically rather than keeping track of a map. |
52 std::set<AccessibleWebView*> web_views_; | 55 std::set<View*> web_views_; |
53 | 56 |
54 // The most recent top view used in a call to GetAccessibleFromWebView. | 57 // The most recent top view used in a call to GetAccessibleFromWebView. |
55 View* last_top_view_; | 58 View* last_top_view_; |
56 | 59 |
57 // The most recent web view where an accessible object was found, | 60 // The most recent web view where an accessible object was found, |
58 // corresponding to |last_top_view_|. | 61 // corresponding to |last_top_view_|. |
59 AccessibleWebView* last_web_view_; | 62 View* last_web_view_; |
60 | 63 |
61 DISALLOW_COPY_AND_ASSIGN(AccessibleWebViewRegistry); | 64 DISALLOW_COPY_AND_ASSIGN(AccessibleWebViewRegistry); |
62 }; | 65 }; |
63 | 66 |
64 AccessibleWebViewRegistry::AccessibleWebViewRegistry() | 67 AccessibleWebViewRegistry::AccessibleWebViewRegistry() |
65 : last_top_view_(NULL), | 68 : last_top_view_(NULL), |
66 last_web_view_(NULL) { | 69 last_web_view_(NULL) { |
67 } | 70 } |
68 | 71 |
69 AccessibleWebViewRegistry* AccessibleWebViewRegistry::GetInstance() { | 72 AccessibleWebViewRegistry* AccessibleWebViewRegistry::GetInstance() { |
70 return Singleton<AccessibleWebViewRegistry>::get(); | 73 return Singleton<AccessibleWebViewRegistry>::get(); |
71 } | 74 } |
72 | 75 |
73 void AccessibleWebViewRegistry::RegisterWebView(AccessibleWebView* web_view) { | 76 void AccessibleWebViewRegistry::RegisterWebView(View* web_view) { |
74 DCHECK(web_views_.find(web_view) == web_views_.end()); | 77 DCHECK(web_views_.find(web_view) == web_views_.end()); |
75 web_views_.insert(web_view); | 78 web_views_.insert(web_view); |
76 } | 79 } |
77 | 80 |
78 void AccessibleWebViewRegistry::UnregisterWebView(AccessibleWebView* web_view) { | 81 void AccessibleWebViewRegistry::UnregisterWebView(View* web_view) { |
79 DCHECK(web_views_.find(web_view) != web_views_.end()); | 82 DCHECK(web_views_.find(web_view) != web_views_.end()); |
80 web_views_.erase(web_view); | 83 web_views_.erase(web_view); |
81 if (last_web_view_ == web_view) { | 84 if (last_web_view_ == web_view) { |
82 last_top_view_ = NULL; | 85 last_top_view_ = NULL; |
83 last_web_view_ = NULL; | 86 last_web_view_ = NULL; |
84 } | 87 } |
85 } | 88 } |
86 | 89 |
87 IAccessible* AccessibleWebViewRegistry::GetAccessibleFromWebView( | 90 IAccessible* AccessibleWebViewRegistry::GetAccessibleFromWebView( |
88 View* top_view, long child_id) { | 91 View* top_view, long child_id) { |
89 // This function gets called frequently, so try to avoid searching all | 92 // This function gets called frequently, so try to avoid searching all |
90 // of the web views if the notification is on the same web view that | 93 // of the web views if the notification is on the same web view that |
91 // sent the last one. | 94 // sent the last one. |
92 if (last_top_view_ == top_view) { | 95 if (last_top_view_ == top_view) { |
93 IAccessible* accessible = | 96 IAccessible* accessible = |
94 last_web_view_->AccessibleObjectFromChildId(child_id); | 97 AccessibleObjectFromChildId(last_web_view_, child_id); |
95 if (accessible) | 98 if (accessible) |
96 return accessible; | 99 return accessible; |
97 } | 100 } |
98 | 101 |
99 // Search all web views. For each one, first ensure it's a descendant | 102 // Search all web views. For each one, first ensure it's a descendant |
100 // of this view where the event was posted - and if so, see if it owns | 103 // of this view where the event was posted - and if so, see if it owns |
101 // an accessible object with that child id. If so, save the view to speed | 104 // an accessible object with that child id. If so, save the view to speed |
102 // up the next notification. | 105 // up the next notification. |
103 for (std::set<AccessibleWebView*>::iterator iter = web_views_.begin(); | 106 for (std::set<View*>::iterator iter = web_views_.begin(); |
104 iter != web_views_.end(); ++iter) { | 107 iter != web_views_.end(); ++iter) { |
105 AccessibleWebView* web_view = *iter; | 108 View* web_view = *iter; |
106 if (!top_view->Contains(web_view->AsView())) | 109 if (!top_view->Contains(web_view)) |
107 continue; | 110 continue; |
108 IAccessible* accessible = web_view->AccessibleObjectFromChildId(child_id); | 111 IAccessible* accessible = AccessibleObjectFromChildId(web_view, child_id); |
109 if (accessible) { | 112 if (accessible) { |
110 last_top_view_ = top_view; | 113 last_top_view_ = top_view; |
111 last_web_view_ = web_view; | 114 last_web_view_ = web_view; |
112 return accessible; | 115 return accessible; |
113 } | 116 } |
114 } | 117 } |
| 118 |
115 return NULL; | 119 return NULL; |
116 } | 120 } |
117 | 121 |
| 122 IAccessible* AccessibleWebViewRegistry::AccessibleObjectFromChildId( |
| 123 View* web_view, |
| 124 long child_id) { |
| 125 IAccessible* web_view_accessible = web_view->GetNativeViewAccessible(); |
| 126 if (web_view_accessible == NULL) |
| 127 return NULL; |
| 128 |
| 129 VARIANT var_child; |
| 130 var_child.vt = VT_I4; |
| 131 var_child.lVal = child_id; |
| 132 IAccessible* result = NULL; |
| 133 if (S_OK == web_view_accessible->get_accChild( |
| 134 var_child, reinterpret_cast<IDispatch**>(&result))) { |
| 135 return result; |
| 136 } |
| 137 |
| 138 return NULL; |
| 139 } |
| 140 |
118 } // anonymous namespace | 141 } // anonymous namespace |
119 | 142 |
120 // static | 143 // static |
121 long NativeViewAccessibilityWin::next_unique_id_ = 1; | 144 long NativeViewAccessibilityWin::next_unique_id_ = 1; |
122 int NativeViewAccessibilityWin::view_storage_ids_[kMaxViewStorageIds] = {0}; | 145 int NativeViewAccessibilityWin::view_storage_ids_[kMaxViewStorageIds] = {0}; |
123 int NativeViewAccessibilityWin::next_view_storage_id_index_ = 0; | 146 int NativeViewAccessibilityWin::next_view_storage_id_index_ = 0; |
124 | 147 |
125 // static | 148 // static |
126 NativeViewAccessibility* NativeViewAccessibility::Create(View* view) { | 149 NativeViewAccessibility* NativeViewAccessibility::Create(View* view) { |
127 // Make sure ATL is initialized in this module. | 150 // Make sure ATL is initialized in this module. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 | 195 |
173 gfx::NativeViewAccessible NativeViewAccessibilityWin::GetNativeObject() { | 196 gfx::NativeViewAccessible NativeViewAccessibilityWin::GetNativeObject() { |
174 return this; | 197 return this; |
175 } | 198 } |
176 | 199 |
177 void NativeViewAccessibilityWin::Destroy() { | 200 void NativeViewAccessibilityWin::Destroy() { |
178 view_ = NULL; | 201 view_ = NULL; |
179 Release(); | 202 Release(); |
180 } | 203 } |
181 | 204 |
182 // TODO(ctguil): Handle case where child View is not contained by parent. | |
183 STDMETHODIMP NativeViewAccessibilityWin::accHitTest( | 205 STDMETHODIMP NativeViewAccessibilityWin::accHitTest( |
184 LONG x_left, LONG y_top, VARIANT* child) { | 206 LONG x_left, LONG y_top, VARIANT* child) { |
185 if (!child) | 207 if (!child) |
186 return E_INVALIDARG; | 208 return E_INVALIDARG; |
187 | 209 |
188 if (!view_) | 210 if (!view_) |
189 return E_FAIL; | 211 return E_FAIL; |
190 | 212 |
191 gfx::Point point(x_left, y_top); | 213 gfx::Point point(x_left, y_top); |
192 View::ConvertPointToTarget(NULL, view_, &point); | 214 View::ConvertPointToTarget(NULL, view_, &point); |
193 | 215 |
| 216 // If the point is not inside this view, return false. |
194 if (!view_->HitTestPoint(point)) { | 217 if (!view_->HitTestPoint(point)) { |
195 // If containing parent is not hit, return with failure. | |
196 child->vt = VT_EMPTY; | 218 child->vt = VT_EMPTY; |
197 return S_FALSE; | 219 return S_FALSE; |
198 } | 220 } |
199 | 221 |
200 View* view = view_->GetEventHandlerForPoint(point); | 222 // Check if the point is within any of the immediate children of this |
201 if (view == view_) { | 223 // view. |
202 // No child hit, return parent id. | 224 View* hit_child_view = NULL; |
203 child->vt = VT_I4; | 225 for (int i = view_->child_count() - 1; i >= 0; --i) { |
204 child->lVal = CHILDID_SELF; | 226 View* child_view = view_->child_at(i); |
205 } else { | 227 if (!child_view->visible()) |
206 child->vt = VT_DISPATCH; | 228 continue; |
207 child->pdispVal = view->GetNativeViewAccessible(); | 229 |
208 child->pdispVal->AddRef(); | 230 gfx::Point point_in_child_coords(point); |
| 231 view_->ConvertPointToTarget(view_, child_view, &point_in_child_coords); |
| 232 if (child_view->HitTestPoint(point_in_child_coords)) { |
| 233 hit_child_view = child_view; |
| 234 break; |
| 235 } |
209 } | 236 } |
| 237 |
| 238 // If the point was within one of this view's immediate children, |
| 239 // call accHitTest recursively on that child's native view accessible - |
| 240 // which may be a recursive call to this function or it may be overridden, |
| 241 // for example in the case of a WebView. |
| 242 if (hit_child_view) { |
| 243 HRESULT result = hit_child_view->GetNativeViewAccessible()->accHitTest( |
| 244 x_left, y_top, child); |
| 245 |
| 246 // If the recursive call returned CHILDID_SELF, we have to convert that |
| 247 // into a VT_DISPATCH for the return value to this call. |
| 248 if (S_OK == result && child->vt == VT_I4 && child->lVal == CHILDID_SELF) { |
| 249 child->vt = VT_DISPATCH; |
| 250 child->pdispVal = hit_child_view->GetNativeViewAccessible(); |
| 251 // Always increment ref when returning a reference to a COM object. |
| 252 child->pdispVal->AddRef(); |
| 253 } |
| 254 return result; |
| 255 } |
| 256 |
| 257 // This object is the best match, so return CHILDID_SELF. It's tempting to |
| 258 // simplify the logic and use VT_DISPATCH everywhere, but the Windows |
| 259 // call AccessibleObjectFromPoint will keep calling accHitTest until some |
| 260 // object returns CHILDID_SELF. |
| 261 child->vt = VT_I4; |
| 262 child->lVal = CHILDID_SELF; |
210 return S_OK; | 263 return S_OK; |
211 } | 264 } |
212 | 265 |
213 HRESULT NativeViewAccessibilityWin::accDoDefaultAction(VARIANT var_id) { | 266 HRESULT NativeViewAccessibilityWin::accDoDefaultAction(VARIANT var_id) { |
214 if (!IsValidId(var_id)) | 267 if (!IsValidId(var_id)) |
215 return E_INVALIDARG; | 268 return E_INVALIDARG; |
216 | 269 |
217 // The object does not support the method. This value is returned for | 270 // The object does not support the method. This value is returned for |
218 // controls that do not perform actions, such as edit fields. | 271 // controls that do not perform actions, such as edit fields. |
219 return DISP_E_MEMBERNOTFOUND; | 272 return DISP_E_MEMBERNOTFOUND; |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 int view_storage_id_index = | 424 int view_storage_id_index = |
372 base::win::kFirstViewsAccessibilityId - child_id; | 425 base::win::kFirstViewsAccessibilityId - child_id; |
373 if (view_storage_id_index >= 0 && | 426 if (view_storage_id_index >= 0 && |
374 view_storage_id_index < kMaxViewStorageIds) { | 427 view_storage_id_index < kMaxViewStorageIds) { |
375 int view_storage_id = view_storage_ids_[view_storage_id_index]; | 428 int view_storage_id = view_storage_ids_[view_storage_id_index]; |
376 ViewStorage* view_storage = ViewStorage::GetInstance(); | 429 ViewStorage* view_storage = ViewStorage::GetInstance(); |
377 child_view = view_storage->RetrieveView(view_storage_id); | 430 child_view = view_storage->RetrieveView(view_storage_id); |
378 } else { | 431 } else { |
379 *disp_child = AccessibleWebViewRegistry::GetInstance()-> | 432 *disp_child = AccessibleWebViewRegistry::GetInstance()-> |
380 GetAccessibleFromWebView(view_, child_id); | 433 GetAccessibleFromWebView(view_, child_id); |
381 if (*disp_child) { | 434 if (*disp_child) |
382 (*disp_child)->AddRef(); | |
383 return S_OK; | 435 return S_OK; |
384 } | |
385 } | 436 } |
386 } | 437 } |
387 | 438 |
388 if (!child_view) { | 439 if (!child_view) { |
389 // No child found. | 440 // No child found. |
390 *disp_child = NULL; | 441 *disp_child = NULL; |
391 return E_FAIL; | 442 return E_FAIL; |
392 } | 443 } |
393 | 444 |
394 *disp_child = child_view->GetNativeViewAccessible(); | 445 *disp_child = child_view->GetNativeViewAccessible(); |
(...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
977 } else { | 1028 } else { |
978 V_VT(ret) = VT_EMPTY; | 1029 V_VT(ret) = VT_EMPTY; |
979 } | 1030 } |
980 return S_OK; | 1031 return S_OK; |
981 } | 1032 } |
982 | 1033 |
983 // | 1034 // |
984 // Static methods. | 1035 // Static methods. |
985 // | 1036 // |
986 | 1037 |
987 void NativeViewAccessibility::RegisterWebView(AccessibleWebView* web_view) { | 1038 void NativeViewAccessibility::RegisterWebView(View* web_view) { |
988 AccessibleWebViewRegistry::GetInstance()->RegisterWebView(web_view); | 1039 AccessibleWebViewRegistry::GetInstance()->RegisterWebView(web_view); |
989 } | 1040 } |
990 | 1041 |
991 void NativeViewAccessibility::UnregisterWebView(AccessibleWebView* web_view) { | 1042 void NativeViewAccessibility::UnregisterWebView(View* web_view) { |
992 AccessibleWebViewRegistry::GetInstance()->UnregisterWebView(web_view); | 1043 AccessibleWebViewRegistry::GetInstance()->UnregisterWebView(web_view); |
993 } | 1044 } |
994 | 1045 |
995 int32 NativeViewAccessibilityWin::MSAAEvent(AccessibilityTypes::Event event) { | 1046 int32 NativeViewAccessibilityWin::MSAAEvent(AccessibilityTypes::Event event) { |
996 switch (event) { | 1047 switch (event) { |
997 case AccessibilityTypes::EVENT_ALERT: | 1048 case AccessibilityTypes::EVENT_ALERT: |
998 return EVENT_SYSTEM_ALERT; | 1049 return EVENT_SYSTEM_ALERT; |
999 case AccessibilityTypes::EVENT_FOCUS: | 1050 case AccessibilityTypes::EVENT_FOCUS: |
1000 return EVENT_OBJECT_FOCUS; | 1051 return EVENT_OBJECT_FOCUS; |
1001 case AccessibilityTypes::EVENT_MENUSTART: | 1052 case AccessibilityTypes::EVENT_MENUSTART: |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1226 LONG start_offset, | 1277 LONG start_offset, |
1227 ui::TextBoundaryDirection direction) { | 1278 ui::TextBoundaryDirection direction) { |
1228 HandleSpecialTextOffset(text, &start_offset); | 1279 HandleSpecialTextOffset(text, &start_offset); |
1229 ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary); | 1280 ui::TextBoundaryType boundary = IA2TextBoundaryToTextBoundary(ia2_boundary); |
1230 std::vector<int32> line_breaks; | 1281 std::vector<int32> line_breaks; |
1231 return ui::FindAccessibleTextBoundary( | 1282 return ui::FindAccessibleTextBoundary( |
1232 text, line_breaks, boundary, start_offset, direction); | 1283 text, line_breaks, boundary, start_offset, direction); |
1233 } | 1284 } |
1234 | 1285 |
1235 } // namespace views | 1286 } // namespace views |
OLD | NEW |