diff options
author | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-10 05:41:23 +0000 |
---|---|---|
committer | ananta@chromium.org <ananta@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-10 05:41:23 +0000 |
commit | a64f3390904e06e4ee06203bcd03055e77dbde12 (patch) | |
tree | 09686f3874743f0e1ee5c6e027f48a31da4d5735 /views/accessibility | |
parent | b5f4cc278286dd1b0f7d9fb98d2c3554de325f0c (diff) | |
download | chromium_src-a64f3390904e06e4ee06203bcd03055e77dbde12.zip chromium_src-a64f3390904e06e4ee06203bcd03055e77dbde12.tar.gz chromium_src-a64f3390904e06e4ee06203bcd03055e77dbde12.tar.bz2 |
Accessibility information from the renderer was not being returned to tools like screen readers, etc.
This was because the object implementing the root IAccessible interface did not know how to navigate
a native render view. To work around this, we now check if the underlying view is a native view in
our root IAccessible::get_accChild function and if yes we send the WM_GETOBJECT message to the
corresponding RenderWidgetHostViewWin class, which returns an IAccessible interface which then can
expose information from the renderer.
The other changes in the accessibility code are for some crashes I observed while testing the
screen readers like nvda, the Windows screen reader which send a flurry of WM_GETOBJECT messages
leading to some race conditions.
We also ensure that the accessibility information for a view is torn down when the view is destroyed.
Fixes portions of http://code.google.com/p/chromium/issues/detail?id=13291
Bug=13291
Review URL: http://codereview.chromium.org/261044
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28655 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views/accessibility')
-rw-r--r-- | views/accessibility/view_accessibility.cc | 81 | ||||
-rw-r--r-- | views/accessibility/view_accessibility.h | 9 | ||||
-rw-r--r-- | views/accessibility/view_accessibility_wrapper.cc | 14 | ||||
-rw-r--r-- | views/accessibility/view_accessibility_wrapper.h | 2 |
4 files changed, 105 insertions, 1 deletions
diff --git a/views/accessibility/view_accessibility.cc b/views/accessibility/view_accessibility.cc index 03d03bb..0b8f4af 100644 --- a/views/accessibility/view_accessibility.cc +++ b/views/accessibility/view_accessibility.cc @@ -7,6 +7,13 @@ #include "views/accessibility/view_accessibility_wrapper.h" #include "views/widget/widget.h" +const wchar_t kViewsUninitializeAccessibilityInstance[] = + L"Views_Uninitialize_AccessibilityInstance"; + +const wchar_t kViewsNativeHostPropForAccessibility[] = + L"Views_NativeViewHostHWNDForAccessibility"; + + HRESULT ViewAccessibility::Initialize(views::View* view) { if (!view) { return E_INVALIDARG; @@ -23,6 +30,10 @@ STDMETHODIMP ViewAccessibility::accHitTest(LONG x_left, LONG y_top, return E_INVALIDARG; } + if (!view_) { + return E_FAIL; + } + gfx::Point pt(x_left, y_top); views::View::ConvertPointToView(NULL, view_, &pt); @@ -82,6 +93,10 @@ STDMETHODIMP ViewAccessibility::accLocation(LONG* x_left, LONG* y_top, return E_INVALIDARG; } + if (!view_) { + return E_FAIL; + } + gfx::Rect view_bounds; // Retrieving the parent View to be used for converting from view-to-screen // coordinates. @@ -126,6 +141,10 @@ STDMETHODIMP ViewAccessibility::accNavigate(LONG nav_dir, VARIANT start, return E_INVALIDARG; } + if (!view_) { + return E_FAIL; + } + switch (nav_dir) { case NAVDIR_FIRSTCHILD: case NAVDIR_LASTCHILD: { @@ -181,7 +200,7 @@ STDMETHODIMP ViewAccessibility::accNavigate(LONG nav_dir, VARIANT start, // Check navigation bounds, adjusting for View child indexing (MSAA // child indexing starts with 1, whereas View indexing starts with 0). if (!IsValidNav(nav_dir, view_index, -1, - parent->GetChildViewCount())) { + parent->GetChildViewCount() - 1)) { // Navigation attempted to go out-of-bounds. end->vt = VT_EMPTY; return S_FALSE; @@ -261,6 +280,10 @@ STDMETHODIMP ViewAccessibility::get_accChild(VARIANT var_child, return S_OK; } + if (!view_) { + return E_FAIL; + } + views::View* child_view = NULL; bool get_iaccessible = false; @@ -293,6 +316,12 @@ STDMETHODIMP ViewAccessibility::get_accChild(VARIANT var_child, return E_NOINTERFACE; } } else { + if (child_view->GetClassName() == views::NativeViewHost::kViewClassName) { + views::NativeViewHost* native_host = + static_cast<views::NativeViewHost*>(child_view); + if (GetNativeIAccessibleInterface(native_host, disp_child) == S_OK) + return S_OK; + } // When at a leaf, children are handled by the parent object. *disp_child = NULL; return S_FALSE; @@ -304,6 +333,10 @@ STDMETHODIMP ViewAccessibility::get_accChildCount(LONG* child_count) { return E_INVALIDARG; } + if (!view_) { + return E_FAIL; + } + *child_count = view_->GetChildViewCount(); return S_OK; } @@ -314,6 +347,10 @@ STDMETHODIMP ViewAccessibility::get_accDefaultAction(VARIANT var_id, return E_INVALIDARG; } + if (!view_) { + return E_FAIL; + } + std::wstring temp_action; if (var_id.lVal == CHILDID_SELF) { @@ -363,6 +400,10 @@ STDMETHODIMP ViewAccessibility::get_accFocus(VARIANT* focus_child) { return E_INVALIDARG; } + if (!view_) { + return E_FAIL; + } + if (view_->GetChildViewCount() == 0 && view_->HasFocus()) { // Parent view has focus. focus_child->vt = VT_I4; @@ -401,6 +442,10 @@ STDMETHODIMP ViewAccessibility::get_accKeyboardShortcut(VARIANT var_id, return E_INVALIDARG; } + if (!view_) { + return E_FAIL; + } + std::wstring temp_key; if (var_id.lVal == CHILDID_SELF) { @@ -426,6 +471,10 @@ STDMETHODIMP ViewAccessibility::get_accName(VARIANT var_id, BSTR* name) { return E_INVALIDARG; } + if (!view_) { + return E_FAIL; + } + std::wstring temp_name; if (var_id.lVal == CHILDID_SELF) { @@ -454,6 +503,10 @@ STDMETHODIMP ViewAccessibility::get_accParent(IDispatch** disp_parent) { return E_INVALIDARG; } + if (!view_) { + return E_FAIL; + } + views::View* parent_view = view_->GetParent(); if (!parent_view) { @@ -705,6 +758,32 @@ STDMETHODIMP ViewAccessibility::put_accName(VARIANT var_id, BSTR put_name) { } STDMETHODIMP ViewAccessibility::put_accValue(VARIANT var_id, BSTR put_val) { + if (V_VT(&var_id) == VT_BSTR) { + if (!lstrcmpi(var_id.bstrVal, kViewsUninitializeAccessibilityInstance)) { + view_ = NULL; + return S_OK; + } + } // Deprecated. return E_NOTIMPL; } + +HRESULT ViewAccessibility::GetNativeIAccessibleInterface( + views::NativeViewHost* native_host, IDispatch** disp_child) { + if (!native_host || !disp_child) { + return E_INVALIDARG; + } + + HWND render_view_window = + static_cast<HWND>(GetProp(native_host->native_view(), + kViewsNativeHostPropForAccessibility)); + + if (IsWindow(render_view_window)) { + LRESULT ret = SendMessage(render_view_window, WM_GETOBJECT, 0, + OBJID_CLIENT); + return ObjectFromLresult(ret, IID_IDispatch, 0, + reinterpret_cast<void**>(disp_child)); + } + + return E_FAIL; +} diff --git a/views/accessibility/view_accessibility.h b/views/accessibility/view_accessibility.h index bc1c26f..57eb45d 100644 --- a/views/accessibility/view_accessibility.h +++ b/views/accessibility/view_accessibility.h @@ -10,6 +10,7 @@ #include <oleacc.h> +#include "views/controls/native/native_view_host.h" #include "views/view.h" //////////////////////////////////////////////////////////////////////////////// @@ -135,10 +136,18 @@ class ATL_NO_VTABLE ViewAccessibility // to MSAA states set. long MSAAState(AccessibilityTypes::State state); + // Returns the IAccessible interface for a native view if applicable. + // Returns S_OK on success. + HRESULT GetNativeIAccessibleInterface(views::NativeViewHost* native_host, + IDispatch** disp_child); + // Member View needed for view-specific calls. views::View* view_; DISALLOW_EVIL_CONSTRUCTORS(ViewAccessibility); }; +extern const wchar_t kViewsUninitializeAccessibilityInstance[]; +extern const wchar_t kViewsNativeHostPropForAccessibility[]; + #endif // VIEWS_ACCESSIBILITY_VIEW_ACCESSIBILITY_H_ diff --git a/views/accessibility/view_accessibility_wrapper.cc b/views/accessibility/view_accessibility_wrapper.cc index 7e7f5a6..989c90a 100644 --- a/views/accessibility/view_accessibility_wrapper.cc +++ b/views/accessibility/view_accessibility_wrapper.cc @@ -4,6 +4,8 @@ #include "views/accessibility/view_accessibility_wrapper.h" +#include "base/scoped_variant_win.h" + #include "views/accessibility/view_accessibility.h" //////////////////////////////////////////////////////////////////////////////// @@ -43,6 +45,18 @@ STDMETHODIMP ViewAccessibilityWrapper::CreateDefaultInstance(REFIID iid) { return E_NOINTERFACE; } +HRESULT ViewAccessibilityWrapper::Uninitialize() { + view_ = NULL; + if (accessibility_info_.get()) { + accessibility_info_->put_accValue( + ScopedVariant(kViewsUninitializeAccessibilityInstance), NULL); + ::CoDisconnectObject(accessibility_info_.get(), 0); + accessibility_info_ = NULL; + } + + return S_OK; +} + STDMETHODIMP ViewAccessibilityWrapper::GetInstance(REFIID iid, void** interface_ptr) { if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid) { diff --git a/views/accessibility/view_accessibility_wrapper.h b/views/accessibility/view_accessibility_wrapper.h index 8ea1743..619c91d 100644 --- a/views/accessibility/view_accessibility_wrapper.h +++ b/views/accessibility/view_accessibility_wrapper.h @@ -32,6 +32,8 @@ class ViewAccessibilityWrapper { STDMETHODIMP CreateDefaultInstance(REFIID iid); + HRESULT Uninitialize(); + // Returns a pointer to a specified interface on an object to which a client // currently holds an interface pointer. If pointer exists, it is reused, // otherwise a new pointer is created. Used by accessibility implementation to |