1 // Copyright (c) 2013 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 "base/basictypes.h" 6 #include "base/memory/scoped_ptr.h" 7 #include "base/time/time.h" 8 #include "content/browser/renderer_host/render_widget_host_delegate.h" 9 #include "content/browser/renderer_host/smooth_scroll_gesture_controller.h" 10 #include "content/browser/renderer_host/test_render_view_host.h" 11 #include "content/common/view_messages.h" 12 #include "content/port/browser/render_widget_host_view_port.h" 13 #include "content/port/browser/smooth_scroll_gesture.h" 14 #include "content/public/test/mock_render_process_host.h" 15 #include "content/public/test/test_browser_context.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 #if defined(USE_AURA) 19 #include "ui/aura/env.h" 20 #include "ui/aura/test/test_screen.h" 21 #endif 22 23 using base::TimeDelta; 24 25 namespace content { 26 27 namespace { 28 29 class MockSmoothScrollGesture : public SmoothScrollGesture { 30 public: 31 MockSmoothScrollGesture() : 32 called_(0) { 33 } 34 35 // SmoothScrollGesture implementation: 36 virtual bool ForwardInputEvents(base::TimeTicks now, 37 RenderWidgetHost* host) OVERRIDE { 38 ++called_; 39 return true; 40 } 41 42 int called_; 43 44 protected: 45 virtual ~MockSmoothScrollGesture() { 46 } 47 }; 48 49 class MockRenderWidgetHostDelegate : public RenderWidgetHostDelegate { 50 public: 51 MockRenderWidgetHostDelegate() { 52 } 53 virtual ~MockRenderWidgetHostDelegate() {} 54 }; 55 56 class MockRenderWidgetHost : public RenderWidgetHostImpl { 57 public: 58 MockRenderWidgetHost( 59 RenderWidgetHostDelegate* delegate, 60 RenderProcessHost* process, 61 int routing_id) 62 : RenderWidgetHostImpl(delegate, process, routing_id) { 63 } 64 virtual ~MockRenderWidgetHost() {} 65 }; 66 67 class TestView : public TestRenderWidgetHostView { 68 public: 69 explicit TestView(RenderWidgetHostImpl* rwh) 70 : TestRenderWidgetHostView(rwh), 71 mock_gesture_(NULL) { 72 } 73 virtual ~TestView() {} 74 75 // TestRenderWidgetHostView implementation: 76 virtual SmoothScrollGesture* CreateSmoothScrollGesture( 77 bool scroll_down, int pixels_to_scroll, int mouse_event_x, 78 int mouse_event_y) OVERRIDE { 79 mock_gesture_ = new MockSmoothScrollGesture(); 80 return mock_gesture_; 81 } 82 83 virtual RenderWidgetHost* GetRenderWidgetHost() const OVERRIDE { 84 return rwh_; 85 } 86 87 MockSmoothScrollGesture* mock_gesture_; 88 }; 89 90 class SmoothScrollGestureControllerTest : public testing::Test { 91 public: 92 SmoothScrollGestureControllerTest() : process_(NULL) { 93 } 94 virtual ~SmoothScrollGestureControllerTest() {} 95 96 protected: 97 // testing::Test implementation: 98 virtual void SetUp() OVERRIDE { 99 browser_context_.reset(new TestBrowserContext()); 100 delegate_.reset(new MockRenderWidgetHostDelegate()); 101 process_ = new MockRenderProcessHost(browser_context_.get()); 102 #if defined(USE_AURA) 103 screen_.reset(aura::TestScreen::Create()); 104 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get()); 105 #endif 106 host_.reset( 107 new MockRenderWidgetHost(delegate_.get(), process_, MSG_ROUTING_NONE)); 108 view_.reset(new TestView(host_.get())); 109 host_->SetView(view_.get()); 110 host_->Init(); 111 } 112 113 virtual void TearDown() OVERRIDE { 114 view_.reset(); 115 host_.reset(); 116 delegate_.reset(); 117 process_ = NULL; 118 browser_context_.reset(); 119 120 #if defined(USE_AURA) 121 aura::Env::DeleteInstance(); 122 screen_.reset(); 123 #endif 124 125 // Process all pending tasks to avoid leaks. 126 base::MessageLoop::current()->RunUntilIdle(); 127 } 128 129 void PostQuitMessageAndRun() { 130 // Allow the message loop to process pending synthetic scrolls, then quit. 131 base::MessageLoop::current()->PostDelayedTask( 132 FROM_HERE, base::MessageLoop::QuitClosure(), 133 TimeDelta::FromMilliseconds( 134 controller_.GetSyntheticScrollMessageInterval().InMilliseconds() * 135 3)); 136 base::MessageLoop::current()->Run(); 137 } 138 139 base::MessageLoopForUI message_loop_; 140 141 scoped_ptr<TestBrowserContext> browser_context_; 142 MockRenderProcessHost* process_; // Deleted automatically by the widget. 143 scoped_ptr<MockRenderWidgetHostDelegate> delegate_; 144 scoped_ptr<MockRenderWidgetHost> host_; 145 scoped_ptr<TestView> view_; 146 #if defined(USE_AURA) 147 scoped_ptr<gfx::Screen> screen_; 148 #endif 149 150 SmoothScrollGestureController controller_; 151 }; 152 153 TEST_F(SmoothScrollGestureControllerTest, Tick) { 154 ViewHostMsg_BeginSmoothScroll_Params params; 155 params.scroll_down = true; 156 params.pixels_to_scroll = 10; 157 params.mouse_event_x = 20; 158 params.mouse_event_y = 30; 159 160 // Begin a smooth scroll, |mock_gesture_| won't be |called| until we post 161 // message. 162 controller_.BeginSmoothScroll(view_.get(), params); 163 EXPECT_TRUE(view_->mock_gesture_ != NULL); 164 EXPECT_EQ(0, view_->mock_gesture_->called_); 165 166 PostQuitMessageAndRun(); 167 const int current_ticks = view_->mock_gesture_->called_; 168 EXPECT_LT(0, current_ticks); 169 170 // Ensure it won't start another smooth scroll. 171 MockSmoothScrollGesture* original_gesture = view_->mock_gesture_; 172 controller_.BeginSmoothScroll(view_.get(), params); 173 PostQuitMessageAndRun(); 174 EXPECT_EQ(original_gesture, view_->mock_gesture_); 175 176 // Ensure the smooth scroll is ticked. 177 PostQuitMessageAndRun(); 178 EXPECT_LT(current_ticks, view_->mock_gesture_->called_); 179 } 180 181 } // namespace 182 183 } // namespace content 184