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