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

Unified 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 side-by-side diff with in-line comments
Download patch
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..c76460e53c63da200bda0dcf3cec80946e79fd0a 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();
}
- return handled;
+ }
+
+ 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));
+ }
+
+ 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,25 @@ 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())
+ distance_y = 0;
+ else
+ distance_x = 0;
}
if (distance_x || distance_y) {
@@ -392,16 +399,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 +426,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 +449,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 +457,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 +485,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 +521,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 +536,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 +551,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 +560,65 @@ class GestureProvider::GestureListenerImpl
gesture_detector_.SetDoubleTapListener(enabled ? this : NULL);
}
+ void SetMultiTouchZoomEnabled(bool enabled) {
+ // Note that returning false from |OnScaleBegin()| or |OnScale()| prevents
+ // the detector from emitting further scale updates for the current touch
+ // sequence. Thus, if multitouch events are enabled in the middle of a
+ // gesture, it will only take effect with the next gesture.
+ 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 forwarded for the
+ // current touch sequence.
+ bool pinch_event_sent_;
+ bool scroll_event_sent_;
DISALLOW_COPY_AND_ASSIGN(GestureListenerImpl);
};
@@ -574,43 +627,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 +678,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 +731,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 +741,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 +757,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
« 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