OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2014 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 "base/command_line.h" | |
6 #include "base/logging.h" | |
7 #include "content/browser/accessibility/browser_accessibility.h" | |
8 #include "content/browser/accessibility/browser_accessibility_manager.h" | |
9 #include "content/browser/frame_host/frame_tree.h" | |
10 #include "content/browser/renderer_host/render_view_host_impl.h" | |
11 #include "content/browser/web_contents/web_contents_impl.h" | |
12 #include "content/port/browser/render_widget_host_view_port.h" | |
13 #include "content/public/browser/browser_accessibility_state.h" | |
14 #include "content/public/browser/notification_observer.h" | |
15 #include "content/public/browser/notification_service.h" | |
16 #include "content/public/browser/notification_types.h" | |
17 #include "content/public/browser/web_contents.h" | |
18 #include "content/public/browser/web_contents_observer.h" | |
19 #include "content/public/common/content_switches.h" | |
20 #include "content/public/common/url_constants.h" | |
21 #include "content/public/test/browser_test_utils.h" | |
22 #include "content/public/test/content_browser_test.h" | |
23 #include "content/public/test/content_browser_test_utils.h" | |
24 #include "content/public/test/test_utils.h" | |
25 #include "content/shell/browser/shell.h" | |
26 #include "content/test/accessibility_browser_test_utils.h" | |
27 #include "net/dns/mock_host_resolver.h" | |
28 #include "testing/gtest/include/gtest/gtest.h" | |
29 #include "url/gurl.h" | |
30 | |
31 namespace content { | |
32 | |
33 namespace { | |
34 | |
35 // TODO: share this with site_per_process_browsertest.cc | |
36 class SitePerProcessWebContentsObserver: public WebContentsObserver { | |
37 public: | |
38 explicit SitePerProcessWebContentsObserver(WebContents* web_contents) | |
39 : WebContentsObserver(web_contents), | |
40 navigation_succeeded_(false) {} | |
41 virtual ~SitePerProcessWebContentsObserver() {} | |
42 | |
43 virtual void DidStartProvisionalLoadForFrame( | |
44 int64 frame_id, | |
45 int64 parent_frame_id, | |
46 bool is_main_frame, | |
47 const GURL& validated_url, | |
48 bool is_error_page, | |
49 bool is_iframe_srcdoc, | |
50 RenderViewHost* render_view_host) OVERRIDE { | |
51 navigation_succeeded_ = false; | |
52 } | |
53 | |
54 virtual void DidFailProvisionalLoad( | |
55 int64 frame_id, | |
56 const base::string16& frame_unique_name, | |
57 bool is_main_frame, | |
58 const GURL& validated_url, | |
59 int error_code, | |
60 const base::string16& error_description, | |
61 RenderViewHost* render_view_host) OVERRIDE { | |
62 navigation_url_ = validated_url; | |
63 navigation_succeeded_ = false; | |
64 } | |
65 | |
66 virtual void DidCommitProvisionalLoadForFrame( | |
67 int64 frame_id, | |
68 const base::string16& frame_unique_name, | |
69 bool is_main_frame, | |
70 const GURL& url, | |
71 PageTransition transition_type, | |
72 RenderViewHost* render_view_host) OVERRIDE{ | |
73 navigation_url_ = url; | |
74 navigation_succeeded_ = true; | |
75 } | |
76 | |
77 const GURL& navigation_url() const { | |
78 return navigation_url_; | |
79 } | |
80 | |
81 int navigation_succeeded() const { return navigation_succeeded_; } | |
82 | |
83 private: | |
84 GURL navigation_url_; | |
85 bool navigation_succeeded_; | |
86 | |
87 DISALLOW_COPY_AND_ASSIGN(SitePerProcessWebContentsObserver); | |
88 }; | |
89 | |
90 } // namespace. | |
91 | |
92 class SitePerProcessAccessibilityBrowserTest : public ContentBrowserTest { | |
93 public: | |
94 SitePerProcessAccessibilityBrowserTest() {} | |
95 | |
96 protected: | |
97 // Start at a data URL so each extra navigation creates a navigation entry. | |
98 // (The first navigation will silently be classified as AUTO_SUBFRAME.) | |
99 // TODO(creis): This won't be necessary when we can wait for LOAD_STOP. | |
100 void StartFrameAtDataURL() { | |
101 std::string data_url_script = | |
102 "var iframes = document.getElementById('test');iframes.src=" | |
103 "'data:text/html,dataurl';"; | |
104 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script)); | |
105 } | |
106 | |
107 // TODO: share this with site_per_process_browsertest.cc | |
108 bool NavigateIframeToURL(Shell* window, | |
ncarter (slow)
2014/05/02 19:10:02
One OKR we have for this quarter is to try to get
| |
109 const GURL& url, | |
110 std::string iframe_id) { | |
111 // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe | |
112 // navigations generate extra DidStartLoading and DidStopLoading messages. | |
113 // Until we replace swappedout:// with frame proxies, we need to listen for | |
114 // something else. For now, we trigger NEW_SUBFRAME navigations and listen | |
115 // for commit. | |
116 std::string script = base::StringPrintf( | |
117 "setTimeout(\"" | |
118 "var iframes = document.getElementById('%s');iframes.src='%s';" | |
119 "\",0)", | |
120 iframe_id.c_str(), url.spec().c_str()); | |
121 WindowedNotificationObserver load_observer( | |
122 NOTIFICATION_NAV_ENTRY_COMMITTED, | |
123 Source<NavigationController>( | |
124 &window->web_contents()->GetController())); | |
125 bool result = ExecuteScript(window->web_contents(), script); | |
126 load_observer.Wait(); | |
127 return result; | |
128 } | |
129 | |
130 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | |
131 command_line->AppendSwitch(switches::kSitePerProcess); | |
132 } | |
133 }; | |
134 | |
135 IN_PROC_BROWSER_TEST_F(SitePerProcessAccessibilityBrowserTest, | |
136 CrossSiteIframeAccessibility) { | |
137 // Enable full accessibility for all current and future RenderWidgetHosts. | |
138 BrowserAccessibilityState::GetInstance()->EnableAccessibility(); | |
139 | |
140 AccessibilityNotificationWaiter accessibility_waiter( | |
141 shell(), AccessibilityModeComplete, | |
142 ui::AX_EVENT_LOAD_COMPLETE); | |
143 | |
144 host_resolver()->AddRule("*", "127.0.0.1"); | |
145 ASSERT_TRUE(test_server()->Start()); | |
146 GURL main_url(test_server()->GetURL("files/site_per_process_main.html")); | |
147 NavigateToURL(shell(), main_url); | |
148 | |
149 StartFrameAtDataURL(); | |
150 | |
151 SitePerProcessWebContentsObserver observer(shell()->web_contents()); | |
152 | |
153 // TODO: share this with site_per_process_browsertest.cc | |
154 | |
155 // Load same-site page into iframe. | |
156 GURL http_url(test_server()->GetURL("files/title1.html")); | |
157 EXPECT_TRUE(NavigateIframeToURL(shell(), http_url, "test")); | |
158 EXPECT_EQ(http_url, observer.navigation_url()); | |
159 EXPECT_TRUE(observer.navigation_succeeded()); | |
160 | |
161 // These must stay in scope with replace_host. | |
162 GURL::Replacements replace_host; | |
163 std::string foo_com("foo.com"); | |
164 | |
165 // Load cross-site page into iframe. | |
166 GURL cross_site_url(test_server()->GetURL("files/title2.html")); | |
167 replace_host.SetHostStr(foo_com); | |
168 cross_site_url = cross_site_url.ReplaceComponents(replace_host); | |
169 EXPECT_TRUE(NavigateIframeToURL(shell(), cross_site_url, "test")); | |
170 EXPECT_EQ(cross_site_url, observer.navigation_url()); | |
171 EXPECT_TRUE(observer.navigation_succeeded()); | |
172 | |
173 // Ensure that we have created a new process for the subframe. | |
174 FrameTreeNode* root = | |
175 static_cast<WebContentsImpl*>(shell()->web_contents())-> | |
176 GetFrameTree()->root(); | |
177 ASSERT_EQ(1U, root->child_count()); | |
178 FrameTreeNode* child = root->child_at(0); | |
179 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), | |
180 child->current_frame_host()->render_view_host()); | |
181 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), | |
182 child->current_frame_host()->render_view_host()->GetSiteInstance()); | |
183 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), | |
184 child->current_frame_host()->GetProcess()); | |
185 | |
186 RenderViewHostImpl* child_rvhi = | |
187 child->current_frame_host()->render_view_host(); | |
188 | |
189 AccessibilityNotificationWaiter accessibility_waiter2( | |
190 shell(), AccessibilityModeComplete, ui::AX_EVENT_LOAD_COMPLETE, | |
191 child_rvhi); | |
192 | |
193 accessibility_waiter.WaitForNotification(); | |
194 accessibility_waiter2.WaitForNotification(); | |
195 | |
196 RenderWidgetHostViewPort* host_view = RenderWidgetHostViewPort::FromRWHV( | |
197 shell()->web_contents()->GetRenderWidgetHostView()); | |
198 | |
199 BrowserAccessibilityManager* manager = | |
200 host_view->GetBrowserAccessibilityManager(); | |
201 LOG(INFO) << "Main frame accessibility tree:\n" | |
202 << manager->SnapshotAXTreeForTesting().ToString(); | |
203 | |
204 BrowserAccessibilityManager* child_frame_manager = | |
205 RenderWidgetHostViewPort::FromRWHV(child_rvhi->GetView())-> | |
206 GetBrowserAccessibilityManager(); | |
207 LOG(INFO) << "Child frame accessibility tree:\n" | |
208 << child_frame_manager->SnapshotAXTreeForTesting().ToString(); | |
209 | |
210 // Assert that we can walk from the main frame down into the child frame | |
211 // directly, getting correct roles and data along the way. | |
212 | |
213 BrowserAccessibility* ax_root = manager->GetRoot(); | |
214 ASSERT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, ax_root->GetRole()); | |
215 ASSERT_EQ(1U, ax_root->PlatformChildCount()); | |
216 | |
217 BrowserAccessibility* ax_group = ax_root->PlatformGetChild(0); | |
218 ASSERT_EQ(ui::AX_ROLE_GROUP, ax_group->GetRole()); | |
219 ASSERT_EQ(1U, ax_group->PlatformChildCount()); | |
220 | |
221 BrowserAccessibility* ax_iframe = ax_group->PlatformGetChild(0); | |
222 ASSERT_EQ(ui::AX_ROLE_IFRAME, ax_iframe->GetRole()); | |
223 ASSERT_EQ(1U, ax_iframe->PlatformChildCount()); | |
224 | |
225 BrowserAccessibility* ax_scroll_area = ax_iframe->PlatformGetChild(0); | |
226 ASSERT_EQ(ui::AX_ROLE_SCROLL_AREA, ax_scroll_area->GetRole()); | |
227 ASSERT_EQ(1U, ax_scroll_area->PlatformChildCount()); | |
228 | |
229 BrowserAccessibility* ax_child_frame_root = | |
230 ax_scroll_area->PlatformGetChild(0); | |
231 ASSERT_EQ(ui::AX_ROLE_ROOT_WEB_AREA, ax_child_frame_root->GetRole()); | |
232 ASSERT_EQ(1U, ax_child_frame_root->PlatformChildCount()); | |
233 ASSERT_EQ("Title Of Awesomeness", ax_child_frame_root->name()); | |
234 | |
235 BrowserAccessibility* ax_child_frame_group = | |
236 ax_child_frame_root->PlatformGetChild(0); | |
237 ASSERT_EQ(ui::AX_ROLE_GROUP, ax_child_frame_group->GetRole()); | |
238 ASSERT_EQ(1U, ax_child_frame_group->PlatformChildCount()); | |
239 | |
240 BrowserAccessibility* ax_child_frame_static_text = | |
241 ax_child_frame_group->PlatformGetChild(0); | |
242 ASSERT_EQ(ui::AX_ROLE_STATIC_TEXT, ax_child_frame_static_text->GetRole()); | |
243 ASSERT_EQ(0U, ax_child_frame_static_text->PlatformChildCount()); | |
244 } | |
245 | |
246 } // namespace content | |
OLD | NEW |