summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/accessibility_win_browsertest.cc131
-rw-r--r--chrome/test/interactive_ui/interactive_ui_tests.gypi1
-rw-r--r--views/accessibility/view_accessibility.cc9
3 files changed, 135 insertions, 6 deletions
diff --git a/chrome/browser/accessibility_win_browsertest.cc b/chrome/browser/accessibility_win_browsertest.cc
index 138fab9..9d17796 100644
--- a/chrome/browser/accessibility_win_browsertest.cc
+++ b/chrome/browser/accessibility_win_browsertest.cc
@@ -14,6 +14,7 @@
#include "chrome/common/notification_type.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
+#include "ia2_api_all.h" // Generated
using std::auto_ptr;
using std::vector;
@@ -130,7 +131,7 @@ IAccessible* GetAccessibleFromResultVariant(IAccessible* parent, VARIANT *var) {
case VT_I4: {
CComPtr<IDispatch> dispatch;
HRESULT hr = parent->get_accChild(CreateI4Variant(V_I4(var)), &dispatch);
- EXPECT_EQ(hr, S_OK);
+ EXPECT_TRUE(SUCCEEDED(hr));
return CComQIPtr<IAccessible>(dispatch).Detach();
break;
}
@@ -139,6 +140,68 @@ IAccessible* GetAccessibleFromResultVariant(IAccessible* parent, VARIANT *var) {
return NULL;
}
+HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) {
+ // TODO(ctguil): For some reason querying the IAccessible2 interface from
+ // IAccessible fails.
+ ScopedComPtr<IServiceProvider> service_provider;
+ HRESULT hr = accessible->QueryInterface(service_provider.Receive());
+ if (FAILED(hr))
+ return hr;
+
+ hr = service_provider->QueryService(IID_IAccessible2, accessible2);
+ return hr;
+}
+
+// Sets result to true if the child is located in the parent's tree. An
+// exhustive search is perform here because we determine equality using
+// IAccessible2::get_uniqueID which is only supported by the child node.
+void AccessibleContainsAccessible(
+ IAccessible* parent, IAccessible2* child, bool* result) {
+ vector<ScopedComPtr<IAccessible>> accessible_list;
+ accessible_list.push_back(ScopedComPtr<IAccessible>(parent));
+
+ LONG unique_id;
+ HRESULT hr = child->get_uniqueID(&unique_id);
+ ASSERT_EQ(hr, S_OK);
+ *result = false;
+
+ while (accessible_list.size()) {
+ ScopedComPtr<IAccessible> accessible = accessible_list.back();
+ accessible_list.pop_back();
+
+ ScopedComPtr<IAccessible2> accessible2;
+ hr = QueryIAccessible2(accessible, accessible2.Receive());
+ if (SUCCEEDED(hr)) {
+ LONG child_id;
+ accessible2->get_uniqueID(&child_id);
+ if (child_id == unique_id) {
+ *result = true;
+ break;
+ }
+ }
+
+ LONG child_count;
+ hr = accessible->get_accChildCount(&child_count);
+ ASSERT_EQ(hr, S_OK);
+ if (child_count == 0)
+ continue;
+
+ auto_ptr<VARIANT> child_array(new VARIANT[child_count]);
+ LONG obtained_count = 0;
+ hr = AccessibleChildren(
+ accessible, 0, child_count, child_array.get(), &obtained_count);
+ ASSERT_EQ(hr, S_OK);
+ ASSERT_EQ(child_count, obtained_count);
+
+ for (int index = 0; index < obtained_count; index++) {
+ ScopedComPtr<IAccessible> child_accessible(
+ GetAccessibleFromResultVariant(accessible, &child_array.get()[index]));
+ if (child_accessible.get())
+ accessible_list.push_back(ScopedComPtr<IAccessible>(child_accessible));
+ }
+ }
+}
+
// Retrieve the MSAA client accessibility object for the Render Widget Host View
// of the selected tab.
IAccessible*
@@ -260,6 +323,7 @@ void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
++child_checker, ++child) {
ScopedComPtr<IAccessible> child_accessible;
child_accessible.Attach(GetAccessibleFromResultVariant(parent, child));
+ ASSERT_TRUE(child_accessible.get());
(*child_checker)->CheckAccessible(child_accessible);
}
}
@@ -400,4 +464,69 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
STATE_SYSTEM_READONLY);
document_checker.CheckAccessible(document_accessible);
}
+
+// This test verifies that browser-side cache of the renderer accessibility
+// tree is reachable from the browser's tree. Tools that analyze windows
+// accessibility trees like AccExplorer32 should be able to drill into the
+// cached renderer accessibility tree.
+IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
+ ContainsRendererAccessibilityTree) {
+ // By requesting an accessible chrome will believe a screen reader has been
+ // detected. Request and wait for the accessibility tree to be updated.
+ GURL tree_url("data:text/html,<body><input type='checkbox' /></body>");
+ browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
+ ScopedComPtr<IAccessible> document_accessible(
+ GetRenderWidgetHostViewClientAccessible());
+ ui_test_utils::WaitForNotification(
+ NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
+
+ // Get the accessibility object for the browser window.
+ HWND browser_hwnd = browser()->window()->GetNativeHandle();
+ ScopedComPtr<IAccessible> browser_accessible;
+ HRESULT hr = AccessibleObjectFromWindow(
+ browser_hwnd,
+ OBJID_WINDOW,
+ IID_IAccessible,
+ reinterpret_cast<void**>(browser_accessible.Receive()));
+ ASSERT_EQ(S_OK, hr);
+
+ // Get the accessibility object for the renderer client document.
+ document_accessible = GetRenderWidgetHostViewClientAccessible();
+ ScopedComPtr<IAccessible2> document_accessible2;
+ hr = QueryIAccessible2(document_accessible, document_accessible2.Receive());
+ ASSERT_EQ(S_OK, hr);
+
+ // TODO(ctguil): Pointer comparison of retrieved IAccessible pointers dosen't
+ // seem to work for here. Perhaps make IAccessible2 available in views to make
+ // unique id comparison available.
+ bool found = false;
+ ScopedComPtr<IAccessible> parent = document_accessible;
+ while (parent.get()) {
+ ScopedComPtr<IDispatch> parent_dispatch;
+ hr = parent->get_accParent(parent_dispatch.Receive());
+ ASSERT_TRUE(SUCCEEDED(hr));
+ if (!parent_dispatch.get()) {
+ ASSERT_EQ(hr, S_FALSE);
+ break;
+ }
+
+ parent.Release();
+ hr = parent_dispatch.QueryInterface(parent.Receive());
+ ASSERT_EQ(S_OK, hr);
+
+ if (parent.get() == browser_accessible.get()) {
+ found = true;
+ break;
+ }
+ }
+
+ // If pointer comparison fails resort to the exhuasive search that can use
+ // IAccessible2::get_uniqueID for equality comparison.
+ if (!found) {
+ AccessibleContainsAccessible(
+ browser_accessible, document_accessible2, &found);
+ }
+
+ ASSERT_EQ(found, true);
+}
} // namespace.
diff --git a/chrome/test/interactive_ui/interactive_ui_tests.gypi b/chrome/test/interactive_ui/interactive_ui_tests.gypi
index 856e043..c07e74c 100644
--- a/chrome/test/interactive_ui/interactive_ui_tests.gypi
+++ b/chrome/test/interactive_ui/interactive_ui_tests.gypi
@@ -116,6 +116,7 @@
'<(DEPTH)/chrome/chrome.gyp:crash_service', # run time dependency
'<(DEPTH)/chrome/chrome.gyp:installer_util_strings',
'<(DEPTH)/sandbox/sandbox.gyp:sandbox',
+ '<(DEPTH)/third_party/iaccessible2/iaccessible2.gyp:iaccessible2',
],
'sources': [
'<(DEPTH)/webkit/glue/resources/aliasb.cur',
diff --git a/views/accessibility/view_accessibility.cc b/views/accessibility/view_accessibility.cc
index 5ed0c99..46f2e56 100644
--- a/views/accessibility/view_accessibility.cc
+++ b/views/accessibility/view_accessibility.cc
@@ -290,11 +290,6 @@ STDMETHODIMP ViewAccessibility::get_accChild(VARIANT var_child,
// Check to see if child is out-of-bounds.
if (IsValidChild((var_child.lVal - 1), view_)) {
child_view = view_->GetChildViewAt(var_child.lVal - 1);
-
- // Parents handle leaf IAccessible's.
- if (child_view && child_view->GetChildViewCount() == 0 &&
- !child_view->child_widget())
- return S_FALSE;
} else {
// Child is located elsewhere in this view's subtree.
// Positive child id's are 1-based indexes so you can iterate over all
@@ -335,6 +330,10 @@ STDMETHODIMP ViewAccessibility::get_accChild(VARIANT var_child,
}
}
+ // Parents handle leaf IAccessible's.
+ if (child_view->GetChildViewCount() == 0)
+ return S_FALSE;
+
// Finally, try our ViewAccessibility implementation.
// Retrieve the IUnknown interface for the requested child view, and
// assign the IDispatch returned.