Commit c0c403b2 authored by yusufo@chromium.org's avatar yusufo@chromium.org

Coalesce scrollUpdate and pinchUpdate on gesture_event queue

Currently we are just coalescing scrollUpdates and we end up not utilizing
this when we have interleaved scrollUpdate and pinchUpdates. This change makes
that possible and makes sure the gesture_event_queue doesnt get flooded with
interleaved scroll and pinch updates.

BUG=174189


Review URL: https://chromiumcodereview.appspot.com/12225056

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182205 0039d316-1c4b-4281-b951-d872f2087c98
parent d366a9da
...@@ -61,6 +61,8 @@ GestureEventFilter::GestureEventFilter(RenderWidgetHostImpl* rwhv) ...@@ -61,6 +61,8 @@ GestureEventFilter::GestureEventFilter(RenderWidgetHostImpl* rwhv)
: render_widget_host_(rwhv), : render_widget_host_(rwhv),
fling_in_progress_(false), fling_in_progress_(false),
scrolling_in_progress_(false), scrolling_in_progress_(false),
ignore_next_ack_(false),
combined_scroll_pinch_(gfx::Transform()),
tap_suppression_controller_(new TapSuppressionController(rwhv)), tap_suppression_controller_(new TapSuppressionController(rwhv)),
maximum_tap_gap_time_ms_(GetTapDownDeferralTimeMs()), maximum_tap_gap_time_ms_(GetTapDownDeferralTimeMs()),
debounce_interval_time_ms_(kDebouncingIntervalTimeMs) { debounce_interval_time_ms_(kDebouncingIntervalTimeMs) {
...@@ -188,8 +190,9 @@ bool GestureEventFilter::ShouldForwardForTapDeferral( ...@@ -188,8 +190,9 @@ bool GestureEventFilter::ShouldForwardForTapDeferral(
deferred_tap_down_event_.type = WebInputEvent::Undefined; deferred_tap_down_event_.type = WebInputEvent::Undefined;
coalesced_gesture_events_.push_back(gesture_event); coalesced_gesture_events_.push_back(gesture_event);
return ShouldHandleEventNow(); return ShouldHandleEventNow();
case WebInputEvent::GesturePinchUpdate:
case WebInputEvent::GestureScrollUpdate: case WebInputEvent::GestureScrollUpdate:
MergeOrInsertScrollEvent(gesture_event); MergeOrInsertScrollAndPinchEvent(gesture_event);
return ShouldHandleEventNow(); return ShouldHandleEventNow();
default: default:
coalesced_gesture_events_.push_back(gesture_event); coalesced_gesture_events_.push_back(gesture_event);
...@@ -203,6 +206,8 @@ bool GestureEventFilter::ShouldForwardForTapDeferral( ...@@ -203,6 +206,8 @@ bool GestureEventFilter::ShouldForwardForTapDeferral(
void GestureEventFilter::Reset() { void GestureEventFilter::Reset() {
fling_in_progress_ = false; fling_in_progress_ = false;
scrolling_in_progress_ = false; scrolling_in_progress_ = false;
ignore_next_ack_ = false;
combined_scroll_pinch_ = gfx::Transform();
coalesced_gesture_events_.clear(); coalesced_gesture_events_.clear();
deferred_tap_down_event_.type = WebInputEvent::Undefined; deferred_tap_down_event_.type = WebInputEvent::Undefined;
debouncing_deferral_queue_.clear(); debouncing_deferral_queue_.clear();
...@@ -220,10 +225,25 @@ void GestureEventFilter::ProcessGestureAck(bool processed, int type) { ...@@ -220,10 +225,25 @@ void GestureEventFilter::ProcessGestureAck(bool processed, int type) {
coalesced_gesture_events_.pop_front(); coalesced_gesture_events_.pop_front();
if (type == WebInputEvent::GestureFlingCancel) if (type == WebInputEvent::GestureFlingCancel)
tap_suppression_controller_->GestureFlingCancelAck(processed); tap_suppression_controller_->GestureFlingCancelAck(processed);
if (!coalesced_gesture_events_.empty()) { if (!coalesced_gesture_events_.empty() && !ignore_next_ack_) {
WebGestureEvent next_gesture_event = coalesced_gesture_events_.front(); const WebGestureEvent& next_gesture_event =
coalesced_gesture_events_.front();
render_widget_host_->ForwardGestureEventImmediately(next_gesture_event); render_widget_host_->ForwardGestureEventImmediately(next_gesture_event);
} // TODO(yusufo): Introduce GesturePanScroll so that these can be combined
// into one gesture and kept inside the queue that way.
if (coalesced_gesture_events_.size() > 1) {
const WebGestureEvent& second_gesture_event =
coalesced_gesture_events_[1];
if (next_gesture_event.type == WebInputEvent::GestureScrollUpdate &&
second_gesture_event.type == WebInputEvent::GesturePinchUpdate) {
render_widget_host_->
ForwardGestureEventImmediately(second_gesture_event);
ignore_next_ack_ = true;
combined_scroll_pinch_ = gfx::Transform();
}
}
} else if (ignore_next_ack_)
ignore_next_ack_ = false;
} }
TapSuppressionController* GestureEventFilter::GetTapSuppressionController() { TapSuppressionController* GestureEventFilter::GetTapSuppressionController() {
...@@ -237,7 +257,10 @@ bool GestureEventFilter::HasQueuedGestureEvents() const { ...@@ -237,7 +257,10 @@ bool GestureEventFilter::HasQueuedGestureEvents() const {
const WebKit::WebInputEvent& const WebKit::WebInputEvent&
GestureEventFilter::GetGestureEventAwaitingAck() const { GestureEventFilter::GetGestureEventAwaitingAck() const {
DCHECK(!coalesced_gesture_events_.empty()); DCHECK(!coalesced_gesture_events_.empty());
return coalesced_gesture_events_.front(); if (!ignore_next_ack_)
return coalesced_gesture_events_.front();
else
return coalesced_gesture_events_.at(1);
} }
void GestureEventFilter::FlingHasBeenHalted() { void GestureEventFilter::FlingHasBeenHalted() {
...@@ -273,26 +296,86 @@ void GestureEventFilter::SendScrollEndingEventsNow() { ...@@ -273,26 +296,86 @@ void GestureEventFilter::SendScrollEndingEventsNow() {
debouncing_deferral_queue_.clear(); debouncing_deferral_queue_.clear();
} }
void GestureEventFilter::MergeOrInsertScrollEvent( void GestureEventFilter::MergeOrInsertScrollAndPinchEvent(
const WebGestureEvent& gesture_event) { const WebGestureEvent& gesture_event) {
WebGestureEvent* last_gesture_event = coalesced_gesture_events_.empty() ? 0 : if (coalesced_gesture_events_.size() <= 1) {
&coalesced_gesture_events_.back(); coalesced_gesture_events_.push_back(gesture_event);
return;
}
WebGestureEvent* last_event = &coalesced_gesture_events_.back();
if (coalesced_gesture_events_.size() > 1 && if (coalesced_gesture_events_.size() > 1 &&
last_gesture_event->type == gesture_event.type && gesture_event.type == WebInputEvent::GestureScrollUpdate &&
last_gesture_event->modifiers == gesture_event.modifiers) { last_event->type == WebInputEvent::GestureScrollUpdate &&
last_gesture_event->data.scrollUpdate.deltaX += last_event->modifiers == gesture_event.modifiers) {
last_event->data.scrollUpdate.deltaX +=
gesture_event.data.scrollUpdate.deltaX; gesture_event.data.scrollUpdate.deltaX;
last_gesture_event->data.scrollUpdate.deltaY += last_event->data.scrollUpdate.deltaY +=
gesture_event.data.scrollUpdate.deltaY; gesture_event.data.scrollUpdate.deltaY;
DLOG_IF(WARNING, return;
gesture_event.timeStampSeconds <= } else if (coalesced_gesture_events_.size() < 3 ||
last_gesture_event->timeStampSeconds) (coalesced_gesture_events_.size() == 3 && ignore_next_ack_) ||
<< "Event time not monotonic?\n"; !ShouldTryMerging(gesture_event,*last_event)) {
DCHECK(last_gesture_event->type == WebInputEvent::GestureScrollUpdate);
last_gesture_event->timeStampSeconds = gesture_event.timeStampSeconds;
} else {
coalesced_gesture_events_.push_back(gesture_event); coalesced_gesture_events_.push_back(gesture_event);
return;
} }
WebGestureEvent scroll_event;
WebGestureEvent pinch_event;
scroll_event.modifiers |= gesture_event.modifiers;
scroll_event.timeStampSeconds = gesture_event.timeStampSeconds;
pinch_event = scroll_event;
scroll_event.type = WebInputEvent::GestureScrollUpdate;
pinch_event.type = WebInputEvent::GesturePinchUpdate;
pinch_event.x = gesture_event.type == WebInputEvent::GesturePinchUpdate ?
gesture_event.x : last_event->x;
pinch_event.y = gesture_event.type == WebInputEvent::GesturePinchUpdate ?
gesture_event.y : last_event->y;
combined_scroll_pinch_.ConcatTransform(GetTransformForEvent(gesture_event));
WebGestureEvent* second_last_event = &coalesced_gesture_events_
[coalesced_gesture_events_.size() - 2];
if (ShouldTryMerging(gesture_event, *second_last_event)) {
coalesced_gesture_events_.pop_back();
} else {
DCHECK(combined_scroll_pinch_ == GetTransformForEvent(gesture_event));
combined_scroll_pinch_.
PreconcatTransform(GetTransformForEvent(*last_event));
}
coalesced_gesture_events_.pop_back();
float combined_scale = combined_scroll_pinch_.matrix().getDouble(0, 0);
scroll_event.data.scrollUpdate.deltaX =
(combined_scroll_pinch_.matrix().getDouble(0, 3) + pinch_event.x)
/ combined_scale - pinch_event.x;
scroll_event.data.scrollUpdate.deltaY =
(combined_scroll_pinch_.matrix().getDouble(1, 3) + pinch_event.y)
/ combined_scale - pinch_event.y;
coalesced_gesture_events_.push_back(scroll_event);
pinch_event.data.pinchUpdate.scale = combined_scale;
coalesced_gesture_events_.push_back(pinch_event);
} }
bool GestureEventFilter::ShouldTryMerging(const WebGestureEvent& new_event,
const WebGestureEvent& event_in_queue) {
DLOG_IF(WARNING,
new_event.timeStampSeconds <
event_in_queue.timeStampSeconds)
<< "Event time not monotonic?\n";
return (event_in_queue.type == WebInputEvent::GestureScrollUpdate ||
event_in_queue.type == WebInputEvent::GesturePinchUpdate) &&
event_in_queue.modifiers == new_event.modifiers;
}
gfx::Transform GestureEventFilter::GetTransformForEvent(
const WebGestureEvent& gesture_event) {
gfx::Transform gesture_transform = gfx::Transform();
if (gesture_event.type == WebInputEvent::GestureScrollUpdate) {
gesture_transform.Translate(gesture_event.data.scrollUpdate.deltaX,
gesture_event.data.scrollUpdate.deltaY);
} else if (gesture_event.type == WebInputEvent::GesturePinchUpdate) {
float scale = gesture_event.data.pinchUpdate.scale;
gesture_transform.Translate(-gesture_event.x, -gesture_event.y);
gesture_transform.Scale(scale,scale);
gesture_transform.Translate(gesture_event.x, gesture_event.y);
}
return gesture_transform;
}
} // namespace content } // namespace content
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/timer.h" #include "base/timer.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "ui/gfx/transform.h"
namespace content { namespace content {
class MockRenderWidgetHost; class MockRenderWidgetHost;
...@@ -78,8 +79,9 @@ class GestureEventFilter { ...@@ -78,8 +79,9 @@ class GestureEventFilter {
// hence that event should be handled now. // hence that event should be handled now.
bool ShouldHandleEventNow(); bool ShouldHandleEventNow();
// Merge or append a GestureScrollUpdate into the coalescing queue. // Merge or append a GestureScrollUpdate or GesturePinchUpdate into
void MergeOrInsertScrollEvent( // the coalescing queue.
void MergeOrInsertScrollAndPinchEvent(
const WebKit::WebGestureEvent& gesture_event); const WebKit::WebGestureEvent& gesture_event);
// Sub-filter for removing bounces from in-progress scrolls. // Sub-filter for removing bounces from in-progress scrolls.
...@@ -91,6 +93,18 @@ class GestureEventFilter { ...@@ -91,6 +93,18 @@ class GestureEventFilter {
bool ShouldForwardForTapDeferral( bool ShouldForwardForTapDeferral(
const WebKit::WebGestureEvent& gesture_event); const WebKit::WebGestureEvent& gesture_event);
// Whether the event_in_queue is GesturePinchUpdate or
// GestureScrollUpdate and it has the same modifiers as the
// new event.
bool ShouldTryMerging(const WebKit::WebGestureEvent& new_event,
const WebKit::WebGestureEvent& event_in_queue);
// Returns the transform matrix corresponding to the gesture event.
// Assumes the gesture event sent is either GestureScrollUpdate or
// GesturePinchUpdate. Returns the identity matrix otherwise.
gfx::Transform GetTransformForEvent(
const WebKit::WebGestureEvent& gesture_event);
// Only a RenderWidgetHostViewImpl can own an instance. // Only a RenderWidgetHostViewImpl can own an instance.
RenderWidgetHostImpl* render_widget_host_; RenderWidgetHostImpl* render_widget_host_;
...@@ -101,6 +115,14 @@ class GestureEventFilter { ...@@ -101,6 +115,14 @@ class GestureEventFilter {
// True if a GestureScrollUpdate sequence is in progress. // True if a GestureScrollUpdate sequence is in progress.
bool scrolling_in_progress_; bool scrolling_in_progress_;
// True if two related gesture events were sent before without waiting
// for an ACK, so the next gesture ACK should be ignored.
bool ignore_next_ack_;
// Transform that holds the combined transform matrix for the current
// scroll-pinch sequence at the end of the queue.
gfx::Transform combined_scroll_pinch_;
// Timer to release a previously deferred GestureTapDown event. // Timer to release a previously deferred GestureTapDown event.
base::OneShotTimer<GestureEventFilter> send_gtd_timer_; base::OneShotTimer<GestureEventFilter> send_gtd_timer_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment