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.
23 if (var_id
.vt
!= VT_I4
)
26 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCDODEFAULTACTION
, var_id
,
31 if (!response().return_code
)
37 STDMETHODIMP
BrowserAccessibility::accHitTest(LONG x_left
, LONG y_top
,
39 if (!instance_active()) {
40 // Instance no longer active, fail gracefully.
48 // Parent HWND needed for coordinate conversion.
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(),
62 if (!response().return_code
) {
63 // The point is outside of the object's boundaries.
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();
79 child
->lVal
= response().output_long1
;
85 STDMETHODIMP
BrowserAccessibility::accLocation(LONG
* x_left
, LONG
* y_top
,
86 LONG
* width
, LONG
* height
,
88 if (!instance_active()) {
89 // Instance no longer active, fail gracefully.
93 if (var_id
.vt
!= VT_I4
|| !x_left
|| !y_top
|| !width
|| !height
||
98 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCLOCATION
, var_id
, NULL
,
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
;
118 STDMETHODIMP
BrowserAccessibility::accNavigate(LONG nav_dir
, VARIANT start
,
120 if (!instance_active()) {
121 // Instance no longer active, fail gracefully.
125 if (start
.vt
!= VT_I4
|| !end
)
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.
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.
140 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCNAVIGATE
, start
, nav_dir
,
145 if (!response().return_code
) {
146 // No screen element was found in the specified direction.
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();
158 return E_NOINTERFACE
;
162 end
->lVal
= response().output_long1
;
168 STDMETHODIMP
BrowserAccessibility::get_accChild(VARIANT var_child
,
169 IDispatch
** disp_child
) {
170 if (!instance_active()) {
171 // Instance no longer active, fail gracefully.
175 if (var_child
.vt
!= VT_I4
|| !disp_child
)
178 // If var_child is the parent, remain with the same IDispatch.
179 if (var_child
.lVal
== CHILDID_SELF
&& iaccessible_id_
!= 0)
182 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCCHILD
, var_child
, NULL
,
187 if (!response().return_code
) {
188 // When at a leaf, children are handled by the parent object.
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();
201 return E_NOINTERFACE
;
205 STDMETHODIMP
BrowserAccessibility::get_accChildCount(LONG
* child_count
) {
206 if (!instance_active()) {
207 // Instance no longer active, fail gracefully.
214 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCCHILDCOUNT
,
215 EmptyVariant(), NULL
, NULL
)) {
219 *child_count
= response().output_long1
;
223 STDMETHODIMP
BrowserAccessibility::get_accDefaultAction(VARIANT var_id
,
225 if (!instance_active()) {
226 // Instance no longer active, fail gracefully.
230 if (var_id
.vt
!= VT_I4
|| !def_action
)
233 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCDEFAULTACTION
, var_id
,
238 if (!response().return_code
) {
243 *def_action
= CComBSTR(response().output_string
.c_str()).Detach();
249 STDMETHODIMP
BrowserAccessibility::get_accDescription(VARIANT var_id
,
251 if (!instance_active()) {
252 // Instance no longer active, fail gracefully.
256 if (var_id
.vt
!= VT_I4
|| !desc
)
259 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCDESCRIPTION
, var_id
,
264 if (!response().return_code
) {
269 *desc
= CComBSTR(response().output_string
.c_str()).Detach();
275 STDMETHODIMP
BrowserAccessibility::get_accFocus(VARIANT
* focus_child
) {
276 if (!instance_active()) {
277 // Instance no longer active, fail gracefully.
284 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCFOCUS
, EmptyVariant(),
289 if (!response().return_code
) {
290 // The window that contains this object is not the active window.
291 focus_child
->vt
= VT_EMPTY
;
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();
302 return E_NOINTERFACE
;
305 focus_child
->vt
= VT_I4
;
306 focus_child
->lVal
= response().output_long1
;
312 STDMETHODIMP
BrowserAccessibility::get_accHelp(VARIANT var_id
, BSTR
* help
) {
313 if (!instance_active()) {
314 // Instance no longer active, fail gracefully.
318 if (var_id
.vt
!= VT_I4
|| !help
)
321 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCHELP
, var_id
, NULL
,
326 if (!response().return_code
) {
331 *help
= CComBSTR(response().output_string
.c_str()).Detach();
337 STDMETHODIMP
BrowserAccessibility::get_accKeyboardShortcut(VARIANT var_id
,
339 if (!instance_active()) {
340 // Instance no longer active, fail gracefully.
344 if (var_id
.vt
!= VT_I4
|| !acc_key
)
347 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCKEYBOARDSHORTCUT
,
348 var_id
, NULL
, NULL
)) {
352 if (!response().return_code
) {
357 *acc_key
= CComBSTR(response().output_string
.c_str()).Detach();
363 STDMETHODIMP
BrowserAccessibility::get_accName(VARIANT var_id
, BSTR
* name
) {
364 if (!instance_active()) {
365 // Instance no longer active, fail gracefully.
369 if (var_id
.vt
!= VT_I4
|| !name
)
372 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCNAME
, var_id
, NULL
,
377 if (!response().return_code
) {
382 *name
= CComBSTR(response().output_string
.c_str()).Detach();
388 STDMETHODIMP
BrowserAccessibility::get_accParent(IDispatch
** disp_parent
) {
389 if (!instance_active()) {
390 // Instance no longer active, fail gracefully.
394 if (!disp_parent
|| !parent_hwnd())
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.
402 ::CreateStdAccessibleObject(parent_hwnd(), OBJID_WINDOW
,
404 reinterpret_cast<void**>(disp_parent
));
406 if (!SUCCEEDED(hr
)) {
413 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCPARENT
, EmptyVariant(),
418 if (!response().return_code
) {
419 // No parent exists for this object.
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();
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.
441 if (var_id
.vt
!= VT_I4
|| !role
)
444 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCROLE
, var_id
, NULL
,
450 role
->lVal
= response().output_long1
;
455 STDMETHODIMP
BrowserAccessibility::get_accState(VARIANT var_id
,
457 if (!instance_active()) {
458 // Instance no longer active, fail gracefully.
462 if (var_id
.vt
!= VT_I4
|| !state
)
465 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCSTATE
, var_id
, NULL
,
471 state
->lVal
= response().output_long1
;
476 STDMETHODIMP
BrowserAccessibility::get_accValue(VARIANT var_id
, BSTR
* value
) {
477 if (!instance_active()) {
478 // Instance no longer active, fail gracefully.
482 if (var_id
.vt
!= VT_I4
|| !value
)
485 if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCVALUE
, var_id
, NULL
,
490 if (!response().return_code
) {
495 *value
= CComBSTR(response().output_string
.c_str()).Detach();
501 STDMETHODIMP
BrowserAccessibility::accSelect(LONG flags_select
,
503 return DISP_E_MEMBERNOTFOUND
;
506 STDMETHODIMP
BrowserAccessibility::get_accHelpTopic(BSTR
* help_file
,
513 *topic_id
= static_cast<LONG
>(-1);
515 return DISP_E_MEMBERNOTFOUND
;
518 STDMETHODIMP
BrowserAccessibility::get_accSelection(VARIANT
* 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
,
535 void** interface_ptr
) {
536 return BrowserAccessibilityManager::GetInstance()->
537 CreateAccessibilityInstance(iid
, iaccessible_id
, instance_id(),
541 bool BrowserAccessibility::RequestAccessibilityInfo(int iaccessible_func_id
,
542 VARIANT var_id
, LONG input1
,
544 return BrowserAccessibilityManager::GetInstance()->RequestAccessibilityInfo(
545 iaccessible_id(), instance_id(), iaccessible_func_id
, var_id
, input1
,
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());