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
43namespace {
44
45// TODO(tdresser): Find a way to avoid sleeping like this. See crbug.com/405282
46// for details.
47void 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.
57class 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
97namespace content {
98
99// This class keeps track of the RenderViewHost whose screenshot was captured.
100class 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
158class 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
189class 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
238class 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
439IN_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
452IN_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
465IN_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
556IN_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.
661IN_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.
732IN_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.
770IN_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
795IN_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
827IN_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.
883IN_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.
897IN_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.
927IN_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
1020IN_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
1158