web_contents_view_aura_browsertest.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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_observer.h" 27#include "content/public/common/content_switches.h" 28#include "content/public/test/browser_test_utils.h" 29#include "content/public/test/content_browser_test.h" 30#include "content/public/test/content_browser_test_utils.h" 31#include "content/public/test/test_renderer_host.h" 32#include "content/public/test/test_utils.h" 33#include "content/shell/browser/shell.h" 34#include "ui/aura/window.h" 35#include "ui/aura/window_tree_host.h" 36#include "ui/compositor/scoped_animation_duration_scale_mode.h" 37#include "ui/events/event_processor.h" 38#include "ui/events/event_switches.h" 39#include "ui/events/event_utils.h" 40#include "ui/events/test/event_generator.h" 41 42namespace { 43 44// TODO(tdresser): Find a way to avoid sleeping like this. See crbug.com/405282 45// for details. 46void GiveItSomeTime() { 47 base::RunLoop run_loop; 48 base::MessageLoop::current()->PostDelayedTask( 49 FROM_HERE, 50 run_loop.QuitClosure(), 51 base::TimeDelta::FromMillisecondsD(10)); 52 run_loop.Run(); 53} 54 55} //namespace 56 57 58namespace content { 59 60// This class keeps track of the RenderViewHost whose screenshot was captured. 61class ScreenshotTracker : public NavigationEntryScreenshotManager { 62 public: 63 explicit ScreenshotTracker(NavigationControllerImpl* controller) 64 : NavigationEntryScreenshotManager(controller), 65 screenshot_taken_for_(NULL), 66 waiting_for_screenshots_(0) { 67 } 68 69 virtual ~ScreenshotTracker() { 70 } 71 72 RenderViewHost* screenshot_taken_for() { return screenshot_taken_for_; } 73 74 void Reset() { 75 screenshot_taken_for_ = NULL; 76 screenshot_set_.clear(); 77 } 78 79 void SetScreenshotInterval(int interval_ms) { 80 SetMinScreenshotIntervalMS(interval_ms); 81 } 82 83 void WaitUntilScreenshotIsReady() { 84 if (!waiting_for_screenshots_) 85 return; 86 message_loop_runner_ = new content::MessageLoopRunner; 87 message_loop_runner_->Run(); 88 } 89 90 bool ScreenshotSetForEntry(NavigationEntryImpl* entry) const { 91 return screenshot_set_.count(entry) > 0; 92 } 93 94 private: 95 // Overridden from NavigationEntryScreenshotManager: 96 virtual void TakeScreenshotImpl(RenderViewHost* host, 97 NavigationEntryImpl* entry) OVERRIDE { 98 ++waiting_for_screenshots_; 99 screenshot_taken_for_ = host; 100 NavigationEntryScreenshotManager::TakeScreenshotImpl(host, entry); 101 } 102 103 virtual void OnScreenshotSet(NavigationEntryImpl* entry) OVERRIDE { 104 --waiting_for_screenshots_; 105 screenshot_set_[entry] = true; 106 NavigationEntryScreenshotManager::OnScreenshotSet(entry); 107 if (waiting_for_screenshots_ == 0 && message_loop_runner_.get()) 108 message_loop_runner_->Quit(); 109 } 110 111 RenderViewHost* screenshot_taken_for_; 112 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; 113 int waiting_for_screenshots_; 114 std::map<NavigationEntryImpl*, bool> screenshot_set_; 115 116 DISALLOW_COPY_AND_ASSIGN(ScreenshotTracker); 117}; 118 119class NavigationWatcher : public WebContentsObserver { 120 public: 121 explicit NavigationWatcher(WebContents* contents) 122 : WebContentsObserver(contents), 123 navigated_(false), 124 should_quit_loop_(false) { 125 } 126 127 virtual ~NavigationWatcher() {} 128 129 void WaitUntilNavigationStarts() { 130 if (navigated_) 131 return; 132 should_quit_loop_ = true; 133 base::MessageLoop::current()->Run(); 134 } 135 136 private: 137 // Overridden from WebContentsObserver: 138 virtual void AboutToNavigateRenderView(RenderViewHost* host) OVERRIDE { 139 navigated_ = true; 140 if (should_quit_loop_) 141 base::MessageLoop::current()->Quit(); 142 } 143 144 bool navigated_; 145 bool should_quit_loop_; 146 147 DISALLOW_COPY_AND_ASSIGN(NavigationWatcher); 148}; 149 150class InputEventMessageFilterWaitsForAcks : public BrowserMessageFilter { 151 public: 152 InputEventMessageFilterWaitsForAcks() 153 : BrowserMessageFilter(InputMsgStart), 154 type_(blink::WebInputEvent::Undefined), 155 state_(INPUT_EVENT_ACK_STATE_UNKNOWN) {} 156 157 void WaitForAck(blink::WebInputEvent::Type type) { 158 base::RunLoop run_loop; 159 base::AutoReset<base::Closure> reset_quit(&quit_, run_loop.QuitClosure()); 160 base::AutoReset<blink::WebInputEvent::Type> reset_type(&type_, type); 161 run_loop.Run(); 162 } 163 164 InputEventAckState last_ack_state() const { return state_; } 165 166 protected: 167 virtual ~InputEventMessageFilterWaitsForAcks() {} 168 169 private: 170 void ReceivedEventAck(blink::WebInputEvent::Type type, 171 InputEventAckState state) { 172 if (type_ == type) { 173 state_ = state; 174 quit_.Run(); 175 } 176 } 177 178 // BrowserMessageFilter: 179 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 180 if (message.type() == InputHostMsg_HandleInputEvent_ACK::ID) { 181 InputHostMsg_HandleInputEvent_ACK::Param params; 182 InputHostMsg_HandleInputEvent_ACK::Read(&message, ¶ms); 183 blink::WebInputEvent::Type type = params.a.type; 184 InputEventAckState ack = params.a.state; 185 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 186 base::Bind(&InputEventMessageFilterWaitsForAcks::ReceivedEventAck, 187 this, type, ack)); 188 } 189 return false; 190 } 191 192 base::Closure quit_; 193 blink::WebInputEvent::Type type_; 194 InputEventAckState state_; 195 196 DISALLOW_COPY_AND_ASSIGN(InputEventMessageFilterWaitsForAcks); 197}; 198 199class WebContentsViewAuraTest : public ContentBrowserTest { 200 public: 201 WebContentsViewAuraTest() 202 : screenshot_manager_(NULL) { 203 } 204 205 // Executes the javascript synchronously and makes sure the returned value is 206 // freed properly. 207 void ExecuteSyncJSFunction(RenderFrameHost* rfh, const std::string& jscript) { 208 scoped_ptr<base::Value> value = 209 content::ExecuteScriptAndGetValue(rfh, jscript); 210 } 211 212 // Starts the test server and navigates to the given url. Sets a large enough 213 // size to the root window. Returns after the navigation to the url is 214 // complete. 215 void StartTestWithPage(const std::string& url) { 216 ASSERT_TRUE(test_server()->Start()); 217 GURL test_url(test_server()->GetURL(url)); 218 NavigateToURL(shell(), test_url); 219 220 WebContentsImpl* web_contents = 221 static_cast<WebContentsImpl*>(shell()->web_contents()); 222 NavigationControllerImpl* controller = &web_contents->GetController(); 223 224 screenshot_manager_ = new ScreenshotTracker(controller); 225 controller->SetScreenshotManager(screenshot_manager_); 226 } 227 228 virtual void SetUpCommandLine(CommandLine* cmd) OVERRIDE { 229 cmd->AppendSwitchASCII(switches::kTouchEvents, 230 switches::kTouchEventsEnabled); 231 } 232 233 void TestOverscrollNavigation(bool touch_handler) { 234 ASSERT_NO_FATAL_FAILURE( 235 StartTestWithPage("files/overscroll_navigation.html")); 236 WebContentsImpl* web_contents = 237 static_cast<WebContentsImpl*>(shell()->web_contents()); 238 NavigationController& controller = web_contents->GetController(); 239 RenderFrameHost* main_frame = web_contents->GetMainFrame(); 240 241 EXPECT_FALSE(controller.CanGoBack()); 242 EXPECT_FALSE(controller.CanGoForward()); 243 int index = -1; 244 scoped_ptr<base::Value> value = 245 content::ExecuteScriptAndGetValue(main_frame, "get_current()"); 246 ASSERT_TRUE(value->GetAsInteger(&index)); 247 EXPECT_EQ(0, index); 248 249 if (touch_handler) 250 ExecuteSyncJSFunction(main_frame, "install_touch_handler()"); 251 252 ExecuteSyncJSFunction(main_frame, "navigate_next()"); 253 ExecuteSyncJSFunction(main_frame, "navigate_next()"); 254 value = content::ExecuteScriptAndGetValue(main_frame, "get_current()"); 255 ASSERT_TRUE(value->GetAsInteger(&index)); 256 EXPECT_EQ(2, index); 257 EXPECT_TRUE(controller.CanGoBack()); 258 EXPECT_FALSE(controller.CanGoForward()); 259 260 aura::Window* content = web_contents->GetContentNativeView(); 261 gfx::Rect bounds = content->GetBoundsInRootWindow(); 262 ui::test::EventGenerator generator(content->GetRootWindow(), content); 263 const int kScrollDurationMs = 20; 264 const int kScrollSteps = 10; 265 266 { 267 // Do a swipe-right now. That should navigate backwards. 268 base::string16 expected_title = base::ASCIIToUTF16("Title: #1"); 269 content::TitleWatcher title_watcher(web_contents, expected_title); 270 generator.GestureScrollSequence( 271 gfx::Point(bounds.x() + 2, bounds.y() + 10), 272 gfx::Point(bounds.right() - 10, bounds.y() + 10), 273 base::TimeDelta::FromMilliseconds(kScrollDurationMs), 274 kScrollSteps); 275 base::string16 actual_title = title_watcher.WaitAndGetTitle(); 276 EXPECT_EQ(expected_title, actual_title); 277 value = content::ExecuteScriptAndGetValue(main_frame, "get_current()"); 278 ASSERT_TRUE(value->GetAsInteger(&index)); 279 EXPECT_EQ(1, index); 280 EXPECT_TRUE(controller.CanGoBack()); 281 EXPECT_TRUE(controller.CanGoForward()); 282 } 283 284 { 285 // Do a fling-right now. That should navigate backwards. 286 base::string16 expected_title = base::ASCIIToUTF16("Title:"); 287 content::TitleWatcher title_watcher(web_contents, expected_title); 288 generator.GestureScrollSequence( 289 gfx::Point(bounds.x() + 2, bounds.y() + 10), 290 gfx::Point(bounds.right() - 10, bounds.y() + 10), 291 base::TimeDelta::FromMilliseconds(kScrollDurationMs), 292 kScrollSteps); 293 base::string16 actual_title = title_watcher.WaitAndGetTitle(); 294 EXPECT_EQ(expected_title, actual_title); 295 value = content::ExecuteScriptAndGetValue(main_frame, "get_current()"); 296 ASSERT_TRUE(value->GetAsInteger(&index)); 297 EXPECT_EQ(0, index); 298 EXPECT_FALSE(controller.CanGoBack()); 299 EXPECT_TRUE(controller.CanGoForward()); 300 } 301 302 { 303 // Do a swipe-left now. That should navigate forward. 304 base::string16 expected_title = base::ASCIIToUTF16("Title: #1"); 305 content::TitleWatcher title_watcher(web_contents, expected_title); 306 generator.GestureScrollSequence( 307 gfx::Point(bounds.right() - 10, bounds.y() + 10), 308 gfx::Point(bounds.x() + 2, bounds.y() + 10), 309 base::TimeDelta::FromMilliseconds(kScrollDurationMs), 310 kScrollSteps); 311 base::string16 actual_title = title_watcher.WaitAndGetTitle(); 312 EXPECT_EQ(expected_title, actual_title); 313 value = content::ExecuteScriptAndGetValue(main_frame, "get_current()"); 314 ASSERT_TRUE(value->GetAsInteger(&index)); 315 EXPECT_EQ(1, index); 316 EXPECT_TRUE(controller.CanGoBack()); 317 EXPECT_TRUE(controller.CanGoForward()); 318 } 319 } 320 321 int GetCurrentIndex() { 322 WebContentsImpl* web_contents = 323 static_cast<WebContentsImpl*>(shell()->web_contents()); 324 RenderFrameHost* main_frame = web_contents->GetMainFrame(); 325 int index = -1; 326 scoped_ptr<base::Value> value; 327 value = content::ExecuteScriptAndGetValue(main_frame, "get_current()"); 328 if (!value->GetAsInteger(&index)) 329 index = -1; 330 return index; 331 } 332 333 int ExecuteScriptAndExtractInt(const std::string& script) { 334 int value = 0; 335 EXPECT_TRUE(content::ExecuteScriptAndExtractInt( 336 shell()->web_contents(), 337 "domAutomationController.send(" + script + ")", 338 &value)); 339 return value; 340 } 341 342 RenderViewHost* GetRenderViewHost() const { 343 RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost(); 344 CHECK(rvh); 345 return rvh; 346 } 347 348 RenderWidgetHostImpl* GetRenderWidgetHost() const { 349 RenderWidgetHostImpl* const rwh = 350 RenderWidgetHostImpl::From(shell() 351 ->web_contents() 352 ->GetRenderWidgetHostView() 353 ->GetRenderWidgetHost()); 354 CHECK(rwh); 355 return rwh; 356 } 357 358 RenderWidgetHostViewBase* GetRenderWidgetHostView() const { 359 return static_cast<RenderWidgetHostViewBase*>( 360 GetRenderViewHost()->GetView()); 361 } 362 363 InputEventMessageFilterWaitsForAcks* filter() { 364 return filter_.get(); 365 } 366 367 void WaitAFrame() { 368 uint32 frame = GetRenderWidgetHostView()->RendererFrameNumber(); 369 while (!GetRenderWidgetHost()->ScheduleComposite()) 370 GiveItSomeTime(); 371 while (GetRenderWidgetHostView()->RendererFrameNumber() == frame) 372 GiveItSomeTime(); 373 } 374 375 protected: 376 ScreenshotTracker* screenshot_manager() { return screenshot_manager_; } 377 void set_min_screenshot_interval(int interval_ms) { 378 screenshot_manager_->SetScreenshotInterval(interval_ms); 379 } 380 381 void AddInputEventMessageFilter() { 382 filter_ = new InputEventMessageFilterWaitsForAcks(); 383 GetRenderWidgetHost()->GetProcess()->AddFilter(filter_); 384 } 385 386 private: 387 ScreenshotTracker* screenshot_manager_; 388 scoped_refptr<InputEventMessageFilterWaitsForAcks> filter_; 389 390 DISALLOW_COPY_AND_ASSIGN(WebContentsViewAuraTest); 391}; 392 393// Flaky on Windows: http://crbug.com/305722 394#if defined(OS_WIN) 395#define MAYBE_OverscrollNavigation DISABLED_OverscrollNavigation 396#else 397#define MAYBE_OverscrollNavigation OverscrollNavigation 398#endif 399 400IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollNavigation) { 401 TestOverscrollNavigation(false); 402} 403 404// Flaky on Windows (might be related to the above test): 405// http://crbug.com/305722 406#if defined(OS_WIN) 407#define MAYBE_OverscrollNavigationWithTouchHandler \ 408 DISABLED_OverscrollNavigationWithTouchHandler 409#else 410#define MAYBE_OverscrollNavigationWithTouchHandler \ 411 OverscrollNavigationWithTouchHandler 412#endif 413IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, 414 MAYBE_OverscrollNavigationWithTouchHandler) { 415 TestOverscrollNavigation(true); 416} 417 418// Disabled because the test always fails the first time it runs on the Win Aura 419// bots, and usually but not always passes second-try (See crbug.com/179532). 420#if defined(OS_WIN) 421#define MAYBE_QuickOverscrollDirectionChange \ 422 DISABLED_QuickOverscrollDirectionChange 423#else 424#define MAYBE_QuickOverscrollDirectionChange QuickOverscrollDirectionChange 425#endif 426IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, 427 MAYBE_QuickOverscrollDirectionChange) { 428 ASSERT_NO_FATAL_FAILURE( 429 StartTestWithPage("files/overscroll_navigation.html")); 430 WebContentsImpl* web_contents = 431 static_cast<WebContentsImpl*>(shell()->web_contents()); 432 RenderFrameHost* main_frame = web_contents->GetMainFrame(); 433 434 // This test triggers a large number of animations. Speed them up to ensure 435 // the test completes within its time limit. 436 ui::ScopedAnimationDurationScaleMode fast_duration_mode( 437 ui::ScopedAnimationDurationScaleMode::FAST_DURATION); 438 439 // Make sure the page has both back/forward history. 440 ExecuteSyncJSFunction(main_frame, "navigate_next()"); 441 EXPECT_EQ(1, GetCurrentIndex()); 442 ExecuteSyncJSFunction(main_frame, "navigate_next()"); 443 EXPECT_EQ(2, GetCurrentIndex()); 444 web_contents->GetController().GoBack(); 445 EXPECT_EQ(1, GetCurrentIndex()); 446 447 aura::Window* content = web_contents->GetContentNativeView(); 448 ui::EventProcessor* dispatcher = content->GetHost()->event_processor(); 449 gfx::Rect bounds = content->GetBoundsInRootWindow(); 450 451 base::TimeDelta timestamp = ui::EventTimeForNow(); 452 ui::TouchEvent press(ui::ET_TOUCH_PRESSED, 453 gfx::Point(bounds.x() + bounds.width() / 2, bounds.y() + 5), 454 0, timestamp); 455 ui::EventDispatchDetails details = dispatcher->OnEventFromSource(&press); 456 ASSERT_FALSE(details.dispatcher_destroyed); 457 EXPECT_EQ(1, GetCurrentIndex()); 458 459 timestamp += base::TimeDelta::FromMilliseconds(10); 460 ui::TouchEvent move1(ui::ET_TOUCH_MOVED, 461 gfx::Point(bounds.right() - 10, bounds.y() + 5), 462 0, timestamp); 463 details = dispatcher->OnEventFromSource(&move1); 464 ASSERT_FALSE(details.dispatcher_destroyed); 465 EXPECT_EQ(1, GetCurrentIndex()); 466 467 // Swipe back from the right edge, back to the left edge, back to the right 468 // edge. 469 470 for (int x = bounds.right() - 10; x >= bounds.x() + 10; x-= 10) { 471 timestamp += base::TimeDelta::FromMilliseconds(10); 472 ui::TouchEvent inc(ui::ET_TOUCH_MOVED, 473 gfx::Point(x, bounds.y() + 5), 474 0, timestamp); 475 details = dispatcher->OnEventFromSource(&inc); 476 ASSERT_FALSE(details.dispatcher_destroyed); 477 EXPECT_EQ(1, GetCurrentIndex()); 478 } 479 480 for (int x = bounds.x() + 10; x <= bounds.width() - 10; x+= 10) { 481 timestamp += base::TimeDelta::FromMilliseconds(10); 482 ui::TouchEvent inc(ui::ET_TOUCH_MOVED, 483 gfx::Point(x, bounds.y() + 5), 484 0, timestamp); 485 details = dispatcher->OnEventFromSource(&inc); 486 ASSERT_FALSE(details.dispatcher_destroyed); 487 EXPECT_EQ(1, GetCurrentIndex()); 488 } 489 490 for (int x = bounds.width() - 10; x >= bounds.x() + 10; x-= 10) { 491 timestamp += base::TimeDelta::FromMilliseconds(10); 492 ui::TouchEvent inc(ui::ET_TOUCH_MOVED, 493 gfx::Point(x, bounds.y() + 5), 494 0, timestamp); 495 details = dispatcher->OnEventFromSource(&inc); 496 ASSERT_FALSE(details.dispatcher_destroyed); 497 EXPECT_EQ(1, GetCurrentIndex()); 498 } 499 500 // Do not end the overscroll sequence. 501} 502 503// Tests that the page has has a screenshot when navigation happens: 504// - from within the page (from a JS function) 505// - interactively, when user does an overscroll gesture 506// - interactively, when user navigates in history without the overscroll 507// gesture. 508// Flaky on Windows (http://crbug.com/357311). Might be related to 509// OverscrollNavigation test. 510// Flaky on Ozone (http://crbug.com/399676). 511// Flaky on ChromeOS (http://crbug.com/405945). 512#if defined(OS_WIN) || defined(USE_OZONE) || defined(OS_CHROMEOS) 513#define MAYBE_OverscrollScreenshot DISABLED_OverscrollScreenshot 514#else 515#define MAYBE_OverscrollScreenshot OverscrollScreenshot 516#endif 517IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollScreenshot) { 518 // Disable the test for WinXP. See http://crbug/294116. 519#if defined(OS_WIN) 520 if (base::win::GetVersion() < base::win::VERSION_VISTA) { 521 LOG(WARNING) << "Test disabled due to unknown bug on WinXP."; 522 return; 523 } 524#endif 525 526 ASSERT_NO_FATAL_FAILURE( 527 StartTestWithPage("files/overscroll_navigation.html")); 528 WebContentsImpl* web_contents = 529 static_cast<WebContentsImpl*>(shell()->web_contents()); 530 RenderFrameHost* main_frame = web_contents->GetMainFrame(); 531 532 set_min_screenshot_interval(0); 533 534 // Do a few navigations initiated by the page. 535 // Screenshots should never be captured since these are all in-page 536 // navigations. 537 ExecuteSyncJSFunction(main_frame, "navigate_next()"); 538 EXPECT_EQ(1, GetCurrentIndex()); 539 ExecuteSyncJSFunction(main_frame, "navigate_next()"); 540 EXPECT_EQ(2, GetCurrentIndex()); 541 screenshot_manager()->WaitUntilScreenshotIsReady(); 542 543 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry( 544 web_contents->GetController().GetEntryAtIndex(2)); 545 EXPECT_FALSE(entry->screenshot().get()); 546 547 entry = NavigationEntryImpl::FromNavigationEntry( 548 web_contents->GetController().GetEntryAtIndex(1)); 549 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry)); 550 551 entry = NavigationEntryImpl::FromNavigationEntry( 552 web_contents->GetController().GetEntryAtIndex(0)); 553 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry)); 554 555 ExecuteSyncJSFunction(main_frame, "navigate_next()"); 556 screenshot_manager()->WaitUntilScreenshotIsReady(); 557 558 entry = NavigationEntryImpl::FromNavigationEntry( 559 web_contents->GetController().GetEntryAtIndex(2)); 560 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry)); 561 562 entry = NavigationEntryImpl::FromNavigationEntry( 563 web_contents->GetController().GetEntryAtIndex(3)); 564 EXPECT_FALSE(entry->screenshot().get()); 565 { 566 // Now, swipe right to navigate backwards. This should navigate away from 567 // index 3 to index 2. 568 base::string16 expected_title = base::ASCIIToUTF16("Title: #2"); 569 content::TitleWatcher title_watcher(web_contents, expected_title); 570 aura::Window* content = web_contents->GetContentNativeView(); 571 gfx::Rect bounds = content->GetBoundsInRootWindow(); 572 ui::test::EventGenerator generator(content->GetRootWindow(), content); 573 generator.GestureScrollSequence( 574 gfx::Point(bounds.x() + 2, bounds.y() + 10), 575 gfx::Point(bounds.right() - 10, bounds.y() + 10), 576 base::TimeDelta::FromMilliseconds(20), 577 1); 578 base::string16 actual_title = title_watcher.WaitAndGetTitle(); 579 EXPECT_EQ(expected_title, actual_title); 580 EXPECT_EQ(2, GetCurrentIndex()); 581 screenshot_manager()->WaitUntilScreenshotIsReady(); 582 entry = NavigationEntryImpl::FromNavigationEntry( 583 web_contents->GetController().GetEntryAtIndex(3)); 584 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry)); 585 } 586 587 // Navigate a couple more times. 588 ExecuteSyncJSFunction(main_frame, "navigate_next()"); 589 EXPECT_EQ(3, GetCurrentIndex()); 590 ExecuteSyncJSFunction(main_frame, "navigate_next()"); 591 EXPECT_EQ(4, GetCurrentIndex()); 592 screenshot_manager()->WaitUntilScreenshotIsReady(); 593 entry = NavigationEntryImpl::FromNavigationEntry( 594 web_contents->GetController().GetEntryAtIndex(4)); 595 EXPECT_FALSE(entry->screenshot().get()); 596 597 { 598 // Navigate back in history. 599 base::string16 expected_title = base::ASCIIToUTF16("Title: #3"); 600 content::TitleWatcher title_watcher(web_contents, expected_title); 601 web_contents->GetController().GoBack(); 602 base::string16 actual_title = title_watcher.WaitAndGetTitle(); 603 EXPECT_EQ(expected_title, actual_title); 604 EXPECT_EQ(3, GetCurrentIndex()); 605 screenshot_manager()->WaitUntilScreenshotIsReady(); 606 entry = NavigationEntryImpl::FromNavigationEntry( 607 web_contents->GetController().GetEntryAtIndex(4)); 608 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry)); 609 } 610} 611 612// Crashes under ThreadSanitizer, http://crbug.com/356758. 613#if defined(THREAD_SANITIZER) 614#define MAYBE_ScreenshotForSwappedOutRenderViews \ 615 DISABLED_ScreenshotForSwappedOutRenderViews 616#else 617#define MAYBE_ScreenshotForSwappedOutRenderViews \ 618 ScreenshotForSwappedOutRenderViews 619#endif 620// Tests that screenshot is taken correctly when navigation causes a 621// RenderViewHost to be swapped out. 622IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, 623 MAYBE_ScreenshotForSwappedOutRenderViews) { 624 ASSERT_NO_FATAL_FAILURE( 625 StartTestWithPage("files/overscroll_navigation.html")); 626 // Create a new server with a different site. 627 net::SpawnedTestServer https_server( 628 net::SpawnedTestServer::TYPE_HTTPS, 629 net::SpawnedTestServer::kLocalhost, 630 base::FilePath(FILE_PATH_LITERAL("content/test/data"))); 631 ASSERT_TRUE(https_server.Start()); 632 633 WebContentsImpl* web_contents = 634 static_cast<WebContentsImpl*>(shell()->web_contents()); 635 set_min_screenshot_interval(0); 636 637 struct { 638 GURL url; 639 int transition; 640 } navigations[] = { 641 { https_server.GetURL("files/title1.html"), 642 PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR }, 643 { test_server()->GetURL("files/title2.html"), 644 PAGE_TRANSITION_AUTO_BOOKMARK }, 645 { https_server.GetURL("files/title3.html"), 646 PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR }, 647 { GURL(), 0 } 648 }; 649 650 screenshot_manager()->Reset(); 651 for (int i = 0; !navigations[i].url.is_empty(); ++i) { 652 // Navigate via the user initiating a navigation from the UI. 653 NavigationController::LoadURLParams params(navigations[i].url); 654 params.transition_type = PageTransitionFromInt(navigations[i].transition); 655 656 RenderViewHost* old_host = web_contents->GetRenderViewHost(); 657 web_contents->GetController().LoadURLWithParams(params); 658 WaitForLoadStop(web_contents); 659 screenshot_manager()->WaitUntilScreenshotIsReady(); 660 661 EXPECT_NE(old_host, web_contents->GetRenderViewHost()) 662 << navigations[i].url.spec(); 663 EXPECT_EQ(old_host, screenshot_manager()->screenshot_taken_for()); 664 665 NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry( 666 web_contents->GetController().GetEntryAtOffset(-1)); 667 EXPECT_TRUE(screenshot_manager()->ScreenshotSetForEntry(entry)); 668 669 entry = NavigationEntryImpl::FromNavigationEntry( 670 web_contents->GetController().GetLastCommittedEntry()); 671 EXPECT_FALSE(screenshot_manager()->ScreenshotSetForEntry(entry)); 672 EXPECT_FALSE(entry->screenshot().get()); 673 screenshot_manager()->Reset(); 674 } 675 676 // Increase the minimum interval between taking screenshots. 677 set_min_screenshot_interval(60000); 678 679 // Navigate again. This should not take any screenshot because of the 680 // increased screenshot interval. 681 NavigationController::LoadURLParams params(navigations[0].url); 682 params.transition_type = PageTransitionFromInt(navigations[0].transition); 683 web_contents->GetController().LoadURLWithParams(params); 684 WaitForLoadStop(web_contents); 685 screenshot_manager()->WaitUntilScreenshotIsReady(); 686 687 EXPECT_EQ(NULL, screenshot_manager()->screenshot_taken_for()); 688} 689 690// Tests that navigations resulting from reloads, history.replaceState, 691// and history.pushState do not capture screenshots. 692IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, ReplaceStateReloadPushState) { 693 ASSERT_NO_FATAL_FAILURE( 694 StartTestWithPage("files/overscroll_navigation.html")); 695 WebContentsImpl* web_contents = 696 static_cast<WebContentsImpl*>(shell()->web_contents()); 697 RenderFrameHost* main_frame = web_contents->GetMainFrame(); 698 699 set_min_screenshot_interval(0); 700 screenshot_manager()->Reset(); 701 ExecuteSyncJSFunction(main_frame, "use_replace_state()"); 702 screenshot_manager()->WaitUntilScreenshotIsReady(); 703 // history.replaceState shouldn't capture a screenshot 704 EXPECT_FALSE(screenshot_manager()->screenshot_taken_for()); 705 screenshot_manager()->Reset(); 706 web_contents->GetController().Reload(true); 707 WaitForLoadStop(web_contents); 708 // reloading the page shouldn't capture a screenshot 709 // TODO (mfomitchev): currently broken. Uncomment when 710 // FrameHostMsg_DidCommitProvisionalLoad_Params.was_within_same_page 711 // is populated properly when reloading the page. 712 //EXPECT_FALSE(screenshot_manager()->screenshot_taken_for()); 713 screenshot_manager()->Reset(); 714 ExecuteSyncJSFunction(main_frame, "use_push_state()"); 715 screenshot_manager()->WaitUntilScreenshotIsReady(); 716 // pushing a state shouldn't capture a screenshot 717 // TODO (mfomitchev): currently broken. Uncomment when 718 // FrameHostMsg_DidCommitProvisionalLoad_Params.was_within_same_page 719 // is populated properly when pushState is used. 720 //EXPECT_FALSE(screenshot_manager()->screenshot_taken_for()); 721} 722 723// TODO(sadrul): This test is disabled because it reparents in a way the 724// FocusController does not support. This code would crash in 725// a production build. It only passed prior to this revision 726// because testing used the old FocusManager which did some 727// different (osbolete) processing. TODO(sadrul) to figure out 728// how this test should work that mimics production code a bit 729// better. 730IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, 731 DISABLED_ContentWindowReparent) { 732 ASSERT_NO_FATAL_FAILURE( 733 StartTestWithPage("files/overscroll_navigation.html")); 734 735 scoped_ptr<aura::Window> window(new aura::Window(NULL)); 736 window->Init(aura::WINDOW_LAYER_NOT_DRAWN); 737 738 WebContentsImpl* web_contents = 739 static_cast<WebContentsImpl*>(shell()->web_contents()); 740 ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()"); 741 EXPECT_EQ(1, GetCurrentIndex()); 742 743 aura::Window* content = web_contents->GetContentNativeView(); 744 gfx::Rect bounds = content->GetBoundsInRootWindow(); 745 ui::test::EventGenerator generator(content->GetRootWindow(), content); 746 generator.GestureScrollSequence( 747 gfx::Point(bounds.x() + 2, bounds.y() + 10), 748 gfx::Point(bounds.right() - 10, bounds.y() + 10), 749 base::TimeDelta::FromMilliseconds(20), 750 1); 751 752 window->AddChild(shell()->web_contents()->GetContentNativeView()); 753} 754 755IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, ContentWindowClose) { 756 ASSERT_NO_FATAL_FAILURE( 757 StartTestWithPage("files/overscroll_navigation.html")); 758 759 WebContentsImpl* web_contents = 760 static_cast<WebContentsImpl*>(shell()->web_contents()); 761 ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()"); 762 EXPECT_EQ(1, GetCurrentIndex()); 763 764 aura::Window* content = web_contents->GetContentNativeView(); 765 gfx::Rect bounds = content->GetBoundsInRootWindow(); 766 ui::test::EventGenerator generator(content->GetRootWindow(), content); 767 generator.GestureScrollSequence( 768 gfx::Point(bounds.x() + 2, bounds.y() + 10), 769 gfx::Point(bounds.right() - 10, bounds.y() + 10), 770 base::TimeDelta::FromMilliseconds(20), 771 1); 772 773 delete web_contents->GetContentNativeView(); 774} 775 776 777#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) 778// This appears to be flaky in the same was as the other overscroll 779// tests. Enabling for non-Windows platforms. 780// See http://crbug.com/369871. 781// For linux, see http://crbug.com/381294 782#define MAYBE_RepeatedQuickOverscrollGestures DISABLED_RepeatedQuickOverscrollGestures 783#else 784#define MAYBE_RepeatedQuickOverscrollGestures RepeatedQuickOverscrollGestures 785#endif 786 787IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, 788 MAYBE_RepeatedQuickOverscrollGestures) { 789 ASSERT_NO_FATAL_FAILURE( 790 StartTestWithPage("files/overscroll_navigation.html")); 791 792 WebContentsImpl* web_contents = 793 static_cast<WebContentsImpl*>(shell()->web_contents()); 794 NavigationController& controller = web_contents->GetController(); 795 RenderFrameHost* main_frame = web_contents->GetMainFrame(); 796 ExecuteSyncJSFunction(main_frame, "install_touch_handler()"); 797 798 // Navigate twice, then navigate back in history once. 799 ExecuteSyncJSFunction(main_frame, "navigate_next()"); 800 ExecuteSyncJSFunction(main_frame, "navigate_next()"); 801 EXPECT_EQ(2, GetCurrentIndex()); 802 EXPECT_TRUE(controller.CanGoBack()); 803 EXPECT_FALSE(controller.CanGoForward()); 804 805 web_contents->GetController().GoBack(); 806 WaitForLoadStop(web_contents); 807 EXPECT_EQ(1, GetCurrentIndex()); 808 EXPECT_EQ(base::ASCIIToUTF16("Title: #1"), web_contents->GetTitle()); 809 EXPECT_TRUE(controller.CanGoBack()); 810 EXPECT_TRUE(controller.CanGoForward()); 811 812 aura::Window* content = web_contents->GetContentNativeView(); 813 gfx::Rect bounds = content->GetBoundsInRootWindow(); 814 ui::test::EventGenerator generator(content->GetRootWindow(), content); 815 816 // Do a swipe left to start a forward navigation. Then quickly do a swipe 817 // right. 818 base::string16 expected_title = base::ASCIIToUTF16("Title: #2"); 819 content::TitleWatcher title_watcher(web_contents, expected_title); 820 NavigationWatcher nav_watcher(web_contents); 821 822 generator.GestureScrollSequence( 823 gfx::Point(bounds.right() - 10, bounds.y() + 10), 824 gfx::Point(bounds.x() + 2, bounds.y() + 10), 825 base::TimeDelta::FromMilliseconds(2000), 826 10); 827 nav_watcher.WaitUntilNavigationStarts(); 828 829 generator.GestureScrollSequence( 830 gfx::Point(bounds.x() + 2, bounds.y() + 10), 831 gfx::Point(bounds.right() - 10, bounds.y() + 10), 832 base::TimeDelta::FromMilliseconds(2000), 833 10); 834 base::string16 actual_title = title_watcher.WaitAndGetTitle(); 835 EXPECT_EQ(expected_title, actual_title); 836 837 EXPECT_EQ(2, GetCurrentIndex()); 838 EXPECT_TRUE(controller.CanGoBack()); 839 EXPECT_FALSE(controller.CanGoForward()); 840} 841 842// Verify that hiding a parent of the renderer will hide the content too. 843IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, HideContentOnParenHide) { 844 ASSERT_NO_FATAL_FAILURE(StartTestWithPage("files/title1.html")); 845 WebContentsImpl* web_contents = 846 static_cast<WebContentsImpl*>(shell()->web_contents()); 847 aura::Window* content = web_contents->GetNativeView()->parent(); 848 EXPECT_TRUE(web_contents->should_normally_be_visible()); 849 content->Hide(); 850 EXPECT_FALSE(web_contents->should_normally_be_visible()); 851 content->Show(); 852 EXPECT_TRUE(web_contents->should_normally_be_visible()); 853} 854 855// Ensure that SnapToPhysicalPixelBoundary() is called on WebContentsView parent 856// change. This is a regression test for http://crbug.com/388908. 857IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, WebContentsViewReparent) { 858 ASSERT_NO_FATAL_FAILURE( 859 StartTestWithPage("files/overscroll_navigation.html")); 860 861 scoped_ptr<aura::Window> window(new aura::Window(NULL)); 862 window->Init(aura::WINDOW_LAYER_NOT_DRAWN); 863 864 RenderWidgetHostViewAura* rwhva = 865 static_cast<RenderWidgetHostViewAura*>( 866 shell()->web_contents()->GetRenderWidgetHostView()); 867 rwhva->ResetHasSnappedToBoundary(); 868 EXPECT_FALSE(rwhva->has_snapped_to_boundary()); 869 window->AddChild(shell()->web_contents()->GetNativeView()); 870 EXPECT_TRUE(rwhva->has_snapped_to_boundary()); 871} 872 873// Flaky on some platforms, likely for the same reason as other flaky overscroll 874// tests. http://crbug.com/305722 875#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) 876#define MAYBE_OverscrollNavigationTouchThrottling \ 877 DISABLED_OverscrollNavigationTouchThrottling 878#else 879#define MAYBE_OverscrollNavigationTouchThrottling \ 880 OverscrollNavigationTouchThrottling 881#endif 882 883// Tests that touch moves are not throttled when performing a scroll gesture on 884// a non-scrollable area, except during gesture-nav. 885IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, 886 MAYBE_OverscrollNavigationTouchThrottling) { 887 ASSERT_NO_FATAL_FAILURE( 888 StartTestWithPage("files/overscroll_navigation.html")); 889 890 AddInputEventMessageFilter(); 891 892 WebContentsImpl* web_contents = 893 static_cast<WebContentsImpl*>(shell()->web_contents()); 894 aura::Window* content = web_contents->GetContentNativeView(); 895 gfx::Rect bounds = content->GetBoundsInRootWindow(); 896 const int dx = 20; 897 898 ExecuteSyncJSFunction(web_contents->GetMainFrame(), 899 "install_touchmove_handler()"); 900 901 WaitAFrame(); 902 903 for (int navigated = 0; navigated <= 1; ++navigated) { 904 if (navigated) { 905 ExecuteSyncJSFunction(web_contents->GetMainFrame(), "navigate_next()"); 906 ExecuteSyncJSFunction(web_contents->GetMainFrame(), 907 "reset_touchmove_count()"); 908 } 909 // Send touch press. 910 SyntheticWebTouchEvent touch; 911 touch.PressPoint(bounds.x() + 2, bounds.y() + 10); 912 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, 913 ui::LatencyInfo()); 914 filter()->WaitForAck(blink::WebInputEvent::TouchStart); 915 WaitAFrame(); 916 917 // Assert on the ack, because we'll end up waiting for acks that will never 918 // come if this is not true. 919 ASSERT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state()); 920 921 // Send first touch move, and then a scroll begin. 922 touch.MovePoint(0, bounds.x() + 20 + 1 * dx, bounds.y() + 100); 923 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, 924 ui::LatencyInfo()); 925 filter()->WaitForAck(blink::WebInputEvent::TouchMove); 926 ASSERT_EQ(INPUT_EVENT_ACK_STATE_NOT_CONSUMED, filter()->last_ack_state()); 927 928 blink::WebGestureEvent scroll_begin = 929 SyntheticWebGestureEventBuilder::BuildScrollBegin(1, 1); 930 GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo( 931 scroll_begin, ui::LatencyInfo()); 932 // Scroll begin ignores ack disposition, so don't wait for the ack. 933 WaitAFrame(); 934 935 // First touchmove already sent, start at 2. 936 for (int i = 2; i <= 10; ++i) { 937 // Send a touch move, followed by a scroll update 938 touch.MovePoint(0, bounds.x() + 20 + i * dx, bounds.y() + 100); 939 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo( 940 touch, ui::LatencyInfo()); 941 WaitAFrame(); 942 943 blink::WebGestureEvent scroll_update = 944 SyntheticWebGestureEventBuilder::BuildScrollUpdate(dx, 5, 0); 945 946 GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo( 947 scroll_update, ui::LatencyInfo()); 948 949 WaitAFrame(); 950 } 951 952 touch.ReleasePoint(0); 953 GetRenderWidgetHost()->ForwardTouchEventWithLatencyInfo(touch, 954 ui::LatencyInfo()); 955 WaitAFrame(); 956 957 blink::WebGestureEvent scroll_end; 958 scroll_end.type = blink::WebInputEvent::GestureScrollEnd; 959 GetRenderWidgetHost()->ForwardGestureEventWithLatencyInfo( 960 scroll_end, ui::LatencyInfo()); 961 WaitAFrame(); 962 963 if (!navigated) 964 EXPECT_EQ(10, ExecuteScriptAndExtractInt("touchmoveCount")); 965 else 966 EXPECT_GT(10, ExecuteScriptAndExtractInt("touchmoveCount")); 967 } 968} 969 970} // namespace content 971