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
3 // found in the LICENSE file.
5 #include "content/browser/web_contents/web_contents_view_aura.h"
7 #include "base/command_line.h"
8 #include "base/run_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/test/test_timeouts.h"
11 #include "base/values.h"
13 #include "base/win/windows_version.h"
15 #include "content/browser/frame_host/navigation_controller_impl.h"
16 #include "content/browser/frame_host/navigation_entry_impl.h"
17 #include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
18 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
19 #include "content/browser/web_contents/web_contents_impl.h"
20 #include "content/browser/web_contents/web_contents_view.h"
21 #include "content/common/input/synthetic_web_input_event_builders.h"
22 #include "content/common/input_messages.h"
23 #include "content/common/view_messages.h"
24 #include "content/public/browser/browser_message_filter.h"
25 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/web_contents_delegate.h"
27 #include "content/public/browser/web_contents_observer.h"
28 #include "content/public/common/content_switches.h"
29 #include "content/public/test/browser_test_utils.h"
30 #include "content/public/test/content_browser_test.h"
31 #include "content/public/test/content_browser_test_utils.h"
32 #include "content/public/test/test_renderer_host.h"
33 #include "content/public/test/test_utils.h"
34 #include "content/shell/browser/shell.h"
35 #include "ui/aura/window.h"
36 #include "ui/aura/window_tree_host.h"
37 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
38 #include "ui/events/event_processor.h"
39 #include "ui/events/event_switches.h"
40 #include "ui/events/event_utils.h"
41 #include "ui/events/test/event_generator.h"
45 // TODO(tdresser): Find a way to avoid sleeping like this. See crbug.com/405282
47 void GiveItSomeTime() {
48 base::RunLoop run_loop;
49 base::MessageLoop::current()->PostDelayedTask(
51 run_loop.QuitClosure(),
52 base::TimeDelta::FromMillisecondsD(10));
56 // WebContentsDelegate which tracks vertical overscroll updates.
57 class VerticalOverscrollTracker : public content::WebContentsDelegate {
59 VerticalOverscrollTracker() : count_(0), completed_(false) {}
60 virtual ~VerticalOverscrollTracker() {}
62 int num_overscroll_updates() const {
66 bool overscroll_completed() const {
76 virtual bool CanOverscrollContent() const OVERRIDE {
80 virtual void OverscrollUpdate(int delta_y) OVERRIDE {
84 virtual void OverscrollComplete() OVERRIDE {
91 DISALLOW_COPY_AND_ASSIGN(VerticalOverscrollTracker);
99 // This class keeps track of the RenderViewHost whose screenshot was captured.
100 class ScreenshotTracker : public NavigationEntryScreenshotManager {
102 explicit ScreenshotTracker(NavigationControllerImpl* controller)
103 : NavigationEntryScreenshotManager(controller),
104 screenshot_taken_for_(NULL),
105 waiting_for_screenshots_(0) {
108 virtual ~ScreenshotTracker() {
111 RenderViewHost* screenshot_taken_for() { return screenshot_taken_for_; }
114 screenshot_taken_for_ = NULL;
115 screenshot_set_.clear();
118 void SetScreenshotInterval(int interval_ms) {
119 SetMinScreenshotIntervalMS(interval_ms);
122 void WaitUntilScreenshotIsReady() {
123 if (!waiting_for_screenshots_)
125 message_loop_runner_ = new content::MessageLoopRunner;
126 message_loop_runner_->Run();
129 bool ScreenshotSetForEntry(NavigationEntryImpl* entry) const {
130 return screenshot_set_.count(entry) > 0;
134 // Overridden from NavigationEntryScreenshotManager:
135 virtual void TakeScreenshotImpl(RenderViewHost* host,
136 NavigationEntryImpl* entry) OVERRIDE {
137 ++waiting_for_screenshots_;
138 screenshot_taken_for_ = host;
139 NavigationEntryScreenshotManager::TakeScreenshotImpl(host, entry);
142 virtual void OnScreenshotSet(NavigationEntryImpl* entry) OVERRIDE {
143 --waiting_for_screenshots_;
144 screenshot_set_[entry] = true;
145 NavigationEntryScreenshotManager::OnScreenshotSet(entry);
146 if (waiting_for_screenshots_ == 0 && message_loop_runner_.get())
147 message_loop_runner_->Quit();
150 RenderViewHost* screenshot_taken_for_;
151 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
152 int waiting_for_screenshots_;
153 std::map<NavigationEntryImpl*, bool> screenshot_set_;
155 DISALLOW_COPY_AND_ASSIGN(ScreenshotTracker);
158 class NavigationWatcher : public WebContentsObserver {
160 explicit NavigationWatcher(WebContents* contents)
161 : WebContentsObserver(contents),
163 should_quit_loop_(false) {
166 virtual ~NavigationWatcher() {}
168 void WaitUntilNavigationStarts() {
171 should_quit_loop_ = true;
172 base::MessageLoop::current()->Run();
176 // Overridden from WebContentsObserver:
177 virtual void AboutToNavigateRenderView(RenderViewHost* host) OVERRIDE {
179 if (should_quit_loop_)
180 base::MessageLoop::current()->Quit();
184 bool should_quit_loop_;
186 DISALLOW_COPY_AND_ASSIGN(NavigationWatcher);
189 class InputEventMessageFilterWaitsForAcks : public BrowserMessageFilter {
191 InputEventMessageFilterWaitsForAcks()
192 : BrowserMessageFilter(InputMsgStart),
193 type_(blink::WebInputEvent::Undefined),
194 state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {}
196 void WaitForAck(blink::WebInputEvent::Type type) {
197 base::RunLoop run_loop;
198 base::AutoReset<base::Closure> reset_quit(&quit_, run_loop.QuitClosure());
199 base::AutoReset<blink::WebInputEvent::Type> reset_type(&type_, type);
203 InputEventAckState last_ack_state() const { return state_; }
206 virtual ~InputEventMessageFilterWaitsForAcks() {}
209 void ReceivedEventAck(blink::WebInputEvent::Type type,
210 InputEventAckState state) {
217 // BrowserMessageFilter:
218 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
219 if (message.type() == InputHostMsg_HandleInputEvent_ACK::ID) {
220 InputHostMsg_HandleInputEvent_ACK::Param params;
221 InputHostMsg_HandleInputEvent_ACK::Read(&message, ¶ms);
222 blink::WebInputEvent::Type type = params.a.type;
223 InputEventAckState ack = params.a.state;
224 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
225 base::Bind(&InputEventMessageFilterWaitsForAcks::ReceivedEventAck,
232 blink::WebInputEvent::Type type_;
233 InputEventAckState state_;
235 DISALLOW_COPY_AND_ASSIGN(InputEventMessageFilterWaitsForAcks);
238 class WebContentsViewAuraTest : public ContentBrowserTest {
240 WebContentsViewAuraTest()
241 : screenshot_manager_(NULL) {
244 // Executes the javascript synchronously and makes sure the returned value is
246 void ExecuteSyncJSFunction(RenderFrameHost* rfh, const std::string& jscript) {
247 scoped_ptr<base::Value> value =
248 content::ExecuteScriptAndGetValue(rfh, jscript);
251 // Starts the test server and navigates to the given url. Sets a large enough
252 // size to the root window. Returns after the navigation to the url is
254 void StartTestWithPage(const std::string& url) {
255 ASSERT_TRUE(test_server()->Start());
256 GURL test_url(test_server()->GetURL(url));
257 NavigateToURL(shell(), test_url);
259 WebContentsImpl* web_contents =
260 static_cast<WebContentsImpl*>(shell()->web_contents());
261 NavigationControllerImpl* controller = &web_contents->GetController();
263 screenshot_manager_ = new ScreenshotTracker(controller);
264 controller->SetScreenshotManager(screenshot_manager_);
267 virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE {
268 cmd->AppendSwitchASCII(switches::kTouchEvents,
269 switches::kTouchEventsEnabled);
272 void TestOverscrollNavigation(bool touch_handler) {
273 ASSERT_NO_FATAL_FAILURE(
274 StartTestWithPage("files/overscroll_navigation.html"));
275 WebContentsImpl* web_contents =
276 static_cast<WebContentsImpl*>(shell()->web_contents());
277 NavigationController& controller = web_contents->GetController();
278 RenderFrameHost* main_frame = web_contents->GetMainFrame();
280 EXPECT_FALSE(controller.CanGoBack());
281 EXPECT_FALSE(controller.CanGoForward());
283 scoped_ptr<base::Value> value =
284 content::ExecuteScriptAndGetValue(main_frame, "get_current()");
285 ASSERT_TRUE(value->GetAsInteger(&index));
289 ExecuteSyncJSFunction(main_frame, "install_touch_handler()");
291 ExecuteSyncJSFunction(main_frame, "navigate_next()");
292 ExecuteSyncJSFunction(main_frame, "navigate_next()");
293 value = content::ExecuteScriptAndGetValue(main_frame, "get_current()");
294 ASSERT_TRUE(value->GetAsInteger(&index));
296 EXPECT_TRUE(controller.CanGoBack());
297 EXPECT_FALSE(controller.CanGoForward());
299 aura::Window* content = web_contents->GetContentNativeView();
300 gfx::Rect bounds = content->GetBoundsInRootWindow();
301 ui::test::EventGenerator generator(content->GetRootWindow(), content);
302 const int kScrollDurationMs = 20;
303 const int kScrollSteps = 10;
306 // Do a swipe-right now. That should navigate backwards.
307 base::string16 expected_title = base::ASCIIToUTF16("Title: #1");
308 content::TitleWatcher title_watcher(web_contents, expected_title);
309 generator.GestureScrollSequence(
310 gfx::Point(bounds.x() + 2, bounds.y() + 10),
311 gfx::Point(bounds.right() - 10, bounds.y() + 10),
312 base::TimeDelta::FromMilliseconds(kScrollDurationMs),
314 base::string16 actual_title = title_watcher.WaitAndGetTitle();
315 EXPECT_EQ(expected_title, actual_title);
316 value = content::ExecuteScriptAndGetValue(main_frame, "get_current()");
317 ASSERT_TRUE(value->GetAsInteger(&index));
319 EXPECT_TRUE(controller.CanGoBack());
320 EXPECT_TRUE(controller.CanGoForward());
324 // Do a fling-right now. That should navigate backwards.
325 base::string16 expected_title = base::ASCIIToUTF16("Title:");
326 content::TitleWatcher title_watcher(web_contents, expected_title);
327 generator.GestureScrollSequence(
328 gfx::Point(bounds.x() + 2, bounds.y() + 10),
329 gfx::Point(bounds.right() - 10, bounds.y() + 10),
330 base::TimeDelta::FromMilliseconds(kScrollDurationMs),
332 base::string16 actual_title = title_watcher.WaitAndGetTitle();
333 EXPECT_EQ(expected_title, actual_title);
334 value = content::ExecuteScriptAndGetValue(main_frame, "get_current()");
335 ASSERT_TRUE(value->GetAsInteger(&index));
337 EXPECT_FALSE(controller.CanGoBack());
338 EXPECT_TRUE(controller.CanGoForward());
342 // Do a swipe-left now. That should navigate forward.
343 base::string16 expected_title = base::ASCIIToUTF16("Title: #1");
344 content::TitleWatcher title_watcher(web_contents, expected_title);
345 generator.GestureScrollSequence(
346 gfx::Point(bounds.right() - 10, bounds.y() + 10),
347 gfx::Point(bounds.x() + 2, bounds.y() + 10),
348 base::TimeDelta::FromMilliseconds(kScrollDurationMs),
350 base::string16 actual_title = title_watcher.WaitAndGetTitle();
351 EXPECT_EQ(expected_title, actual_title);
352 value = content::ExecuteScriptAndGetValue(main_frame, "get_current()");
353 ASSERT_TRUE(value->GetAsInteger(&index));
355 EXPECT_TRUE(controller.CanGoBack());
356 EXPECT_TRUE(controller.CanGoForward());
360 int GetCurrentIndex() {
361 WebContentsImpl* web_contents =
362 static_cast<WebContentsImpl*>(shell()->web_contents());
363 RenderFrameHost* main_frame = web_contents->GetMainFrame();
365 scoped_ptr<base::Value> value;
366 value = content::ExecuteScriptAndGetValue(main_frame, "get_current()");
367 if (!value->GetAsInteger(&index))
372 int ExecuteScriptAndExtractInt(const std::string& script) {
374 EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
375 shell()->web_contents(),
376 "domAutomationController.send(" + script + ")",
381 RenderViewHost* GetRenderViewHost() const {
382 RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost();
387 RenderWidgetHostImpl* GetRenderWidgetHost() const {
388 RenderWidgetHostImpl* const rwh =
389 RenderWidgetHostImpl::From(shell()
391 ->GetRenderWidgetHostView()
392 ->GetRenderWidgetHost());
397 RenderWidgetHostViewBase* GetRenderWidgetHostView() const {
398 return static_cast<RenderWidgetHostViewBase*>(
399 GetRenderViewHost()->GetView());
402 InputEventMessageFilterWaitsForAcks* filter() {
403 return filter_.get();
407 uint32 frame = GetRenderWidgetHostView()->RendererFrameNumber();
408 while (!GetRenderWidgetHost()->ScheduleComposite())
410 while (GetRenderWidgetHostView()->RendererFrameNumber() == frame)
415 ScreenshotTracker* screenshot_manager() { return screenshot_manager_; }
416 void set_min_screenshot_interval(int interval_ms) {
417 screenshot_manager_->SetScreenshotInterval(interval_ms);
420 void AddInputEventMessageFilter() {
421 filter_ = new InputEventMessageFilterWaitsForAcks();
422 GetRenderWidgetHost()->GetProcess()->AddFilter(filter_.get());
426 ScreenshotTracker* screenshot_manager_;
427 scoped_refptr<InputEventMessageFilterWaitsForAcks> filter_;
429 DISALLOW_COPY_AND_ASSIGN(WebContentsViewAuraTest);
432 // Flaky on Windows: http://crbug.com/305722
434 #define MAYBE_OverscrollNavigation DISABLED_OverscrollNavigation
436 #define MAYBE_OverscrollNavigation OverscrollNavigation
439 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollNavigation) {
440 TestOverscrollNavigation(false);
443 // Flaky on Windows (might be related to the above test):
444 // http://crbug.com/305722
446 #define MAYBE_OverscrollNavigationWithTouchHandler \
447 DISABLED_OverscrollNavigationWithTouchHandler
449 #define MAYBE_OverscrollNavigationWithTouchHandler \
450 OverscrollNavigationWithTouchHandler
452 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
453 MAYBE_OverscrollNavigationWithTouchHandler) {
454 TestOverscrollNavigation(true);
457 // Disabled because the test always fails the first time it runs on the Win Aura
458 // bots, and usually but not always passes second-try (See crbug.com/179532).
460 #define MAYBE_QuickOverscrollDirectionChange \
461 DISABLED_QuickOverscrollDirectionChange
463 #define MAYBE_QuickOverscrollDirectionChange QuickOverscrollDirectionChange
465 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
466 MAYBE_QuickOverscrollDirectionChange) {
467 ASSERT_NO_FATAL_FAILURE(
468 StartTestWithPage("files/overscroll_navigation.html"));
469 WebContentsImpl* web_contents =
470 static_cast<WebContentsImpl*>(shell()->web_contents());
471 RenderFrameHost* main_frame = web_contents->GetMainFrame();
473 // This test triggers a large number of animations. Speed them up to ensure
474 // the test completes within its time limit.
475 ui::ScopedAnimationDurationScaleMode fast_duration_mode(
476 ui::ScopedAnimationDurationScaleMode::FAST_DURATION);
478 // Make sure the page has both back/forward history.
479 ExecuteSyncJSFunction(main_frame, "navigate_next()");
480 EXPECT_EQ(1, GetCurrentIndex());
481 ExecuteSyncJSFunction(main_frame, "navigate_next()");
482 EXPECT_EQ(2, GetCurrentIndex());
483 web_contents->GetController().GoBack();
484 EXPECT_EQ(1, GetCurrentIndex());
486 aura::Window* content = web_contents->GetContentNativeView();
487 ui::EventProcessor* dispatcher = content->GetHost()->event_processor();
488 gfx::Rect bounds = content->GetBoundsInRootWindow();
490 base::TimeDelta timestamp = ui::EventTimeForNow();
491 ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
492 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
494 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
495 ASSERT_FALSE(details.dispatcher_destroyed);
496 EXPECT_EQ(1, GetCurrentIndex());
498 timestamp += base::TimeDelta::FromMilliseconds(10);
499 ui::TouchEvent move1(ui::ET_TOUCH_MOVED,
500 gfx::Point(bounds.right() - 10, bounds.y() + 5),
502 details = dispatcher->OnEventFromSource(&move1);
503 ASSERT_FALSE(details.dispatcher_destroyed);
504 EXPECT_EQ(1, GetCurrentIndex());
506 // Swipe back from the right edge, back to the left edge, back to the right
509 for (int x = bounds.right() - 10; x >= bounds.x() + 10; x-= 10) {
510 timestamp += base::TimeDelta::FromMilliseconds(10);
511 ui::TouchEvent inc(ui::ET_TOUCH_MOVED,
512 gfx::Point(x, bounds.y() + 5),
514 details = dispatcher->OnEventFromSource(&inc);
515 ASSERT_FALSE(details.dispatcher_destroyed);
516 EXPECT_EQ(1, GetCurrentIndex());
519 for (int x = bounds.x() + 10; x <= bounds.width() - 10; x+= 10) {
520 timestamp += base::TimeDelta::FromMilliseconds(10);
521 ui::TouchEvent inc(ui::ET_TOUCH_MOVED,
522 gfx::Point(x, bounds.y() + 5),
524 details = dispatcher->OnEventFromSource(&inc);
525 ASSERT_FALSE(details.dispatcher_destroyed);
526 EXPECT_EQ(1, GetCurrentIndex());
529 for (int x = bounds.width() - 10; x >= bounds.x() + 10; x-= 10) {
530 timestamp += base::TimeDelta::FromMilliseconds(10);
531 ui::TouchEvent inc(ui::ET_TOUCH_MOVED,
532 gfx::Point(x, bounds.y() + 5),
534 details = dispatcher->OnEventFromSource(&inc);
535 ASSERT_FALSE(details.dispatcher_destroyed);
536 EXPECT_EQ(1, GetCurrentIndex());
539 // Do not end the overscroll sequence.
542 // Tests that the page has has a screenshot when navigation happens:
543 // - from within the page (from a JS function)
544 // - interactively, when user does an overscroll gesture
545 // - interactively, when user navigates in history without the overscroll
547 // Flaky on Windows (http://crbug.com/357311). Might be related to
548 // OverscrollNavigation test.
549 // Flaky on Ozone (http://crbug.com/399676).
550 // Flaky on ChromeOS (http://crbug.com/405945).
551 #if defined(OS_WIN) || defined(USE_OZONE) || defined(OS_CHROMEOS)
552 #define MAYBE_OverscrollScreenshot DISABLED_OverscrollScreenshot
554 #define MAYBE_OverscrollScreenshot OverscrollScreenshot
556 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollScreenshot) {
557 // Disable the test for WinXP. See http://crbug/294116.
559 if (base::win::GetVersion() < base::win::VERSION_VISTA) {
560 LOG(WARNING) << "Test disabled due to unknown bug on WinXP.";
565 ASSERT_NO_FATAL_FAILURE(
566 StartTestWithPage("files/overscroll_navigation.html"));
567 WebContentsImpl* web_contents =
568 static_cast<WebContentsImpl*>(shell()->web_contents());
569 RenderFrameHost* main_frame = web_contents->GetMainFrame();
571 set_min_screenshot_interval(0);
573 // Do a few navigations initiated by the page.
574 // Screenshots should never be captured since these are all in-page
576 ExecuteSyncJSFunction(main_frame, "navigate_next()");
577 EXPECT_EQ(1, GetCurrentIndex());
578 ExecuteSyncJSFunction(main_frame, "navigate_next()");
579 EXPECT_EQ(2, GetCurrentIndex());
580 screenshot_manager()->WaitUntilScreenshotIsReady();
582 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
583 web_contents->GetController().GetEntryAtIndex(2));
584 EXPECT_FALSE(entry->screenshot().get());
586 entry = NavigationEntryImpl::FromNavigationEntry(
587 web_contents->GetController().GetEntryAtIndex(1));
588 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
590 entry = NavigationEntryImpl::FromNavigationEntry(
591 web_contents->GetController().GetEntryAtIndex(0));
592 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
594 ExecuteSyncJSFunction(main_frame, "navigate_next()");
595 screenshot_manager()->WaitUntilScreenshotIsReady();
597 entry = NavigationEntryImpl::FromNavigationEntry(
598 web_contents->GetController().GetEntryAtIndex(2));
599 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
601 entry = NavigationEntryImpl::FromNavigationEntry(
602 web_contents->GetController().GetEntryAtIndex(3));
603 EXPECT_FALSE(entry->screenshot().get());
605 // Now, swipe right to navigate backwards. This should navigate away from
606 // index 3 to index 2.
607 base::string16 expected_title = base::ASCIIToUTF16("Title: #2");
608 content::TitleWatcher title_watcher(web_contents, expected_title);
609 aura::Window* content = web_contents->GetContentNativeView();
610 gfx::Rect bounds = content->GetBoundsInRootWindow();
611 ui::test::EventGenerator generator(content->GetRootWindow(), content);
612 generator.GestureScrollSequence(
613 gfx::Point(bounds.x() + 2, bounds.y() + 10),
614 gfx::Point(bounds.right() - 10, bounds.y() + 10),
615 base::TimeDelta::FromMilliseconds(20),
617 base::string16 actual_title = title_watcher.WaitAndGetTitle();
618 EXPECT_EQ(expected_title, actual_title);
619 EXPECT_EQ(2, GetCurrentIndex());
620 screenshot_manager()->WaitUntilScreenshotIsReady();
621 entry = NavigationEntryImpl::FromNavigationEntry(
622 web_contents->GetController().GetEntryAtIndex(3));
623 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
626 // Navigate a couple more times.
627 ExecuteSyncJSFunction(main_frame, "navigate_next()");
628 EXPECT_EQ(3, GetCurrentIndex());
629 ExecuteSyncJSFunction(main_frame, "navigate_next()");
630 EXPECT_EQ(4, GetCurrentIndex());
631 screenshot_manager()->WaitUntilScreenshotIsReady();
632 entry = NavigationEntryImpl::FromNavigationEntry(
633 web_contents->GetController().GetEntryAtIndex(4));
634 EXPECT_FALSE(entry->screenshot().get());
637 // Navigate back in history.
638 base::string16 expected_title = base::ASCIIToUTF16("Title: #3");
639 content::TitleWatcher title_watcher(web_contents, expected_title);
640 web_contents->GetController().GoBack();
641 base::string16 actual_title = title_watcher.WaitAndGetTitle();
642 EXPECT_EQ(expected_title, actual_title);
643 EXPECT_EQ(3, GetCurrentIndex());
644 screenshot_manager()->WaitUntilScreenshotIsReady();
645 entry = NavigationEntryImpl::FromNavigationEntry(
646 web_contents->GetController().GetEntryAtIndex(4));
647 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
651 // Crashes under ThreadSanitizer, http://crbug.com/356758.
652 #if defined(THREAD_SANITIZER)
653 #define MAYBE_ScreenshotForSwappedOutRenderViews \
654 DISABLED_ScreenshotForSwappedOutRenderViews
656 #define MAYBE_ScreenshotForSwappedOutRenderViews \
657 ScreenshotForSwappedOutRenderViews
659 // Tests that screenshot is taken correctly when navigation causes a
660 // RenderViewHost to be swapped out.
661 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
662 MAYBE_ScreenshotForSwappedOutRenderViews) {
663 ASSERT_NO_FATAL_FAILURE(
664 StartTestWithPage("files/overscroll_navigation.html"));
665 // Create a new server with a different site.
666 net::SpawnedTestServer https_server(
667 net::SpawnedTestServer::TYPE_HTTPS,
668 net::SpawnedTestServer::kLocalhost,
669 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
670 ASSERT_TRUE(https_server.Start());
672 WebContentsImpl* web_contents =
673 static_cast<WebContentsImpl*>(shell()->web_contents());
674 set_min_screenshot_interval(0);
680 { https_server.GetURL("files/title1.html"),
681 ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR },
682 { test_server()->GetURL("files/title2.html"),
683 ui::PAGE_TRANSITION_AUTO_BOOKMARK },
684 { https_server.GetURL("files/title3.html"),
685 ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR },
689 screenshot_manager()->Reset();
690 for (int i = 0; !navigations[i].url.is_empty(); ++i) {
691 // Navigate via the user initiating a navigation from the UI.
692 NavigationController::LoadURLParams params(navigations[i].url);
693 params.transition_type =
694 ui::PageTransitionFromInt(navigations[i].transition);
696 RenderViewHost* old_host = web_contents->GetRenderViewHost();
697 web_contents->GetController().LoadURLWithParams(params);
698 WaitForLoadStop(web_contents);
699 screenshot_manager()->WaitUntilScreenshotIsReady();
701 EXPECT_NE(old_host, web_contents->GetRenderViewHost())
702 << navigations[i].url.spec();
703 EXPECT_EQ(old_host, screenshot_manager()->screenshot_taken_for());
705 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
706 web_contents->GetController().GetEntryAtOffset(-1));
707 EXPECT_TRUE(screenshot_manager()->ScreenshotSetForEntry(entry));
709 entry = NavigationEntryImpl::FromNavigationEntry(
710 web_contents->GetController().GetLastCommittedEntry());
711 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
712 EXPECT_FALSE(entry->screenshot().get());
713 screenshot_manager()->Reset();
716 // Increase the minimum interval between taking screenshots.
717 set_min_screenshot_interval(60000);
719 // Navigate again. This should not take any screenshot because of the
720 // increased screenshot interval.
721 NavigationController::LoadURLParams params(navigations[0].url);
722 params.transition_type = ui::PageTransitionFromInt(navigations[0].transition);
723 web_contents->GetController().LoadURLWithParams(params);
724 WaitForLoadStop(web_contents);
725 screenshot_manager()->WaitUntilScreenshotIsReady();
727 EXPECT_EQ(NULL, screenshot_manager()->screenshot_taken_for());
730 // Tests that navigations resulting from reloads, history.replaceState,
731 // and history.pushState do not capture screenshots.
732 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, ReplaceStateReloadPushState) {
733 ASSERT_NO_FATAL_FAILURE(
734 StartTestWithPage("files/overscroll_navigation.html"));
735 WebContentsImpl* web_contents =
736 static_cast<WebContentsImpl*>(shell()->web_contents());
737 RenderFrameHost* main_frame = web_contents->GetMainFrame();
739 set_min_screenshot_interval(0);
740 screenshot_manager()->Reset();
741 ExecuteSyncJSFunction(main_frame, "use_replace_state()");
742 screenshot_manager()->WaitUntilScreenshotIsReady();
743 // history.replaceState shouldn't capture a screenshot
744 EXPECT_FALSE(screenshot_manager()->screenshot_taken_for());
745 screenshot_manager()->Reset();
746 web_contents->GetController().Reload(true);
747 WaitForLoadStop(web_contents);
748 // reloading the page shouldn't capture a screenshot
749 // TODO (mfomitchev): currently broken. Uncomment when
750 // FrameHostMsg_DidCommitProvisionalLoad_Params.was_within_same_page
751 // is populated properly when reloading the page.
752 //EXPECT_FALSE(screenshot_manager()->screenshot_taken_for());
753 screenshot_manager()->Reset();
754 ExecuteSyncJSFunction(main_frame, "use_push_state()");
755 screenshot_manager()->WaitUntilScreenshotIsReady();
756 // pushing a state shouldn't capture a screenshot
757 // TODO (mfomitchev): currently broken. Uncomment when
758 // FrameHostMsg_DidCommitProvisionalLoad_Params.was_within_same_page
759 // is populated properly when pushState is used.
760 //EXPECT_FALSE(screenshot_manager()->screenshot_taken_for());
763 // TODO(sadrul): This test is disabled because it reparents in a way the
764 // FocusController does not support. This code would crash in
765 // a production build. It only passed prior to this revision
766 // because testing used the old FocusManager which did some
767 // different (osbolete) processing. TODO(sadrul) to figure out
768 // how this test should work that mimics production code a bit
770 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
771 DISABLED_ContentWindowReparent) {
772 ASSERT_NO_FATAL_FAILURE(
773 StartTestWithPage("files/overscroll_navigation.html"));
775 scoped_ptr<aura::Window> window(new aura::Window(NULL));
776 window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
778 WebContentsImpl* web_contents =
779 static_cast<WebContentsImpl*>(shell()->web_contents());
780 ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()");
781 EXPECT_EQ(1, GetCurrentIndex());
783 aura::Window* content = web_contents->GetContentNativeView();
784 gfx::Rect bounds = content->GetBoundsInRootWindow();
785 ui::test::EventGenerator generator(content->GetRootWindow(), content);
786 generator.GestureScrollSequence(
787 gfx::Point(bounds.x() + 2, bounds.y() + 10),
788 gfx::Point(bounds.right() - 10, bounds.y() + 10),
789 base::TimeDelta::FromMilliseconds(20),
792 window->AddChild(shell()->web_contents()->GetContentNativeView());
795 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, ContentWindowClose) {
796 ASSERT_NO_FATAL_FAILURE(
797 StartTestWithPage("files/overscroll_navigation.html"));
799 WebContentsImpl* web_contents =
800 static_cast<WebContentsImpl*>(shell()->web_contents());
801 ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()");
802 EXPECT_EQ(1, GetCurrentIndex());
804 aura::Window* content = web_contents->GetContentNativeView();
805 gfx::Rect bounds = content->GetBoundsInRootWindow();
806 ui::test::EventGenerator generator(content->GetRootWindow(), content);
807 generator.GestureScrollSequence(
808 gfx::Point(bounds.x() + 2, bounds.y() + 10),
809 gfx::Point(bounds.right() - 10, bounds.y() + 10),
810 base::TimeDelta::FromMilliseconds(20),
813 delete web_contents->GetContentNativeView();
817 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
818 // This appears to be flaky in the same was as the other overscroll
819 // tests. Enabling for non-Windows platforms.
820 // See http://crbug.com/369871.
821 // For linux, see http://crbug.com/381294
822 #define MAYBE_RepeatedQuickOverscrollGestures DISABLED_RepeatedQuickOverscrollGestures
824 #define MAYBE_RepeatedQuickOverscrollGestures RepeatedQuickOverscrollGestures
827 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
828 MAYBE_RepeatedQuickOverscrollGestures) {
829 ASSERT_NO_FATAL_FAILURE(
830 StartTestWithPage("files/overscroll_navigation.html"));
832 WebContentsImpl* web_contents =
833 static_cast<WebContentsImpl*>(shell()->web_contents());
834 NavigationController& controller = web_contents->GetController();
835 RenderFrameHost* main_frame = web_contents->GetMainFrame();
836 ExecuteSyncJSFunction(main_frame, "install_touch_handler()");
838 // Navigate twice, then navigate back in history once.
839 ExecuteSyncJSFunction(main_frame, "navigate_next()");
840 ExecuteSyncJSFunction(main_frame, "navigate_next()");
841 EXPECT_EQ(2, GetCurrentIndex());
842 EXPECT_TRUE(controller.CanGoBack());
843 EXPECT_FALSE(controller.CanGoForward());
845 web_contents->GetController().GoBack();
846 WaitForLoadStop(web_contents);
847 EXPECT_EQ(1, GetCurrentIndex());
848 EXPECT_EQ(base::ASCIIToUTF16("Title: #1"), web_contents->GetTitle());
849 EXPECT_TRUE(controller.CanGoBack());
850 EXPECT_TRUE(controller.CanGoForward());
852 aura::Window* content = web_contents->GetContentNativeView();
853 gfx::Rect bounds = content->GetBoundsInRootWindow();
854 ui::test::EventGenerator generator(content->GetRootWindow(), content);
856 // Do a swipe left to start a forward navigation. Then quickly do a swipe
858 base::string16 expected_title = base::ASCIIToUTF16("Title: #2");
859 content::TitleWatcher title_watcher(web_contents, expected_title);
860 NavigationWatcher nav_watcher(web_contents);
862 generator.GestureScrollSequence(
863 gfx::Point(bounds.right() - 10, bounds.y() + 10),
864 gfx::Point(bounds.x() + 2, bounds.y() + 10),
865 base::TimeDelta::FromMilliseconds(2000),
867 nav_watcher.WaitUntilNavigationStarts();
869 generator.GestureScrollSequence(
870 gfx::Point(bounds.x() + 2, bounds.y() + 10),
871 gfx::Point(bounds.right() - 10, bounds.y() + 10),
872 base::TimeDelta::FromMilliseconds(2000),
874 base::string16 actual_title = title_watcher.WaitAndGetTitle();
875 EXPECT_EQ(expected_title, actual_title);
877 EXPECT_EQ(2, GetCurrentIndex());
878 EXPECT_TRUE(controller.CanGoBack());
879 EXPECT_FALSE(controller.CanGoForward());
882 // Verify that hiding a parent of the renderer will hide the content too.
883 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, HideContentOnParenHide) {
884 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/title1.html"));
885 WebContentsImpl* web_contents =
886 static_cast<WebContentsImpl*>(shell()->web_contents());
887 aura::Window* content = web_contents->GetNativeView()->parent();
888 EXPECT_TRUE(web_contents->should_normally_be_visible());
890 EXPECT_FALSE(web_contents->should_normally_be_visible());
892 EXPECT_TRUE(web_contents->should_normally_be_visible());
895 // Ensure that SnapToPhysicalPixelBoundary() is called on WebContentsView parent
896 // change. This is a regression test for http://crbug.com/388908.
897 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, WebContentsViewReparent) {
898 ASSERT_NO_FATAL_FAILURE(
899 StartTestWithPage("files/overscroll_navigation.html"));
901 scoped_ptr<aura::Window> window(new aura::Window(NULL));
902 window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
904 RenderWidgetHostViewAura* rwhva =
905 static_cast<RenderWidgetHostViewAura*>(
906 shell()->web_contents()->GetRenderWidgetHostView());
907 rwhva->ResetHasSnappedToBoundary();
908 EXPECT_FALSE(rwhva->has_snapped_to_boundary());
909 window->AddChild(shell()->web_contents()->GetNativeView());
910 EXPECT_TRUE(rwhva->has_snapped_to_boundary());
913 // Flaky on some platforms, likely for the same reason as other flaky overscroll
914 // tests. http://crbug.com/305722
915 // TODO(tdresser): Re-enable this once eager GR is back on. See
917 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
918 #define MAYBE_OverscrollNavigationTouchThrottling \
919 DISABLED_OverscrollNavigationTouchThrottling
921 #define MAYBE_OverscrollNavigationTouchThrottling \
922 DISABLED_OverscrollNavigationTouchThrottling
925 // Tests that touch moves are not throttled when performing a scroll gesture on
926 // a non-scrollable area, except during gesture-nav.
927 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
928 MAYBE_OverscrollNavigationTouchThrottling) {
929 ASSERT_NO_FATAL_FAILURE(
930 StartTestWithPage("files/overscroll_navigation.html"));
932 AddInputEventMessageFilter();
934 WebContentsImpl* web_contents =
935 static_cast<WebContentsImpl*>(shell()->web_contents());
936 aura::Window* content = web_contents->GetContentNativeView();
937 gfx::Rect bounds = content->GetBoundsInRootWindow();
940 ExecuteSyncJSFunction(web_contents->GetMainFrame(),
941 "install_touchmove_handler()");
945 for (int navigated = 0; navigated <= 1; ++navigated) {
947 ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()");
948 ExecuteSyncJSFunction(web_contents->GetMainFrame(),
949 "reset_touchmove_count()");
952 SyntheticWebTouchEvent touch;
953 touch.PressPoint(bounds.x() + 2, bounds.y() + 10);
954 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch,
956 filter()->WaitForAck(blink::WebInputEvent::TouchStart);
959 // Assert on the ack, because we'll end up waiting for acks that will never
960 // come if this is not true.
961 ASSERT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state());
963 // Send first touch move, and then a scroll begin.
964 touch.MovePoint(0, bounds.x() + 20 + 1 * dx, bounds.y() + 100);
965 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch,
967 filter()->WaitForAck(blink::WebInputEvent::TouchMove);
968 ASSERT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state());
970 blink::WebGestureEvent scroll_begin =
971 SyntheticWebGestureEventBuilder::BuildScrollBegin(1, 1);
972 GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
973 scroll_begin, ui::LatencyInfo());
974 // Scroll begin ignores ack disposition, so don't wait for the ack.
977 // First touchmove already sent, start at 2.
978 for (int i = 2; i <= 10; ++i) {
979 // Send a touch move, followed by a scroll update
980 touch.MovePoint(0, bounds.x() + 20 + i * dx, bounds.y() + 100);
981 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(
982 touch, ui::LatencyInfo());
985 blink::WebGestureEvent scroll_update =
986 SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx, 5, 0);
988 GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
989 scroll_update, ui::LatencyInfo());
994 touch.ReleasePoint(0);
995 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch,
999 blink::WebGestureEvent scroll_end;
1000 scroll_end.type = blink::WebInputEvent::GestureScrollEnd;
1001 GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
1002 scroll_end, ui::LatencyInfo());
1006 EXPECT_EQ(10, ExecuteScriptAndExtractInt("touchmoveCount"));
1008 EXPECT_GT(10, ExecuteScriptAndExtractInt("touchmoveCount"));
1012 // Test that vertical overscroll updates are sent only when a user overscrolls
1015 #define MAYBE_VerticalOverscroll DISABLED_VerticalOverscroll
1017 #define MAYBE_VerticalOverscroll VerticalOverscroll
1020 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_VerticalOverscroll) {
1021 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1022 switches::kScrollEndEffect, "1");
1024 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("about:blank"));
1025 WebContentsImpl* web_contents =
1026 static_cast<WebContentsImpl*>(shell()->web_contents());
1027 VerticalOverscrollTracker tracker;
1028 web_contents->SetDelegate(&tracker);
1030 // This test triggers a large number of animations. Speed them up to ensure
1031 // the test completes within its time limit.
1032 ui::ScopedAnimationDurationScaleMode fast_duration_mode(
1033 ui::ScopedAnimationDurationScaleMode::FAST_DURATION);
1035 aura::Window* content = web_contents->GetContentNativeView();
1036 ui::EventProcessor* dispatcher = content->GetHost()->event_processor();
1037 gfx::Rect bounds = content->GetBoundsInRootWindow();
1039 // Overscroll horizontally.
1041 int kXStep = bounds.width() / 10;
1042 gfx::Point location(bounds.right() - kXStep, bounds.y() + 5);
1043 base::TimeDelta timestamp = ui::EventTimeForNow();
1044 ui::TouchEvent press(
1045 ui::ET_TOUCH_PRESSED,
1049 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
1050 ASSERT_FALSE(details.dispatcher_destroyed);
1052 location -= gfx::Vector2d(kXStep, 0);
1053 timestamp += base::TimeDelta::FromMilliseconds(10);
1055 while (location.x() > bounds.x() + kXStep) {
1056 ui::TouchEvent inc(ui::ET_TOUCH_MOVED, location, 0, timestamp);
1057 details = dispatcher->OnEventFromSource(&inc);
1058 ASSERT_FALSE(details.dispatcher_destroyed);
1060 location -= gfx::Vector2d(10, 0);
1061 timestamp += base::TimeDelta::FromMilliseconds(10);
1064 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, location, 0, timestamp);
1065 details = dispatcher->OnEventFromSource(&press);
1066 ASSERT_FALSE(details.dispatcher_destroyed);
1069 EXPECT_EQ(0, tracker.num_overscroll_updates());
1070 EXPECT_FALSE(tracker.overscroll_completed());
1073 // Overscroll vertically.
1077 int kYStep = bounds.height() / 10;
1078 gfx::Point location(bounds.x() + 10, bounds.y() + kYStep);
1079 base::TimeDelta timestamp = ui::EventTimeForNow();
1080 ui::TouchEvent press(
1081 ui::ET_TOUCH_PRESSED,
1085 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
1086 ASSERT_FALSE(details.dispatcher_destroyed);
1088 location += gfx::Vector2d(0, kYStep);
1089 timestamp += base::TimeDelta::FromMilliseconds(10);
1091 while (location.y() < bounds.bottom() - kYStep) {
1092 ui::TouchEvent inc(ui::ET_TOUCH_MOVED, location, 0, timestamp);
1093 details = dispatcher->OnEventFromSource(&inc);
1094 ASSERT_FALSE(details.dispatcher_destroyed);
1096 location += gfx::Vector2d(0, kYStep);
1097 timestamp += base::TimeDelta::FromMilliseconds(10);
1100 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, location, 0, timestamp);
1101 details = dispatcher->OnEventFromSource(&release);
1102 ASSERT_FALSE(details.dispatcher_destroyed);
1105 EXPECT_LT(0, tracker.num_overscroll_updates());
1106 EXPECT_TRUE(tracker.overscroll_completed());
1109 // Start out overscrolling vertically, then switch directions and finish
1110 // overscrolling horizontally.
1114 int kXStep = bounds.width() / 10;
1115 int kYStep = bounds.height() / 10;
1116 gfx::Point location = bounds.origin() + gfx::Vector2d(0, kYStep);
1117 base::TimeDelta timestamp = ui::EventTimeForNow();
1118 ui::TouchEvent press(
1119 ui::ET_TOUCH_PRESSED,
1123 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
1124 ASSERT_FALSE(details.dispatcher_destroyed);
1126 location += gfx::Vector2d(0, kYStep);
1127 timestamp += base::TimeDelta::FromMilliseconds(10);
1129 for (size_t i = 0; i < 3; ++i) {
1130 ui::TouchEvent inc(ui::ET_TOUCH_MOVED, location, 0, timestamp);
1131 details = dispatcher->OnEventFromSource(&inc);
1132 ASSERT_FALSE(details.dispatcher_destroyed);
1134 location += gfx::Vector2d(0, kYStep);
1135 timestamp += base::TimeDelta::FromMilliseconds(10);
1138 while (location.x() < bounds.right() - kXStep) {
1139 ui::TouchEvent inc(ui::ET_TOUCH_MOVED, location, 0, timestamp);
1140 details = dispatcher->OnEventFromSource(&inc);
1141 ASSERT_FALSE(details.dispatcher_destroyed);
1143 location += gfx::Vector2d(kXStep, 0);
1144 timestamp += base::TimeDelta::FromMilliseconds(10);
1147 ui::TouchEvent release(ui::ET_TOUCH_RELEASED, location, 0, timestamp);
1148 details = dispatcher->OnEventFromSource(&release);
1149 ASSERT_FALSE(details.dispatcher_destroyed);
1152 EXPECT_LT(0, tracker.num_overscroll_updates());
1153 EXPECT_FALSE(tracker.overscroll_completed());
1157 } // namespace content