blob: 49fdbff7dee47e726962418819eaf9b4083b0a32 [file] [log] [blame]
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "WebCompositorInputHandlerImpl.h"
#include "WebCompositorInitializer.h"
#include "WebCompositorInputHandlerClient.h"
#include "WebInputEvent.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <public/WebCompositor.h>
#include <public/WebFloatPoint.h>
#include <public/WebInputHandler.h>
#include <public/WebInputHandlerClient.h>
#include <public/WebPoint.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassOwnPtr.h>
using namespace WebKit;
namespace {
class MockWebInputHandlerClient : public WebInputHandlerClient {
WTF_MAKE_NONCOPYABLE(MockWebInputHandlerClient);
public:
MockWebInputHandlerClient()
{
}
virtual ~MockWebInputHandlerClient() { }
MOCK_METHOD0(pinchGestureBegin, void());
MOCK_METHOD2(pinchGestureUpdate, void(float magnifyDelta, WebPoint anchor));
MOCK_METHOD0(pinchGestureEnd, void());
MOCK_METHOD0(scheduleAnimation, void());
MOCK_METHOD2(scrollBegin, ScrollStatus(WebPoint, WebInputHandlerClient::ScrollInputType));
MOCK_METHOD2(scrollBy, void(WebPoint, WebSize));
MOCK_METHOD0(scrollEnd, void());
private:
virtual void startPageScaleAnimation(WebSize targetPosition,
bool anchorPoint,
float pageScale,
double startTimeMs,
double durationMs) OVERRIDE { }
};
class MockWebCompositorInputHandlerClient : public WebCompositorInputHandlerClient {
WTF_MAKE_NONCOPYABLE(MockWebCompositorInputHandlerClient);
public:
MockWebCompositorInputHandlerClient()
: WebCompositorInputHandlerClient()
{
}
virtual ~MockWebCompositorInputHandlerClient() { }
MOCK_METHOD0(willShutdown, void());
MOCK_METHOD0(didHandleInputEvent, void());
MOCK_METHOD1(didNotHandleInputEvent, void(bool sendToWidget));
MOCK_METHOD1(transferActiveWheelFlingAnimation, void(const WebActiveWheelFlingParameters&));
};
class WebCompositorInputHandlerImplTest : public testing::Test {
public:
WebCompositorInputHandlerImplTest()
: m_initializer(0)
, m_expectedDisposition(DidHandle)
{
m_inputHandler = adoptPtr(new WebCompositorInputHandlerImpl);
m_inputHandler->bindToClient(&m_mockInputHandlerClient);
m_inputHandler->setClient(&m_mockClient);
}
~WebCompositorInputHandlerImplTest()
{
m_inputHandler->setClient(0);
m_inputHandler.clear();
}
// This is defined as a macro because when an expectation is not satisfied the only output you get
// out of gmock is the line number that set the expectation.
#define VERIFY_AND_RESET_MOCKS() do \
{ \
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient); \
testing::Mock::VerifyAndClearExpectations(&m_mockClient); \
switch (m_expectedDisposition) { \
case DidHandle: \
/* If we expect to handle events, we shouldn't get any didNotHandleInputEvent() calls with any parameter. */ \
EXPECT_CALL(m_mockClient, didNotHandleInputEvent(::testing::_)).Times(0); \
EXPECT_CALL(m_mockClient, didHandleInputEvent()); \
break; \
case DidNotHandle: \
/* If we aren't expecting to handle events, we shouldn't call didHandleInputEvent(). */ \
EXPECT_CALL(m_mockClient, didHandleInputEvent()).Times(0); \
EXPECT_CALL(m_mockClient, didNotHandleInputEvent(false)).Times(0); \
EXPECT_CALL(m_mockClient, didNotHandleInputEvent(true)); \
break; \
case DropEvent: \
/* If we're expecting to drop, we shouldn't get any didHandle..() or didNotHandleInputEvent(true) calls. */ \
EXPECT_CALL(m_mockClient, didHandleInputEvent()).Times(0); \
EXPECT_CALL(m_mockClient, didNotHandleInputEvent(true)).Times(0); \
EXPECT_CALL(m_mockClient, didNotHandleInputEvent(false)); \
break; \
} \
} while (0)
protected:
testing::StrictMock<MockWebInputHandlerClient> m_mockInputHandlerClient;
OwnPtr<WebCompositorInputHandlerImpl> m_inputHandler;
testing::StrictMock<MockWebCompositorInputHandlerClient> m_mockClient;
WebGestureEvent gesture;
WebKitTests::WebCompositorInitializer m_initializer;
enum ExpectedDisposition { DidHandle, DidNotHandle, DropEvent };
ExpectedDisposition m_expectedDisposition;
};
TEST_F(WebCompositorInputHandlerImplTest, gestureScrollStarted)
{
// We shouldn't send any events to the widget for this gesture.
m_expectedDisposition = DidHandle;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusStarted));
gesture.type = WebInputEvent::GestureScrollBegin;
m_inputHandler->handleInputEvent(gesture);
VERIFY_AND_RESET_MOCKS();
gesture.type = WebInputEvent::GestureScrollUpdate;
gesture.data.scrollUpdate.deltaY = -40; // -Y means scroll down - i.e. in the +Y direction.
EXPECT_CALL(m_mockInputHandlerClient, scrollBy(testing::_, testing::Field(&WebSize::height, testing::Gt(0))));
m_inputHandler->handleInputEvent(gesture);
VERIFY_AND_RESET_MOCKS();
gesture.type = WebInputEvent::GestureScrollEnd;
gesture.data.scrollUpdate.deltaY = 0;
EXPECT_CALL(m_mockInputHandlerClient, scrollEnd());
m_inputHandler->handleInputEvent(gesture);
}
TEST_F(WebCompositorInputHandlerImplTest, gestureScrollOnMainThread)
{
// We should send all events to the widget for this gesture.
m_expectedDisposition = DidNotHandle;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(::testing::_, ::testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusOnMainThread));
gesture.type = WebInputEvent::GestureScrollBegin;
m_inputHandler->handleInputEvent(gesture);
VERIFY_AND_RESET_MOCKS();
gesture.type = WebInputEvent::GestureScrollUpdate;
gesture.data.scrollUpdate.deltaY = 40;
m_inputHandler->handleInputEvent(gesture);
VERIFY_AND_RESET_MOCKS();
gesture.type = WebInputEvent::GestureScrollEnd;
gesture.data.scrollUpdate.deltaY = 0;
m_inputHandler->handleInputEvent(gesture);
}
TEST_F(WebCompositorInputHandlerImplTest, gestureScrollIgnored)
{
// We shouldn't handle the GestureScrollBegin.
// Instead, we should get one didNotHandleInputEvent(false) call per handleInputEvent(),
// indicating that we could determine that there's nothing that could scroll or otherwise
// react to this gesture sequence and thus we should drop the whole gesture sequence on the floor.
m_expectedDisposition = DropEvent;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusIgnored));
gesture.type = WebInputEvent::GestureScrollBegin;
m_inputHandler->handleInputEvent(gesture);
}
TEST_F(WebCompositorInputHandlerImplTest, gesturePinch)
{
// We shouldn't send any events to the widget for this gesture.
m_expectedDisposition = DidHandle;
VERIFY_AND_RESET_MOCKS();
gesture.type = WebInputEvent::GesturePinchBegin;
EXPECT_CALL(m_mockInputHandlerClient, pinchGestureBegin());
m_inputHandler->handleInputEvent(gesture);
VERIFY_AND_RESET_MOCKS();
gesture.type = WebInputEvent::GesturePinchUpdate;
gesture.data.pinchUpdate.scale = 1.5;
gesture.x = 7;
gesture.y = 13;
EXPECT_CALL(m_mockInputHandlerClient, pinchGestureUpdate(1.5, WebPoint(7, 13)));
m_inputHandler->handleInputEvent(gesture);
VERIFY_AND_RESET_MOCKS();
gesture.type = WebInputEvent::GesturePinchUpdate;
gesture.data.pinchUpdate.scale = 0.5;
gesture.x = 9;
gesture.y = 6;
EXPECT_CALL(m_mockInputHandlerClient, pinchGestureUpdate(.5, WebPoint(9, 6)));
m_inputHandler->handleInputEvent(gesture);
VERIFY_AND_RESET_MOCKS();
gesture.type = WebInputEvent::GesturePinchEnd;
EXPECT_CALL(m_mockInputHandlerClient, pinchGestureEnd());
m_inputHandler->handleInputEvent(gesture);
}
TEST_F(WebCompositorInputHandlerImplTest, gestureFlingStarted)
{
// We shouldn't send any events to the widget for this gesture.
m_expectedDisposition = DidHandle;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusStarted));
EXPECT_CALL(m_mockInputHandlerClient, scrollEnd());
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
gesture.type = WebInputEvent::GestureFlingStart;
gesture.data.flingStart.velocityX = 10;
m_inputHandler->handleInputEvent(gesture);
VERIFY_AND_RESET_MOCKS();
// Verify that a GestureFlingCancel during an animation cancels it.
gesture.type = WebInputEvent::GestureFlingCancel;
m_inputHandler->handleInputEvent(gesture);
}
TEST_F(WebCompositorInputHandlerImplTest, gestureFlingFailed)
{
// We should send all events to the widget for this gesture.
m_expectedDisposition = DidNotHandle;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusOnMainThread));
gesture.type = WebInputEvent::GestureFlingStart;
m_inputHandler->handleInputEvent(gesture);
VERIFY_AND_RESET_MOCKS();
// Even if we didn't start a fling ourselves, we still need to send the cancel event to the widget.
gesture.type = WebInputEvent::GestureFlingCancel;
m_inputHandler->handleInputEvent(gesture);
}
TEST_F(WebCompositorInputHandlerImplTest, gestureFlingIgnored)
{
m_expectedDisposition = DidNotHandle;
VERIFY_AND_RESET_MOCKS();
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusIgnored));
gesture.type = WebInputEvent::GestureFlingStart;
m_inputHandler->handleInputEvent(gesture);
VERIFY_AND_RESET_MOCKS();
// Even if we didn't start a fling ourselves, we still need to send the cancel event to the widget.
gesture.type = WebInputEvent::GestureFlingCancel;
m_inputHandler->handleInputEvent(gesture);
}
TEST_F(WebCompositorInputHandlerImplTest, gestureFlingAnimates)
{
// We shouldn't send any events to the widget for this gesture.
m_expectedDisposition = DidHandle;
VERIFY_AND_RESET_MOCKS();
// On the fling start, we should schedule an animation but not actually start
// scrolling.
gesture.type = WebInputEvent::GestureFlingStart;
WebFloatPoint flingDelta = WebFloatPoint(1000, 0);
WebPoint flingPoint = WebPoint(7, 13);
WebPoint flingGlobalPoint = WebPoint(17, 23);
int modifiers = 7;
gesture.data.flingStart.velocityX = flingDelta.x;
gesture.data.flingStart.velocityY = flingDelta.y;
gesture.x = flingPoint.x;
gesture.y = flingPoint.y;
gesture.globalX = flingGlobalPoint.x;
gesture.globalY = flingGlobalPoint.y;
gesture.modifiers = modifiers;
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusStarted));
EXPECT_CALL(m_mockInputHandlerClient, scrollEnd());
m_inputHandler->handleInputEvent(gesture);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
// The first animate call should let us pick up an animation start time, but we
// shouldn't actually move anywhere just yet. The first frame after the fling start
// will typically include the last scroll from the gesture that lead to the scroll
// (either wheel or gesture scroll), so there should be no visible hitch.
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_)).Times(0);
m_inputHandler->animate(10);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
// The second call should start scrolling in the -X direction.
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusStarted));
EXPECT_CALL(m_mockInputHandlerClient, scrollBy(testing::_, testing::Field(&WebSize::width, testing::Lt(0))));
EXPECT_CALL(m_mockInputHandlerClient, scrollEnd());
m_inputHandler->animate(10.1);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
// Let's say on the third call we hit a non-scrollable region. We should abort the fling and not scroll.
// We also should pass the current fling parameters out to the client so the rest of the fling can be
// transferred to the main thread.
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusOnMainThread));
EXPECT_CALL(m_mockInputHandlerClient, scrollBy(testing::_, testing::_)).Times(0);
EXPECT_CALL(m_mockInputHandlerClient, scrollEnd()).Times(0);
// Expected wheel fling animation parameters:
// *) flingDelta and flingPoint should match the original GestureFlingStart event
// *) startTime should be 10 to match the time parameter of the first animate() call after the GestureFlingStart
// *) cumulativeScroll depends on the curve, but since we've animated in the -X direction the X value should be < 0
EXPECT_CALL(m_mockClient, transferActiveWheelFlingAnimation(testing::AllOf(
testing::Field(&WebActiveWheelFlingParameters::delta, testing::Eq(flingDelta)),
testing::Field(&WebActiveWheelFlingParameters::point, testing::Eq(flingPoint)),
testing::Field(&WebActiveWheelFlingParameters::globalPoint, testing::Eq(flingGlobalPoint)),
testing::Field(&WebActiveWheelFlingParameters::modifiers, testing::Eq(modifiers)),
testing::Field(&WebActiveWheelFlingParameters::startTime, testing::Eq(10)),
testing::Field(&WebActiveWheelFlingParameters::cumulativeScroll,
testing::Field(&WebSize::width, testing::Gt(0))))));
m_inputHandler->animate(10.2);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
testing::Mock::VerifyAndClearExpectations(&m_mockClient);
// Since we've aborted the fling, the next animation should be a no-op and should not result in another
// frame being requested.
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation()).Times(0);
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_)).Times(0);
m_inputHandler->animate(10.3);
// Since we've transferred the fling to the main thread, we need to pass the next GestureFlingCancel to the main
// thread as well.
EXPECT_CALL(m_mockClient, didNotHandleInputEvent(true));
gesture.type = WebInputEvent::GestureFlingCancel;
m_inputHandler->handleInputEvent(gesture);
}
TEST_F(WebCompositorInputHandlerImplTest, gestureFlingTransferResets)
{
// We shouldn't send any events to the widget for this gesture.
m_expectedDisposition = DidHandle;
VERIFY_AND_RESET_MOCKS();
// Start a gesture fling in the -X direction with zero Y movement.
gesture.type = WebInputEvent::GestureFlingStart;
WebFloatPoint flingDelta = WebFloatPoint(1000, 0);
WebPoint flingPoint = WebPoint(7, 13);
WebPoint flingGlobalPoint = WebPoint(17, 23);
int modifiers = 1;
gesture.data.flingStart.velocityX = flingDelta.x;
gesture.data.flingStart.velocityY = flingDelta.y;
gesture.x = flingPoint.x;
gesture.y = flingPoint.y;
gesture.globalX = flingGlobalPoint.x;
gesture.globalY = flingGlobalPoint.y;
gesture.modifiers = modifiers;
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusStarted));
EXPECT_CALL(m_mockInputHandlerClient, scrollEnd());
m_inputHandler->handleInputEvent(gesture);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
// Start the fling animation at time 10. This shouldn't actually scroll, just establish a start time.
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_)).Times(0);
m_inputHandler->animate(10);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
// The second call should start scrolling in the -X direction.
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusStarted));
EXPECT_CALL(m_mockInputHandlerClient, scrollBy(testing::_, testing::Field(&WebSize::width, testing::Lt(0))));
EXPECT_CALL(m_mockInputHandlerClient, scrollEnd());
m_inputHandler->animate(10.1);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
// Let's say on the third call we hit a non-scrollable region. We should abort the fling and not scroll.
// We also should pass the current fling parameters out to the client so the rest of the fling can be
// transferred to the main thread.
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusOnMainThread));
EXPECT_CALL(m_mockInputHandlerClient, scrollBy(testing::_, testing::_)).Times(0);
EXPECT_CALL(m_mockInputHandlerClient, scrollEnd()).Times(0);
// Expected wheel fling animation parameters:
// *) flingDelta and flingPoint should match the original GestureFlingStart event
// *) startTime should be 10 to match the time parameter of the first animate() call after the GestureFlingStart
// *) cumulativeScroll depends on the curve, but since we've animated in the -X direction the X value should be < 0
EXPECT_CALL(m_mockClient, transferActiveWheelFlingAnimation(testing::AllOf(
testing::Field(&WebActiveWheelFlingParameters::delta, testing::Eq(flingDelta)),
testing::Field(&WebActiveWheelFlingParameters::point, testing::Eq(flingPoint)),
testing::Field(&WebActiveWheelFlingParameters::globalPoint, testing::Eq(flingGlobalPoint)),
testing::Field(&WebActiveWheelFlingParameters::modifiers, testing::Eq(modifiers)),
testing::Field(&WebActiveWheelFlingParameters::startTime, testing::Eq(10)),
testing::Field(&WebActiveWheelFlingParameters::cumulativeScroll,
testing::Field(&WebSize::width, testing::Gt(0))))));
m_inputHandler->animate(10.2);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
testing::Mock::VerifyAndClearExpectations(&m_mockClient);
// Since we've aborted the fling, the next animation should be a no-op and should not result in another
// frame being requested.
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation()).Times(0);
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_)).Times(0);
m_inputHandler->animate(10.3);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
// Since we've transferred the fling to the main thread, we need to pass the next GestureFlingCancel to the main
// thread as well.
EXPECT_CALL(m_mockClient, didNotHandleInputEvent(true));
gesture.type = WebInputEvent::GestureFlingCancel;
m_inputHandler->handleInputEvent(gesture);
VERIFY_AND_RESET_MOCKS();
// Start a second gesture fling, this time in the +Y direction with no X.
gesture.type = WebInputEvent::GestureFlingStart;
flingDelta = WebFloatPoint(0, -1000);
flingPoint = WebPoint(95, 87);
flingGlobalPoint = WebPoint(32, 71);
modifiers = 2;
gesture.data.flingStart.velocityX = flingDelta.x;
gesture.data.flingStart.velocityY = flingDelta.y;
gesture.x = flingPoint.x;
gesture.y = flingPoint.y;
gesture.globalX = flingGlobalPoint.x;
gesture.globalY = flingGlobalPoint.y;
gesture.modifiers = modifiers;
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusStarted));
EXPECT_CALL(m_mockInputHandlerClient, scrollEnd());
m_inputHandler->handleInputEvent(gesture);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
// Start the second fling animation at time 30.
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_)).Times(0);
m_inputHandler->animate(30);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
// Tick the second fling once normally.
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusStarted));
EXPECT_CALL(m_mockInputHandlerClient, scrollBy(testing::_, testing::Field(&WebSize::height, testing::Gt(0))));
EXPECT_CALL(m_mockInputHandlerClient, scrollEnd());
m_inputHandler->animate(30.1);
testing::Mock::VerifyAndClearExpectations(&m_mockInputHandlerClient);
// Then abort the second fling.
EXPECT_CALL(m_mockInputHandlerClient, scheduleAnimation());
EXPECT_CALL(m_mockInputHandlerClient, scrollBegin(testing::_, testing::_))
.WillOnce(testing::Return(WebInputHandlerClient::ScrollStatusOnMainThread));
EXPECT_CALL(m_mockInputHandlerClient, scrollBy(testing::_, testing::_)).Times(0);
EXPECT_CALL(m_mockInputHandlerClient, scrollEnd()).Times(0);
// We should get parameters from the second fling, nothing from the first fling should "leak".
EXPECT_CALL(m_mockClient, transferActiveWheelFlingAnimation(testing::AllOf(
testing::Field(&WebActiveWheelFlingParameters::delta, testing::Eq(flingDelta)),
testing::Field(&WebActiveWheelFlingParameters::point, testing::Eq(flingPoint)),
testing::Field(&WebActiveWheelFlingParameters::globalPoint, testing::Eq(flingGlobalPoint)),
testing::Field(&WebActiveWheelFlingParameters::modifiers, testing::Eq(modifiers)),
testing::Field(&WebActiveWheelFlingParameters::startTime, testing::Eq(30)),
testing::Field(&WebActiveWheelFlingParameters::cumulativeScroll,
testing::Field(&WebSize::height, testing::Lt(0))))));
m_inputHandler->animate(30.2);
}
}