web_contents_view_aura_browsertest.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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#include "content/browser/renderer_host/render_view_host_impl.h"
13#include "content/browser/web_contents/navigation_controller_impl.h"
14#include "content/browser/web_contents/navigation_entry_impl.h"
15#include "content/browser/web_contents/web_contents_impl.h"
16#include "content/browser/web_contents/web_contents_screenshot_manager.h"
17#include "content/public/browser/web_contents_view.h"
18#include "content/public/common/content_switches.h"
19#include "content/public/test/browser_test_utils.h"
20#include "content/public/test/test_utils.h"
21#include "content/shell/shell.h"
22#include "content/test/content_browser_test.h"
23#include "content/test/content_browser_test_utils.h"
24#include "ui/aura/root_window.h"
25#include "ui/aura/test/event_generator.h"
26#include "ui/aura/window.h"
27#include "ui/compositor/scoped_animation_duration_scale_mode.h"
28
29namespace content {
30
31// This class keeps track of the RenderViewHost whose screenshot was captured.
32class ScreenshotTracker : public WebContentsScreenshotManager {
33 public:
34  explicit ScreenshotTracker(NavigationControllerImpl* controller)
35      : WebContentsScreenshotManager(controller),
36        screenshot_taken_for_(NULL),
37        waiting_for_screenshots_(0) {
38  }
39
40  virtual ~ScreenshotTracker() {
41  }
42
43  RenderViewHost* screenshot_taken_for() { return screenshot_taken_for_; }
44
45  void Reset() {
46    screenshot_taken_for_ = NULL;
47  }
48
49  void SetScreenshotInterval(int interval_ms) {
50    SetMinScreenshotIntervalMS(interval_ms);
51  }
52
53  void WaitUntilScreenshotIsReady() {
54    if (!waiting_for_screenshots_)
55      return;
56    message_loop_runner_ = new content::MessageLoopRunner;
57    message_loop_runner_->Run();
58  }
59
60 private:
61  // Overridden from WebContentsScreenshotManager:
62  virtual void TakeScreenshotImpl(RenderViewHost* host,
63                                  NavigationEntryImpl* entry) OVERRIDE {
64    ++waiting_for_screenshots_;
65    screenshot_taken_for_ = host;
66    WebContentsScreenshotManager::TakeScreenshotImpl(host, entry);
67  }
68
69  virtual void OnScreenshotSet(NavigationEntryImpl* entry) OVERRIDE {
70    --waiting_for_screenshots_;
71    WebContentsScreenshotManager::OnScreenshotSet(entry);
72    if (waiting_for_screenshots_ == 0 && message_loop_runner_.get())
73      message_loop_runner_->Quit();
74  }
75
76  RenderViewHost* screenshot_taken_for_;
77  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
78  int waiting_for_screenshots_;
79
80  DISALLOW_COPY_AND_ASSIGN(ScreenshotTracker);
81};
82
83class WebContentsViewAuraTest : public ContentBrowserTest {
84 public:
85  WebContentsViewAuraTest()
86      : screenshot_manager_(NULL) {
87  }
88
89  // Executes the javascript synchronously and makes sure the returned value is
90  // freed properly.
91  void ExecuteSyncJSFunction(RenderViewHost* rvh, const std::string& jscript) {
92    scoped_ptr<base::Value> value =
93        content::ExecuteScriptAndGetValue(rvh, jscript);
94  }
95
96  // Starts the test server and navigates to the given url. Sets a large enough
97  // size to the root window.  Returns after the navigation to the url is
98  // complete.
99  void StartTestWithPage(const std::string& url) {
100    ASSERT_TRUE(test_server()->Start());
101    GURL test_url(test_server()->GetURL(url));
102    NavigateToURL(shell(), test_url);
103    aura::Window* content =
104        shell()->web_contents()->GetView()->GetContentNativeView();
105    content->GetRootWindow()->SetHostSize(gfx::Size(800, 600));
106
107    WebContentsImpl* web_contents =
108        static_cast<WebContentsImpl*>(shell()->web_contents());
109    NavigationControllerImpl* controller = &web_contents->GetController();
110
111    screenshot_manager_ = new ScreenshotTracker(controller);
112    controller->SetScreenshotManager(screenshot_manager_);
113  }
114
115  void TestOverscrollNavigation(bool touch_handler) {
116    ASSERT_NO_FATAL_FAILURE(
117        StartTestWithPage("files/overscroll_navigation.html"));
118    WebContentsImpl* web_contents =
119        static_cast<WebContentsImpl*>(shell()->web_contents());
120    NavigationController& controller = web_contents->GetController();
121    RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(
122        web_contents->GetRenderViewHost());
123    WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
124        web_contents->GetView());
125    view_aura->SetupOverlayWindowForTesting();
126
127    EXPECT_FALSE(controller.CanGoBack());
128    EXPECT_FALSE(controller.CanGoForward());
129    int index = -1;
130    scoped_ptr<base::Value> value =
131        content::ExecuteScriptAndGetValue(view_host, "get_current()");
132    ASSERT_TRUE(value->GetAsInteger(&index));
133    EXPECT_EQ(0, index);
134
135    if (touch_handler)
136      ExecuteSyncJSFunction(view_host, "install_touch_handler()");
137
138    ExecuteSyncJSFunction(view_host, "navigate_next()");
139    ExecuteSyncJSFunction(view_host, "navigate_next()");
140    value = content::ExecuteScriptAndGetValue(view_host, "get_current()");
141    ASSERT_TRUE(value->GetAsInteger(&index));
142    EXPECT_EQ(2, index);
143    EXPECT_TRUE(controller.CanGoBack());
144    EXPECT_FALSE(controller.CanGoForward());
145
146    aura::Window* content = web_contents->GetView()->GetContentNativeView();
147    gfx::Rect bounds = content->GetBoundsInRootWindow();
148    aura::test::EventGenerator generator(content->GetRootWindow(), content);
149
150    {
151      // Do a swipe-right now. That should navigate backwards.
152      string16 expected_title = ASCIIToUTF16("Title: #1");
153      content::TitleWatcher title_watcher(web_contents, expected_title);
154      generator.GestureScrollSequence(
155          gfx::Point(bounds.x() + 2, bounds.y() + 10),
156          gfx::Point(bounds.right() - 10, bounds.y() + 10),
157          base::TimeDelta::FromMilliseconds(20),
158          1);
159      string16 actual_title = title_watcher.WaitAndGetTitle();
160      EXPECT_EQ(expected_title, actual_title);
161      value = content::ExecuteScriptAndGetValue(view_host, "get_current()");
162      ASSERT_TRUE(value->GetAsInteger(&index));
163      EXPECT_EQ(1, index);
164      EXPECT_TRUE(controller.CanGoBack());
165      EXPECT_TRUE(controller.CanGoForward());
166    }
167
168    {
169      // Do a fling-right now. That should navigate backwards.
170      string16 expected_title = ASCIIToUTF16("Title:");
171      content::TitleWatcher title_watcher(web_contents, expected_title);
172      generator.GestureScrollSequence(
173          gfx::Point(bounds.x() + 2, bounds.y() + 10),
174          gfx::Point(bounds.right() - 10, bounds.y() + 10),
175          base::TimeDelta::FromMilliseconds(20),
176          10);
177      string16 actual_title = title_watcher.WaitAndGetTitle();
178      EXPECT_EQ(expected_title, actual_title);
179      value = content::ExecuteScriptAndGetValue(view_host, "get_current()");
180      ASSERT_TRUE(value->GetAsInteger(&index));
181      EXPECT_EQ(0, index);
182      EXPECT_FALSE(controller.CanGoBack());
183      EXPECT_TRUE(controller.CanGoForward());
184    }
185
186    {
187      // Do a swipe-left now. That should navigate forward.
188      string16 expected_title = ASCIIToUTF16("Title: #1");
189      content::TitleWatcher title_watcher(web_contents, expected_title);
190      generator.GestureScrollSequence(
191          gfx::Point(bounds.right() - 10, bounds.y() + 10),
192          gfx::Point(bounds.x() + 2, bounds.y() + 10),
193          base::TimeDelta::FromMilliseconds(20),
194          10);
195      string16 actual_title = title_watcher.WaitAndGetTitle();
196      EXPECT_EQ(expected_title, actual_title);
197      value = content::ExecuteScriptAndGetValue(view_host, "get_current()");
198      ASSERT_TRUE(value->GetAsInteger(&index));
199      EXPECT_EQ(1, index);
200      EXPECT_TRUE(controller.CanGoBack());
201      EXPECT_TRUE(controller.CanGoForward());
202    }
203  }
204
205  int GetCurrentIndex() {
206    WebContentsImpl* web_contents =
207        static_cast<WebContentsImpl*>(shell()->web_contents());
208    RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(
209        web_contents->GetRenderViewHost());
210    int index = -1;
211    scoped_ptr<base::Value> value;
212    value = content::ExecuteScriptAndGetValue(view_host, "get_current()");
213    if (!value->GetAsInteger(&index))
214      index = -1;
215    return index;
216  }
217
218 protected:
219  ScreenshotTracker* screenshot_manager() { return screenshot_manager_; }
220  void set_min_screenshot_interval(int interval_ms) {
221    screenshot_manager_->SetScreenshotInterval(interval_ms);
222  }
223
224 private:
225  ScreenshotTracker* screenshot_manager_;
226
227  DISALLOW_COPY_AND_ASSIGN(WebContentsViewAuraTest);
228};
229
230IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
231                       OverscrollNavigation) {
232  TestOverscrollNavigation(false);
233}
234
235IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
236                       OverscrollNavigationWithTouchHandler) {
237  TestOverscrollNavigation(true);
238}
239
240// Disabled because the test always fails the first time it runs on the Win Aura
241// bots, and usually but not always passes second-try (See crbug.com/179532).
242#if defined(OS_WIN)
243#define MAYBE_QuickOverscrollDirectionChange \
244        DISABLED_QuickOverscrollDirectionChange
245#else
246#define MAYBE_QuickOverscrollDirectionChange QuickOverscrollDirectionChange
247#endif
248IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
249                       MAYBE_QuickOverscrollDirectionChange) {
250  ASSERT_NO_FATAL_FAILURE(
251      StartTestWithPage("files/overscroll_navigation.html"));
252  WebContentsImpl* web_contents =
253      static_cast<WebContentsImpl*>(shell()->web_contents());
254  RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(
255      web_contents->GetRenderViewHost());
256
257  // This test triggers a large number of animations. Speed them up to ensure
258  // the test completes within its time limit.
259  ui::ScopedAnimationDurationScaleMode fast_duration_mode(
260      ui::ScopedAnimationDurationScaleMode::FAST_DURATION);
261
262  // Make sure the page has both back/forward history.
263  ExecuteSyncJSFunction(view_host, "navigate_next()");
264  EXPECT_EQ(1, GetCurrentIndex());
265  ExecuteSyncJSFunction(view_host, "navigate_next()");
266  EXPECT_EQ(2, GetCurrentIndex());
267  web_contents->GetController().GoBack();
268  EXPECT_EQ(1, GetCurrentIndex());
269
270  aura::Window* content = web_contents->GetView()->GetContentNativeView();
271  aura::RootWindow* root_window = content->GetRootWindow();
272  gfx::Rect bounds = content->GetBoundsInRootWindow();
273
274  base::TimeDelta timestamp;
275  ui::TouchEvent press(ui::ET_TOUCH_PRESSED,
276      gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5),
277      0, timestamp);
278  root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&press);
279  EXPECT_EQ(1, GetCurrentIndex());
280
281  timestamp += base::TimeDelta::FromMilliseconds(10);
282  ui::TouchEvent move1(ui::ET_TOUCH_MOVED,
283      gfx::Point(bounds.right() - 10, bounds.y() + 5),
284      0, timestamp);
285  root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&move1);
286  EXPECT_EQ(1, GetCurrentIndex());
287
288  // Swipe back from the right edge, back to the left edge, back to the right
289  // edge.
290
291  for (int x = bounds.right() - 10; x >= bounds.x() + 10; x-= 10) {
292    timestamp += base::TimeDelta::FromMilliseconds(10);
293    ui::TouchEvent inc(ui::ET_TOUCH_MOVED,
294        gfx::Point(x, bounds.y() + 5),
295        0, timestamp);
296    root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&inc);
297    EXPECT_EQ(1, GetCurrentIndex());
298  }
299
300  for (int x = bounds.x() + 10; x <= bounds.width() - 10; x+= 10) {
301    timestamp += base::TimeDelta::FromMilliseconds(10);
302    ui::TouchEvent inc(ui::ET_TOUCH_MOVED,
303        gfx::Point(x, bounds.y() + 5),
304        0, timestamp);
305    root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&inc);
306    EXPECT_EQ(1, GetCurrentIndex());
307  }
308
309  for (int x = bounds.width() - 10; x >= bounds.x() + 10; x-= 10) {
310    timestamp += base::TimeDelta::FromMilliseconds(10);
311    ui::TouchEvent inc(ui::ET_TOUCH_MOVED,
312        gfx::Point(x, bounds.y() + 5),
313        0, timestamp);
314    root_window->AsRootWindowHostDelegate()->OnHostTouchEvent(&inc);
315    EXPECT_EQ(1, GetCurrentIndex());
316  }
317
318  // Do not end the overscroll sequence.
319}
320
321// Tests that the page has has a screenshot when navigation happens:
322//  - from within the page (from a JS function)
323//  - interactively, when user does an overscroll gesture
324//  - interactively, when user navigates in history without the overscroll
325//    gesture.
326IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
327                       OverscrollScreenshot) {
328  ASSERT_NO_FATAL_FAILURE(
329      StartTestWithPage("files/overscroll_navigation.html"));
330  WebContentsImpl* web_contents =
331      static_cast<WebContentsImpl*>(shell()->web_contents());
332  RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(
333      web_contents->GetRenderViewHost());
334
335  set_min_screenshot_interval(0);
336
337  // Do a few navigations initiated by the page.
338  ExecuteSyncJSFunction(view_host, "navigate_next()");
339  EXPECT_EQ(1, GetCurrentIndex());
340  ExecuteSyncJSFunction(view_host, "navigate_next()");
341  EXPECT_EQ(2, GetCurrentIndex());
342  screenshot_manager()->WaitUntilScreenshotIsReady();
343
344  // The current entry won't have any screenshots. But the entries in the
345  // history should now have screenshots.
346  NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
347      web_contents->GetController().GetEntryAtIndex(2));
348  EXPECT_FALSE(entry->screenshot().get());
349
350  entry = NavigationEntryImpl::FromNavigationEntry(
351      web_contents->GetController().GetEntryAtIndex(1));
352  EXPECT_TRUE(entry->screenshot().get());
353
354  entry = NavigationEntryImpl::FromNavigationEntry(
355      web_contents->GetController().GetEntryAtIndex(0));
356  EXPECT_TRUE(entry->screenshot().get());
357
358  // Navigate again. Index 2 should now have a screenshot.
359  ExecuteSyncJSFunction(view_host, "navigate_next()");
360  EXPECT_EQ(3, GetCurrentIndex());
361  screenshot_manager()->WaitUntilScreenshotIsReady();
362
363  entry = NavigationEntryImpl::FromNavigationEntry(
364      web_contents->GetController().GetEntryAtIndex(2));
365  EXPECT_TRUE(entry->screenshot().get());
366
367  entry = NavigationEntryImpl::FromNavigationEntry(
368      web_contents->GetController().GetEntryAtIndex(3));
369  EXPECT_FALSE(entry->screenshot().get());
370
371  {
372    // Now, swipe right to navigate backwards. This should navigate away from
373    // index 3 to index 2, and index 3 should have a screenshot.
374    string16 expected_title = ASCIIToUTF16("Title: #2");
375    content::TitleWatcher title_watcher(web_contents, expected_title);
376    aura::Window* content = web_contents->GetView()->GetContentNativeView();
377    gfx::Rect bounds = content->GetBoundsInRootWindow();
378    aura::test::EventGenerator generator(content->GetRootWindow(), content);
379    generator.GestureScrollSequence(
380        gfx::Point(bounds.x() + 2, bounds.y() + 10),
381        gfx::Point(bounds.right() - 10, bounds.y() + 10),
382        base::TimeDelta::FromMilliseconds(20),
383        1);
384    string16 actual_title = title_watcher.WaitAndGetTitle();
385    EXPECT_EQ(expected_title, actual_title);
386    EXPECT_EQ(2, GetCurrentIndex());
387    screenshot_manager()->WaitUntilScreenshotIsReady();
388    entry = NavigationEntryImpl::FromNavigationEntry(
389        web_contents->GetController().GetEntryAtIndex(3));
390    EXPECT_TRUE(entry->screenshot().get());
391  }
392
393  // Navigate a couple more times.
394  ExecuteSyncJSFunction(view_host, "navigate_next()");
395  EXPECT_EQ(3, GetCurrentIndex());
396  ExecuteSyncJSFunction(view_host, "navigate_next()");
397  EXPECT_EQ(4, GetCurrentIndex());
398  screenshot_manager()->WaitUntilScreenshotIsReady();
399  entry = NavigationEntryImpl::FromNavigationEntry(
400      web_contents->GetController().GetEntryAtIndex(4));
401  EXPECT_FALSE(entry->screenshot().get());
402
403  {
404    // Navigate back in history.
405    string16 expected_title = ASCIIToUTF16("Title: #3");
406    content::TitleWatcher title_watcher(web_contents, expected_title);
407    web_contents->GetController().GoBack();
408    string16 actual_title = title_watcher.WaitAndGetTitle();
409    EXPECT_EQ(expected_title, actual_title);
410    EXPECT_EQ(3, GetCurrentIndex());
411    screenshot_manager()->WaitUntilScreenshotIsReady();
412    entry = NavigationEntryImpl::FromNavigationEntry(
413        web_contents->GetController().GetEntryAtIndex(4));
414    EXPECT_TRUE(entry->screenshot().get());
415  }
416}
417
418// Tests that screenshot is taken correctly when navigation causes a
419// RenderViewHost to be swapped out.
420IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
421                       ScreenshotForSwappedOutRenderViews) {
422  ASSERT_NO_FATAL_FAILURE(
423      StartTestWithPage("files/overscroll_navigation.html"));
424  // Create a new server with a different site.
425  net::SpawnedTestServer https_server(
426      net::SpawnedTestServer::TYPE_HTTPS,
427      net::SpawnedTestServer::kLocalhost,
428      base::FilePath(FILE_PATH_LITERAL("content/test/data")));
429  ASSERT_TRUE(https_server.Start());
430
431  WebContentsImpl* web_contents =
432      static_cast<WebContentsImpl*>(shell()->web_contents());
433  set_min_screenshot_interval(0);
434
435  struct {
436    GURL url;
437    int transition;
438  } navigations[] = {
439    { https_server.GetURL("files/title1.html"),
440      PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR },
441    { test_server()->GetURL("files/title2.html"),
442      PAGE_TRANSITION_AUTO_BOOKMARK },
443    { https_server.GetURL("files/title3.html"),
444      PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR },
445    { GURL(), 0 }
446  };
447
448  screenshot_manager()->Reset();
449  for (int i = 0; !navigations[i].url.is_empty(); ++i) {
450    // Navigate via the user initiating a navigation from the UI.
451    NavigationController::LoadURLParams params(navigations[i].url);
452    params.transition_type = PageTransitionFromInt(navigations[i].transition);
453
454    RenderViewHost* old_host = web_contents->GetRenderViewHost();
455    web_contents->GetController().LoadURLWithParams(params);
456    WaitForLoadStop(web_contents);
457    screenshot_manager()->WaitUntilScreenshotIsReady();
458
459    EXPECT_NE(old_host, web_contents->GetRenderViewHost())
460        << navigations[i].url.spec();
461    EXPECT_EQ(old_host, screenshot_manager()->screenshot_taken_for());
462    screenshot_manager()->Reset();
463
464    NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
465        web_contents->GetController().GetEntryAtOffset(-1));
466    EXPECT_TRUE(entry->screenshot().get());
467
468    entry = NavigationEntryImpl::FromNavigationEntry(
469        web_contents->GetController().GetActiveEntry());
470    EXPECT_FALSE(entry->screenshot().get());
471  }
472
473  // Increase the minimum interval between taking screenshots.
474  set_min_screenshot_interval(60000);
475
476  // Navigate again. This should not take any screenshot because of the
477  // increased screenshot interval.
478  NavigationController::LoadURLParams params(navigations[0].url);
479  params.transition_type = PageTransitionFromInt(navigations[0].transition);
480  web_contents->GetController().LoadURLWithParams(params);
481  WaitForLoadStop(web_contents);
482  screenshot_manager()->WaitUntilScreenshotIsReady();
483
484  EXPECT_EQ(NULL, screenshot_manager()->screenshot_taken_for());
485}
486
487// Failing on win7_aura trybot (see crbug.com/260983).
488#if defined(OS_WIN)
489#define MAYBE_ContentWindowReparent \
490        DISABLED_ContentWindowReparent
491#else
492#define MAYBE_ContentWindowReparent ContentWindowReparent
493#endif
494IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
495                       MAYBE_ContentWindowReparent) {
496  ASSERT_NO_FATAL_FAILURE(
497      StartTestWithPage("files/overscroll_navigation.html"));
498
499  scoped_ptr<aura::Window> window(new aura::Window(NULL));
500  window->Init(ui::LAYER_NOT_DRAWN);
501
502  WebContentsImpl* web_contents =
503      static_cast<WebContentsImpl*>(shell()->web_contents());
504  ExecuteSyncJSFunction(web_contents->GetRenderViewHost(), "navigate_next()");
505  EXPECT_EQ(1, GetCurrentIndex());
506
507  aura::Window* content = web_contents->GetView()->GetContentNativeView();
508  gfx::Rect bounds = content->GetBoundsInRootWindow();
509  aura::test::EventGenerator generator(content->GetRootWindow(), content);
510  generator.GestureScrollSequence(
511      gfx::Point(bounds.x() + 2, bounds.y() + 10),
512      gfx::Point(bounds.right() - 10, bounds.y() + 10),
513      base::TimeDelta::FromMilliseconds(20),
514      1);
515
516  window->AddChild(shell()->web_contents()->GetView()->GetContentNativeView());
517}
518
519IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
520                       ContentWindowClose) {
521  ASSERT_NO_FATAL_FAILURE(
522      StartTestWithPage("files/overscroll_navigation.html"));
523
524  WebContentsImpl* web_contents =
525      static_cast<WebContentsImpl*>(shell()->web_contents());
526  ExecuteSyncJSFunction(web_contents->GetRenderViewHost(), "navigate_next()");
527  EXPECT_EQ(1, GetCurrentIndex());
528
529  aura::Window* content = web_contents->GetView()->GetContentNativeView();
530  gfx::Rect bounds = content->GetBoundsInRootWindow();
531  aura::test::EventGenerator generator(content->GetRootWindow(), content);
532  generator.GestureScrollSequence(
533      gfx::Point(bounds.x() + 2, bounds.y() + 10),
534      gfx::Point(bounds.right() - 10, bounds.y() + 10),
535      base::TimeDelta::FromMilliseconds(20),
536      1);
537
538  delete web_contents->GetView()->GetContentNativeView();
539}
540
541IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest,
542                       RepeatedQuickOverscrollGestures) {
543  ASSERT_NO_FATAL_FAILURE(
544      StartTestWithPage("files/overscroll_navigation.html"));
545
546  WebContentsImpl* web_contents =
547      static_cast<WebContentsImpl*>(shell()->web_contents());
548  NavigationController& controller = web_contents->GetController();
549  RenderViewHostImpl* view_host = static_cast<RenderViewHostImpl*>(
550      web_contents->GetRenderViewHost());
551  WebContentsViewAura* view_aura = static_cast<WebContentsViewAura*>(
552      web_contents->GetView());
553  view_aura->SetupOverlayWindowForTesting();
554  ExecuteSyncJSFunction(view_host, "install_touch_handler()");
555
556  // Navigate twice, then navigate back in history once.
557  ExecuteSyncJSFunction(view_host, "navigate_next()");
558  ExecuteSyncJSFunction(view_host, "navigate_next()");
559  EXPECT_EQ(2, GetCurrentIndex());
560  EXPECT_TRUE(controller.CanGoBack());
561  EXPECT_FALSE(controller.CanGoForward());
562
563  web_contents->GetController().GoBack();
564  WaitForLoadStop(web_contents);
565  EXPECT_EQ(1, GetCurrentIndex());
566  EXPECT_TRUE(controller.CanGoBack());
567  EXPECT_TRUE(controller.CanGoForward());
568
569  aura::Window* content = web_contents->GetView()->GetContentNativeView();
570  gfx::Rect bounds = content->GetBoundsInRootWindow();
571  aura::test::EventGenerator generator(content->GetRootWindow(), content);
572
573  // Do a swipe left to start a forward navigation. Then quickly do a swipe
574  // right.
575  string16 expected_title = ASCIIToUTF16("Title: #2");
576  content::TitleWatcher title_watcher(web_contents, expected_title);
577
578  generator.GestureScrollSequence(
579      gfx::Point(bounds.right() - 10, bounds.y() + 10),
580      gfx::Point(bounds.x() + 2, bounds.y() + 10),
581      base::TimeDelta::FromMilliseconds(2000),
582      10);
583  // Make sure the GestureEventFilter's debouncing doesn't interfere.
584  base::MessageLoop::current()->PostDelayedTask(
585      FROM_HERE,
586      base::MessageLoop::QuitClosure(),
587      base::TimeDelta::FromMilliseconds(100));
588  base::MessageLoop::current()->Run();
589  generator.GestureScrollSequence(
590      gfx::Point(bounds.x() + 2, bounds.y() + 10),
591      gfx::Point(bounds.right() - 10, bounds.y() + 10),
592      base::TimeDelta::FromMilliseconds(2000),
593      10);
594  string16 actual_title = title_watcher.WaitAndGetTitle();
595  EXPECT_EQ(expected_title, actual_title);
596
597  EXPECT_EQ(2, GetCurrentIndex());
598  EXPECT_TRUE(controller.CanGoBack());
599  EXPECT_FALSE(controller.CanGoForward());
600}
601
602}  // namespace content
603