Chromium Code Reviews| Index: ui/events/gesture_detection/gesture_provider.cc |
| diff --git a/ui/events/gesture_detection/gesture_provider.cc b/ui/events/gesture_detection/gesture_provider.cc |
| index e38957ab31c4fcefccf0417e5ffe2c042a760b37..7699e48d670d6c1f47636d5fe2f885c64ebe2e23 100644 |
| --- a/ui/events/gesture_detection/gesture_provider.cc |
| +++ b/ui/events/gesture_detection/gesture_provider.cc |
| @@ -19,13 +19,19 @@ namespace { |
| const float kDoubleTapDragZoomSpeed = 0.005f; |
| const char* GetMotionEventActionName(MotionEvent::Action action) { |
| - switch(action) { |
| - case MotionEvent::ACTION_POINTER_DOWN: return "ACTION_POINTER_DOWN"; |
| - case MotionEvent::ACTION_POINTER_UP: return "ACTION_POINTER_UP"; |
| - case MotionEvent::ACTION_DOWN: return "ACTION_DOWN"; |
| - case MotionEvent::ACTION_UP: return "ACTION_UP"; |
| - case MotionEvent::ACTION_CANCEL: return "ACTION_CANCEL"; |
| - case MotionEvent::ACTION_MOVE: return "ACTION_MOVE"; |
| + switch (action) { |
| + case MotionEvent::ACTION_POINTER_DOWN: |
| + return "ACTION_POINTER_DOWN"; |
| + case MotionEvent::ACTION_POINTER_UP: |
| + return "ACTION_POINTER_UP"; |
| + case MotionEvent::ACTION_DOWN: |
| + return "ACTION_DOWN"; |
| + case MotionEvent::ACTION_UP: |
| + return "ACTION_UP"; |
| + case MotionEvent::ACTION_CANCEL: |
| + return "ACTION_CANCEL"; |
| + case MotionEvent::ACTION_MOVE: |
| + return "ACTION_MOVE"; |
| } |
| return ""; |
| } |
| @@ -110,12 +116,11 @@ GestureEventData CreateGesture(EventType type, const MotionEvent& event) { |
| return CreateGesture(GestureEventDetails(type, 0, 0), event); |
| } |
| -GestureEventDetails CreateTapGestureDetails(EventType type) { |
| +GestureEventData CreateTapGesture(EventType type, const MotionEvent& event) { |
| // Set the tap count to 1 even for ET_GESTURE_DOUBLE_TAP, in order to be |
| // consistent with double tap behavior on a mobile viewport. See |
| // crbug.com/234986 for context. |
| - GestureEventDetails tap_details(type, 1, 0); |
| - return tap_details; |
| + return CreateGesture(GestureEventDetails(type, 1, 0), event); |
| } |
| gfx::RectF ClampBoundingBox(const gfx::RectF& bounds, |
| @@ -145,41 +150,128 @@ GestureProvider::Config::Config() |
| disable_click_delay(false), |
| gesture_begin_end_types_enabled(false), |
| min_gesture_bounds_length(0), |
| - max_gesture_bounds_length(0) {} |
| + max_gesture_bounds_length(0) { |
| +} |
| -GestureProvider::Config::~Config() {} |
| +GestureProvider::Config::~Config() { |
| +} |
| -// GestureProvider::ScaleGestureListener |
| +// GestureProvider::GestureListener |
| -class GestureProvider::ScaleGestureListenerImpl |
| - : public ScaleGestureDetector::ScaleGestureListener { |
| +class GestureProvider::GestureListenerImpl |
| + : public ScaleGestureDetector::ScaleGestureListener, |
| + public GestureDetector::GestureListener, |
| + public GestureDetector::DoubleTapListener { |
| public: |
| - ScaleGestureListenerImpl(const ScaleGestureDetector::Config& config, |
| - GestureProvider* provider) |
| - : scale_gesture_detector_(config, this), |
| - provider_(provider), |
| - ignore_multitouch_events_(false), |
| + GestureListenerImpl(const GestureProvider::Config& config, |
| + GestureProviderClient* client) |
| + : config_(config), |
| + client_(client), |
| + gesture_detector_(config.gesture_detector_config, this, this), |
| + scale_gesture_detector_(config.scale_gesture_detector_config, this), |
| + snap_scroll_controller_(config.display), |
| + ignore_multitouch_zoom_events_(false), |
| + ignore_single_tap_(false), |
| pinch_event_sent_(false), |
| - min_pinch_update_span_delta_(config.min_pinch_update_span_delta) {} |
| + scroll_event_sent_(false) {} |
| - bool OnTouchEvent(const MotionEvent& event) { |
| - // TODO: Need to deal with multi-touch transition. |
| + void OnTouchEvent(const MotionEvent& event) { |
| const bool in_scale_gesture = IsScaleGestureDetectionInProgress(); |
| - bool handled = scale_gesture_detector_.OnTouchEvent(event); |
| - if (!in_scale_gesture && |
| - (event.GetAction() == MotionEvent::ACTION_UP || |
| - event.GetAction() == MotionEvent::ACTION_CANCEL)) { |
| - return false; |
| + snap_scroll_controller_.SetSnapScrollingMode(event, in_scale_gesture); |
| + if (in_scale_gesture) |
| + SetIgnoreSingleTap(true); |
| + |
| + const MotionEvent::Action action = event.GetAction(); |
| + if (action == MotionEvent::ACTION_DOWN) { |
| + current_down_time_ = event.GetEventTime(); |
| + current_longpress_time_ = base::TimeTicks(); |
| + ignore_single_tap_ = false; |
| + scroll_event_sent_ = false; |
| + pinch_event_sent_ = false; |
| + gesture_detector_.set_longpress_enabled(true); |
| + } |
| + |
| + gesture_detector_.OnTouchEvent(event); |
| + scale_gesture_detector_.OnTouchEvent(event); |
| + |
| + if (action == MotionEvent::ACTION_UP || |
| + action == MotionEvent::ACTION_CANCEL) { |
| + // Note: This call will have no effect if a fling was just generated, as |
| + // |Fling()| will have already signalled an end to touch-scrolling. |
| + if (scroll_event_sent_) |
| + Send(CreateGesture(ET_GESTURE_SCROLL_END, event)); |
| + current_down_time_ = base::TimeTicks(); |
| + } |
| + } |
| + |
| + void Send(GestureEventData gesture) { |
| + DCHECK(!gesture.time.is_null()); |
| + // The only valid events that should be sent without an active touch |
| + // sequence are SHOW_PRESS and TAP, potentially triggered by the double-tap |
| + // delay timing out. |
| + DCHECK(!current_down_time_.is_null() || gesture.type() == ET_GESTURE_TAP || |
| + gesture.type() == ET_GESTURE_SHOW_PRESS || |
| + gesture.type() == ET_GESTURE_BEGIN || |
| + gesture.type() == ET_GESTURE_END); |
| + |
| + if (gesture.primary_tool_type == MotionEvent::TOOL_TYPE_UNKNOWN || |
| + gesture.primary_tool_type == MotionEvent::TOOL_TYPE_FINGER) { |
| + gesture.details.set_bounding_box( |
| + ClampBoundingBox(gesture.details.bounding_box_f(), |
| + config_.min_gesture_bounds_length, |
| + config_.max_gesture_bounds_length)); |
| } |
| - return handled; |
| + |
| + switch (gesture.type()) { |
| + case ET_GESTURE_LONG_PRESS: |
| + DCHECK(!IsScaleGestureDetectionInProgress()); |
| + current_longpress_time_ = gesture.time; |
| + break; |
| + case ET_GESTURE_LONG_TAP: |
| + current_longpress_time_ = base::TimeTicks(); |
| + break; |
| + case ET_GESTURE_SCROLL_BEGIN: |
| + DCHECK(!scroll_event_sent_); |
| + scroll_event_sent_ = true; |
| + break; |
| + case ET_GESTURE_SCROLL_END: |
| + DCHECK(scroll_event_sent_); |
| + if (pinch_event_sent_) |
| + Send(GestureEventData(ET_GESTURE_PINCH_END, gesture)); |
| + scroll_event_sent_ = false; |
| + break; |
| + case ET_SCROLL_FLING_START: |
| + DCHECK(scroll_event_sent_); |
| + scroll_event_sent_ = false; |
| + break; |
| + case ET_GESTURE_PINCH_BEGIN: |
| + DCHECK(!pinch_event_sent_); |
| + if (!scroll_event_sent_) |
| + Send(GestureEventData(ET_GESTURE_SCROLL_BEGIN, gesture)); |
| + pinch_event_sent_ = true; |
| + break; |
| + case ET_GESTURE_PINCH_END: |
| + DCHECK(pinch_event_sent_); |
| + pinch_event_sent_ = false; |
| + break; |
| + case ET_GESTURE_SHOW_PRESS: |
| + // It's possible that a double-tap drag zoom (from ScaleGestureDetector) |
| + // will start before the press gesture fires (from GestureDetector), in |
| + // which case the press should simply be dropped. |
| + if (pinch_event_sent_ || scroll_event_sent_) |
| + return; |
| + default: |
| + break; |
| + }; |
| + |
| + client_->OnGestureEvent(gesture); |
| } |
| // ScaleGestureDetector::ScaleGestureListener implementation. |
| virtual bool OnScaleBegin(const ScaleGestureDetector& detector, |
| const MotionEvent& e) OVERRIDE { |
| - if (ignore_multitouch_events_ && !detector.InDoubleTapMode()) |
| + if (ignore_multitouch_zoom_events_ && !detector.InDoubleTapMode()) |
| return false; |
| - pinch_event_sent_ = false; |
| return true; |
| } |
| @@ -187,30 +279,28 @@ class GestureProvider::ScaleGestureListenerImpl |
| const MotionEvent& e) OVERRIDE { |
| if (!pinch_event_sent_) |
| return; |
| - provider_->Send(CreateGesture(ET_GESTURE_PINCH_END, e)); |
| - pinch_event_sent_ = false; |
| + Send(CreateGesture(ET_GESTURE_PINCH_END, e)); |
| } |
| virtual bool OnScale(const ScaleGestureDetector& detector, |
| const MotionEvent& e) OVERRIDE { |
| - if (ignore_multitouch_events_ && !detector.InDoubleTapMode()) |
| + if (ignore_multitouch_zoom_events_ && !detector.InDoubleTapMode()) |
| return false; |
| if (!pinch_event_sent_) { |
| - pinch_event_sent_ = true; |
| - provider_->Send(CreateGesture(ET_GESTURE_PINCH_BEGIN, |
| - e.GetId(), |
| - e.GetToolType(), |
| - detector.GetEventTime(), |
| - detector.GetFocusX(), |
| - detector.GetFocusY(), |
| - detector.GetFocusX() + e.GetRawOffsetX(), |
| - detector.GetFocusY() + e.GetRawOffsetY(), |
| - e.GetPointerCount(), |
| - GetBoundingBox(e))); |
| + Send(CreateGesture(ET_GESTURE_PINCH_BEGIN, |
| + e.GetId(), |
| + e.GetToolType(), |
| + detector.GetEventTime(), |
| + detector.GetFocusX(), |
| + detector.GetFocusY(), |
| + detector.GetFocusX() + e.GetRawOffsetX(), |
| + detector.GetFocusY() + e.GetRawOffsetY(), |
| + e.GetPointerCount(), |
| + GetBoundingBox(e))); |
| } |
| if (std::abs(detector.GetCurrentSpan() - detector.GetPreviousSpan()) < |
| - min_pinch_update_span_delta_) { |
| + config_.scale_gesture_detector_config.min_pinch_update_span_delta) { |
| return false; |
| } |
| @@ -231,107 +321,23 @@ class GestureProvider::ScaleGestureListenerImpl |
| std::abs(dy)); |
| } |
| GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0); |
| - provider_->Send(CreateGesture(pinch_details, |
| - e.GetId(), |
| - e.GetToolType(), |
| - detector.GetEventTime(), |
| - detector.GetFocusX(), |
| - detector.GetFocusY(), |
| - detector.GetFocusX() + e.GetRawOffsetX(), |
| - detector.GetFocusY() + e.GetRawOffsetY(), |
| - e.GetPointerCount(), |
| - GetBoundingBox(e))); |
| + Send(CreateGesture(pinch_details, |
| + e.GetId(), |
| + e.GetToolType(), |
| + detector.GetEventTime(), |
| + detector.GetFocusX(), |
| + detector.GetFocusY(), |
| + detector.GetFocusX() + e.GetRawOffsetX(), |
| + detector.GetFocusY() + e.GetRawOffsetY(), |
| + e.GetPointerCount(), |
| + GetBoundingBox(e))); |
| return true; |
| } |
| - void SetDoubleTapEnabled(bool enabled) { |
| - DCHECK(!IsDoubleTapInProgress()); |
| - scale_gesture_detector_.SetQuickScaleEnabled(enabled); |
| - } |
| - |
| - void SetMultiTouchEnabled(bool enabled) { |
| - // Note that returning false from OnScaleBegin / OnScale makes the |
| - // gesture detector not to emit further scaling notifications |
| - // related to this gesture. Thus, if detector events are enabled in |
| - // the middle of the gesture, we don't need to do anything. |
| - ignore_multitouch_events_ = !enabled; |
| - } |
| - |
| - bool IsDoubleTapInProgress() const { |
| - return IsScaleGestureDetectionInProgress() && InDoubleTapMode(); |
| - } |
| - |
| - bool IsScaleGestureDetectionInProgress() const { |
| - return scale_gesture_detector_.IsInProgress(); |
| - } |
| - |
| - private: |
| - bool InDoubleTapMode() const { |
| - return scale_gesture_detector_.InDoubleTapMode(); |
| - } |
| - |
| - ScaleGestureDetector scale_gesture_detector_; |
| - |
| - GestureProvider* const provider_; |
| - |
| - // Completely silence multi-touch (pinch) scaling events. Used in WebView when |
| - // zoom support is turned off. |
| - bool ignore_multitouch_events_; |
| - |
| - // Whether any pinch zoom event has been sent to native. |
| - bool pinch_event_sent_; |
| - |
| - // The minimum change in span required before this is considered a pinch. See |
| - // crbug.com/373318. |
| - float min_pinch_update_span_delta_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(ScaleGestureListenerImpl); |
| -}; |
| - |
| -// GestureProvider::GestureListener |
| - |
| -class GestureProvider::GestureListenerImpl |
| - : public GestureDetector::GestureListener, |
| - public GestureDetector::DoubleTapListener { |
| - public: |
| - GestureListenerImpl( |
| - const gfx::Display& display, |
| - const GestureDetector::Config& gesture_detector_config, |
| - bool disable_click_delay, |
| - GestureProvider* provider) |
| - : gesture_detector_(gesture_detector_config, this, this), |
| - snap_scroll_controller_(display), |
| - provider_(provider), |
| - disable_click_delay_(disable_click_delay), |
| - touch_slop_(gesture_detector_config.touch_slop), |
| - double_tap_timeout_(gesture_detector_config.double_tap_timeout), |
| - ignore_single_tap_(false), |
| - seen_first_scroll_event_(false) {} |
| - |
| - virtual ~GestureListenerImpl() {} |
| - |
| - bool OnTouchEvent(const MotionEvent& e, |
| - bool is_scale_gesture_detection_in_progress) { |
| - snap_scroll_controller_.SetSnapScrollingMode( |
| - e, is_scale_gesture_detection_in_progress); |
| - |
| - if (is_scale_gesture_detection_in_progress) |
| - SetIgnoreSingleTap(true); |
| - |
| - if (e.GetAction() == MotionEvent::ACTION_DOWN) |
| - gesture_detector_.set_longpress_enabled(true); |
| - |
| - return gesture_detector_.OnTouchEvent(e); |
| - } |
| - |
| // GestureDetector::GestureListener implementation. |
| virtual bool OnDown(const MotionEvent& e) OVERRIDE { |
| - current_down_time_ = e.GetEventTime(); |
| - ignore_single_tap_ = false; |
| - seen_first_scroll_event_ = false; |
| - |
| GestureEventDetails tap_details(ET_GESTURE_TAP_DOWN, 0, 0); |
| - provider_->Send(CreateGesture(tap_details, e)); |
| + Send(CreateGesture(tap_details, e)); |
| // Return true to indicate that we want to handle touch. |
| return true; |
| @@ -343,29 +349,21 @@ class GestureProvider::GestureListenerImpl |
| float raw_distance_y) OVERRIDE { |
| float distance_x = raw_distance_x; |
| float distance_y = raw_distance_y; |
| - if (!seen_first_scroll_event_) { |
| + if (!scroll_event_sent_) { |
| // Remove the touch slop region from the first scroll event to avoid a |
| // jump. |
| - seen_first_scroll_event_ = true; |
| double distance = |
| std::sqrt(distance_x * distance_x + distance_y * distance_y); |
| double epsilon = 1e-3; |
| if (distance > epsilon) { |
| - double ratio = std::max(0., distance - touch_slop_) / distance; |
| + double ratio = |
| + std::max(0., |
| + distance - config_.gesture_detector_config.touch_slop) / |
| + distance; |
| distance_x *= ratio; |
| distance_y *= ratio; |
| } |
| - } |
| - snap_scroll_controller_.UpdateSnapScrollMode(distance_x, distance_y); |
| - if (snap_scroll_controller_.IsSnappingScrolls()) { |
| - if (snap_scroll_controller_.IsSnapHorizontal()) { |
| - distance_y = 0; |
| - } else { |
| - distance_x = 0; |
| - } |
| - } |
| - if (!provider_->IsScrollInProgress()) { |
| // Note that scroll start hints are in distance traveled, where |
| // scroll deltas are in the opposite direction. |
| GestureEventDetails scroll_details( |
| @@ -373,16 +371,26 @@ class GestureProvider::GestureListenerImpl |
| // Use the co-ordinates from the touch down, as these co-ordinates are |
| // used to determine which layer the scroll should affect. |
| - provider_->Send(CreateGesture(scroll_details, |
| - e2.GetId(), |
| - e2.GetToolType(), |
| - e2.GetEventTime(), |
| - e1.GetX(), |
| - e1.GetY(), |
| - e1.GetRawX(), |
| - e1.GetRawY(), |
| - e2.GetPointerCount(), |
| - GetBoundingBox(e2))); |
| + Send(CreateGesture(scroll_details, |
| + e2.GetId(), |
| + e2.GetToolType(), |
| + e2.GetEventTime(), |
| + e1.GetX(), |
| + e1.GetY(), |
| + e1.GetRawX(), |
| + e1.GetRawY(), |
| + e2.GetPointerCount(), |
| + GetBoundingBox(e2))); |
| + DCHECK(scroll_event_sent_); |
| + } |
| + |
| + snap_scroll_controller_.UpdateSnapScrollMode(distance_x, distance_y); |
| + if (snap_scroll_controller_.IsSnappingScrolls()) { |
| + if (snap_scroll_controller_.IsSnapHorizontal()) { |
|
tdresser
2014/08/22 18:19:04
While you're here, you could switch to a braceless
jdduke (slow)
2014/08/22 20:33:10
Done.
|
| + distance_y = 0; |
| + } else { |
| + distance_x = 0; |
| + } |
| } |
| if (distance_x || distance_y) { |
| @@ -392,16 +400,16 @@ class GestureProvider::GestureListenerImpl |
| center + gfx::Vector2dF(e2.GetRawOffsetX(), e2.GetRawOffsetY()); |
| GestureEventDetails scroll_details( |
| ET_GESTURE_SCROLL_UPDATE, -distance_x, -distance_y); |
| - provider_->Send(CreateGesture(scroll_details, |
| - e2.GetId(), |
| - e2.GetToolType(), |
| - e2.GetEventTime(), |
| - center.x(), |
| - center.y(), |
| - raw_center.x(), |
| - raw_center.y(), |
| - e2.GetPointerCount(), |
| - bounding_box)); |
| + Send(CreateGesture(scroll_details, |
| + e2.GetId(), |
| + e2.GetToolType(), |
| + e2.GetEventTime(), |
| + center.x(), |
| + center.y(), |
| + raw_center.x(), |
| + raw_center.y(), |
| + e2.GetPointerCount(), |
| + bounding_box)); |
| } |
| return true; |
| @@ -419,7 +427,21 @@ class GestureProvider::GestureListenerImpl |
| } |
| } |
| - provider_->Fling(e2, velocity_x, velocity_y); |
| + if (!velocity_x && !velocity_y) |
| + return true; |
| + |
| + if (!scroll_event_sent_) { |
| + // The native side needs a ET_GESTURE_SCROLL_BEGIN before |
| + // ET_SCROLL_FLING_START to send the fling to the correct target. |
| + // The distance traveled in one second is a reasonable scroll start hint. |
| + GestureEventDetails scroll_details( |
| + ET_GESTURE_SCROLL_BEGIN, velocity_x, velocity_y); |
| + Send(CreateGesture(scroll_details, e2)); |
| + } |
| + |
| + GestureEventDetails fling_details( |
| + ET_SCROLL_FLING_START, velocity_x, velocity_y); |
| + Send(CreateGesture(fling_details, e2)); |
| return true; |
| } |
| @@ -428,7 +450,7 @@ class GestureProvider::GestureListenerImpl |
| float velocity_x, |
| float velocity_y) OVERRIDE { |
| GestureEventDetails swipe_details(ET_GESTURE_SWIPE, velocity_x, velocity_y); |
| - provider_->Send(CreateGesture(swipe_details, e2)); |
| + Send(CreateGesture(swipe_details, e2)); |
| return true; |
| } |
| @@ -436,25 +458,24 @@ class GestureProvider::GestureListenerImpl |
| const MotionEvent& e2) OVERRIDE { |
| // The location of the two finger tap event should be the location of the |
| // primary pointer. |
| - GestureEventDetails two_finger_tap_details(ET_GESTURE_TWO_FINGER_TAP, |
| - e1.GetTouchMajor(), |
| - e1.GetTouchMajor()); |
| - provider_->Send(CreateGesture(two_finger_tap_details, |
| - e2.GetId(), |
| - e2.GetToolType(), |
| - e2.GetEventTime(), |
| - e1.GetX(), |
| - e1.GetY(), |
| - e1.GetRawX(), |
| - e1.GetRawY(), |
| - e2.GetPointerCount(), |
| - GetBoundingBox(e2))); |
| + GestureEventDetails two_finger_tap_details( |
| + ET_GESTURE_TWO_FINGER_TAP, e1.GetTouchMajor(), e1.GetTouchMajor()); |
| + Send(CreateGesture(two_finger_tap_details, |
| + e2.GetId(), |
| + e2.GetToolType(), |
| + e2.GetEventTime(), |
| + e1.GetX(), |
| + e1.GetY(), |
| + e1.GetRawX(), |
| + e1.GetRawY(), |
| + e2.GetPointerCount(), |
| + GetBoundingBox(e2))); |
| return true; |
| } |
| virtual void OnShowPress(const MotionEvent& e) OVERRIDE { |
| GestureEventDetails show_press_details(ET_GESTURE_SHOW_PRESS, 0, 0); |
| - provider_->Send(CreateGesture(show_press_details, e)); |
| + Send(CreateGesture(show_press_details, e)); |
| } |
| virtual bool OnSingleTapUp(const MotionEvent& e) OVERRIDE { |
| @@ -465,21 +486,29 @@ class GestureProvider::GestureListenerImpl |
| // OnSingleTapUp() in this case. This assumes singleTapUp |
| // gets always called before singleTapConfirmed. |
| if (!ignore_single_tap_) { |
| - if (e.GetEventTime() - current_down_time_ > double_tap_timeout_) { |
| + if (e.GetEventTime() - current_down_time_ > |
| + config_.gesture_detector_config.double_tap_timeout) { |
| return OnSingleTapConfirmed(e); |
| - } else if (!IsDoubleTapEnabled() || disable_click_delay_) { |
| + } else if (!IsDoubleTapEnabled() || config_.disable_click_delay) { |
| // If double-tap has been disabled, there is no need to wait |
| // for the double-tap timeout. |
| return OnSingleTapConfirmed(e); |
| } else { |
| // Notify Blink about this tapUp event anyway, when none of the above |
| // conditions applied. |
| - provider_->Send(CreateGesture( |
| - CreateTapGestureDetails(ET_GESTURE_TAP_UNCONFIRMED), e)); |
| + Send(CreateTapGesture(ET_GESTURE_TAP_UNCONFIRMED, e)); |
| } |
| } |
| - return provider_->SendLongTapIfNecessary(e); |
| + if (e.GetAction() == MotionEvent::ACTION_UP && |
| + !current_longpress_time_.is_null() && |
| + !IsScaleGestureDetectionInProgress()) { |
| + GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP, 0, 0); |
| + Send(CreateGesture(long_tap_details, e)); |
| + return true; |
| + } |
| + |
| + return false; |
| } |
| // GestureDetector::DoubleTapListener implementation. |
| @@ -493,11 +522,13 @@ class GestureProvider::GestureListenerImpl |
| ignore_single_tap_ = true; |
| - provider_->Send(CreateGesture(CreateTapGestureDetails(ET_GESTURE_TAP), e)); |
| + Send(CreateTapGesture(ET_GESTURE_TAP, e)); |
| return true; |
| } |
| - virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { return false; } |
| + virtual bool OnDoubleTap(const MotionEvent& e) OVERRIDE { |
| + return scale_gesture_detector_.OnDoubleTap(e); |
| + } |
| virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE { |
| switch (e.GetAction()) { |
| @@ -506,13 +537,12 @@ class GestureProvider::GestureListenerImpl |
| break; |
| case MotionEvent::ACTION_UP: |
| - if (!provider_->IsPinchInProgress() && |
| - !provider_->IsScrollInProgress()) { |
| - provider_->Send( |
| - CreateGesture(CreateTapGestureDetails(ET_GESTURE_DOUBLE_TAP), e)); |
| + if (!IsPinchInProgress() && !IsScrollInProgress()) { |
| + Send(CreateTapGesture(ET_GESTURE_DOUBLE_TAP, e)); |
| return true; |
| } |
| break; |
| + |
| default: |
| break; |
| } |
| @@ -522,9 +552,8 @@ class GestureProvider::GestureListenerImpl |
| virtual void OnLongPress(const MotionEvent& e) OVERRIDE { |
| DCHECK(!IsDoubleTapInProgress()); |
| SetIgnoreSingleTap(true); |
| - |
| GestureEventDetails long_press_details(ET_GESTURE_LONG_PRESS, 0, 0); |
| - provider_->Send(CreateGesture(long_press_details, e)); |
| + Send(CreateGesture(long_press_details, e)); |
| } |
| void SetDoubleTapEnabled(bool enabled) { |
| @@ -532,40 +561,65 @@ class GestureProvider::GestureListenerImpl |
| gesture_detector_.SetDoubleTapListener(enabled ? this : NULL); |
| } |
| + void SetMultiTouchZoomEnabled(bool enabled) { |
| + // Note that returning false from OnScaleBegin / OnScale makes the |
| + // gesture detector not to emit further scaling notifications |
|
tdresser
2014/08/22 18:19:04
Might as well reword this comment while you're her
jdduke (slow)
2014/08/22 20:33:09
Ah, yeah this can be cleaned up. I think we still
|
| + // related to this gesture. Thus, if detector events are enabled in |
| + // the middle of the gesture, we don't need to do anything. |
| + ignore_multitouch_zoom_events_ = !enabled; |
| + } |
| + |
| bool IsDoubleTapInProgress() const { |
| - return gesture_detector_.is_double_tapping(); |
| + return gesture_detector_.is_double_tapping() || |
| + (IsScaleGestureDetectionInProgress() && InDoubleTapMode()); |
| } |
| + bool IsScrollInProgress() const { return scroll_event_sent_; } |
| + |
| + bool IsPinchInProgress() const { return pinch_event_sent_; } |
| + |
| private: |
| - void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; } |
| + bool IsScaleGestureDetectionInProgress() const { |
| + return scale_gesture_detector_.IsInProgress(); |
| + } |
| + |
| + bool InDoubleTapMode() const { |
| + return scale_gesture_detector_.InDoubleTapMode(); |
| + } |
| bool IsDoubleTapEnabled() const { |
| return gesture_detector_.has_doubletap_listener(); |
| } |
| - GestureDetector gesture_detector_; |
| - SnapScrollController snap_scroll_controller_; |
| + void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; } |
| - GestureProvider* const provider_; |
| + const GestureProvider::Config config_; |
| + GestureProviderClient* const client_; |
| - // Whether the click delay should always be disabled by sending clicks for |
| - // double-tap gestures. |
| - const bool disable_click_delay_; |
| + GestureDetector gesture_detector_; |
| + ScaleGestureDetector scale_gesture_detector_; |
| + SnapScrollController snap_scroll_controller_; |
| - const float touch_slop_; |
| + base::TimeTicks current_down_time_; |
| - const base::TimeDelta double_tap_timeout_; |
| + // Keeps track of the current GESTURE_LONG_PRESS event. If a context menu is |
| + // opened after a GESTURE_LONG_PRESS, this is used to insert a |
| + // GESTURE_TAP_CANCEL for removing any ::active styling. |
| + base::TimeTicks current_longpress_time_; |
| - base::TimeTicks current_down_time_; |
| + // Completely silence multi-touch (pinch) scaling events. Used in WebView when |
| + // zoom support is turned off. |
| + bool ignore_multitouch_zoom_events_; |
| // TODO(klobag): This is to avoid a bug in GestureDetector. With multi-touch, |
| // always_in_tap_region_ is not reset. So when the last finger is up, |
| - // OnSingleTapUp() will be mistakenly fired. |
| + // |OnSingleTapUp()| will be mistakenly fired. |
| bool ignore_single_tap_; |
| - // Used to remove the touch slop from the initial scroll event in a scroll |
| - // gesture. |
| - bool seen_first_scroll_event_; |
| + // Tracks whether {PINCH|SCROLL|_BEGIN events have been forwadred for the |
|
tdresser
2014/08/22 18:19:04
forwadred -> forwarded
{PINCH|SCROLL|_BEGIN -> ...
jdduke (slow)
2014/08/22 20:33:09
Done.
|
| + // current touch sequence. |
| + bool pinch_event_sent_; |
| + bool scroll_event_sent_; |
| DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl); |
| }; |
| @@ -574,43 +628,40 @@ class GestureProvider::GestureListenerImpl |
| GestureProvider::GestureProvider(const Config& config, |
| GestureProviderClient* client) |
| - : client_(client), |
| - touch_scroll_in_progress_(false), |
| - pinch_in_progress_(false), |
| - double_tap_support_for_page_(true), |
| + : double_tap_support_for_page_(true), |
| double_tap_support_for_platform_(true), |
| - gesture_begin_end_types_enabled_(config.gesture_begin_end_types_enabled), |
| - min_gesture_bounds_length_(config.min_gesture_bounds_length), |
| - max_gesture_bounds_length_(config.max_gesture_bounds_length) { |
| + gesture_begin_end_types_enabled_(config.gesture_begin_end_types_enabled) { |
| DCHECK(client); |
| - DCHECK(!min_gesture_bounds_length_ || !max_gesture_bounds_length_ || |
| - min_gesture_bounds_length_ <= max_gesture_bounds_length_); |
| - InitGestureDetectors(config); |
| + DCHECK(!config.min_gesture_bounds_length || |
| + !config.max_gesture_bounds_length || |
| + config.min_gesture_bounds_length <= config.max_gesture_bounds_length); |
| + TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors"); |
| + gesture_listener_.reset(new GestureListenerImpl(config, client)); |
| + UpdateDoubleTapDetectionSupport(); |
| } |
| -GestureProvider::~GestureProvider() {} |
| +GestureProvider::~GestureProvider() { |
| +} |
| bool GestureProvider::OnTouchEvent(const MotionEvent& event) { |
| - TRACE_EVENT1("input", "GestureProvider::OnTouchEvent", |
| - "action", GetMotionEventActionName(event.GetAction())); |
| + TRACE_EVENT1("input", |
| + "GestureProvider::OnTouchEvent", |
| + "action", |
| + GetMotionEventActionName(event.GetAction())); |
| DCHECK_NE(0u, event.GetPointerCount()); |
| if (!CanHandle(event)) |
| return false; |
| - const bool in_scale_gesture = |
| - scale_gesture_listener_->IsScaleGestureDetectionInProgress(); |
| - |
| OnTouchEventHandlingBegin(event); |
| - gesture_listener_->OnTouchEvent(event, in_scale_gesture); |
| - scale_gesture_listener_->OnTouchEvent(event); |
| + gesture_listener_->OnTouchEvent(event); |
| OnTouchEventHandlingEnd(event); |
| return true; |
| } |
| void GestureProvider::SetMultiTouchZoomSupportEnabled(bool enabled) { |
| - scale_gesture_listener_->SetMultiTouchEnabled(enabled); |
| + gesture_listener_->SetMultiTouchZoomEnabled(enabled); |
| } |
| void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) { |
| @@ -628,165 +679,45 @@ void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) { |
| } |
| bool GestureProvider::IsScrollInProgress() const { |
| - // TODO(wangxianzhu): Also return true when fling is active once the UI knows |
| - // exactly when the fling ends. |
| - return touch_scroll_in_progress_; |
| + return gesture_listener_->IsScrollInProgress(); |
| } |
| -bool GestureProvider::IsPinchInProgress() const { return pinch_in_progress_; } |
| - |
| -bool GestureProvider::IsDoubleTapInProgress() const { |
| - return gesture_listener_->IsDoubleTapInProgress() || |
| - scale_gesture_listener_->IsDoubleTapInProgress(); |
| +bool GestureProvider::IsPinchInProgress() const { |
| + return gesture_listener_->IsPinchInProgress(); |
| } |
| -void GestureProvider::InitGestureDetectors(const Config& config) { |
| - TRACE_EVENT0("input", "GestureProvider::InitGestureDetectors"); |
| - gesture_listener_.reset( |
| - new GestureListenerImpl(config.display, |
| - config.gesture_detector_config, |
| - config.disable_click_delay, |
| - this)); |
| - |
| - scale_gesture_listener_.reset( |
| - new ScaleGestureListenerImpl(config.scale_gesture_detector_config, this)); |
| - |
| - UpdateDoubleTapDetectionSupport(); |
| +bool GestureProvider::IsDoubleTapInProgress() const { |
| + return gesture_listener_->IsDoubleTapInProgress(); |
| } |
| bool GestureProvider::CanHandle(const MotionEvent& event) const { |
| // Aura requires one cancel event per touch point, whereas Android requires |
| // one cancel event per touch sequence. Thus we need to allow extra cancel |
| // events. |
| - return event.GetAction() == MotionEvent::ACTION_DOWN || current_down_event_ || |
| + return current_down_event_ || event.GetAction() == MotionEvent::ACTION_DOWN || |
| event.GetAction() == MotionEvent::ACTION_CANCEL; |
| } |
| -void GestureProvider::Fling(const MotionEvent& event, |
| - float velocity_x, |
| - float velocity_y) { |
| - if (!velocity_x && !velocity_y) { |
| - EndTouchScrollIfNecessary(event, true); |
| - return; |
| - } |
| - |
| - if (!touch_scroll_in_progress_) { |
| - // The native side needs a ET_GESTURE_SCROLL_BEGIN before |
| - // ET_SCROLL_FLING_START to send the fling to the correct target. Send if it |
| - // has not sent. The distance traveled in one second is a reasonable scroll |
| - // start hint. |
| - GestureEventDetails scroll_details( |
| - ET_GESTURE_SCROLL_BEGIN, velocity_x, velocity_y); |
| - Send(CreateGesture(scroll_details, event)); |
| - } |
| - EndTouchScrollIfNecessary(event, false); |
| - |
| - GestureEventDetails fling_details( |
| - ET_SCROLL_FLING_START, velocity_x, velocity_y); |
| - Send(CreateGesture(fling_details, event)); |
| -} |
| - |
| -void GestureProvider::Send(GestureEventData gesture) { |
| - DCHECK(!gesture.time.is_null()); |
| - // The only valid events that should be sent without an active touch sequence |
| - // are SHOW_PRESS and TAP, potentially triggered by the double-tap |
| - // delay timing out. |
| - DCHECK(current_down_event_ || gesture.type() == ET_GESTURE_TAP || |
| - gesture.type() == ET_GESTURE_SHOW_PRESS || |
| - gesture.type() == ET_GESTURE_END); |
| - |
| - if (gesture.primary_tool_type == MotionEvent::TOOL_TYPE_UNKNOWN || |
| - gesture.primary_tool_type == MotionEvent::TOOL_TYPE_FINGER) { |
| - gesture.details.set_bounding_box( |
| - ClampBoundingBox(gesture.details.bounding_box_f(), |
| - min_gesture_bounds_length_, |
| - max_gesture_bounds_length_)); |
| - } |
| - |
| - switch (gesture.type()) { |
| - case ET_GESTURE_LONG_PRESS: |
| - DCHECK(!scale_gesture_listener_->IsScaleGestureDetectionInProgress()); |
| - current_longpress_time_ = gesture.time; |
| - break; |
| - case ET_GESTURE_LONG_TAP: |
| - current_longpress_time_ = base::TimeTicks(); |
| - break; |
| - case ET_GESTURE_SCROLL_BEGIN: |
| - DCHECK(!touch_scroll_in_progress_); |
| - touch_scroll_in_progress_ = true; |
| - break; |
| - case ET_GESTURE_SCROLL_END: |
| - DCHECK(touch_scroll_in_progress_); |
| - if (pinch_in_progress_) |
| - Send(GestureEventData(ET_GESTURE_PINCH_END, gesture)); |
| - touch_scroll_in_progress_ = false; |
| - break; |
| - case ET_GESTURE_PINCH_BEGIN: |
| - DCHECK(!pinch_in_progress_); |
| - if (!touch_scroll_in_progress_) |
| - Send(GestureEventData(ET_GESTURE_SCROLL_BEGIN, gesture)); |
| - pinch_in_progress_ = true; |
| - break; |
| - case ET_GESTURE_PINCH_END: |
| - DCHECK(pinch_in_progress_); |
| - pinch_in_progress_ = false; |
| - break; |
| - case ET_GESTURE_SHOW_PRESS: |
| - // It's possible that a double-tap drag zoom (from ScaleGestureDetector) |
| - // will start before the press gesture fires (from GestureDetector), in |
| - // which case the press should simply be dropped. |
| - if (pinch_in_progress_ || touch_scroll_in_progress_) |
| - return; |
| - default: |
| - break; |
| - }; |
| - |
| - client_->OnGestureEvent(gesture); |
| -} |
| - |
| -bool GestureProvider::SendLongTapIfNecessary(const MotionEvent& event) { |
| - if (event.GetAction() == MotionEvent::ACTION_UP && |
| - !current_longpress_time_.is_null() && |
| - !scale_gesture_listener_->IsScaleGestureDetectionInProgress()) { |
| - GestureEventDetails long_tap_details(ET_GESTURE_LONG_TAP, 0, 0); |
| - Send(CreateGesture(long_tap_details, event)); |
| - return true; |
| - } |
| - return false; |
| -} |
| - |
| -void GestureProvider::EndTouchScrollIfNecessary(const MotionEvent& event, |
| - bool send_scroll_end_event) { |
| - if (!touch_scroll_in_progress_) |
| - return; |
| - if (send_scroll_end_event) |
| - Send(CreateGesture(ET_GESTURE_SCROLL_END, event)); |
| - touch_scroll_in_progress_ = false; |
| -} |
| - |
| void GestureProvider::OnTouchEventHandlingBegin(const MotionEvent& event) { |
| switch (event.GetAction()) { |
| case MotionEvent::ACTION_DOWN: |
| current_down_event_ = event.Clone(); |
| - touch_scroll_in_progress_ = false; |
| - pinch_in_progress_ = false; |
| - current_longpress_time_ = base::TimeTicks(); |
| if (gesture_begin_end_types_enabled_) |
| - Send(CreateGesture(ET_GESTURE_BEGIN, event)); |
| + gesture_listener_->Send(CreateGesture(ET_GESTURE_BEGIN, event)); |
| break; |
| case MotionEvent::ACTION_POINTER_DOWN: |
| if (gesture_begin_end_types_enabled_) { |
| const int action_index = event.GetActionIndex(); |
| - Send(CreateGesture(ET_GESTURE_BEGIN, |
| - event.GetId(), |
| - event.GetToolType(), |
| - event.GetEventTime(), |
| - event.GetX(action_index), |
| - event.GetY(action_index), |
| - event.GetRawX(action_index), |
| - event.GetRawY(action_index), |
| - event.GetPointerCount(), |
| - GetBoundingBox(event))); |
| + gesture_listener_->Send(CreateGesture(ET_GESTURE_BEGIN, |
| + event.GetId(), |
| + event.GetToolType(), |
| + event.GetEventTime(), |
| + event.GetX(action_index), |
| + event.GetY(action_index), |
| + event.GetRawX(action_index), |
| + event.GetRawY(action_index), |
| + event.GetPointerCount(), |
| + GetBoundingBox(event))); |
| } |
| break; |
| case MotionEvent::ACTION_POINTER_UP: |
| @@ -801,12 +732,8 @@ void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) { |
| switch (event.GetAction()) { |
| case MotionEvent::ACTION_UP: |
| case MotionEvent::ACTION_CANCEL: { |
| - // Note: This call will have no effect if a fling was just generated, as |
| - // |Fling()| will have already signalled an end to touch-scrolling. |
| - EndTouchScrollIfNecessary(event, true); |
| - |
| if (gesture_begin_end_types_enabled_) |
| - Send(CreateGesture(ET_GESTURE_END, event)); |
| + gesture_listener_->Send(CreateGesture(ET_GESTURE_END, event)); |
| current_down_event_.reset(); |
| @@ -815,7 +742,7 @@ void GestureProvider::OnTouchEventHandlingEnd(const MotionEvent& event) { |
| } |
| case MotionEvent::ACTION_POINTER_UP: |
| if (gesture_begin_end_types_enabled_) |
| - Send(CreateGesture(ET_GESTURE_END, event)); |
| + gesture_listener_->Send(CreateGesture(ET_GESTURE_END, event)); |
| break; |
| case MotionEvent::ACTION_DOWN: |
| case MotionEvent::ACTION_POINTER_DOWN: |
| @@ -831,10 +758,9 @@ void GestureProvider::UpdateDoubleTapDetectionSupport() { |
| if (current_down_event_) |
| return; |
| - const bool double_tap_enabled = double_tap_support_for_page_ && |
| - double_tap_support_for_platform_; |
| + const bool double_tap_enabled = |
| + double_tap_support_for_page_ && double_tap_support_for_platform_; |
| gesture_listener_->SetDoubleTapEnabled(double_tap_enabled); |
| - scale_gesture_listener_->SetDoubleTapEnabled(double_tap_enabled); |
| } |
| } // namespace ui |