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" | |
35 #include "content/common/frame_messages.h" | 34 #include "content/common/frame_messages.h" |
36 #include "content/common/input/synthetic_tap_gesture_params.h" | 35 #include "content/common/input/synthetic_tap_gesture_params.h" |
37 #include "content/common/view_messages.h" | 36 #include "content/common/view_messages.h" |
38 #include "content/public/browser/cert_store.h" | 37 #include "content/public/browser/cert_store.h" |
39 #include "content/public/browser/notification_observer.h" | 38 #include "content/public/browser/notification_observer.h" |
40 #include "content/public/browser/notification_service.h" | 39 #include "content/public/browser/notification_service.h" |
41 #include "content/public/browser/notification_types.h" | 40 #include "content/public/browser/notification_types.h" |
42 #include "content/public/browser/resource_dispatcher_host.h" | 41 #include "content/public/browser/resource_dispatcher_host.h" |
43 #include "content/public/common/browser_side_navigation_policy.h" | 42 #include "content/public/common/browser_side_navigation_policy.h" |
44 #include "content/public/common/content_switches.h" | 43 #include "content/public/common/content_switches.h" |
45 #include "content/public/common/url_constants.h" | 44 #include "content/public/common/url_constants.h" |
46 #include "content/public/test/browser_test_utils.h" | 45 #include "content/public/test/browser_test_utils.h" |
47 #include "content/public/test/content_browser_test_utils.h" | 46 #include "content/public/test/content_browser_test_utils.h" |
48 #include "content/public/test/test_navigation_observer.h" | 47 #include "content/public/test/test_navigation_observer.h" |
49 #include "content/public/test/test_utils.h" | 48 #include "content/public/test/test_utils.h" |
50 #include "content/shell/browser/shell.h" | |
51 #include "content/test/content_browser_test_utils_internal.h" | 49 #include "content/test/content_browser_test_utils_internal.h" |
52 #include "content/test/test_frame_navigation_observer.h" | 50 #include "content/test/test_frame_navigation_observer.h" |
53 #include "ipc/ipc_security_test_util.h" | 51 #include "ipc/ipc_security_test_util.h" |
54 #include "net/dns/mock_host_resolver.h" | 52 #include "net/dns/mock_host_resolver.h" |
55 #include "net/test/embedded_test_server/embedded_test_server.h" | 53 #include "net/test/embedded_test_server/embedded_test_server.h" |
56 #include "third_party/WebKit/public/web/WebInputEvent.h" | 54 #include "third_party/WebKit/public/web/WebInputEvent.h" |
57 #include "third_party/WebKit/public/web/WebSandboxFlags.h" | 55 #include "third_party/WebKit/public/web/WebSandboxFlags.h" |
58 #include "ui/events/event.h" | 56 #include "ui/events/event.h" |
59 #include "ui/events/event_utils.h" | 57 #include "ui/events/event_utils.h" |
60 #include "ui/gfx/geometry/point.h" | 58 #include "ui/gfx/geometry/point.h" |
(...skipping 6254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6315 frame_observer.Wait(); | 6313 frame_observer.Wait(); |
6316 EXPECT_EQ(b_url, root->current_url()); | 6314 EXPECT_EQ(b_url, root->current_url()); |
6317 | 6315 |
6318 // Verify that the same RenderViewHost is preserved and that it is no longer | 6316 // Verify that the same RenderViewHost is preserved and that it is no longer |
6319 // in swapped out state. | 6317 // in swapped out state. |
6320 EXPECT_EQ(rvh, contents->GetFrameTree()->GetRenderViewHost( | 6318 EXPECT_EQ(rvh, contents->GetFrameTree()->GetRenderViewHost( |
6321 root->current_frame_host()->GetSiteInstance())); | 6319 root->current_frame_host()->GetSiteInstance())); |
6322 EXPECT_FALSE(rvh->is_swapped_out_); | 6320 EXPECT_FALSE(rvh->is_swapped_out_); |
6323 } | 6321 } |
6324 | 6322 |
| 6323 // This class will sniff incoming IPC for ViewHostMsg_TextInputStateChanged. |
| 6324 class TextInputStateChangedMessageFilter : public BrowserMessageFilter { |
| 6325 public: |
| 6326 explicit TextInputStateChangedMessageFilter( |
| 6327 RenderWidgetHostImpl* render_widget_host) |
| 6328 : BrowserMessageFilter(ViewMsgStart), text_input_state_changed_(false) { |
| 6329 if (!render_widget_host || !render_widget_host->GetProcess()) |
| 6330 text_input_state_changed_ = true; |
| 6331 old_state = *render_widget_host->GetView()->text_input_state(); |
| 6332 render_widget_host->GetProcess()->AddFilter(this); |
| 6333 } |
| 6334 |
| 6335 void WaitUntilTextInputStateChanges() { |
| 6336 if (!text_input_state_changed_) { |
| 6337 message_loop_runner_ = new MessageLoopRunner; |
| 6338 message_loop_runner_->Run(); |
| 6339 } |
| 6340 } |
| 6341 |
| 6342 private: |
| 6343 ~TextInputStateChangedMessageFilter() override {} |
| 6344 |
| 6345 bool OnMessageReceived(const IPC::Message& msg) override { |
| 6346 IPC_BEGIN_MESSAGE_MAP(TextInputStateChangedMessageFilter, msg) |
| 6347 IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputStateChanged, |
| 6348 OnTextInputStateChangedMessageReceived) |
| 6349 IPC_END_MESSAGE_MAP() |
| 6350 return false; |
| 6351 } |
| 6352 |
| 6353 void OnTextInputStateChangedMessageReceived(const TextInputState& new_state) { |
| 6354 if (new_state.type != old_state.type || new_state.mode != old_state.mode || |
| 6355 new_state.value != old_state.value) { |
| 6356 text_input_state_changed_ = true; |
| 6357 if (message_loop_runner_) |
| 6358 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| 6359 message_loop_runner_->QuitClosure()); |
| 6360 } |
| 6361 } |
| 6362 |
| 6363 bool text_input_state_changed_; |
| 6364 scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| 6365 TextInputState old_state; |
| 6366 |
| 6367 DISALLOW_COPY_AND_ASSIGN(TextInputStateChangedMessageFilter); |
| 6368 }; |
| 6369 |
| 6370 // Verify that when moving the focus between different frames, the WebContents |
| 6371 // properly keeps track of the text input state. |
| 6372 // The test loads a page with one input field, two out of process frames, and a |
| 6373 // second input field positioned after the last <iframe>. Then a sequence of TAB |
| 6374 // inputs are faked to navigate focus in between the different <input> elements. |
| 6375 // After each change, we check with the RWHV of the frame as well as the |
| 6376 // WebContents to make sure the text input state is as expected. |
| 6377 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, TextInputStateChanged) { |
| 6378 GURL main_page_url(embedded_test_server()->GetURL( |
| 6379 "a.com", "/textinput/page_with_input_iframeX2_input.html")); |
| 6380 NavigateToURL(shell(), main_page_url); |
| 6381 |
| 6382 WebContents* contents = shell()->web_contents(); |
| 6383 |
| 6384 FrameTreeNode* root = web_contents()->GetFrameTree()->root(); |
| 6385 |
| 6386 FrameTreeNode* child_b = root->child_at(0); |
| 6387 GURL child_b_url(embedded_test_server()->GetURL( |
| 6388 "b.com", "/textinput/page_with_input.html")); |
| 6389 NavigateFrameToURL(child_b, child_b_url); |
| 6390 EXPECT_TRUE(WaitForRenderFrameReady(child_b->current_frame_host())); |
| 6391 |
| 6392 FrameTreeNode* child_c = root->child_at(1); |
| 6393 GURL child_c_url(embedded_test_server()->GetURL( |
| 6394 "c.com", "/textinput/page_with_input.html")); |
| 6395 NavigateFrameToURL(child_c, child_c_url); |
| 6396 EXPECT_TRUE(WaitForRenderFrameReady(child_c->current_frame_host())); |
| 6397 |
| 6398 RenderWidgetHostImpl* root_rwh = |
| 6399 root->current_frame_host()->GetRenderWidgetHost(); |
| 6400 RenderWidgetHostViewBase* root_rwhv = root_rwh->GetView(); |
| 6401 |
| 6402 RenderWidgetHostImpl* child_b_rwh = |
| 6403 child_b->current_frame_host()->GetRenderWidgetHost(); |
| 6404 RenderWidgetHostViewBase* child_b_rwhv = child_b_rwh->GetView(); |
| 6405 |
| 6406 RenderWidgetHostImpl* child_c_rwh = |
| 6407 child_c->current_frame_host()->GetRenderWidgetHost(); |
| 6408 RenderWidgetHostViewBase* child_c_rwhv = child_c_rwh->GetView(); |
| 6409 |
| 6410 // Change the text value in <input> field of either frame so that we can |
| 6411 // later track the changes. |
| 6412 EXPECT_TRUE( |
| 6413 ExecuteScript(child_b->current_frame_host(), |
| 6414 "document.querySelector('input').value = 'second';")); |
| 6415 EXPECT_TRUE( |
| 6416 ExecuteScript(child_c->current_frame_host(), |
| 6417 "document.querySelector('input').value = 'third';")); |
| 6418 |
| 6419 // Verify the input type is none in the beginning. |
| 6420 EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, root_rwhv->text_input_state()->type); |
| 6421 |
| 6422 // A helper function to send a tab key to the frame and wait for a state |
| 6423 // changed message. |
| 6424 auto press_tab_and_wait_for_text_input_state_change = |
| 6425 [contents](RenderWidgetHostImpl* rwh) { |
| 6426 scoped_refptr<TextInputStateChangedMessageFilter> filter = |
| 6427 new TextInputStateChangedMessageFilter(rwh); |
| 6428 SimulateKeyPress(contents, ui::VKEY_TAB, false, false, false, false); |
| 6429 filter->WaitUntilTextInputStateChanges(); |
| 6430 }; |
| 6431 |
| 6432 // Send focus to the first input field. |
| 6433 press_tab_and_wait_for_text_input_state_change(root_rwh); |
| 6434 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, root_rwhv->text_input_state()->type); |
| 6435 EXPECT_EQ("first", root_rwhv->text_input_state()->value); |
| 6436 |
| 6437 // Verify the top-level state is changed. |
| 6438 EXPECT_EQ("first", web_contents()->GetTextInputState()->value); |
| 6439 |
| 6440 // Send focus to the input field in frame b. |
| 6441 press_tab_and_wait_for_text_input_state_change(child_b_rwh); |
| 6442 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, child_b_rwhv->text_input_state()->type); |
| 6443 EXPECT_EQ("second", child_b_rwhv->text_input_state()->value); |
| 6444 |
| 6445 EXPECT_EQ("second", web_contents()->GetTextInputState()->value); |
| 6446 |
| 6447 // Send focus to the input field in frame c. |
| 6448 press_tab_and_wait_for_text_input_state_change(child_c_rwh); |
| 6449 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, child_c_rwhv->text_input_state()->type); |
| 6450 EXPECT_EQ("third", child_c_rwhv->text_input_state()->value); |
| 6451 |
| 6452 EXPECT_EQ("third", web_contents()->GetTextInputState()->value); |
| 6453 |
| 6454 // Send focus to the last input field in top frame. |
| 6455 press_tab_and_wait_for_text_input_state_change(root_rwh); |
| 6456 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, root_rwhv->text_input_state()->type); |
| 6457 EXPECT_EQ("fourth", root_rwhv->text_input_state()->value); |
| 6458 |
| 6459 EXPECT_EQ("fourth", web_contents()->GetTextInputState()->value); |
| 6460 } |
| 6461 |
| 6462 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| 6463 TextInputStateChangesAfterRendererCrashes) { |
| 6464 GURL main_url( |
| 6465 embedded_test_server()->GetURL("a.com", "/page_with_iframe.html")); |
| 6466 NavigateToURL(shell(), main_url); |
| 6467 WebContentsImpl* contents = web_contents(); |
| 6468 |
| 6469 FrameTreeNode* root = contents->GetFrameTree()->root(); |
| 6470 |
| 6471 FrameTreeNode* child = root->child_at(0); |
| 6472 GURL child_url(embedded_test_server()->GetURL( |
| 6473 "b.com", "/textinput/page_with_input.html")); |
| 6474 NavigateFrameToURL(child, child_url); |
| 6475 EXPECT_TRUE(WaitForRenderFrameReady(child->current_frame_host())); |
| 6476 |
| 6477 // Verify that the text input state is initially none. |
| 6478 EXPECT_EQ(ui::TEXT_INPUT_TYPE_NONE, contents->GetTextInputState()->type); |
| 6479 |
| 6480 auto press_tab_and_wait_for_state_change = |
| 6481 [contents](RenderWidgetHostImpl* rwh) { |
| 6482 scoped_refptr<TextInputStateChangedMessageFilter> filter = |
| 6483 new TextInputStateChangedMessageFilter(rwh); |
| 6484 SimulateKeyPress(contents, ui::VKEY_TAB, false, false, false, false); |
| 6485 filter->WaitUntilTextInputStateChanges(); |
| 6486 }; |
| 6487 |
| 6488 auto crash_renderer_and_wait_for_input_state_none = [contents]( |
| 6489 RenderProcessHost* host) { |
| 6490 RenderProcessHostWatcher crash_observer( |
| 6491 host, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); |
| 6492 host->Shutdown(0, false); |
| 6493 crash_observer.Wait(); |
| 6494 |
| 6495 // We need to wait until the actual text input state update occurs. |
| 6496 while (contents->GetTextInputState()->type != ui::TEXT_INPUT_TYPE_NONE) { |
| 6497 scoped_refptr<MessageLoopRunner> loop_runner_ = new MessageLoopRunner(); |
| 6498 BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, |
| 6499 loop_runner_->QuitClosure(), |
| 6500 base::TimeDelta::FromMilliseconds(0LL)); |
| 6501 loop_runner_->Run(); |
| 6502 } |
| 6503 }; |
| 6504 |
| 6505 // Press a tab key to focus the <input> and verify that the top level |
| 6506 // WebContents sees it. |
| 6507 RenderWidgetHostImpl* child_rwh = |
| 6508 child->current_frame_host()->GetRenderWidgetHost(); |
| 6509 press_tab_and_wait_for_state_change(child_rwh); |
| 6510 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, contents->GetTextInputState()->type); |
| 6511 |
| 6512 // Crash the renderer and wait until WebContentsImpl has updates the |
| 6513 // state. |
| 6514 RenderProcessHost* child_process = child_rwh->GetProcess(); |
| 6515 crash_renderer_and_wait_for_input_state_none(child_process); |
| 6516 |
| 6517 // Now repeat the same test for the top level RWHV. |
| 6518 // First remove the <iframe> and append an <input> |
| 6519 EXPECT_TRUE(ExecuteScript(contents, |
| 6520 "var f = document.querySelector('iframe'); " |
| 6521 "f.parentNode.removeChild(f);")); |
| 6522 EXPECT_TRUE(ExecuteScript( |
| 6523 contents, "document.body.appendChild(document.createElement('input'));")); |
| 6524 |
| 6525 // Press tab to focus the <input> and observe the state change. |
| 6526 RenderWidgetHostImpl* root_rwh = |
| 6527 root->current_frame_host()->GetRenderWidgetHost(); |
| 6528 press_tab_and_wait_for_state_change(root_rwh); |
| 6529 EXPECT_EQ(ui::TEXT_INPUT_TYPE_TEXT, contents->GetTextInputState()->type); |
| 6530 |
| 6531 // Crash the tab renderer and observer the input state going back to none. |
| 6532 RenderProcessHost* host_process = root_rwh->GetProcess(); |
| 6533 crash_renderer_and_wait_for_input_state_none(host_process); |
| 6534 } |
| 6535 |
6325 } // namespace content | 6536 } // namespace content |
OLD | NEW |