Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / web_contents / web_contents_view_aura_browsertest.cc
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.
4
5 #include "content/browser/web_contents/web_contents_view_aura.h"
6
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"
12 #if defined(OS_WIN)
13 #include "base/win/windows_version.h"
14 #endif
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"
42
43 namespace {
44
45 // TODO(tdresser): Find a way to avoid sleeping like this. See crbug.com/405282
46 // for details.
47 void GiveItSomeTime() {
48   base::RunLoop run_loop;
49   base::MessageLoop::current()->PostDelayedTask(
50       FROM_HERE,
51       run_loop.QuitClosure(),
52       base::TimeDelta::FromMillisecondsD(10));
53   run_loop.Run();
54 }
55
56 // WebContentsDelegate which tracks vertical overscroll updates.
57 class VerticalOverscrollTracker : public content::WebContentsDelegate {
58  public:
59   VerticalOverscrollTracker() : count_(0), completed_(false) {}
60   virtual ~VerticalOverscrollTracker() {}
61
62   int num_overscroll_updates() const {
63     return count_;
64   }
65
66   bool overscroll_completed() const {
67     return completed_;
68   }
69
70   void Reset() {
71     count_ = 0;
72     completed_ = false;
73   }
74
75  private:
76   virtual bool CanOverscrollContent() const OVERRIDE {
77     return true;
78   }
79
80   virtual void OverscrollUpdate(int delta_y) OVERRIDE {
81     ++count_;
82   }
83
84   virtual void OverscrollComplete() OVERRIDE {
85     completed_ = true;
86   }
87
88   int count_;
89   bool completed_;
90
91   DISALLOW_COPY_AND_ASSIGN(VerticalOverscrollTracker);
92 };
93
94 }  //namespace
95
96
97 namespace content {
98
99 // This class keeps track of the RenderViewHost whose screenshot was captured.
100 class ScreenshotTracker : public NavigationEntryScreenshotManager {
101  public:
102   explicit ScreenshotTracker(NavigationControllerImpl* controller)
103       : NavigationEntryScreenshotManager(controller),
104         screenshot_taken_for_(NULL),
105         waiting_for_screenshots_(0) {
106   }
107
108   virtual ~ScreenshotTracker() {
109   }
110
111   RenderViewHost* screenshot_taken_for() { return screenshot_taken_for_; }
112
113   void Reset() {
114     screenshot_taken_for_ = NULL;
115     screenshot_set_.clear();
116   }
117
118   void SetScreenshotInterval(int interval_ms) {
119     SetMinScreenshotIntervalMS(interval_ms);
120   }
121
122   void WaitUntilScreenshotIsReady() {
123     if (!waiting_for_screenshots_)
124       return;
125     message_loop_runner_ = new content::MessageLoopRunner;
126     message_loop_runner_->Run();
127   }
128
129   bool ScreenshotSetForEntry(NavigationEntryImpl* entry) const {
130     return screenshot_set_.count(entry) > 0;
131   }
132
133  private:
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);
140   }
141
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();
148   }
149
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_;
154
155   DISALLOW_COPY_AND_ASSIGN(ScreenshotTracker);
156 };
157
158 class NavigationWatcher : public WebContentsObserver {
159  public:
160   explicit NavigationWatcher(WebContents* contents)
161       : WebContentsObserver(contents),
162         navigated_(false),
163         should_quit_loop_(false) {
164   }
165
166   virtual ~NavigationWatcher() {}
167
168   void WaitUntilNavigationStarts() {
169     if (navigated_)
170       return;
171     should_quit_loop_ = true;
172     base::MessageLoop::current()->Run();
173   }
174
175  private:
176   // Overridden from WebContentsObserver:
177   virtual void AboutToNavigateRenderView(RenderViewHost* host) OVERRIDE {
178     navigated_ = true;
179     if (should_quit_loop_)
180       base::MessageLoop::current()->Quit();
181   }
182
183   bool navigated_;
184   bool should_quit_loop_;
185
186   DISALLOW_COPY_AND_ASSIGN(NavigationWatcher);
187 };
188
189 class InputEventMessageFilterWaitsForAcks : public BrowserMessageFilter {
190  public:
191   InputEventMessageFilterWaitsForAcks()
192       : BrowserMessageFilter(InputMsgStart),
193         type_(blink::WebInputEvent::Undefined),
194         state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {}
195
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);
200     run_loop.Run();
201   }
202
203   InputEventAckState last_ack_state() const { return state_; }
204
205  protected:
206   virtual ~InputEventMessageFilterWaitsForAcks() {}
207
208  private:
209   void ReceivedEventAck(blink::WebInputEvent::Type type,
210                         InputEventAckState state) {
211     if (type_ == type) {
212       state_ = state;
213       quit_.Run();
214     }
215   }
216
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, &params);
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,
226                      this, type, ack));
227     }
228     return false;
229   }
230
231   base::Closure quit_;
232   blink::WebInputEvent::Type type_;
233   InputEventAckState state_;
234
235   DISALLOW_COPY_AND_ASSIGN(InputEventMessageFilterWaitsForAcks);
236 };
237
238 class WebContentsViewAuraTest : public ContentBrowserTest {
239  public:
240   WebContentsViewAuraTest()
241       : screenshot_manager_(NULL) {
242   }
243
244   // Executes the javascript synchronously and makes sure the returned value is
245   // freed properly.
246   void ExecuteSyncJSFunction(RenderFrameHost* rfh, const std::string& jscript) {
247     scoped_ptr<base::Value> value =
248         content::ExecuteScriptAndGetValue(rfh, jscript);
249   }
250
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
253   // complete.
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);
258
259     WebContentsImpl* web_contents =
260         static_cast<WebContentsImpl*>(shell()->web_contents());
261     NavigationControllerImpl* controller = &web_contents->GetController();
262
263     screenshot_manager_ = new ScreenshotTracker(controller);
264     controller->SetScreenshotManager(screenshot_manager_);
265   }
266
267   virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE {
268     cmd->AppendSwitchASCII(switches::kTouchEvents,
269                            switches::kTouchEventsEnabled);
270   }
271
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();
279
280     EXPECT_FALSE(controller.CanGoBack());
281     EXPECT_FALSE(controller.CanGoForward());
282     int index = -1;
283     scoped_ptr<base::Value> value =
284         content::ExecuteScriptAndGetValue(main_frame, "get_current()");
285     ASSERT_TRUE(value->GetAsInteger(&index));
286     EXPECT_EQ(0, index);
287
288     if (touch_handler)
289       ExecuteSyncJSFunction(main_frame, "install_touch_handler()");
290
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));
295     EXPECT_EQ(2, index);
296     EXPECT_TRUE(controller.CanGoBack());
297     EXPECT_FALSE(controller.CanGoForward());
298
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;
304
305     {
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),
313           kScrollSteps);
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));
318       EXPECT_EQ(1, index);
319       EXPECT_TRUE(controller.CanGoBack());
320       EXPECT_TRUE(controller.CanGoForward());
321     }
322
323     {
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),
331           kScrollSteps);
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));
336       EXPECT_EQ(0, index);
337       EXPECT_FALSE(controller.CanGoBack());
338       EXPECT_TRUE(controller.CanGoForward());
339     }
340
341     {
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),
349           kScrollSteps);
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));
354       EXPECT_EQ(1, index);
355       EXPECT_TRUE(controller.CanGoBack());
356       EXPECT_TRUE(controller.CanGoForward());
357     }
358   }
359
360   int GetCurrentIndex() {
361     WebContentsImpl* web_contents =
362         static_cast<WebContentsImpl*>(shell()->web_contents());
363     RenderFrameHost* main_frame = web_contents->GetMainFrame();
364     int index = -1;
365     scoped_ptr<base::Value> value;
366     value = content::ExecuteScriptAndGetValue(main_frame, "get_current()");
367     if (!value->GetAsInteger(&index))
368       index = -1;
369     return index;
370   }
371
372   int ExecuteScriptAndExtractInt(const std::string& script) {
373     int value = 0;
374     EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
375         shell()->web_contents(),
376         "domAutomationController.send(" + script + ")",
377         &value));
378     return value;
379   }
380
381   RenderViewHost* GetRenderViewHost() const {
382     RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost();
383     CHECK(rvh);
384     return rvh;
385   }
386
387   RenderWidgetHostImpl* GetRenderWidgetHost() const {
388     RenderWidgetHostImpl* const rwh =
389         RenderWidgetHostImpl::From(shell()
390                                        ->web_contents()
391                                        ->GetRenderWidgetHostView()
392                                        ->GetRenderWidgetHost());
393     CHECK(rwh);
394     return rwh;
395   }
396
397   RenderWidgetHostViewBase* GetRenderWidgetHostView() const {
398     return static_cast<RenderWidgetHostViewBase*>(
399         GetRenderViewHost()->GetView());
400   }
401
402   InputEventMessageFilterWaitsForAcks* filter() {
403     return filter_.get();
404   }
405
406   void WaitAFrame() {
407     uint32 frame = GetRenderWidgetHostView()->RendererFrameNumber();
408     while (!GetRenderWidgetHost()->ScheduleComposite())
409       GiveItSomeTime();
410     while (GetRenderWidgetHostView()->RendererFrameNumber() == frame)
411       GiveItSomeTime();
412   }
413
414  protected:
415   ScreenshotTracker* screenshot_manager() { return screenshot_manager_; }
416   void set_min_screenshot_interval(int interval_ms) {
417     screenshot_manager_->SetScreenshotInterval(interval_ms);
418   }
419
420   void AddInputEventMessageFilter() {
421     filter_ = new InputEventMessageFilterWaitsForAcks();
422     GetRenderWidgetHost()->GetProcess()->AddFilter(filter_.get());
423   }
424
425  private:
426   ScreenshotTracker* screenshot_manager_;
427   scoped_refptr<InputEventMessageFilterWaitsForAcks> filter_;
428
429   DISALLOW_COPY_AND_ASSIGN(WebContentsViewAuraTest);
430 };
431
432 // Flaky on Windows: http://crbug.com/305722
433 #if defined(OS_WIN)
434 #define MAYBE_OverscrollNavigation DISABLED_OverscrollNavigation
435 #else
436 #define MAYBE_OverscrollNavigation OverscrollNavigation
437 #endif
438
439 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollNavigation) {
440   TestOverscrollNavigation(false);
441 }
442
443 // Flaky on Windows (might be related to the above test):
444 // http://crbug.com/305722
445 #if defined(OS_WIN)
446 #define MAYBE_OverscrollNavigationWithTouchHandler \
447         DISABLED_OverscrollNavigationWithTouchHandler
448 #else
449 #define MAYBE_OverscrollNavigationWithTouchHandler \
450         OverscrollNavigationWithTouchHandler
451 #endif
452 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
453                        MAYBE_OverscrollNavigationWithTouchHandler) {
454   TestOverscrollNavigation(true);
455 }
456
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).
459 #if defined(OS_WIN)
460 #define MAYBE_QuickOverscrollDirectionChange \
461         DISABLED_QuickOverscrollDirectionChange
462 #else
463 #define MAYBE_QuickOverscrollDirectionChange QuickOverscrollDirectionChange
464 #endif
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();
472
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);
477
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());
485
486   aura::Window* content = web_contents->GetContentNativeView();
487   ui::EventProcessor* dispatcher = content->GetHost()->event_processor();
488   gfx::Rect bounds = content->GetBoundsInRootWindow();
489
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),
493       0, timestamp);
494   ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
495   ASSERT_FALSE(details.dispatcher_destroyed);
496   EXPECT_EQ(1, GetCurrentIndex());
497
498   timestamp += base::TimeDelta::FromMilliseconds(10);
499   ui::TouchEvent move1(ui::ET_TOUCH_MOVED,
500       gfx::Point(bounds.right() - 10, bounds.y() + 5),
501       0, timestamp);
502   details = dispatcher->OnEventFromSource(&move1);
503   ASSERT_FALSE(details.dispatcher_destroyed);
504   EXPECT_EQ(1, GetCurrentIndex());
505
506   // Swipe back from the right edge, back to the left edge, back to the right
507   // edge.
508
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),
513         0, timestamp);
514     details = dispatcher->OnEventFromSource(&inc);
515     ASSERT_FALSE(details.dispatcher_destroyed);
516     EXPECT_EQ(1, GetCurrentIndex());
517   }
518
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),
523         0, timestamp);
524     details = dispatcher->OnEventFromSource(&inc);
525     ASSERT_FALSE(details.dispatcher_destroyed);
526     EXPECT_EQ(1, GetCurrentIndex());
527   }
528
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),
533         0, timestamp);
534     details = dispatcher->OnEventFromSource(&inc);
535     ASSERT_FALSE(details.dispatcher_destroyed);
536     EXPECT_EQ(1, GetCurrentIndex());
537   }
538
539   // Do not end the overscroll sequence.
540 }
541
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
546 //    gesture.
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
553 #else
554 #define MAYBE_OverscrollScreenshot OverscrollScreenshot
555 #endif
556 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollScreenshot) {
557   // Disable the test for WinXP.  See http://crbug/294116.
558 #if defined(OS_WIN)
559   if (base::win::GetVersion() < base::win::VERSION_VISTA) {
560     LOG(WARNING) << "Test disabled due to unknown bug on WinXP.";
561     return;
562   }
563 #endif
564
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();
570
571   set_min_screenshot_interval(0);
572
573   // Do a few navigations initiated by the page.
574   // Screenshots should never be captured since these are all in-page
575   // navigations.
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();
581
582   NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
583       web_contents->GetController().GetEntryAtIndex(2));
584   EXPECT_FALSE(entry->screenshot().get());
585
586   entry = NavigationEntryImpl::FromNavigationEntry(
587       web_contents->GetController().GetEntryAtIndex(1));
588   EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
589
590   entry = NavigationEntryImpl::FromNavigationEntry(
591       web_contents->GetController().GetEntryAtIndex(0));
592   EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
593
594   ExecuteSyncJSFunction(main_frame, "navigate_next()");
595   screenshot_manager()->WaitUntilScreenshotIsReady();
596
597   entry = NavigationEntryImpl::FromNavigationEntry(
598       web_contents->GetController().GetEntryAtIndex(2));
599   EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry));
600
601   entry = NavigationEntryImpl::FromNavigationEntry(
602       web_contents->GetController().GetEntryAtIndex(3));
603   EXPECT_FALSE(entry->screenshot().get());
604   {
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),
616         1);
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));
624   }
625
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());
635
636   {
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));
648   }
649 }
650
651 // Crashes under ThreadSanitizer, http://crbug.com/356758.
652 #if defined(THREAD_SANITIZER)
653 #define MAYBE_ScreenshotForSwappedOutRenderViews \
654     DISABLED_ScreenshotForSwappedOutRenderViews
655 #else
656 #define MAYBE_ScreenshotForSwappedOutRenderViews \
657     ScreenshotForSwappedOutRenderViews
658 #endif
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());
671
672   WebContentsImpl* web_contents =
673       static_cast<WebContentsImpl*>(shell()->web_contents());
674   set_min_screenshot_interval(0);
675
676   struct {
677     GURL url;
678     int transition;
679   } navigations[] = {
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 },
686     { GURL(), 0 }
687   };
688
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);
695
696     RenderViewHost* old_host = web_contents->GetRenderViewHost();
697     web_contents->GetController().LoadURLWithParams(params);
698     WaitForLoadStop(web_contents);
699     screenshot_manager()->WaitUntilScreenshotIsReady();
700
701     EXPECT_NE(old_host, web_contents->GetRenderViewHost())
702         << navigations[i].url.spec();
703     EXPECT_EQ(old_host, screenshot_manager()->screenshot_taken_for());
704
705     NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
706         web_contents->GetController().GetEntryAtOffset(-1));
707     EXPECT_TRUE(screenshot_manager()->ScreenshotSetForEntry(entry));
708
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();
714   }
715
716   // Increase the minimum interval between taking screenshots.
717   set_min_screenshot_interval(60000);
718
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();
726
727   EXPECT_EQ(NULL, screenshot_manager()->screenshot_taken_for());
728 }
729
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();
738
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());
761 }
762
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
769 //               better.
770 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
771                        DISABLED_ContentWindowReparent) {
772   ASSERT_NO_FATAL_FAILURE(
773       StartTestWithPage("files/overscroll_navigation.html"));
774
775   scoped_ptr<aura::Window> window(new aura::Window(NULL));
776   window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
777
778   WebContentsImpl* web_contents =
779       static_cast<WebContentsImpl*>(shell()->web_contents());
780   ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()");
781   EXPECT_EQ(1, GetCurrentIndex());
782
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),
790       1);
791
792   window->AddChild(shell()->web_contents()->GetContentNativeView());
793 }
794
795 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, ContentWindowClose) {
796   ASSERT_NO_FATAL_FAILURE(
797       StartTestWithPage("files/overscroll_navigation.html"));
798
799   WebContentsImpl* web_contents =
800       static_cast<WebContentsImpl*>(shell()->web_contents());
801   ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()");
802   EXPECT_EQ(1, GetCurrentIndex());
803
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),
811       1);
812
813   delete web_contents->GetContentNativeView();
814 }
815
816
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
823 #else
824 #define MAYBE_RepeatedQuickOverscrollGestures RepeatedQuickOverscrollGestures
825 #endif
826
827 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
828                        MAYBE_RepeatedQuickOverscrollGestures) {
829   ASSERT_NO_FATAL_FAILURE(
830       StartTestWithPage("files/overscroll_navigation.html"));
831
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()");
837
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());
844
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());
851
852   aura::Window* content = web_contents->GetContentNativeView();
853   gfx::Rect bounds = content->GetBoundsInRootWindow();
854   ui::test::EventGenerator generator(content->GetRootWindow(), content);
855
856   // Do a swipe left to start a forward navigation. Then quickly do a swipe
857   // right.
858   base::string16 expected_title = base::ASCIIToUTF16("Title: #2");
859   content::TitleWatcher title_watcher(web_contents, expected_title);
860   NavigationWatcher nav_watcher(web_contents);
861
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),
866       10);
867   nav_watcher.WaitUntilNavigationStarts();
868
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),
873       10);
874   base::string16 actual_title = title_watcher.WaitAndGetTitle();
875   EXPECT_EQ(expected_title, actual_title);
876
877   EXPECT_EQ(2, GetCurrentIndex());
878   EXPECT_TRUE(controller.CanGoBack());
879   EXPECT_FALSE(controller.CanGoForward());
880 }
881
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());
889   content->Hide();
890   EXPECT_FALSE(web_contents->should_normally_be_visible());
891   content->Show();
892   EXPECT_TRUE(web_contents->should_normally_be_visible());
893 }
894
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"));
900
901   scoped_ptr<aura::Window> window(new aura::Window(NULL));
902   window->Init(aura::WINDOW_LAYER_NOT_DRAWN);
903
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());
911 }
912
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
916 // crbug.com/410280.
917 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
918 #define MAYBE_OverscrollNavigationTouchThrottling \
919         DISABLED_OverscrollNavigationTouchThrottling
920 #else
921 #define MAYBE_OverscrollNavigationTouchThrottling \
922         DISABLED_OverscrollNavigationTouchThrottling
923 #endif
924
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"));
931
932   AddInputEventMessageFilter();
933
934   WebContentsImpl* web_contents =
935       static_cast<WebContentsImpl*>(shell()->web_contents());
936   aura::Window* content = web_contents->GetContentNativeView();
937   gfx::Rect bounds = content->GetBoundsInRootWindow();
938   const int dx = 20;
939
940   ExecuteSyncJSFunction(web_contents->GetMainFrame(),
941                         "install_touchmove_handler()");
942
943   WaitAFrame();
944
945   for (int navigated = 0; navigated <= 1; ++navigated) {
946     if (navigated) {
947       ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()");
948       ExecuteSyncJSFunction(web_contents->GetMainFrame(),
949                             "reset_touchmove_count()");
950     }
951     // Send touch press.
952     SyntheticWebTouchEvent touch;
953     touch.PressPoint(bounds.x() + 2, bounds.y() + 10);
954     GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch,
955                                                             ui::LatencyInfo());
956     filter()->WaitForAck(blink::WebInputEvent::TouchStart);
957     WaitAFrame();
958
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());
962
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,
966                                                             ui::LatencyInfo());
967     filter()->WaitForAck(blink::WebInputEvent::TouchMove);
968     ASSERT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state());
969
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.
975     WaitAFrame();
976
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());
983       WaitAFrame();
984
985       blink::WebGestureEvent scroll_update =
986           SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx, 5, 0);
987
988       GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
989           scroll_update, ui::LatencyInfo());
990
991       WaitAFrame();
992     }
993
994     touch.ReleasePoint(0);
995     GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch,
996                                                             ui::LatencyInfo());
997     WaitAFrame();
998
999     blink::WebGestureEvent scroll_end;
1000     scroll_end.type = blink::WebInputEvent::GestureScrollEnd;
1001     GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
1002         scroll_end, ui::LatencyInfo());
1003     WaitAFrame();
1004
1005     if (!navigated)
1006       EXPECT_EQ(10, ExecuteScriptAndExtractInt("touchmoveCount"));
1007     else
1008       EXPECT_GT(10, ExecuteScriptAndExtractInt("touchmoveCount"));
1009   }
1010 }
1011
1012 // Test that vertical overscroll updates are sent only when a user overscrolls
1013 // vertically.
1014 #if defined(OS_WIN)
1015 #define MAYBE_VerticalOverscroll DISABLED_VerticalOverscroll
1016 #else
1017 #define MAYBE_VerticalOverscroll VerticalOverscroll
1018 #endif
1019
1020 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_VerticalOverscroll) {
1021   base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1022       switches::kScrollEndEffect, "1");
1023
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);
1029
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);
1034
1035   aura::Window* content = web_contents->GetContentNativeView();
1036   ui::EventProcessor* dispatcher = content->GetHost()->event_processor();
1037   gfx::Rect bounds = content->GetBoundsInRootWindow();
1038
1039   // Overscroll horizontally.
1040   {
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,
1046         location,
1047         0,
1048         timestamp);
1049     ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
1050     ASSERT_FALSE(details.dispatcher_destroyed);
1051     WaitAFrame();
1052     location -= gfx::Vector2d(kXStep, 0);
1053     timestamp += base::TimeDelta::FromMilliseconds(10);
1054
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);
1059       WaitAFrame();
1060       location -= gfx::Vector2d(10, 0);
1061       timestamp += base::TimeDelta::FromMilliseconds(10);
1062     }
1063
1064     ui::TouchEvent release(ui::ET_TOUCH_RELEASED, location, 0, timestamp);
1065     details = dispatcher->OnEventFromSource(&press);
1066     ASSERT_FALSE(details.dispatcher_destroyed);
1067     WaitAFrame();
1068
1069     EXPECT_EQ(0, tracker.num_overscroll_updates());
1070     EXPECT_FALSE(tracker.overscroll_completed());
1071   }
1072
1073   // Overscroll vertically.
1074   {
1075     tracker.Reset();
1076
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,
1082         location,
1083         0,
1084         timestamp);
1085     ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
1086     ASSERT_FALSE(details.dispatcher_destroyed);
1087     WaitAFrame();
1088     location += gfx::Vector2d(0, kYStep);
1089     timestamp += base::TimeDelta::FromMilliseconds(10);
1090
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);
1095       WaitAFrame();
1096       location += gfx::Vector2d(0, kYStep);
1097       timestamp += base::TimeDelta::FromMilliseconds(10);
1098     }
1099
1100     ui::TouchEvent release(ui::ET_TOUCH_RELEASED, location, 0, timestamp);
1101     details = dispatcher->OnEventFromSource(&release);
1102     ASSERT_FALSE(details.dispatcher_destroyed);
1103     WaitAFrame();
1104
1105     EXPECT_LT(0, tracker.num_overscroll_updates());
1106     EXPECT_TRUE(tracker.overscroll_completed());
1107   }
1108
1109   // Start out overscrolling vertically, then switch directions and finish
1110   // overscrolling horizontally.
1111   {
1112     tracker.Reset();
1113
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,
1120         location,
1121         0,
1122         timestamp);
1123     ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press);
1124     ASSERT_FALSE(details.dispatcher_destroyed);
1125     WaitAFrame();
1126     location += gfx::Vector2d(0, kYStep);
1127     timestamp += base::TimeDelta::FromMilliseconds(10);
1128
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);
1133       WaitAFrame();
1134       location += gfx::Vector2d(0, kYStep);
1135       timestamp += base::TimeDelta::FromMilliseconds(10);
1136     }
1137
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);
1142       WaitAFrame();
1143       location += gfx::Vector2d(kXStep, 0);
1144       timestamp += base::TimeDelta::FromMilliseconds(10);
1145     }
1146
1147     ui::TouchEvent release(ui::ET_TOUCH_RELEASED, location, 0, timestamp);
1148     details = dispatcher->OnEventFromSource(&release);
1149     ASSERT_FALSE(details.dispatcher_destroyed);
1150     WaitAFrame();
1151
1152     EXPECT_LT(0, tracker.num_overscroll_updates());
1153     EXPECT_FALSE(tracker.overscroll_completed());
1154   }
1155 }
1156
1157 }  // namespace content