// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/web_contents/aura/overscroll_navigation_overlay.h" #include "content/browser/frame_host/navigation_entry_impl.h" #include "content/browser/web_contents/aura/image_window_delegate.h" #include "content/browser/web_contents/web_contents_view.h" #include "content/common/frame_messages.h" #include "content/common/view_messages.h" #include "content/public/test/mock_render_process_host.h" #include "content/test/test_render_frame_host.h" #include "content/test/test_render_view_host.h" #include "content/test/test_web_contents.h" #include "ui/aura/test/test_windows.h" #include "ui/aura/window.h" #include "ui/gfx/codec/png_codec.h" namespace content { class OverscrollNavigationOverlayTest : public RenderViewHostImplTestHarness { public: OverscrollNavigationOverlayTest() {} virtual ~OverscrollNavigationOverlayTest() {} gfx::Image CreateDummyScreenshot() { SkBitmap bitmap; bitmap.allocN32Pixels(1, 1); bitmap.eraseColor(SK_ColorWHITE); return gfx::Image::CreateFrom1xBitmap(bitmap); } void SetDummyScreenshotOnNavEntry(NavigationEntry* entry) { SkBitmap bitmap; bitmap.allocN32Pixels(1, 1); bitmap.eraseColor(SK_ColorWHITE); std::vector<unsigned char> png_data; gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &png_data); scoped_refptr<base::RefCountedBytes> png_bytes = base::RefCountedBytes::TakeVector(&png_data); NavigationEntryImpl* entry_impl = NavigationEntryImpl::FromNavigationEntry(entry); entry_impl->SetScreenshotPNGData(png_bytes); } void ReceivePaintUpdate() { FrameHostMsg_DidFirstVisuallyNonEmptyPaint msg( main_test_rfh()->GetRoutingID()); RenderViewHostTester::TestOnMessageReceived(test_rvh(), msg); } void PerformBackNavigationViaSliderCallbacks() { // Sets slide direction to SLIDE_BACK, sets screenshot from NavEntry at // offset -1 on layer_delegate_. delete GetOverlay()->CreateBackLayer(); // Performs BACK navigation, sets image from layer_delegate_ on // image_delegate_. GetOverlay()->OnWindowSlideCompleting(); GetOverlay()->OnWindowSlideCompleted(scoped_ptr<ui::Layer>()); } protected: // RenderViewHostImplTestHarness: virtual void SetUp() override { RenderViewHostImplTestHarness::SetUp(); const GURL first("https://www.google.com"); contents()->NavigateAndCommit(first); EXPECT_TRUE(controller().GetVisibleEntry()); EXPECT_FALSE(controller().CanGoBack()); const GURL second("http://www.chromium.org"); contents()->NavigateAndCommit(second); EXPECT_TRUE(controller().CanGoBack()); // Receive a paint update. This is necessary to make sure the size is set // correctly in RenderWidgetHostImpl. ViewHostMsg_UpdateRect_Params params; memset(¶ms, 0, sizeof(params)); params.view_size = gfx::Size(10, 10); ViewHostMsg_UpdateRect rect(test_rvh()->GetRoutingID(), params); RenderViewHostTester::TestOnMessageReceived(test_rvh(), rect); // Reset pending flags for size/paint. test_rvh()->ResetSizeAndRepaintPendingFlags(); // Create the overlay, and set the contents of the overlay window. overlay_.reset(new OverscrollNavigationOverlay(contents())); ImageWindowDelegate* image_delegate = new ImageWindowDelegate(); scoped_ptr<aura::Window> overlay_window( aura::test::CreateTestWindowWithDelegate( image_delegate, 0, gfx::Rect(root_window()->bounds().size()), root_window())); overlay_->SetOverlayWindow(overlay_window.Pass(), image_delegate); overlay_->StartObserving(); EXPECT_TRUE(overlay_->web_contents()); EXPECT_FALSE(overlay_->loading_complete_); EXPECT_FALSE(overlay_->received_paint_update_); } virtual void TearDown() override { overlay_.reset(); RenderViewHostImplTestHarness::TearDown(); } OverscrollNavigationOverlay* GetOverlay() { return overlay_.get(); } private: scoped_ptr<OverscrollNavigationOverlay> overlay_; DISALLOW_COPY_AND_ASSIGN(OverscrollNavigationOverlayTest); }; TEST_F(OverscrollNavigationOverlayTest, FirstVisuallyNonEmptyPaint_NoImage) { ReceivePaintUpdate(); EXPECT_TRUE(GetOverlay()->received_paint_update_); EXPECT_FALSE(GetOverlay()->loading_complete_); // The paint update will hide the overlay. EXPECT_FALSE(GetOverlay()->web_contents()); } TEST_F(OverscrollNavigationOverlayTest, FirstVisuallyNonEmptyPaint_WithImage) { GetOverlay()->image_delegate_->SetImage(CreateDummyScreenshot()); ReceivePaintUpdate(); EXPECT_TRUE(GetOverlay()->received_paint_update_); EXPECT_FALSE(GetOverlay()->loading_complete_); // The paint update will hide the overlay. EXPECT_FALSE(GetOverlay()->web_contents()); } TEST_F(OverscrollNavigationOverlayTest, LoadUpdateWithoutNonEmptyPaint) { GetOverlay()->image_delegate_->SetImage(CreateDummyScreenshot()); process()->sink().ClearMessages(); contents()->TestSetIsLoading(false); EXPECT_TRUE(GetOverlay()->loading_complete_); EXPECT_FALSE(GetOverlay()->received_paint_update_); // The page load should hide the overlay. EXPECT_FALSE(GetOverlay()->web_contents()); } TEST_F(OverscrollNavigationOverlayTest, MultiNavigation_PaintUpdate) { GetOverlay()->image_delegate_->SetImage(CreateDummyScreenshot()); SetDummyScreenshotOnNavEntry(controller().GetEntryAtOffset(-1)); PerformBackNavigationViaSliderCallbacks(); // Screenshot was set on NavEntry at offset -1. EXPECT_TRUE(GetOverlay()->image_delegate_->has_image()); EXPECT_FALSE(GetOverlay()->received_paint_update_); ReceivePaintUpdate(); // Paint updates until the navigation is committed typically represent updates // for the previous page, so they shouldn't affect the flag. EXPECT_FALSE(GetOverlay()->received_paint_update_); contents()->CommitPendingNavigation(); ReceivePaintUpdate(); // Navigation was committed and the paint update was received - the flag // should now be updated. EXPECT_TRUE(GetOverlay()->received_paint_update_); EXPECT_FALSE(GetOverlay()->web_contents()); } TEST_F(OverscrollNavigationOverlayTest, MultiNavigation_LoadingUpdate) { GetOverlay()->image_delegate_->SetImage(CreateDummyScreenshot()); PerformBackNavigationViaSliderCallbacks(); // No screenshot was set on NavEntry at offset -1. EXPECT_FALSE(GetOverlay()->image_delegate_->has_image()); // Navigation was started, so the loading status flag should be reset. EXPECT_FALSE(GetOverlay()->loading_complete_); // DidStopLoading for any navigation should always reset the load flag and // dismiss the overlay even if the pending navigation wasn't committed - // this is a "safety net" in case we mis-identify the destination webpage // (which can happen if a new navigation is performed while while a GestureNav // navigation is in progress). contents()->TestSetIsLoading(true); contents()->TestSetIsLoading(false); EXPECT_TRUE(GetOverlay()->loading_complete_); EXPECT_FALSE(GetOverlay()->web_contents()); } } // namespace content