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