Home | History | Annotate | Download | only in accessibility
      1 // Copyright (c) 2011 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.
      4 
      5 #include <atlbase.h>
      6 #include <vector>
      7 
      8 #include "base/win/scoped_comptr.h"
      9 #include "chrome/browser/automation/ui_controls.h"
     10 #include "chrome/browser/renderer_host/render_widget_host_view_win.h"
     11 #include "chrome/browser/ui/browser.h"
     12 #include "chrome/browser/ui/browser_window.h"
     13 #include "chrome/test/in_process_browser_test.h"
     14 #include "chrome/test/ui_test_utils.h"
     15 #include "content/browser/renderer_host/render_view_host.h"
     16 #include "content/browser/tab_contents/tab_contents.h"
     17 #include "content/common/notification_type.h"
     18 #include "ia2_api_all.h"  // Generated    NOLINT
     19 #include "ISimpleDOMNode.h"  // Generated   NOLINT
     20 
     21 using std::auto_ptr;
     22 using std::vector;
     23 using std::wstring;
     24 
     25 namespace {
     26 
     27 class AccessibilityWinBrowserTest : public InProcessBrowserTest {
     28  public:
     29   AccessibilityWinBrowserTest() {}
     30 
     31   // InProcessBrowserTest
     32   void SetUpInProcessBrowserTestFixture();
     33 
     34  protected:
     35   IAccessible* GetRendererAccessible();
     36   void ExecuteScript(wstring script);
     37 };
     38 
     39 void AccessibilityWinBrowserTest::SetUpInProcessBrowserTestFixture() {
     40   // If the mouse happens to be on the document then it will have the unexpected
     41   // STATE_SYSTEM_HOTTRACKED state. Move it to a non-document location.
     42   ui_controls::SendMouseMove(0, 0);
     43 }
     44 
     45 class AccessibleChecker {
     46  public:
     47   AccessibleChecker(
     48       wstring expected_name,
     49       int32 expected_role,
     50       wstring expected_value);
     51   AccessibleChecker(
     52       wstring expected_name,
     53       wstring expected_role,
     54       wstring expected_value);
     55 
     56   // Append an AccessibleChecker that verifies accessibility information for
     57   // a child IAccessible. Order is important.
     58   void AppendExpectedChild(AccessibleChecker* expected_child);
     59 
     60   // Check that the name and role of the given IAccessible instance and its
     61   // descendants match the expected names and roles that this object was
     62   // initialized with.
     63   void CheckAccessible(IAccessible* accessible);
     64 
     65   // Set the expected value for this AccessibleChecker.
     66   void SetExpectedValue(wstring expected_value);
     67 
     68   // Set the expected state for this AccessibleChecker.
     69   void SetExpectedState(LONG expected_state);
     70 
     71  private:
     72   void CheckAccessibleName(IAccessible* accessible);
     73   void CheckAccessibleRole(IAccessible* accessible);
     74   void CheckAccessibleValue(IAccessible* accessible);
     75   void CheckAccessibleState(IAccessible* accessible);
     76   void CheckAccessibleChildren(IAccessible* accessible);
     77 
     78  private:
     79   typedef vector<AccessibleChecker*> AccessibleCheckerVector;
     80 
     81   // Expected accessible name. Checked against IAccessible::get_accName.
     82   wstring name_;
     83 
     84   // Expected accessible role. Checked against IAccessible::get_accRole.
     85   CComVariant role_;
     86 
     87   // Expected accessible value. Checked against IAccessible::get_accValue.
     88   wstring value_;
     89 
     90   // Expected accessible state. Checked against IAccessible::get_accState.
     91   LONG state_;
     92 
     93   // Expected accessible children. Checked using IAccessible::get_accChildCount
     94   // and ::AccessibleChildren.
     95   AccessibleCheckerVector children_;
     96 };
     97 
     98 VARIANT CreateI4Variant(LONG value) {
     99   VARIANT variant = {0};
    100 
    101   V_VT(&variant) = VT_I4;
    102   V_I4(&variant) = value;
    103 
    104   return variant;
    105 }
    106 
    107 IAccessible* GetAccessibleFromResultVariant(IAccessible* parent, VARIANT *var) {
    108   switch (V_VT(var)) {
    109     case VT_DISPATCH:
    110       return CComQIPtr<IAccessible>(V_DISPATCH(var)).Detach();
    111       break;
    112 
    113     case VT_I4: {
    114       CComPtr<IDispatch> dispatch;
    115       HRESULT hr = parent->get_accChild(CreateI4Variant(V_I4(var)), &dispatch);
    116       EXPECT_TRUE(SUCCEEDED(hr));
    117       return CComQIPtr<IAccessible>(dispatch).Detach();
    118       break;
    119     }
    120   }
    121 
    122   return NULL;
    123 }
    124 
    125 HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) {
    126   // TODO(ctguil): For some reason querying the IAccessible2 interface from
    127   // IAccessible fails.
    128   base::win::ScopedComPtr<IServiceProvider> service_provider;
    129   HRESULT hr = accessible->QueryInterface(service_provider.Receive());
    130   if (FAILED(hr))
    131     return hr;
    132 
    133   hr = service_provider->QueryService(IID_IAccessible2, accessible2);
    134   return hr;
    135 }
    136 
    137 // Sets result to true if the child is located in the parent's tree. An
    138 // exhustive search is perform here because we determine equality using
    139 // IAccessible2::get_unique_id which is only supported by the child node.
    140 void AccessibleContainsAccessible(
    141     IAccessible* parent, IAccessible2* child, bool* result) {
    142   vector<base::win::ScopedComPtr<IAccessible>> accessible_list;
    143   accessible_list.push_back(base::win::ScopedComPtr<IAccessible>(parent));
    144 
    145   LONG unique_id;
    146   HRESULT hr = child->get_uniqueID(&unique_id);
    147   ASSERT_EQ(S_OK, hr);
    148   *result = false;
    149 
    150   while (accessible_list.size()) {
    151     base::win::ScopedComPtr<IAccessible> accessible = accessible_list.back();
    152     accessible_list.pop_back();
    153 
    154     base::win::ScopedComPtr<IAccessible2> accessible2;
    155     hr = QueryIAccessible2(accessible, accessible2.Receive());
    156     if (SUCCEEDED(hr)) {
    157       LONG child_id;
    158       accessible2->get_uniqueID(&child_id);
    159       if (child_id == unique_id) {
    160         *result = true;
    161         break;
    162       }
    163     }
    164 
    165     LONG child_count;
    166     hr = accessible->get_accChildCount(&child_count);
    167     ASSERT_EQ(S_OK, hr);
    168     if (child_count == 0)
    169       continue;
    170 
    171     auto_ptr<VARIANT> child_array(new VARIANT[child_count]);
    172     LONG obtained_count = 0;
    173     hr = AccessibleChildren(
    174         accessible, 0, child_count, child_array.get(), &obtained_count);
    175     ASSERT_EQ(S_OK, hr);
    176     ASSERT_EQ(child_count, obtained_count);
    177 
    178     for (int index = 0; index < obtained_count; index++) {
    179       base::win::ScopedComPtr<IAccessible> child_accessible(
    180         GetAccessibleFromResultVariant(accessible, &child_array.get()[index]));
    181       if (child_accessible.get()) {
    182         accessible_list.push_back(
    183             base::win::ScopedComPtr<IAccessible>(child_accessible));
    184       }
    185     }
    186   }
    187 }
    188 
    189 // Retrieve the MSAA client accessibility object for the Render Widget Host View
    190 // of the selected tab.
    191 IAccessible*
    192 AccessibilityWinBrowserTest::GetRendererAccessible() {
    193   HWND hwnd_render_widget_host_view =
    194       browser()->GetSelectedTabContents()->GetRenderWidgetHostView()->
    195           GetNativeView();
    196 
    197   // Invoke windows screen reader detection by sending the WM_GETOBJECT message
    198   // with kIdCustom as the LPARAM.
    199   const int32 kIdCustom = 1;
    200   SendMessage(
    201       hwnd_render_widget_host_view, WM_GETOBJECT, OBJID_CLIENT, kIdCustom);
    202 
    203   IAccessible* accessible;
    204   HRESULT hr = AccessibleObjectFromWindow(
    205       hwnd_render_widget_host_view, OBJID_CLIENT,
    206       IID_IAccessible, reinterpret_cast<void**>(&accessible));
    207   EXPECT_EQ(S_OK, hr);
    208   EXPECT_NE(accessible, reinterpret_cast<IAccessible*>(NULL));
    209 
    210   return accessible;
    211 }
    212 
    213 void AccessibilityWinBrowserTest::ExecuteScript(wstring script) {
    214   browser()->GetSelectedTabContents()->render_view_host()->
    215       ExecuteJavascriptInWebFrame(L"", script);
    216 }
    217 
    218 AccessibleChecker::AccessibleChecker(
    219     wstring expected_name, int32 expected_role, wstring expected_value) :
    220     name_(expected_name),
    221     role_(expected_role),
    222     value_(expected_value),
    223     state_(-1) {
    224 }
    225 
    226 AccessibleChecker::AccessibleChecker(
    227     wstring expected_name, wstring expected_role, wstring expected_value) :
    228     name_(expected_name),
    229     role_(expected_role.c_str()),
    230     value_(expected_value),
    231     state_(-1) {
    232 }
    233 
    234 void AccessibleChecker::AppendExpectedChild(
    235     AccessibleChecker* expected_child) {
    236   children_.push_back(expected_child);
    237 }
    238 
    239 void AccessibleChecker::CheckAccessible(IAccessible* accessible) {
    240   CheckAccessibleName(accessible);
    241   CheckAccessibleRole(accessible);
    242   CheckAccessibleValue(accessible);
    243   CheckAccessibleState(accessible);
    244   CheckAccessibleChildren(accessible);
    245 }
    246 
    247 void AccessibleChecker::SetExpectedValue(wstring expected_value) {
    248   value_ = expected_value;
    249 }
    250 
    251 void AccessibleChecker::SetExpectedState(LONG expected_state) {
    252   state_ = expected_state;
    253 }
    254 
    255 void AccessibleChecker::CheckAccessibleName(IAccessible* accessible) {
    256   CComBSTR name;
    257   HRESULT hr =
    258       accessible->get_accName(CreateI4Variant(CHILDID_SELF), &name);
    259 
    260   if (name_.empty()) {
    261     // If the object doesn't have name S_FALSE should be returned.
    262     EXPECT_EQ(hr, S_FALSE);
    263   } else {
    264     // Test that the correct string was returned.
    265     EXPECT_EQ(S_OK, hr);
    266     EXPECT_STREQ(name_.c_str(),
    267                  wstring(name.m_str, SysStringLen(name)).c_str());
    268   }
    269 }
    270 
    271 void AccessibleChecker::CheckAccessibleRole(IAccessible* accessible) {
    272   VARIANT var_role = {0};
    273   HRESULT hr =
    274       accessible->get_accRole(CreateI4Variant(CHILDID_SELF), &var_role);
    275   ASSERT_EQ(S_OK, hr);
    276   EXPECT_TRUE(role_ == var_role);
    277 }
    278 
    279 void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) {
    280   CComBSTR value;
    281   HRESULT hr =
    282       accessible->get_accValue(CreateI4Variant(CHILDID_SELF), &value);
    283   EXPECT_EQ(S_OK, hr);
    284 
    285   // Test that the correct string was returned.
    286   EXPECT_STREQ(value_.c_str(),
    287                wstring(value.m_str, SysStringLen(value)).c_str());
    288 }
    289 
    290 void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) {
    291   if (state_ < 0)
    292     return;
    293 
    294   VARIANT var_state = {0};
    295   HRESULT hr =
    296       accessible->get_accState(CreateI4Variant(CHILDID_SELF), &var_state);
    297   EXPECT_EQ(S_OK, hr);
    298   ASSERT_EQ(VT_I4, V_VT(&var_state));
    299   EXPECT_EQ(state_, V_I4(&var_state));
    300 }
    301 
    302 void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
    303   LONG child_count = 0;
    304   HRESULT hr = parent->get_accChildCount(&child_count);
    305   EXPECT_EQ(S_OK, hr);
    306   ASSERT_EQ(child_count, children_.size());
    307 
    308   auto_ptr<VARIANT> child_array(new VARIANT[child_count]);
    309   LONG obtained_count = 0;
    310   hr = AccessibleChildren(parent, 0, child_count,
    311                           child_array.get(), &obtained_count);
    312   ASSERT_EQ(S_OK, hr);
    313   ASSERT_EQ(child_count, obtained_count);
    314 
    315   VARIANT* child = child_array.get();
    316   for (AccessibleCheckerVector::iterator child_checker = children_.begin();
    317        child_checker != children_.end();
    318        ++child_checker, ++child) {
    319     base::win::ScopedComPtr<IAccessible> child_accessible;
    320     child_accessible.Attach(GetAccessibleFromResultVariant(parent, child));
    321     ASSERT_TRUE(child_accessible.get());
    322     (*child_checker)->CheckAccessible(child_accessible);
    323   }
    324 }
    325 
    326 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    327                        TestRendererAccessibilityTree) {
    328   // The initial accessible returned should have state STATE_SYSTEM_BUSY while
    329   // the accessibility tree is being requested from the renderer.
    330   AccessibleChecker document1_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
    331   document1_checker.SetExpectedState(
    332       STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED |
    333       STATE_SYSTEM_BUSY);
    334   document1_checker.CheckAccessible(GetRendererAccessible());
    335 
    336   // Wait for the initial accessibility tree to load. Busy state should clear.
    337   ui_test_utils::WaitForNotification(
    338       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    339   document1_checker.SetExpectedState(
    340       STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED);
    341   document1_checker.CheckAccessible(GetRendererAccessible());
    342 
    343   GURL tree_url(
    344       "data:text/html,<html><head><title>Accessibility Win Test</title></head>"
    345       "<body><input type='button' value='push' /><input type='checkbox' />"
    346       "</body></html>");
    347   browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
    348   ui_test_utils::WaitForNotification(
    349       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    350 
    351   // Check the browser's copy of the renderer accessibility tree.
    352   AccessibleChecker button_checker(L"push", ROLE_SYSTEM_PUSHBUTTON, L"push");
    353   AccessibleChecker checkbox_checker(L"", ROLE_SYSTEM_CHECKBUTTON, L"");
    354   AccessibleChecker body_checker(L"", L"body", L"");
    355   AccessibleChecker document2_checker(
    356     L"Accessibility Win Test", ROLE_SYSTEM_DOCUMENT, L"");
    357   body_checker.AppendExpectedChild(&button_checker);
    358   body_checker.AppendExpectedChild(&checkbox_checker);
    359   document2_checker.AppendExpectedChild(&body_checker);
    360   document2_checker.CheckAccessible(GetRendererAccessible());
    361 
    362   // Check that document accessible has a parent accessible.
    363   base::win::ScopedComPtr<IAccessible> document_accessible(
    364       GetRendererAccessible());
    365   ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
    366   base::win::ScopedComPtr<IDispatch> parent_dispatch;
    367   HRESULT hr = document_accessible->get_accParent(parent_dispatch.Receive());
    368   EXPECT_EQ(S_OK, hr);
    369   EXPECT_NE(parent_dispatch, reinterpret_cast<IDispatch*>(NULL));
    370 
    371   // Navigate to another page.
    372   GURL about_url("about:");
    373   ui_test_utils::NavigateToURL(browser(), about_url);
    374 
    375   // Verify that the IAccessible reference still points to a valid object and
    376   // that calls to its methods fail since the tree is no longer valid after
    377   // the page navagation.
    378   CComBSTR name;
    379   hr = document_accessible->get_accName(CreateI4Variant(CHILDID_SELF), &name);
    380   ASSERT_EQ(E_FAIL, hr);
    381 }
    382 
    383 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    384                        TestNotificationActiveDescendantChanged) {
    385   GURL tree_url("data:text/html,<ul tabindex='-1' role='radiogroup'><li id='li'"
    386       ">li</li></ul>");
    387   browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
    388   GetRendererAccessible();
    389   ui_test_utils::WaitForNotification(
    390       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    391 
    392   // Check the browser's copy of the renderer accessibility tree.
    393   AccessibleChecker list_marker_checker(L"", ROLE_SYSTEM_LISTITEM, L"\x2022");
    394   AccessibleChecker static_text_checker(L"li", ROLE_SYSTEM_TEXT, L"");
    395   AccessibleChecker list_item_checker(L"", ROLE_SYSTEM_LISTITEM, L"");
    396   list_item_checker.SetExpectedState(
    397       STATE_SYSTEM_READONLY);
    398   AccessibleChecker radio_group_checker(L"", ROLE_SYSTEM_GROUPING, L"");
    399   radio_group_checker.SetExpectedState(
    400       STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY);
    401   AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
    402   list_item_checker.AppendExpectedChild(&list_marker_checker);
    403   list_item_checker.AppendExpectedChild(&static_text_checker);
    404   radio_group_checker.AppendExpectedChild(&list_item_checker);
    405   document_checker.AppendExpectedChild(&radio_group_checker);
    406   document_checker.CheckAccessible(GetRendererAccessible());
    407 
    408   // Set focus to the radio group.
    409   ExecuteScript(L"document.body.children[0].focus()");
    410   ui_test_utils::WaitForNotification(
    411       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    412 
    413   // Check that the accessibility tree of the browser has been updated.
    414   radio_group_checker.SetExpectedState(
    415       STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSED);
    416   document_checker.CheckAccessible(GetRendererAccessible());
    417 
    418   // Set the active descendant of the radio group
    419   ExecuteScript(
    420       L"document.body.children[0].setAttribute('aria-activedescendant', 'li')");
    421   ui_test_utils::WaitForNotification(
    422       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    423 
    424   // Check that the accessibility tree of the browser has been updated.
    425   list_item_checker.SetExpectedState(
    426       STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSED);
    427   radio_group_checker.SetExpectedState(
    428       STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY);
    429   document_checker.CheckAccessible(GetRendererAccessible());
    430 }
    431 
    432 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    433                        TestNotificationCheckedStateChanged) {
    434   GURL tree_url("data:text/html,<body><input type='checkbox' /></body>");
    435   browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
    436   GetRendererAccessible();
    437   ui_test_utils::WaitForNotification(
    438       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    439 
    440   // Check the browser's copy of the renderer accessibility tree.
    441   AccessibleChecker checkbox_checker(L"", ROLE_SYSTEM_CHECKBUTTON, L"");
    442   checkbox_checker.SetExpectedState(
    443       STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY);
    444   AccessibleChecker body_checker(L"", L"body", L"");
    445   AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
    446   body_checker.AppendExpectedChild(&checkbox_checker);
    447   document_checker.AppendExpectedChild(&body_checker);
    448   document_checker.CheckAccessible(GetRendererAccessible());
    449 
    450   // Check the checkbox.
    451   ExecuteScript(L"document.body.children[0].checked=true");
    452   ui_test_utils::WaitForNotification(
    453       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    454 
    455   // Check that the accessibility tree of the browser has been updated.
    456   checkbox_checker.SetExpectedState(
    457       STATE_SYSTEM_CHECKED | STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY);
    458   document_checker.CheckAccessible(GetRendererAccessible());
    459 }
    460 
    461 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    462                        TestNotificationChildrenChanged) {
    463   // The role attribute causes the node to be in the accessibility tree.
    464   GURL tree_url(
    465       "data:text/html,<body role=group></body>");
    466   browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
    467   GetRendererAccessible();
    468   ui_test_utils::WaitForNotification(
    469       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    470 
    471   // Check the browser's copy of the renderer accessibility tree.
    472   AccessibleChecker body_checker(L"", L"body", L"");
    473   AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
    474   document_checker.AppendExpectedChild(&body_checker);
    475   document_checker.CheckAccessible(GetRendererAccessible());
    476 
    477   // Change the children of the document body.
    478   ExecuteScript(L"document.body.innerHTML='<b>new text</b>'");
    479   ui_test_utils::WaitForNotification(
    480       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    481 
    482   // Check that the accessibility tree of the browser has been updated.
    483   AccessibleChecker text_checker(L"new text", ROLE_SYSTEM_TEXT, L"");
    484   body_checker.AppendExpectedChild(&text_checker);
    485   document_checker.CheckAccessible(GetRendererAccessible());
    486 }
    487 
    488 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    489                        TestNotificationChildrenChanged2) {
    490   // The role attribute causes the node to be in the accessibility tree.
    491   GURL tree_url(
    492       "data:text/html,<div role=group style='visibility: hidden'>text"
    493       "</div>");
    494   browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
    495   GetRendererAccessible();
    496   ui_test_utils::WaitForNotification(
    497       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    498 
    499   // Check the accessible tree of the browser.
    500   AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
    501   document_checker.CheckAccessible(GetRendererAccessible());
    502 
    503   // Change the children of the document body.
    504   ExecuteScript(L"document.body.children[0].style.visibility='visible'");
    505   ui_test_utils::WaitForNotification(
    506       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    507 
    508   // Check that the accessibility tree of the browser has been updated.
    509   AccessibleChecker static_text_checker(L"text", ROLE_SYSTEM_TEXT, L"");
    510   AccessibleChecker div_checker(L"", L"div", L"");
    511   document_checker.AppendExpectedChild(&div_checker);
    512   div_checker.AppendExpectedChild(&static_text_checker);
    513   document_checker.CheckAccessible(GetRendererAccessible());
    514 }
    515 
    516 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    517                        TestNotificationFocusChanged) {
    518   // The role attribute causes the node to be in the accessibility tree.
    519   GURL tree_url(
    520       "data:text/html,<div role=group tabindex='-1'></div>");
    521   browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
    522   GetRendererAccessible();
    523   ui_test_utils::WaitForNotification(
    524       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    525 
    526   // Check the browser's copy of the renderer accessibility tree.
    527   AccessibleChecker div_checker(L"", L"div", L"");
    528   div_checker.SetExpectedState(
    529       STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_OFFSCREEN | STATE_SYSTEM_READONLY);
    530   AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
    531   document_checker.AppendExpectedChild(&div_checker);
    532   document_checker.CheckAccessible(GetRendererAccessible());
    533 
    534   // Focus the div in the document
    535   ExecuteScript(L"document.body.children[0].focus()");
    536   ui_test_utils::WaitForNotification(
    537       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    538 
    539   // Check that the accessibility tree of the browser has been updated.
    540   div_checker.SetExpectedState(
    541       STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSED);
    542   document_checker.CheckAccessible(GetRendererAccessible());
    543 
    544   // Focus the document accessible. This will un-focus the current node.
    545   base::win::ScopedComPtr<IAccessible> document_accessible(
    546       GetRendererAccessible());
    547   ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
    548   HRESULT hr = document_accessible->accSelect(
    549     SELFLAG_TAKEFOCUS, CreateI4Variant(CHILDID_SELF));
    550   ASSERT_EQ(S_OK, hr);
    551   ui_test_utils::WaitForNotification(
    552       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    553 
    554   // Check that the accessibility tree of the browser has been updated.
    555   div_checker.SetExpectedState(
    556       STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY);
    557   document_checker.CheckAccessible(GetRendererAccessible());
    558 }
    559 
    560 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    561                        TestNotificationValueChanged) {
    562   GURL tree_url("data:text/html,<body><input type='text' value='old value'/>"
    563       "</body>");
    564   browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
    565   GetRendererAccessible();
    566   ui_test_utils::WaitForNotification(
    567       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    568 
    569   // Check the browser's copy of the renderer accessibility tree.
    570 
    571   AccessibleChecker text_field_div_checker(L"", L"div", L"");
    572   AccessibleChecker text_field_checker(L"", ROLE_SYSTEM_TEXT, L"old value");
    573   text_field_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
    574   AccessibleChecker body_checker(L"", L"body", L"");
    575   AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
    576   text_field_checker.AppendExpectedChild(&text_field_div_checker);
    577   body_checker.AppendExpectedChild(&text_field_checker);
    578   document_checker.AppendExpectedChild(&body_checker);
    579   document_checker.CheckAccessible(GetRendererAccessible());
    580 
    581   // Set the value of the text control
    582   ExecuteScript(L"document.body.children[0].value='new value'");
    583   ui_test_utils::WaitForNotification(
    584       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    585 
    586   // Check that the accessibility tree of the browser has been updated.
    587   text_field_checker.SetExpectedValue(L"new value");
    588   document_checker.CheckAccessible(GetRendererAccessible());
    589 }
    590 
    591 // FAILS crbug.com/54220
    592 // This test verifies that browser-side cache of the renderer accessibility
    593 // tree is reachable from the browser's tree. Tools that analyze windows
    594 // accessibility trees like AccExplorer32 should be able to drill into the
    595 // cached renderer accessibility tree.
    596 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    597                        DISABLED_ContainsRendererAccessibilityTree) {
    598   GURL tree_url("data:text/html,<body><input type='checkbox' /></body>");
    599   browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
    600   GetRendererAccessible();
    601   ui_test_utils::WaitForNotification(
    602       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    603 
    604   // Get the accessibility object for the browser window.
    605   HWND browser_hwnd = browser()->window()->GetNativeHandle();
    606   base::win::ScopedComPtr<IAccessible> browser_accessible;
    607   HRESULT hr = AccessibleObjectFromWindow(
    608       browser_hwnd,
    609       OBJID_WINDOW,
    610       IID_IAccessible,
    611       reinterpret_cast<void**>(browser_accessible.Receive()));
    612   ASSERT_EQ(S_OK, hr);
    613 
    614   // Get the accessibility object for the renderer client document.
    615   base::win::ScopedComPtr<IAccessible> document_accessible(
    616       GetRendererAccessible());
    617   ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
    618   base::win::ScopedComPtr<IAccessible2> document_accessible2;
    619   hr = QueryIAccessible2(document_accessible, document_accessible2.Receive());
    620   ASSERT_EQ(S_OK, hr);
    621 
    622   // TODO(ctguil): Pointer comparison of retrieved IAccessible pointers dosen't
    623   // seem to work for here. Perhaps make IAccessible2 available in views to make
    624   // unique id comparison available.
    625   bool found = false;
    626   base::win::ScopedComPtr<IAccessible> parent = document_accessible;
    627   while (parent.get()) {
    628     base::win::ScopedComPtr<IDispatch> parent_dispatch;
    629     hr = parent->get_accParent(parent_dispatch.Receive());
    630     ASSERT_TRUE(SUCCEEDED(hr));
    631     if (!parent_dispatch.get()) {
    632       ASSERT_EQ(hr, S_FALSE);
    633       break;
    634     }
    635 
    636     parent.Release();
    637     hr = parent_dispatch.QueryInterface(parent.Receive());
    638     ASSERT_EQ(S_OK, hr);
    639 
    640     if (parent.get() == browser_accessible.get()) {
    641       found = true;
    642       break;
    643     }
    644   }
    645 
    646   // If pointer comparison fails resort to the exhuasive search that can use
    647   // IAccessible2::get_unique_id for equality comparison.
    648   if (!found) {
    649     AccessibleContainsAccessible(
    650         browser_accessible, document_accessible2, &found);
    651   }
    652 
    653   ASSERT_EQ(found, true);
    654 }
    655 
    656 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    657                        SupportsISimpleDOM) {
    658   GURL tree_url("data:text/html,<body><input type='checkbox' /></body>");
    659   browser()->OpenURL(tree_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
    660   GetRendererAccessible();
    661   ui_test_utils::WaitForNotification(
    662       NotificationType::RENDER_VIEW_HOST_ACCESSIBILITY_TREE_UPDATED);
    663 
    664   // Get the IAccessible object for the document.
    665   base::win::ScopedComPtr<IAccessible> document_accessible(
    666       GetRendererAccessible());
    667   ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
    668 
    669   // Get the ISimpleDOM object for the document.
    670   base::win::ScopedComPtr<IServiceProvider> service_provider;
    671   HRESULT hr = static_cast<IAccessible*>(document_accessible)->QueryInterface(
    672       service_provider.Receive());
    673   ASSERT_EQ(S_OK, hr);
    674   const GUID refguid = {0x0c539790, 0x12e4, 0x11cf,
    675                         0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
    676   base::win::ScopedComPtr<ISimpleDOMNode> document_isimpledomnode;
    677   hr = static_cast<IServiceProvider *>(service_provider)->QueryService(
    678       refguid, IID_ISimpleDOMNode,
    679       reinterpret_cast<void**>(document_isimpledomnode.Receive()));
    680   ASSERT_EQ(S_OK, hr);
    681 
    682   BSTR node_name;
    683   short name_space_id;  // NOLINT
    684   BSTR node_value;
    685   unsigned int num_children;
    686   unsigned int unique_id;
    687   unsigned short node_type;  // NOLINT
    688   hr = document_isimpledomnode->get_nodeInfo(
    689       &node_name, &name_space_id, &node_value, &num_children, &unique_id,
    690       &node_type);
    691   ASSERT_EQ(S_OK, hr);
    692   EXPECT_EQ(NODETYPE_DOCUMENT, node_type);
    693   EXPECT_EQ(1, num_children);
    694 
    695   base::win::ScopedComPtr<ISimpleDOMNode> body_isimpledomnode;
    696   hr = document_isimpledomnode->get_firstChild(
    697       body_isimpledomnode.Receive());
    698   ASSERT_EQ(S_OK, hr);
    699   hr = body_isimpledomnode->get_nodeInfo(
    700       &node_name, &name_space_id, &node_value, &num_children, &unique_id,
    701       &node_type);
    702   ASSERT_EQ(S_OK, hr);
    703   EXPECT_STREQ(L"body", wstring(node_name, SysStringLen(node_name)).c_str());
    704   EXPECT_EQ(NODETYPE_ELEMENT, node_type);
    705   EXPECT_EQ(1, num_children);
    706 
    707   base::win::ScopedComPtr<ISimpleDOMNode> checkbox_isimpledomnode;
    708   hr = body_isimpledomnode->get_firstChild(
    709       checkbox_isimpledomnode.Receive());
    710   ASSERT_EQ(S_OK, hr);
    711   hr = checkbox_isimpledomnode->get_nodeInfo(
    712       &node_name, &name_space_id, &node_value, &num_children, &unique_id,
    713       &node_type);
    714   ASSERT_EQ(S_OK, hr);
    715   EXPECT_STREQ(L"input", wstring(node_name, SysStringLen(node_name)).c_str());
    716   EXPECT_EQ(NODETYPE_ELEMENT, node_type);
    717   EXPECT_EQ(0, num_children);
    718 }
    719 }  // namespace.
    720