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

Side by Side Diff: chrome/browser/browser_accessibility.cc

Issue 4057: Adds MSAA/IAccessible exposure of web content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 2 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 | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/browser_accessibility.h"
6
7 #include "chrome/browser/browser_accessibility_manager.h"
8 #include "chrome/browser/iaccessible_function_ids.h"
9
10 BrowserAccessibility::BrowserAccessibility()
11 : iaccessible_id_(-1),
12 instance_active_(true) {
13 }
14
15 HRESULT BrowserAccessibility::accDoDefaultAction(VARIANT var_id) {
16 if (!instance_active()) {
17 // Instance no longer active, fail gracefully.
18 // TODO(klink): Once we have MSAA events, change these fails for having
19 // BrowserAccessibilityManager firing the right event.
20 return E_FAIL;
21 }
22
23 if (var_id.vt != VT_I4)
24 return E_INVALIDARG;
25
26 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCDODEFAULTACTION, var_id,
27 NULL, NULL)) {
28 return E_FAIL;
29 }
30
31 if (!response().return_code)
32 return S_FALSE;
33
34 return S_OK;
35 }
36
37 STDMETHODIMP BrowserAccessibility::accHitTest(LONG x_left, LONG y_top,
38 VARIANT* child) {
39 if (!instance_active()) {
40 // Instance no longer active, fail gracefully.
41 return E_FAIL;
42 }
43
44 if (!child)
45 return E_INVALIDARG;
46
47 if (!parent_hwnd()) {
48 // Parent HWND needed for coordinate conversion.
49 return E_FAIL;
50 }
51
52 // Convert coordinates to test from screen into client window coordinates, to
53 // maintain sandbox functionality on renderer side.
54 POINT p = {x_left, y_top};
55 ::ScreenToClient(parent_hwnd(), &p);
56
57 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCHITTEST, EmptyVariant(),
58 p.x, p.y)) {
59 return E_FAIL;
60 }
61
62 if (!response().return_code) {
63 // The point is outside of the object's boundaries.
64 child->vt = VT_EMPTY;
65 return S_FALSE;
66 }
67
68 if (response().output_long1 == -1) {
69 if (CreateInstance(IID_IAccessible, response().iaccessible_id,
70 reinterpret_cast<void**>(&child->pdispVal)) == S_OK) {
71 child->vt = VT_DISPATCH;
72 // Increment the reference count for the retrieved interface.
73 child->pdispVal->AddRef();
74 } else {
75 return E_NOINTERFACE;
76 }
77 } else {
78 child->vt = VT_I4;
79 child->lVal = response().output_long1;
80 }
81
82 return S_OK;
83 }
84
85 STDMETHODIMP BrowserAccessibility::accLocation(LONG* x_left, LONG* y_top,
86 LONG* width, LONG* height,
87 VARIANT var_id) {
88 if (!instance_active()) {
89 // Instance no longer active, fail gracefully.
90 return E_FAIL;
91 }
92
93 if (var_id.vt != VT_I4 || !x_left || !y_top || !width || !height ||
94 !parent_hwnd()) {
95 return E_INVALIDARG;
96 }
97
98 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCLOCATION, var_id, NULL,
99 NULL)) {
100 return E_FAIL;
101 }
102
103 POINT top_left = {0, 0};
104
105 // Find the top left corner of the containing window in screen coords, and
106 // adjust the output position by this amount.
107 ::ClientToScreen(parent_hwnd(), &top_left);
108
109 *x_left = response().output_long1 + top_left.x;
110 *y_top = response().output_long2 + top_left.y;
111
112 *width = response().output_long3;
113 *height = response().output_long4;
114
115 return S_OK;
116 }
117
118 STDMETHODIMP BrowserAccessibility::accNavigate(LONG nav_dir, VARIANT start,
119 VARIANT* end) {
120 if (!instance_active()) {
121 // Instance no longer active, fail gracefully.
122 return E_FAIL;
123 }
124
125 if (start.vt != VT_I4 || !end)
126 return E_INVALIDARG;
127
128 if ((nav_dir == NAVDIR_LASTCHILD || nav_dir == NAVDIR_FIRSTCHILD) &&
129 start.lVal != CHILDID_SELF) {
130 // MSAA states that navigating to first/last child can only be from self.
131 return E_INVALIDARG;
132 }
133
134 if (nav_dir == NAVDIR_DOWN || nav_dir == NAVDIR_UP ||
135 nav_dir == NAVDIR_LEFT || nav_dir == NAVDIR_RIGHT) {
136 // Directions not implemented, matching Mozilla and IE.
137 return E_INVALIDARG;
138 }
139
140 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCNAVIGATE, start, nav_dir,
141 NULL)) {
142 return E_FAIL;
143 }
144
145 if (!response().return_code) {
146 // No screen element was found in the specified direction.
147 end->vt = VT_EMPTY;
148 return S_FALSE;
149 }
150
151 if (response().output_long1 == -1) {
152 if (CreateInstance(IID_IAccessible, response().iaccessible_id,
153 reinterpret_cast<void**>(&end->pdispVal)) == S_OK) {
154 end->vt = VT_DISPATCH;
155 // Increment the reference count for the retrieved interface.
156 end->pdispVal->AddRef();
157 } else {
158 return E_NOINTERFACE;
159 }
160 } else {
161 end->vt = VT_I4;
162 end->lVal = response().output_long1;
163 }
164
165 return S_OK;
166 }
167
168 STDMETHODIMP BrowserAccessibility::get_accChild(VARIANT var_child,
169 IDispatch** disp_child) {
170 if (!instance_active()) {
171 // Instance no longer active, fail gracefully.
172 return E_FAIL;
173 }
174
175 if (var_child.vt != VT_I4 || !disp_child)
176 return E_INVALIDARG;
177
178 // If var_child is the parent, remain with the same IDispatch.
179 if (var_child.lVal == CHILDID_SELF && iaccessible_id_ != 0)
180 return S_OK;
181
182 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCCHILD, var_child, NULL,
183 NULL)) {
184 return E_FAIL;
185 }
186
187 if (!response().return_code) {
188 // When at a leaf, children are handled by the parent object.
189 *disp_child = NULL;
190 return S_FALSE;
191 }
192
193 // Retrieve the IUnknown interface for the parent view, and assign the
194 // IDispatch returned.
195 if (CreateInstance(IID_IAccessible, response().iaccessible_id,
196 reinterpret_cast<void**>(disp_child)) == S_OK) {
197 // Increment the reference count for the retrieved interface.
198 (*disp_child)->AddRef();
199 return S_OK;
200 } else {
201 return E_NOINTERFACE;
202 }
203 }
204
205 STDMETHODIMP BrowserAccessibility::get_accChildCount(LONG* child_count) {
206 if (!instance_active()) {
207 // Instance no longer active, fail gracefully.
208 return E_FAIL;
209 }
210
211 if (!child_count)
212 return E_INVALIDARG;
213
214 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCCHILDCOUNT,
215 EmptyVariant(), NULL, NULL)) {
216 return E_FAIL;
217 }
218
219 *child_count = response().output_long1;
220 return S_OK;
221 }
222
223 STDMETHODIMP BrowserAccessibility::get_accDefaultAction(VARIANT var_id,
224 BSTR* def_action) {
225 if (!instance_active()) {
226 // Instance no longer active, fail gracefully.
227 return E_FAIL;
228 }
229
230 if (var_id.vt != VT_I4 || !def_action)
231 return E_INVALIDARG;
232
233 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCDEFAULTACTION, var_id,
234 NULL, NULL)) {
235 return E_FAIL;
236 }
237
238 if (!response().return_code) {
239 // No string found.
240 return S_FALSE;
241 }
242
243 *def_action = CComBSTR(response().output_string.c_str()).Detach();
244
245 DCHECK(*def_action);
246 return S_OK;
247 }
248
249 STDMETHODIMP BrowserAccessibility::get_accDescription(VARIANT var_id,
250 BSTR* desc) {
251 if (!instance_active()) {
252 // Instance no longer active, fail gracefully.
253 return E_FAIL;
254 }
255
256 if (var_id.vt != VT_I4 || !desc)
257 return E_INVALIDARG;
258
259 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCDESCRIPTION, var_id,
260 NULL, NULL)) {
261 return E_FAIL;
262 }
263
264 if (!response().return_code) {
265 // No string found.
266 return S_FALSE;
267 }
268
269 *desc = CComBSTR(response().output_string.c_str()).Detach();
270
271 DCHECK(*desc);
272 return S_OK;
273 }
274
275 STDMETHODIMP BrowserAccessibility::get_accFocus(VARIANT* focus_child) {
276 if (!instance_active()) {
277 // Instance no longer active, fail gracefully.
278 return E_FAIL;
279 }
280
281 if (!focus_child)
282 return E_INVALIDARG;
283
284 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCFOCUS, EmptyVariant(),
285 NULL, NULL)) {
286 return E_FAIL;
287 }
288
289 if (!response().return_code) {
290 // The window that contains this object is not the active window.
291 focus_child->vt = VT_EMPTY;
292 return S_FALSE;
293 }
294
295 if (response().output_long1 == -1) {
296 if (CreateInstance(IID_IAccessible, response().iaccessible_id,
297 reinterpret_cast<void**>(&focus_child->pdispVal)) == S_OK) {
298 focus_child->vt = VT_DISPATCH;
299 // Increment the reference count for the retrieved interface.
300 focus_child->pdispVal->AddRef();
301 } else {
302 return E_NOINTERFACE;
303 }
304 } else {
305 focus_child->vt = VT_I4;
306 focus_child->lVal = response().output_long1;
307 }
308
309 return S_OK;
310 }
311
312 STDMETHODIMP BrowserAccessibility::get_accHelp(VARIANT var_id, BSTR* help) {
313 if (!instance_active()) {
314 // Instance no longer active, fail gracefully.
315 return E_FAIL;
316 }
317
318 if (var_id.vt != VT_I4 || !help)
319 return E_INVALIDARG;
320
321 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCHELP, var_id, NULL,
322 NULL)) {
323 return E_FAIL;
324 }
325
326 if (!response().return_code) {
327 // No string found.
328 return S_FALSE;
329 }
330
331 *help = CComBSTR(response().output_string.c_str()).Detach();
332
333 DCHECK(*help);
334 return S_OK;
335 }
336
337 STDMETHODIMP BrowserAccessibility::get_accKeyboardShortcut(VARIANT var_id,
338 BSTR* acc_key) {
339 if (!instance_active()) {
340 // Instance no longer active, fail gracefully.
341 return E_FAIL;
342 }
343
344 if (var_id.vt != VT_I4 || !acc_key)
345 return E_INVALIDARG;
346
347 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCKEYBOARDSHORTCUT,
348 var_id, NULL, NULL)) {
349 return E_FAIL;
350 }
351
352 if (!response().return_code) {
353 // No string found.
354 return S_FALSE;
355 }
356
357 *acc_key = CComBSTR(response().output_string.c_str()).Detach();
358
359 DCHECK(*acc_key);
360 return S_OK;
361 }
362
363 STDMETHODIMP BrowserAccessibility::get_accName(VARIANT var_id, BSTR* name) {
364 if (!instance_active()) {
365 // Instance no longer active, fail gracefully.
366 return E_FAIL;
367 }
368
369 if (var_id.vt != VT_I4 || !name)
370 return E_INVALIDARG;
371
372 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCNAME, var_id, NULL,
373 NULL)) {
374 return E_FAIL;
375 }
376
377 if (!response().return_code) {
378 // No string found.
379 return S_FALSE;
380 }
381
382 *name = CComBSTR(response().output_string.c_str()).Detach();
383
384 DCHECK(*name);
385 return S_OK;
386 }
387
388 STDMETHODIMP BrowserAccessibility::get_accParent(IDispatch** disp_parent) {
389 if (!instance_active()) {
390 // Instance no longer active, fail gracefully.
391 return E_FAIL;
392 }
393
394 if (!disp_parent || !parent_hwnd())
395 return E_INVALIDARG;
396
397 // Root node's parent is the containing HWND's IAccessible.
398 if (iaccessible_id() == 0) {
399 // For an object that has no parent (e.g. root), point the accessible parent
400 // to the default implementation.
401 HRESULT hr =
402 ::CreateStdAccessibleObject(parent_hwnd(), OBJID_WINDOW,
403 IID_IAccessible,
404 reinterpret_cast<void**>(disp_parent));
405
406 if (!SUCCEEDED(hr)) {
407 *disp_parent = NULL;
408 return S_FALSE;
409 }
410 return S_OK;
411 }
412
413 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCPARENT, EmptyVariant(),
414 NULL, NULL)) {
415 return E_FAIL;
416 }
417
418 if (!response().return_code) {
419 // No parent exists for this object.
420 return S_FALSE;
421 }
422
423 // Retrieve the IUnknown interface for the parent view, and assign the
424 // IDispatch returned.
425 if (CreateInstance(IID_IAccessible, response().iaccessible_id,
426 reinterpret_cast<void**>(disp_parent)) == S_OK) {
427 // Increment the reference count for the retrieved interface.
428 (*disp_parent)->AddRef();
429 return S_OK;
430 } else {
431 return E_NOINTERFACE;
432 }
433 }
434
435 STDMETHODIMP BrowserAccessibility::get_accRole(VARIANT var_id, VARIANT* role) {
436 if (!instance_active()) {
437 // Instance no longer active, fail gracefully.
438 return E_FAIL;
439 }
440
441 if (var_id.vt != VT_I4 || !role)
442 return E_INVALIDARG;
443
444 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCROLE, var_id, NULL,
445 NULL)) {
446 return E_FAIL;
447 }
448
449 role->vt = VT_I4;
450 role->lVal = response().output_long1;
451
452 return S_OK;
453 }
454
455 STDMETHODIMP BrowserAccessibility::get_accState(VARIANT var_id,
456 VARIANT* state) {
457 if (!instance_active()) {
458 // Instance no longer active, fail gracefully.
459 return E_FAIL;
460 }
461
462 if (var_id.vt != VT_I4 || !state)
463 return E_INVALIDARG;
464
465 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCSTATE, var_id, NULL,
466 NULL)) {
467 return E_FAIL;
468 }
469
470 state->vt = VT_I4;
471 state->lVal = response().output_long1;
472
473 return S_OK;
474 }
475
476 STDMETHODIMP BrowserAccessibility::get_accValue(VARIANT var_id, BSTR* value) {
477 if (!instance_active()) {
478 // Instance no longer active, fail gracefully.
479 return E_FAIL;
480 }
481
482 if (var_id.vt != VT_I4 || !value)
483 return E_INVALIDARG;
484
485 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCVALUE, var_id, NULL,
486 NULL)) {
487 return E_FAIL;
488 }
489
490 if (!response().return_code) {
491 // No string found.
492 return S_FALSE;
493 }
494
495 *value = CComBSTR(response().output_string.c_str()).Detach();
496
497 DCHECK(*value);
498 return S_OK;
499 }
500
501 STDMETHODIMP BrowserAccessibility::accSelect(LONG flags_select,
502 VARIANT var_id) {
503 return DISP_E_MEMBERNOTFOUND;
504 }
505
506 STDMETHODIMP BrowserAccessibility::get_accHelpTopic(BSTR* help_file,
507 VARIANT var_id,
508 LONG* topic_id) {
509 if (help_file) {
510 *help_file = NULL;
511 }
512 if (topic_id) {
513 *topic_id = static_cast<LONG>(-1);
514 }
515 return DISP_E_MEMBERNOTFOUND;
516 }
517
518 STDMETHODIMP BrowserAccessibility::get_accSelection(VARIANT* selected) {
519 if (selected)
520 selected->vt = VT_EMPTY;
521
522 return DISP_E_MEMBERNOTFOUND;
523 }
524
525 STDMETHODIMP BrowserAccessibility::put_accName(VARIANT var_id, BSTR put_name) {
526 return DISP_E_MEMBERNOTFOUND;
527 }
528
529 STDMETHODIMP BrowserAccessibility::put_accValue(VARIANT var_id, BSTR put_val) {
530 return DISP_E_MEMBERNOTFOUND;
531 }
532
533 STDMETHODIMP BrowserAccessibility::CreateInstance(REFIID iid,
534 int iaccessible_id,
535 void** interface_ptr) {
536 return BrowserAccessibilityManager::Instance()->CreateAccessibilityInstance(
537 iid, iaccessible_id, instance_id(), interface_ptr);
538 }
539
540 bool BrowserAccessibility::RequestAccessibilityInfo(int iaccessible_func_id,
541 VARIANT var_id, LONG input1,
542 LONG input2) {
543 return BrowserAccessibilityManager::Instance()->RequestAccessibilityInfo(
544 iaccessible_id(), instance_id(), iaccessible_func_id, var_id, input1,
545 input2);
546 }
547
548 ViewHostMsg_Accessibility_Out_Params BrowserAccessibility::response() {
549 return BrowserAccessibilityManager::Instance()->response();
550 }
551
552 HWND BrowserAccessibility::parent_hwnd() {
553 return BrowserAccessibilityManager::Instance()->parent_hwnd(instance_id());
554 }
555
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698