| Index: chrome/browser/browser_accessibility.cc
|
| ===================================================================
|
| --- chrome/browser/browser_accessibility.cc (revision 0)
|
| +++ chrome/browser/browser_accessibility.cc (revision 0)
|
| @@ -0,0 +1,555 @@
|
| +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/browser_accessibility.h"
|
| +
|
| +#include "chrome/browser/browser_accessibility_manager.h"
|
| +#include "chrome/browser/iaccessible_function_ids.h"
|
| +
|
| +BrowserAccessibility::BrowserAccessibility()
|
| + : iaccessible_id_(-1),
|
| + instance_active_(true) {
|
| +}
|
| +
|
| +HRESULT BrowserAccessibility::accDoDefaultAction(VARIANT var_id) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + // TODO(klink): Once we have MSAA events, change these fails for having
|
| + // BrowserAccessibilityManager firing the right event.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (var_id.vt != VT_I4)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCDODEFAULTACTION, var_id,
|
| + NULL, NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code)
|
| + return S_FALSE;
|
| +
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::accHitTest(LONG x_left, LONG y_top,
|
| + VARIANT* child) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!child)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!parent_hwnd()) {
|
| + // Parent HWND needed for coordinate conversion.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + // Convert coordinates to test from screen into client window coordinates, to
|
| + // maintain sandbox functionality on renderer side.
|
| + POINT p = {x_left, y_top};
|
| + ::ScreenToClient(parent_hwnd(), &p);
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCHITTEST, EmptyVariant(),
|
| + p.x, p.y)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code) {
|
| + // The point is outside of the object's boundaries.
|
| + child->vt = VT_EMPTY;
|
| + return S_FALSE;
|
| + }
|
| +
|
| + if (response().output_long1 == -1) {
|
| + if (CreateInstance(IID_IAccessible, response().iaccessible_id,
|
| + reinterpret_cast<void**>(&child->pdispVal)) == S_OK) {
|
| + child->vt = VT_DISPATCH;
|
| + // Increment the reference count for the retrieved interface.
|
| + child->pdispVal->AddRef();
|
| + } else {
|
| + return E_NOINTERFACE;
|
| + }
|
| + } else {
|
| + child->vt = VT_I4;
|
| + child->lVal = response().output_long1;
|
| + }
|
| +
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::accLocation(LONG* x_left, LONG* y_top,
|
| + LONG* width, LONG* height,
|
| + VARIANT var_id) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (var_id.vt != VT_I4 || !x_left || !y_top || !width || !height ||
|
| + !parent_hwnd()) {
|
| + return E_INVALIDARG;
|
| + }
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCLOCATION, var_id, NULL,
|
| + NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + POINT top_left = {0, 0};
|
| +
|
| + // Find the top left corner of the containing window in screen coords, and
|
| + // adjust the output position by this amount.
|
| + ::ClientToScreen(parent_hwnd(), &top_left);
|
| +
|
| + *x_left = response().output_long1 + top_left.x;
|
| + *y_top = response().output_long2 + top_left.y;
|
| +
|
| + *width = response().output_long3;
|
| + *height = response().output_long4;
|
| +
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::accNavigate(LONG nav_dir, VARIANT start,
|
| + VARIANT* end) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (start.vt != VT_I4 || !end)
|
| + return E_INVALIDARG;
|
| +
|
| + if ((nav_dir == NAVDIR_LASTCHILD || nav_dir == NAVDIR_FIRSTCHILD) &&
|
| + start.lVal != CHILDID_SELF) {
|
| + // MSAA states that navigating to first/last child can only be from self.
|
| + return E_INVALIDARG;
|
| + }
|
| +
|
| + if (nav_dir == NAVDIR_DOWN || nav_dir == NAVDIR_UP ||
|
| + nav_dir == NAVDIR_LEFT || nav_dir == NAVDIR_RIGHT) {
|
| + // Directions not implemented, matching Mozilla and IE.
|
| + return E_INVALIDARG;
|
| + }
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_ACCNAVIGATE, start, nav_dir,
|
| + NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code) {
|
| + // No screen element was found in the specified direction.
|
| + end->vt = VT_EMPTY;
|
| + return S_FALSE;
|
| + }
|
| +
|
| + if (response().output_long1 == -1) {
|
| + if (CreateInstance(IID_IAccessible, response().iaccessible_id,
|
| + reinterpret_cast<void**>(&end->pdispVal)) == S_OK) {
|
| + end->vt = VT_DISPATCH;
|
| + // Increment the reference count for the retrieved interface.
|
| + end->pdispVal->AddRef();
|
| + } else {
|
| + return E_NOINTERFACE;
|
| + }
|
| + } else {
|
| + end->vt = VT_I4;
|
| + end->lVal = response().output_long1;
|
| + }
|
| +
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accChild(VARIANT var_child,
|
| + IDispatch** disp_child) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (var_child.vt != VT_I4 || !disp_child)
|
| + return E_INVALIDARG;
|
| +
|
| + // If var_child is the parent, remain with the same IDispatch.
|
| + if (var_child.lVal == CHILDID_SELF && iaccessible_id_ != 0)
|
| + return S_OK;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCCHILD, var_child, NULL,
|
| + NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code) {
|
| + // When at a leaf, children are handled by the parent object.
|
| + *disp_child = NULL;
|
| + return S_FALSE;
|
| + }
|
| +
|
| + // Retrieve the IUnknown interface for the parent view, and assign the
|
| + // IDispatch returned.
|
| + if (CreateInstance(IID_IAccessible, response().iaccessible_id,
|
| + reinterpret_cast<void**>(disp_child)) == S_OK) {
|
| + // Increment the reference count for the retrieved interface.
|
| + (*disp_child)->AddRef();
|
| + return S_OK;
|
| + } else {
|
| + return E_NOINTERFACE;
|
| + }
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accChildCount(LONG* child_count) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!child_count)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCCHILDCOUNT,
|
| + EmptyVariant(), NULL, NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + *child_count = response().output_long1;
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accDefaultAction(VARIANT var_id,
|
| + BSTR* def_action) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (var_id.vt != VT_I4 || !def_action)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCDEFAULTACTION, var_id,
|
| + NULL, NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code) {
|
| + // No string found.
|
| + return S_FALSE;
|
| + }
|
| +
|
| + *def_action = CComBSTR(response().output_string.c_str()).Detach();
|
| +
|
| + DCHECK(*def_action);
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accDescription(VARIANT var_id,
|
| + BSTR* desc) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (var_id.vt != VT_I4 || !desc)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCDESCRIPTION, var_id,
|
| + NULL, NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code) {
|
| + // No string found.
|
| + return S_FALSE;
|
| + }
|
| +
|
| + *desc = CComBSTR(response().output_string.c_str()).Detach();
|
| +
|
| + DCHECK(*desc);
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accFocus(VARIANT* focus_child) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!focus_child)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCFOCUS, EmptyVariant(),
|
| + NULL, NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code) {
|
| + // The window that contains this object is not the active window.
|
| + focus_child->vt = VT_EMPTY;
|
| + return S_FALSE;
|
| + }
|
| +
|
| + if (response().output_long1 == -1) {
|
| + if (CreateInstance(IID_IAccessible, response().iaccessible_id,
|
| + reinterpret_cast<void**>(&focus_child->pdispVal)) == S_OK) {
|
| + focus_child->vt = VT_DISPATCH;
|
| + // Increment the reference count for the retrieved interface.
|
| + focus_child->pdispVal->AddRef();
|
| + } else {
|
| + return E_NOINTERFACE;
|
| + }
|
| + } else {
|
| + focus_child->vt = VT_I4;
|
| + focus_child->lVal = response().output_long1;
|
| + }
|
| +
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accHelp(VARIANT var_id, BSTR* help) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (var_id.vt != VT_I4 || !help)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCHELP, var_id, NULL,
|
| + NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code) {
|
| + // No string found.
|
| + return S_FALSE;
|
| + }
|
| +
|
| + *help = CComBSTR(response().output_string.c_str()).Detach();
|
| +
|
| + DCHECK(*help);
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accKeyboardShortcut(VARIANT var_id,
|
| + BSTR* acc_key) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (var_id.vt != VT_I4 || !acc_key)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCKEYBOARDSHORTCUT,
|
| + var_id, NULL, NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code) {
|
| + // No string found.
|
| + return S_FALSE;
|
| + }
|
| +
|
| + *acc_key = CComBSTR(response().output_string.c_str()).Detach();
|
| +
|
| + DCHECK(*acc_key);
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accName(VARIANT var_id, BSTR* name) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (var_id.vt != VT_I4 || !name)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCNAME, var_id, NULL,
|
| + NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code) {
|
| + // No string found.
|
| + return S_FALSE;
|
| + }
|
| +
|
| + *name = CComBSTR(response().output_string.c_str()).Detach();
|
| +
|
| + DCHECK(*name);
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accParent(IDispatch** disp_parent) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!disp_parent || !parent_hwnd())
|
| + return E_INVALIDARG;
|
| +
|
| + // Root node's parent is the containing HWND's IAccessible.
|
| + if (iaccessible_id() == 0) {
|
| + // For an object that has no parent (e.g. root), point the accessible parent
|
| + // to the default implementation.
|
| + HRESULT hr =
|
| + ::CreateStdAccessibleObject(parent_hwnd(), OBJID_WINDOW,
|
| + IID_IAccessible,
|
| + reinterpret_cast<void**>(disp_parent));
|
| +
|
| + if (!SUCCEEDED(hr)) {
|
| + *disp_parent = NULL;
|
| + return S_FALSE;
|
| + }
|
| + return S_OK;
|
| + }
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCPARENT, EmptyVariant(),
|
| + NULL, NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code) {
|
| + // No parent exists for this object.
|
| + return S_FALSE;
|
| + }
|
| +
|
| + // Retrieve the IUnknown interface for the parent view, and assign the
|
| + // IDispatch returned.
|
| + if (CreateInstance(IID_IAccessible, response().iaccessible_id,
|
| + reinterpret_cast<void**>(disp_parent)) == S_OK) {
|
| + // Increment the reference count for the retrieved interface.
|
| + (*disp_parent)->AddRef();
|
| + return S_OK;
|
| + } else {
|
| + return E_NOINTERFACE;
|
| + }
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accRole(VARIANT var_id, VARIANT* role) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (var_id.vt != VT_I4 || !role)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCROLE, var_id, NULL,
|
| + NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + role->vt = VT_I4;
|
| + role->lVal = response().output_long1;
|
| +
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accState(VARIANT var_id,
|
| + VARIANT* state) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (var_id.vt != VT_I4 || !state)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCSTATE, var_id, NULL,
|
| + NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + state->vt = VT_I4;
|
| + state->lVal = response().output_long1;
|
| +
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accValue(VARIANT var_id, BSTR* value) {
|
| + if (!instance_active()) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (var_id.vt != VT_I4 || !value)
|
| + return E_INVALIDARG;
|
| +
|
| + if (!RequestAccessibilityInfo(IACCESSIBLE_FUNC_GET_ACCVALUE, var_id, NULL,
|
| + NULL)) {
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!response().return_code) {
|
| + // No string found.
|
| + return S_FALSE;
|
| + }
|
| +
|
| + *value = CComBSTR(response().output_string.c_str()).Detach();
|
| +
|
| + DCHECK(*value);
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::accSelect(LONG flags_select,
|
| + VARIANT var_id) {
|
| + return DISP_E_MEMBERNOTFOUND;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accHelpTopic(BSTR* help_file,
|
| + VARIANT var_id,
|
| + LONG* topic_id) {
|
| + if (help_file) {
|
| + *help_file = NULL;
|
| + }
|
| + if (topic_id) {
|
| + *topic_id = static_cast<LONG>(-1);
|
| + }
|
| + return DISP_E_MEMBERNOTFOUND;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_accSelection(VARIANT* selected) {
|
| + if (selected)
|
| + selected->vt = VT_EMPTY;
|
| +
|
| + return DISP_E_MEMBERNOTFOUND;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::put_accName(VARIANT var_id, BSTR put_name) {
|
| + return DISP_E_MEMBERNOTFOUND;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::put_accValue(VARIANT var_id, BSTR put_val) {
|
| + return DISP_E_MEMBERNOTFOUND;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::CreateInstance(REFIID iid,
|
| + int iaccessible_id,
|
| + void** interface_ptr) {
|
| + return BrowserAccessibilityManager::Instance()->CreateAccessibilityInstance(
|
| + iid, iaccessible_id, instance_id(), interface_ptr);
|
| +}
|
| +
|
| +bool BrowserAccessibility::RequestAccessibilityInfo(int iaccessible_func_id,
|
| + VARIANT var_id, LONG input1,
|
| + LONG input2) {
|
| + return BrowserAccessibilityManager::Instance()->RequestAccessibilityInfo(
|
| + iaccessible_id(), instance_id(), iaccessible_func_id, var_id, input1,
|
| + input2);
|
| +}
|
| +
|
| +ViewHostMsg_Accessibility_Out_Params BrowserAccessibility::response() {
|
| + return BrowserAccessibilityManager::Instance()->response();
|
| +}
|
| +
|
| +HWND BrowserAccessibility::parent_hwnd() {
|
| + return BrowserAccessibilityManager::Instance()->parent_hwnd(instance_id());
|
| +}
|
| +
|
|
|
| Property changes on: chrome\browser\browser_accessibility.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|