Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=8 et tw=80 : */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef mozilla_layers_GestureEventListener_h
8 : #define mozilla_layers_GestureEventListener_h
9 :
10 : #include "InputData.h" // for MultiTouchInput, etc
11 : #include "Units.h"
12 : #include "mozilla/EventForwards.h" // for nsEventStatus
13 : #include "mozilla/RefPtr.h" // for RefPtr
14 : #include "nsISupportsImpl.h"
15 : #include "nsTArray.h" // for nsTArray
16 :
17 : namespace mozilla {
18 :
19 : class CancelableRunnable;
20 :
21 : namespace layers {
22 :
23 : class AsyncPanZoomController;
24 :
25 : /**
26 : * Platform-non-specific, generalized gesture event listener. This class
27 : * intercepts all touches events on their way to AsyncPanZoomController and
28 : * determines whether or not they are part of a gesture.
29 : *
30 : * For example, seeing that two fingers are on the screen means that the user
31 : * wants to do a pinch gesture, so we don't forward the touches along to
32 : * AsyncPanZoomController since it will think that they are just trying to pan
33 : * the screen. Instead, we generate a PinchGestureInput and send that. If the
34 : * touch event is not part of a gesture, we just return nsEventStatus_eIgnore
35 : * and AsyncPanZoomController is expected to handle it.
36 : */
37 : class GestureEventListener final {
38 : public:
39 2 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GestureEventListener)
40 :
41 : explicit GestureEventListener(AsyncPanZoomController* aAsyncPanZoomController);
42 :
43 : // --------------------------------------------------------------------------
44 : // These methods must only be called on the controller/UI thread.
45 : //
46 :
47 : /**
48 : * General input handler for a touch event. If the touch event is not a part
49 : * of a gesture, then we pass it along to AsyncPanZoomController. Otherwise,
50 : * it gets consumed here and never forwarded along.
51 : */
52 : nsEventStatus HandleInputEvent(const MultiTouchInput& aEvent);
53 :
54 : /**
55 : * Returns the identifier of the touch in the last touch event processed by
56 : * this GestureEventListener. This should only be called when the last touch
57 : * event contained only one touch.
58 : */
59 : int32_t GetLastTouchIdentifier() const;
60 :
61 : /**
62 : * Function used to disable long tap gestures.
63 : *
64 : * On slow running tests, drags and touch events can be misinterpreted
65 : * as a long tap. This allows tests to disable long tap gesture detection.
66 : */
67 : static void SetLongTapEnabled(bool aLongTapEnabled);
68 :
69 : private:
70 : // Private destructor, to discourage deletion outside of Release():
71 : ~GestureEventListener();
72 :
73 : /**
74 : * States of GEL finite-state machine.
75 : */
76 : enum GestureState {
77 : // This is the initial and final state of any gesture.
78 : // In this state there's no gesture going on, and we don't think we're
79 : // about to enter one.
80 : // Allowed next states: GESTURE_FIRST_SINGLE_TOUCH_DOWN, GESTURE_MULTI_TOUCH_DOWN.
81 : GESTURE_NONE,
82 :
83 : // A touch start with a single touch point has just happened.
84 : // After having gotten into this state we start timers for MAX_TAP_TIME and
85 : // gfxPrefs::UiClickHoldContextMenusDelay().
86 : // Allowed next states: GESTURE_MULTI_TOUCH_DOWN, GESTURE_NONE,
87 : // GESTURE_FIRST_SINGLE_TOUCH_UP, GESTURE_LONG_TOUCH_DOWN,
88 : // GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN.
89 : GESTURE_FIRST_SINGLE_TOUCH_DOWN,
90 :
91 : // While in GESTURE_FIRST_SINGLE_TOUCH_DOWN state a MAX_TAP_TIME timer got
92 : // triggered. Now we'll trigger either a single tap if a user lifts her
93 : // finger or a long tap if gfxPrefs::UiClickHoldContextMenusDelay() happens
94 : // first.
95 : // Allowed next states: GESTURE_MULTI_TOUCH_DOWN, GESTURE_NONE,
96 : // GESTURE_LONG_TOUCH_DOWN.
97 : GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN,
98 :
99 : // A user put her finger down and lifted it up quickly enough.
100 : // After having gotten into this state we clear the timer for MAX_TAP_TIME.
101 : // Allowed next states: GESTURE_SECOND_SINGLE_TOUCH_DOWN, GESTURE_NONE,
102 : // GESTURE_MULTI_TOUCH_DOWN.
103 : GESTURE_FIRST_SINGLE_TOUCH_UP,
104 :
105 : // A user put down her finger again right after a single tap thus the
106 : // gesture can't be a single tap, but rather a double tap. But we're
107 : // still not sure about that until the user lifts her finger again.
108 : // Allowed next states: GESTURE_MULTI_TOUCH_DOWN, GESTURE_ONE_TOUCH_PINCH,
109 : // GESTURE_NONE.
110 : GESTURE_SECOND_SINGLE_TOUCH_DOWN,
111 :
112 : // A long touch has happened, but the user still keeps her finger down.
113 : // We'll trigger a "long tap up" event when the finger is up.
114 : // Allowed next states: GESTURE_NONE, GESTURE_MULTI_TOUCH_DOWN.
115 : GESTURE_LONG_TOUCH_DOWN,
116 :
117 : // We have detected that two or more fingers are on the screen, but there
118 : // hasn't been enough movement yet to make us start actually zooming the
119 : // screen.
120 : // Allowed next states: GESTURE_PINCH, GESTURE_NONE
121 : GESTURE_MULTI_TOUCH_DOWN,
122 :
123 : // There are two or more fingers on the screen, and the user has already
124 : // pinched enough for us to start zooming the screen.
125 : // Allowed next states: GESTURE_NONE
126 : GESTURE_PINCH,
127 :
128 : // The user has double tapped, but not lifted her finger, and moved her
129 : // finger more than PINCH_START_THRESHOLD.
130 : // Allowed next states: GESTURE_NONE.
131 : GESTURE_ONE_TOUCH_PINCH
132 : };
133 :
134 : /**
135 : * These HandleInput* functions comprise input alphabet of the GEL
136 : * finite-state machine triggering state transitions.
137 : */
138 : nsEventStatus HandleInputTouchSingleStart();
139 : nsEventStatus HandleInputTouchMultiStart();
140 : nsEventStatus HandleInputTouchEnd();
141 : nsEventStatus HandleInputTouchMove();
142 : nsEventStatus HandleInputTouchCancel();
143 : void HandleInputTimeoutLongTap();
144 : void HandleInputTimeoutMaxTap(bool aDuringFastFling);
145 :
146 : void TriggerSingleTapConfirmedEvent();
147 :
148 : bool MoveDistanceIsLarge();
149 :
150 : /**
151 : * Returns current vertical span, counting from the where the user first put
152 : * her finger down.
153 : */
154 : ParentLayerCoord GetYSpanFromStartPoint();
155 :
156 : /**
157 : * Do actual state transition and reset substates.
158 : */
159 : void SetState(GestureState aState);
160 :
161 : RefPtr<AsyncPanZoomController> mAsyncPanZoomController;
162 :
163 : /**
164 : * Array containing all active touches. When a touch happens it, gets added to
165 : * this array, even if we choose not to handle it. When it ends, we remove it.
166 : * We need to maintain this array in order to detect the end of the
167 : * "multitouch" states because touch start events contain all current touches,
168 : * but touch end events contain only those touches that have gone.
169 : */
170 : nsTArray<SingleTouchData> mTouches;
171 :
172 : /**
173 : * Current state we're dealing with.
174 : */
175 : GestureState mState;
176 :
177 : /**
178 : * Total change in span since we detected a pinch gesture. Only used when we
179 : * are in the |GESTURE_WAITING_PINCH| state and need to know how far zoomed
180 : * out we are compared to our original pinch span. Note that this does _not_
181 : * continue to be updated once we jump into the |GESTURE_PINCH| state.
182 : */
183 : ParentLayerCoord mSpanChange;
184 :
185 : /**
186 : * Previous span calculated for the purposes of setting inside a
187 : * PinchGestureInput.
188 : */
189 : ParentLayerCoord mPreviousSpan;
190 :
191 : /* Properties similar to mSpanChange and mPreviousSpan, but for the focus */
192 : ParentLayerCoord mFocusChange;
193 : ParentLayerPoint mPreviousFocus;
194 :
195 : /**
196 : * Cached copy of the last touch input.
197 : */
198 : MultiTouchInput mLastTouchInput;
199 :
200 : /**
201 : * Cached copy of the last tap gesture input.
202 : * In the situation when we have a tap followed by a pinch we lose info
203 : * about tap since we keep only last input and to dispatch it correctly
204 : * we save last tap copy into this variable.
205 : * For more info see bug 947892.
206 : */
207 : MultiTouchInput mLastTapInput;
208 :
209 : /**
210 : * Position of the last touch starting. This is only valid during an attempt
211 : * to determine if a touch is a tap. If a touch point moves away from
212 : * mTouchStartPosition to the distance greater than
213 : * AsyncPanZoomController::GetTouchStartTolerance() while in
214 : * GESTURE_FIRST_SINGLE_TOUCH_DOWN, GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN
215 : * or GESTURE_SECOND_SINGLE_TOUCH_DOWN then we're certain the gesture is
216 : * not tap.
217 : */
218 : ParentLayerPoint mTouchStartPosition;
219 :
220 : /**
221 : * Task used to timeout a long tap. This gets posted to the UI thread such
222 : * that it runs a time when a single tap happens. We cache it so that
223 : * we can cancel it if any other touch event happens.
224 : *
225 : * The task is supposed to be non-null if in GESTURE_FIRST_SINGLE_TOUCH_DOWN
226 : * and GESTURE_FIRST_SINGLE_TOUCH_MAX_TAP_DOWN states.
227 : *
228 : * CancelLongTapTimeoutTask: Cancel the mLongTapTimeoutTask and also set
229 : * it to null.
230 : */
231 : RefPtr<CancelableRunnable> mLongTapTimeoutTask;
232 : void CancelLongTapTimeoutTask();
233 : void CreateLongTapTimeoutTask();
234 :
235 : /**
236 : * Task used to timeout a single tap or a double tap.
237 : *
238 : * The task is supposed to be non-null if in GESTURE_FIRST_SINGLE_TOUCH_DOWN,
239 : * GESTURE_FIRST_SINGLE_TOUCH_UP and GESTURE_SECOND_SINGLE_TOUCH_DOWN states.
240 : *
241 : * CancelMaxTapTimeoutTask: Cancel the mMaxTapTimeoutTask and also set
242 : * it to null.
243 : */
244 : RefPtr<CancelableRunnable> mMaxTapTimeoutTask;
245 : void CancelMaxTapTimeoutTask();
246 : void CreateMaxTapTimeoutTask();
247 :
248 : /**
249 : * Tracks whether the single-tap event was already sent to content. This is
250 : * needed because it affects how the double-tap gesture, if detected, is
251 : * handled. The value is only valid in states GESTURE_FIRST_SINGLE_TOUCH_UP and
252 : * GESTURE_SECOND_SINGLE_TOUCH_DOWN; to more easily catch violations it is
253 : * stored in a Maybe which is set to Nothing() at all other times.
254 : */
255 : Maybe<bool> mSingleTapSent;
256 : };
257 :
258 : } // namespace layers
259 : } // namespace mozilla
260 :
261 : #endif
|