Fixing build: GetViewContainer changed name from under me. :)
[chromium-blink-merge.git] / chrome / browser / browser_accessibility.cc
blobfea5bf296d7c8f78d82e7889c1dfee237b737971
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.
5 #include "chrome/browser/browser_accessibility.h"
7 #include "chrome/browser/browser_accessibility_manager.h"
8 #include "chrome/browser/iaccessible_function_ids.h"
10 BrowserAccessibility::BrowserAccessibility()
11 : iaccessible_id_(-1),
12 instance_active_(true) {
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;
23 if (var_id.vt != VT_I4)
24 return E_INVALIDARG;
26 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCDODEFAULTACTION, var_id,
27 NULL, NULL)) {
28 return E_FAIL;
31 if (!response().return_code)
32 return S_FALSE;
34 return S_OK;
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;
44 if (!child)
45 return E_INVALIDARG;
47 if (!parent_hwnd()) {
48 // Parent HWND needed for coordinate conversion.
49 return E_FAIL;
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);
57 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCHITTEST, EmptyVariant(),
58 p.x, p.y)) {
59 return E_FAIL;
62 if (!response().return_code) {
63 // The point is outside of the object's boundaries.
64 child->vt = VT_EMPTY;
65 return S_FALSE;
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;
77 } else {
78 child->vt = VT_I4;
79 child->lVal = response().output_long1;
82 return S_OK;
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;
93 if (var_id.vt != VT_I4 || !x_left || !y_top || !width || !height ||
94 !parent_hwnd()) {
95 return E_INVALIDARG;
98 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCLOCATION, var_id, NULL,
99 NULL)) {
100 return E_FAIL;
103 POINT top_left = {0, 0};
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);
109 *x_left = response().output_long1 + top_left.x;
110 *y_top = response().output_long2 + top_left.y;
112 *width = response().output_long3;
113 *height = response().output_long4;
115 return S_OK;
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;
125 if (start.vt != VT_I4 || !end)
126 return E_INVALIDARG;
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;
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;
140 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCNAVIGATE, start, nav_dir,
141 NULL)) {
142 return E_FAIL;
145 if (!response().return_code) {
146 // No screen element was found in the specified direction.
147 end->vt = VT_EMPTY;
148 return S_FALSE;
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;
160 } else {
161 end->vt = VT_I4;
162 end->lVal = response().output_long1;
165 return S_OK;
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;
175 if (var_child.vt != VT_I4 || !disp_child)
176 return E_INVALIDARG;
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;
182 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCCHILD, var_child, NULL,
183 NULL)) {
184 return E_FAIL;
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;
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;
205 STDMETHODIMP BrowserAccessibility::get_accChildCount(LONG* child_count) {
206 if (!instance_active()) {
207 // Instance no longer active, fail gracefully.
208 return E_FAIL;
211 if (!child_count)
212 return E_INVALIDARG;
214 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCCHILDCOUNT,
215 EmptyVariant(), NULL, NULL)) {
216 return E_FAIL;
219 *child_count = response().output_long1;
220 return S_OK;
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;
230 if (var_id.vt != VT_I4 || !def_action)
231 return E_INVALIDARG;
233 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCDEFAULTACTION, var_id,
234 NULL, NULL)) {
235 return E_FAIL;
238 if (!response().return_code) {
239 // No string found.
240 return S_FALSE;
243 *def_action = CComBSTR(response().output_string.c_str()).Detach();
245 DCHECK(*def_action);
246 return S_OK;
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;
256 if (var_id.vt != VT_I4 || !desc)
257 return E_INVALIDARG;
259 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCDESCRIPTION, var_id,
260 NULL, NULL)) {
261 return E_FAIL;
264 if (!response().return_code) {
265 // No string found.
266 return S_FALSE;
269 *desc = CComBSTR(response().output_string.c_str()).Detach();
271 DCHECK(*desc);
272 return S_OK;
275 STDMETHODIMP BrowserAccessibility::get_accFocus(VARIANT* focus_child) {
276 if (!instance_active()) {
277 // Instance no longer active, fail gracefully.
278 return E_FAIL;
281 if (!focus_child)
282 return E_INVALIDARG;
284 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCFOCUS, EmptyVariant(),
285 NULL, NULL)) {
286 return E_FAIL;
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;
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;
304 } else {
305 focus_child->vt = VT_I4;
306 focus_child->lVal = response().output_long1;
309 return S_OK;
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;
318 if (var_id.vt != VT_I4 || !help)
319 return E_INVALIDARG;
321 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCHELP, var_id, NULL,
322 NULL)) {
323 return E_FAIL;
326 if (!response().return_code) {
327 // No string found.
328 return S_FALSE;
331 *help = CComBSTR(response().output_string.c_str()).Detach();
333 DCHECK(*help);
334 return S_OK;
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;
344 if (var_id.vt != VT_I4 || !acc_key)
345 return E_INVALIDARG;
347 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCKEYBOARDSHORTCUT,
348 var_id, NULL, NULL)) {
349 return E_FAIL;
352 if (!response().return_code) {
353 // No string found.
354 return S_FALSE;
357 *acc_key = CComBSTR(response().output_string.c_str()).Detach();
359 DCHECK(*acc_key);
360 return S_OK;
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;
369 if (var_id.vt != VT_I4 || !name)
370 return E_INVALIDARG;
372 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCNAME, var_id, NULL,
373 NULL)) {
374 return E_FAIL;
377 if (!response().return_code) {
378 // No string found.
379 return S_FALSE;
382 *name = CComBSTR(response().output_string.c_str()).Detach();
384 DCHECK(*name);
385 return S_OK;
388 STDMETHODIMP BrowserAccessibility::get_accParent(IDispatch** disp_parent) {
389 if (!instance_active()) {
390 // Instance no longer active, fail gracefully.
391 return E_FAIL;
394 if (!disp_parent || !parent_hwnd())
395 return E_INVALIDARG;
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));
406 if (!SUCCEEDED(hr)) {
407 *disp_parent = NULL;
408 return S_FALSE;
410 return S_OK;
413 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCPARENT, EmptyVariant(),
414 NULL, NULL)) {
415 return E_FAIL;
418 if (!response().return_code) {
419 // No parent exists for this object.
420 return S_FALSE;
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;
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;
441 if (var_id.vt != VT_I4 || !role)
442 return E_INVALIDARG;
444 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCROLE, var_id, NULL,
445 NULL)) {
446 return E_FAIL;
449 role->vt = VT_I4;
450 role->lVal = response().output_long1;
452 return S_OK;
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;
462 if (var_id.vt != VT_I4 || !state)
463 return E_INVALIDARG;
465 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCSTATE, var_id, NULL,
466 NULL)) {
467 return E_FAIL;
470 state->vt = VT_I4;
471 state->lVal = response().output_long1;
473 return S_OK;
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;
482 if (var_id.vt != VT_I4 || !value)
483 return E_INVALIDARG;
485 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCVALUE, var_id, NULL,
486 NULL)) {
487 return E_FAIL;
490 if (!response().return_code) {
491 // No string found.
492 return S_FALSE;
495 *value = CComBSTR(response().output_string.c_str()).Detach();
497 DCHECK(*value);
498 return S_OK;
501 STDMETHODIMP BrowserAccessibility::accSelect(LONG flags_select,
502 VARIANT var_id) {
503 return DISP_E_MEMBERNOTFOUND;
506 STDMETHODIMP BrowserAccessibility::get_accHelpTopic(BSTR* help_file,
507 VARIANT var_id,
508 LONG* topic_id) {
509 if (help_file) {
510 *help_file = NULL;
512 if (topic_id) {
513 *topic_id = static_cast<LONG>(-1);
515 return DISP_E_MEMBERNOTFOUND;
518 STDMETHODIMP BrowserAccessibility::get_accSelection(VARIANT* selected) {
519 if (selected)
520 selected->vt = VT_EMPTY;
522 return DISP_E_MEMBERNOTFOUND;
525 STDMETHODIMP BrowserAccessibility::put_accName(VARIANT var_id, BSTR put_name) {
526 return DISP_E_MEMBERNOTFOUND;
529 STDMETHODIMP BrowserAccessibility::put_accValue(VARIANT var_id, BSTR put_val) {
530 return DISP_E_MEMBERNOTFOUND;
533 STDMETHODIMP BrowserAccessibility::CreateInstance(REFIID iid,
534 int iaccessible_id,
535 void** interface_ptr) {
536 return BrowserAccessibilityManager::GetInstance()->
537 CreateAccessibilityInstance(iid, iaccessible_id, instance_id(),
538 interface_ptr);
541 bool BrowserAccessibility::RequestAccessibilityInfo(int iaccessible_func_id,
542 VARIANT var_id, LONG input1,
543 LONG input2) {
544 return BrowserAccessibilityManager::GetInstance()->RequestAccessibilityInfo(
545 iaccessible_id(), instance_id(), iaccessible_func_id, var_id, input1,
546 input2);
549 ViewHostMsg_Accessibility_Out_Params BrowserAccessibility::response() {
550 return BrowserAccessibilityManager::GetInstance()->response();
553 HWND BrowserAccessibility::parent_hwnd() {
554 return BrowserAccessibilityManager::GetInstance()->parent_hwnd(instance_id());