| Index: chrome/browser/browser_accessibility.cc
|
| ===================================================================
|
| --- chrome/browser/browser_accessibility.cc (revision 46908)
|
| +++ chrome/browser/browser_accessibility.cc (working copy)
|
| @@ -1,4 +1,4 @@
|
| -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| +// Copyright (c) 2010 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.
|
|
|
| @@ -9,134 +9,159 @@
|
|
|
| using webkit_glue::WebAccessibility;
|
|
|
| -HRESULT BrowserAccessibility::Initialize(int iaccessible_id, int routing_id,
|
| - int process_id, HWND parent_hwnd) {
|
| - // Check input parameters. Root id is 1000, to avoid conflicts with the ids
|
| - // used by MSAA.
|
| - if (!parent_hwnd || iaccessible_id < 1000)
|
| - return E_INVALIDARG;
|
| +BrowserAccessibility::BrowserAccessibility()
|
| + : manager_(NULL),
|
| + parent_(NULL),
|
| + child_id_(-1),
|
| + index_in_parent_(-1),
|
| + renderer_id_(-1),
|
| + instance_active_(false) {
|
| +}
|
|
|
| - iaccessible_id_ = iaccessible_id;
|
| - routing_id_ = routing_id;
|
| - process_id_ = process_id;
|
| - parent_hwnd_ = parent_hwnd;
|
| +BrowserAccessibility::~BrowserAccessibility() {
|
| + InactivateTree();
|
| +}
|
|
|
| - // Mark instance as active.
|
| +void BrowserAccessibility::Initialize(
|
| + BrowserAccessibilityManager* manager,
|
| + BrowserAccessibility* parent,
|
| + LONG child_id,
|
| + LONG index_in_parent,
|
| + const webkit_glue::WebAccessibility& src) {
|
| + manager_ = manager;
|
| + parent_ = parent;
|
| + child_id_ = child_id;
|
| + index_in_parent_ = index_in_parent;
|
| +
|
| + renderer_id_ = src.id;
|
| + name_ = src.name;
|
| + value_ = src.value;
|
| + action_ = src.action;
|
| + description_ = src.description;
|
| + help_ = src.help;
|
| + shortcut_ = src.shortcut;
|
| + role_ = MSAARole(src.role);
|
| + state_ = MSAAState(src.state);
|
| + location_ = src.location;
|
| +
|
| instance_active_ = true;
|
| - return S_OK;
|
| +
|
| + // Focused is a dynamic state, only one node will be focused at a time.
|
| + state_ &= ~STATE_SYSTEM_FOCUSED;
|
| }
|
|
|
| -HRESULT BrowserAccessibility::accDoDefaultAction(VARIANT var_id) {
|
| - if (!instance_active()) {
|
| - // Instance no longer active, fail gracefully.
|
| - // TODO(ctguil): Once we have MSAA events, change these fails to having
|
| - // BrowserAccessibilityManager firing the right event.
|
| - return E_FAIL;
|
| - }
|
| +void BrowserAccessibility::AddChild(BrowserAccessibility* child) {
|
| + children_.push_back(child);
|
| +}
|
|
|
| - if (var_id.vt != VT_I4)
|
| - return E_INVALIDARG;
|
| +void BrowserAccessibility::InactivateTree() {
|
| + // Mark this object as inactive, so calls to all COM methods will return
|
| + // failure.
|
| + instance_active_ = false;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_DODEFAULTACTION,
|
| - var_id, NULL, NULL)) {
|
| - return E_FAIL;
|
| + // Now we can safely call InactivateTree on our children and remove
|
| + // references to them, so that as much of the tree as possible will be
|
| + // destroyed now - however, nodes that still have references to them
|
| + // might stick around a while until all clients have released them.
|
| + for (std::vector<BrowserAccessibility*>::iterator iter =
|
| + children_.begin();
|
| + iter != children_.end(); ++iter) {
|
| + (*iter)->InactivateTree();
|
| + (*iter)->Release();
|
| }
|
| + children_.clear();
|
| +}
|
|
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE)
|
| - return S_FALSE;
|
| +bool BrowserAccessibility::IsDescendantOf(BrowserAccessibility* ancestor) {
|
| + if (this == ancestor) {
|
| + return true;
|
| + } else if (parent_) {
|
| + return parent_->IsDescendantOf(ancestor);
|
| + }
|
|
|
| - return S_OK;
|
| + return false;
|
| }
|
|
|
| -STDMETHODIMP BrowserAccessibility::accHitTest(LONG x_left, LONG y_top,
|
| - VARIANT* child) {
|
| - if (!instance_active()) {
|
| - // Instance no longer active, fail gracefully.
|
| - return E_FAIL;
|
| +BrowserAccessibility* BrowserAccessibility::GetPreviousSibling() {
|
| + if (parent_ && index_in_parent_ > 0)
|
| + return parent_->children_[index_in_parent_ - 1];
|
| +
|
| + return NULL;
|
| +}
|
| +
|
| +BrowserAccessibility* BrowserAccessibility::GetNextSibling() {
|
| + if (parent_ &&
|
| + index_in_parent_ < static_cast<int>(parent_->children_.size() - 1)) {
|
| + return parent_->children_[index_in_parent_ + 1];
|
| }
|
|
|
| - if (!child)
|
| - return E_INVALIDARG;
|
| + return NULL;
|
| +}
|
|
|
| - if (!parent_hwnd_) {
|
| - // Parent HWND needed for coordinate conversion.
|
| +BrowserAccessibility* BrowserAccessibility::NewReference() {
|
| + AddRef();
|
| + return this;
|
| +}
|
| +
|
| +//
|
| +// IAccessible methods.
|
| +//
|
| +
|
| +HRESULT BrowserAccessibility::accDoDefaultAction(VARIANT var_id) {
|
| + if (!instance_active_) {
|
| + // Instance no longer active, fail gracefully.
|
| 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);
|
| + return E_NOTIMPL;
|
| +}
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_HITTEST,
|
| - ChildSelfVariant(), p.x, p.y)) {
|
| +STDMETHODIMP BrowserAccessibility::accHitTest(LONG x_left, LONG y_top,
|
| + VARIANT* child) {
|
| + if (!instance_active_) {
|
| + // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
|
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE) {
|
| - // The point is outside of the object's boundaries.
|
| - child->vt = VT_EMPTY;
|
| - return S_FALSE;
|
| - }
|
| + if (!child)
|
| + return E_INVALIDARG;
|
|
|
| - if (response().output_long1 == -1) {
|
| - if (CreateInstance(IID_IAccessible, response().object_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;
|
| + return E_NOTIMPL;
|
| }
|
|
|
| STDMETHODIMP BrowserAccessibility::accLocation(LONG* x_left, LONG* y_top,
|
| LONG* width, LONG* height,
|
| VARIANT var_id) {
|
| - if (!instance_active()) {
|
| + 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_) {
|
| + if (!x_left || !y_top || !width || !height)
|
| return E_INVALIDARG;
|
| - }
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_LOCATION, var_id,
|
| - NULL, NULL)) {
|
| - return E_FAIL;
|
| - }
|
| + BrowserAccessibility* target = GetTargetFromChildID(var_id);
|
| + if (!target)
|
| + return E_INVALIDARG;
|
|
|
| - 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);
|
| + HWND parent_hwnd = manager_->GetParentHWND();
|
| + POINT top_left = {0, 0};
|
| + ::ClientToScreen(parent_hwnd, &top_left);
|
|
|
| - *x_left = response().output_long1 + top_left.x;
|
| - *y_top = response().output_long2 + top_left.y;
|
| + *x_left = target->location_.x + top_left.x;
|
| + *y_top = target->location_.y + top_left.y;
|
| + *width = target->location_.width;
|
| + *height = target->location_.height;
|
|
|
| - *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)
|
| +STDMETHODIMP BrowserAccessibility::accNavigate(
|
| + LONG nav_dir, VARIANT start, VARIANT* end) {
|
| + BrowserAccessibility* target = GetTargetFromChildID(start);
|
| + if (!target)
|
| return E_INVALIDARG;
|
|
|
| if ((nav_dir == NAVDIR_LASTCHILD || nav_dir == NAVDIR_FIRSTCHILD) &&
|
| @@ -145,80 +170,62 @@
|
| 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;
|
| + BrowserAccessibility* result;
|
| + switch (nav_dir) {
|
| + case NAVDIR_DOWN:
|
| + case NAVDIR_UP:
|
| + case NAVDIR_LEFT:
|
| + case NAVDIR_RIGHT:
|
| + // These directions are not implemented, matching Mozilla and IE.
|
| + return E_NOTIMPL;
|
| + case NAVDIR_FIRSTCHILD:
|
| + if (target->children_.size() > 0)
|
| + result = target->children_[0];
|
| + break;
|
| + case NAVDIR_LASTCHILD:
|
| + if (target->children_.size() > 0)
|
| + result = target->children_[target->children_.size() - 1];
|
| + break;
|
| + case NAVDIR_NEXT:
|
| + result = target->GetNextSibling();
|
| + break;
|
| + case NAVDIR_PREVIOUS:
|
| + result = target->GetPreviousSibling();
|
| + break;
|
| }
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_NAVIGATE, start,
|
| - nav_dir, NULL)) {
|
| - return E_FAIL;
|
| - }
|
| -
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE) {
|
| - // No screen element was found in the specified direction.
|
| + if (!result) {
|
| end->vt = VT_EMPTY;
|
| return S_FALSE;
|
| }
|
|
|
| - if (response().output_long1 == -1) {
|
| - if (CreateInstance(IID_IAccessible, response().object_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;
|
| - }
|
| -
|
| + end->vt = VT_DISPATCH;
|
| + end->pdispVal = result->NewReference();
|
| return S_OK;
|
| }
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accChild(VARIANT var_child,
|
| IDispatch** disp_child) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
|
|
| - if (var_child.vt != VT_I4 || !disp_child)
|
| + if (!disp_child)
|
| return E_INVALIDARG;
|
|
|
| - // If var_child is the parent, remain with the same IDispatch.
|
| - if (var_child.lVal == CHILDID_SELF && iaccessible_id_ != 1000)
|
| - return S_OK;
|
| + *disp_child = NULL;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_GETCHILD, var_child,
|
| - NULL, NULL)) {
|
| - return E_FAIL;
|
| - }
|
| + BrowserAccessibility* target = GetTargetFromChildID(var_child);
|
| + if (!target)
|
| + return E_INVALIDARG;
|
|
|
| - // TODO(ctguil): Figure out when the return code would be false
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE) {
|
| - // 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().object_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;
|
| - }
|
| + (*disp_child) = target->NewReference();
|
| + return S_OK;
|
| }
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accChildCount(LONG* child_count) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
| @@ -226,36 +233,29 @@
|
| if (!child_count)
|
| return E_INVALIDARG;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_CHILDCOUNT,
|
| - ChildSelfVariant(), NULL, NULL)) {
|
| - return E_FAIL;
|
| - }
|
| -
|
| - *child_count = response().output_long1;
|
| + *child_count = children_.size();
|
| return S_OK;
|
| }
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accDefaultAction(VARIANT var_id,
|
| BSTR* def_action) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
|
|
| - if (var_id.vt != VT_I4 || !def_action)
|
| + if (!def_action)
|
| return E_INVALIDARG;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_DEFAULTACTION,
|
| - var_id, NULL, NULL)) {
|
| - return E_FAIL;
|
| - }
|
| + BrowserAccessibility* target = GetTargetFromChildID(var_id);
|
| + if (!target)
|
| + return E_INVALIDARG;
|
|
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE) {
|
| - // No string found.
|
| + // Return false if the string is empty.
|
| + if (target->action_.size() == 0)
|
| return S_FALSE;
|
| - }
|
|
|
| - *def_action = SysAllocString(response().output_string.c_str());
|
| + *def_action = SysAllocString(target->action_.c_str());
|
|
|
| DCHECK(*def_action);
|
| return S_OK;
|
| @@ -263,32 +263,30 @@
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accDescription(VARIANT var_id,
|
| BSTR* desc) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
|
|
| - if (var_id.vt != VT_I4 || !desc)
|
| + if (!desc)
|
| return E_INVALIDARG;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_DESCRIPTION, var_id,
|
| - NULL, NULL)) {
|
| - return E_FAIL;
|
| - }
|
| + BrowserAccessibility* target = GetTargetFromChildID(var_id);
|
| + if (!target)
|
| + return E_INVALIDARG;
|
|
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE) {
|
| - // No string found.
|
| + // Return false if the string is empty.
|
| + if (target->description_.size() == 0)
|
| return S_FALSE;
|
| - }
|
|
|
| - *desc = SysAllocString(response().output_string.c_str());
|
| + *desc = SysAllocString(target->description_.c_str());
|
|
|
| DCHECK(*desc);
|
| return S_OK;
|
| }
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accFocus(VARIANT* focus_child) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
| @@ -296,55 +294,38 @@
|
| if (!focus_child)
|
| return E_INVALIDARG;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_GETFOCUSEDCHILD,
|
| - ChildSelfVariant(), NULL, NULL)) {
|
| - return E_FAIL;
|
| - }
|
| -
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE) {
|
| - // The window that contains this object is not the active window.
|
| + BrowserAccessibility* focus = manager_->GetFocus(this);
|
| + if (focus == this) {
|
| + focus_child->vt = VT_I4;
|
| + focus_child->lVal = CHILDID_SELF;
|
| + } else if (focus == NULL) {
|
| focus_child->vt = VT_EMPTY;
|
| - return S_FALSE;
|
| - }
|
| -
|
| - if (response().output_long1 == -1) {
|
| - if (CreateInstance(IID_IAccessible, response().object_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;
|
| + focus_child->vt = VT_DISPATCH;
|
| + focus_child->pdispVal = focus->NewReference();
|
| }
|
|
|
| return S_OK;
|
| }
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accHelp(VARIANT var_id, BSTR* help) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
|
|
| - if (var_id.vt != VT_I4 || !help)
|
| + if (!help)
|
| return E_INVALIDARG;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_HELPTEXT, var_id,
|
| - NULL, NULL)) {
|
| - return E_FAIL;
|
| - }
|
| + BrowserAccessibility* target = GetTargetFromChildID(var_id);
|
| + if (!target)
|
| + return E_INVALIDARG;
|
|
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE ||
|
| - response().output_string.empty()) {
|
| - // No string found.
|
| + // Return false if the string is empty.
|
| + if (target->help_.size() == 0)
|
| return S_FALSE;
|
| - }
|
|
|
| - *help = SysAllocString(response().output_string.c_str());
|
| + *help = SysAllocString(target->help_.c_str());
|
|
|
| DCHECK(*help);
|
| return S_OK;
|
| @@ -352,163 +333,127 @@
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accKeyboardShortcut(VARIANT var_id,
|
| BSTR* acc_key) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
|
|
| - if (var_id.vt != VT_I4 || !acc_key)
|
| + if (!acc_key)
|
| return E_INVALIDARG;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_KEYBOARDSHORTCUT,
|
| - var_id, NULL, NULL)) {
|
| - return E_FAIL;
|
| - }
|
| + BrowserAccessibility* target = GetTargetFromChildID(var_id);
|
| + if (!target)
|
| + return E_INVALIDARG;
|
|
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE) {
|
| - // No string found.
|
| + // Return false if the string is empty.
|
| + if (target->shortcut_.size() == 0)
|
| return S_FALSE;
|
| - }
|
|
|
| - *acc_key = SysAllocString(response().output_string.c_str());
|
| + *acc_key = SysAllocString(target->shortcut_.c_str());
|
|
|
| DCHECK(*acc_key);
|
| return S_OK;
|
| }
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accName(VARIANT var_id, BSTR* name) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
|
|
| - if (var_id.vt != VT_I4 || !name)
|
| + if (!name)
|
| return E_INVALIDARG;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_NAME, var_id, NULL,
|
| - NULL)) {
|
| - return E_FAIL;
|
| - }
|
| + BrowserAccessibility* target = GetTargetFromChildID(var_id);
|
| + if (!target)
|
| + return E_INVALIDARG;
|
|
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE) {
|
| - // No string found.
|
| + // Return false if the string is empty.
|
| + if (target->name_.size() == 0)
|
| return S_FALSE;
|
| - }
|
|
|
| - *name = SysAllocString(response().output_string.c_str());
|
| + *name = SysAllocString(target->name_.c_str());
|
|
|
| DCHECK(*name);
|
| return S_OK;
|
| }
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accParent(IDispatch** disp_parent) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
|
|
| - if (!disp_parent || !parent_hwnd_)
|
| + if (!disp_parent)
|
| return E_INVALIDARG;
|
|
|
| - // Root node's parent is the containing HWND's IAccessible.
|
| - if (iaccessible_id_ == 1000) {
|
| - // 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;
|
| + IAccessible* parent = parent_;
|
| + if (parent == NULL) {
|
| + // This happens if we're the root of the tree;
|
| + // return the IAccessible for the window.
|
| + parent = manager_->GetParentWindowIAccessible();
|
| }
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_GETPARENT,
|
| - ChildSelfVariant(), NULL, NULL)) {
|
| - return E_FAIL;
|
| - }
|
| -
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE) {
|
| - // 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().object_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;
|
| - }
|
| + parent->AddRef();
|
| + *disp_parent = parent;
|
| + return S_OK;
|
| }
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accRole(VARIANT var_id, VARIANT* role) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
|
|
| - if (var_id.vt != VT_I4 || !role)
|
| + if (!role)
|
| return E_INVALIDARG;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_ROLE, var_id, NULL,
|
| - NULL)) {
|
| - return E_FAIL;
|
| - }
|
| + BrowserAccessibility* target = GetTargetFromChildID(var_id);
|
| + if (!target)
|
| + return E_INVALIDARG;
|
|
|
| role->vt = VT_I4;
|
| - role->lVal = MSAARole(response().output_long1);
|
| + role->lVal = target->role_;
|
| return S_OK;
|
| }
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accState(VARIANT var_id,
|
| VARIANT* state) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
|
|
| - if (var_id.vt != VT_I4 || !state)
|
| + if (!state)
|
| return E_INVALIDARG;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_STATE, var_id, NULL,
|
| - NULL)) {
|
| - return E_FAIL;
|
| - }
|
| + BrowserAccessibility* target = GetTargetFromChildID(var_id);
|
| + if (!target)
|
| + return E_INVALIDARG;
|
|
|
| state->vt = VT_I4;
|
| - state->lVal = MSAAState(response().output_long1);
|
| + state->lVal = target->state_;
|
| + if (manager_->GetFocus(NULL) == this)
|
| + state->lVal |= STATE_SYSTEM_FOCUSED;
|
| +
|
| return S_OK;
|
| }
|
|
|
| STDMETHODIMP BrowserAccessibility::get_accValue(VARIANT var_id, BSTR* value) {
|
| - if (!instance_active()) {
|
| + if (!instance_active_) {
|
| // Instance no longer active, fail gracefully.
|
| return E_FAIL;
|
| }
|
|
|
| - if (var_id.vt != VT_I4 || !value)
|
| + if (!value)
|
| return E_INVALIDARG;
|
|
|
| - if (!RequestAccessibilityInfo(WebAccessibility::FUNCTION_VALUE, var_id, NULL,
|
| - NULL)) {
|
| - return E_FAIL;
|
| - }
|
| + BrowserAccessibility* target = GetTargetFromChildID(var_id);
|
| + if (!target)
|
| + return E_INVALIDARG;
|
|
|
| - if (response().return_code == WebAccessibility::RETURNCODE_FALSE ||
|
| - response().output_string.empty()) {
|
| - // No string found.
|
| - return S_FALSE;
|
| - }
|
| + *value = SysAllocString(target->value_.c_str());
|
|
|
| - *value = SysAllocString(response().output_string.c_str());
|
| -
|
| DCHECK(*value);
|
| return S_OK;
|
| }
|
| @@ -516,54 +461,136 @@
|
| STDMETHODIMP BrowserAccessibility::get_accHelpTopic(BSTR* help_file,
|
| VARIANT var_id,
|
| LONG* topic_id) {
|
| - if (help_file)
|
| - *help_file = NULL;
|
| + return E_NOTIMPL;
|
| +}
|
|
|
| - if (topic_id)
|
| - *topic_id = static_cast<LONG>(-1);
|
| +STDMETHODIMP BrowserAccessibility::get_accSelection(VARIANT* selected) {
|
| + if (!instance_active_) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
|
|
| return E_NOTIMPL;
|
| }
|
|
|
| -STDMETHODIMP BrowserAccessibility::get_accSelection(VARIANT* selected) {
|
| - if (selected)
|
| - selected->vt = VT_EMPTY;
|
| +STDMETHODIMP BrowserAccessibility::accSelect(LONG flags_sel, VARIANT var_id) {
|
| + if (!instance_active_) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
|
|
| return E_NOTIMPL;
|
| }
|
|
|
| -STDMETHODIMP BrowserAccessibility::CreateInstance(REFIID iid,
|
| - int iaccessible_id,
|
| - void** interface_ptr) {
|
| - return BrowserAccessibilityManager::GetInstance()->
|
| - CreateAccessibilityInstance(iid, iaccessible_id, routing_id_,
|
| - process_id_, parent_hwnd_, interface_ptr);
|
| +//
|
| +// IAccessible2 methods.
|
| +//
|
| +
|
| +STDMETHODIMP BrowserAccessibility::role(LONG* role) {
|
| + if (!instance_active_) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!role)
|
| + return E_INVALIDARG;
|
| +
|
| + *role = role_;
|
| +
|
| + return S_OK;
|
| }
|
|
|
| -bool BrowserAccessibility::RequestAccessibilityInfo(int iaccessible_func_id,
|
| - VARIANT var_id, LONG input1,
|
| - LONG input2) {
|
| - DCHECK(V_VT(&var_id) == VT_I4);
|
| +STDMETHODIMP BrowserAccessibility::get_states(AccessibleStates* states) {
|
| + if (!instance_active_) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
|
|
| - // Create and populate IPC message structure, for retrieval of accessibility
|
| - // information from the renderer.
|
| - WebAccessibility::InParams in_params;
|
| - in_params.object_id = iaccessible_id_;
|
| - in_params.function_id = iaccessible_func_id;
|
| - in_params.child_id = V_I4(&var_id);
|
| - in_params.input_long1 = input1;
|
| - in_params.input_long2 = input2;
|
| + if (!states)
|
| + return E_INVALIDARG;
|
|
|
| - return BrowserAccessibilityManager::GetInstance()->
|
| - RequestAccessibilityInfo(&in_params, routing_id_, process_id_) &&
|
| - response().return_code != WebAccessibility::RETURNCODE_FAIL;
|
| + *states = state_;
|
| +
|
| + return S_OK;
|
| }
|
|
|
| -const WebAccessibility::OutParams& BrowserAccessibility::response() {
|
| - return BrowserAccessibilityManager::GetInstance()->response();
|
| +STDMETHODIMP BrowserAccessibility::get_uniqueID(LONG* unique_id) {
|
| + if (!instance_active_) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!unique_id)
|
| + return E_INVALIDARG;
|
| +
|
| + *unique_id = child_id_;
|
| + return S_OK;
|
| }
|
|
|
| -long BrowserAccessibility::MSAARole(long browser_accessibility_role) {
|
| +STDMETHODIMP BrowserAccessibility::get_windowHandle(HWND* window_handle) {
|
| + if (!instance_active_) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!window_handle)
|
| + return E_INVALIDARG;
|
| +
|
| + *window_handle = manager_->GetParentHWND();
|
| + return S_OK;
|
| +}
|
| +
|
| +STDMETHODIMP BrowserAccessibility::get_indexInParent(LONG* index_in_parent) {
|
| + if (!instance_active_) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (!index_in_parent)
|
| + return E_INVALIDARG;
|
| +
|
| + *index_in_parent = index_in_parent_;
|
| + return S_OK;
|
| +}
|
| +
|
| +//
|
| +// IServiceProvider methods.
|
| +//
|
| +
|
| +STDMETHODIMP BrowserAccessibility::QueryService(
|
| + REFGUID guidService, REFIID riid, void** object) {
|
| + if (!instance_active_) {
|
| + // Instance no longer active, fail gracefully.
|
| + return E_FAIL;
|
| + }
|
| +
|
| + if (guidService == IID_IAccessible || guidService == IID_IAccessible2)
|
| + return QueryInterface(riid, object);
|
| +
|
| + *object = NULL;
|
| + return E_FAIL;
|
| +}
|
| +
|
| +//
|
| +// Private methods.
|
| +//
|
| +
|
| +BrowserAccessibility* BrowserAccessibility::GetTargetFromChildID(
|
| + const VARIANT& var_id) {
|
| + if (var_id.vt != VT_I4)
|
| + return NULL;
|
| +
|
| + LONG child_id = var_id.lVal;
|
| + if (child_id == CHILDID_SELF)
|
| + return this;
|
| +
|
| + if (child_id >= 1 && child_id <= static_cast<LONG>(children_.size()))
|
| + return children_[child_id - 1];
|
| +
|
| + return manager_->GetFromChildID(child_id);
|
| +}
|
| +
|
| +LONG BrowserAccessibility::MSAARole(LONG browser_accessibility_role) {
|
| switch (browser_accessibility_role) {
|
| case WebAccessibility::ROLE_APPLICATION:
|
| return ROLE_SYSTEM_APPLICATION;
|
| @@ -631,8 +658,8 @@
|
| }
|
| }
|
|
|
| -long BrowserAccessibility::MSAAState(long browser_accessibility_state) {
|
| - long state = 0;
|
| +LONG BrowserAccessibility::MSAAState(LONG browser_accessibility_state) {
|
| + LONG state = 0;
|
|
|
| if ((browser_accessibility_state >> WebAccessibility::STATE_CHECKED) & 1)
|
| state |= STATE_SYSTEM_CHECKED;
|
|
|