OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/site_per_process_browsertest.h" | 5 #include "content/browser/site_per_process_browsertest.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
(...skipping 13 matching lines...) Expand all Loading... |
24 #include "content/browser/frame_host/frame_tree.h" | 24 #include "content/browser/frame_host/frame_tree.h" |
25 #include "content/browser/frame_host/navigator.h" | 25 #include "content/browser/frame_host/navigator.h" |
26 #include "content/browser/frame_host/render_frame_proxy_host.h" | 26 #include "content/browser/frame_host/render_frame_proxy_host.h" |
27 #include "content/browser/frame_host/render_widget_host_view_child_frame.h" | 27 #include "content/browser/frame_host/render_widget_host_view_child_frame.h" |
28 #include "content/browser/gpu/compositor_util.h" | 28 #include "content/browser/gpu/compositor_util.h" |
29 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 29 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
30 #include "content/browser/renderer_host/input/synthetic_tap_gesture.h" | 30 #include "content/browser/renderer_host/input/synthetic_tap_gesture.h" |
31 #include "content/browser/renderer_host/render_view_host_impl.h" | 31 #include "content/browser/renderer_host/render_view_host_impl.h" |
32 #include "content/browser/renderer_host/render_widget_host_input_event_router.h" | 32 #include "content/browser/renderer_host/render_widget_host_input_event_router.h" |
33 #include "content/browser/renderer_host/render_widget_host_view_aura.h" | 33 #include "content/browser/renderer_host/render_widget_host_view_aura.h" |
| 34 #include "content/browser/web_contents/web_contents_impl.h" |
34 #include "content/common/frame_messages.h" | 35 #include "content/common/frame_messages.h" |
35 #include "content/common/input/synthetic_tap_gesture_params.h" | 36 #include "content/common/input/synthetic_tap_gesture_params.h" |
36 #include "content/common/view_messages.h" | 37 #include "content/common/view_messages.h" |
37 #include "content/public/browser/cert_store.h" | 38 #include "content/public/browser/cert_store.h" |
38 #include "content/public/browser/notification_observer.h" | 39 #include "content/public/browser/notification_observer.h" |
39 #include "content/public/browser/notification_service.h" | 40 #include "content/public/browser/notification_service.h" |
40 #include "content/public/browser/notification_types.h" | 41 #include "content/public/browser/notification_types.h" |
41 #include "content/public/browser/resource_dispatcher_host.h" | 42 #include "content/public/browser/resource_dispatcher_host.h" |
42 #include "content/public/common/browser_side_navigation_policy.h" | 43 #include "content/public/common/browser_side_navigation_policy.h" |
43 #include "content/public/common/content_switches.h" | 44 #include "content/public/common/content_switches.h" |
44 #include "content/public/common/url_constants.h" | 45 #include "content/public/common/url_constants.h" |
45 #include "content/public/test/browser_test_utils.h" | 46 #include "content/public/test/browser_test_utils.h" |
46 #include "content/public/test/content_browser_test_utils.h" | 47 #include "content/public/test/content_browser_test_utils.h" |
47 #include "content/public/test/test_navigation_observer.h" | 48 #include "content/public/test/test_navigation_observer.h" |
48 #include "content/public/test/test_utils.h" | 49 #include "content/public/test/test_utils.h" |
| 50 #include "content/shell/browser/shell.h" |
49 #include "content/test/content_browser_test_utils_internal.h" | 51 #include "content/test/content_browser_test_utils_internal.h" |
50 #include "content/test/test_frame_navigation_observer.h" | 52 #include "content/test/test_frame_navigation_observer.h" |
51 #include "ipc/ipc_security_test_util.h" | 53 #include "ipc/ipc_security_test_util.h" |
52 #include "net/dns/mock_host_resolver.h" | 54 #include "net/dns/mock_host_resolver.h" |
53 #include "net/test/embedded_test_server/embedded_test_server.h" | 55 #include "net/test/embedded_test_server/embedded_test_server.h" |
54 #include "third_party/WebKit/public/web/WebInputEvent.h" | 56 #include "third_party/WebKit/public/web/WebInputEvent.h" |
55 #include "third_party/WebKit/public/web/WebSandboxFlags.h" | 57 #include "third_party/WebKit/public/web/WebSandboxFlags.h" |
56 #include "ui/events/event.h" | 58 #include "ui/events/event.h" |
57 #include "ui/events/event_utils.h" | 59 #include "ui/events/event_utils.h" |
58 #include "ui/gfx/geometry/point.h" | 60 #include "ui/gfx/geometry/point.h" |
(...skipping 6170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6229 frame_observer.Wait(); | 6231 frame_observer.Wait(); |
6230 EXPECT_EQ(b_url, root->current_url()); | 6232 EXPECT_EQ(b_url, root->current_url()); |
6231 | 6233 |
6232 // Verify that the same RenderViewHost is preserved and that it is no longer | 6234 // Verify that the same RenderViewHost is preserved and that it is no longer |
6233 // in swapped out state. | 6235 // in swapped out state. |
6234 EXPECT_EQ(rvh, contents->GetFrameTree()->GetRenderViewHost( | 6236 EXPECT_EQ(rvh, contents->GetFrameTree()->GetRenderViewHost( |
6235 root->current_frame_host()->GetSiteInstance())); | 6237 root->current_frame_host()->GetSiteInstance())); |
6236 EXPECT_FALSE(rvh->is_swapped_out_); | 6238 EXPECT_FALSE(rvh->is_swapped_out_); |
6237 } | 6239 } |
6238 | 6240 |
6239 // This class will sniff incoming IPC for ViewHostMsg_TextInputStateChanged. | |
6240 class TextInputStateChangedMessageFilter : public BrowserMessageFilter { | |
6241 public: | |
6242 explicit TextInputStateChangedMessageFilter( | |
6243 RenderWidgetHostImpl* render_widget_host) | |
6244 : BrowserMessageFilter(ViewMsgStart), text_input_state_changed_(false) { | |
6245 if (!render_widget_host || !render_widget_host->GetProcess()) | |
6246 text_input_state_changed_ = true; | |
6247 old_state = *render_widget_host->GetView()->text_input_state(); | |
6248 render_widget_host->GetProcess()->AddFilter(this); | |
6249 } | |
6250 | |
6251 void WaitUntilTextInputStateChanges() { | |
6252 if (!text_input_state_changed_) { | |
6253 message_loop_runner_ = new MessageLoopRunner; | |
6254 message_loop_runner_->Run(); | |
6255 } | |
6256 } | |
6257 | |
6258 private: | |
6259 ~TextInputStateChangedMessageFilter() override {} | |
6260 | |
6261 bool OnMessageReceived(const IPC::Message& msg) override { | |
6262 IPC_BEGIN_MESSAGE_MAP(TextInputStateChangedMessageFilter, msg) | |
6263 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged, | |
6264 OnTextInputStateChangedMessageReceived) | |
6265 IPC_END_MESSAGE_MAP() | |
6266 return false; | |
6267 } | |
6268 | |
6269 void OnTextInputStateChangedMessageReceived(const TextInputState& new_state) { | |
6270 if (new_state.type != old_state.type || new_state.mode != old_state.mode || | |
6271 new_state.value != old_state.value) { | |
6272 text_input_state_changed_ = true; | |
6273 if (message_loop_runner_) | |
6274 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
6275 message_loop_runner_->QuitClosure()); | |
6276 } | |
6277 } | |
6278 | |
6279 bool text_input_state_changed_; | |
6280 scoped_refptr<MessageLoopRunner> message_loop_runner_; | |
6281 TextInputState old_state; | |
6282 | |
6283 DISALLOW_COPY_AND_ASSIGN(TextInputStateChangedMessageFilter); | |
6284 }; | |
6285 | |
6286 // Verify that when moving the focus between different frames, the WebContents | |
6287 // properly keeps track of the text input state. | |
6288 // The test loads a page with one input field, two out of process frames, and a | |
6289 // second input field positioned after the last <iframe>. Then a sequence of TAB | |
6290 // inputs are faked to navigate focus in between the different <input> elements. | |
6291 // After each change, we check with the RWHV of the frame as well as the | |
6292 // WebContents to make sure the text input state is as expected. | |
6293 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, TextInputStateChanged) { | |
6294 GURL main_page_url(embedded_test_server()->GetURL( | |
6295 "a.com", "/textinput/page_with_input_iframeX2_input.html")); | |
6296 NavigateToURL(shell(), main_page_url); | |
6297 | |
6298 WebContents* contents = shell()->web_contents(); | |
6299 | |
6300 FrameTreeNode* root = web_contents()->GetFrameTree()->root(); | |
6301 | |
6302 FrameTreeNode* child_b = root->child_at(0); | |
6303 GURL child_b_url(embedded_test_server()->GetURL( | |
6304 "b.com", "/textinput/page_with_input.html")); | |
6305 NavigateFrameToURL(child_b, child_b_url); | |
6306 EXPECT_TRUE(WaitForRenderFrameReady(child_b->current_frame_host())); | |
6307 | |
6308 FrameTreeNode* child_c = root->child_at(1); | |
6309 GURL child_c_url(embedded_test_server()->GetURL( | |
6310 "c.com", "/textinput/page_with_input.html")); | |
6311 NavigateFrameToURL(child_c, child_c_url); | |
6312 EXPECT_TRUE(WaitForRenderFrameReady(child_c->current_frame_host())); | |
6313 | |
6314 RenderWidgetHostImpl* root_rwh = | |
6315 root->current_frame_host()->GetRenderWidgetHost(); | |
6316 RenderWidgetHostViewBase* root_rwhv = root_rwh->GetView(); | |
6317 | |
6318 RenderWidgetHostImpl* child_b_rwh = | |
6319 child_b->current_frame_host()->GetRenderWidgetHost(); | |
6320 RenderWidgetHostViewBase* child_b_rwhv = child_b_rwh->GetView(); | |
6321 | |
6322 RenderWidgetHostImpl* child_c_rwh = | |
6323 child_c->current_frame_host()->GetRenderWidgetHost(); | |
6324 RenderWidgetHostViewBase* child_c_rwhv = child_c_rwh->GetView(); | |
6325 | |
6326 // Change the text value in <input> field of either frame so that we can | |
6327 // later track the changes. | |
6328 EXPECT_TRUE( | |
6329 ExecuteScript(child_b->current_frame_host(), | |
6330 "document.querySelector('input').value = 'second';")); | |
6331 EXPECT_TRUE( | |
6332 ExecuteScript(child_c->current_frame_host(), | |
6333 "document.querySelector('input').value = 'third';")); | |
6334 | |
6335 // Verify the input type is none in the beginning. | |
6336 EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, root_rwhv->text_input_state()->type); | |
6337 | |
6338 // A helper function to send a tab key to the frame and wait for a state | |
6339 // changed message. | |
6340 auto press_tab_and_wait_for_text_input_state_change = | |
6341 [contents](RenderWidgetHostImpl* rwh) { | |
6342 scoped_refptr<TextInputStateChangedMessageFilter> filter = | |
6343 new TextInputStateChangedMessageFilter(rwh); | |
6344 SimulateKeyPress(contents, ui::VKEY_TAB, false, false, false, false); | |
6345 filter->WaitUntilTextInputStateChanges(); | |
6346 }; | |
6347 | |
6348 // Send focus to the first input field. | |
6349 press_tab_and_wait_for_text_input_state_change(root_rwh); | |
6350 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, root_rwhv->text_input_state()->type); | |
6351 EXPECT_EQ("first", root_rwhv->text_input_state()->value); | |
6352 | |
6353 // Verify the top-level state is changed. | |
6354 EXPECT_EQ("first", web_contents()->GetTextInputState()->value); | |
6355 | |
6356 // Send focus to the input field in frame b. | |
6357 press_tab_and_wait_for_text_input_state_change(child_b_rwh); | |
6358 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, child_b_rwhv->text_input_state()->type); | |
6359 EXPECT_EQ("second", child_b_rwhv->text_input_state()->value); | |
6360 | |
6361 EXPECT_EQ("second", web_contents()->GetTextInputState()->value); | |
6362 | |
6363 // Send focus to the input field in frame c. | |
6364 press_tab_and_wait_for_text_input_state_change(child_c_rwh); | |
6365 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, child_c_rwhv->text_input_state()->type); | |
6366 EXPECT_EQ("third", child_c_rwhv->text_input_state()->value); | |
6367 | |
6368 EXPECT_EQ("third", web_contents()->GetTextInputState()->value); | |
6369 | |
6370 // Send focus to the last input field in top frame. | |
6371 press_tab_and_wait_for_text_input_state_change(root_rwh); | |
6372 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, root_rwhv->text_input_state()->type); | |
6373 EXPECT_EQ("fourth", root_rwhv->text_input_state()->value); | |
6374 | |
6375 EXPECT_EQ("fourth", web_contents()->GetTextInputState()->value); | |
6376 } | |
6377 | |
6378 // Disable this test on Android (http://crbug.com/603209) | |
6379 #if defined(OS_ANDROID) | |
6380 #define MAYBE_TextInputStateChangesAfterRendererCrashes \ | |
6381 DISABLED_TextInputStateChangesAfterRendererCrashes | |
6382 #else | |
6383 #define MAYBE_TextInputStateChangesAfterRendererCrashes \ | |
6384 TextInputStateChangesAfterRendererCrashes | |
6385 #endif | |
6386 | |
6387 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, | |
6388 MAYBE_TextInputStateChangesAfterRendererCrashes) { | |
6389 GURL main_url( | |
6390 embedded_test_server()->GetURL("a.com", "/page_with_iframe.html")); | |
6391 NavigateToURL(shell(), main_url); | |
6392 WebContentsImpl* contents = web_contents(); | |
6393 | |
6394 FrameTreeNode* root = contents->GetFrameTree()->root(); | |
6395 | |
6396 FrameTreeNode* child = root->child_at(0); | |
6397 GURL child_url(embedded_test_server()->GetURL( | |
6398 "b.com", "/textinput/page_with_input.html")); | |
6399 NavigateFrameToURL(child, child_url); | |
6400 EXPECT_TRUE(WaitForRenderFrameReady(child->current_frame_host())); | |
6401 | |
6402 // Verify that the text input state is initially none. | |
6403 EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, contents->GetTextInputState()->type); | |
6404 | |
6405 auto press_tab_and_wait_for_state_change = | |
6406 [contents](RenderWidgetHostImpl* rwh) { | |
6407 scoped_refptr<TextInputStateChangedMessageFilter> filter = | |
6408 new TextInputStateChangedMessageFilter(rwh); | |
6409 SimulateKeyPress(contents, ui::VKEY_TAB, false, false, false, false); | |
6410 filter->WaitUntilTextInputStateChanges(); | |
6411 }; | |
6412 | |
6413 auto crash_renderer_and_wait_for_input_state_none = [contents]( | |
6414 RenderProcessHost* host) { | |
6415 RenderProcessHostWatcher crash_observer( | |
6416 host, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); | |
6417 host->Shutdown(0, false); | |
6418 crash_observer.Wait(); | |
6419 | |
6420 // We need to wait until the actual text input state update occurs. | |
6421 while (contents->GetTextInputState()->type != ui::TEXT_INPUT_TYPE_NONE) { | |
6422 scoped_refptr<MessageLoopRunner> loop_runner_ = new MessageLoopRunner(); | |
6423 BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, | |
6424 loop_runner_->QuitClosure(), | |
6425 base::TimeDelta::FromMilliseconds(0LL)); | |
6426 loop_runner_->Run(); | |
6427 } | |
6428 }; | |
6429 | |
6430 // Press a tab key to focus the <input> and verify that the top level | |
6431 // WebContents sees it. | |
6432 RenderWidgetHostImpl* child_rwh = | |
6433 child->current_frame_host()->GetRenderWidgetHost(); | |
6434 press_tab_and_wait_for_state_change(child_rwh); | |
6435 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, contents->GetTextInputState()->type); | |
6436 | |
6437 // Crash the renderer and wait until WebContentsImpl has updates the | |
6438 // state. | |
6439 RenderProcessHost* child_process = child_rwh->GetProcess(); | |
6440 crash_renderer_and_wait_for_input_state_none(child_process); | |
6441 | |
6442 // Now repeat the same test for the top level RWHV. | |
6443 // First remove the <iframe> and append an <input> | |
6444 EXPECT_TRUE(ExecuteScript(contents, | |
6445 "var f = document.querySelector('iframe'); " | |
6446 "f.parentNode.removeChild(f);")); | |
6447 EXPECT_TRUE(ExecuteScript( | |
6448 contents, "document.body.appendChild(document.createElement('input'));")); | |
6449 | |
6450 // Press tab to focus the <input> and observe the state change. | |
6451 RenderWidgetHostImpl* root_rwh = | |
6452 root->current_frame_host()->GetRenderWidgetHost(); | |
6453 press_tab_and_wait_for_state_change(root_rwh); | |
6454 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, contents->GetTextInputState()->type); | |
6455 | |
6456 // Crash the tab renderer and observer the input state going back to none. | |
6457 RenderProcessHost* host_process = root_rwh->GetProcess(); | |
6458 crash_renderer_and_wait_for_input_state_none(host_process); | |
6459 } | |
6460 | |
6461 } // namespace content | 6241 } // namespace content |
OLD | NEW |