Home | History | Annotate | Download | only in accessibility
      1 // Copyright (c) 2012 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 <vector>
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "base/win/scoped_bstr.h"
     10 #include "base/win/scoped_comptr.h"
     11 #include "base/win/scoped_variant.h"
     12 #include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
     13 #include "content/browser/renderer_host/render_view_host_impl.h"
     14 #include "content/public/browser/notification_service.h"
     15 #include "content/public/browser/notification_types.h"
     16 #include "content/public/browser/render_view_host.h"
     17 #include "content/public/browser/render_widget_host_view.h"
     18 #include "content/public/browser/web_contents.h"
     19 #include "content/public/common/url_constants.h"
     20 #include "content/shell/shell.h"
     21 #include "content/test/accessibility_browser_test_utils.h"
     22 #include "content/test/content_browser_test.h"
     23 #include "content/test/content_browser_test_utils.h"
     24 #include "third_party/iaccessible2/ia2_api_all.h"
     25 #include "third_party/isimpledom/ISimpleDOMNode.h"
     26 
     27 // TODO(dmazzoni): Disabled accessibility tests on Win64. crbug.com/179717
     28 #if defined(ARCH_CPU_X86_64)
     29 #define MAYBE(x) DISABLED_##x
     30 #else
     31 #define MAYBE(x) x
     32 #endif
     33 
     34 namespace content {
     35 
     36 namespace {
     37 
     38 
     39 // Helpers --------------------------------------------------------------------
     40 
     41 base::win::ScopedComPtr<IAccessible> GetAccessibleFromResultVariant(
     42     IAccessible* parent,
     43     VARIANT* var) {
     44   base::win::ScopedComPtr<IAccessible> ptr;
     45   switch (V_VT(var)) {
     46     case VT_DISPATCH: {
     47       IDispatch* dispatch = V_DISPATCH(var);
     48       if (dispatch)
     49         ptr.QueryFrom(dispatch);
     50       break;
     51     }
     52 
     53     case VT_I4: {
     54       base::win::ScopedComPtr<IDispatch> dispatch;
     55       HRESULT hr = parent->get_accChild(*var, dispatch.Receive());
     56       EXPECT_TRUE(SUCCEEDED(hr));
     57       if (dispatch)
     58         dispatch.QueryInterface(ptr.Receive());
     59       break;
     60     }
     61   }
     62   return ptr;
     63 }
     64 
     65 HRESULT QueryIAccessible2(IAccessible* accessible, IAccessible2** accessible2) {
     66   // TODO(ctguil): For some reason querying the IAccessible2 interface from
     67   // IAccessible fails.
     68   base::win::ScopedComPtr<IServiceProvider> service_provider;
     69   HRESULT hr = accessible->QueryInterface(service_provider.Receive());
     70   return SUCCEEDED(hr) ?
     71       service_provider->QueryService(IID_IAccessible2, accessible2) : hr;
     72 }
     73 
     74 // Recursively search through all of the descendants reachable from an
     75 // IAccessible node and return true if we find one with the given role
     76 // and name.
     77 void RecursiveFindNodeInAccessibilityTree(IAccessible* node,
     78                                           int32 expected_role,
     79                                           const std::wstring& expected_name,
     80                                           int32 depth,
     81                                           bool* found) {
     82   base::win::ScopedBstr name_bstr;
     83   base::win::ScopedVariant childid_self(CHILDID_SELF);
     84   node->get_accName(childid_self, name_bstr.Receive());
     85   std::wstring name(name_bstr, name_bstr.Length());
     86   base::win::ScopedVariant role;
     87   node->get_accRole(childid_self, role.Receive());
     88   ASSERT_EQ(VT_I4, role.type());
     89 
     90   // Print the accessibility tree as we go, because if this test fails
     91   // on the bots, this is really helpful in figuring out why.
     92   for (int i = 0; i < depth; i++)
     93     printf("  ");
     94   printf("role=%d name=%s\n", V_I4(&role), WideToUTF8(name).c_str());
     95 
     96   if (expected_role == V_I4(&role) && expected_name == name) {
     97     *found = true;
     98     return;
     99   }
    100 
    101   LONG child_count = 0;
    102   HRESULT hr = node->get_accChildCount(&child_count);
    103   ASSERT_EQ(S_OK, hr);
    104 
    105   scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]);
    106   LONG obtained_count = 0;
    107   hr = AccessibleChildren(
    108       node, 0, child_count, child_array.get(), &obtained_count);
    109   ASSERT_EQ(S_OK, hr);
    110   ASSERT_EQ(child_count, obtained_count);
    111 
    112   for (int index = 0; index < obtained_count; index++) {
    113     base::win::ScopedComPtr<IAccessible> child_accessible(
    114         GetAccessibleFromResultVariant(node, &child_array.get()[index]));
    115     if (child_accessible) {
    116       RecursiveFindNodeInAccessibilityTree(
    117           child_accessible.get(), expected_role, expected_name, depth + 1,
    118           found);
    119       if (*found)
    120         return;
    121     }
    122   }
    123 }
    124 
    125 
    126 // AccessibilityWinBrowserTest ------------------------------------------------
    127 
    128 class AccessibilityWinBrowserTest : public ContentBrowserTest {
    129  public:
    130   AccessibilityWinBrowserTest();
    131   virtual ~AccessibilityWinBrowserTest();
    132 
    133  protected:
    134   void LoadInitialAccessibilityTreeFromHtml(const std::string& html);
    135   IAccessible* GetRendererAccessible();
    136   void ExecuteScript(const std::wstring& script);
    137 
    138  private:
    139   DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest);
    140 };
    141 
    142 AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() {
    143 }
    144 
    145 AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() {
    146 }
    147 
    148 void AccessibilityWinBrowserTest::LoadInitialAccessibilityTreeFromHtml(
    149     const std::string& html) {
    150   AccessibilityNotificationWaiter waiter(
    151       shell(), AccessibilityModeComplete,
    152       AccessibilityNotificationLoadComplete);
    153   GURL html_data_url("data:text/html," + html);
    154   NavigateToURL(shell(), html_data_url);
    155   waiter.WaitForNotification();
    156 }
    157 
    158 // Retrieve the MSAA client accessibility object for the Render Widget Host View
    159 // of the selected tab.
    160 IAccessible* AccessibilityWinBrowserTest::GetRendererAccessible() {
    161   HWND hwnd_render_widget_host_view =
    162       shell()->web_contents()->GetRenderWidgetHostView()->GetNativeView();
    163 
    164   // Invoke windows screen reader detection by sending the WM_GETOBJECT message
    165   // with kIdCustom as the LPARAM.
    166   const int32 kIdCustom = 1;
    167   SendMessage(
    168       hwnd_render_widget_host_view, WM_GETOBJECT, OBJID_CLIENT, kIdCustom);
    169 
    170   IAccessible* accessible;
    171   HRESULT hr = AccessibleObjectFromWindow(
    172       hwnd_render_widget_host_view, OBJID_CLIENT,
    173       IID_IAccessible, reinterpret_cast<void**>(&accessible));
    174 
    175   EXPECT_EQ(S_OK, hr);
    176   EXPECT_NE(accessible, reinterpret_cast<IAccessible*>(NULL));
    177 
    178   return accessible;
    179 }
    180 
    181 void AccessibilityWinBrowserTest::ExecuteScript(const std::wstring& script) {
    182   shell()->web_contents()->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
    183       std::wstring(), script);
    184 }
    185 
    186 
    187 // AccessibleChecker ----------------------------------------------------------
    188 
    189 class AccessibleChecker {
    190  public:
    191   // This constructor can be used if the IA2 role will be the same as the MSAA
    192   // role.
    193   AccessibleChecker(const std::wstring& expected_name,
    194                     int32 expected_role,
    195                     const std::wstring& expected_value);
    196   AccessibleChecker(const std::wstring& expected_name,
    197                     int32 expected_role,
    198                     int32 expected_ia2_role,
    199                     const std::wstring& expected_value);
    200   AccessibleChecker(const std::wstring& expected_name,
    201                     const std::wstring& expected_role,
    202                     int32 expected_ia2_role,
    203                     const std::wstring& expected_value);
    204 
    205   // Append an AccessibleChecker that verifies accessibility information for
    206   // a child IAccessible. Order is important.
    207   void AppendExpectedChild(AccessibleChecker* expected_child);
    208 
    209   // Check that the name and role of the given IAccessible instance and its
    210   // descendants match the expected names and roles that this object was
    211   // initialized with.
    212   void CheckAccessible(IAccessible* accessible);
    213 
    214   // Set the expected value for this AccessibleChecker.
    215   void SetExpectedValue(const std::wstring& expected_value);
    216 
    217   // Set the expected state for this AccessibleChecker.
    218   void SetExpectedState(LONG expected_state);
    219 
    220  private:
    221   typedef std::vector<AccessibleChecker*> AccessibleCheckerVector;
    222 
    223   void CheckAccessibleName(IAccessible* accessible);
    224   void CheckAccessibleRole(IAccessible* accessible);
    225   void CheckIA2Role(IAccessible* accessible);
    226   void CheckAccessibleValue(IAccessible* accessible);
    227   void CheckAccessibleState(IAccessible* accessible);
    228   void CheckAccessibleChildren(IAccessible* accessible);
    229   string16 RoleVariantToString(const base::win::ScopedVariant& role);
    230 
    231   // Expected accessible name. Checked against IAccessible::get_accName.
    232   std::wstring name_;
    233 
    234   // Expected accessible role. Checked against IAccessible::get_accRole.
    235   base::win::ScopedVariant role_;
    236 
    237   // Expected IAccessible2 role. Checked against IAccessible2::role.
    238   int32 ia2_role_;
    239 
    240   // Expected accessible value. Checked against IAccessible::get_accValue.
    241   std::wstring value_;
    242 
    243   // Expected accessible state. Checked against IAccessible::get_accState.
    244   LONG state_;
    245 
    246   // Expected accessible children. Checked using IAccessible::get_accChildCount
    247   // and ::AccessibleChildren.
    248   AccessibleCheckerVector children_;
    249 };
    250 
    251 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
    252                                      int32 expected_role,
    253                                      const std::wstring& expected_value)
    254     : name_(expected_name),
    255       role_(expected_role),
    256       ia2_role_(expected_role),
    257       value_(expected_value),
    258       state_(-1) {
    259 }
    260 
    261 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
    262                                      int32 expected_role,
    263                                      int32 expected_ia2_role,
    264                                      const std::wstring& expected_value)
    265     : name_(expected_name),
    266       role_(expected_role),
    267       ia2_role_(expected_ia2_role),
    268       value_(expected_value),
    269       state_(-1) {
    270 }
    271 
    272 AccessibleChecker::AccessibleChecker(const std::wstring& expected_name,
    273                                      const std::wstring& expected_role,
    274                                      int32 expected_ia2_role,
    275                                      const std::wstring& expected_value)
    276     : name_(expected_name),
    277       role_(expected_role.c_str()),
    278       ia2_role_(expected_ia2_role),
    279       value_(expected_value),
    280       state_(-1) {
    281 }
    282 
    283 void AccessibleChecker::AppendExpectedChild(
    284     AccessibleChecker* expected_child) {
    285   children_.push_back(expected_child);
    286 }
    287 
    288 void AccessibleChecker::CheckAccessible(IAccessible* accessible) {
    289   SCOPED_TRACE("while checking " + UTF16ToUTF8(RoleVariantToString(role_)));
    290   CheckAccessibleName(accessible);
    291   CheckAccessibleRole(accessible);
    292   CheckIA2Role(accessible);
    293   CheckAccessibleValue(accessible);
    294   CheckAccessibleState(accessible);
    295   CheckAccessibleChildren(accessible);
    296 }
    297 
    298 void AccessibleChecker::SetExpectedValue(const std::wstring& expected_value) {
    299   value_ = expected_value;
    300 }
    301 
    302 void AccessibleChecker::SetExpectedState(LONG expected_state) {
    303   state_ = expected_state;
    304 }
    305 
    306 void AccessibleChecker::CheckAccessibleName(IAccessible* accessible) {
    307   base::win::ScopedBstr name;
    308   base::win::ScopedVariant childid_self(CHILDID_SELF);
    309   HRESULT hr = accessible->get_accName(childid_self, name.Receive());
    310 
    311   if (name_.empty()) {
    312     // If the object doesn't have name S_FALSE should be returned.
    313     EXPECT_EQ(S_FALSE, hr);
    314   } else {
    315     // Test that the correct string was returned.
    316     EXPECT_EQ(S_OK, hr);
    317     EXPECT_EQ(name_, std::wstring(name, name.Length()));
    318   }
    319 }
    320 
    321 void AccessibleChecker::CheckAccessibleRole(IAccessible* accessible) {
    322   base::win::ScopedVariant role;
    323   base::win::ScopedVariant childid_self(CHILDID_SELF);
    324   HRESULT hr = accessible->get_accRole(childid_self, role.Receive());
    325   ASSERT_EQ(S_OK, hr);
    326   EXPECT_EQ(0, role_.Compare(role))
    327       << "Expected role: " << RoleVariantToString(role_)
    328       << "\nGot role: " << RoleVariantToString(role);
    329 }
    330 
    331 void AccessibleChecker::CheckIA2Role(IAccessible* accessible) {
    332   base::win::ScopedComPtr<IAccessible2> accessible2;
    333   HRESULT hr = QueryIAccessible2(accessible, accessible2.Receive());
    334   ASSERT_EQ(S_OK, hr);
    335   long ia2_role = 0;
    336   hr = accessible2->role(&ia2_role);
    337   ASSERT_EQ(S_OK, hr);
    338   EXPECT_EQ(ia2_role_, ia2_role)
    339     << "Expected ia2 role: " << IAccessible2RoleToString(ia2_role_)
    340     << "\nGot ia2 role: " << IAccessible2RoleToString(ia2_role);
    341 }
    342 
    343 void AccessibleChecker::CheckAccessibleValue(IAccessible* accessible) {
    344   // Don't check the value if if's a DOCUMENT role, because the value
    345   // is supposed to be the url (and we don't keep track of that in the
    346   // test expectations).
    347   base::win::ScopedVariant role;
    348   base::win::ScopedVariant childid_self(CHILDID_SELF);
    349   HRESULT hr = accessible->get_accRole(childid_self, role.Receive());
    350   ASSERT_EQ(S_OK, hr);
    351   if (role.type() == VT_I4 && V_I4(&role) == ROLE_SYSTEM_DOCUMENT)
    352     return;
    353 
    354   // Get the value.
    355   base::win::ScopedBstr value;
    356   hr = accessible->get_accValue(childid_self, value.Receive());
    357   EXPECT_EQ(S_OK, hr);
    358 
    359   // Test that the correct string was returned.
    360   EXPECT_EQ(value_, std::wstring(value, value.Length()));
    361 }
    362 
    363 void AccessibleChecker::CheckAccessibleState(IAccessible* accessible) {
    364   if (state_ < 0)
    365     return;
    366 
    367   base::win::ScopedVariant state;
    368   base::win::ScopedVariant childid_self(CHILDID_SELF);
    369   HRESULT hr = accessible->get_accState(childid_self, state.Receive());
    370   EXPECT_EQ(S_OK, hr);
    371   ASSERT_EQ(VT_I4, state.type());
    372   LONG obj_state = V_I4(&state);
    373   // Avoid flakiness. The "offscreen" state depends on whether the browser
    374   // window is frontmost or not, and "hottracked" depends on whether the
    375   // mouse cursor happens to be over the element.
    376   obj_state &= ~(STATE_SYSTEM_OFFSCREEN | STATE_SYSTEM_HOTTRACKED);
    377   EXPECT_EQ(state_, obj_state)
    378     << "Expected state: " << IAccessibleStateToString(state_)
    379     << "\nGot state: " << IAccessibleStateToString(obj_state);
    380 }
    381 
    382 void AccessibleChecker::CheckAccessibleChildren(IAccessible* parent) {
    383   LONG child_count = 0;
    384   HRESULT hr = parent->get_accChildCount(&child_count);
    385   EXPECT_EQ(S_OK, hr);
    386   ASSERT_EQ(child_count, children_.size());
    387 
    388   scoped_ptr<VARIANT[]> child_array(new VARIANT[child_count]);
    389   LONG obtained_count = 0;
    390   hr = AccessibleChildren(parent, 0, child_count,
    391                           child_array.get(), &obtained_count);
    392   ASSERT_EQ(S_OK, hr);
    393   ASSERT_EQ(child_count, obtained_count);
    394 
    395   VARIANT* child = child_array.get();
    396   for (AccessibleCheckerVector::iterator child_checker = children_.begin();
    397        child_checker != children_.end();
    398        ++child_checker, ++child) {
    399     base::win::ScopedComPtr<IAccessible> child_accessible(
    400         GetAccessibleFromResultVariant(parent, child));
    401     ASSERT_TRUE(child_accessible.get());
    402     (*child_checker)->CheckAccessible(child_accessible);
    403   }
    404 }
    405 
    406 string16 AccessibleChecker::RoleVariantToString(
    407     const base::win::ScopedVariant& role) {
    408   if (role.type() == VT_I4)
    409     return IAccessibleRoleToString(V_I4(&role));
    410   if (role.type() == VT_BSTR)
    411     return string16(V_BSTR(&role), SysStringLen(V_BSTR(&role)));
    412   return string16();
    413 }
    414 
    415 }  // namespace
    416 
    417 
    418 // Tests ----------------------------------------------------------------------
    419 
    420 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    421                        MAYBE(TestBusyAccessibilityTree)) {
    422   NavigateToURL(shell(), GURL(kAboutBlankURL));
    423 
    424   // The initial accessible returned should have state STATE_SYSTEM_BUSY while
    425   // the accessibility tree is being requested from the renderer.
    426   AccessibleChecker document1_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
    427                                       std::wstring());
    428   document1_checker.SetExpectedState(
    429       STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED |
    430       STATE_SYSTEM_BUSY);
    431   document1_checker.CheckAccessible(GetRendererAccessible());
    432 }
    433 
    434 // Flaky, http://crbug.com/167320 .
    435 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    436                        DISABLED_TestRendererAccessibilityTree) {
    437   LoadInitialAccessibilityTreeFromHtml(
    438       "<html><head><title>Accessibility Win Test</title></head>"
    439       "<body><input type='button' value='push' /><input type='checkbox' />"
    440       "</body></html>");
    441 
    442   // Check the browser's copy of the renderer accessibility tree.
    443   AccessibleChecker button_checker(L"push", ROLE_SYSTEM_PUSHBUTTON,
    444                                    std::wstring());
    445   AccessibleChecker checkbox_checker(std::wstring(), ROLE_SYSTEM_CHECKBUTTON,
    446                                      std::wstring());
    447   AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
    448                                  std::wstring());
    449   AccessibleChecker document2_checker(L"Accessibility Win Test",
    450                                       ROLE_SYSTEM_DOCUMENT, std::wstring());
    451   body_checker.AppendExpectedChild(&button_checker);
    452   body_checker.AppendExpectedChild(&checkbox_checker);
    453   document2_checker.AppendExpectedChild(&body_checker);
    454   document2_checker.CheckAccessible(GetRendererAccessible());
    455 
    456   // Check that document accessible has a parent accessible.
    457   base::win::ScopedComPtr<IAccessible> document_accessible(
    458       GetRendererAccessible());
    459   ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
    460   base::win::ScopedComPtr<IDispatch> parent_dispatch;
    461   HRESULT hr = document_accessible->get_accParent(parent_dispatch.Receive());
    462   EXPECT_EQ(S_OK, hr);
    463   EXPECT_NE(parent_dispatch, reinterpret_cast<IDispatch*>(NULL));
    464 
    465   // Navigate to another page.
    466   NavigateToURL(shell(), GURL(kAboutBlankURL));
    467 
    468   // Verify that the IAccessible reference still points to a valid object and
    469   // that calls to its methods fail since the tree is no longer valid after
    470   // the page navagation.
    471   base::win::ScopedBstr name;
    472   base::win::ScopedVariant childid_self(CHILDID_SELF);
    473   hr = document_accessible->get_accName(childid_self, name.Receive());
    474   ASSERT_EQ(E_FAIL, hr);
    475 }
    476 
    477 // Periodically failing.  See crbug.com/145537
    478 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    479                        DISABLED_TestNotificationActiveDescendantChanged) {
    480   LoadInitialAccessibilityTreeFromHtml(
    481       "<ul tabindex='-1' role='radiogroup' aria-label='ul'>"
    482       "<li id='li'>li</li></ul>");
    483 
    484   // Check the browser's copy of the renderer accessibility tree.
    485   AccessibleChecker list_marker_checker(L"\x2022", ROLE_SYSTEM_TEXT,
    486                                         std::wstring());
    487   AccessibleChecker static_text_checker(L"li", ROLE_SYSTEM_TEXT,
    488                                         std::wstring());
    489   AccessibleChecker list_item_checker(std::wstring(), ROLE_SYSTEM_LISTITEM,
    490                                       std::wstring());
    491   list_item_checker.SetExpectedState(STATE_SYSTEM_READONLY);
    492   AccessibleChecker radio_group_checker(L"ul", ROLE_SYSTEM_GROUPING,
    493                                         IA2_ROLE_SECTION, std::wstring());
    494   radio_group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
    495   AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
    496                                      std::wstring());
    497   list_item_checker.AppendExpectedChild(&list_marker_checker);
    498   list_item_checker.AppendExpectedChild(&static_text_checker);
    499   radio_group_checker.AppendExpectedChild(&list_item_checker);
    500   document_checker.AppendExpectedChild(&radio_group_checker);
    501   document_checker.CheckAccessible(GetRendererAccessible());
    502 
    503   // Set focus to the radio group.
    504   scoped_ptr<AccessibilityNotificationWaiter> waiter(
    505       new AccessibilityNotificationWaiter(
    506           shell(), AccessibilityModeComplete,
    507           AccessibilityNotificationFocusChanged));
    508   ExecuteScript(L"document.body.children[0].focus()");
    509   waiter->WaitForNotification();
    510 
    511   // Check that the accessibility tree of the browser has been updated.
    512   radio_group_checker.SetExpectedState(
    513       STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED);
    514   document_checker.CheckAccessible(GetRendererAccessible());
    515 
    516   // Set the active descendant of the radio group
    517   waiter.reset(new AccessibilityNotificationWaiter(
    518       shell(), AccessibilityModeComplete,
    519       AccessibilityNotificationFocusChanged));
    520   ExecuteScript(
    521       L"document.body.children[0].setAttribute('aria-activedescendant', 'li')");
    522   waiter->WaitForNotification();
    523 
    524   // Check that the accessibility tree of the browser has been updated.
    525   list_item_checker.SetExpectedState(
    526       STATE_SYSTEM_READONLY | STATE_SYSTEM_FOCUSED);
    527   radio_group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
    528   document_checker.CheckAccessible(GetRendererAccessible());
    529 }
    530 
    531 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    532                        MAYBE(TestNotificationCheckedStateChanged)) {
    533   LoadInitialAccessibilityTreeFromHtml(
    534       "<body><input type='checkbox' /></body>");
    535 
    536   // Check the browser's copy of the renderer accessibility tree.
    537   AccessibleChecker checkbox_checker(std::wstring(), ROLE_SYSTEM_CHECKBUTTON,
    538                                      std::wstring());
    539   checkbox_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
    540   AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
    541                                  std::wstring());
    542   AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
    543                                      std::wstring());
    544   body_checker.AppendExpectedChild(&checkbox_checker);
    545   document_checker.AppendExpectedChild(&body_checker);
    546   document_checker.CheckAccessible(GetRendererAccessible());
    547 
    548   // Check the checkbox.
    549   scoped_ptr<AccessibilityNotificationWaiter> waiter(
    550       new AccessibilityNotificationWaiter(
    551           shell(), AccessibilityModeComplete,
    552           AccessibilityNotificationCheckStateChanged));
    553   ExecuteScript(L"document.body.children[0].checked=true");
    554   waiter->WaitForNotification();
    555 
    556   // Check that the accessibility tree of the browser has been updated.
    557   checkbox_checker.SetExpectedState(
    558       STATE_SYSTEM_CHECKED | STATE_SYSTEM_FOCUSABLE);
    559   document_checker.CheckAccessible(GetRendererAccessible());
    560 }
    561 
    562 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    563                        MAYBE(TestNotificationChildrenChanged)) {
    564   // The role attribute causes the node to be in the accessibility tree.
    565   LoadInitialAccessibilityTreeFromHtml("<body role=group></body>");
    566 
    567   // Check the browser's copy of the renderer accessibility tree.
    568   AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
    569                                   std::wstring());
    570   AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
    571                                      std::wstring());
    572   document_checker.AppendExpectedChild(&group_checker);
    573   document_checker.CheckAccessible(GetRendererAccessible());
    574 
    575   // Change the children of the document body.
    576   scoped_ptr<AccessibilityNotificationWaiter> waiter(
    577       new AccessibilityNotificationWaiter(
    578           shell(),
    579           AccessibilityModeComplete,
    580           AccessibilityNotificationChildrenChanged));
    581   ExecuteScript(L"document.body.innerHTML='<b>new text</b>'");
    582   waiter->WaitForNotification();
    583 
    584   // Check that the accessibility tree of the browser has been updated.
    585   AccessibleChecker text_checker(L"new text", ROLE_SYSTEM_TEXT, std::wstring());
    586   group_checker.AppendExpectedChild(&text_checker);
    587   document_checker.CheckAccessible(GetRendererAccessible());
    588 }
    589 
    590 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    591                        MAYBE(TestNotificationChildrenChanged2)) {
    592   // The role attribute causes the node to be in the accessibility tree.
    593   LoadInitialAccessibilityTreeFromHtml(
    594       "<div role=group style='visibility: hidden'>text</div>");
    595 
    596   // Check the accessible tree of the browser.
    597   AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
    598                                      std::wstring());
    599   document_checker.CheckAccessible(GetRendererAccessible());
    600 
    601   // Change the children of the document body.
    602   scoped_ptr<AccessibilityNotificationWaiter> waiter(
    603       new AccessibilityNotificationWaiter(
    604           shell(), AccessibilityModeComplete,
    605           AccessibilityNotificationChildrenChanged));
    606   ExecuteScript(L"document.body.children[0].style.visibility='visible'");
    607   waiter->WaitForNotification();
    608 
    609   // Check that the accessibility tree of the browser has been updated.
    610   AccessibleChecker static_text_checker(L"text", ROLE_SYSTEM_TEXT,
    611                                         std::wstring());
    612   AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
    613                                   std::wstring());
    614   document_checker.AppendExpectedChild(&group_checker);
    615   group_checker.AppendExpectedChild(&static_text_checker);
    616   document_checker.CheckAccessible(GetRendererAccessible());
    617 }
    618 
    619 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    620                        MAYBE(TestNotificationFocusChanged)) {
    621   // The role attribute causes the node to be in the accessibility tree.
    622   LoadInitialAccessibilityTreeFromHtml("<div role=group tabindex='-1'></div>");
    623 
    624   // Check the browser's copy of the renderer accessibility tree.
    625   SCOPED_TRACE("Check initial tree");
    626   AccessibleChecker group_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
    627                                   std::wstring());
    628   group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
    629   AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
    630                                      std::wstring());
    631   document_checker.AppendExpectedChild(&group_checker);
    632   document_checker.CheckAccessible(GetRendererAccessible());
    633 
    634   // Focus the div in the document
    635   scoped_ptr<AccessibilityNotificationWaiter> waiter(
    636       new AccessibilityNotificationWaiter(
    637           shell(), AccessibilityModeComplete,
    638           AccessibilityNotificationFocusChanged));
    639   ExecuteScript(L"document.body.children[0].focus()");
    640   waiter->WaitForNotification();
    641 
    642   // Check that the accessibility tree of the browser has been updated.
    643   SCOPED_TRACE("Check updated tree after focusing div");
    644   group_checker.SetExpectedState(
    645       STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED);
    646   document_checker.CheckAccessible(GetRendererAccessible());
    647 
    648   // Focus the document accessible. This will un-focus the current node.
    649   waiter.reset(
    650       new AccessibilityNotificationWaiter(
    651           shell(), AccessibilityModeComplete,
    652           AccessibilityNotificationBlur));
    653   base::win::ScopedComPtr<IAccessible> document_accessible(
    654       GetRendererAccessible());
    655   ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
    656   base::win::ScopedVariant childid_self(CHILDID_SELF);
    657   HRESULT hr = document_accessible->accSelect(SELFLAG_TAKEFOCUS, childid_self);
    658   ASSERT_EQ(S_OK, hr);
    659   waiter->WaitForNotification();
    660 
    661   // Check that the accessibility tree of the browser has been updated.
    662   SCOPED_TRACE("Check updated tree after focusing document again");
    663   group_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
    664   document_checker.CheckAccessible(GetRendererAccessible());
    665 }
    666 
    667 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    668                        MAYBE(TestNotificationValueChanged)) {
    669   LoadInitialAccessibilityTreeFromHtml(
    670       "<body><input type='text' value='old value'/></body>");
    671 
    672   // Check the browser's copy of the renderer accessibility tree.
    673   AccessibleChecker text_field_checker(std::wstring(), ROLE_SYSTEM_TEXT,
    674                                        L"old value");
    675   text_field_checker.SetExpectedState(STATE_SYSTEM_FOCUSABLE);
    676   AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
    677                                  std::wstring());
    678   AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
    679                                      std::wstring());
    680   body_checker.AppendExpectedChild(&text_field_checker);
    681   document_checker.AppendExpectedChild(&body_checker);
    682   document_checker.CheckAccessible(GetRendererAccessible());
    683 
    684   // Set the value of the text control
    685   scoped_ptr<AccessibilityNotificationWaiter> waiter(
    686       new AccessibilityNotificationWaiter(
    687           shell(), AccessibilityModeComplete,
    688           AccessibilityNotificationValueChanged));
    689   ExecuteScript(L"document.body.children[0].value='new value'");
    690   waiter->WaitForNotification();
    691 
    692   // Check that the accessibility tree of the browser has been updated.
    693   text_field_checker.SetExpectedValue(L"new value");
    694   document_checker.CheckAccessible(GetRendererAccessible());
    695 }
    696 
    697 // This test verifies that the web content's accessibility tree is a
    698 // descendant of the main browser window's accessibility tree, so that
    699 // tools like AccExplorer32 or AccProbe can be used to examine Chrome's
    700 // accessibility support.
    701 //
    702 // If you made a change and this test now fails, check that the NativeViewHost
    703 // that wraps the tab contents returns the IAccessible implementation
    704 // provided by RenderWidgetHostViewWin in GetNativeViewAccessible().
    705 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    706                        MAYBE(ContainsRendererAccessibilityTree)) {
    707   LoadInitialAccessibilityTreeFromHtml(
    708       "<html><head><title>MyDocument</title></head>"
    709       "<body>Content</body></html>");
    710 
    711   // Get the accessibility object for the browser window.
    712   HWND browser_hwnd = shell()->window();
    713   base::win::ScopedComPtr<IAccessible> browser_accessible;
    714   HRESULT hr = AccessibleObjectFromWindow(
    715       browser_hwnd,
    716       OBJID_WINDOW,
    717       IID_IAccessible,
    718       reinterpret_cast<void**>(browser_accessible.Receive()));
    719   ASSERT_EQ(S_OK, hr);
    720 
    721   bool found = false;
    722   RecursiveFindNodeInAccessibilityTree(
    723       browser_accessible.get(), ROLE_SYSTEM_DOCUMENT, L"MyDocument", 0, &found);
    724   ASSERT_EQ(found, true);
    725 }
    726 
    727 // Disabled because of http://crbug.com/144390.
    728 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    729                        DISABLED_TestToggleButtonRoleAndStates) {
    730   AccessibleChecker* button_checker;
    731   std::string button_html("data:text/html,");
    732   AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
    733                                      std::wstring());
    734   AccessibleChecker body_checker(std::wstring(), L"body", IA2_ROLE_SECTION,
    735                                  std::wstring());
    736   document_checker.AppendExpectedChild(&body_checker);
    737 
    738 // Temporary macro
    739 #define ADD_BUTTON(html, ia2_role, state) \
    740     button_html += html; \
    741     button_checker = new AccessibleChecker(L"x", ROLE_SYSTEM_PUSHBUTTON, \
    742       ia2_role, std::wstring()); \
    743     button_checker->SetExpectedState(state); \
    744     body_checker.AppendExpectedChild(button_checker)
    745 
    746   // If aria-pressed is 'undefined', empty or not present, use PUSHBUTTON
    747   // Otherwise use TOGGLE_BUTTON, even if the value is invalid.
    748   // The spec does this in an attempt future-proof in case new values are added.
    749   ADD_BUTTON("<span role='button' aria-pressed='false'>x</span>",
    750       IA2_ROLE_TOGGLE_BUTTON, 0);
    751   ADD_BUTTON("<span role='button' aria-pressed='true'>x</span>",
    752       IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_PRESSED);
    753   ADD_BUTTON("<span role='button' aria-pressed='mixed'>x</span>",
    754       IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_MIXED);
    755   ADD_BUTTON("<span role='button' aria-pressed='xyz'>x</span>",
    756     IA2_ROLE_TOGGLE_BUTTON, 0);
    757   ADD_BUTTON("<span role='button' aria-pressed=''>x</span>",
    758       ROLE_SYSTEM_PUSHBUTTON, 0);
    759   ADD_BUTTON("<span role='button' aria-pressed>x</span>",
    760       ROLE_SYSTEM_PUSHBUTTON, 0);
    761   ADD_BUTTON("<span role='button' aria-pressed='undefined'>x</span>",
    762       ROLE_SYSTEM_PUSHBUTTON, 0);
    763   ADD_BUTTON("<span role='button'>x</span>", ROLE_SYSTEM_PUSHBUTTON, 0);
    764   ADD_BUTTON("<input type='button' aria-pressed='true' value='x'/>",
    765       IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_PRESSED);
    766   ADD_BUTTON("<input type='button' aria-pressed='false' value='x'/>",
    767       IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE);
    768   ADD_BUTTON("<input type='button' aria-pressed='mixed' value='x'>",
    769       IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_MIXED);
    770   ADD_BUTTON("<input type='button' aria-pressed='xyz' value='x'/>",
    771       IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE);
    772   ADD_BUTTON("<input type='button' aria-pressed='' value='x'/>",
    773       ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
    774   ADD_BUTTON("<input type='button' aria-pressed value='x'>",
    775       ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
    776   ADD_BUTTON("<input type='button' aria-pressed='undefined' value='x'>",
    777       ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
    778   ADD_BUTTON("<input type='button' value='x'>",
    779       ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
    780   ADD_BUTTON("<button aria-pressed='true'>x</button>",
    781       IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_PRESSED);
    782   ADD_BUTTON("<button aria-pressed='false'>x</button>",
    783       IA2_ROLE_TOGGLE_BUTTON, STATE_SYSTEM_FOCUSABLE);
    784   ADD_BUTTON("<button aria-pressed='mixed'>x</button>", IA2_ROLE_TOGGLE_BUTTON,
    785       STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_MIXED);
    786   ADD_BUTTON("<button aria-pressed='xyz'>x</button>", IA2_ROLE_TOGGLE_BUTTON,
    787       STATE_SYSTEM_FOCUSABLE);
    788   ADD_BUTTON("<button aria-pressed=''>x</button>",
    789       ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
    790   ADD_BUTTON("<button aria-pressed>x</button>",
    791       ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
    792   ADD_BUTTON("<button aria-pressed='undefined'>x</button>",
    793       ROLE_SYSTEM_PUSHBUTTON, STATE_SYSTEM_FOCUSABLE);
    794   ADD_BUTTON("<button>x</button>", ROLE_SYSTEM_PUSHBUTTON,
    795       STATE_SYSTEM_FOCUSABLE);
    796 #undef ADD_BUTTON    // Temporary macro
    797 
    798   LoadInitialAccessibilityTreeFromHtml(button_html);
    799   document_checker.CheckAccessible(GetRendererAccessible());
    800 }
    801 
    802 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest,
    803                        MAYBE(SupportsISimpleDOM)) {
    804   LoadInitialAccessibilityTreeFromHtml(
    805       "<body><input type='checkbox' /></body>");
    806 
    807   // Get the IAccessible object for the document.
    808   base::win::ScopedComPtr<IAccessible> document_accessible(
    809       GetRendererAccessible());
    810   ASSERT_NE(document_accessible.get(), reinterpret_cast<IAccessible*>(NULL));
    811 
    812   // Get the ISimpleDOM object for the document.
    813   base::win::ScopedComPtr<IServiceProvider> service_provider;
    814   HRESULT hr = static_cast<IAccessible*>(document_accessible)->QueryInterface(
    815       service_provider.Receive());
    816   ASSERT_EQ(S_OK, hr);
    817   const GUID refguid = {0x0c539790, 0x12e4, 0x11cf,
    818                         0xb6, 0x61, 0x00, 0xaa, 0x00, 0x4c, 0xd6, 0xd8};
    819   base::win::ScopedComPtr<ISimpleDOMNode> document_isimpledomnode;
    820   hr = static_cast<IServiceProvider *>(service_provider)->QueryService(
    821       refguid, IID_ISimpleDOMNode,
    822       reinterpret_cast<void**>(document_isimpledomnode.Receive()));
    823   ASSERT_EQ(S_OK, hr);
    824 
    825   base::win::ScopedBstr node_name;
    826   short name_space_id;  // NOLINT
    827   base::win::ScopedBstr node_value;
    828   unsigned int num_children;
    829   unsigned int unique_id;
    830   unsigned short node_type;  // NOLINT
    831   hr = document_isimpledomnode->get_nodeInfo(
    832       node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
    833       &unique_id, &node_type);
    834   ASSERT_EQ(S_OK, hr);
    835   EXPECT_EQ(NODETYPE_DOCUMENT, node_type);
    836   EXPECT_EQ(1, num_children);
    837   node_name.Reset();
    838   node_value.Reset();
    839 
    840   base::win::ScopedComPtr<ISimpleDOMNode> body_isimpledomnode;
    841   hr = document_isimpledomnode->get_firstChild(
    842       body_isimpledomnode.Receive());
    843   ASSERT_EQ(S_OK, hr);
    844   hr = body_isimpledomnode->get_nodeInfo(
    845       node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
    846       &unique_id, &node_type);
    847   ASSERT_EQ(S_OK, hr);
    848   EXPECT_EQ(L"body", std::wstring(node_name, node_name.Length()));
    849   EXPECT_EQ(NODETYPE_ELEMENT, node_type);
    850   EXPECT_EQ(1, num_children);
    851   node_name.Reset();
    852   node_value.Reset();
    853 
    854   base::win::ScopedComPtr<ISimpleDOMNode> checkbox_isimpledomnode;
    855   hr = body_isimpledomnode->get_firstChild(
    856       checkbox_isimpledomnode.Receive());
    857   ASSERT_EQ(S_OK, hr);
    858   hr = checkbox_isimpledomnode->get_nodeInfo(
    859       node_name.Receive(), &name_space_id, node_value.Receive(), &num_children,
    860       &unique_id, &node_type);
    861   ASSERT_EQ(S_OK, hr);
    862   EXPECT_EQ(L"input", std::wstring(node_name, node_name.Length()));
    863   EXPECT_EQ(NODETYPE_ELEMENT, node_type);
    864   EXPECT_EQ(0, num_children);
    865 }
    866 
    867 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, MAYBE(TestRoleGroup)) {
    868   LoadInitialAccessibilityTreeFromHtml(
    869       "<fieldset></fieldset><div role=group></div>");
    870 
    871   // Check the browser's copy of the renderer accessibility tree.
    872   AccessibleChecker grouping1_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
    873                                       std::wstring());
    874   AccessibleChecker grouping2_checker(std::wstring(), ROLE_SYSTEM_GROUPING,
    875                                       std::wstring());
    876   AccessibleChecker document_checker(std::wstring(), ROLE_SYSTEM_DOCUMENT,
    877                                      std::wstring());
    878   document_checker.AppendExpectedChild(&grouping1_checker);
    879   document_checker.AppendExpectedChild(&grouping2_checker);
    880   document_checker.CheckAccessible(GetRendererAccessible());
    881 }
    882 
    883 }  // namespace content
    884