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