Chromium Code Reviews

Side by Side Diff: ui/events/gesture_detection/gesture_provider.cc

Issue 501503003: Avoid an extra GestureDetector instance for double-tap drag zooming (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove unnecessary scoped_ptr include Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/events/gesture_detection/gesture_provider.h" 5 #include "ui/events/gesture_detection/gesture_provider.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 8
9 #include "base/auto_reset.h" 9 #include "base/auto_reset.h"
10 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
11 #include "ui/events/event_constants.h" 11 #include "ui/events/event_constants.h"
12 #include "ui/events/gesture_detection/gesture_event_data.h" 12 #include "ui/events/gesture_detection/gesture_event_data.h"
13 #include "ui/events/gesture_detection/motion_event.h" 13 #include "ui/events/gesture_detection/motion_event.h"
14 14
15 namespace ui { 15 namespace ui {
16 namespace { 16 namespace {
17 17
18 // Double-tap drag zoom sensitivity (speed). 18 // Double-tap drag zoom sensitivity (speed).
19 const float kDoubleTapDragZoomSpeed = 0.005f; 19 const float kDoubleTapDragZoomSpeed = 0.005f;
20 20
21 const char* GetMotionEventActionName(MotionEvent::Action action) { 21 const char* GetMotionEventActionName(MotionEvent::Action action) {
22 switch(action) { 22 switch (action) {
23 case MotionEvent::ACTION_POINTER_DOWN: return "ACTION_POINTER_DOWN"; 23 case MotionEvent::ACTION_POINTER_DOWN:
24 case MotionEvent::ACTION_POINTER_UP: return "ACTION_POINTER_UP"; 24 return "ACTION_POINTER_DOWN";
25 case MotionEvent::ACTION_DOWN: return "ACTION_DOWN"; 25 case MotionEvent::ACTION_POINTER_UP:
26 case MotionEvent::ACTION_UP: return "ACTION_UP"; 26 return "ACTION_POINTER_UP";
27 case MotionEvent::ACTION_CANCEL: return "ACTION_CANCEL"; 27 case MotionEvent::ACTION_DOWN:
28 case MotionEvent::ACTION_MOVE: return "ACTION_MOVE"; 28 return "ACTION_DOWN";
29 case MotionEvent::ACTION_UP:
30 return "ACTION_UP";
31 case MotionEvent::ACTION_CANCEL:
32 return "ACTION_CANCEL";
33 case MotionEvent::ACTION_MOVE:
34 return "ACTION_MOVE";
29 } 35 }
30 return ""; 36 return "";
31 } 37 }
32 38
33 gfx::RectF GetBoundingBox(const MotionEvent& event) { 39 gfx::RectF GetBoundingBox(const MotionEvent& event) {
34 // Can't use gfx::RectF::Union, as it ignores touches with a radius of 0. 40 // Can't use gfx::RectF::Union, as it ignores touches with a radius of 0.
35 float left = std::numeric_limits<float>::max(); 41 float left = std::numeric_limits<float>::max();
36 float top = std::numeric_limits<float>::max(); 42 float top = std::numeric_limits<float>::max();
37 float right = -std::numeric_limits<float>::max(); 43 float right = -std::numeric_limits<float>::max();
38 float bottom = -std::numeric_limits<float>::max(); 44 float bottom = -std::numeric_limits<float>::max();
(...skipping 64 matching lines...)
103 event.GetRawX(), 109 event.GetRawX(),
104 event.GetRawY(), 110 event.GetRawY(),
105 event.GetPointerCount(), 111 event.GetPointerCount(),
106 GetBoundingBox(event)); 112 GetBoundingBox(event));
107 } 113 }
108 114
109 GestureEventData CreateGesture(EventType type, const MotionEvent& event) { 115 GestureEventData CreateGesture(EventType type, const MotionEvent& event) {
110 return CreateGesture(GestureEventDetails(type, 0, 0), event); 116 return CreateGesture(GestureEventDetails(type, 0, 0), event);
111 } 117 }
112 118
113 GestureEventDetails CreateTapGestureDetails(EventType type) { 119 GestureEventData CreateTapGesture(EventType type, const MotionEvent& event) {
114 // Set the tap count to 1 even for ET_GESTURE_DOUBLE_TAP, in order to be 120 // Set the tap count to 1 even for ET_GESTURE_DOUBLE_TAP, in order to be
115 // consistent with double tap behavior on a mobile viewport. See 121 // consistent with double tap behavior on a mobile viewport. See
116 // crbug.com/234986 for context. 122 // crbug.com/234986 for context.
117 GestureEventDetails tap_details(type, 1, 0); 123 return CreateGesture(GestureEventDetails(type, 1, 0), event);
118 return tap_details;
119 } 124 }
120 125
121 gfx::RectF ClampBoundingBox(const gfx::RectF& bounds, 126 gfx::RectF ClampBoundingBox(const gfx::RectF& bounds,
122 float min_length, 127 float min_length,
123 float max_length) { 128 float max_length) {
124 float width = bounds.width(); 129 float width = bounds.width();
125 float height = bounds.height(); 130 float height = bounds.height();
126 if (min_length) { 131 if (min_length) {
127 width = std::max(min_length, width); 132 width = std::max(min_length, width);
128 height = std::max(min_length, height); 133 height = std::max(min_length, height);
129 } 134 }
130 if (max_length) { 135 if (max_length) {
131 width = std::min(max_length, width); 136 width = std::min(max_length, width);
132 height = std::min(max_length, height); 137 height = std::min(max_length, height);
133 } 138 }
134 const gfx::PointF center = bounds.CenterPoint(); 139 const gfx::PointF center = bounds.CenterPoint();
135 return gfx::RectF( 140 return gfx::RectF(
136 center.x() - width / 2.f, center.y() - height / 2.f, width, height); 141 center.x() - width / 2.f, center.y() - height / 2.f, width, height);
137 } 142 }
138 143
139 } // namespace 144 } // namespace
140 145
141 // GestureProvider:::Config 146 // GestureProvider:::Config
142 147
143 GestureProvider::Config::Config() 148 GestureProvider::Config::Config()
144 : display(gfx::Display::kInvalidDisplayID, gfx::Rect(1, 1)), 149 : display(gfx::Display::kInvalidDisplayID, gfx::Rect(1, 1)),
145 disable_click_delay(false), 150 disable_click_delay(false),
146 gesture_begin_end_types_enabled(false), 151 gesture_begin_end_types_enabled(false),
147 min_gesture_bounds_length(0), 152 min_gesture_bounds_length(0),
148 max_gesture_bounds_length(0) {} 153 max_gesture_bounds_length(0) {
154 }
149 155
150 GestureProvider::Config::~Config() {} 156 GestureProvider::Config::~Config() {
157 }
151 158
152 // GestureProvider::ScaleGestureListener 159 // GestureProvider::GestureListener
153 160
154 class GestureProvider::ScaleGestureListenerImpl 161 class GestureProvider::GestureListenerImpl
155 : public ScaleGestureDetector::ScaleGestureListener { 162 : public ScaleGestureDetector::ScaleGestureListener,
163 public GestureDetector::GestureListener,
164 public GestureDetector::DoubleTapListener {
156 public: 165 public:
157 ScaleGestureListenerImpl(const ScaleGestureDetector::Config& config, 166 GestureListenerImpl(const GestureProvider::Config& config,
158 GestureProvider* provider) 167 GestureProviderClient* client)
159 : scale_gesture_detector_(config, this), 168 : config_(config),
160 provider_(provider), 169 client_(client),
161 ignore_multitouch_events_(false), 170 gesture_detector_(config.gesture_detector_config, this, this),
171 scale_gesture_detector_(config.scale_gesture_detector_config, this),
172 snap_scroll_controller_(config.display),
173 ignore_multitouch_zoom_events_(false),
174 ignore_single_tap_(false),
162 pinch_event_sent_(false), 175 pinch_event_sent_(false),
163 min_pinch_update_span_delta_(config.min_pinch_update_span_delta) {} 176 scroll_event_sent_(false) {}
164 177
165 bool OnTouchEvent(const MotionEvent& event) { 178 void OnTouchEvent(const MotionEvent& event) {
166 // TODO: Need to deal with multi-touch transition.
167 const bool in_scale_gesture = IsScaleGestureDetectionInProgress(); 179 const bool in_scale_gesture = IsScaleGestureDetectionInProgress();
168 bool handled = scale_gesture_detector_.OnTouchEvent(event); 180 snap_scroll_controller_.SetSnapScrollingMode(event, in_scale_gesture);
169 if (!in_scale_gesture && 181 if (in_scale_gesture)
170 (event.GetAction() == MotionEvent::ACTION_UP || 182 SetIgnoreSingleTap(true);
171 event.GetAction() == MotionEvent::ACTION_CANCEL)) { 183
172 return false; 184 const MotionEvent::Action action = event.GetAction();
185 if (action == MotionEvent::ACTION_DOWN) {
186 current_down_time_ = event.GetEventTime();
187 current_longpress_time_ = base::TimeTicks();
188 ignore_single_tap_ = false;
189 scroll_event_sent_ = false;
190 pinch_event_sent_ = false;
191 gesture_detector_.set_longpress_enabled(true);
173 } 192 }
174 return handled; 193
194 gesture_detector_.OnTouchEvent(event);
195 scale_gesture_detector_.OnTouchEvent(event);
196
197 if (action == MotionEvent::ACTION_UP ||
198 action == MotionEvent::ACTION_CANCEL) {
199 // Note: This call will have no effect if a fling was just generated, as
200 // |Fling()| will have already signalled an end to touch-scrolling.
201 if (scroll_event_sent_)
202 Send(CreateGesture(ET_GESTURE_SCROLL_END, event));
203 current_down_time_ = base::TimeTicks();
204 }
205 }
206
207 void Send(GestureEventData gesture) {
208 DCHECK(!gesture.time.is_null());
209 // The only valid events that should be sent without an active touch
210 // sequence are SHOW_PRESS and TAP, potentially triggered by the double-tap
211 // delay timing out.
212 DCHECK(!current_down_time_.is_null() || gesture.type() == ET_GESTURE_TAP ||
213 gesture.type() == ET_GESTURE_SHOW_PRESS ||
214 gesture.type() == ET_GESTURE_BEGIN ||
215 gesture.type() == ET_GESTURE_END);
216
217 if (gesture.primary_tool_type == MotionEvent::TOOL_TYPE_UNKNOWN ||
218 gesture.primary_tool_type == MotionEvent::TOOL_TYPE_FINGER) {
219 gesture.details.set_bounding_box(
220 ClampBoundingBox(gesture.details.bounding_box_f(),
221 config_.min_gesture_bounds_length,
222 config_.max_gesture_bounds_length));
223 }
224
225 switch (gesture.type()) {
226 case ET_GESTURE_LONG_PRESS:
227 DCHECK(!IsScaleGestureDetectionInProgress());
228 current_longpress_time_ = gesture.time;
229 break;
230 case ET_GESTURE_LONG_TAP:
231 current_longpress_time_ = base::TimeTicks();
232 break;
233 case ET_GESTURE_SCROLL_BEGIN:
234 DCHECK(!scroll_event_sent_);
235 scroll_event_sent_ = true;
236 break;
237 case ET_GESTURE_SCROLL_END:
238 DCHECK(scroll_event_sent_);
239 if (pinch_event_sent_)
240 Send(GestureEventData(ET_GESTURE_PINCH_END, gesture));
241 scroll_event_sent_ = false;
242 break;
243 case ET_SCROLL_FLING_START:
244 DCHECK(scroll_event_sent_);
245 scroll_event_sent_ = false;
246 break;
247 case ET_GESTURE_PINCH_BEGIN:
248 DCHECK(!pinch_event_sent_);
249 if (!scroll_event_sent_)
250 Send(GestureEventData(ET_GESTURE_SCROLL_BEGIN, gesture));
251 pinch_event_sent_ = true;
252 break;
253 case ET_GESTURE_PINCH_END:
254 DCHECK(pinch_event_sent_);
255 pinch_event_sent_ = false;
256 break;
257 case ET_GESTURE_SHOW_PRESS:
258 // It's possible that a double-tap drag zoom (from ScaleGestureDetector)
259 // will start before the press gesture fires (from GestureDetector), in
260 // which case the press should simply be dropped.
261 if (pinch_event_sent_ || scroll_event_sent_)
262 return;
263 default:
264 break;
265 };
266
267 client_->OnGestureEvent(gesture);
175 } 268 }
176 269
177 // ScaleGestureDetector::ScaleGestureListener implementation. 270 // ScaleGestureDetector::ScaleGestureListener implementation.
178 virtual bool OnScaleBegin(const ScaleGestureDetector& detector, 271 virtual bool OnScaleBegin(const ScaleGestureDetector& detector,
179 const MotionEvent& e) OVERRIDE { 272 const MotionEvent& e) OVERRIDE {
180 if (ignore_multitouch_events_ && !detector.InDoubleTapMode()) 273 if (ignore_multitouch_zoom_events_ && !detector.InDoubleTapMode())
181 return false; 274 return false;
182 pinch_event_sent_ = false;
183 return true; 275 return true;
184 } 276 }
185 277
186 virtual void OnScaleEnd(const ScaleGestureDetector& detector, 278 virtual void OnScaleEnd(const ScaleGestureDetector& detector,
187 const MotionEvent& e) OVERRIDE { 279 const MotionEvent& e) OVERRIDE {
188 if (!pinch_event_sent_) 280 if (!pinch_event_sent_)
189 return; 281 return;
190 provider_->Send(CreateGesture(ET_GESTURE_PINCH_END, e)); 282 Send(CreateGesture(ET_GESTURE_PINCH_END, e));
191 pinch_event_sent_ = false;
192 } 283 }
193 284
194 virtual bool OnScale(const ScaleGestureDetector& detector, 285 virtual bool OnScale(const ScaleGestureDetector& detector,
195 const MotionEvent& e) OVERRIDE { 286 const MotionEvent& e) OVERRIDE {
196 if (ignore_multitouch_events_ && !detector.InDoubleTapMode()) 287 if (ignore_multitouch_zoom_events_ && !detector.InDoubleTapMode())
197 return false; 288 return false;
198 if (!pinch_event_sent_) { 289 if (!pinch_event_sent_) {
199 pinch_event_sent_ = true; 290 Send(CreateGesture(ET_GESTURE_PINCH_BEGIN,
200 provider_->Send(CreateGesture(ET_GESTURE_PINCH_BEGIN, 291 e.GetId(),
201 e.GetId(), 292 e.GetToolType(),
202 e.GetToolType(), 293 detector.GetEventTime(),
203 detector.GetEventTime(), 294 detector.GetFocusX(),
204 detector.GetFocusX(), 295 detector.GetFocusY(),
205 detector.GetFocusY(), 296 detector.GetFocusX() + e.GetRawOffsetX(),
206 detector.GetFocusX() + e.GetRawOffsetX(), 297 detector.GetFocusY() + e.GetRawOffsetY(),
207 detector.GetFocusY() + e.GetRawOffsetY(), 298 e.GetPointerCount(),
208 e.GetPointerCount(), 299 GetBoundingBox(e)));
209 GetBoundingBox(e)));
210 } 300 }
211 301
212 if (std::abs(detector.GetCurrentSpan() - detector.GetPreviousSpan()) < 302 if (std::abs(detector.GetCurrentSpan() - detector.GetPreviousSpan()) <
213 min_pinch_update_span_delta_) { 303 config_.scale_gesture_detector_config.min_pinch_update_span_delta) {
214 return false; 304 return false;
215 } 305 }
216 306
217 float scale = detector.GetScaleFactor(); 307 float scale = detector.GetScaleFactor();
218 if (scale == 1) 308 if (scale == 1)
219 return true; 309 return true;
220 310
221 if (detector.InDoubleTapMode()) { 311 if (detector.InDoubleTapMode()) {
222 // Relative changes in the double-tap scale factor computed by |detector| 312 // Relative changes in the double-tap scale factor computed by |detector|
223 // diminish as the touch moves away from the original double-tap focus. 313 // diminish as the touch moves away from the original double-tap focus.
224 // For historical reasons, Chrome has instead adopted a scale factor 314 // For historical reasons, Chrome has instead adopted a scale factor
225 // computation that is invariant to the focal distance, where 315 // computation that is invariant to the focal distance, where
226 // the scale delta remains constant if the touch velocity is constant. 316 // the scale delta remains constant if the touch velocity is constant.
227 float dy = 317 float dy =
228 (detector.GetCurrentSpanY() - detector.GetPreviousSpanY()) * 0.5f; 318 (detector.GetCurrentSpanY() - detector.GetPreviousSpanY()) * 0.5f;
229 scale = std::pow(scale > 1 ? 1.0f + kDoubleTapDragZoomSpeed 319 scale = std::pow(scale > 1 ? 1.0f + kDoubleTapDragZoomSpeed
230 : 1.0f - kDoubleTapDragZoomSpeed, 320 : 1.0f - kDoubleTapDragZoomSpeed,
231 std::abs(dy)); 321 std::abs(dy));
232 } 322 }
233 GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0); 323 GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0);
234 provider_->Send(CreateGesture(pinch_details, 324 Send(CreateGesture(pinch_details,
235 e.GetId(), 325 e.GetId(),
236 e.GetToolType(), 326 e.GetToolType(),
237 detector.GetEventTime(), 327 detector.GetEventTime(),
238 detector.GetFocusX(), 328 detector.GetFocusX(),
239 detector.GetFocusY(), 329 detector.GetFocusY(),
240 detector.GetFocusX() + e.GetRawOffsetX(), 330 detector.GetFocusX() + e.GetRawOffsetX(),
241 detector.GetFocusY() + e.GetRawOffsetY(), 331 detector.GetFocusY() + e.GetRawOffsetY(),
242 e.GetPointerCount(), 332 e.GetPointerCount(),
243 GetBoundingBox(e))); 333 GetBoundingBox(e)));
244 return true; 334 return true;
245 } 335 }
246 336
247 void SetDoubleTapEnabled(bool enabled) {
248 DCHECK(!IsDoubleTapInProgress());
249 scale_gesture_detector_.SetQuickScaleEnabled(enabled);
250 }
251
252 void SetMultiTouchEnabled(bool enabled) {
253 // Note that returning false from OnScaleBegin / OnScale makes the
254 // gesture detector not to emit further scaling notifications
255 // related to this gesture. Thus, if detector events are enabled in
256 // the middle of the gesture, we don't need to do anything.
257 ignore_multitouch_events_ = !enabled;
258 }
259
260 bool IsDoubleTapInProgress() const {
261 return IsScaleGestureDetectionInProgress() && InDoubleTapMode();
262 }
263
264 bool IsScaleGestureDetectionInProgress() const {
265 return scale_gesture_detector_.IsInProgress();
266 }
267
268 private:
269 bool InDoubleTapMode() const {
270 return scale_gesture_detector_.InDoubleTapMode();
271 }
272
273 ScaleGestureDetector scale_gesture_detector_;
274
275 GestureProvider* const provider_;
276
277 // Completely silence multi-touch (pinch) scaling events. Used in WebView when
278 // zoom support is turned off.
279 bool ignore_multitouch_events_;
280
281 // Whether any pinch zoom event has been sent to native.
282 bool pinch_event_sent_;
283
284 // The minimum change in span required before this is considered a pinch. See
285 // crbug.com/373318.
286 float min_pinch_update_span_delta_;
287
288 DISALLOW_COPY_AND_ASSIGN(ScaleGestureListenerImpl);
289 };
290
291 // GestureProvider::GestureListener
292
293 class GestureProvider::GestureListenerImpl
294 : public GestureDetector::GestureListener,
295 public GestureDetector::DoubleTapListener {
296 public:
297 GestureListenerImpl(
298 const gfx::Display& display,
299 const GestureDetector::Config& gesture_detector_config,
300 bool disable_click_delay,
301 GestureProvider* provider)
302 : gesture_detector_(gesture_detector_config, this, this),
303 snap_scroll_controller_(display),
304 provider_(provider),
305 disable_click_delay_(disable_click_delay),
306 touch_slop_(gesture_detector_config.touch_slop),
307 double_tap_timeout_(gesture_detector_config.double_tap_timeout),
308 ignore_single_tap_(false),
309 seen_first_scroll_event_(false) {}
310
311 virtual ~GestureListenerImpl() {}
312
313 bool OnTouchEvent(const MotionEvent& e,
314 bool is_scale_gesture_detection_in_progress) {
315 snap_scroll_controller_.SetSnapScrollingMode(
316 e, is_scale_gesture_detection_in_progress);
317
318 if (is_scale_gesture_detection_in_progress)
319 SetIgnoreSingleTap(true);
320
321 if (e.GetAction() == MotionEvent::ACTION_DOWN)
322 gesture_detector_.set_longpress_enabled(true);
323
324 return gesture_detector_.OnTouchEvent(e);
325 }
326
327 // GestureDetector::GestureListener implementation. 337 // GestureDetector::GestureListener implementation.
328 virtual bool OnDown(const MotionEvent& e) OVERRIDE { 338 virtual bool OnDown(const MotionEvent& e) OVERRIDE {
329 current_down_time_ = e.GetEventTime();
330 ignore_single_tap_ = false;
331 seen_first_scroll_event_ = false;
332
333 GestureEventDetails tap_details(ET_GESTURE_TAP_DOWN, 0, 0); 339 GestureEventDetails tap_details(ET_GESTURE_TAP_DOWN, 0, 0);
334 provider_->Send(CreateGesture(tap_details, e)); 340 Send(CreateGesture(tap_details, e));
335 341
336 // Return true to indicate that we want to handle touch. 342 // Return true to indicate that we want to handle touch.
337 return true; 343 return true;
338 } 344 }
339 345
340 virtual bool OnScroll(const MotionEvent& e1, 346 virtual bool OnScroll(const MotionEvent& e1,
341 const MotionEvent& e2, 347 const MotionEvent& e2,
342 float raw_distance_x, 348 float raw_distance_x,
343 float raw_distance_y) OVERRIDE { 349 float raw_distance_y) OVERRIDE {
344 float distance_x = raw_distance_x; 350 float distance_x = raw_distance_x;
345 float distance_y = raw_distance_y; 351 float distance_y = raw_distance_y;
346 if (!seen_first_scroll_event_) { 352 if (!scroll_event_sent_) {
347 // Remove the touch slop region from the first scroll event to avoid a 353 // Remove the touch slop region from the first scroll event to avoid a
348 // jump. 354 // jump.
349 seen_first_scroll_event_ = true;
350 double distance = 355 double distance =
351 std::sqrt(distance_x * distance_x + distance_y * distance_y); 356 std::sqrt(distance_x * distance_x + distance_y * distance_y);
352 double epsilon = 1e-3; 357 double epsilon = 1e-3;
353 if (distance > epsilon) { 358 if (distance > epsilon) {
354 double ratio = std::max(0., distance - touch_slop_) / distance; 359 double ratio =
360 std::max(0.,
361 distance - config_.gesture_detector_config.touch_slop) /
362 distance;
355 distance_x *= ratio; 363 distance_x *= ratio;
356 distance_y *= ratio; 364 distance_y *= ratio;
357 } 365 }
358 }
359 snap_scroll_controller_.UpdateSnapScrollMode(distance_x, distance_y);
360 if (snap_scroll_controller_.IsSnappingScrolls()) {
361 if (snap_scroll_controller_.IsSnapHorizontal()) {
362 distance_y = 0;
363 } else {
364 distance_x = 0;
365 }
366 }
367 366
368 if (!provider_->IsScrollInProgress()) {
369 // Note that scroll start hints are in distance traveled, where 367 // Note that scroll start hints are in distance traveled, where
370 // scroll deltas are in the opposite direction. 368 // scroll deltas are in the opposite direction.
371 GestureEventDetails scroll_details( 369 GestureEventDetails scroll_details(
372 ET_GESTURE_SCROLL_BEGIN, -raw_distance_x, -raw_distance_y); 370 ET_GESTURE_SCROLL_BEGIN, -raw_distance_x, -raw_distance_y);
373 371
374 // Use the co-ordinates from the touch down, as these co-ordinates are 372 // Use the co-ordinates from the touch down, as these co-ordinates are
375 // used to determine which layer the scroll should affect. 373 // used to determine which layer the scroll should affect.
376 provider_->Send(CreateGesture(scroll_details, 374 Send(CreateGesture(scroll_details,
377 e2.GetId(), 375 e2.GetId(),
378 e2.GetToolType(), 376 e2.GetToolType(),
379 e2.GetEventTime(), 377 e2.GetEventTime(),
380 e1.GetX(), 378 e1.GetX(),
381 e1.GetY(), 379 e1.GetY(),
382 e1.GetRawX(), 380 e1.GetRawX(),
383 e1.GetRawY(), 381 e1.GetRawY(),
384 e2.GetPointerCount(), 382 e2.GetPointerCount(),
385 GetBoundingBox(e2))); 383 GetBoundingBox(e2)));
384 DCHECK(scroll_event_sent_);
385 }
386
387 snap_scroll_controller_.UpdateSnapScrollMode(distance_x, distance_y);
388 if (snap_scroll_controller_.IsSnappingScrolls()) {
389 if (snap_scroll_controller_.IsSnapHorizontal()) {
tdresser 2014/08/22 18:19:04 While you're here, you could switch to a braceless
jdduke (slow) 2014/08/22 20:33:10 Done.
390 distance_y = 0;
391 } else {
392 distance_x = 0;
393 }
386 } 394 }
387 395
388 if (distance_x || distance_y) { 396 if (distance_x || distance_y) {
389 const gfx::RectF bounding_box = GetBoundingBox(e2); 397 const gfx::RectF bounding_box = GetBoundingBox(e2);
390 const gfx::PointF center = bounding_box.CenterPoint(); 398 const gfx::PointF center = bounding_box.CenterPoint();
391 const gfx::PointF raw_center = 399 const gfx::PointF raw_center =
392 center + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY()); 400 center + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY());
393 GestureEventDetails scroll_details( 401 GestureEventDetails scroll_details(
394 ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y); 402 ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y);
395 provider_->Send(CreateGesture(scroll_details, 403 Send(CreateGesture(scroll_details,
396 e2.GetId(), 404 e2.GetId(),
397 e2.GetToolType(), 405 e2.GetToolType(),
398 e2.GetEventTime(), 406 e2.GetEventTime(),
399 center.x(), 407 center.x(),
400 center.y(), 408 center.y(),
401 raw_center.x(), 409 raw_center.x(),
402 raw_center.y(), 410 raw_center.y(),
403 e2.GetPointerCount(), 411 e2.GetPointerCount(),
404 bounding_box)); 412 bounding_box));
405 } 413 }
406 414
407 return true; 415 return true;
408 } 416 }
409 417
410 virtual bool OnFling(const MotionEvent& e1, 418 virtual bool OnFling(const MotionEvent& e1,
411 const MotionEvent& e2, 419 const MotionEvent& e2,
412 float velocity_x, 420 float velocity_x,
413 float velocity_y) OVERRIDE { 421 float velocity_y) OVERRIDE {
414 if (snap_scroll_controller_.IsSnappingScrolls()) { 422 if (snap_scroll_controller_.IsSnappingScrolls()) {
415 if (snap_scroll_controller_.IsSnapHorizontal()) { 423 if (snap_scroll_controller_.IsSnapHorizontal()) {
416 velocity_y = 0; 424 velocity_y = 0;
417 } else { 425 } else {
418 velocity_x = 0; 426 velocity_x = 0;
419 } 427 }
420 } 428 }
421 429
422 provider_->Fling(e2, velocity_x, velocity_y); 430 if (!velocity_x && !velocity_y)
431 return true;
432
433 if (!scroll_event_sent_) {
434 // The native side needs a ET_GESTURE_SCROLL_BEGIN before
435 // ET_SCROLL_FLING_START to send the fling to the correct target.
436 // The distance traveled in one second is a reasonable scroll start hint.
437 GestureEventDetails scroll_details(
438 ET_GESTURE_SCROLL_BEGIN, velocity_x, velocity_y);
439 Send(CreateGesture(scroll_details, e2));
440 }
441
442 GestureEventDetails fling_details(
443 ET_SCROLL_FLING_START, velocity_x, velocity_y);
444 Send(CreateGesture(fling_details, e2));
423 return true; 445 return true;
424 } 446 }
425 447
426 virtual bool OnSwipe(const MotionEvent& e1, 448 virtual bool OnSwipe(const MotionEvent& e1,
427 const MotionEvent& e2, 449 const MotionEvent& e2,
428 float velocity_x, 450 float velocity_x,
429 float velocity_y) OVERRIDE { 451 float velocity_y) OVERRIDE {
430 GestureEventDetails swipe_details(ET_GESTURE_SWIPE, velocity_x, velocity_y); 452 GestureEventDetails swipe_details(ET_GESTURE_SWIPE, velocity_x, velocity_y);
431 provider_->Send(CreateGesture(swipe_details, e2)); 453 Send(CreateGesture(swipe_details, e2));
432 return true; 454 return true;
433 } 455 }
434 456
435 virtual bool OnTwoFingerTap(const MotionEvent& e1, 457 virtual bool OnTwoFingerTap(const MotionEvent& e1,
436 const MotionEvent& e2) OVERRIDE { 458 const MotionEvent& e2) OVERRIDE {
437 // The location of the two finger tap event should be the location of the 459 // The location of the two finger tap event should be the location of the
438 // primary pointer. 460 // primary pointer.
439 GestureEventDetails two_finger_tap_details(ET_GESTURE_TWO_FINGER_TAP, 461 GestureEventDetails two_finger_tap_details(
440 e1.GetTouchMajor(), 462 ET_GESTURE_TWO_FINGER_TAP, e1.GetTouchMajor(), e1.GetTouchMajor());
441 e1.GetTouchMajor()); 463 Send(CreateGesture(two_finger_tap_details,
442 provider_->Send(CreateGesture(two_finger_tap_details, 464 e2.GetId(),
443 e2.GetId(), 465 e2.GetToolType(),
444 e2.GetToolType(), 466 e2.GetEventTime(),
445 e2.GetEventTime(), 467 e1.GetX(),
446 e1.GetX(), 468 e1.GetY(),
447 e1.GetY(), 469 e1.GetRawX(),
448 e1.GetRawX(), 470 e1.GetRawY(),
449 e1.GetRawY(), 471 e2.GetPointerCount(),
450 e2.GetPointerCount(), 472 GetBoundingBox(e2)));
451 GetBoundingBox(e2)));
452 return true; 473 return true;
453 } 474 }
454 475
455 virtual void OnShowPress(const MotionEvent& e) OVERRIDE { 476 virtual void OnShowPress(const MotionEvent& e) OVERRIDE {
456 GestureEventDetails show_press_details(ET_GESTURE_SHOW_PRESS, 0, 0); 477 GestureEventDetails show_press_details(ET_GESTURE_SHOW_PRESS, 0, 0);
457 provider_->Send(CreateGesture(show_press_details, e)); 478 Send(CreateGesture(show_press_details, e));
458 } 479 }
459 480
460 virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE { 481 virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE {
461 // This is a hack to address the issue where user hovers 482 // This is a hack to address the issue where user hovers
462 // over a link for longer than double_tap_timeout_, then 483 // over a link for longer than double_tap_timeout_, then
463 // OnSingleTapConfirmed() is not triggered. But we still 484 // OnSingleTapConfirmed() is not triggered. But we still
464 // want to trigger the tap event at UP. So we override 485 // want to trigger the tap event at UP. So we override
465 // OnSingleTapUp() in this case. This assumes singleTapUp 486 // OnSingleTapUp() in this case. This assumes singleTapUp
466 // gets always called before singleTapConfirmed. 487 // gets always called before singleTapConfirmed.
467 if (!ignore_single_tap_) { 488 if (!ignore_single_tap_) {
468 if (e.GetEventTime() - current_down_time_ > double_tap_timeout_) { 489 if (e.GetEventTime() - current_down_time_ >
490 config_.gesture_detector_config.double_tap_timeout) {
469 return OnSingleTapConfirmed(e); 491 return OnSingleTapConfirmed(e);
470 } else if (!IsDoubleTapEnabled() || disable_click_delay_) { 492 } else if (!IsDoubleTapEnabled() || config_.disable_click_delay) {
471 // If double-tap has been disabled, there is no need to wait 493 // If double-tap has been disabled, there is no need to wait
472 // for the double-tap timeout. 494 // for the double-tap timeout.
473 return OnSingleTapConfirmed(e); 495 return OnSingleTapConfirmed(e);
474 } else { 496 } else {
475 // Notify Blink about this tapUp event anyway, when none of the above 497 // Notify Blink about this tapUp event anyway, when none of the above
476 // conditions applied. 498 // conditions applied.
477 provider_->Send(CreateGesture( 499 Send(CreateTapGesture(ET_GESTURE_TAP_UNCONFIRMED, e));
478 CreateTapGestureDetails(ET_GESTURE_TAP_UNCONFIRMED), e));
479 } 500 }
480 } 501 }
481 502
482 return provider_->SendLongTapIfNecessary(e); 503 if (e.GetAction() == MotionEvent::ACTION_UP &&
504 !current_longpress_time_.is_null() &&
505 !IsScaleGestureDetectionInProgress()) {
506 GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP, 0, 0);
507 Send(CreateGesture(long_tap_details, e));
508 return true;
509 }
510
511 return false;
483 } 512 }
484 513
485 // GestureDetector::DoubleTapListener implementation. 514 // GestureDetector::DoubleTapListener implementation.
486 virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE { 515 virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE {
487 // Long taps in the edges of the screen have their events delayed by 516 // Long taps in the edges of the screen have their events delayed by
488 // ContentViewHolder for tab swipe operations. As a consequence of the delay 517 // ContentViewHolder for tab swipe operations. As a consequence of the delay
489 // this method might be called after receiving the up event. 518 // this method might be called after receiving the up event.
490 // These corner cases should be ignored. 519 // These corner cases should be ignored.
491 if (ignore_single_tap_) 520 if (ignore_single_tap_)
492 return true; 521 return true;
493 522
494 ignore_single_tap_ = true; 523 ignore_single_tap_ = true;
495 524
496 provider_->Send(CreateGesture(CreateTapGestureDetails(ET_GESTURE_TAP), e)); 525 Send(CreateTapGesture(ET_GESTURE_TAP, e));
497 return true; 526 return true;
498 } 527 }
499 528
500 virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { return false; } 529 virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE {
530 return scale_gesture_detector_.OnDoubleTap(e);
531 }
501 532
502 virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE { 533 virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE {
503 switch (e.GetAction()) { 534 switch (e.GetAction()) {
504 case MotionEvent::ACTION_DOWN: 535 case MotionEvent::ACTION_DOWN:
505 gesture_detector_.set_longpress_enabled(false); 536 gesture_detector_.set_longpress_enabled(false);
506 break; 537 break;
507 538
508 case MotionEvent::ACTION_UP: 539 case MotionEvent::ACTION_UP:
509 if (!provider_->IsPinchInProgress() && 540 if (!IsPinchInProgress() && !IsScrollInProgress()) {
510 !provider_->IsScrollInProgress()) { 541 Send(CreateTapGesture(ET_GESTURE_DOUBLE_TAP, e));
511 provider_->Send(
512 CreateGesture(CreateTapGestureDetails(ET_GESTURE_DOUBLE_TAP), e));
513 return true; 542 return true;
514 } 543 }
515 break; 544 break;
545
516 default: 546 default:
517 break; 547 break;
518 } 548 }
519 return false; 549 return false;
520 } 550 }
521 551
522 virtual void OnLongPress(const MotionEvent& e) OVERRIDE { 552 virtual void OnLongPress(const MotionEvent& e) OVERRIDE {
523 DCHECK(!IsDoubleTapInProgress()); 553 DCHECK(!IsDoubleTapInProgress());
524 SetIgnoreSingleTap(true); 554 SetIgnoreSingleTap(true);
525
526 GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0); 555 GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0);
527 provider_->Send(CreateGesture(long_press_details, e)); 556 Send(CreateGesture(long_press_details, e));
528 } 557 }
529 558
530 void SetDoubleTapEnabled(bool enabled) { 559 void SetDoubleTapEnabled(bool enabled) {
531 DCHECK(!IsDoubleTapInProgress()); 560 DCHECK(!IsDoubleTapInProgress());
532 gesture_detector_.SetDoubleTapListener(enabled ? this : NULL); 561 gesture_detector_.SetDoubleTapListener(enabled ? this : NULL);
533 } 562 }
534 563
535 bool IsDoubleTapInProgress() const { 564 void SetMultiTouchZoomEnabled(bool enabled) {
536 return gesture_detector_.is_double_tapping(); 565 // Note that returning false from OnScaleBegin / OnScale makes the
566 // gesture detector not to emit further scaling notifications
tdresser 2014/08/22 18:19:04 Might as well reword this comment while you're her
jdduke (slow) 2014/08/22 20:33:09 Ah, yeah this can be cleaned up. I think we still
567 // related to this gesture. Thus, if detector events are enabled in
568 // the middle of the gesture, we don't need to do anything.
569 ignore_multitouch_zoom_events_ = !enabled;
537 } 570 }
538 571
572 bool IsDoubleTapInProgress() const {
573 return gesture_detector_.is_double_tapping() ||
574 (IsScaleGestureDetectionInProgress() && InDoubleTapMode());
575 }
576
577 bool IsScrollInProgress() const { return scroll_event_sent_; }
578
579 bool IsPinchInProgress() const { return pinch_event_sent_; }
580
539 private: 581 private:
540 void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; } 582 bool IsScaleGestureDetectionInProgress() const {
583 return scale_gesture_detector_.IsInProgress();
584 }
585
586 bool InDoubleTapMode() const {
587 return scale_gesture_detector_.InDoubleTapMode();
588 }
541 589
542 bool IsDoubleTapEnabled() const { 590 bool IsDoubleTapEnabled() const {
543 return gesture_detector_.has_doubletap_listener(); 591 return gesture_detector_.has_doubletap_listener();
544 } 592 }
545 593
594 void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; }
595
596 const GestureProvider::Config config_;
597 GestureProviderClient* const client_;
598
546 GestureDetector gesture_detector_; 599 GestureDetector gesture_detector_;
600 ScaleGestureDetector scale_gesture_detector_;
547 SnapScrollController snap_scroll_controller_; 601 SnapScrollController snap_scroll_controller_;
548 602
549 GestureProvider* const provider_;
550
551 // Whether the click delay should always be disabled by sending clicks for
552 // double-tap gestures.
553 const bool disable_click_delay_;
554
555 const float touch_slop_;
556
557 const base::TimeDelta double_tap_timeout_;
558
559 base::TimeTicks current_down_time_; 603 base::TimeTicks current_down_time_;
560 604
605 // Keeps track of the current GESTURE_LONG_PRESS event. If a context menu is
606 // opened after a GESTURE_LONG_PRESS, this is used to insert a
607 // GESTURE_TAP_CANCEL for removing any ::active styling.
608 base::TimeTicks current_longpress_time_;
609
610 // Completely silence multi-touch (pinch) scaling events. Used in WebView when
611 // zoom support is turned off.
612 bool ignore_multitouch_zoom_events_;
613
561 // TODO(klobag): This is to avoid a bug in GestureDetector. With multi-touch, 614 // TODO(klobag): This is to avoid a bug in GestureDetector. With multi-touch,
562 // always_in_tap_region_ is not reset. So when the last finger is up, 615 // always_in_tap_region_ is not reset. So when the last finger is up,
563 // OnSingleTapUp() will be mistakenly fired. 616 // |OnSingleTapUp()| will be mistakenly fired.
564 bool ignore_single_tap_; 617 bool ignore_single_tap_;
565 618
566 // Used to remove the touch slop from the initial scroll event in a scroll 619 // Tracks whether {PINCH|SCROLL|_BEGIN events have been forwadred for the
tdresser 2014/08/22 18:19:04 forwadred -> forwarded {PINCH|SCROLL|_BEGIN -> ...
jdduke (slow) 2014/08/22 20:33:09 Done.
567 // gesture. 620 // current touch sequence.
568 bool seen_first_scroll_event_; 621 bool pinch_event_sent_;
622 bool scroll_event_sent_;
569 623
570 DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl); 624 DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl);
571 }; 625 };
572 626
573 // GestureProvider 627 // GestureProvider
574 628
575 GestureProvider::GestureProvider(const Config& config, 629 GestureProvider::GestureProvider(const Config& config,
576 GestureProviderClient* client) 630 GestureProviderClient* client)
577 : client_(client), 631 : double_tap_support_for_page_(true),
578 touch_scroll_in_progress_(false),
579 pinch_in_progress_(false),
580 double_tap_support_for_page_(true),
581 double_tap_support_for_platform_(true), 632 double_tap_support_for_platform_(true),
582 gesture_begin_end_types_enabled_(config.gesture_begin_end_types_enabled), 633 gesture_begin_end_types_enabled_(config.gesture_begin_end_types_enabled) {
583 min_gesture_bounds_length_(config.min_gesture_bounds_length),
584 max_gesture_bounds_length_(config.max_gesture_bounds_length) {
585 DCHECK(client); 634 DCHECK(client);
586 DCHECK(!min_gesture_bounds_length_ || !max_gesture_bounds_length_ || 635 DCHECK(!config.min_gesture_bounds_length ||
587 min_gesture_bounds_length_ <= max_gesture_bounds_length_); 636 !config.max_gesture_bounds_length ||
588 InitGestureDetectors(config); 637 config.min_gesture_bounds_length <= config.max_gesture_bounds_length);
638 TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors");
639 gesture_listener_.reset(new GestureListenerImpl(config, client));
640 UpdateDoubleTapDetectionSupport();
589 } 641 }
590 642
591 GestureProvider::~GestureProvider() {} 643 GestureProvider::~GestureProvider() {
644 }
592 645
593 bool GestureProvider::OnTouchEvent(const MotionEvent& event) { 646 bool GestureProvider::OnTouchEvent(const MotionEvent& event) {
594 TRACE_EVENT1("input", "GestureProvider::OnTouchEvent", 647 TRACE_EVENT1("input",
595 "action", GetMotionEventActionName(event.GetAction())); 648 "GestureProvider::OnTouchEvent",
649 "action",
650 GetMotionEventActionName(event.GetAction()));
596 651
597 DCHECK_NE(0u, event.GetPointerCount()); 652 DCHECK_NE(0u, event.GetPointerCount());
598 653
599 if (!CanHandle(event)) 654 if (!CanHandle(event))
600 return false; 655 return false;
601 656
602 const bool in_scale_gesture =
603 scale_gesture_listener_->IsScaleGestureDetectionInProgress();
604
605 OnTouchEventHandlingBegin(event); 657 OnTouchEventHandlingBegin(event);
606 gesture_listener_->OnTouchEvent(event, in_scale_gesture); 658 gesture_listener_->OnTouchEvent(event);
607 scale_gesture_listener_->OnTouchEvent(event);
608 OnTouchEventHandlingEnd(event); 659 OnTouchEventHandlingEnd(event);
609 return true; 660 return true;
610 } 661 }
611 662
612 void GestureProvider::SetMultiTouchZoomSupportEnabled(bool enabled) { 663 void GestureProvider::SetMultiTouchZoomSupportEnabled(bool enabled) {
613 scale_gesture_listener_->SetMultiTouchEnabled(enabled); 664 gesture_listener_->SetMultiTouchZoomEnabled(enabled);
614 } 665 }
615 666
616 void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) { 667 void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) {
617 if (double_tap_support_for_platform_ == enabled) 668 if (double_tap_support_for_platform_ == enabled)
618 return; 669 return;
619 double_tap_support_for_platform_ = enabled; 670 double_tap_support_for_platform_ = enabled;
620 UpdateDoubleTapDetectionSupport(); 671 UpdateDoubleTapDetectionSupport();
621 } 672 }
622 673
623 void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) { 674 void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) {
624 if (double_tap_support_for_page_ == enabled) 675 if (double_tap_support_for_page_ == enabled)
625 return; 676 return;
626 double_tap_support_for_page_ = enabled; 677 double_tap_support_for_page_ = enabled;
627 UpdateDoubleTapDetectionSupport(); 678 UpdateDoubleTapDetectionSupport();
628 } 679 }
629 680
630 bool GestureProvider::IsScrollInProgress() const { 681 bool GestureProvider::IsScrollInProgress() const {
631 // TODO(wangxianzhu): Also return true when fling is active once the UI knows 682 return gesture_listener_->IsScrollInProgress();
632 // exactly when the fling ends.
633 return touch_scroll_in_progress_;
634 } 683 }
635 684
636 bool GestureProvider::IsPinchInProgress() const { return pinch_in_progress_; } 685 bool GestureProvider::IsPinchInProgress() const {
686 return gesture_listener_->IsPinchInProgress();
687 }
637 688
638 bool GestureProvider::IsDoubleTapInProgress() const { 689 bool GestureProvider::IsDoubleTapInProgress() const {
639 return gesture_listener_->IsDoubleTapInProgress() || 690 return gesture_listener_->IsDoubleTapInProgress();
640 scale_gesture_listener_->IsDoubleTapInProgress();
641 }
642
643 void GestureProvider::InitGestureDetectors(const Config& config) {
644 TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors");
645 gesture_listener_.reset(
646 new GestureListenerImpl(config.display,
647 config.gesture_detector_config,
648 config.disable_click_delay,
649 this));
650
651 scale_gesture_listener_.reset(
652 new ScaleGestureListenerImpl(config.scale_gesture_detector_config, this));
653
654 UpdateDoubleTapDetectionSupport();
655 } 691 }
656 692
657 bool GestureProvider::CanHandle(const MotionEvent& event) const { 693 bool GestureProvider::CanHandle(const MotionEvent& event) const {
658 // Aura requires one cancel event per touch point, whereas Android requires 694 // Aura requires one cancel event per touch point, whereas Android requires
659 // one cancel event per touch sequence. Thus we need to allow extra cancel 695 // one cancel event per touch sequence. Thus we need to allow extra cancel
660 // events. 696 // events.
661 return event.GetAction() == MotionEvent::ACTION_DOWN || current_down_event_ || 697 return current_down_event_ || event.GetAction() == MotionEvent::ACTION_DOWN ||
662 event.GetAction() == MotionEvent::ACTION_CANCEL; 698 event.GetAction() == MotionEvent::ACTION_CANCEL;
663 } 699 }
664 700
665 void GestureProvider::Fling(const MotionEvent& event,
666 float velocity_x,
667 float velocity_y) {
668 if (!velocity_x && !velocity_y) {
669 EndTouchScrollIfNecessary(event, true);
670 return;
671 }
672
673 if (!touch_scroll_in_progress_) {
674 // The native side needs a ET_GESTURE_SCROLL_BEGIN before
675 // ET_SCROLL_FLING_START to send the fling to the correct target. Send if it
676 // has not sent. The distance traveled in one second is a reasonable scroll
677 // start hint.
678 GestureEventDetails scroll_details(
679 ET_GESTURE_SCROLL_BEGIN, velocity_x, velocity_y);
680 Send(CreateGesture(scroll_details, event));
681 }
682 EndTouchScrollIfNecessary(event, false);
683
684 GestureEventDetails fling_details(
685 ET_SCROLL_FLING_START, velocity_x, velocity_y);
686 Send(CreateGesture(fling_details, event));
687 }
688
689 void GestureProvider::Send(GestureEventData gesture) {
690 DCHECK(!gesture.time.is_null());
691 // The only valid events that should be sent without an active touch sequence
692 // are SHOW_PRESS and TAP, potentially triggered by the double-tap
693 // delay timing out.
694 DCHECK(current_down_event_ || gesture.type() == ET_GESTURE_TAP ||
695 gesture.type() == ET_GESTURE_SHOW_PRESS ||
696 gesture.type() == ET_GESTURE_END);
697
698 if (gesture.primary_tool_type == MotionEvent::TOOL_TYPE_UNKNOWN ||
699 gesture.primary_tool_type == MotionEvent::TOOL_TYPE_FINGER) {
700 gesture.details.set_bounding_box(
701 ClampBoundingBox(gesture.details.bounding_box_f(),
702 min_gesture_bounds_length_,
703 max_gesture_bounds_length_));
704 }
705
706 switch (gesture.type()) {
707 case ET_GESTURE_LONG_PRESS:
708 DCHECK(!scale_gesture_listener_->IsScaleGestureDetectionInProgress());
709 current_longpress_time_ = gesture.time;
710 break;
711 case ET_GESTURE_LONG_TAP:
712 current_longpress_time_ = base::TimeTicks();
713 break;
714 case ET_GESTURE_SCROLL_BEGIN:
715 DCHECK(!touch_scroll_in_progress_);
716 touch_scroll_in_progress_ = true;
717 break;
718 case ET_GESTURE_SCROLL_END:
719 DCHECK(touch_scroll_in_progress_);
720 if (pinch_in_progress_)
721 Send(GestureEventData(ET_GESTURE_PINCH_END, gesture));
722 touch_scroll_in_progress_ = false;
723 break;
724 case ET_GESTURE_PINCH_BEGIN:
725 DCHECK(!pinch_in_progress_);
726 if (!touch_scroll_in_progress_)
727 Send(GestureEventData(ET_GESTURE_SCROLL_BEGIN, gesture));
728 pinch_in_progress_ = true;
729 break;
730 case ET_GESTURE_PINCH_END:
731 DCHECK(pinch_in_progress_);
732 pinch_in_progress_ = false;
733 break;
734 case ET_GESTURE_SHOW_PRESS:
735 // It's possible that a double-tap drag zoom (from ScaleGestureDetector)
736 // will start before the press gesture fires (from GestureDetector), in
737 // which case the press should simply be dropped.
738 if (pinch_in_progress_ || touch_scroll_in_progress_)
739 return;
740 default:
741 break;
742 };
743
744 client_->OnGestureEvent(gesture);
745 }
746
747 bool GestureProvider::SendLongTapIfNecessary(const MotionEvent& event) {
748 if (event.GetAction() == MotionEvent::ACTION_UP &&
749 !current_longpress_time_.is_null() &&
750 !scale_gesture_listener_->IsScaleGestureDetectionInProgress()) {
751 GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP, 0, 0);
752 Send(CreateGesture(long_tap_details, event));
753 return true;
754 }
755 return false;
756 }
757
758 void GestureProvider::EndTouchScrollIfNecessary(const MotionEvent& event,
759 bool send_scroll_end_event) {
760 if (!touch_scroll_in_progress_)
761 return;
762 if (send_scroll_end_event)
763 Send(CreateGesture(ET_GESTURE_SCROLL_END, event));
764 touch_scroll_in_progress_ = false;
765 }
766
767 void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) { 701 void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) {
768 switch (event.GetAction()) { 702 switch (event.GetAction()) {
769 case MotionEvent::ACTION_DOWN: 703 case MotionEvent::ACTION_DOWN:
770 current_down_event_ = event.Clone(); 704 current_down_event_ = event.Clone();
771 touch_scroll_in_progress_ = false;
772 pinch_in_progress_ = false;
773 current_longpress_time_ = base::TimeTicks();
774 if (gesture_begin_end_types_enabled_) 705 if (gesture_begin_end_types_enabled_)
775 Send(CreateGesture(ET_GESTURE_BEGIN, event)); 706 gesture_listener_->Send(CreateGesture(ET_GESTURE_BEGIN, event));
776 break; 707 break;
777 case MotionEvent::ACTION_POINTER_DOWN: 708 case MotionEvent::ACTION_POINTER_DOWN:
778 if (gesture_begin_end_types_enabled_) { 709 if (gesture_begin_end_types_enabled_) {
779 const int action_index = event.GetActionIndex(); 710 const int action_index = event.GetActionIndex();
780 Send(CreateGesture(ET_GESTURE_BEGIN, 711 gesture_listener_->Send(CreateGesture(ET_GESTURE_BEGIN,
781 event.GetId(), 712 event.GetId(),
782 event.GetToolType(), 713 event.GetToolType(),
783 event.GetEventTime(), 714 event.GetEventTime(),
784 event.GetX(action_index), 715 event.GetX(action_index),
785 event.GetY(action_index), 716 event.GetY(action_index),
786 event.GetRawX(action_index), 717 event.GetRawX(action_index),
787 event.GetRawY(action_index), 718 event.GetRawY(action_index),
788 event.GetPointerCount(), 719 event.GetPointerCount(),
789 GetBoundingBox(event))); 720 GetBoundingBox(event)));
790 } 721 }
791 break; 722 break;
792 case MotionEvent::ACTION_POINTER_UP: 723 case MotionEvent::ACTION_POINTER_UP:
793 case MotionEvent::ACTION_UP: 724 case MotionEvent::ACTION_UP:
794 case MotionEvent::ACTION_CANCEL: 725 case MotionEvent::ACTION_CANCEL:
795 case MotionEvent::ACTION_MOVE: 726 case MotionEvent::ACTION_MOVE:
796 break; 727 break;
797 } 728 }
798 } 729 }
799 730
800 void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) { 731 void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) {
801 switch (event.GetAction()) { 732 switch (event.GetAction()) {
802 case MotionEvent::ACTION_UP: 733 case MotionEvent::ACTION_UP:
803 case MotionEvent::ACTION_CANCEL: { 734 case MotionEvent::ACTION_CANCEL: {
804 // Note: This call will have no effect if a fling was just generated, as
805 // |Fling()| will have already signalled an end to touch-scrolling.
806 EndTouchScrollIfNecessary(event, true);
807
808 if (gesture_begin_end_types_enabled_) 735 if (gesture_begin_end_types_enabled_)
809 Send(CreateGesture(ET_GESTURE_END, event)); 736 gesture_listener_->Send(CreateGesture(ET_GESTURE_END, event));
810 737
811 current_down_event_.reset(); 738 current_down_event_.reset();
812 739
813 UpdateDoubleTapDetectionSupport(); 740 UpdateDoubleTapDetectionSupport();
814 break; 741 break;
815 } 742 }
816 case MotionEvent::ACTION_POINTER_UP: 743 case MotionEvent::ACTION_POINTER_UP:
817 if (gesture_begin_end_types_enabled_) 744 if (gesture_begin_end_types_enabled_)
818 Send(CreateGesture(ET_GESTURE_END, event)); 745 gesture_listener_->Send(CreateGesture(ET_GESTURE_END, event));
819 break; 746 break;
820 case MotionEvent::ACTION_DOWN: 747 case MotionEvent::ACTION_DOWN:
821 case MotionEvent::ACTION_POINTER_DOWN: 748 case MotionEvent::ACTION_POINTER_DOWN:
822 case MotionEvent::ACTION_MOVE: 749 case MotionEvent::ACTION_MOVE:
823 break; 750 break;
824 } 751 }
825 } 752 }
826 753
827 void GestureProvider::UpdateDoubleTapDetectionSupport() { 754 void GestureProvider::UpdateDoubleTapDetectionSupport() {
828 // The GestureDetector requires that any provided DoubleTapListener remain 755 // The GestureDetector requires that any provided DoubleTapListener remain
829 // attached to it for the duration of a touch sequence. Defer any potential 756 // attached to it for the duration of a touch sequence. Defer any potential
830 // null'ing of the listener until the sequence has ended. 757 // null'ing of the listener until the sequence has ended.
831 if (current_down_event_) 758 if (current_down_event_)
832 return; 759 return;
833 760
834 const bool double_tap_enabled = double_tap_support_for_page_ && 761 const bool double_tap_enabled =
835 double_tap_support_for_platform_; 762 double_tap_support_for_page_ && double_tap_support_for_platform_;
836 gesture_listener_->SetDoubleTapEnabled(double_tap_enabled); 763 gesture_listener_->SetDoubleTapEnabled(double_tap_enabled);
837 scale_gesture_listener_->SetDoubleTapEnabled(double_tap_enabled);
838 } 764 }
839 765
840 } // namespace ui 766 } // namespace ui
OLDNEW

Powered by Google App Engine