[chromium] Implement fling-by-wheel on compositor thread
[WebKit-https.git] / Source / WebKit / chromium / tests / WebCompositorInputHandlerImplTest.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #include "WebCompositorInputHandlerImpl.h"
29
30 #include "WebCompositor.h"
31 #include "WebCompositorInputHandlerClient.h"
32 #include "WebInputEvent.h"
33 #include "cc/CCActiveGestureAnimation.h"
34 #include "cc/CCInputHandler.h"
35 #include "cc/CCSingleThreadProxy.h"
36
37 #include <gmock/gmock.h>
38 #include <gtest/gtest.h>
39 #include <wtf/OwnPtr.h>
40
41 using WebKit::WebCompositorInputHandler;
42 using WebKit::WebCompositorInputHandlerImpl;
43
44 namespace {
45
46 class MockCCInputHandlerClient : public WebCore::CCInputHandlerClient {
47     WTF_MAKE_NONCOPYABLE(MockCCInputHandlerClient);
48 public:
49     MockCCInputHandlerClient()
50     {
51     }
52     virtual ~MockCCInputHandlerClient() { }
53
54
55     MOCK_METHOD0(pinchGestureBegin, void());
56     MOCK_METHOD2(pinchGestureUpdate, void(float magnifyDelta, const WebCore::IntPoint& anchor));
57     MOCK_METHOD0(pinchGestureEnd, void());
58
59     MOCK_METHOD0(scheduleAnimation, void());
60
61     MOCK_METHOD2(scrollBegin, ScrollStatus(const WebCore::IntPoint&, WebCore::CCInputHandlerClient::ScrollInputType));
62     MOCK_METHOD1(scrollBy, void(const WebCore::IntSize&));
63     MOCK_METHOD0(scrollEnd, void());
64
65 private:
66     virtual void startPageScaleAnimation(const WebCore::IntSize& targetPosition,
67                                          bool anchorPoint,
68                                          float pageScale,
69                                          double startTimeMs,
70                                          double durationMs) OVERRIDE { }
71
72     virtual WebCore::CCActiveGestureAnimation* activeGestureAnimation() OVERRIDE { return 0; }
73     virtual void setActiveGestureAnimation(PassOwnPtr<WebCore::CCActiveGestureAnimation>) OVERRIDE { }
74 };
75
76 class MockWebCompositorInputHandlerClient : public WebKit::WebCompositorInputHandlerClient {
77     WTF_MAKE_NONCOPYABLE(MockWebCompositorInputHandlerClient);
78 public:
79     MockWebCompositorInputHandlerClient()
80         : WebKit::WebCompositorInputHandlerClient()
81     {
82     }
83     virtual ~MockWebCompositorInputHandlerClient() { }
84
85     MOCK_METHOD0(willShutdown, void());
86     MOCK_METHOD0(didHandleInputEvent, void());
87     MOCK_METHOD1(didNotHandleInputEvent, void(bool sendToWidget));
88 };
89
90 TEST(WebCompositorInputHandlerImpl, fromIdentifier)
91 {
92     WebKit::WebCompositor::initialize(0);
93     WebCore::DebugScopedSetImplThread alwaysImplThread;
94
95     // Before creating any WebCompositorInputHandlers, lookups for any value should fail and not crash.
96     EXPECT_EQ(0, WebCompositorInputHandler::fromIdentifier(2));
97     EXPECT_EQ(0, WebCompositorInputHandler::fromIdentifier(0));
98     EXPECT_EQ(0, WebCompositorInputHandler::fromIdentifier(-1));
99
100     int compositorIdentifier = -1;
101     {
102         OwnPtr<WebCompositorInputHandlerImpl> inputHandler = WebCompositorInputHandlerImpl::create(0);
103         compositorIdentifier = inputHandler->identifier();
104         // The compositor we just created should be locatable.
105         EXPECT_EQ(inputHandler.get(), WebCompositorInputHandler::fromIdentifier(compositorIdentifier));
106
107         // But nothing else.
108         EXPECT_EQ(0, WebCompositorInputHandler::fromIdentifier(inputHandler->identifier() + 10));
109     }
110
111     // After the compositor is destroyed, its entry should be removed from the map.
112     EXPECT_EQ(0, WebCompositorInputHandler::fromIdentifier(compositorIdentifier));
113     WebKit::WebCompositor::shutdown();
114 }
115
116 class WebCompositorInputHandlerImplTest : public testing::Test {
117 public:
118     WebCompositorInputHandlerImplTest()
119         : m_expectedDisposition(DidHandle)
120     {
121         WebKit::WebCompositor::initialize(0);
122         m_inputHandler = WebCompositorInputHandlerImpl::create(&m_mockCCInputHandlerClient);
123         m_inputHandler->setClient(&m_mockClient);
124     }
125
126     ~WebCompositorInputHandlerImplTest()
127     {
128         m_inputHandler->setClient(0);
129         m_inputHandler.clear();
130         WebKit::WebCompositor::shutdown();
131     }
132
133     void verifyAndResetMocks()
134     {
135         testing::Mock::VerifyAndClearExpectations(&m_mockCCInputHandlerClient);
136         testing::Mock::VerifyAndClearExpectations(&m_mockClient);
137         switch (m_expectedDisposition) {
138         case DidHandle:
139             // If we expect to handle events, we shouldn't get any didNotHandleInputEvent() calls with any parameter.
140             EXPECT_CALL(m_mockClient, didNotHandleInputEvent(::testing::_)).Times(0);
141             EXPECT_CALL(m_mockClient, didHandleInputEvent());
142             break;
143         case DidNotHandle:
144             // If we aren't expecting to handle events, we shouldn't call didHandleInputEvent().
145             EXPECT_CALL(m_mockClient, didHandleInputEvent()).Times(0);
146             EXPECT_CALL(m_mockClient, didNotHandleInputEvent(false)).Times(0);
147             EXPECT_CALL(m_mockClient, didNotHandleInputEvent(true));
148             break;
149         case DropEvent:
150             // If we're expecting to drop, we shouldn't get any didHandle..() or didNotHandleInputEvent(true /* sendToWidget */) calls.
151             EXPECT_CALL(m_mockClient, didHandleInputEvent()).Times(0);
152             EXPECT_CALL(m_mockClient, didNotHandleInputEvent(true)).Times(0);
153             EXPECT_CALL(m_mockClient, didNotHandleInputEvent(false));
154             break;
155         }
156     }
157
158 protected:
159     MockCCInputHandlerClient m_mockCCInputHandlerClient;
160     OwnPtr<WebCompositorInputHandlerImpl> m_inputHandler;
161     MockWebCompositorInputHandlerClient m_mockClient;
162     WebKit::WebGestureEvent gesture;
163
164     enum ExpectedDisposition { DidHandle, DidNotHandle, DropEvent };
165     ExpectedDisposition m_expectedDisposition;
166
167 private:
168     WebCore::DebugScopedSetImplThread m_alwaysImplThread;
169 };
170
171
172 TEST_F(WebCompositorInputHandlerImplTest, gestureScrollStarted)
173 {
174     // We shouldn't send any events to the widget for this gesture.
175     m_expectedDisposition = DidHandle;
176     verifyAndResetMocks();
177
178     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
179         .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollStarted));
180
181     gesture.type = WebKit::WebInputEvent::GestureScrollBegin;
182     m_inputHandler->handleInputEvent(gesture);
183
184     verifyAndResetMocks();
185
186     gesture.type = WebKit::WebInputEvent::GestureScrollUpdate;
187     gesture.deltaY = -40; // -Y means scroll down - i.e. in the +Y direction.
188     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBy(testing::Property(&WebCore::IntSize::height, testing::Gt(0))));
189     m_inputHandler->handleInputEvent(gesture);
190
191     verifyAndResetMocks();
192
193     gesture.type = WebKit::WebInputEvent::GestureScrollEnd;
194     gesture.deltaY = 0;
195     EXPECT_CALL(m_mockCCInputHandlerClient, scrollEnd());
196     m_inputHandler->handleInputEvent(gesture);
197 }
198
199 TEST_F(WebCompositorInputHandlerImplTest, gestureScrollFailed)
200 {
201     // We should send all events to the widget for this gesture.
202     m_expectedDisposition = DidNotHandle;
203     verifyAndResetMocks();
204
205     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(::testing::_, ::testing::_))
206         .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollFailed));
207
208     gesture.type = WebKit::WebInputEvent::GestureScrollBegin;
209     m_inputHandler->handleInputEvent(gesture);
210
211     verifyAndResetMocks();
212
213     gesture.type = WebKit::WebInputEvent::GestureScrollUpdate;
214     gesture.deltaY = 40;
215     m_inputHandler->handleInputEvent(gesture);
216
217     verifyAndResetMocks();
218
219     gesture.type = WebKit::WebInputEvent::GestureScrollEnd;
220     gesture.deltaY = 0;
221     m_inputHandler->handleInputEvent(gesture);
222 }
223
224 TEST_F(WebCompositorInputHandlerImplTest, gestureScrollIgnored)
225 {
226     // We shouldn't handle the GestureScrollBegin.
227     // Instead, we should get one didNotHandleInputEvent(false) call per handleInputEvent(),
228     // indicating that we could determine that there's nothing that could scroll or otherwise
229     // react to this gesture sequence and thus we should drop the whole gesture sequence on the floor.
230     m_expectedDisposition = DropEvent;
231     verifyAndResetMocks();
232
233     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
234         .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollIgnored));
235
236     gesture.type = WebKit::WebInputEvent::GestureScrollBegin;
237     m_inputHandler->handleInputEvent(gesture);
238 }
239
240 TEST_F(WebCompositorInputHandlerImplTest, gesturePinch)
241 {
242     // We shouldn't send any events to the widget for this gesture.
243     m_expectedDisposition = DidHandle;
244     verifyAndResetMocks();
245
246     gesture.type = WebKit::WebInputEvent::GesturePinchBegin;
247     EXPECT_CALL(m_mockCCInputHandlerClient, pinchGestureBegin());
248     m_inputHandler->handleInputEvent(gesture);
249
250     verifyAndResetMocks();
251
252     gesture.type = WebKit::WebInputEvent::GesturePinchUpdate;
253     gesture.deltaX = 1.5;
254     gesture.x = 7;
255     gesture.y = 13;
256     EXPECT_CALL(m_mockCCInputHandlerClient, pinchGestureUpdate(1.5, WebCore::IntPoint(7, 13)));
257     m_inputHandler->handleInputEvent(gesture);
258
259     verifyAndResetMocks();
260
261     gesture.type = WebKit::WebInputEvent::GesturePinchUpdate;
262     gesture.deltaX = 0.5;
263     gesture.x = 9;
264     gesture.y = 6;
265     EXPECT_CALL(m_mockCCInputHandlerClient, pinchGestureUpdate(.5, WebCore::IntPoint(9, 6)));
266     m_inputHandler->handleInputEvent(gesture);
267
268     verifyAndResetMocks();
269
270     gesture.type = WebKit::WebInputEvent::GesturePinchEnd;
271     EXPECT_CALL(m_mockCCInputHandlerClient, pinchGestureEnd());
272     m_inputHandler->handleInputEvent(gesture);
273 }
274
275 TEST_F(WebCompositorInputHandlerImplTest, gestureFlingStarted)
276 {
277     // We shouldn't send any events to the widget for this gesture.
278     m_expectedDisposition = DidHandle;
279     verifyAndResetMocks();
280
281     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
282         .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollStarted));
283
284     gesture.type = WebKit::WebInputEvent::GestureFlingStart;
285     gesture.deltaX = 10;
286     EXPECT_CALL(m_mockCCInputHandlerClient, scheduleAnimation());
287     m_inputHandler->handleInputEvent(gesture);
288
289     verifyAndResetMocks();
290
291     // Verify that a GestureFlingCancel during an animation cancels it.
292     gesture.type = WebKit::WebInputEvent::GestureFlingCancel;
293     m_inputHandler->handleInputEvent(gesture);
294 }
295
296 TEST_F(WebCompositorInputHandlerImplTest, gestureFlingFailed)
297 {
298     // We should send all events to the widget for this gesture.
299     m_expectedDisposition = DidNotHandle;
300     verifyAndResetMocks();
301
302     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
303         .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollFailed));
304
305     gesture.type = WebKit::WebInputEvent::GestureFlingStart;
306     m_inputHandler->handleInputEvent(gesture);
307
308     verifyAndResetMocks();
309
310     // Even if we didn't start a fling ourselves, we still need to send the cancel event to the widget.
311     gesture.type = WebKit::WebInputEvent::GestureFlingCancel;
312     m_inputHandler->handleInputEvent(gesture);
313 }
314
315 TEST_F(WebCompositorInputHandlerImplTest, gestureFlingIgnored)
316 {
317     m_expectedDisposition = DidNotHandle;
318     verifyAndResetMocks();
319
320     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
321         .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollIgnored));
322
323     gesture.type = WebKit::WebInputEvent::GestureFlingStart;
324     m_inputHandler->handleInputEvent(gesture);
325
326     verifyAndResetMocks();
327
328     // Even if we didn't start a fling ourselves, we still need to send the cancel event to the widget.
329     gesture.type = WebKit::WebInputEvent::GestureFlingCancel;
330     m_inputHandler->handleInputEvent(gesture);
331 }
332
333 TEST_F(WebCompositorInputHandlerImplTest, gestureFlingAnimates)
334 {
335     // We shouldn't send any events to the widget for this gesture.
336     m_expectedDisposition = DidHandle;
337     verifyAndResetMocks();
338
339     // On the fling start, we should schedule an animation but not actually start
340     // scrolling.
341     gesture.type = WebKit::WebInputEvent::GestureFlingStart;
342     gesture.deltaX = -1000;
343     EXPECT_CALL(m_mockCCInputHandlerClient, scheduleAnimation());
344     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
345         .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollStarted));
346     m_inputHandler->handleInputEvent(gesture);
347
348     testing::Mock::VerifyAndClearExpectations(&m_mockCCInputHandlerClient);
349     // The first animate call should let us pick up an animation start time, but we
350     // shouldn't actually move anywhere just yet. The first frame after the fling start
351     // will typically include the last scroll from the gesture that lead to the scroll
352     // (either wheel or gesture scroll), so there should be no visible hitch.
353     EXPECT_CALL(m_mockCCInputHandlerClient, scheduleAnimation());
354     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_)).Times(0);
355     m_inputHandler->animate(10);
356
357     testing::Mock::VerifyAndClearExpectations(&m_mockCCInputHandlerClient);
358
359     // The second call should start scrolling in the +X direction.
360     EXPECT_CALL(m_mockCCInputHandlerClient, scheduleAnimation());
361     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
362         .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollStarted));
363     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBy(testing::Property(&WebCore::IntSize::width, testing::Gt(0))));
364     EXPECT_CALL(m_mockCCInputHandlerClient, scrollEnd());
365     m_inputHandler->animate(10.1);
366
367     testing::Mock::VerifyAndClearExpectations(&m_mockCCInputHandlerClient);
368
369     // Let's say on the third call we hit a non-scrollable region. We should abort the fling and not scroll.
370     // FIXME: We also need to do some work to transfer the rest of this fling to the main thread.
371     // Add tests for this once it's implemented.
372     EXPECT_CALL(m_mockCCInputHandlerClient, scheduleAnimation());
373     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_))
374         .WillOnce(testing::Return(WebCore::CCInputHandlerClient::ScrollFailed));
375     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBy(testing::_)).Times(0);
376     EXPECT_CALL(m_mockCCInputHandlerClient, scrollEnd()).Times(0);
377     m_inputHandler->animate(10.2);
378
379     testing::Mock::VerifyAndClearExpectations(&m_mockCCInputHandlerClient);
380
381     // Since we've aborted the fling, the next animation should be a no-op and should not result in another
382     // frame being requested.
383     EXPECT_CALL(m_mockCCInputHandlerClient, scheduleAnimation()).Times(0);
384     EXPECT_CALL(m_mockCCInputHandlerClient, scrollBegin(testing::_, testing::_)).Times(0);
385     m_inputHandler->animate(10.3);
386 }
387
388 }