[Qt] Fade out tap highlighting when starting to pan
[WebKit-https.git] / Source / WebKit2 / UIProcess / qt / QtTapGestureRecognizer.cpp
1 /*
2  * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)
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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #include "config.h"
26 #include "QtTapGestureRecognizer.h"
27
28 #include "QtWebPageEventHandler.h"
29 #include <QLineF>
30 #include <QTouchEvent>
31
32 namespace WebKit {
33
34 QtTapGestureRecognizer::QtTapGestureRecognizer(QtWebPageEventHandler* eventHandler)
35     : QtGestureRecognizer(eventHandler)
36     , m_tapState(NoTap)
37 {
38 }
39
40 bool QtTapGestureRecognizer::recognize(const QTouchEvent* event, qint64 eventTimestampMillis)
41 {
42     if (event->touchPoints().size() != 1) {
43         reset();
44         return false;
45     }
46
47     switch (event->type()) {
48     case QEvent::TouchBegin:
49         ASSERT(m_tapState == NoTap);
50         ASSERT(!m_tapAndHoldTimer.isActive());
51
52         m_tapAndHoldTimer.start(tapAndHoldTime, this);
53
54         if (m_doubleTapTimer.isActive()) {
55             // Might be double tap.
56             ASSERT(m_touchBeginEventForTap);
57             m_doubleTapTimer.stop();
58             QPointF lastPosition = m_touchBeginEventForTap->touchPoints().first().screenPos();
59             QPointF newPosition = event->touchPoints().first().screenPos();
60             if (QLineF(lastPosition, newPosition).length() < maxDoubleTapDistance)
61                 m_tapState = DoubleTapCandidate;
62             else {
63                 // Received a new tap, that is unrelated to the previous one.
64                 tapTimeout();
65                 m_tapState = SingleTapStarted;
66             }
67         } else
68             m_tapState = SingleTapStarted;
69         m_touchBeginEventForTap = adoptPtr(new QTouchEvent(*event));
70
71         if (m_tapState == SingleTapStarted) {
72             const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first();
73             m_eventHandler->handlePotentialSingleTapEvent(touchPoint);
74         }
75         break;
76     case QEvent::TouchUpdate:
77         // If the touch point moves further than the threshold, we cancel the tap gesture.
78         if (m_tapState == SingleTapStarted) {
79             const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first();
80             QPointF offset(touchPoint.scenePos() - m_touchBeginEventForTap->touchPoints().first().scenePos());
81             const qreal distX = qAbs(offset.x());
82             const qreal distY = qAbs(offset.y());
83             if (distX > initialTriggerDistanceThreshold || distY > initialTriggerDistanceThreshold)
84                 reset();
85         }
86         break;
87     case QEvent::TouchEnd:
88         m_tapAndHoldTimer.stop();
89         m_eventHandler->handlePotentialSingleTapEvent(QTouchEvent::TouchPoint());
90
91         switch (m_tapState) {
92         case DoubleTapCandidate:
93             {
94                 ASSERT(!m_doubleTapTimer.isActive());
95                 m_tapState = NoTap;
96
97                 const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first();
98                 QPointF startPosition = touchPoint.startScreenPos();
99                 QPointF endPosition = touchPoint.screenPos();
100                 if (QLineF(endPosition, startPosition).length() < maxDoubleTapDistance && m_eventHandler)
101                     m_eventHandler->handleDoubleTapEvent(touchPoint);
102                 break;
103             }
104         case SingleTapStarted:
105             ASSERT(!m_doubleTapTimer.isActive());
106             m_doubleTapTimer.start(doubleClickInterval, this);
107             m_tapState = NoTap;
108             break;
109         case TapAndHold:
110             m_tapState = NoTap;
111             break;
112         default:
113             break;
114         }
115         break;
116     default:
117         break;
118     }
119
120     return false;
121 }
122
123 void QtTapGestureRecognizer::tapTimeout()
124 {
125     m_doubleTapTimer.stop();
126     m_eventHandler->handleSingleTapEvent(m_touchBeginEventForTap->touchPoints().at(0));
127     m_touchBeginEventForTap.clear();
128 }
129
130 void QtTapGestureRecognizer::tapAndHoldTimeout()
131 {
132     ASSERT(m_touchBeginEventForTap);
133     m_tapAndHoldTimer.stop();
134 #if 0 // No support for synthetic context menus in WK2 yet.
135     QTouchEvent::TouchPoint tapPoint = m_touchBeginEventForTap->touchPoints().at(0);
136     WebGestureEvent gesture(WebEvent::GestureTapAndHold, tapPoint.pos().toPoint(), tapPoint.screenPos().toPoint(), WebEvent::Modifiers(0), 0);
137     if (m_webPageProxy)
138         m_webPageProxy->handleGestureEvent(gesture);
139 #endif
140     m_touchBeginEventForTap.clear();
141     m_tapState = TapAndHold;
142
143     ASSERT(!m_doubleTapTimer.isActive());
144     m_doubleTapTimer.stop();
145 }
146
147 void QtTapGestureRecognizer::reset()
148 {
149     m_eventHandler->handlePotentialSingleTapEvent(QTouchEvent::TouchPoint());
150
151     m_tapState = NoTap;
152     m_touchBeginEventForTap.clear();
153     m_tapAndHoldTimer.stop();
154
155     QtGestureRecognizer::reset();
156 }
157
158 void QtTapGestureRecognizer::timerEvent(QTimerEvent* ev)
159 {
160     int timerId = ev->timerId();
161     if (timerId == m_doubleTapTimer.timerId())
162         tapTimeout();
163     else if (timerId == m_tapAndHoldTimer.timerId())
164         tapAndHoldTimeout();
165     else
166         QObject::timerEvent(ev);
167 }
168
169 } // namespace WebKit