12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/time/time.h"
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/common/frame_messages.h"
8effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/common/view_message_enums.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/test/render_view_test.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/renderer/accessibility/renderer_accessibility_complete.h"
11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/renderer/render_frame_impl.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/renderer/render_view_impl.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebSize.h"
1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "third_party/WebKit/public/web/WebAXObject.h"
167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebDocument.h"
177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebView.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/accessibility/ax_node_data.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebAXObject;
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)using blink::WebDocument;
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content {
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class TestRendererAccessibilityComplete : public RendererAccessibilityComplete {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  explicit TestRendererAccessibilityComplete(RenderFrameImpl* render_frame)
28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    : RendererAccessibilityComplete(render_frame) {
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  void SendPendingAccessibilityEvents() {
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    RendererAccessibilityComplete::SendPendingAccessibilityEvents();
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class RendererAccessibilityTest : public RenderViewTest {
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RendererAccessibilityTest() {}
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RenderViewImpl* view() {
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return static_cast<RenderViewImpl*>(view_);
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RenderFrameImpl* frame() {
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return static_cast<RenderFrameImpl*>(view()->GetMainRenderFrame());
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void SetUp() {
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RenderViewTest::SetUp();
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sink_ = &render_thread_->sink();
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  void SetMode(AccessibilityMode mode) {
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    frame()->OnSetAccessibilityMode(mode);
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  void GetLastAccEvent(
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      AccessibilityHostMsg_EventParams* params) {
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const IPC::Message* message =
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        sink_->GetUniqueMessageMatching(AccessibilityHostMsg_Events::ID);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_TRUE(message);
6229b820f8d84e3bc97d62552e54923c42407f2f29Ben Murdoch    Tuple2<std::vector<AccessibilityHostMsg_EventParams>, int> param;
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AccessibilityHostMsg_Events::Read(message, &param);
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ASSERT_GE(param.a.size(), 1U);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *params = param.a[0];
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int CountAccessibilityNodesSentToBrowser() {
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AccessibilityHostMsg_EventParams event;
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetLastAccEvent(&event);
71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return event.update.nodes.size();
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) protected:
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  IPC::TestSink* sink_;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(RendererAccessibilityTest);
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)TEST_F(RendererAccessibilityTest, EditableTextModeFocusEvents) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This is not a test of true web accessibility, it's a test of
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // a mode used on Windows 8 in Metro mode where an extremely simplified
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // accessibility tree containing only the current focused node is
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // generated.
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetMode(AccessibilityModeEditableTextOnly);
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Set a minimum size and give focus so simulated events work.
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  view()->webwidget()->resize(blink::WebSize(500, 500));
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  view()->webwidget()->setFocus(true);
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string html =
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "<body>"
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  <input>"
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  <textarea></textarea>"
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  <p contentEditable>Editable</p>"
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  <div tabindex=0 role=textbox>Textbox</div>"
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  <button>Button</button>"
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  <a href=#>Link</a>"
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "</body>";
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Load the test page.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LoadHTML(html.c_str());
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We should have sent a message to the browser with the initial focus
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // on the document.
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SCOPED_TRACE("Initial focus on document");
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AccessibilityHostMsg_EventParams event;
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetLastAccEvent(&event);
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EXPECT_EQ(event.event_type,
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              ui::AX_EVENT_LAYOUT_COMPLETE);
11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EXPECT_EQ(event.id, 1);
114c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes.size(), 2U);
115c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[0].id, 1);
116c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[0].role,
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              ui::AX_ROLE_ROOT_WEB_AREA);
118c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[0].state,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_READ_ONLY) |
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSABLE) |
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSED));
122c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[0].child_ids.size(), 1U);
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Now focus the input element, and check everything again.
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SCOPED_TRACE("input");
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sink_->ClearMessages();
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExecuteJavaScript("document.querySelector('input').focus();");
13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AccessibilityHostMsg_EventParams event;
13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetLastAccEvent(&event);
13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EXPECT_EQ(event.event_type,
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              ui::AX_EVENT_FOCUS);
13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EXPECT_EQ(event.id, 3);
135c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[0].id, 1);
136c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[0].role,
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              ui::AX_ROLE_ROOT_WEB_AREA);
138c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[0].state,
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_READ_ONLY) |
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSABLE));
141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[0].child_ids.size(), 1U);
142c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[1].id, 3);
143c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[1].role,
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              ui::AX_ROLE_GROUP);
145c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[1].state,
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSABLE) |
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSED));
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check other editable text nodes.
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SCOPED_TRACE("textarea");
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sink_->ClearMessages();
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExecuteJavaScript("document.querySelector('textarea').focus();");
15558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AccessibilityHostMsg_EventParams event;
15658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetLastAccEvent(&event);
15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EXPECT_EQ(event.id, 4);
158c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[1].state,
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSABLE) |
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSED));
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SCOPED_TRACE("contentEditable");
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sink_->ClearMessages();
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExecuteJavaScript("document.querySelector('p').focus();");
16758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AccessibilityHostMsg_EventParams event;
16858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetLastAccEvent(&event);
16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EXPECT_EQ(event.id, 5);
170c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[1].state,
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSABLE) |
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSED));
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SCOPED_TRACE("role=textarea");
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sink_->ClearMessages();
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExecuteJavaScript("document.querySelector('div').focus();");
17958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AccessibilityHostMsg_EventParams event;
18058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetLastAccEvent(&event);
18158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EXPECT_EQ(event.id, 6);
182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[1].state,
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSABLE) |
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSED));
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Try focusing things that aren't editable text.
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SCOPED_TRACE("button");
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sink_->ClearMessages();
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExecuteJavaScript("document.querySelector('button').focus();");
19258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AccessibilityHostMsg_EventParams event;
19358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetLastAccEvent(&event);
19458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EXPECT_EQ(event.id, 7);
195c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[1].state,
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSABLE) |
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSED) |
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_READ_ONLY));
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SCOPED_TRACE("link");
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sink_->ClearMessages();
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExecuteJavaScript("document.querySelector('a').focus();");
20558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AccessibilityHostMsg_EventParams event;
20658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetLastAccEvent(&event);
20758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EXPECT_EQ(event.id, 8);
208c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(event.update.nodes[1].state,
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSABLE) |
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_FOCUSED) |
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              (1U << ui::AX_STATE_READ_ONLY));
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Clear focus.
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SCOPED_TRACE("Back to document.");
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sink_->ClearMessages();
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ExecuteJavaScript("document.activeElement.blur()");
21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AccessibilityHostMsg_EventParams event;
22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetLastAccEvent(&event);
22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    EXPECT_EQ(event.id, 1);
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(RendererAccessibilityTest, SendFullAccessibilityTreeOnReload) {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // The job of RendererAccessibilityComplete is to serialize the
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // accessibility tree built by WebKit and send it to the browser.
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // When the accessibility tree changes, it tries to send only
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the nodes that actually changed or were reparented. This test
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ensures that the messages sent are correct in cases when a page
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // reloads, and that internal state is properly garbage-collected.
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string html =
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "<body>"
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  <div role='group' id='A'>"
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "    <div role='group' id='A1'></div>"
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "    <div role='group' id='A2'></div>"
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  </div>"
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "</body>";
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LoadHTML(html.c_str());
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Creating a RendererAccessibilityComplete should sent the tree
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // to the browser.
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<TestRendererAccessibilityComplete> accessibility(
244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new TestRendererAccessibilityComplete(frame()));
24558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(4, CountAccessibilityNodesSentToBrowser());
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // If we post another event but the tree doesn't change,
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // we should only send 1 node to the browser.
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sink_->ClearMessages();
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebDocument document = view()->GetWebView()->mainFrame()->document();
25258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  WebAXObject root_obj = document.accessibilityObject();
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  accessibility->HandleAXEvent(
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      root_obj,
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui::AX_EVENT_LAYOUT_COMPLETE);
25658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(1, CountAccessibilityNodesSentToBrowser());
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Make sure it's the root object that was updated.
26058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AccessibilityHostMsg_EventParams event;
26158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GetLastAccEvent(&event);
262c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    EXPECT_EQ(root_obj.axID(), event.update.nodes[0].id);
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
26558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // If we reload the page and send a event, we should send
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // all 4 nodes to the browser. Also double-check that we didn't
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // leak any of the old BrowserTreeNodes.
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LoadHTML(html.c_str());
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  document = view()->GetWebView()->mainFrame()->document();
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  root_obj = document.accessibilityObject();
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sink_->ClearMessages();
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  accessibility->HandleAXEvent(
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      root_obj,
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui::AX_EVENT_LAYOUT_COMPLETE);
27558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(4, CountAccessibilityNodesSentToBrowser());
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
27858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Even if the first event is sent on an element other than
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the root, the whole tree should be updated because we know
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the browser doesn't have the root element.
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LoadHTML(html.c_str());
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  document = view()->GetWebView()->mainFrame()->document();
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  root_obj = document.accessibilityObject();
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sink_->ClearMessages();
28558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const WebAXObject& first_child = root_obj.childAt(0);
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  accessibility->HandleAXEvent(
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      first_child,
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui::AX_EVENT_LIVE_REGION_CHANGED);
28958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(4, CountAccessibilityNodesSentToBrowser());
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// http://crbug.com/253537
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_ANDROID)
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#define MAYBE_AccessibilityMessagesQueueWhileSwappedOut \
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        DISABLED_AccessibilityMessagesQueueWhileSwappedOut
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#else
298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#define MAYBE_AccessibilityMessagesQueueWhileSwappedOut \
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        AccessibilityMessagesQueueWhileSwappedOut
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_F(RendererAccessibilityTest,
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       MAYBE_AccessibilityMessagesQueueWhileSwappedOut) {
304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string html =
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      "<body>"
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      "  <p>Hello, world.</p>"
307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      "</body>";
308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  LoadHTML(html.c_str());
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static const int kProxyRoutingId = 13;
310eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
311eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Creating a RendererAccessibilityComplete should send the tree
312eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // to the browser.
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<TestRendererAccessibilityComplete> accessibility(
314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new TestRendererAccessibilityComplete(frame()));
31558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
3160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  EXPECT_EQ(5, CountAccessibilityNodesSentToBrowser());
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
31858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // Post a "value changed" event, but then swap out
31958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // before sending it. It shouldn't send the event while
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // swapped out.
321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  sink_->ClearMessages();
322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  WebDocument document = view()->GetWebView()->mainFrame()->document();
32358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  WebAXObject root_obj = document.accessibilityObject();
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  accessibility->HandleAXEvent(
325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      root_obj,
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui::AX_EVENT_VALUE_CHANGED);
3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  view()->GetMainRenderFrame()->OnSwapOut(kProxyRoutingId);
32858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_FALSE(sink_->GetUniqueMessageMatching(
33058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      AccessibilityHostMsg_Events::ID));
331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Navigate, so we're not swapped out anymore. Now we should
33358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // send accessibility events again. Note that the
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // message that was queued up before will be quickly discarded
335eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // because the element it was referring to no longer exists,
33658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // so the event here is from loading this new page.
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FrameMsg_Navigate_Params nav_params;
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  nav_params.url = GURL("data:text/html,<p>Hello, again.</p>");
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  nav_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  nav_params.transition = ui::PAGE_TRANSITION_TYPED;
341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  nav_params.current_history_list_length = 1;
342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  nav_params.current_history_list_offset = 0;
343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  nav_params.pending_history_list_offset = 1;
344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  nav_params.page_id = -1;
345116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  nav_params.browser_navigation_start = base::TimeTicks::FromInternalValue(1);
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  frame()->OnNavigate(nav_params);
34758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_TRUE(sink_->GetUniqueMessageMatching(
34958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      AccessibilityHostMsg_Events::ID));
350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(RendererAccessibilityTest, HideAccessibilityObject) {
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Test RendererAccessibilityComplete and make sure it sends the
35458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // proper event to the browser when an object in the tree
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // is hidden, but its children are not.
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string html =
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "<body>"
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  <div role='group' id='A'>"
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "    <div role='group' id='B'>"
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "      <div role='group' id='C' style='visibility:visible'>"
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "      </div>"
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "    </div>"
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  </div>"
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "</body>";
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LoadHTML(html.c_str());
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<TestRendererAccessibilityComplete> accessibility(
368116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new TestRendererAccessibilityComplete(frame()));
36958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(4, CountAccessibilityNodesSentToBrowser());
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WebDocument document = view()->GetWebView()->mainFrame()->document();
37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  WebAXObject root_obj = document.accessibilityObject();
37458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  WebAXObject node_a = root_obj.childAt(0);
37558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  WebAXObject node_b = node_a.childAt(0);
37658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  WebAXObject node_c = node_b.childAt(0);
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Hide node 'B' ('C' stays visible).
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExecuteJavaScript(
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "document.getElementById('B').style.visibility = 'hidden';");
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Force layout now.
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExecuteJavaScript("document.getElementById('B').offsetLeft;");
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Send a childrenChanged on 'A'.
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sink_->ClearMessages();
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  accessibility->HandleAXEvent(
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      node_a,
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui::AX_EVENT_CHILDREN_CHANGED);
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
39058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
39158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  AccessibilityHostMsg_EventParams event;
39258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  GetLastAccEvent(&event);
393c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ASSERT_EQ(2U, event.update.nodes.size());
394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // RendererAccessibilityComplete notices that 'C' is being reparented,
396c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // so it clears the subtree rooted at 'A', then updates 'A' and then 'C'.
397c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(node_a.axID(), event.update.node_id_to_clear);
398c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(node_a.axID(), event.update.nodes[0].id);
399c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(node_c.axID(), event.update.nodes[1].id);
400c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(2, CountAccessibilityNodesSentToBrowser());
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(RendererAccessibilityTest, ShowAccessibilityObject) {
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Test RendererAccessibilityComplete and make sure it sends the
40558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // proper event to the browser when an object in the tree
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // is shown, causing its own already-visible children to be
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // reparented to it.
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string html =
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "<body>"
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  <div role='group' id='A'>"
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "    <div role='group' id='B' style='visibility:hidden'>"
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "      <div role='group' id='C' style='visibility:visible'>"
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "      </div>"
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "    </div>"
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "  </div>"
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "</body>";
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LoadHTML(html.c_str());
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<TestRendererAccessibilityComplete> accessibility(
420116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new TestRendererAccessibilityComplete(frame()));
42158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(3, CountAccessibilityNodesSentToBrowser());
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Show node 'B', then send a childrenChanged on 'A'.
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExecuteJavaScript(
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "document.getElementById('B').style.visibility = 'visible';");
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExecuteJavaScript("document.getElementById('B').offsetLeft;");
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sink_->ClearMessages();
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebDocument document = view()->GetWebView()->mainFrame()->document();
43158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  WebAXObject root_obj = document.accessibilityObject();
43258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  WebAXObject node_a = root_obj.childAt(0);
433c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  WebAXObject node_b = node_a.childAt(0);
434c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  WebAXObject node_c = node_b.childAt(0);
435c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  accessibility->HandleAXEvent(
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      node_a,
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui::AX_EVENT_CHILDREN_CHANGED);
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
44058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
44158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  AccessibilityHostMsg_EventParams event;
44258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  GetLastAccEvent(&event);
443c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
444c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ASSERT_EQ(3U, event.update.nodes.size());
445c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(node_a.axID(), event.update.node_id_to_clear);
446c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(node_a.axID(), event.update.nodes[0].id);
447c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(node_b.axID(), event.update.nodes[1].id);
448c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(node_c.axID(), event.update.nodes[2].id);
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(3, CountAccessibilityNodesSentToBrowser());
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)TEST_F(RendererAccessibilityTest, DetachAccessibilityObject) {
453d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Test RendererAccessibilityComplete and make sure it sends the
454d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // proper event to the browser when an object in the tree
455d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // is detached, but its children are not. This can happen when
456d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // a layout occurs and an anonymous render block is no longer needed.
457d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::string html =
458d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      "<body aria-label='Body'>"
459d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      "<span>1</span><span style='display:block'>2</span>"
460d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      "</body>";
461d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  LoadHTML(html.c_str());
462d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
463d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  scoped_ptr<TestRendererAccessibilityComplete> accessibility(
464116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new TestRendererAccessibilityComplete(frame()));
465d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
4660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  EXPECT_EQ(7, CountAccessibilityNodesSentToBrowser());
467d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
468d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Initially, the accessibility tree looks like this:
469d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //
470d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //   Document
471d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //   +--Body
472d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //      +--Anonymous Block
473d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //         +--Static Text "1"
4740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  //            +--Inline Text Box "1"
475d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //      +--Static Text "2"
4760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  //         +--Inline Text Box "2"
477d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  WebDocument document = view()->GetWebView()->mainFrame()->document();
478d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  WebAXObject root_obj = document.accessibilityObject();
479d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  WebAXObject body = root_obj.childAt(0);
480d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  WebAXObject anonymous_block = body.childAt(0);
481d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  WebAXObject text_1 = anonymous_block.childAt(0);
482d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  WebAXObject text_2 = body.childAt(1);
483d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
484d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Change the display of the second 'span' back to inline, which causes the
485d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // anonymous block to be destroyed.
486d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ExecuteJavaScript(
487d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      "document.querySelectorAll('span')[1].style.display = 'inline';");
488d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Force layout now.
489d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ExecuteJavaScript("document.body.offsetLeft;");
490d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
491d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Send a childrenChanged on the body.
492d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  sink_->ClearMessages();
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  accessibility->HandleAXEvent(
494d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      body,
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ui::AX_EVENT_CHILDREN_CHANGED);
496d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
497d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
498d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
499d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Afterwards, the accessibility tree looks like this:
500d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //
501d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //   Document
502d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //   +--Body
503d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //      +--Static Text "1"
5040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  //         +--Inline Text Box "1"
505d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //      +--Static Text "2"
5060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  //         +--Inline Text Box "2"
507d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  //
508d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // We just assert that there are now four nodes in the
509d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // accessibility tree and that only three nodes needed
510d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // to be updated (the body, the static text 1, and
511d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // the static text 2).
512d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
513d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  AccessibilityHostMsg_EventParams event;
514d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  GetLastAccEvent(&event);
515c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ASSERT_EQ(5U, event.update.nodes.size());
516d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
517c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(body.axID(), event.update.nodes[0].id);
518c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(text_1.axID(), event.update.nodes[1].id);
519d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // The third event is to update text_2, but its id changes
520d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // so we don't have a test expectation for it.
521d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
522d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
523cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)TEST_F(RendererAccessibilityTest, EventOnObjectNotInTree) {
524cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Test RendererAccessibilityComplete and make sure it doesn't send anything
525cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // if we get a notification from Blink for an object that isn't in the
526cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // tree, like the scroll area that's the parent of the main document,
527cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // which we don't expose.
528cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string html = "<body><input></body>";
529cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  LoadHTML(html.c_str());
530cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
531cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<TestRendererAccessibilityComplete> accessibility(
532116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new TestRendererAccessibilityComplete(frame()));
533cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
534cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(3, CountAccessibilityNodesSentToBrowser());
535cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
536cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  WebDocument document = view()->GetWebView()->mainFrame()->document();
537cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  WebAXObject root_obj = document.accessibilityObject();
538cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  WebAXObject scroll_area = root_obj.parentObject();
539cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_EQ(blink::WebAXRoleScrollArea, scroll_area.role());
540cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
541cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Try to fire a message on the scroll area, and assert that we just
542cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // ignore it.
543cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  sink_->ClearMessages();
544cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  accessibility->HandleAXEvent(scroll_area,
545cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               ui::AX_EVENT_VALUE_CHANGED);
546cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
547cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  accessibility->SendPendingAccessibilityEvents();
548cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
549cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const IPC::Message* message =
550cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      sink_->GetUniqueMessageMatching(AccessibilityHostMsg_Events::ID);
551cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_TRUE(message);
55229b820f8d84e3bc97d62552e54923c42407f2f29Ben Murdoch  Tuple2<std::vector<AccessibilityHostMsg_EventParams>, int> param;
553cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  AccessibilityHostMsg_Events::Read(message, &param);
554cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ASSERT_EQ(0U, param.a.size());
555cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
556cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace content
558