1 // Copyright 2013 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.
5 #include "base/strings/utf_string_conversions.h"
6 #include "base/values.h"
7 #include "content/browser/frame_host/navigation_entry_impl.h"
8 #include "content/browser/renderer_host/render_widget_host_impl.h"
9 #include "content/browser/web_contents/web_contents_impl.h"
10 #include "content/browser/web_contents/web_contents_view.h"
11 #include "content/common/frame_messages.h"
12 #include "content/public/browser/load_notification_details.h"
13 #include "content/public/browser/navigation_controller.h"
14 #include "content/public/browser/notification_details.h"
15 #include "content/public/browser/notification_observer.h"
16 #include "content/public/browser/notification_types.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/render_widget_host_view.h"
19 #include "content/public/browser/web_contents_observer.h"
20 #include "content/public/common/content_paths.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_navigation_observer.h"
25 #include "content/public/test/test_utils.h"
26 #include "content/shell/browser/shell.h"
27 #include "net/dns/mock_host_resolver.h"
28 #include "net/test/embedded_test_server/embedded_test_server.h"
32 void ResizeWebContentsView(Shell
* shell
, const gfx::Size
& size
,
33 bool set_start_page
) {
34 // Shell::SizeTo is not implemented on Aura; WebContentsView::SizeContents
35 // works on Win and ChromeOS but not Linux - we need to resize the shell
36 // window on Linux because if we don't, the next layout of the unchanged shell
37 // window will resize WebContentsView back to the previous size.
38 // SizeContents is a hack and should not be relied on.
39 #if defined(OS_MACOSX)
41 // If |set_start_page| is true, start with blank page to make sure resize
44 NavigateToURL(shell
, GURL("about://blank"));
46 static_cast<WebContentsImpl
*>(shell
->web_contents())->GetView()->
48 #endif // defined(OS_MACOSX)
51 class WebContentsImplBrowserTest
: public ContentBrowserTest
{
53 WebContentsImplBrowserTest() {}
54 void SetUp() override
{
55 RenderWidgetHostImpl::DisableResizeAckCheckForTesting();
56 ContentBrowserTest::SetUp();
60 DISALLOW_COPY_AND_ASSIGN(WebContentsImplBrowserTest
);
63 // Keeps track of data from LoadNotificationDetails so we can later verify that
64 // they are correct, after the LoadNotificationDetails object is deleted.
65 class LoadStopNotificationObserver
: public WindowedNotificationObserver
{
67 LoadStopNotificationObserver(NavigationController
* controller
)
68 : WindowedNotificationObserver(NOTIFICATION_LOAD_STOP
,
69 Source
<NavigationController
>(controller
)),
73 void Observe(int type
,
74 const NotificationSource
& source
,
75 const NotificationDetails
& details
) override
{
76 if (type
== NOTIFICATION_LOAD_STOP
) {
77 const Details
<LoadNotificationDetails
> load_details(details
);
78 url_
= load_details
->url
;
79 session_index_
= load_details
->session_index
;
80 controller_
= load_details
->controller
;
82 WindowedNotificationObserver::Observe(type
, source
, details
);
87 NavigationController
* controller_
;
90 // Starts a new navigation as soon as the current one commits, but does not
91 // wait for it to complete. This allows us to observe DidStopLoading while
92 // a pending entry is present.
93 class NavigateOnCommitObserver
: public WebContentsObserver
{
95 NavigateOnCommitObserver(Shell
* shell
, GURL url
)
96 : WebContentsObserver(shell
->web_contents()),
102 // WebContentsObserver:
103 void NavigationEntryCommitted(
104 const LoadCommittedDetails
& load_details
) override
{
108 shell_
->LoadURL(url_
);
117 class RenderViewSizeDelegate
: public WebContentsDelegate
{
119 void set_size_insets(const gfx::Size
& size_insets
) {
120 size_insets_
= size_insets
;
123 // WebContentsDelegate:
124 gfx::Size
GetSizeForNewRenderView(WebContents
* web_contents
) const override
{
125 gfx::Size
size(web_contents
->GetContainerBounds().size());
126 size
.Enlarge(size_insets_
.width(), size_insets_
.height());
131 gfx::Size size_insets_
;
134 class RenderViewSizeObserver
: public WebContentsObserver
{
136 RenderViewSizeObserver(Shell
* shell
, const gfx::Size
& wcv_new_size
)
137 : WebContentsObserver(shell
->web_contents()),
139 wcv_new_size_(wcv_new_size
) {
142 // WebContentsObserver:
143 void RenderViewCreated(RenderViewHost
* rvh
) override
{
144 rwhv_create_size_
= rvh
->GetView()->GetViewBounds().size();
147 void DidStartNavigationToPendingEntry(
149 NavigationController::ReloadType reload_type
) override
{
150 ResizeWebContentsView(shell_
, wcv_new_size_
, false);
153 gfx::Size
rwhv_create_size() const { return rwhv_create_size_
; }
156 Shell
* shell_
; // Weak ptr.
157 gfx::Size wcv_new_size_
;
158 gfx::Size rwhv_create_size_
;
161 class LoadingStateChangedDelegate
: public WebContentsDelegate
{
163 LoadingStateChangedDelegate()
164 : loadingStateChangedCount_(0)
165 , loadingStateToDifferentDocumentCount_(0) {
168 // WebContentsDelegate:
169 void LoadingStateChanged(WebContents
* contents
,
170 bool to_different_document
) override
{
171 loadingStateChangedCount_
++;
172 if (to_different_document
)
173 loadingStateToDifferentDocumentCount_
++;
176 int loadingStateChangedCount() const { return loadingStateChangedCount_
; }
177 int loadingStateToDifferentDocumentCount() const {
178 return loadingStateToDifferentDocumentCount_
;
182 int loadingStateChangedCount_
;
183 int loadingStateToDifferentDocumentCount_
;
186 // See: http://crbug.com/298193
187 #if defined(OS_WIN) || defined(OS_LINUX)
188 #define MAYBE_DidStopLoadingDetails DISABLED_DidStopLoadingDetails
190 #define MAYBE_DidStopLoadingDetails DidStopLoadingDetails
193 // Test that DidStopLoading includes the correct URL in the details.
194 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
,
195 MAYBE_DidStopLoadingDetails
) {
196 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
198 LoadStopNotificationObserver
load_observer(
199 &shell()->web_contents()->GetController());
200 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
201 load_observer
.Wait();
203 EXPECT_EQ("/title1.html", load_observer
.url_
.path());
204 EXPECT_EQ(0, load_observer
.session_index_
);
205 EXPECT_EQ(&shell()->web_contents()->GetController(),
206 load_observer
.controller_
);
209 // See: http://crbug.com/298193
210 #if defined(OS_WIN) || defined(OS_LINUX)
211 #define MAYBE_DidStopLoadingDetailsWithPending \
212 DISABLED_DidStopLoadingDetailsWithPending
214 #define MAYBE_DidStopLoadingDetailsWithPending DidStopLoadingDetailsWithPending
217 // Test that DidStopLoading includes the correct URL in the details when a
218 // pending entry is present.
219 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
,
220 MAYBE_DidStopLoadingDetailsWithPending
) {
221 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
222 GURL
url("data:text/html,<div>test</div>");
224 // Listen for the first load to stop.
225 LoadStopNotificationObserver
load_observer(
226 &shell()->web_contents()->GetController());
227 // Start a new pending navigation as soon as the first load commits.
228 // We will hear a DidStopLoading from the first load as the new load
230 NavigateOnCommitObserver
commit_observer(
231 shell(), embedded_test_server()->GetURL("/title2.html"));
232 NavigateToURL(shell(), url
);
233 load_observer
.Wait();
235 EXPECT_EQ(url
, load_observer
.url_
);
236 EXPECT_EQ(0, load_observer
.session_index_
);
237 EXPECT_EQ(&shell()->web_contents()->GetController(),
238 load_observer
.controller_
);
240 // Test that a renderer-initiated navigation to an invalid URL does not leave
241 // around a pending entry that could be used in a URL spoof. We test this in
242 // a browser test because our unit test framework incorrectly calls
243 // DidStartProvisionalLoadForFrame for in-page navigations.
244 // See http://crbug.com/280512.
245 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
,
246 ClearNonVisiblePendingOnFail
) {
247 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
249 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
251 // Navigate to an invalid URL and make sure it doesn't leave a pending entry.
252 LoadStopNotificationObserver
load_observer1(
253 &shell()->web_contents()->GetController());
254 ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
255 "window.location.href=\"nonexistent:12121\";"));
256 load_observer1
.Wait();
257 EXPECT_FALSE(shell()->web_contents()->GetController().GetPendingEntry());
259 LoadStopNotificationObserver
load_observer2(
260 &shell()->web_contents()->GetController());
261 ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
262 "window.location.href=\"#foo\";"));
263 load_observer2
.Wait();
264 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html#foo"),
265 shell()->web_contents()->GetVisibleURL());
268 // Crashes under ThreadSanitizer, http://crbug.com/356758.
269 #if defined(OS_WIN) || defined(OS_ANDROID) \
270 || defined(THREAD_SANITIZER)
271 #define MAYBE_GetSizeForNewRenderView DISABLED_GetSizeForNewRenderView
273 #define MAYBE_GetSizeForNewRenderView GetSizeForNewRenderView
275 // Test that RenderViewHost is created and updated at the size specified by
276 // WebContentsDelegate::GetSizeForNewRenderView().
277 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
,
278 MAYBE_GetSizeForNewRenderView
) {
279 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
280 // Create a new server with a different site.
281 net::SpawnedTestServer
https_server(
282 net::SpawnedTestServer::TYPE_HTTPS
,
283 net::SpawnedTestServer::kLocalhost
,
284 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
285 ASSERT_TRUE(https_server
.Start());
287 scoped_ptr
<RenderViewSizeDelegate
> delegate(new RenderViewSizeDelegate());
288 shell()->web_contents()->SetDelegate(delegate
.get());
289 ASSERT_TRUE(shell()->web_contents()->GetDelegate() == delegate
.get());
291 // When no size is set, RenderWidgetHostView adopts the size of
293 NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html"));
294 EXPECT_EQ(shell()->web_contents()->GetContainerBounds().size(),
295 shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
298 // When a size is set, RenderWidgetHostView and WebContentsView honor this
300 gfx::Size
size(300, 300);
301 gfx::Size
size_insets(10, 15);
302 ResizeWebContentsView(shell(), size
, true);
303 delegate
->set_size_insets(size_insets
);
304 NavigateToURL(shell(), https_server
.GetURL("/"));
305 size
.Enlarge(size_insets
.width(), size_insets
.height());
307 shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
309 // The web_contents size is set by the embedder, and should not depend on the
310 // rwhv size. The behavior is correct on OSX, but incorrect on other
312 gfx::Size
exp_wcv_size(300, 300);
313 #if !defined(OS_MACOSX)
314 exp_wcv_size
.Enlarge(size_insets
.width(), size_insets
.height());
317 EXPECT_EQ(exp_wcv_size
,
318 shell()->web_contents()->GetContainerBounds().size());
320 // If WebContentsView is resized after RenderWidgetHostView is created but
321 // before pending navigation entry is committed, both RenderWidgetHostView and
322 // WebContentsView use the new size of WebContentsView.
323 gfx::Size
init_size(200, 200);
324 gfx::Size
new_size(100, 100);
325 size_insets
= gfx::Size(20, 30);
326 ResizeWebContentsView(shell(), init_size
, true);
327 delegate
->set_size_insets(size_insets
);
328 RenderViewSizeObserver
observer(shell(), new_size
);
329 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
330 // RenderWidgetHostView is created at specified size.
331 init_size
.Enlarge(size_insets
.width(), size_insets
.height());
332 EXPECT_EQ(init_size
, observer
.rwhv_create_size());
334 // Once again, the behavior is correct on OSX. The embedder explicitly sets
335 // the size to (100,100) during navigation. Both the wcv and the rwhv should
336 // take on that size.
337 #if !defined(OS_MACOSX)
338 new_size
.Enlarge(size_insets
.width(), size_insets
.height());
340 gfx::Size actual_size
= shell()->web_contents()->GetRenderWidgetHostView()->
341 GetViewBounds().size();
343 EXPECT_EQ(new_size
, actual_size
);
344 EXPECT_EQ(new_size
, shell()->web_contents()->GetContainerBounds().size());
347 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
, OpenURLSubframe
) {
348 // Navigate to a page with frames and grab a subframe's FrameTreeNode ID.
349 ASSERT_TRUE(test_server()->Start());
350 NavigateToURL(shell(),
351 test_server()->GetURL("files/frame_tree/top.html"));
352 WebContentsImpl
* wc
= static_cast<WebContentsImpl
*>(shell()->web_contents());
353 FrameTreeNode
* root
= wc
->GetFrameTree()->root();
354 ASSERT_EQ(3UL, root
->child_count());
355 int frame_tree_node_id
= root
->child_at(0)->frame_tree_node_id();
356 EXPECT_NE(-1, frame_tree_node_id
);
358 // Navigate with the subframe's FrameTreeNode ID.
359 const GURL
url(test_server()->GetURL("files/title1.html"));
360 OpenURLParams
params(url
, Referrer(), frame_tree_node_id
, CURRENT_TAB
,
361 ui::PAGE_TRANSITION_LINK
, true);
362 shell()->web_contents()->OpenURL(params
);
364 // Make sure the NavigationEntry ends up with the FrameTreeNode ID.
365 NavigationController
* controller
= &shell()->web_contents()->GetController();
366 EXPECT_TRUE(controller
->GetPendingEntry());
367 EXPECT_EQ(frame_tree_node_id
,
368 NavigationEntryImpl::FromNavigationEntry(
369 controller
->GetPendingEntry())->frame_tree_node_id());
372 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
,
373 AppendingFrameInWebUIDoesNotCrash
) {
374 const GURL
kWebUIUrl("chrome://tracing");
375 const char kJSCodeForAppendingFrame
[] =
376 "document.body.appendChild(document.createElement('iframe'));";
378 NavigateToURL(shell(), kWebUIUrl
);
380 bool js_executed
= content::ExecuteScript(shell()->web_contents(),
381 kJSCodeForAppendingFrame
);
382 EXPECT_TRUE(js_executed
);
385 // Observer class to track the creation of RenderFrameHost objects. It is used
386 // in subsequent tests.
387 class RenderFrameCreatedObserver
: public WebContentsObserver
{
389 RenderFrameCreatedObserver(Shell
* shell
)
390 : WebContentsObserver(shell
->web_contents()),
394 void RenderFrameCreated(RenderFrameHost
* render_frame_host
) override
{
395 last_rfh_
= render_frame_host
;
398 RenderFrameHost
* last_rfh() const { return last_rfh_
; }
401 RenderFrameHost
* last_rfh_
;
403 DISALLOW_COPY_AND_ASSIGN(RenderFrameCreatedObserver
);
406 // Test that creation of new RenderFrameHost objects sends the correct object
407 // to the WebContentObservers. See http://crbug.com/347339.
408 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
,
409 RenderFrameCreatedCorrectProcessForObservers
) {
410 static const char kFooCom
[] = "foo.com";
411 GURL::Replacements replace_host
;
412 net::HostPortPair foo_host_port
;
415 // Setup the server to allow serving separate sites, so we can perform
416 // cross-process navigation.
417 host_resolver()->AddRule("*", "127.0.0.1");
418 ASSERT_TRUE(test_server()->Start());
420 foo_host_port
= test_server()->host_port_pair();
421 foo_host_port
.set_host(kFooCom
);
423 GURL
initial_url(test_server()->GetURL("/title1.html"));
425 cross_site_url
= test_server()->GetURL("/title2.html");
426 replace_host
.SetHostStr(kFooCom
);
427 cross_site_url
= cross_site_url
.ReplaceComponents(replace_host
);
429 // Navigate to the initial URL and capture the RenderFrameHost for later
431 NavigateToURL(shell(), initial_url
);
432 RenderFrameHost
* orig_rfh
= shell()->web_contents()->GetMainFrame();
434 // Install the observer and navigate cross-site.
435 RenderFrameCreatedObserver
observer(shell());
436 NavigateToURL(shell(), cross_site_url
);
438 // The observer should've seen a RenderFrameCreated call for the new frame
439 // and not the old one.
440 EXPECT_NE(observer
.last_rfh(), orig_rfh
);
441 EXPECT_EQ(observer
.last_rfh(), shell()->web_contents()->GetMainFrame());
444 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
,
445 LoadingStateChangedForSameDocumentNavigation
) {
446 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
447 scoped_ptr
<LoadingStateChangedDelegate
> delegate(
448 new LoadingStateChangedDelegate());
449 shell()->web_contents()->SetDelegate(delegate
.get());
451 LoadStopNotificationObserver
load_observer(
452 &shell()->web_contents()->GetController());
453 TitleWatcher
title_watcher(shell()->web_contents(),
454 base::ASCIIToUTF16("pushState"));
455 NavigateToURL(shell(), embedded_test_server()->GetURL("/push_state.html"));
456 load_observer
.Wait();
457 base::string16 title
= title_watcher
.WaitAndGetTitle();
458 ASSERT_EQ(title
, base::ASCIIToUTF16("pushState"));
460 // LoadingStateChanged should be called 4 times: start and stop for the
461 // initial load of push_state.html, and start and stop for the "navigation"
462 // triggered by history.pushState(). However, the start notification for the
463 // history.pushState() navigation should set to_different_document to false.
464 EXPECT_EQ("pushState", shell()->web_contents()->GetLastCommittedURL().ref());
465 EXPECT_EQ(4, delegate
->loadingStateChangedCount());
466 EXPECT_EQ(3, delegate
->loadingStateToDifferentDocumentCount());
469 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
,
470 RenderViewCreatedForChildWindow
) {
471 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
473 NavigateToURL(shell(),
474 embedded_test_server()->GetURL("/title1.html"));
476 WebContentsAddedObserver new_web_contents_observer
;
477 ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
478 "var a = document.createElement('a');"
479 "a.href='./title2.html';"
480 "a.target = '_blank';"
481 "document.body.appendChild(a);"
483 WebContents
* new_web_contents
= new_web_contents_observer
.GetWebContents();
484 WaitForLoadStop(new_web_contents
);
485 EXPECT_TRUE(new_web_contents_observer
.RenderViewCreatedCalled());
488 struct LoadProgressDelegateAndObserver
: public WebContentsDelegate
,
489 public WebContentsObserver
{
490 LoadProgressDelegateAndObserver(Shell
* shell
)
491 : WebContentsObserver(shell
->web_contents()),
492 did_start_loading(false),
493 did_stop_loading(false) {
494 web_contents()->SetDelegate(this);
497 // WebContentsDelegate:
498 void LoadProgressChanged(WebContents
* source
, double progress
) override
{
499 EXPECT_TRUE(did_start_loading
);
500 EXPECT_FALSE(did_stop_loading
);
501 progresses
.push_back(progress
);
504 // WebContentsObserver:
505 void DidStartLoading() override
{
506 EXPECT_FALSE(did_start_loading
);
507 EXPECT_EQ(0U, progresses
.size());
508 EXPECT_FALSE(did_stop_loading
);
509 did_start_loading
= true;
512 void DidStopLoading() override
{
513 EXPECT_TRUE(did_start_loading
);
514 EXPECT_GE(progresses
.size(), 1U);
515 EXPECT_FALSE(did_stop_loading
);
516 did_stop_loading
= true;
519 bool did_start_loading
;
520 std::vector
<double> progresses
;
521 bool did_stop_loading
;
524 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
, LoadProgress
) {
525 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
526 scoped_ptr
<LoadProgressDelegateAndObserver
> delegate(
527 new LoadProgressDelegateAndObserver(shell()));
529 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
531 const std::vector
<double>& progresses
= delegate
->progresses
;
532 // All updates should be in order ...
533 if (std::adjacent_find(progresses
.begin(),
535 std::greater
<double>()) != progresses
.end()) {
536 ADD_FAILURE() << "Progress values should be in order: "
537 << ::testing::PrintToString(progresses
);
540 // ... and the last one should be 1.0, meaning complete.
541 ASSERT_GE(progresses
.size(), 1U)
542 << "There should be at least one progress update";
543 EXPECT_EQ(1.0, *progresses
.rbegin());
546 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
, LoadProgressWithFrames
) {
547 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
548 scoped_ptr
<LoadProgressDelegateAndObserver
> delegate(
549 new LoadProgressDelegateAndObserver(shell()));
551 NavigateToURL(shell(),
552 embedded_test_server()->GetURL("/frame_tree/top.html"));
554 const std::vector
<double>& progresses
= delegate
->progresses
;
555 // All updates should be in order ...
556 if (std::adjacent_find(progresses
.begin(),
558 std::greater
<double>()) != progresses
.end()) {
559 ADD_FAILURE() << "Progress values should be in order: "
560 << ::testing::PrintToString(progresses
);
563 // ... and the last one should be 1.0, meaning complete.
564 ASSERT_GE(progresses
.size(), 1U)
565 << "There should be at least one progress update";
566 EXPECT_EQ(1.0, *progresses
.rbegin());
569 // Ensure that a new navigation that interrupts a pending one will still fire
570 // a DidStopLoading. See http://crbug.com/429399.
571 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
,
572 LoadProgressAfterInterruptedNav
) {
573 host_resolver()->AddRule("*", "127.0.0.1");
574 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
576 // Start at a real page.
577 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
579 // Simulate a navigation that has not completed.
580 scoped_ptr
<LoadProgressDelegateAndObserver
> delegate(
581 new LoadProgressDelegateAndObserver(shell()));
582 RenderFrameHost
* main_frame
= shell()->web_contents()->GetMainFrame();
583 FrameHostMsg_DidStartLoading
start_msg(main_frame
->GetRoutingID(), true);
584 static_cast<RenderFrameHostImpl
*>(main_frame
)->OnMessageReceived(start_msg
);
585 EXPECT_TRUE(delegate
->did_start_loading
);
586 EXPECT_FALSE(delegate
->did_stop_loading
);
588 // Also simulate a DidChangeLoadProgress, but not a DidStopLoading.
589 FrameHostMsg_DidChangeLoadProgress
progress_msg(main_frame
->GetRoutingID(),
591 static_cast<RenderFrameHostImpl
*>(main_frame
)->OnMessageReceived(
593 EXPECT_TRUE(delegate
->did_start_loading
);
594 EXPECT_FALSE(delegate
->did_stop_loading
);
596 // Now interrupt with a new cross-process navigation.
597 TestNavigationObserver
tab_observer(shell()->web_contents(), 1);
598 GURL
url(embedded_test_server()->GetURL("foo.com", "/title2.html"));
599 shell()->LoadURL(url
);
601 EXPECT_EQ(url
, shell()->web_contents()->GetLastCommittedURL());
603 // We should have gotten to DidStopLoading.
604 EXPECT_TRUE(delegate
->did_stop_loading
);
607 struct FirstVisuallyNonEmptyPaintObserver
: public WebContentsObserver
{
608 FirstVisuallyNonEmptyPaintObserver(Shell
* shell
)
609 : WebContentsObserver(shell
->web_contents()),
610 did_fist_visually_non_empty_paint_(false) {}
612 void DidFirstVisuallyNonEmptyPaint() override
{
613 did_fist_visually_non_empty_paint_
= true;
614 on_did_first_visually_non_empty_paint_
.Run();
617 void WaitForDidFirstVisuallyNonEmptyPaint() {
618 if (did_fist_visually_non_empty_paint_
)
620 base::RunLoop run_loop
;
621 on_did_first_visually_non_empty_paint_
= run_loop
.QuitClosure();
625 base::Closure on_did_first_visually_non_empty_paint_
;
626 bool did_fist_visually_non_empty_paint_
;
629 // See: http://crbug.com/395664
630 #if defined(OS_ANDROID)
631 #define MAYBE_FirstVisuallyNonEmptyPaint DISABLED_FirstVisuallyNonEmptyPaint
633 // http://crbug.com/398471
634 #define MAYBE_FirstVisuallyNonEmptyPaint DISABLED_FirstVisuallyNonEmptyPaint
636 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
,
637 MAYBE_FirstVisuallyNonEmptyPaint
) {
638 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
639 scoped_ptr
<FirstVisuallyNonEmptyPaintObserver
> observer(
640 new FirstVisuallyNonEmptyPaintObserver(shell()));
642 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
644 observer
->WaitForDidFirstVisuallyNonEmptyPaint();
645 ASSERT_TRUE(observer
->did_fist_visually_non_empty_paint_
);
650 class WebDisplayModeDelegate
: public WebContentsDelegate
{
652 explicit WebDisplayModeDelegate(blink::WebDisplayMode mode
) : mode_(mode
) { }
653 ~WebDisplayModeDelegate() override
{ }
655 blink::WebDisplayMode
GetDisplayMode(
656 const WebContents
* source
) const override
{ return mode_
; }
657 void set_mode(blink::WebDisplayMode mode
) { mode_
= mode
; }
659 blink::WebDisplayMode mode_
;
661 DISALLOW_COPY_AND_ASSIGN(WebDisplayModeDelegate
);
666 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest
, ChangeDisplayMode
) {
667 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
668 WebDisplayModeDelegate
delegate(blink::WebDisplayModeMinimalUi
);
669 shell()->web_contents()->SetDelegate(&delegate
);
671 NavigateToURL(shell(), GURL("about://blank"));
673 ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
675 " window.matchMedia('(display-mode:"
676 " minimal-ui)').matches"));
677 EXPECT_EQ(base::ASCIIToUTF16("true"), shell()->web_contents()->GetTitle());
679 delegate
.set_mode(blink::WebDisplayModeFullscreen
);
680 // Simulate widget is entering fullscreen (changing size is enough).
681 shell()->web_contents()->GetRenderViewHost()->WasResized();
683 ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
685 " window.matchMedia('(display-mode:"
686 " fullscreen)').matches"));
687 EXPECT_EQ(base::ASCIIToUTF16("true"), shell()->web_contents()->GetTitle());
690 } // namespace content