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

Unified Diff: trunk/src/content/browser/renderer_host/input/touch_event_queue.cc

Issue 252023005: Revert 266470 "Implement async touchmove dispatch during scroll" (Closed) Base URL: svn://svn.chromium.org/chrome/
Patch Set: Created 6 years, 8 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: trunk/src/content/browser/renderer_host/input/touch_event_queue.cc
===================================================================
--- trunk/src/content/browser/renderer_host/input/touch_event_queue.cc (revision 266575)
+++ trunk/src/content/browser/renderer_host/input/touch_event_queue.cc (working copy)
@@ -21,15 +21,6 @@
namespace content {
namespace {
-// Time interval at which touchmove events will be forwarded to the client while
-// scrolling is active and possible.
-const double kAsyncTouchMoveIntervalSec = .2;
-
-// A slop region just larger than that used by many web applications. When
-// touchmove's are being sent asynchronously, movement outside this region will
-// trigger an immediate async touchmove to cancel potential tap-related logic.
-const double kApplicationSlopRegionLengthDipsSqared = 15. * 15.;
-
// Using a small epsilon when comparing slop distances allows pixel perfect
// slop determination when using fractional DIP coordinates (assuming the slop
// region and DPI scale are reasonably proportioned).
@@ -48,18 +39,11 @@
return event;
}
-bool ShouldTouchTriggerTimeout(const WebTouchEvent& event) {
- return (event.type == WebInputEvent::TouchStart ||
- event.type == WebInputEvent::TouchMove) &&
- !WebInputEventTraits::IgnoresAckDisposition(event);
+bool ShouldTouchTypeTriggerTimeout(WebInputEvent::Type type) {
+ return type == WebInputEvent::TouchStart ||
+ type == WebInputEvent::TouchMove;
}
-bool OutsideApplicationSlopRegion(const WebTouchEvent& event,
- const gfx::PointF& anchor) {
- return (gfx::PointF(event.touches[0].position) - anchor).LengthSquared() >
- kApplicationSlopRegionLengthDipsSqared;
-}
-
} // namespace
@@ -79,7 +63,7 @@
void Start(const TouchEventWithLatencyInfo& event) {
DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE);
- DCHECK(ShouldTouchTriggerTimeout(event.event));
+ DCHECK(ShouldTouchTypeTriggerTimeout(event.event.type));
timeout_event_ = event;
timeout_monitor_.Restart(timeout_delay_);
}
@@ -94,7 +78,7 @@
SetPendingAckState(PENDING_ACK_CANCEL_EVENT);
TouchEventWithLatencyInfo cancel_event =
ObtainCancelEventForTouchEvent(timeout_event_);
- touch_queue_->SendTouchEventImmediately(cancel_event);
+ touch_queue_->client_->SendTouchEventImmediately(cancel_event);
} else {
SetPendingAckState(PENDING_ACK_NONE);
touch_queue_->UpdateTouchAckStates(timeout_event_.event, ack_result);
@@ -244,27 +228,25 @@
// the Client receives the event with their original timestamp.
class CoalescedWebTouchEvent {
public:
- // Events for which |async| is true will not be ack'ed to the client after the
- // corresponding ack is received following dispatch.
- CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event, bool async)
- : coalesced_event_(event) {
- if (async)
- coalesced_event_.event.cancelable = false;
- else
- events_to_ack_.push_back(event);
-
- TRACE_EVENT_ASYNC_BEGIN0("input", "TouchEventQueue::QueueEvent", this);
+ CoalescedWebTouchEvent(const TouchEventWithLatencyInfo& event,
+ bool ignore_ack)
+ : coalesced_event_(event),
+ ignore_ack_(ignore_ack) {
+ events_.push_back(event);
+ TRACE_EVENT_ASYNC_BEGIN0(
+ "input", "TouchEventQueue::QueueEvent", this);
}
~CoalescedWebTouchEvent() {
- TRACE_EVENT_ASYNC_END0("input", "TouchEventQueue::QueueEvent", this);
+ TRACE_EVENT_ASYNC_END0(
+ "input", "TouchEventQueue::QueueEvent", this);
}
// Coalesces the event with the existing event if possible. Returns whether
// the event was coalesced.
bool CoalesceEventIfPossible(
const TouchEventWithLatencyInfo& event_with_latency) {
- if (!WillDispatchAckToClient())
+ if (ignore_ack_)
return false;
if (!coalesced_event_.CanCoalesceWith(event_with_latency))
@@ -273,51 +255,37 @@
TRACE_EVENT_INSTANT0(
"input", "TouchEventQueue::MoveCoalesced", TRACE_EVENT_SCOPE_THREAD);
coalesced_event_.CoalesceWith(event_with_latency);
- events_to_ack_.push_back(event_with_latency);
+ events_.push_back(event_with_latency);
return true;
}
- void UpdateLatencyInfoForAck(const ui::LatencyInfo& renderer_latency_info) {
- if (!WillDispatchAckToClient())
- return;
-
- for (WebTouchEventWithLatencyList::iterator iter = events_to_ack_.begin(),
- end = events_to_ack_.end();
- iter != end;
- ++iter) {
- iter->latency.AddNewLatencyFrom(renderer_latency_info);
- }
+ const TouchEventWithLatencyInfo& coalesced_event() const {
+ return coalesced_event_;
}
- void DispatchAckToClient(InputEventAckState ack_result,
- TouchEventQueueClient* client) {
- DCHECK(client);
- if (!WillDispatchAckToClient())
- return;
-
- for (WebTouchEventWithLatencyList::const_iterator
- iter = events_to_ack_.begin(),
- end = events_to_ack_.end();
- iter != end;
- ++iter) {
- client->OnTouchEventAck(*iter, ack_result);
- }
+ WebTouchEventWithLatencyList::iterator begin() {
+ return events_.begin();
}
- const TouchEventWithLatencyInfo& coalesced_event() const {
- return coalesced_event_;
+ WebTouchEventWithLatencyList::iterator end() {
+ return events_.end();
}
+ size_t size() const { return events_.size(); }
+
+ bool ignore_ack() const { return ignore_ack_; }
+
private:
- bool WillDispatchAckToClient() const { return !events_to_ack_.empty(); }
-
// This is the event that is forwarded to the renderer.
TouchEventWithLatencyInfo coalesced_event_;
- // This is the list of the original events that were coalesced, each requiring
- // future ack dispatch to the client.
- WebTouchEventWithLatencyList events_to_ack_;
+ // This is the list of the original events that were coalesced.
+ WebTouchEventWithLatencyList events_;
+ // If |ignore_ack_| is true, don't send this touch event to client
+ // when the event is acked.
+ bool ignore_ack_;
+
DISALLOW_COPY_AND_ASSIGN(CoalescedWebTouchEvent);
};
@@ -331,8 +299,7 @@
ack_timeout_enabled_(false),
touchmove_slop_suppressor_(new TouchMoveSlopSuppressor(
touchmove_suppression_length_dips + kSlopEpsilon)),
- send_touch_events_async_(false),
- last_sent_touch_timestamp_sec_(0),
+ absorbing_touch_moves_(false),
touch_scrolling_mode_(mode) {
DCHECK(client);
}
@@ -350,19 +317,17 @@
if (touch_queue_.empty() && !dispatching_touch_ack_) {
// Optimization of the case without touch handlers. Removing this path
// yields identical results, but this avoids unnecessary allocations.
- PreFilterResult filter_result = FilterBeforeForwarding(event.event);
- if (filter_result != FORWARD_TO_RENDERER) {
- client_->OnTouchEventAck(event,
- filter_result == ACK_WITH_NO_CONSUMER_EXISTS
- ? INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
- : INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ if (touch_filtering_state_ == DROP_ALL_TOUCHES ||
+ (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE &&
+ !WebTouchEventTraits::IsTouchSequenceStart(event.event))) {
+ client_->OnTouchEventAck(event, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
return;
}
// There is no touch event in the queue. Forward it to the renderer
// immediately.
touch_queue_.push_back(new CoalescedWebTouchEvent(event, false));
- ForwardNextEventToRenderer();
+ TryForwardNextEventToRenderer();
return;
}
@@ -405,6 +370,7 @@
touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
}
+ UpdateTouchAckStates(acked_event, ack_result);
PopTouchEventToClient(ack_result, latency_info);
TryForwardNextEventToRenderer();
}
@@ -414,102 +380,47 @@
// If there are queued touch events, then try to forward them to the renderer
// immediately, or ACK the events back to the client if appropriate.
while (!touch_queue_.empty()) {
- PreFilterResult filter_result =
- FilterBeforeForwarding(touch_queue_.front()->coalesced_event().event);
- switch (filter_result) {
+ const TouchEventWithLatencyInfo& touch =
+ touch_queue_.front()->coalesced_event();
+ PreFilterResult result = FilterBeforeForwarding(touch.event);
+ switch (result) {
case ACK_WITH_NO_CONSUMER_EXISTS:
- PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
+ LatencyInfo());
break;
case ACK_WITH_NOT_CONSUMED:
- PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED,
+ LatencyInfo());
break;
case FORWARD_TO_RENDERER:
- ForwardNextEventToRenderer();
+ ForwardToRenderer(touch);
return;
}
}
}
-void TouchEventQueue::ForwardNextEventToRenderer() {
- TRACE_EVENT0("input", "TouchEventQueue::ForwardNextEventToRenderer");
+void TouchEventQueue::ForwardToRenderer(
+ const TouchEventWithLatencyInfo& touch) {
+ TRACE_EVENT0("input", "TouchEventQueue::ForwardToRenderer");
- DCHECK(!empty());
DCHECK(!dispatching_touch_);
DCHECK_NE(touch_filtering_state_, DROP_ALL_TOUCHES);
- TouchEventWithLatencyInfo touch = touch_queue_.front()->coalesced_event();
if (WebTouchEventTraits::IsTouchSequenceStart(touch.event)) {
touch_filtering_state_ =
ack_timeout_enabled_ ? FORWARD_TOUCHES_UNTIL_TIMEOUT
: FORWARD_ALL_TOUCHES;
touch_ack_states_.clear();
- send_touch_events_async_ = false;
- touch_sequence_start_position_ =
- gfx::PointF(touch.event.touches[0].position);
+ absorbing_touch_moves_ = false;
}
- if (send_touch_events_async_ &&
- touch.event.type == WebInputEvent::TouchMove) {
- // Throttling touchmove's in a continuous touchmove stream while scrolling
- // reduces the risk of jank. However, it's still important that the web
- // application be sent touches at key points in the gesture stream,
- // e.g., when the application slop region is exceeded or touchmove
- // coalescing fails because of different modifiers.
- const bool send_touch_move_now =
- size() > 1 ||
- (touch.event.timeStampSeconds >=
- last_sent_touch_timestamp_sec_ + kAsyncTouchMoveIntervalSec) ||
- (needs_async_touch_move_for_outer_slop_region_ &&
- OutsideApplicationSlopRegion(touch.event,
- touch_sequence_start_position_)) ||
- (pending_async_touch_move_ &&
- !pending_async_touch_move_->CanCoalesceWith(touch));
-
- if (!send_touch_move_now) {
- if (!pending_async_touch_move_) {
- pending_async_touch_move_.reset(new TouchEventWithLatencyInfo(touch));
- } else {
- DCHECK(pending_async_touch_move_->CanCoalesceWith(touch));
- pending_async_touch_move_->CoalesceWith(touch);
- }
- PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
- return;
- }
- }
-
- last_sent_touch_timestamp_sec_ = touch.event.timeStampSeconds;
-
- // Flush any pending async touch move. If it can be combined with the current
- // (touchmove) event, great, otherwise send it immediately but separately. Its
- // ack will trigger forwarding of the original |touch| event.
- if (pending_async_touch_move_) {
- if (pending_async_touch_move_->CanCoalesceWith(touch)) {
- pending_async_touch_move_->CoalesceWith(touch);
- pending_async_touch_move_->event.cancelable = !send_touch_events_async_;
- touch = *pending_async_touch_move_.Pass();
- } else {
- scoped_ptr<TouchEventWithLatencyInfo> async_move =
- pending_async_touch_move_.Pass();
- async_move->event.cancelable = false;
- touch_queue_.push_front(new CoalescedWebTouchEvent(*async_move, true));
- SendTouchEventImmediately(*async_move);
- return;
- }
- }
-
- // Note: Marking touchstart events as not-cancelable prevents them from
- // blocking subsequent gestures, but it may not be the best long term solution
- // for tracking touch point dispatch.
- if (send_touch_events_async_)
- touch.event.cancelable = false;
-
// A synchronous ack will reset |dispatching_touch_|, in which case
// the touch timeout should not be started.
base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true);
- SendTouchEventImmediately(touch);
+ client_->SendTouchEventImmediately(touch);
if (dispatching_touch_ &&
touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT &&
- ShouldTouchTriggerTimeout(touch.event)) {
+ ShouldTouchTypeTriggerTimeout(touch.event.type)) {
DCHECK(timeout_handler_);
timeout_handler_->Start(touch);
}
@@ -520,12 +431,8 @@
if (gesture_event.event.type != blink::WebInputEvent::GestureScrollBegin)
return;
- if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) {
- pending_async_touch_move_.reset();
- send_touch_events_async_ = true;
- needs_async_touch_move_for_outer_slop_region_ = true;
- return;
- }
+ if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE)
+ absorbing_touch_moves_ = true;
if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_TOUCHCANCEL)
return;
@@ -556,21 +463,18 @@
void TouchEventQueue::OnGestureEventAck(
const GestureEventWithLatencyInfo& event,
InputEventAckState ack_result) {
- if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE)
+ if (touch_scrolling_mode_ != TOUCH_SCROLLING_MODE_ABSORB_TOUCHMOVE)
return;
if (event.event.type != blink::WebInputEvent::GestureScrollUpdate)
return;
- // Throttle sending touchmove events as long as the scroll events are handled.
+ // Suspend sending touchmove events as long as the scroll events are handled.
// Note that there's no guarantee that this ACK is for the most recent
// gesture event (or even part of the current sequence). Worst case, the
- // delay in updating the absorption state will result in minor UI glitches.
- // A valid |pending_async_touch_move_| will be flushed when the next event is
- // forwarded.
- send_touch_events_async_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
- if (!send_touch_events_async_)
- needs_async_touch_move_for_outer_slop_region_ = false;
+ // delay in updating the absorption state should only result in minor UI
+ // glitches.
+ absorbing_touch_moves_ = (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED);
}
void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) {
@@ -588,7 +492,6 @@
// TODO(jdduke): Synthesize a TouchCancel if necessary to update Blink touch
// state tracking (e.g., if the touch handler was removed mid-sequence).
touch_filtering_state_ = DROP_ALL_TOUCHES;
- pending_async_touch_move_.reset();
if (timeout_handler_)
timeout_handler_->Reset();
if (!touch_queue_.empty())
@@ -629,10 +532,6 @@
timeout_handler_->set_timeout_delay(ack_timeout_delay);
}
-bool TouchEventQueue::HasPendingAsyncTouchMoveForTesting() const {
- return pending_async_touch_move_;
-}
-
bool TouchEventQueue::IsTimeoutRunningForTesting() const {
return timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning();
}
@@ -645,59 +544,37 @@
void TouchEventQueue::FlushQueue() {
DCHECK(!dispatching_touch_ack_);
DCHECK(!dispatching_touch_);
- pending_async_touch_move_.reset();
if (touch_filtering_state_ != DROP_ALL_TOUCHES)
touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
- while (!touch_queue_.empty())
- PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
+ while (!touch_queue_.empty()) {
+ PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS,
+ LatencyInfo());
+ }
}
-void TouchEventQueue::PopTouchEventToClient(InputEventAckState ack_result) {
- AckTouchEventToClient(ack_result, PopTouchEvent());
-}
-
void TouchEventQueue::PopTouchEventToClient(
InputEventAckState ack_result,
const LatencyInfo& renderer_latency_info) {
- scoped_ptr<CoalescedWebTouchEvent> acked_event = PopTouchEvent();
- acked_event->UpdateLatencyInfoForAck(renderer_latency_info);
- AckTouchEventToClient(ack_result, acked_event.Pass());
-}
-
-void TouchEventQueue::AckTouchEventToClient(
- InputEventAckState ack_result,
- scoped_ptr<CoalescedWebTouchEvent> acked_event) {
- DCHECK(acked_event);
DCHECK(!dispatching_touch_ack_);
- UpdateTouchAckStates(acked_event->coalesced_event().event, ack_result);
+ if (touch_queue_.empty())
+ return;
+ scoped_ptr<CoalescedWebTouchEvent> acked_event(touch_queue_.front());
+ touch_queue_.pop_front();
+ if (acked_event->ignore_ack())
+ return;
+
// Note that acking the touch-event may result in multiple gestures being sent
// to the renderer, or touch-events being queued.
- base::AutoReset<const CoalescedWebTouchEvent*> dispatching_touch_ack(
- &dispatching_touch_ack_, acked_event.get());
- acked_event->DispatchAckToClient(ack_result, client_);
-}
+ base::AutoReset<CoalescedWebTouchEvent*>
+ dispatching_touch_ack(&dispatching_touch_ack_, acked_event.get());
-scoped_ptr<CoalescedWebTouchEvent> TouchEventQueue::PopTouchEvent() {
- DCHECK(!touch_queue_.empty());
- scoped_ptr<CoalescedWebTouchEvent> event(touch_queue_.front());
- touch_queue_.pop_front();
- return event.Pass();
-}
-
-void TouchEventQueue::SendTouchEventImmediately(
- const TouchEventWithLatencyInfo& touch) {
- if (needs_async_touch_move_for_outer_slop_region_) {
- // Any event other than a touchmove (e.g., touchcancel or secondary
- // touchstart) after a scroll has started will interrupt the need to send a
- // an outer slop-region exceeding touchmove.
- if (touch.event.type != WebInputEvent::TouchMove ||
- OutsideApplicationSlopRegion(touch.event,
- touch_sequence_start_position_))
- needs_async_touch_move_for_outer_slop_region_ = false;
+ for (WebTouchEventWithLatencyList::iterator iter = acked_event->begin(),
+ end = acked_event->end();
+ iter != end; ++iter) {
+ iter->latency.AddNewLatencyFrom(renderer_latency_info);
+ client_->OnTouchEventAck((*iter), ack_result);
}
-
- client_->SendTouchEventImmediately(touch);
}
TouchEventQueue::PreFilterResult
@@ -715,9 +592,12 @@
event.type != WebInputEvent::TouchCancel) {
if (WebTouchEventTraits::IsTouchSequenceStart(event))
return FORWARD_TO_RENDERER;
- return ACK_WITH_NO_CONSUMER_EXISTS;
+ return ACK_WITH_NOT_CONSUMED;
}
+ if (absorbing_touch_moves_ && event.type == WebInputEvent::TouchMove)
+ return ACK_WITH_NOT_CONSUMED;
+
// Touch press events should always be forwarded to the renderer.
if (event.type == WebInputEvent::TouchStart)
return FORWARD_TO_RENDERER;

Powered by Google App Engine
This is Rietveld 408576698