| OLD | NEW |
| 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 Loading... |
| 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 |
| OLD | NEW |