Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

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: Fix spelling Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
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...) Expand 10 before | Expand all | Expand 10 after
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())
390 distance_y = 0;
391 else
392 distance_x = 0;
386 } 393 }
387 394
388 if (distance_x || distance_y) { 395 if (distance_x || distance_y) {
389 const gfx::RectF bounding_box = GetBoundingBox(e2); 396 const gfx::RectF bounding_box = GetBoundingBox(e2);
390 const gfx::PointF center = bounding_box.CenterPoint(); 397 const gfx::PointF center = bounding_box.CenterPoint();
391 const gfx::PointF raw_center = 398 const gfx::PointF raw_center =
392 center + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY()); 399 center + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY());
393 GestureEventDetails scroll_details( 400 GestureEventDetails scroll_details(
394 ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y); 401 ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y);
395 provider_->Send(CreateGesture(scroll_details, 402 Send(CreateGesture(scroll_details,
396 e2.GetId(), 403 e2.GetId(),
397 e2.GetToolType(), 404 e2.GetToolType(),
398 e2.GetEventTime(), 405 e2.GetEventTime(),
399 center.x(), 406 center.x(),
400 center.y(), 407 center.y(),
401 raw_center.x(), 408 raw_center.x(),
402 raw_center.y(), 409 raw_center.y(),
403 e2.GetPointerCount(), 410 e2.GetPointerCount(),
404 bounding_box)); 411 bounding_box));
405 } 412 }
406 413
407 return true; 414 return true;
408 } 415 }
409 416
410 virtual bool OnFling(const MotionEvent& e1, 417 virtual bool OnFling(const MotionEvent& e1,
411 const MotionEvent& e2, 418 const MotionEvent& e2,
412 float velocity_x, 419 float velocity_x,
413 float velocity_y) OVERRIDE { 420 float velocity_y) OVERRIDE {
414 if (snap_scroll_controller_.IsSnappingScrolls()) { 421 if (snap_scroll_controller_.IsSnappingScrolls()) {
415 if (snap_scroll_controller_.IsSnapHorizontal()) { 422 if (snap_scroll_controller_.IsSnapHorizontal()) {
416 velocity_y = 0; 423 velocity_y = 0;
417 } else { 424 } else {
418 velocity_x = 0; 425 velocity_x = 0;
419 } 426 }
420 } 427 }
421 428
422 provider_->Fling(e2, velocity_x, velocity_y); 429 if (!velocity_x && !velocity_y)
430 return true;
431
432 if (!scroll_event_sent_) {
433 // The native side needs a ET_GESTURE_SCROLL_BEGIN before
434 // ET_SCROLL_FLING_START to send the fling to the correct target.
435 // The distance traveled in one second is a reasonable scroll start hint.
436 GestureEventDetails scroll_details(
437 ET_GESTURE_SCROLL_BEGIN, velocity_x, velocity_y);
438 Send(CreateGesture(scroll_details, e2));
439 }
440
441 GestureEventDetails fling_details(
442 ET_SCROLL_FLING_START, velocity_x, velocity_y);
443 Send(CreateGesture(fling_details, e2));
423 return true; 444 return true;
424 } 445 }
425 446
426 virtual bool OnSwipe(const MotionEvent& e1, 447 virtual bool OnSwipe(const MotionEvent& e1,
427 const MotionEvent& e2, 448 const MotionEvent& e2,
428 float velocity_x, 449 float velocity_x,
429 float velocity_y) OVERRIDE { 450 float velocity_y) OVERRIDE {
430 GestureEventDetails swipe_details(ET_GESTURE_SWIPE, velocity_x, velocity_y); 451 GestureEventDetails swipe_details(ET_GESTURE_SWIPE, velocity_x, velocity_y);
431 provider_->Send(CreateGesture(swipe_details, e2)); 452 Send(CreateGesture(swipe_details, e2));
432 return true; 453 return true;
433 } 454 }
434 455
435 virtual bool OnTwoFingerTap(const MotionEvent& e1, 456 virtual bool OnTwoFingerTap(const MotionEvent& e1,
436 const MotionEvent& e2) OVERRIDE { 457 const MotionEvent& e2) OVERRIDE {
437 // The location of the two finger tap event should be the location of the 458 // The location of the two finger tap event should be the location of the
438 // primary pointer. 459 // primary pointer.
439 GestureEventDetails two_finger_tap_details(ET_GESTURE_TWO_FINGER_TAP, 460 GestureEventDetails two_finger_tap_details(
440 e1.GetTouchMajor(), 461 ET_GESTURE_TWO_FINGER_TAP, e1.GetTouchMajor(), e1.GetTouchMajor());
441 e1.GetTouchMajor()); 462 Send(CreateGesture(two_finger_tap_details,
442 provider_->Send(CreateGesture(two_finger_tap_details, 463 e2.GetId(),
443 e2.GetId(), 464 e2.GetToolType(),
444 e2.GetToolType(), 465 e2.GetEventTime(),
445 e2.GetEventTime(), 466 e1.GetX(),
446 e1.GetX(), 467 e1.GetY(),
447 e1.GetY(), 468 e1.GetRawX(),
448 e1.GetRawX(), 469 e1.GetRawY(),
449 e1.GetRawY(), 470 e2.GetPointerCount(),
450 e2.GetPointerCount(), 471 GetBoundingBox(e2)));
451 GetBoundingBox(e2)));
452 return true; 472 return true;
453 } 473 }
454 474
455 virtual void OnShowPress(const MotionEvent& e) OVERRIDE { 475 virtual void OnShowPress(const MotionEvent& e) OVERRIDE {
456 GestureEventDetails show_press_details(ET_GESTURE_SHOW_PRESS, 0, 0); 476 GestureEventDetails show_press_details(ET_GESTURE_SHOW_PRESS, 0, 0);
457 provider_->Send(CreateGesture(show_press_details, e)); 477 Send(CreateGesture(show_press_details, e));
458 } 478 }
459 479
460 virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE { 480 virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE {
461 // This is a hack to address the issue where user hovers 481 // This is a hack to address the issue where user hovers
462 // over a link for longer than double_tap_timeout_, then 482 // over a link for longer than double_tap_timeout_, then
463 // OnSingleTapConfirmed() is not triggered. But we still 483 // OnSingleTapConfirmed() is not triggered. But we still
464 // want to trigger the tap event at UP. So we override 484 // want to trigger the tap event at UP. So we override
465 // OnSingleTapUp() in this case. This assumes singleTapUp 485 // OnSingleTapUp() in this case. This assumes singleTapUp
466 // gets always called before singleTapConfirmed. 486 // gets always called before singleTapConfirmed.
467 if (!ignore_single_tap_) { 487 if (!ignore_single_tap_) {
468 if (e.GetEventTime() - current_down_time_ > double_tap_timeout_) { 488 if (e.GetEventTime() - current_down_time_ >
489 config_.gesture_detector_config.double_tap_timeout) {
469 return OnSingleTapConfirmed(e); 490 return OnSingleTapConfirmed(e);
470 } else if (!IsDoubleTapEnabled() || disable_click_delay_) { 491 } else if (!IsDoubleTapEnabled() || config_.disable_click_delay) {
471 // If double-tap has been disabled, there is no need to wait 492 // If double-tap has been disabled, there is no need to wait
472 // for the double-tap timeout. 493 // for the double-tap timeout.
473 return OnSingleTapConfirmed(e); 494 return OnSingleTapConfirmed(e);
474 } else { 495 } else {
475 // Notify Blink about this tapUp event anyway, when none of the above 496 // Notify Blink about this tapUp event anyway, when none of the above
476 // conditions applied. 497 // conditions applied.
477 provider_->Send(CreateGesture( 498 Send(CreateTapGesture(ET_GESTURE_TAP_UNCONFIRMED, e));
478 CreateTapGestureDetails(ET_GESTURE_TAP_UNCONFIRMED), e));
479 } 499 }
480 } 500 }
481 501
482 return provider_->SendLongTapIfNecessary(e); 502 if (e.GetAction() == MotionEvent::ACTION_UP &&
503 !current_longpress_time_.is_null() &&
504 !IsScaleGestureDetectionInProgress()) {
505 GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP, 0, 0);
506 Send(CreateGesture(long_tap_details, e));
507 return true;
508 }
509
510 return false;
483 } 511 }
484 512
485 // GestureDetector::DoubleTapListener implementation. 513 // GestureDetector::DoubleTapListener implementation.
486 virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE { 514 virtual bool OnSingleTapConfirmed(const MotionEvent& e) OVERRIDE {
487 // Long taps in the edges of the screen have their events delayed by 515 // 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 516 // ContentViewHolder for tab swipe operations. As a consequence of the delay
489 // this method might be called after receiving the up event. 517 // this method might be called after receiving the up event.
490 // These corner cases should be ignored. 518 // These corner cases should be ignored.
491 if (ignore_single_tap_) 519 if (ignore_single_tap_)
492 return true; 520 return true;
493 521
494 ignore_single_tap_ = true; 522 ignore_single_tap_ = true;
495 523
496 provider_->Send(CreateGesture(CreateTapGestureDetails(ET_GESTURE_TAP), e)); 524 Send(CreateTapGesture(ET_GESTURE_TAP, e));
497 return true; 525 return true;
498 } 526 }
499 527
500 virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { return false; } 528 virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE {
529 return scale_gesture_detector_.OnDoubleTap(e);
530 }
501 531
502 virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE { 532 virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE {
503 switch (e.GetAction()) { 533 switch (e.GetAction()) {
504 case MotionEvent::ACTION_DOWN: 534 case MotionEvent::ACTION_DOWN:
505 gesture_detector_.set_longpress_enabled(false); 535 gesture_detector_.set_longpress_enabled(false);
506 break; 536 break;
507 537
508 case MotionEvent::ACTION_UP: 538 case MotionEvent::ACTION_UP:
509 if (!provider_->IsPinchInProgress() && 539 if (!IsPinchInProgress() && !IsScrollInProgress()) {
510 !provider_->IsScrollInProgress()) { 540 Send(CreateTapGesture(ET_GESTURE_DOUBLE_TAP, e));
511 provider_->Send(
512 CreateGesture(CreateTapGestureDetails(ET_GESTURE_DOUBLE_TAP), e));
513 return true; 541 return true;
514 } 542 }
515 break; 543 break;
544
516 default: 545 default:
517 break; 546 break;
518 } 547 }
519 return false; 548 return false;
520 } 549 }
521 550
522 virtual void OnLongPress(const MotionEvent& e) OVERRIDE { 551 virtual void OnLongPress(const MotionEvent& e) OVERRIDE {
523 DCHECK(!IsDoubleTapInProgress()); 552 DCHECK(!IsDoubleTapInProgress());
524 SetIgnoreSingleTap(true); 553 SetIgnoreSingleTap(true);
525
526 GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0); 554 GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0);
527 provider_->Send(CreateGesture(long_press_details, e)); 555 Send(CreateGesture(long_press_details, e));
528 } 556 }
529 557
530 void SetDoubleTapEnabled(bool enabled) { 558 void SetDoubleTapEnabled(bool enabled) {
531 DCHECK(!IsDoubleTapInProgress()); 559 DCHECK(!IsDoubleTapInProgress());
532 gesture_detector_.SetDoubleTapListener(enabled ? this : NULL); 560 gesture_detector_.SetDoubleTapListener(enabled ? this : NULL);
533 } 561 }
534 562
535 bool IsDoubleTapInProgress() const { 563 void SetMultiTouchZoomEnabled(bool enabled) {
536 return gesture_detector_.is_double_tapping(); 564 // Note that returning false from |OnScaleBegin()| or |OnScale()| prevents
565 // the detector from emitting further scale updates for the current touch
566 // sequence. Thus, if multitouch events are enabled in the middle of a
567 // gesture, it will only take effect with the next gesture.
568 ignore_multitouch_zoom_events_ = !enabled;
537 } 569 }
538 570
571 bool IsDoubleTapInProgress() const {
572 return gesture_detector_.is_double_tapping() ||
573 (IsScaleGestureDetectionInProgress() && InDoubleTapMode());
574 }
575
576 bool IsScrollInProgress() const { return scroll_event_sent_; }
577
578 bool IsPinchInProgress() const { return pinch_event_sent_; }
579
539 private: 580 private:
540 void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; } 581 bool IsScaleGestureDetectionInProgress() const {
582 return scale_gesture_detector_.IsInProgress();
583 }
584
585 bool InDoubleTapMode() const {
586 return scale_gesture_detector_.InDoubleTapMode();
587 }
541 588
542 bool IsDoubleTapEnabled() const { 589 bool IsDoubleTapEnabled() const {
543 return gesture_detector_.has_doubletap_listener(); 590 return gesture_detector_.has_doubletap_listener();
544 } 591 }
545 592
593 void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; }
594
595 const GestureProvider::Config config_;
596 GestureProviderClient* const client_;
597
546 GestureDetector gesture_detector_; 598 GestureDetector gesture_detector_;
599 ScaleGestureDetector scale_gesture_detector_;
547 SnapScrollController snap_scroll_controller_; 600 SnapScrollController snap_scroll_controller_;
548 601
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_; 602 base::TimeTicks current_down_time_;
560 603
604 // Keeps track of the current GESTURE_LONG_PRESS event. If a context menu is
605 // opened after a GESTURE_LONG_PRESS, this is used to insert a
606 // GESTURE_TAP_CANCEL for removing any ::active styling.
607 base::TimeTicks current_longpress_time_;
608
609 // Completely silence multi-touch (pinch) scaling events. Used in WebView when
610 // zoom support is turned off.
611 bool ignore_multitouch_zoom_events_;
612
561 // TODO(klobag): This is to avoid a bug in GestureDetector. With multi-touch, 613 // 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, 614 // always_in_tap_region_ is not reset. So when the last finger is up,
563 // OnSingleTapUp() will be mistakenly fired. 615 // |OnSingleTapUp()| will be mistakenly fired.
564 bool ignore_single_tap_; 616 bool ignore_single_tap_;
565 617
566 // Used to remove the touch slop from the initial scroll event in a scroll 618 // Tracks whether {PINCH|SCROLL}_BEGIN events have been forwarded for the
567 // gesture. 619 // current touch sequence.
568 bool seen_first_scroll_event_; 620 bool pinch_event_sent_;
621 bool scroll_event_sent_;
569 622
570 DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl); 623 DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl);
571 }; 624 };
572 625
573 // GestureProvider 626 // GestureProvider
574 627
575 GestureProvider::GestureProvider(const Config& config, 628 GestureProvider::GestureProvider(const Config& config,
576 GestureProviderClient* client) 629 GestureProviderClient* client)
577 : client_(client), 630 : 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), 631 double_tap_support_for_platform_(true),
582 gesture_begin_end_types_enabled_(config.gesture_begin_end_types_enabled), 632 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); 633 DCHECK(client);
586 DCHECK(!min_gesture_bounds_length_ || !max_gesture_bounds_length_ || 634 DCHECK(!config.min_gesture_bounds_length ||
587 min_gesture_bounds_length_ <= max_gesture_bounds_length_); 635 !config.max_gesture_bounds_length ||
588 InitGestureDetectors(config); 636 config.min_gesture_bounds_length <= config.max_gesture_bounds_length);
637 TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors");
638 gesture_listener_.reset(new GestureListenerImpl(config, client));
639 UpdateDoubleTapDetectionSupport();
589 } 640 }
590 641
591 GestureProvider::~GestureProvider() {} 642 GestureProvider::~GestureProvider() {
643 }
592 644
593 bool GestureProvider::OnTouchEvent(const MotionEvent& event) { 645 bool GestureProvider::OnTouchEvent(const MotionEvent& event) {
594 TRACE_EVENT1("input", "GestureProvider::OnTouchEvent", 646 TRACE_EVENT1("input",
595 "action", GetMotionEventActionName(event.GetAction())); 647 "GestureProvider::OnTouchEvent",
648 "action",
649 GetMotionEventActionName(event.GetAction()));
596 650
597 DCHECK_NE(0u, event.GetPointerCount()); 651 DCHECK_NE(0u, event.GetPointerCount());
598 652
599 if (!CanHandle(event)) 653 if (!CanHandle(event))
600 return false; 654 return false;
601 655
602 const bool in_scale_gesture =
603 scale_gesture_listener_->IsScaleGestureDetectionInProgress();
604
605 OnTouchEventHandlingBegin(event); 656 OnTouchEventHandlingBegin(event);
606 gesture_listener_->OnTouchEvent(event, in_scale_gesture); 657 gesture_listener_->OnTouchEvent(event);
607 scale_gesture_listener_->OnTouchEvent(event);
608 OnTouchEventHandlingEnd(event); 658 OnTouchEventHandlingEnd(event);
609 return true; 659 return true;
610 } 660 }
611 661
612 void GestureProvider::SetMultiTouchZoomSupportEnabled(bool enabled) { 662 void GestureProvider::SetMultiTouchZoomSupportEnabled(bool enabled) {
613 scale_gesture_listener_->SetMultiTouchEnabled(enabled); 663 gesture_listener_->SetMultiTouchZoomEnabled(enabled);
614 } 664 }
615 665
616 void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) { 666 void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) {
617 if (double_tap_support_for_platform_ == enabled) 667 if (double_tap_support_for_platform_ == enabled)
618 return; 668 return;
619 double_tap_support_for_platform_ = enabled; 669 double_tap_support_for_platform_ = enabled;
620 UpdateDoubleTapDetectionSupport(); 670 UpdateDoubleTapDetectionSupport();
621 } 671 }
622 672
623 void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) { 673 void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) {
624 if (double_tap_support_for_page_ == enabled) 674 if (double_tap_support_for_page_ == enabled)
625 return; 675 return;
626 double_tap_support_for_page_ = enabled; 676 double_tap_support_for_page_ = enabled;
627 UpdateDoubleTapDetectionSupport(); 677 UpdateDoubleTapDetectionSupport();
628 } 678 }
629 679
630 bool GestureProvider::IsScrollInProgress() const { 680 bool GestureProvider::IsScrollInProgress() const {
631 // TODO(wangxianzhu): Also return true when fling is active once the UI knows 681 return gesture_listener_->IsScrollInProgress();
632 // exactly when the fling ends.
633 return touch_scroll_in_progress_;
634 } 682 }
635 683
636 bool GestureProvider::IsPinchInProgress() const { return pinch_in_progress_; } 684 bool GestureProvider::IsPinchInProgress() const {
685 return gesture_listener_->IsPinchInProgress();
686 }
637 687
638 bool GestureProvider::IsDoubleTapInProgress() const { 688 bool GestureProvider::IsDoubleTapInProgress() const {
639 return gesture_listener_->IsDoubleTapInProgress() || 689 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 } 690 }
656 691
657 bool GestureProvider::CanHandle(const MotionEvent& event) const { 692 bool GestureProvider::CanHandle(const MotionEvent& event) const {
658 // Aura requires one cancel event per touch point, whereas Android requires 693 // 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 694 // one cancel event per touch sequence. Thus we need to allow extra cancel
660 // events. 695 // events.
661 return event.GetAction() == MotionEvent::ACTION_DOWN || current_down_event_ || 696 return current_down_event_ || event.GetAction() == MotionEvent::ACTION_DOWN ||
662 event.GetAction() == MotionEvent::ACTION_CANCEL; 697 event.GetAction() == MotionEvent::ACTION_CANCEL;
663 } 698 }
664 699
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) { 700 void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) {
768 switch (event.GetAction()) { 701 switch (event.GetAction()) {
769 case MotionEvent::ACTION_DOWN: 702 case MotionEvent::ACTION_DOWN:
770 current_down_event_ = event.Clone(); 703 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_) 704 if (gesture_begin_end_types_enabled_)
775 Send(CreateGesture(ET_GESTURE_BEGIN, event)); 705 gesture_listener_->Send(CreateGesture(ET_GESTURE_BEGIN, event));
776 break; 706 break;
777 case MotionEvent::ACTION_POINTER_DOWN: 707 case MotionEvent::ACTION_POINTER_DOWN:
778 if (gesture_begin_end_types_enabled_) { 708 if (gesture_begin_end_types_enabled_) {
779 const int action_index = event.GetActionIndex(); 709 const int action_index = event.GetActionIndex();
780 Send(CreateGesture(ET_GESTURE_BEGIN, 710 gesture_listener_->Send(CreateGesture(ET_GESTURE_BEGIN,
781 event.GetId(), 711 event.GetId(),
782 event.GetToolType(), 712 event.GetToolType(),
783 event.GetEventTime(), 713 event.GetEventTime(),
784 event.GetX(action_index), 714 event.GetX(action_index),
785 event.GetY(action_index), 715 event.GetY(action_index),
786 event.GetRawX(action_index), 716 event.GetRawX(action_index),
787 event.GetRawY(action_index), 717 event.GetRawY(action_index),
788 event.GetPointerCount(), 718 event.GetPointerCount(),
789 GetBoundingBox(event))); 719 GetBoundingBox(event)));
790 } 720 }
791 break; 721 break;
792 case MotionEvent::ACTION_POINTER_UP: 722 case MotionEvent::ACTION_POINTER_UP:
793 case MotionEvent::ACTION_UP: 723 case MotionEvent::ACTION_UP:
794 case MotionEvent::ACTION_CANCEL: 724 case MotionEvent::ACTION_CANCEL:
795 case MotionEvent::ACTION_MOVE: 725 case MotionEvent::ACTION_MOVE:
796 break; 726 break;
797 } 727 }
798 } 728 }
799 729
800 void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) { 730 void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) {
801 switch (event.GetAction()) { 731 switch (event.GetAction()) {
802 case MotionEvent::ACTION_UP: 732 case MotionEvent::ACTION_UP:
803 case MotionEvent::ACTION_CANCEL: { 733 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_) 734 if (gesture_begin_end_types_enabled_)
809 Send(CreateGesture(ET_GESTURE_END, event)); 735 gesture_listener_->Send(CreateGesture(ET_GESTURE_END, event));
810 736
811 current_down_event_.reset(); 737 current_down_event_.reset();
812 738
813 UpdateDoubleTapDetectionSupport(); 739 UpdateDoubleTapDetectionSupport();
814 break; 740 break;
815 } 741 }
816 case MotionEvent::ACTION_POINTER_UP: 742 case MotionEvent::ACTION_POINTER_UP:
817 if (gesture_begin_end_types_enabled_) 743 if (gesture_begin_end_types_enabled_)
818 Send(CreateGesture(ET_GESTURE_END, event)); 744 gesture_listener_->Send(CreateGesture(ET_GESTURE_END, event));
819 break; 745 break;
820 case MotionEvent::ACTION_DOWN: 746 case MotionEvent::ACTION_DOWN:
821 case MotionEvent::ACTION_POINTER_DOWN: 747 case MotionEvent::ACTION_POINTER_DOWN:
822 case MotionEvent::ACTION_MOVE: 748 case MotionEvent::ACTION_MOVE:
823 break; 749 break;
824 } 750 }
825 } 751 }
826 752
827 void GestureProvider::UpdateDoubleTapDetectionSupport() { 753 void GestureProvider::UpdateDoubleTapDetectionSupport() {
828 // The GestureDetector requires that any provided DoubleTapListener remain 754 // The GestureDetector requires that any provided DoubleTapListener remain
829 // attached to it for the duration of a touch sequence. Defer any potential 755 // attached to it for the duration of a touch sequence. Defer any potential
830 // null'ing of the listener until the sequence has ended. 756 // null'ing of the listener until the sequence has ended.
831 if (current_down_event_) 757 if (current_down_event_)
832 return; 758 return;
833 759
834 const bool double_tap_enabled = double_tap_support_for_page_ && 760 const bool double_tap_enabled =
835 double_tap_support_for_platform_; 761 double_tap_support_for_page_ && double_tap_support_for_platform_;
836 gesture_listener_->SetDoubleTapEnabled(double_tap_enabled); 762 gesture_listener_->SetDoubleTapEnabled(double_tap_enabled);
837 scale_gesture_listener_->SetDoubleTapEnabled(double_tap_enabled);
838 } 763 }
839 764
840 } // namespace ui 765 } // namespace ui
OLDNEW
« no previous file with comments | « ui/events/gesture_detection/gesture_provider.h ('k') | ui/events/gesture_detection/gesture_provider_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698