1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/web_contents/web_contents_view_aura.h"
7 #include "base/command_line.h"
8 #include "base/run_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/test/test_timeouts.h"
11 #include "base/values.h"
13 #include "base/win/windows_version.h"
15 #include "content/browser/frame_host/navigation_controller_impl.h"
16 #include "content/browser/frame_host/navigation_entry_impl.h"
17 #include "content/browser/frame_host/navigation_entry_screenshot_manager.h"
18 #include "content/browser/renderer_host/render_widget_host_view_aura.h"
19 #include "content/browser/web_contents/web_contents_impl.h"
20 #include "content/browser/web_contents/web_contents_view.h"
21 #include "content/common/input/synthetic_web_input_event_builders.h"
22 #include "content/common/input_messages.h"
23 #include "content/common/view_messages.h"
24 #include "content/public/browser/browser_message_filter.h"
25 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/web_contents_delegate.h"
27 #include "content/public/browser/web_contents_observer.h"
28 #include "content/public/common/content_switches.h"
29 #include "content/public/test/browser_test_utils.h"
30 #include "content/public/test/content_browser_test.h"
31 #include "content/public/test/content_browser_test_utils.h"
32 #include "content/public/test/test_renderer_host.h"
33 #include "content/public/test/test_utils.h"
34 #include "content/shell/browser/shell.h"
35 #include "ui/aura/window.h"
36 #include "ui/aura/window_tree_host.h"
37 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
38 #include "ui/events/event_processor.h"
39 #include "ui/events/event_switches.h"
40 #include "ui/events/event_utils.h"
41 #include "ui/events/test/event_generator.h"
45 // TODO(tdresser): Find a way to avoid sleeping like this. See crbug.com/405282
47 void GiveItSomeTime() {
48 base::RunLoop run_loop
;
49 base::MessageLoop::current()->PostDelayedTask(
51 run_loop
.QuitClosure(),
52 base::TimeDelta::FromMillisecondsD(10));
56 // WebContentsDelegate which tracks vertical overscroll updates.
57 class VerticalOverscrollTracker
: public content::WebContentsDelegate
{
59 VerticalOverscrollTracker() : count_(0), completed_(false) {}
60 ~VerticalOverscrollTracker() override
{}
62 int num_overscroll_updates() const {
66 bool overscroll_completed() const {
76 bool CanOverscrollContent() const override
{ return true; }
78 void OverscrollUpdate(float delta_y
) override
{ ++count_
; }
80 void OverscrollComplete() override
{ completed_
= true; }
85 DISALLOW_COPY_AND_ASSIGN(VerticalOverscrollTracker
);
93 // This class keeps track of the RenderViewHost whose screenshot was captured.
94 class ScreenshotTracker
: public NavigationEntryScreenshotManager
{
96 explicit ScreenshotTracker(NavigationControllerImpl
* controller
)
97 : NavigationEntryScreenshotManager(controller
),
98 screenshot_taken_for_(NULL
),
99 waiting_for_screenshots_(0) {
102 ~ScreenshotTracker() override
{}
104 RenderViewHost
* screenshot_taken_for() { return screenshot_taken_for_
; }
107 screenshot_taken_for_
= NULL
;
108 screenshot_set_
.clear();
111 void SetScreenshotInterval(int interval_ms
) {
112 SetMinScreenshotIntervalMS(interval_ms
);
115 void WaitUntilScreenshotIsReady() {
116 if (!waiting_for_screenshots_
)
118 message_loop_runner_
= new content::MessageLoopRunner
;
119 message_loop_runner_
->Run();
122 bool ScreenshotSetForEntry(NavigationEntryImpl
* entry
) const {
123 return screenshot_set_
.count(entry
) > 0;
127 // Overridden from NavigationEntryScreenshotManager:
128 void TakeScreenshotImpl(RenderViewHost
* host
,
129 NavigationEntryImpl
* entry
) override
{
130 ++waiting_for_screenshots_
;
131 screenshot_taken_for_
= host
;
132 NavigationEntryScreenshotManager::TakeScreenshotImpl(host
, entry
);
135 void OnScreenshotSet(NavigationEntryImpl
* entry
) override
{
136 --waiting_for_screenshots_
;
137 screenshot_set_
[entry
] = true;
138 NavigationEntryScreenshotManager::OnScreenshotSet(entry
);
139 if (waiting_for_screenshots_
== 0 && message_loop_runner_
.get())
140 message_loop_runner_
->Quit();
143 RenderViewHost
* screenshot_taken_for_
;
144 scoped_refptr
<content::MessageLoopRunner
> message_loop_runner_
;
145 int waiting_for_screenshots_
;
146 std::map
<NavigationEntryImpl
*, bool> screenshot_set_
;
148 DISALLOW_COPY_AND_ASSIGN(ScreenshotTracker
);
151 class NavigationWatcher
: public WebContentsObserver
{
153 explicit NavigationWatcher(WebContents
* contents
)
154 : WebContentsObserver(contents
),
156 should_quit_loop_(false) {
159 ~NavigationWatcher() override
{}
161 void WaitUntilNavigationStarts() {
164 should_quit_loop_
= true;
165 base::MessageLoop::current()->Run();
169 // Overridden from WebContentsObserver:
170 void AboutToNavigateRenderView(RenderViewHost
* host
) override
{
172 if (should_quit_loop_
)
173 base::MessageLoop::current()->Quit();
177 bool should_quit_loop_
;
179 DISALLOW_COPY_AND_ASSIGN(NavigationWatcher
);
182 class InputEventMessageFilterWaitsForAcks
: public BrowserMessageFilter
{
184 InputEventMessageFilterWaitsForAcks()
185 : BrowserMessageFilter(InputMsgStart
),
186 type_(blink::WebInputEvent::Undefined
),
187 state_(INPUT_EVENT_ACK_STATE_UNKNOWN
) {}
189 void WaitForAck(blink::WebInputEvent::Type type
) {
190 base::RunLoop run_loop
;
191 base::AutoReset
<base::Closure
> reset_quit(&quit_
, run_loop
.QuitClosure());
192 base::AutoReset
<blink::WebInputEvent::Type
> reset_type(&type_
, type
);
196 InputEventAckState
last_ack_state() const { return state_
; }
199 ~InputEventMessageFilterWaitsForAcks() override
{}
202 void ReceivedEventAck(blink::WebInputEvent::Type type
,
203 InputEventAckState state
) {
210 // BrowserMessageFilter:
211 bool OnMessageReceived(const IPC::Message
& message
) override
{
212 if (message
.type() == InputHostMsg_HandleInputEvent_ACK::ID
) {
213 InputHostMsg_HandleInputEvent_ACK::Param params
;
214 InputHostMsg_HandleInputEvent_ACK::Read(&message
, ¶ms
);
215 blink::WebInputEvent::Type type
= params
.a
.type
;
216 InputEventAckState ack
= params
.a
.state
;
217 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
218 base::Bind(&InputEventMessageFilterWaitsForAcks::ReceivedEventAck
,
225 blink::WebInputEvent::Type type_
;
226 InputEventAckState state_
;
228 DISALLOW_COPY_AND_ASSIGN(InputEventMessageFilterWaitsForAcks
);
231 class WebContentsViewAuraTest
: public ContentBrowserTest
{
233 WebContentsViewAuraTest()
234 : screenshot_manager_(NULL
) {
237 // Executes the javascript synchronously and makes sure the returned value is
239 void ExecuteSyncJSFunction(RenderFrameHost
* rfh
, const std::string
& jscript
) {
240 scoped_ptr
<base::Value
> value
=
241 content::ExecuteScriptAndGetValue(rfh
, jscript
);
244 // Starts the test server and navigates to the given url. Sets a large enough
245 // size to the root window. Returns after the navigation to the url is
247 void StartTestWithPage(const std::string
& url
) {
248 ASSERT_TRUE(test_server()->Start());
249 GURL
test_url(test_server()->GetURL(url
));
250 NavigateToURL(shell(), test_url
);
252 WebContentsImpl
* web_contents
=
253 static_cast<WebContentsImpl
*>(shell()->web_contents());
254 NavigationControllerImpl
* controller
= &web_contents
->GetController();
256 screenshot_manager_
= new ScreenshotTracker(controller
);
257 controller
->SetScreenshotManager(screenshot_manager_
);
260 void SetUpCommandLine(CommandLine
* cmd
) override
{
261 cmd
->AppendSwitchASCII(switches::kTouchEvents
,
262 switches::kTouchEventsEnabled
);
265 void TestOverscrollNavigation(bool touch_handler
) {
266 ASSERT_NO_FATAL_FAILURE(
267 StartTestWithPage("files/overscroll_navigation.html"));
268 WebContentsImpl
* web_contents
=
269 static_cast<WebContentsImpl
*>(shell()->web_contents());
270 NavigationController
& controller
= web_contents
->GetController();
271 RenderFrameHost
* main_frame
= web_contents
->GetMainFrame();
273 EXPECT_FALSE(controller
.CanGoBack());
274 EXPECT_FALSE(controller
.CanGoForward());
276 scoped_ptr
<base::Value
> value
=
277 content::ExecuteScriptAndGetValue(main_frame
, "get_current()");
278 ASSERT_TRUE(value
->GetAsInteger(&index
));
282 ExecuteSyncJSFunction(main_frame
, "install_touch_handler()");
284 ExecuteSyncJSFunction(main_frame
, "navigate_next()");
285 ExecuteSyncJSFunction(main_frame
, "navigate_next()");
286 value
= content::ExecuteScriptAndGetValue(main_frame
, "get_current()");
287 ASSERT_TRUE(value
->GetAsInteger(&index
));
289 EXPECT_TRUE(controller
.CanGoBack());
290 EXPECT_FALSE(controller
.CanGoForward());
292 aura::Window
* content
= web_contents
->GetContentNativeView();
293 gfx::Rect bounds
= content
->GetBoundsInRootWindow();
294 ui::test::EventGenerator
generator(content
->GetRootWindow(), content
);
295 const int kScrollDurationMs
= 20;
296 const int kScrollSteps
= 10;
299 // Do a swipe-right now. That should navigate backwards.
300 base::string16 expected_title
= base::ASCIIToUTF16("Title: #1");
301 content::TitleWatcher
title_watcher(web_contents
, expected_title
);
302 generator
.GestureScrollSequence(
303 gfx::Point(bounds
.x() + 2, bounds
.y() + 10),
304 gfx::Point(bounds
.right() - 10, bounds
.y() + 10),
305 base::TimeDelta::FromMilliseconds(kScrollDurationMs
),
307 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
308 EXPECT_EQ(expected_title
, actual_title
);
309 value
= content::ExecuteScriptAndGetValue(main_frame
, "get_current()");
310 ASSERT_TRUE(value
->GetAsInteger(&index
));
312 EXPECT_TRUE(controller
.CanGoBack());
313 EXPECT_TRUE(controller
.CanGoForward());
317 // Do a fling-right now. That should navigate backwards.
318 base::string16 expected_title
= base::ASCIIToUTF16("Title:");
319 content::TitleWatcher
title_watcher(web_contents
, expected_title
);
320 generator
.GestureScrollSequence(
321 gfx::Point(bounds
.x() + 2, bounds
.y() + 10),
322 gfx::Point(bounds
.right() - 10, bounds
.y() + 10),
323 base::TimeDelta::FromMilliseconds(kScrollDurationMs
),
325 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
326 EXPECT_EQ(expected_title
, actual_title
);
327 value
= content::ExecuteScriptAndGetValue(main_frame
, "get_current()");
328 ASSERT_TRUE(value
->GetAsInteger(&index
));
330 EXPECT_FALSE(controller
.CanGoBack());
331 EXPECT_TRUE(controller
.CanGoForward());
335 // Do a swipe-left now. That should navigate forward.
336 base::string16 expected_title
= base::ASCIIToUTF16("Title: #1");
337 content::TitleWatcher
title_watcher(web_contents
, expected_title
);
338 generator
.GestureScrollSequence(
339 gfx::Point(bounds
.right() - 10, bounds
.y() + 10),
340 gfx::Point(bounds
.x() + 2, bounds
.y() + 10),
341 base::TimeDelta::FromMilliseconds(kScrollDurationMs
),
343 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
344 EXPECT_EQ(expected_title
, actual_title
);
345 value
= content::ExecuteScriptAndGetValue(main_frame
, "get_current()");
346 ASSERT_TRUE(value
->GetAsInteger(&index
));
348 EXPECT_TRUE(controller
.CanGoBack());
349 EXPECT_TRUE(controller
.CanGoForward());
353 int GetCurrentIndex() {
354 WebContentsImpl
* web_contents
=
355 static_cast<WebContentsImpl
*>(shell()->web_contents());
356 RenderFrameHost
* main_frame
= web_contents
->GetMainFrame();
358 scoped_ptr
<base::Value
> value
;
359 value
= content::ExecuteScriptAndGetValue(main_frame
, "get_current()");
360 if (!value
->GetAsInteger(&index
))
365 int ExecuteScriptAndExtractInt(const std::string
& script
) {
367 EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
368 shell()->web_contents(),
369 "domAutomationController.send(" + script
+ ")",
374 RenderViewHost
* GetRenderViewHost() const {
375 RenderViewHost
* const rvh
= shell()->web_contents()->GetRenderViewHost();
380 RenderWidgetHostImpl
* GetRenderWidgetHost() const {
381 RenderWidgetHostImpl
* const rwh
=
382 RenderWidgetHostImpl::From(shell()
384 ->GetRenderWidgetHostView()
385 ->GetRenderWidgetHost());
390 RenderWidgetHostViewBase
* GetRenderWidgetHostView() const {
391 return static_cast<RenderWidgetHostViewBase
*>(
392 GetRenderViewHost()->GetView());
395 InputEventMessageFilterWaitsForAcks
* filter() {
396 return filter_
.get();
400 uint32 frame
= GetRenderWidgetHostView()->RendererFrameNumber();
401 while (!GetRenderWidgetHost()->ScheduleComposite())
403 while (GetRenderWidgetHostView()->RendererFrameNumber() == frame
)
408 ScreenshotTracker
* screenshot_manager() { return screenshot_manager_
; }
409 void set_min_screenshot_interval(int interval_ms
) {
410 screenshot_manager_
->SetScreenshotInterval(interval_ms
);
413 void AddInputEventMessageFilter() {
414 filter_
= new InputEventMessageFilterWaitsForAcks();
415 GetRenderWidgetHost()->GetProcess()->AddFilter(filter_
.get());
419 ScreenshotTracker
* screenshot_manager_
;
420 scoped_refptr
<InputEventMessageFilterWaitsForAcks
> filter_
;
422 DISALLOW_COPY_AND_ASSIGN(WebContentsViewAuraTest
);
425 // Flaky on Windows: http://crbug.com/305722
427 #define MAYBE_OverscrollNavigation DISABLED_OverscrollNavigation
429 #define MAYBE_OverscrollNavigation OverscrollNavigation
432 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
, MAYBE_OverscrollNavigation
) {
433 TestOverscrollNavigation(false);
436 // Flaky on Windows (might be related to the above test):
437 // http://crbug.com/305722
439 #define MAYBE_OverscrollNavigationWithTouchHandler \
440 DISABLED_OverscrollNavigationWithTouchHandler
442 #define MAYBE_OverscrollNavigationWithTouchHandler \
443 OverscrollNavigationWithTouchHandler
445 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
,
446 MAYBE_OverscrollNavigationWithTouchHandler
) {
447 TestOverscrollNavigation(true);
450 // Disabled because the test always fails the first time it runs on the Win Aura
451 // bots, and usually but not always passes second-try (See crbug.com/179532).
453 #define MAYBE_QuickOverscrollDirectionChange \
454 DISABLED_QuickOverscrollDirectionChange
456 #define MAYBE_QuickOverscrollDirectionChange QuickOverscrollDirectionChange
458 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
,
459 MAYBE_QuickOverscrollDirectionChange
) {
460 ASSERT_NO_FATAL_FAILURE(
461 StartTestWithPage("files/overscroll_navigation.html"));
462 WebContentsImpl
* web_contents
=
463 static_cast<WebContentsImpl
*>(shell()->web_contents());
464 RenderFrameHost
* main_frame
= web_contents
->GetMainFrame();
466 // This test triggers a large number of animations. Speed them up to ensure
467 // the test completes within its time limit.
468 ui::ScopedAnimationDurationScaleMode
fast_duration_mode(
469 ui::ScopedAnimationDurationScaleMode::FAST_DURATION
);
471 // Make sure the page has both back/forward history.
472 ExecuteSyncJSFunction(main_frame
, "navigate_next()");
473 EXPECT_EQ(1, GetCurrentIndex());
474 ExecuteSyncJSFunction(main_frame
, "navigate_next()");
475 EXPECT_EQ(2, GetCurrentIndex());
476 web_contents
->GetController().GoBack();
477 EXPECT_EQ(1, GetCurrentIndex());
479 aura::Window
* content
= web_contents
->GetContentNativeView();
480 ui::EventProcessor
* dispatcher
= content
->GetHost()->event_processor();
481 gfx::Rect bounds
= content
->GetBoundsInRootWindow();
483 base::TimeDelta timestamp
= ui::EventTimeForNow();
484 ui::TouchEvent
press(ui::ET_TOUCH_PRESSED
,
485 gfx::Point(bounds
.x() + bounds
.width() / 2, bounds
.y() + 5),
487 ui::EventDispatchDetails details
= dispatcher
->OnEventFromSource(&press
);
488 ASSERT_FALSE(details
.dispatcher_destroyed
);
489 EXPECT_EQ(1, GetCurrentIndex());
491 timestamp
+= base::TimeDelta::FromMilliseconds(10);
492 ui::TouchEvent
move1(ui::ET_TOUCH_MOVED
,
493 gfx::Point(bounds
.right() - 10, bounds
.y() + 5),
495 details
= dispatcher
->OnEventFromSource(&move1
);
496 ASSERT_FALSE(details
.dispatcher_destroyed
);
497 EXPECT_EQ(1, GetCurrentIndex());
499 // Swipe back from the right edge, back to the left edge, back to the right
502 for (int x
= bounds
.right() - 10; x
>= bounds
.x() + 10; x
-= 10) {
503 timestamp
+= base::TimeDelta::FromMilliseconds(10);
504 ui::TouchEvent
inc(ui::ET_TOUCH_MOVED
,
505 gfx::Point(x
, bounds
.y() + 5),
507 details
= dispatcher
->OnEventFromSource(&inc
);
508 ASSERT_FALSE(details
.dispatcher_destroyed
);
509 EXPECT_EQ(1, GetCurrentIndex());
512 for (int x
= bounds
.x() + 10; x
<= bounds
.width() - 10; x
+= 10) {
513 timestamp
+= base::TimeDelta::FromMilliseconds(10);
514 ui::TouchEvent
inc(ui::ET_TOUCH_MOVED
,
515 gfx::Point(x
, bounds
.y() + 5),
517 details
= dispatcher
->OnEventFromSource(&inc
);
518 ASSERT_FALSE(details
.dispatcher_destroyed
);
519 EXPECT_EQ(1, GetCurrentIndex());
522 for (int x
= bounds
.width() - 10; x
>= bounds
.x() + 10; x
-= 10) {
523 timestamp
+= base::TimeDelta::FromMilliseconds(10);
524 ui::TouchEvent
inc(ui::ET_TOUCH_MOVED
,
525 gfx::Point(x
, bounds
.y() + 5),
527 details
= dispatcher
->OnEventFromSource(&inc
);
528 ASSERT_FALSE(details
.dispatcher_destroyed
);
529 EXPECT_EQ(1, GetCurrentIndex());
532 // Do not end the overscroll sequence.
535 // Tests that the page has has a screenshot when navigation happens:
536 // - from within the page (from a JS function)
537 // - interactively, when user does an overscroll gesture
538 // - interactively, when user navigates in history without the overscroll
540 // Flaky on Windows (http://crbug.com/357311). Might be related to
541 // OverscrollNavigation test.
542 // Flaky on Ozone (http://crbug.com/399676).
543 // Flaky on ChromeOS (http://crbug.com/405945).
544 #if defined(OS_WIN) || defined(USE_OZONE) || defined(OS_CHROMEOS)
545 #define MAYBE_OverscrollScreenshot DISABLED_OverscrollScreenshot
547 #define MAYBE_OverscrollScreenshot OverscrollScreenshot
549 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
, MAYBE_OverscrollScreenshot
) {
550 // Disable the test for WinXP. See http://crbug/294116.
552 if (base::win::GetVersion() < base::win::VERSION_VISTA
) {
553 LOG(WARNING
) << "Test disabled due to unknown bug on WinXP.";
558 ASSERT_NO_FATAL_FAILURE(
559 StartTestWithPage("files/overscroll_navigation.html"));
560 WebContentsImpl
* web_contents
=
561 static_cast<WebContentsImpl
*>(shell()->web_contents());
562 RenderFrameHost
* main_frame
= web_contents
->GetMainFrame();
564 set_min_screenshot_interval(0);
566 // Do a few navigations initiated by the page.
567 // Screenshots should never be captured since these are all in-page
569 ExecuteSyncJSFunction(main_frame
, "navigate_next()");
570 EXPECT_EQ(1, GetCurrentIndex());
571 ExecuteSyncJSFunction(main_frame
, "navigate_next()");
572 EXPECT_EQ(2, GetCurrentIndex());
573 screenshot_manager()->WaitUntilScreenshotIsReady();
575 NavigationEntryImpl
* entry
= NavigationEntryImpl::FromNavigationEntry(
576 web_contents
->GetController().GetEntryAtIndex(2));
577 EXPECT_FALSE(entry
->screenshot().get());
579 entry
= NavigationEntryImpl::FromNavigationEntry(
580 web_contents
->GetController().GetEntryAtIndex(1));
581 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry
));
583 entry
= NavigationEntryImpl::FromNavigationEntry(
584 web_contents
->GetController().GetEntryAtIndex(0));
585 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry
));
587 ExecuteSyncJSFunction(main_frame
, "navigate_next()");
588 screenshot_manager()->WaitUntilScreenshotIsReady();
590 entry
= NavigationEntryImpl::FromNavigationEntry(
591 web_contents
->GetController().GetEntryAtIndex(2));
592 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry
));
594 entry
= NavigationEntryImpl::FromNavigationEntry(
595 web_contents
->GetController().GetEntryAtIndex(3));
596 EXPECT_FALSE(entry
->screenshot().get());
598 // Now, swipe right to navigate backwards. This should navigate away from
599 // index 3 to index 2.
600 base::string16 expected_title
= base::ASCIIToUTF16("Title: #2");
601 content::TitleWatcher
title_watcher(web_contents
, expected_title
);
602 aura::Window
* content
= web_contents
->GetContentNativeView();
603 gfx::Rect bounds
= content
->GetBoundsInRootWindow();
604 ui::test::EventGenerator
generator(content
->GetRootWindow(), content
);
605 generator
.GestureScrollSequence(
606 gfx::Point(bounds
.x() + 2, bounds
.y() + 10),
607 gfx::Point(bounds
.right() - 10, bounds
.y() + 10),
608 base::TimeDelta::FromMilliseconds(20),
610 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
611 EXPECT_EQ(expected_title
, actual_title
);
612 EXPECT_EQ(2, GetCurrentIndex());
613 screenshot_manager()->WaitUntilScreenshotIsReady();
614 entry
= NavigationEntryImpl::FromNavigationEntry(
615 web_contents
->GetController().GetEntryAtIndex(3));
616 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry
));
619 // Navigate a couple more times.
620 ExecuteSyncJSFunction(main_frame
, "navigate_next()");
621 EXPECT_EQ(3, GetCurrentIndex());
622 ExecuteSyncJSFunction(main_frame
, "navigate_next()");
623 EXPECT_EQ(4, GetCurrentIndex());
624 screenshot_manager()->WaitUntilScreenshotIsReady();
625 entry
= NavigationEntryImpl::FromNavigationEntry(
626 web_contents
->GetController().GetEntryAtIndex(4));
627 EXPECT_FALSE(entry
->screenshot().get());
630 // Navigate back in history.
631 base::string16 expected_title
= base::ASCIIToUTF16("Title: #3");
632 content::TitleWatcher
title_watcher(web_contents
, expected_title
);
633 web_contents
->GetController().GoBack();
634 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
635 EXPECT_EQ(expected_title
, actual_title
);
636 EXPECT_EQ(3, GetCurrentIndex());
637 screenshot_manager()->WaitUntilScreenshotIsReady();
638 entry
= NavigationEntryImpl::FromNavigationEntry(
639 web_contents
->GetController().GetEntryAtIndex(4));
640 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry
));
644 // Crashes under ThreadSanitizer, http://crbug.com/356758.
645 #if defined(THREAD_SANITIZER)
646 #define MAYBE_ScreenshotForSwappedOutRenderViews \
647 DISABLED_ScreenshotForSwappedOutRenderViews
649 #define MAYBE_ScreenshotForSwappedOutRenderViews \
650 ScreenshotForSwappedOutRenderViews
652 // Tests that screenshot is taken correctly when navigation causes a
653 // RenderViewHost to be swapped out.
654 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
,
655 MAYBE_ScreenshotForSwappedOutRenderViews
) {
656 ASSERT_NO_FATAL_FAILURE(
657 StartTestWithPage("files/overscroll_navigation.html"));
658 // Create a new server with a different site.
659 net::SpawnedTestServer
https_server(
660 net::SpawnedTestServer::TYPE_HTTPS
,
661 net::SpawnedTestServer::kLocalhost
,
662 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
663 ASSERT_TRUE(https_server
.Start());
665 WebContentsImpl
* web_contents
=
666 static_cast<WebContentsImpl
*>(shell()->web_contents());
667 set_min_screenshot_interval(0);
673 { https_server
.GetURL("files/title1.html"),
674 ui::PAGE_TRANSITION_TYPED
| ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
},
675 { test_server()->GetURL("files/title2.html"),
676 ui::PAGE_TRANSITION_AUTO_BOOKMARK
},
677 { https_server
.GetURL("files/title3.html"),
678 ui::PAGE_TRANSITION_TYPED
| ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
},
682 screenshot_manager()->Reset();
683 for (int i
= 0; !navigations
[i
].url
.is_empty(); ++i
) {
684 // Navigate via the user initiating a navigation from the UI.
685 NavigationController::LoadURLParams
params(navigations
[i
].url
);
686 params
.transition_type
=
687 ui::PageTransitionFromInt(navigations
[i
].transition
);
689 RenderViewHost
* old_host
= web_contents
->GetRenderViewHost();
690 web_contents
->GetController().LoadURLWithParams(params
);
691 WaitForLoadStop(web_contents
);
692 screenshot_manager()->WaitUntilScreenshotIsReady();
694 EXPECT_NE(old_host
, web_contents
->GetRenderViewHost())
695 << navigations
[i
].url
.spec();
696 EXPECT_EQ(old_host
, screenshot_manager()->screenshot_taken_for());
698 NavigationEntryImpl
* entry
= NavigationEntryImpl::FromNavigationEntry(
699 web_contents
->GetController().GetEntryAtOffset(-1));
700 EXPECT_TRUE(screenshot_manager()->ScreenshotSetForEntry(entry
));
702 entry
= NavigationEntryImpl::FromNavigationEntry(
703 web_contents
->GetController().GetLastCommittedEntry());
704 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry
));
705 EXPECT_FALSE(entry
->screenshot().get());
706 screenshot_manager()->Reset();
709 // Increase the minimum interval between taking screenshots.
710 set_min_screenshot_interval(60000);
712 // Navigate again. This should not take any screenshot because of the
713 // increased screenshot interval.
714 NavigationController::LoadURLParams
params(navigations
[0].url
);
715 params
.transition_type
= ui::PageTransitionFromInt(navigations
[0].transition
);
716 web_contents
->GetController().LoadURLWithParams(params
);
717 WaitForLoadStop(web_contents
);
718 screenshot_manager()->WaitUntilScreenshotIsReady();
720 EXPECT_EQ(NULL
, screenshot_manager()->screenshot_taken_for());
723 // Tests that navigations resulting from reloads, history.replaceState,
724 // and history.pushState do not capture screenshots.
725 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
, ReplaceStateReloadPushState
) {
726 ASSERT_NO_FATAL_FAILURE(
727 StartTestWithPage("files/overscroll_navigation.html"));
728 WebContentsImpl
* web_contents
=
729 static_cast<WebContentsImpl
*>(shell()->web_contents());
730 RenderFrameHost
* main_frame
= web_contents
->GetMainFrame();
732 set_min_screenshot_interval(0);
733 screenshot_manager()->Reset();
734 ExecuteSyncJSFunction(main_frame
, "use_replace_state()");
735 screenshot_manager()->WaitUntilScreenshotIsReady();
736 // history.replaceState shouldn't capture a screenshot
737 EXPECT_FALSE(screenshot_manager()->screenshot_taken_for());
738 screenshot_manager()->Reset();
739 web_contents
->GetController().Reload(true);
740 WaitForLoadStop(web_contents
);
741 // reloading the page shouldn't capture a screenshot
742 // TODO (mfomitchev): currently broken. Uncomment when
743 // FrameHostMsg_DidCommitProvisionalLoad_Params.was_within_same_page
744 // is populated properly when reloading the page.
745 //EXPECT_FALSE(screenshot_manager()->screenshot_taken_for());
746 screenshot_manager()->Reset();
747 ExecuteSyncJSFunction(main_frame
, "use_push_state()");
748 screenshot_manager()->WaitUntilScreenshotIsReady();
749 // pushing a state shouldn't capture a screenshot
750 // TODO (mfomitchev): currently broken. Uncomment when
751 // FrameHostMsg_DidCommitProvisionalLoad_Params.was_within_same_page
752 // is populated properly when pushState is used.
753 //EXPECT_FALSE(screenshot_manager()->screenshot_taken_for());
756 // TODO(sadrul): This test is disabled because it reparents in a way the
757 // FocusController does not support. This code would crash in
758 // a production build. It only passed prior to this revision
759 // because testing used the old FocusManager which did some
760 // different (osbolete) processing. TODO(sadrul) to figure out
761 // how this test should work that mimics production code a bit
763 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
,
764 DISABLED_ContentWindowReparent
) {
765 ASSERT_NO_FATAL_FAILURE(
766 StartTestWithPage("files/overscroll_navigation.html"));
768 scoped_ptr
<aura::Window
> window(new aura::Window(NULL
));
769 window
->Init(aura::WINDOW_LAYER_NOT_DRAWN
);
771 WebContentsImpl
* web_contents
=
772 static_cast<WebContentsImpl
*>(shell()->web_contents());
773 ExecuteSyncJSFunction(web_contents
->GetMainFrame(), "navigate_next()");
774 EXPECT_EQ(1, GetCurrentIndex());
776 aura::Window
* content
= web_contents
->GetContentNativeView();
777 gfx::Rect bounds
= content
->GetBoundsInRootWindow();
778 ui::test::EventGenerator
generator(content
->GetRootWindow(), content
);
779 generator
.GestureScrollSequence(
780 gfx::Point(bounds
.x() + 2, bounds
.y() + 10),
781 gfx::Point(bounds
.right() - 10, bounds
.y() + 10),
782 base::TimeDelta::FromMilliseconds(20),
785 window
->AddChild(shell()->web_contents()->GetContentNativeView());
788 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
, ContentWindowClose
) {
789 ASSERT_NO_FATAL_FAILURE(
790 StartTestWithPage("files/overscroll_navigation.html"));
792 WebContentsImpl
* web_contents
=
793 static_cast<WebContentsImpl
*>(shell()->web_contents());
794 ExecuteSyncJSFunction(web_contents
->GetMainFrame(), "navigate_next()");
795 EXPECT_EQ(1, GetCurrentIndex());
797 aura::Window
* content
= web_contents
->GetContentNativeView();
798 gfx::Rect bounds
= content
->GetBoundsInRootWindow();
799 ui::test::EventGenerator
generator(content
->GetRootWindow(), content
);
800 generator
.GestureScrollSequence(
801 gfx::Point(bounds
.x() + 2, bounds
.y() + 10),
802 gfx::Point(bounds
.right() - 10, bounds
.y() + 10),
803 base::TimeDelta::FromMilliseconds(20),
806 delete web_contents
->GetContentNativeView();
810 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
811 // This appears to be flaky in the same was as the other overscroll
812 // tests. Enabling for non-Windows platforms.
813 // See http://crbug.com/369871.
814 // For linux, see http://crbug.com/381294
815 #define MAYBE_RepeatedQuickOverscrollGestures DISABLED_RepeatedQuickOverscrollGestures
817 #define MAYBE_RepeatedQuickOverscrollGestures RepeatedQuickOverscrollGestures
820 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
,
821 MAYBE_RepeatedQuickOverscrollGestures
) {
822 ASSERT_NO_FATAL_FAILURE(
823 StartTestWithPage("files/overscroll_navigation.html"));
825 WebContentsImpl
* web_contents
=
826 static_cast<WebContentsImpl
*>(shell()->web_contents());
827 NavigationController
& controller
= web_contents
->GetController();
828 RenderFrameHost
* main_frame
= web_contents
->GetMainFrame();
829 ExecuteSyncJSFunction(main_frame
, "install_touch_handler()");
831 // Navigate twice, then navigate back in history once.
832 ExecuteSyncJSFunction(main_frame
, "navigate_next()");
833 ExecuteSyncJSFunction(main_frame
, "navigate_next()");
834 EXPECT_EQ(2, GetCurrentIndex());
835 EXPECT_TRUE(controller
.CanGoBack());
836 EXPECT_FALSE(controller
.CanGoForward());
838 web_contents
->GetController().GoBack();
839 WaitForLoadStop(web_contents
);
840 EXPECT_EQ(1, GetCurrentIndex());
841 EXPECT_EQ(base::ASCIIToUTF16("Title: #1"), web_contents
->GetTitle());
842 EXPECT_TRUE(controller
.CanGoBack());
843 EXPECT_TRUE(controller
.CanGoForward());
845 aura::Window
* content
= web_contents
->GetContentNativeView();
846 gfx::Rect bounds
= content
->GetBoundsInRootWindow();
847 ui::test::EventGenerator
generator(content
->GetRootWindow(), content
);
849 // Do a swipe left to start a forward navigation. Then quickly do a swipe
851 base::string16 expected_title
= base::ASCIIToUTF16("Title: #2");
852 content::TitleWatcher
title_watcher(web_contents
, expected_title
);
853 NavigationWatcher
nav_watcher(web_contents
);
855 generator
.GestureScrollSequence(
856 gfx::Point(bounds
.right() - 10, bounds
.y() + 10),
857 gfx::Point(bounds
.x() + 2, bounds
.y() + 10),
858 base::TimeDelta::FromMilliseconds(2000),
860 nav_watcher
.WaitUntilNavigationStarts();
862 generator
.GestureScrollSequence(
863 gfx::Point(bounds
.x() + 2, bounds
.y() + 10),
864 gfx::Point(bounds
.right() - 10, bounds
.y() + 10),
865 base::TimeDelta::FromMilliseconds(2000),
867 base::string16 actual_title
= title_watcher
.WaitAndGetTitle();
868 EXPECT_EQ(expected_title
, actual_title
);
870 EXPECT_EQ(2, GetCurrentIndex());
871 EXPECT_TRUE(controller
.CanGoBack());
872 EXPECT_FALSE(controller
.CanGoForward());
875 // Verify that hiding a parent of the renderer will hide the content too.
876 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
, HideContentOnParenHide
) {
877 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/title1.html"));
878 WebContentsImpl
* web_contents
=
879 static_cast<WebContentsImpl
*>(shell()->web_contents());
880 aura::Window
* content
= web_contents
->GetNativeView()->parent();
881 EXPECT_TRUE(web_contents
->should_normally_be_visible());
883 EXPECT_FALSE(web_contents
->should_normally_be_visible());
885 EXPECT_TRUE(web_contents
->should_normally_be_visible());
888 // Ensure that SnapToPhysicalPixelBoundary() is called on WebContentsView parent
889 // change. This is a regression test for http://crbug.com/388908.
890 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
, WebContentsViewReparent
) {
891 ASSERT_NO_FATAL_FAILURE(
892 StartTestWithPage("files/overscroll_navigation.html"));
894 scoped_ptr
<aura::Window
> window(new aura::Window(NULL
));
895 window
->Init(aura::WINDOW_LAYER_NOT_DRAWN
);
897 RenderWidgetHostViewAura
* rwhva
=
898 static_cast<RenderWidgetHostViewAura
*>(
899 shell()->web_contents()->GetRenderWidgetHostView());
900 rwhva
->ResetHasSnappedToBoundary();
901 EXPECT_FALSE(rwhva
->has_snapped_to_boundary());
902 window
->AddChild(shell()->web_contents()->GetNativeView());
903 EXPECT_TRUE(rwhva
->has_snapped_to_boundary());
906 // Flaky on some platforms, likely for the same reason as other flaky overscroll
907 // tests. http://crbug.com/305722
908 // TODO(tdresser): Re-enable this once eager GR is back on. See
910 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
911 #define MAYBE_OverscrollNavigationTouchThrottling \
912 DISABLED_OverscrollNavigationTouchThrottling
914 #define MAYBE_OverscrollNavigationTouchThrottling \
915 DISABLED_OverscrollNavigationTouchThrottling
918 // Tests that touch moves are not throttled when performing a scroll gesture on
919 // a non-scrollable area, except during gesture-nav.
920 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
,
921 MAYBE_OverscrollNavigationTouchThrottling
) {
922 ASSERT_NO_FATAL_FAILURE(
923 StartTestWithPage("files/overscroll_navigation.html"));
925 AddInputEventMessageFilter();
927 WebContentsImpl
* web_contents
=
928 static_cast<WebContentsImpl
*>(shell()->web_contents());
929 aura::Window
* content
= web_contents
->GetContentNativeView();
930 gfx::Rect bounds
= content
->GetBoundsInRootWindow();
933 ExecuteSyncJSFunction(web_contents
->GetMainFrame(),
934 "install_touchmove_handler()");
938 for (int navigated
= 0; navigated
<= 1; ++navigated
) {
940 ExecuteSyncJSFunction(web_contents
->GetMainFrame(), "navigate_next()");
941 ExecuteSyncJSFunction(web_contents
->GetMainFrame(),
942 "reset_touchmove_count()");
945 SyntheticWebTouchEvent touch
;
946 touch
.PressPoint(bounds
.x() + 2, bounds
.y() + 10);
947 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
,
949 filter()->WaitForAck(blink::WebInputEvent::TouchStart
);
952 // Assert on the ack, because we'll end up waiting for acks that will never
953 // come if this is not true.
954 ASSERT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED
, filter()->last_ack_state());
956 // Send first touch move, and then a scroll begin.
957 touch
.MovePoint(0, bounds
.x() + 20 + 1 * dx
, bounds
.y() + 100);
958 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
,
960 filter()->WaitForAck(blink::WebInputEvent::TouchMove
);
961 ASSERT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED
, filter()->last_ack_state());
963 blink::WebGestureEvent scroll_begin
=
964 SyntheticWebGestureEventBuilder::BuildScrollBegin(1, 1);
965 GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
966 scroll_begin
, ui::LatencyInfo());
967 // Scroll begin ignores ack disposition, so don't wait for the ack.
970 // First touchmove already sent, start at 2.
971 for (int i
= 2; i
<= 10; ++i
) {
972 // Send a touch move, followed by a scroll update
973 touch
.MovePoint(0, bounds
.x() + 20 + i
* dx
, bounds
.y() + 100);
974 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(
975 touch
, ui::LatencyInfo());
978 blink::WebGestureEvent scroll_update
=
979 SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx
, 5, 0);
981 GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
982 scroll_update
, ui::LatencyInfo());
987 touch
.ReleasePoint(0);
988 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch
,
992 blink::WebGestureEvent scroll_end
;
993 scroll_end
.type
= blink::WebInputEvent::GestureScrollEnd
;
994 GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo(
995 scroll_end
, ui::LatencyInfo());
999 EXPECT_EQ(10, ExecuteScriptAndExtractInt("touchmoveCount"));
1001 EXPECT_GT(10, ExecuteScriptAndExtractInt("touchmoveCount"));
1005 // Test that vertical overscroll updates are sent only when a user overscrolls
1008 #define MAYBE_VerticalOverscroll DISABLED_VerticalOverscroll
1010 #define MAYBE_VerticalOverscroll VerticalOverscroll
1013 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest
, MAYBE_VerticalOverscroll
) {
1014 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1015 switches::kScrollEndEffect
, "1");
1017 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("about:blank"));
1018 WebContentsImpl
* web_contents
=
1019 static_cast<WebContentsImpl
*>(shell()->web_contents());
1020 VerticalOverscrollTracker tracker
;
1021 web_contents
->SetDelegate(&tracker
);
1023 // This test triggers a large number of animations. Speed them up to ensure
1024 // the test completes within its time limit.
1025 ui::ScopedAnimationDurationScaleMode
fast_duration_mode(
1026 ui::ScopedAnimationDurationScaleMode::FAST_DURATION
);
1028 aura::Window
* content
= web_contents
->GetContentNativeView();
1029 ui::EventProcessor
* dispatcher
= content
->GetHost()->event_processor();
1030 gfx::Rect bounds
= content
->GetBoundsInRootWindow();
1032 // Overscroll horizontally.
1034 int kXStep
= bounds
.width() / 10;
1035 gfx::Point
location(bounds
.right() - kXStep
, bounds
.y() + 5);
1036 base::TimeDelta timestamp
= ui::EventTimeForNow();
1037 ui::TouchEvent
press(
1038 ui::ET_TOUCH_PRESSED
,
1042 ui::EventDispatchDetails details
= dispatcher
->OnEventFromSource(&press
);
1043 ASSERT_FALSE(details
.dispatcher_destroyed
);
1045 location
-= gfx::Vector2d(kXStep
, 0);
1046 timestamp
+= base::TimeDelta::FromMilliseconds(10);
1048 while (location
.x() > bounds
.x() + kXStep
) {
1049 ui::TouchEvent
inc(ui::ET_TOUCH_MOVED
, location
, 0, timestamp
);
1050 details
= dispatcher
->OnEventFromSource(&inc
);
1051 ASSERT_FALSE(details
.dispatcher_destroyed
);
1053 location
-= gfx::Vector2d(10, 0);
1054 timestamp
+= base::TimeDelta::FromMilliseconds(10);
1057 ui::TouchEvent
release(ui::ET_TOUCH_RELEASED
, location
, 0, timestamp
);
1058 details
= dispatcher
->OnEventFromSource(&press
);
1059 ASSERT_FALSE(details
.dispatcher_destroyed
);
1062 EXPECT_EQ(0, tracker
.num_overscroll_updates());
1063 EXPECT_FALSE(tracker
.overscroll_completed());
1066 // Overscroll vertically.
1070 int kYStep
= bounds
.height() / 10;
1071 gfx::Point
location(bounds
.x() + 10, bounds
.y() + kYStep
);
1072 base::TimeDelta timestamp
= ui::EventTimeForNow();
1073 ui::TouchEvent
press(
1074 ui::ET_TOUCH_PRESSED
,
1078 ui::EventDispatchDetails details
= dispatcher
->OnEventFromSource(&press
);
1079 ASSERT_FALSE(details
.dispatcher_destroyed
);
1081 location
+= gfx::Vector2d(0, kYStep
);
1082 timestamp
+= base::TimeDelta::FromMilliseconds(10);
1084 while (location
.y() < bounds
.bottom() - kYStep
) {
1085 ui::TouchEvent
inc(ui::ET_TOUCH_MOVED
, location
, 0, timestamp
);
1086 details
= dispatcher
->OnEventFromSource(&inc
);
1087 ASSERT_FALSE(details
.dispatcher_destroyed
);
1089 location
+= gfx::Vector2d(0, kYStep
);
1090 timestamp
+= base::TimeDelta::FromMilliseconds(10);
1093 ui::TouchEvent
release(ui::ET_TOUCH_RELEASED
, location
, 0, timestamp
);
1094 details
= dispatcher
->OnEventFromSource(&release
);
1095 ASSERT_FALSE(details
.dispatcher_destroyed
);
1098 EXPECT_LT(0, tracker
.num_overscroll_updates());
1099 EXPECT_TRUE(tracker
.overscroll_completed());
1102 // Start out overscrolling vertically, then switch directions and finish
1103 // overscrolling horizontally.
1107 int kXStep
= bounds
.width() / 10;
1108 int kYStep
= bounds
.height() / 10;
1109 gfx::Point location
= bounds
.origin() + gfx::Vector2d(0, kYStep
);
1110 base::TimeDelta timestamp
= ui::EventTimeForNow();
1111 ui::TouchEvent
press(
1112 ui::ET_TOUCH_PRESSED
,
1116 ui::EventDispatchDetails details
= dispatcher
->OnEventFromSource(&press
);
1117 ASSERT_FALSE(details
.dispatcher_destroyed
);
1119 location
+= gfx::Vector2d(0, kYStep
);
1120 timestamp
+= base::TimeDelta::FromMilliseconds(10);
1122 for (size_t i
= 0; i
< 3; ++i
) {
1123 ui::TouchEvent
inc(ui::ET_TOUCH_MOVED
, location
, 0, timestamp
);
1124 details
= dispatcher
->OnEventFromSource(&inc
);
1125 ASSERT_FALSE(details
.dispatcher_destroyed
);
1127 location
+= gfx::Vector2d(0, kYStep
);
1128 timestamp
+= base::TimeDelta::FromMilliseconds(10);
1131 while (location
.x() < bounds
.right() - kXStep
) {
1132 ui::TouchEvent
inc(ui::ET_TOUCH_MOVED
, location
, 0, timestamp
);
1133 details
= dispatcher
->OnEventFromSource(&inc
);
1134 ASSERT_FALSE(details
.dispatcher_destroyed
);
1136 location
+= gfx::Vector2d(kXStep
, 0);
1137 timestamp
+= base::TimeDelta::FromMilliseconds(10);
1140 ui::TouchEvent
release(ui::ET_TOUCH_RELEASED
, location
, 0, timestamp
);
1141 details
= dispatcher
->OnEventFromSource(&release
);
1142 ASSERT_FALSE(details
.dispatcher_destroyed
);
1145 EXPECT_LT(0, tracker
.num_overscroll_updates());
1146 EXPECT_FALSE(tracker
.overscroll_completed());
1150 } // namespace content