Index: content/browser/renderer_host/input/touch_event_queue.cc |
diff --git a/content/browser/renderer_host/input/touch_event_queue.cc b/content/browser/renderer_host/input/touch_event_queue.cc |
index b0646ebdff63fe82ef2154076f3e3823eab4c65e..16d9e114ed871b7c25e33fed81538c19000b6805 100644 |
--- a/content/browser/renderer_host/input/touch_event_queue.cc |
+++ b/content/browser/renderer_host/input/touch_event_queue.cc |
@@ -392,20 +392,11 @@ void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result, |
if (touch_queue_.empty()) |
return; |
- const WebTouchEvent& acked_event = |
- touch_queue_.front()->coalesced_event().event; |
- |
if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED && |
touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT) { |
touch_filtering_state_ = FORWARD_ALL_TOUCHES; |
} |
- if (ack_result == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS && |
- touch_filtering_state_ != DROP_ALL_TOUCHES && |
- WebTouchEventTraits::IsTouchSequenceStart(acked_event)) { |
- touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; |
- } |
- |
PopTouchEventToClient(ack_result, latency_info); |
TryForwardNextEventToRenderer(); |
} |
@@ -473,7 +464,13 @@ void TouchEventQueue::ForwardNextEventToRenderer() { |
DCHECK(pending_async_touch_move_->CanCoalesceWith(touch)); |
pending_async_touch_move_->CoalesceWith(touch); |
} |
+ DCHECK_EQ(1U, size()); |
PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
+ // It's possible (though unlikely) that ack'ing the current touch will |
+ // trigger the queueing of another touch event (e.g., a touchcancel). As |
+ // forwarding of the queued event will be deferred while the ack is being |
+ // dispatched (see |OnTouchEvent()|), try forwarding it now. |
+ TryForwardNextEventToRenderer(); |
return; |
} |
} |
@@ -522,6 +519,21 @@ void TouchEventQueue::OnGestureScrollEvent( |
return; |
if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) { |
+ if (touch_filtering_state_ != DROP_ALL_TOUCHES && |
+ touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE) { |
+ // If no touch points have a consumer, prevent all subsequent touch events |
+ // received during the scroll from reaching the renderer. This ensures |
+ // that the first touchstart the renderer sees in any given sequence can |
+ // always be preventDefault'ed (cancelable == true). |
+ // TODO(jdduke): Revisit if touchstarts during scroll are made cancelable. |
+ if (touch_ack_states_.empty() || |
+ AllTouchAckStatesHaveState( |
+ INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)) { |
+ touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE; |
+ return; |
+ } |
+ } |
+ |
pending_async_touch_move_.reset(); |
send_touch_events_async_ = true; |
needs_async_touch_move_for_outer_slop_region_ = true; |
@@ -764,4 +776,20 @@ void TouchEventQueue::UpdateTouchAckStates(const WebTouchEvent& event, |
} |
} |
+bool TouchEventQueue::AllTouchAckStatesHaveState( |
+ InputEventAckState ack_state) const { |
+ if (touch_ack_states_.empty()) |
+ return false; |
+ |
+ for (TouchPointAckStates::const_iterator iter = touch_ack_states_.begin(), |
+ end = touch_ack_states_.end(); |
+ iter != end; |
+ ++iter) { |
+ if (iter->second != ack_state) |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
} // namespace content |