Commit f61bab71 authored by commit-queue@webkit.org's avatar commit-queue@webkit.org
Browse files

Implement double tap detection in GestureRecognizerChromium

https://bugs.webkit.org/show_bug.cgi?id=67709

Patch by Varun Jain <varunjain@google.com> on 2011-09-08
Reviewed by Dimitri Glazkov.

*  Source/WebCore/page/EventHandler.cpp:
*  Source/WebCore/platform/PlatformGestureEvent.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@94797 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 574b7f45
2011-09-08 Varun Jain <varunjain@google.com>
Implement double tap detection in GestureRecognizerChromium
https://bugs.webkit.org/show_bug.cgi?id=67709
Reviewed by Dimitri Glazkov.
* Source/WebCore/page/EventHandler.cpp:
* Source/WebCore/platform/PlatformGestureEvent.h:
2011-09-08 Ulan Degenbaev <ulan@chromium.org>
 
[v8] Improve performance of typed array set() taking Array
......
......@@ -2221,6 +2221,8 @@ bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
handleMouseReleaseEvent(fakeMouseUp);
return true;
}
case PlatformGestureEvent::DoubleTapType:
break;
case PlatformGestureEvent::ScrollUpdateType: {
const float tickDivisor = (float)WheelEvent::tickMultiplier;
// FIXME: Replace this interim implementation once the above fixme has been addressed.
......
......@@ -40,6 +40,7 @@ public:
ScrollUpdateType,
TapType,
TapDownType,
DoubleTapType,
};
PlatformGestureEvent()
......
......@@ -62,6 +62,12 @@ GestureRecognizerChromium::GestureRecognizerChromium()
addEdgeFunction(Scroll, FirstFinger, Moved, false, &GestureRecognizerChromium::inScroll);
addEdgeFunction(Scroll, FirstFinger, Released, false, &GestureRecognizerChromium::scrollEnd);
addEdgeFunction(Scroll, FirstFinger, Cancelled, false, &GestureRecognizerChromium::scrollEnd);
addEdgeFunction(FirstClickReceived, FirstFinger, Pressed, false, &GestureRecognizerChromium::touchDown);
addEdgeFunction(PendingDoubleClick, FirstFinger, Cancelled, false, &GestureRecognizerChromium::noGesture);
addEdgeFunction(PendingDoubleClick, FirstFinger, Released, false, &GestureRecognizerChromium::doubleClick);
addEdgeFunction(PendingDoubleClick, FirstFinger, Moved, false, &GestureRecognizerChromium::maybeDoubleClick);
addEdgeFunction(PendingDoubleClick, FirstFinger, Stationary, false, &GestureRecognizerChromium::maybeDoubleClick);
}
void GestureRecognizerChromium::reset()
......@@ -86,6 +92,12 @@ bool GestureRecognizerChromium::isInClickTimeWindow()
return duration >= minimumTouchDownDurationInSecondsForClick && duration < maximumTouchDownDurationInSecondsForClick;
}
bool GestureRecognizerChromium::isInSecondClickTimeWindow()
{
double duration(m_lastTouchTime - m_lastClickTime);
return duration >= minimumTouchDownDurationInSecondsForClick && duration < maximumTouchDownDurationInSecondsForClick;
}
bool GestureRecognizerChromium::isInsideManhattanSquare(const PlatformTouchPoint& point)
{
int manhattanDistance = abs(point.pos().x() - m_firstTouchPosition.x()) + abs(point.pos().y() - m_firstTouchPosition.y());
......@@ -102,6 +114,11 @@ void GestureRecognizerChromium::appendClickGestureEvent(const PlatformTouchPoint
gestures->append(PlatformGestureEvent(PlatformGestureEvent::TapType, m_firstTouchPosition, m_firstTouchScreenPosition, m_lastTouchTime, 0.f, 0.f, m_shiftKey, m_ctrlKey, m_altKey, m_metaKey));
}
void GestureRecognizerChromium::appendDoubleClickGestureEvent(const PlatformTouchPoint& touchPoint, Gestures gestures)
{
gestures->append(PlatformGestureEvent(PlatformGestureEvent::DoubleTapType, m_firstTouchPosition, m_firstTouchScreenPosition, m_lastTouchTime, 0.f, 0.f, m_shiftKey, m_ctrlKey, m_altKey, m_metaKey));
}
PlatformGestureRecognizer::PassGestures GestureRecognizerChromium::processTouchEventForGestures(const PlatformTouchEvent& event, bool defaultPrevented)
{
m_ctrlKey = event.ctrlKey();
......@@ -142,6 +159,10 @@ void GestureRecognizerChromium::appendScrollGestureUpdate(const PlatformTouchPoi
void GestureRecognizerChromium::updateValues(const double touchTime, const PlatformTouchPoint& touchPoint)
{
if (state() == FirstClickReceived) {
m_firstTouchTime = touchTime;
m_lastClickTime = m_lastTouchTime;
}
m_lastTouchTime = touchTime;
if (state() == NoGesture) {
m_firstTouchTime = touchTime;
......@@ -164,8 +185,13 @@ unsigned int GestureRecognizerChromium::signature(State gestureState, unsigned i
bool GestureRecognizerChromium::touchDown(const PlatformTouchPoint& touchPoint, Gestures gestures)
{
setState(PendingSyntheticClick);
ASSERT(state() == NoGesture || state() == FirstClickReceived);
appendTapDownGestureEvent(touchPoint, gestures);
if (state() == FirstClickReceived && isInSecondClickTimeWindow() && isInsideManhattanSquare(touchPoint)) {
setState(PendingDoubleClick);
return false;
}
setState(PendingSyntheticClick);
return false;
}
......@@ -177,6 +203,24 @@ bool GestureRecognizerChromium::scrollEnd(const PlatformTouchPoint& point, Gestu
return false;
}
bool GestureRecognizerChromium::doubleClick(const PlatformTouchPoint& point, Gestures gestures)
{
if (isInClickTimeWindow() && isInsideManhattanSquare(point)) {
setState(NoGesture);
appendDoubleClickGestureEvent(point, gestures);
return true;
}
return noGesture(point, gestures);
}
bool GestureRecognizerChromium::maybeDoubleClick(const PlatformTouchPoint& point, Gestures gestures)
{
ASSERT(state() == GestureRecognizerChromium::PendingDoubleClick);
if (point.state() == PlatformTouchPoint::TouchMoved && !isInsideManhattanSquare(point))
return noGesture(point, gestures);
return false;
}
bool GestureRecognizerChromium::noGesture(const PlatformTouchPoint&, Gestures)
{
reset();
......@@ -186,7 +230,7 @@ bool GestureRecognizerChromium::noGesture(const PlatformTouchPoint&, Gestures)
bool GestureRecognizerChromium::click(const PlatformTouchPoint& point, Gestures gestures)
{
if (isInClickTimeWindow() && isInsideManhattanSquare(point)) {
setState(NoGesture);
setState(FirstClickReceived);
appendClickGestureEvent(point, gestures);
return true;
}
......
......@@ -48,7 +48,9 @@ public:
enum State {
NoGesture,
PendingSyntheticClick,
Scroll
Scroll,
FirstClickReceived,
PendingDoubleClick,
};
typedef Vector<PlatformGestureEvent>* Gestures;
......@@ -68,10 +70,12 @@ private:
void addEdgeFunction(State, unsigned finger, PlatformTouchPoint::State, bool touchHandledByJavaScript, GestureTransitionFunction);
void appendTapDownGestureEvent(const PlatformTouchPoint&, Gestures);
void appendClickGestureEvent(const PlatformTouchPoint&, Gestures);
void appendDoubleClickGestureEvent(const PlatformTouchPoint&, Gestures);
void appendScrollGestureBegin(const PlatformTouchPoint&, Gestures);
void appendScrollGestureEnd(const PlatformTouchPoint&, Gestures);
void appendScrollGestureUpdate(const PlatformTouchPoint&, Gestures);
bool isInClickTimeWindow();
bool isInSecondClickTimeWindow();
bool isInsideManhattanSquare(const PlatformTouchPoint&);
void setState(State value) { m_state = value; }
void updateValues(double touchTime, const PlatformTouchPoint&);
......@@ -83,12 +87,16 @@ private:
bool touchDown(const PlatformTouchPoint&, Gestures);
bool scrollEnd(const PlatformTouchPoint&, Gestures);
bool doubleClick(const PlatformTouchPoint&, Gestures);
bool maybeDoubleClick(const PlatformTouchPoint&, Gestures);
WTF::HashMap<int, GestureTransitionFunction> m_edgeFunctions;
IntPoint m_firstTouchPosition;
IntPoint m_firstTouchScreenPosition;
double m_firstTouchTime;
State m_state;
double m_lastTouchTime;
double m_lastClickTime;
bool m_ctrlKey;
bool m_altKey;
......
......@@ -306,6 +306,8 @@ bool PopupContainer::handleGestureEvent(const PlatformGestureEvent& gestureEvent
handleMouseReleaseEvent(fakeMouseUp);
return true;
}
case PlatformGestureEvent::DoubleTapType:
break;
case PlatformGestureEvent::ScrollUpdateType: {
PlatformWheelEvent syntheticWheelEvent(gestureEvent.position(), gestureEvent.globalPosition(), gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEvent.deltaX() / 120.0f, gestureEvent.deltaY() / 120.0f, ScrollByPixelWheelEvent, /* isAccepted */ false, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
handleWheelEvent(syntheticWheelEvent);
......
......@@ -36,7 +36,6 @@
using namespace WebCore;
class InspectableGestureRecognizerChromium : public WebCore::GestureRecognizerChromium {
public:
InspectableGestureRecognizerChromium()
......@@ -157,6 +156,25 @@ protected:
virtual void TearDown() { }
};
void SimulateAndTestFirstClick(InspectableGestureRecognizerChromium& gm)
{
ASSERT_EQ(GestureRecognizerChromium::NoGesture, gm.state());
BuildablePlatformTouchPoint press(10, 15, PlatformTouchPoint::TouchPressed);
BuildablePlatformTouchEvent pressEvent(WebCore::TouchStart, press);
OwnPtr<Vector<WebCore::PlatformGestureEvent> > gestureStart(gm.processTouchEventForGestures(pressEvent, false));
ASSERT_EQ((unsigned int)1, gestureStart->size());
ASSERT_EQ(PlatformGestureEvent::TapDownType, (*gestureStart)[0].type());
ASSERT_EQ(GestureRecognizerChromium::PendingSyntheticClick, gm.state());
BuildablePlatformTouchPoint release(10, 16, PlatformTouchPoint::TouchReleased);
BuildablePlatformTouchEvent releaseEvent(WebCore::TouchEnd, release);
gm.setFirstTouchTime(gm.firstTouchTime() - 0.01);
OwnPtr<Vector<WebCore::PlatformGestureEvent> > gestureEnd(gm.processTouchEventForGestures(releaseEvent, false));
ASSERT_EQ((unsigned int)1, gestureEnd->size());
ASSERT_EQ(PlatformGestureEvent::TapType, (*gestureEnd)[0].type());
}
typedef OwnPtr<Vector<WebCore::PlatformGestureEvent> > Gestures;
TEST_F(GestureRecognizerTest, hash)
......@@ -284,6 +302,63 @@ TEST_F(GestureRecognizerTest, updateValues)
ASSERT_EQ(0.0, gm.lastTouchTime() - gm.firstTouchTime());
}
TEST_F(GestureRecognizerTest, doubleTapGestureTest)
{
InspectableGestureRecognizerChromium gm;
SimulateAndTestFirstClick(gm);
ASSERT_EQ(GestureRecognizerChromium::FirstClickReceived, gm.state());
BuildablePlatformTouchPoint press(10, 15, PlatformTouchPoint::TouchPressed);
BuildablePlatformTouchEvent pressEvent(WebCore::TouchStart, press);
gm.setLastTouchTime(gm.lastTouchTime() - 0.01);
Gestures gestureStart(gm.processTouchEventForGestures(pressEvent, false));
ASSERT_EQ((unsigned int)1, gestureStart->size());
ASSERT_EQ(PlatformGestureEvent::TapDownType, (*gestureStart)[0].type());
ASSERT_EQ(GestureRecognizerChromium::PendingDoubleClick, gm.state());
BuildablePlatformTouchPoint move(10, 16, PlatformTouchPoint::TouchMoved);
BuildablePlatformTouchEvent moveEvent(WebCore::TouchMove, move);
Gestures gestureMove(gm.processTouchEventForGestures(moveEvent, false));
ASSERT_EQ((unsigned int)0, gestureMove->size());
ASSERT_EQ(GestureRecognizerChromium::PendingDoubleClick, gm.state());
BuildablePlatformTouchPoint release(10, 16, PlatformTouchPoint::TouchReleased);
BuildablePlatformTouchEvent releaseEvent(WebCore::TouchEnd, release);
gm.setFirstTouchTime(gm.firstTouchTime() - 0.01);
Gestures gestureEnd(gm.processTouchEventForGestures(releaseEvent, false));
ASSERT_EQ((unsigned int)1, gestureEnd->size());
ASSERT_EQ(PlatformGestureEvent::DoubleTapType, (*gestureEnd)[0].type());
ASSERT_EQ(GestureRecognizerChromium::NoGesture, gm.state());
}
TEST_F(GestureRecognizerTest, doubleTapGestureIncompleteTest)
{
InspectableGestureRecognizerChromium gm;
SimulateAndTestFirstClick(gm);
ASSERT_EQ(GestureRecognizerChromium::FirstClickReceived, gm.state());
BuildablePlatformTouchPoint press(10, 15, PlatformTouchPoint::TouchPressed);
BuildablePlatformTouchEvent pressEvent(WebCore::TouchStart, press);
gm.setLastTouchTime(gm.lastTouchTime() - 0.01);
Gestures gestureStart(gm.processTouchEventForGestures(pressEvent, false));
ASSERT_EQ((unsigned int)1, gestureStart->size());
ASSERT_EQ(PlatformGestureEvent::TapDownType, (*gestureStart)[0].type());
ASSERT_EQ(GestureRecognizerChromium::PendingDoubleClick, gm.state());
BuildablePlatformTouchPoint move(10, 50, PlatformTouchPoint::TouchMoved);
BuildablePlatformTouchEvent moveEvent(WebCore::TouchMove, move);
Gestures gestureMove(gm.processTouchEventForGestures(moveEvent, false));
ASSERT_EQ((unsigned int)0, gestureMove->size());
ASSERT_EQ(GestureRecognizerChromium::NoGesture, gm.state());
BuildablePlatformTouchPoint release(10, 50, PlatformTouchPoint::TouchReleased);
BuildablePlatformTouchEvent releaseEvent(WebCore::TouchEnd, release);
gm.setFirstTouchTime(gm.firstTouchTime() - 0.01);
Gestures gestureEnd(gm.processTouchEventForGestures(releaseEvent, false));
ASSERT_EQ((unsigned int)0, gestureEnd->size());
ASSERT_EQ(GestureRecognizerChromium::NoGesture, gm.state());
}
TEST_F(GestureRecognizerTest, tapDownWithoutTapGestureTest)
{
InspectableGestureRecognizerChromium gm;
......@@ -338,7 +413,7 @@ TEST_F(GestureRecognizerTest, tapDownWithTapGestureTest)
Gestures gestureEnd(gm.processTouchEventForGestures(releaseEvent, false));
ASSERT_EQ((unsigned int)1, gestureEnd->size());
ASSERT_EQ(PlatformGestureEvent::TapType, (*gestureEnd)[0].type());
ASSERT_EQ(GestureRecognizerChromium::NoGesture, gm.state());
ASSERT_EQ(GestureRecognizerChromium::FirstClickReceived, gm.state());
}
TEST_F(GestureRecognizerTest, gestureScrollEvents)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment