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

Unified Diff: ui/events/gesture_detection/gesture_provider.cc

Issue 200623003: Adopt "QuickScale" double-tap drag zoom code in the GestureProvider (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comment Created 6 years, 9 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 4deeba2580f3a7a72928cd3cec30f4a401aa2f18..d5a617f4d716b0370b5e415034cd23dd67708faf 100644
--- a/ui/events/gesture_detection/gesture_provider.cc
+++ b/ui/events/gesture_detection/gesture_provider.cc
@@ -43,7 +43,7 @@ GestureEventData CreateGesture(EventType type,
float x,
float y) {
return GestureEventData(type, time, x, y);
- }
+}
GestureEventData CreateGesture(EventType type,
const MotionEvent& event,
@@ -57,10 +57,6 @@ GestureEventData CreateGesture(EventType type,
return CreateGesture(type, event.GetEventTime(), event.GetX(), event.GetY());
}
-float Round(float f) {
- return (f > 0.f) ? std::floor(f + 0.5f) : std::ceil(f - 0.5f);
-}
-
GestureEventDetails CreateTapGestureDetails(EventType type,
const MotionEvent& event) {
// Set the tap count to 1 even for ET_GESTURE_DOUBLE_TAP, in order to be
@@ -86,10 +82,12 @@ class GestureProvider::ScaleGestureListenerImpl
: public ScaleGestureDetector::ScaleGestureListener {
public:
ScaleGestureListenerImpl(const ScaleGestureDetector::Config& config,
+ float device_scale_factor,
GestureProvider* provider)
: scale_gesture_detector_(config, this),
provider_(provider),
- ignore_detector_events_(false),
+ px_to_dp_(1.0f / device_scale_factor),
+ ignore_multitouch_events_(false),
pinch_event_sent_(false) {}
bool OnTouchEvent(const MotionEvent& event) {
@@ -106,7 +104,7 @@ class GestureProvider::ScaleGestureListenerImpl
// ScaleGestureDetector::ScaleGestureListener implementation.
virtual bool OnScaleBegin(const ScaleGestureDetector& detector) OVERRIDE {
- if (ignore_detector_events_)
+ if (ignore_multitouch_events_ && !detector.InDoubleTapMode())
return false;
pinch_event_sent_ = false;
return true;
@@ -121,7 +119,7 @@ class GestureProvider::ScaleGestureListenerImpl
}
virtual bool OnScale(const ScaleGestureDetector& detector) OVERRIDE {
- if (ignore_detector_events_)
+ if (ignore_multitouch_events_ && !detector.InDoubleTapMode())
return false;
if (!pinch_event_sent_) {
pinch_event_sent_ = true;
@@ -130,8 +128,23 @@ class GestureProvider::ScaleGestureListenerImpl
detector.GetFocusX(),
detector.GetFocusY()));
}
- GestureEventDetails pinch_details(
- ET_GESTURE_PINCH_UPDATE, detector.GetScaleFactor(), 0);
+
+ float scale = detector.GetScaleFactor();
+ if (scale == 1)
+ return true;
+
+ if (detector.InDoubleTapMode()) {
+ // Relative changes in the double-tap scale factor computed by |detector|
+ // diminish as the touch moves away from the original double-tap focus.
+ // Instead, compute a scale factor delta invariant to the distance, where
+ // the scale delta remains constant if the touch velocity is constant.
+ float dy =
+ (detector.GetCurrentSpanY() - detector.GetPreviousSpanY()) * 0.5f;
+ scale = std::pow(scale > 1 ? 1.0f + kDoubleTapDragZoomSpeed
+ : 1.0f - kDoubleTapDragZoomSpeed,
+ std::abs(dy * px_to_dp_));
tdresser 2014/04/03 17:53:30 Do we have any justification for why Chromium and
jdduke (slow) 2014/04/03 19:28:01 I don't, but I can find out.
+ }
+ GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0);
provider_->Send(CreateGesture(ET_GESTURE_PINCH_UPDATE,
detector.GetEventTime(),
detector.GetFocusX(),
@@ -140,26 +153,42 @@ class GestureProvider::ScaleGestureListenerImpl
return true;
}
- bool IsScaleGestureDetectionInProgress() const {
- return !ignore_detector_events_ && scale_gesture_detector_.IsInProgress();
+ void SetDoubleTapSupportEnabled(bool enabled) {
tdresser 2014/04/03 17:53:30 Maybe just "SetDoubleTapEnabled"?
jdduke (slow) 2014/04/03 19:28:01 Done.
+ DCHECK(!IsDoubleTapInProgress());
+ scale_gesture_detector_.SetQuickScaleEnabled(enabled);
}
- void set_ignore_detector_events(bool value) {
+ void SetMultiTouchSupportEnabled(bool value) {
// 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_detector_events_ = value;
+ ignore_multitouch_events_ = value;
+ }
+
+ 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_;
+ // TODO(jdduke): Remove this when all MotionEvent's use DIPs.
+ const float px_to_dp_;
+
// Completely silence scaling events. Used in WebView when zoom support
// is turned off.
- bool ignore_detector_events_;
+ bool ignore_multitouch_events_;
tdresser 2014/04/03 17:53:30 The comment and the variable name don't line up he
jdduke (slow) 2014/04/03 19:28:01 Oops yeah didn't notice the comment, thanks.
// Whether any pinch zoom event has been sent to native.
bool pinch_event_sent_;
@@ -181,24 +210,16 @@ class GestureProvider::GestureListenerImpl
: gesture_detector_(gesture_detector_config, this, this),
snap_scroll_controller_(snap_scroll_controller_config),
provider_(provider),
- px_to_dp_(1.0f / snap_scroll_controller_config.device_scale_factor),
disable_click_delay_(disable_click_delay),
scaled_touch_slop_(gesture_detector_config.scaled_touch_slop),
scaled_touch_slop_square_(scaled_touch_slop_ * scaled_touch_slop_),
double_tap_timeout_(gesture_detector_config.double_tap_timeout),
ignore_single_tap_(false),
seen_first_scroll_event_(false),
- double_tap_mode_(DOUBLE_TAP_MODE_NONE),
- double_tap_y_(0),
- double_tap_support_enabled_(true),
- double_tap_drag_zoom_anchor_x_(0),
- double_tap_drag_zoom_anchor_y_(0),
last_raw_x_(0),
last_raw_y_(0),
accumulated_scroll_error_x_(0),
- accumulated_scroll_error_y_(0) {
- UpdateDoubleTapListener();
- }
+ accumulated_scroll_error_y_(0) {}
virtual ~GestureListenerImpl() {}
@@ -210,12 +231,8 @@ class GestureProvider::GestureListenerImpl
if (is_scale_gesture_detection_in_progress)
SetIgnoreSingleTap(true);
- if (e.GetAction() == MotionEvent::ACTION_POINTER_DOWN ||
- e.GetAction() == MotionEvent::ACTION_CANCEL) {
- EndDoubleTapDragIfNecessary(e);
- } else if (e.GetAction() == MotionEvent::ACTION_DOWN) {
+ if (e.GetAction() == MotionEvent::ACTION_DOWN)
gesture_detector_.set_is_longpress_enabled(true);
- }
return gesture_detector_.OnTouchEvent(e);
}
@@ -343,7 +360,7 @@ class GestureProvider::GestureListenerImpl
if (!ignore_single_tap_) {
if (e.GetEventTime() - current_down_time_ > double_tap_timeout_) {
return OnSingleTapConfirmed(e);
- } else if (IsDoubleTapDisabled() || disable_click_delay_) {
+ } else if (!IsDoubleTapEnabled() || disable_click_delay_) {
// If double-tap has been disabled, there is no need to wait
// for the double-tap timeout.
return OnSingleTapConfirmed(e);
@@ -381,71 +398,22 @@ class GestureProvider::GestureListenerImpl
virtual bool OnDoubleTapEvent(const MotionEvent& e) OVERRIDE {
switch (e.GetAction()) {
case MotionEvent::ACTION_DOWN:
- // Note that this will be called before the corresponding |onDown()|
- // of the same ACTION_DOWN event. Thus, the preceding TAP_DOWN
- // should be cancelled prior to sending a new one (in |onDown()|).
- double_tap_drag_zoom_anchor_x_ = e.GetX();
- double_tap_drag_zoom_anchor_y_ = e.GetY();
- double_tap_mode_ = DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS;
- // If a long-press fires during a double-tap, the GestureDetector
- // will stop feeding MotionEvents to |onDoubleTapEvent()|,
- // preventing double-tap drag zoom. Long press detection will be
- // re-enabled on the next ACTION_DOWN.
gesture_detector_.set_is_longpress_enabled(false);
break;
- case MotionEvent::ACTION_MOVE:
- if (double_tap_mode_ == DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS) {
- float distance_x = double_tap_drag_zoom_anchor_x_ - e.GetX();
- float distance_y = double_tap_drag_zoom_anchor_y_ - e.GetY();
-
- // Begin double-tap drag zoom mode if the move distance is
- // further than the threshold.
- if (IsDistanceGreaterThanTouchSlop(distance_x, distance_y)) {
- GestureEventDetails scroll_details(
- ET_GESTURE_SCROLL_BEGIN, -distance_x, -distance_y);
- provider_->Send(
- CreateGesture(ET_GESTURE_SCROLL_BEGIN, e, scroll_details));
- provider_->Send(
- CreateGesture(ET_GESTURE_PINCH_BEGIN,
- e.GetEventTime(),
- Round(double_tap_drag_zoom_anchor_x_),
- Round(double_tap_drag_zoom_anchor_y_)));
- double_tap_mode_ = DOUBLE_TAP_MODE_DRAG_ZOOM;
- }
- } else if (double_tap_mode_ == DOUBLE_TAP_MODE_DRAG_ZOOM) {
- provider_->Send(CreateGesture(ET_GESTURE_SCROLL_UPDATE, e));
-
- float dy = double_tap_y_ - e.GetY();
- float scale = std::pow(dy > 0 ? 1.0f - kDoubleTapDragZoomSpeed
- : 1.0f + kDoubleTapDragZoomSpeed,
- std::abs(dy * px_to_dp_));
- GestureEventDetails pinch_details(ET_GESTURE_PINCH_UPDATE, scale, 0);
- provider_->Send(CreateGesture(ET_GESTURE_PINCH_UPDATE,
- e.GetEventTime(),
- Round(double_tap_drag_zoom_anchor_x_),
- Round(double_tap_drag_zoom_anchor_y_),
- pinch_details));
- }
- break;
+
case MotionEvent::ACTION_UP:
- if (double_tap_mode_ != DOUBLE_TAP_MODE_DRAG_ZOOM) {
- // Normal double-tap gesture.
+ if (!provider_->IsPinchInProgress()) {
provider_->Send(
CreateGesture(ET_GESTURE_DOUBLE_TAP,
e,
CreateTapGestureDetails(ET_GESTURE_DOUBLE_TAP, e)));
+ return true;
}
- EndDoubleTapDragIfNecessary(e);
- break;
- case MotionEvent::ACTION_CANCEL:
- EndDoubleTapDragIfNecessary(e);
break;
default:
- NOTREACHED() << "Invalid double-tap event.";
break;
}
- double_tap_y_ = e.GetY();
- return true;
+ return false;
}
virtual bool OnLongPress(const MotionEvent& e) OVERRIDE {
@@ -464,43 +432,23 @@ class GestureProvider::GestureListenerImpl
return false;
}
- void SetDoubleTapSupportForPlatformEnabled(bool enabled) {
+ void SetDoubleTapSupportEnabled(bool enabled) {
DCHECK(!IsDoubleTapInProgress());
- DoubleTapMode double_tap_mode =
- enabled ? DOUBLE_TAP_MODE_NONE : DOUBLE_TAP_MODE_DISABLED;
- if (double_tap_mode_ == double_tap_mode)
- return;
- double_tap_mode_ = double_tap_mode;
- UpdateDoubleTapListener();
- }
-
- void SetDoubleTapSupportForPageEnabled(bool enabled) {
- if (double_tap_support_enabled_ == enabled)
- return;
- double_tap_support_enabled_ = enabled;
- UpdateDoubleTapListener();
- }
-
- bool IsDoubleTapDisabled() const {
- return double_tap_mode_ == DOUBLE_TAP_MODE_DISABLED ||
- !double_tap_support_enabled_;
+ if (enabled) {
+ gesture_detector_.set_doubletap_listener(this);
+ } else {
+ // TODO(jdduke): Send GESTURE_TAP if GESTURE_TAP_UNCONFIRMED already sent.
+ gesture_detector_.set_doubletap_listener(NULL);
+ }
}
bool IsClickDelayDisabled() const { return disable_click_delay_; }
bool IsDoubleTapInProgress() const {
- return double_tap_mode_ != DOUBLE_TAP_MODE_DISABLED &&
- double_tap_mode_ != DOUBLE_TAP_MODE_NONE;
+ return gesture_detector_.is_double_tapping();
}
private:
- enum DoubleTapMode {
- DOUBLE_TAP_MODE_NONE,
- DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS,
- DOUBLE_TAP_MODE_DRAG_ZOOM,
- DOUBLE_TAP_MODE_DISABLED
- };
-
bool IsPointOutsideCurrentSlopRegion(float x, float y) const {
return IsDistanceGreaterThanTouchSlop(last_raw_x_ - x, last_raw_y_ - y);
}
@@ -513,27 +461,8 @@ class GestureProvider::GestureListenerImpl
void SetIgnoreSingleTap(bool value) { ignore_single_tap_ = value; }
- void EndDoubleTapDragIfNecessary(const MotionEvent& event) {
- if (!IsDoubleTapInProgress())
- return;
- if (double_tap_mode_ == DOUBLE_TAP_MODE_DRAG_ZOOM) {
- provider_->Send(CreateGesture(ET_GESTURE_PINCH_END, event));
- provider_->Send(CreateGesture(ET_GESTURE_SCROLL_END, event));
- }
- double_tap_mode_ = DOUBLE_TAP_MODE_NONE;
- UpdateDoubleTapListener();
- }
-
- void UpdateDoubleTapListener() {
- if (IsDoubleTapDisabled()) {
- // Defer nulling the DoubleTapListener until the double-tap gesture is
- // complete.
- if (IsDoubleTapInProgress())
- return;
- gesture_detector_.set_doubletap_listener(NULL);
- } else {
- gesture_detector_.set_doubletap_listener(this);
- }
+ bool IsDoubleTapEnabled() const {
+ return gesture_detector_.has_doubletap_listener();
}
GestureDetector gesture_detector_;
@@ -541,8 +470,6 @@ class GestureProvider::GestureListenerImpl
GestureProvider* const provider_;
- const float px_to_dp_;
-
// Whether the click delay should always be disabled by sending clicks for
// double-tap gestures.
const bool disable_click_delay_;
@@ -566,21 +493,6 @@ class GestureProvider::GestureListenerImpl
// gesture.
bool seen_first_scroll_event_;
- // Indicate current double-tap mode state.
- int double_tap_mode_;
-
- // On double-tap this will store the y coordinates of the touch.
- float double_tap_y_;
-
- // The page's viewport and scale sometimes allow us to disable double-tap
- // gesture detection,
- // according to the logic in ContentViewCore.onRenderCoordinatesUpdated().
- bool double_tap_support_enabled_;
-
- // x, y coordinates for an Anchor on double-tap drag zoom.
- float double_tap_drag_zoom_anchor_x_;
- float double_tap_drag_zoom_anchor_y_;
-
// Used to track the last rawX/Y coordinates for moves. This gives absolute
// scroll distance.
// Useful for full screen tracking.
@@ -604,7 +516,9 @@ GestureProvider::GestureProvider(const Config& config,
needs_show_press_event_(false),
needs_tap_ending_event_(false),
touch_scroll_in_progress_(false),
- pinch_in_progress_(false) {
+ pinch_in_progress_(false),
+ double_tap_support_for_page_(true),
+ double_tap_support_for_platform_(true) {
DCHECK(client);
InitGestureDetectors(config);
}
@@ -617,7 +531,6 @@ bool GestureProvider::OnTouchEvent(const MotionEvent& event) {
if (!CanHandle(event))
return false;
- const bool was_touch_scrolling_ = touch_scroll_in_progress_;
const bool in_scale_gesture =
scale_gesture_listener_->IsScaleGestureDetectionInProgress();
@@ -634,16 +547,17 @@ bool GestureProvider::OnTouchEvent(const MotionEvent& event) {
if (event.GetAction() == MotionEvent::ACTION_UP ||
event.GetAction() == MotionEvent::ACTION_CANCEL) {
- // "Last finger raised" could be an end to movement, but it should
- // only terminate scrolling if the event did not cause a fling.
- if (was_touch_scrolling_ && !handled)
- EndTouchScrollIfNecessary(event.GetEventTime(), true);
+ // 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.GetEventTime(), true);
// We shouldn't necessarily cancel a tap on ACTION_UP, as the double-tap
// timeout may yet trigger a SINGLE_TAP.
if (event.GetAction() == MotionEvent::ACTION_CANCEL)
SendTapCancelIfNecessary(event);
+ UpdateDoubleTapDetectionSupport();
+
current_down_event_.reset();
}
@@ -659,15 +573,17 @@ void GestureProvider::ResetGestureDetectors() {
}
void GestureProvider::SetMultiTouchSupportEnabled(bool enabled) {
- scale_gesture_listener_->set_ignore_detector_events(!enabled);
+ scale_gesture_listener_->SetMultiTouchSupportEnabled(!enabled);
}
void GestureProvider::SetDoubleTapSupportForPlatformEnabled(bool enabled) {
- gesture_listener_->SetDoubleTapSupportForPlatformEnabled(enabled);
+ double_tap_support_for_platform_ = enabled;
+ UpdateDoubleTapDetectionSupport();
}
void GestureProvider::SetDoubleTapSupportForPageEnabled(bool enabled) {
- gesture_listener_->SetDoubleTapSupportForPageEnabled(enabled);
+ double_tap_support_for_page_ = enabled;
+ UpdateDoubleTapDetectionSupport();
}
bool GestureProvider::IsScrollInProgress() const {
@@ -679,7 +595,12 @@ bool GestureProvider::IsScrollInProgress() const {
bool GestureProvider::IsPinchInProgress() const { return pinch_in_progress_; }
bool GestureProvider::IsDoubleTapInProgress() const {
- return gesture_listener_->IsDoubleTapInProgress();
+ return gesture_listener_->IsDoubleTapInProgress() ||
+ scale_gesture_listener_->IsDoubleTapInProgress();
+}
+
+bool GestureProvider::IsDoubleTapSupportedEnabled() const {
+ return double_tap_support_for_page_ && double_tap_support_for_platform_;
}
bool GestureProvider::IsClickDelayDisabled() const {
@@ -694,8 +615,12 @@ void GestureProvider::InitGestureDetectors(const Config& config) {
config.disable_click_delay,
this));
- scale_gesture_listener_.reset(
- new ScaleGestureListenerImpl(config.scale_gesture_detector_config, this));
+ scale_gesture_listener_.reset(new ScaleGestureListenerImpl(
+ config.scale_gesture_detector_config,
+ config.snap_scroll_controller_config.device_scale_factor,
+ this));
+
+ UpdateDoubleTapDetectionSupport();
}
bool GestureProvider::CanHandle(const MotionEvent& event) const {
@@ -776,6 +701,9 @@ void GestureProvider::Send(const GestureEventData& gesture) {
touch_scroll_in_progress_ = false;
break;
case ET_GESTURE_PINCH_BEGIN:
+ if (!touch_scroll_in_progress_)
+ Send(CreateGesture(
+ ET_GESTURE_SCROLL_BEGIN, gesture.time, gesture.x, gesture.y));
pinch_in_progress_ = true;
break;
case ET_GESTURE_PINCH_END:
@@ -818,4 +746,13 @@ void GestureProvider::EndTouchScrollIfNecessary(base::TimeTicks time,
Send(CreateGesture(ET_GESTURE_SCROLL_END, time, 0, 0));
}
+void GestureProvider::UpdateDoubleTapDetectionSupport() {
+ if (IsDoubleTapInProgress())
+ return;
+
+ const bool supports_double_tap = IsDoubleTapSupportedEnabled();
+ gesture_listener_->SetDoubleTapSupportEnabled(supports_double_tap);
+ scale_gesture_listener_->SetDoubleTapSupportEnabled(supports_double_tap);
+}
+
} // namespace ui

Powered by Google App Engine
This is Rietveld 408576698