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

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

Issue 586553002: Allow repeated handler removal/addition with the TouchEventQueue (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 6 years, 3 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: 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 8b03c889980329715a5e70dd6a9c9b07788a865d..7edb36356832cad183e651044ba6d5ca3e154218 100644
--- a/content/browser/renderer_host/input/touch_event_queue.cc
+++ b/content/browser/renderer_host/input/touch_event_queue.cc
@@ -69,15 +69,28 @@ class TouchEventQueue::TouchTimeoutHandler {
timeout_delay_(timeout_delay),
pending_ack_state_(PENDING_ACK_NONE),
timeout_monitor_(base::Bind(&TouchTimeoutHandler::OnTimeOut,
- base::Unretained(this))) {
+ base::Unretained(this))),
+ enabled_(true),
+ enabled_for_current_sequence_(false) {
DCHECK(timeout_delay != base::TimeDelta());
}
~TouchTimeoutHandler() {}
- void Start(const TouchEventWithLatencyInfo& event) {
+ void StartIfNecessary(const TouchEventWithLatencyInfo& event) {
DCHECK_EQ(pending_ack_state_, PENDING_ACK_NONE);
- DCHECK(ShouldTouchTriggerTimeout(event.event));
+ if (!enabled_)
+ return;
+
+ if (!ShouldTouchTriggerTimeout(event.event))
+ return;
+
+ if (WebTouchEventTraits::IsTouchSequenceStart(event.event))
+ enabled_for_current_sequence_ = true;
+
+ if (!enabled_for_current_sequence_)
+ return;
+
timeout_event_ = event;
timeout_monitor_.Restart(timeout_delay_);
}
@@ -85,6 +98,8 @@ class TouchEventQueue::TouchTimeoutHandler {
bool ConfirmTouchEvent(InputEventAckState ack_result) {
switch (pending_ack_state_) {
case PENDING_ACK_NONE:
+ if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
+ enabled_for_current_sequence_ = false;
timeout_monitor_.Stop();
return false;
case PENDING_ACK_ORIGINAL_EVENT:
@@ -95,7 +110,8 @@ class TouchEventQueue::TouchTimeoutHandler {
touch_queue_->SendTouchEventImmediately(cancel_event);
} else {
SetPendingAckState(PENDING_ACK_NONE);
- touch_queue_->UpdateTouchAckStates(timeout_event_.event, ack_result);
+ touch_queue_->UpdateTouchConsumerStates(timeout_event_.event,
+ ack_result);
}
return true;
case PENDING_ACK_CANCEL_EVENT:
@@ -109,19 +125,29 @@ class TouchEventQueue::TouchTimeoutHandler {
return HasTimeoutEvent();
}
- bool IsTimeoutTimerRunning() const {
- return timeout_monitor_.IsRunning();
- }
+ void SetEnabled(bool enabled) {
+ if (enabled_ == enabled)
+ return;
- void Reset() {
- pending_ack_state_ = PENDING_ACK_NONE;
- timeout_monitor_.Stop();
- }
+ enabled_ = enabled;
- void set_timeout_delay(base::TimeDelta timeout_delay) {
- timeout_delay_ = timeout_delay;
+ if (enabled_)
+ return;
+
+ enabled_for_current_sequence_ = false;
+ // Only reset the |timeout_handler_| if the timer is running and has not
+ // yet timed out. This ensures that an already timed out sequence is
+ // properly flushed by the handler.
+ if (IsTimeoutTimerRunning()) {
+ pending_ack_state_ = PENDING_ACK_NONE;
+ timeout_monitor_.Stop();
+ }
}
+ bool IsTimeoutTimerRunning() const { return timeout_monitor_.IsRunning(); }
+
+ bool enabled() const { return enabled_; }
+
private:
enum PendingAckState {
PENDING_ACK_NONE,
@@ -184,6 +210,9 @@ class TouchEventQueue::TouchTimeoutHandler {
// Provides timeout-based callback behavior.
TimeoutMonitor timeout_monitor_;
+
+ bool enabled_;
+ bool enabled_for_current_sequence_;
};
// Provides touchmove slop suppression for a single touch that remains within
@@ -344,8 +373,7 @@ TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client,
: client_(client),
dispatching_touch_ack_(NULL),
dispatching_touch_(false),
- touch_filtering_state_(TOUCH_FILTERING_STATE_DEFAULT),
- ack_timeout_enabled_(config.touch_ack_timeout_supported),
+ has_handlers_(true),
touchmove_slop_suppressor_(new TouchMoveSlopSuppressor(
config.touchmove_slop_suppression_length_dips)),
send_touch_events_async_(false),
@@ -353,7 +381,7 @@ TouchEventQueue::TouchEventQueue(TouchEventQueueClient* client,
last_sent_touch_timestamp_sec_(0),
touch_scrolling_mode_(config.touch_scrolling_mode) {
DCHECK(client);
- if (ack_timeout_enabled_) {
+ if (config.touch_ack_timeout_supported) {
timeout_handler_.reset(
new TouchTimeoutHandler(this, config.touch_ack_timeout_delay));
}
@@ -413,11 +441,6 @@ void TouchEventQueue::ProcessTouchAck(InputEventAckState ack_result,
if (touch_queue_.empty())
return;
- if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED &&
- touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT) {
- touch_filtering_state_ = FORWARD_ALL_TOUCHES;
- }
-
PopTouchEventToClient(ack_result, latency_info);
TryForwardNextEventToRenderer();
}
@@ -448,20 +471,8 @@ void TouchEventQueue::ForwardNextEventToRenderer() {
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;
- pending_async_touchmove_.reset();
- touch_sequence_start_position_ =
- gfx::PointF(touch.event.touches[0].position);
- }
-
if (send_touch_events_async_ &&
touch.event.type == WebInputEvent::TouchMove) {
// Throttling touchmove's in a continuous touchmove stream while scrolling
@@ -527,36 +538,27 @@ void TouchEventQueue::ForwardNextEventToRenderer() {
// the touch timeout should not be started.
base::AutoReset<bool> dispatching_touch(&dispatching_touch_, true);
SendTouchEventImmediately(touch);
- if (dispatching_touch_ &&
- touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT &&
- ShouldTouchTriggerTimeout(touch.event)) {
- DCHECK(timeout_handler_);
- timeout_handler_->Start(touch);
- }
+ if (dispatching_touch_ && timeout_handler_)
+ timeout_handler_->StartIfNecessary(touch);
}
void TouchEventQueue::OnGestureScrollEvent(
const GestureEventWithLatencyInfo& gesture_event) {
if (gesture_event.event.type == blink::WebInputEvent::GestureScrollBegin) {
- if (touch_filtering_state_ != DROP_ALL_TOUCHES &&
- touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE) {
+ if (!touch_consumer_states_.is_empty() &&
+ !drop_remaining_touches_in_sequence_) {
DCHECK(!touchmove_slop_suppressor_->suppressing_touchmoves())
- << "The renderer should be offered a touchmove before scrolling "
- "begins";
+ << "A touch handler should be offered a touchmove before scrolling.";
}
-
if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE &&
- touch_filtering_state_ != DROP_ALL_TOUCHES &&
- touch_filtering_state_ != DROP_TOUCHES_IN_SEQUENCE &&
- (touch_ack_states_.empty() ||
- AllTouchAckStatesHaveState(
- INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS))) {
+ !drop_remaining_touches_in_sequence_ &&
+ touch_consumer_states_.is_empty()) {
// 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.
- touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
+ drop_remaining_touches_in_sequence_ = true;
}
if (touch_scrolling_mode_ == TOUCH_SCROLLING_MODE_ASYNC_TOUCHMOVE) {
@@ -583,10 +585,10 @@ void TouchEventQueue::OnGestureScrollEvent(
if (!dispatching_touch_ack_)
return;
- if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE)
+ if (drop_remaining_touches_in_sequence_)
return;
- touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
+ drop_remaining_touches_in_sequence_ = true;
// Fake a TouchCancel to cancel the touch points of the touch event
// that is currently being acked.
@@ -622,22 +624,7 @@ void TouchEventQueue::OnGestureEventAck(
void TouchEventQueue::OnHasTouchEventHandlers(bool has_handlers) {
DCHECK(!dispatching_touch_ack_);
DCHECK(!dispatching_touch_);
-
- if (has_handlers) {
- if (touch_filtering_state_ == DROP_ALL_TOUCHES) {
- // If no touch handler was previously registered, ensure that we don't
- // send a partial touch sequence to the renderer.
- touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
- }
- } else {
- // TODO(jdduke): Synthesize a TouchCancel if necessary to update Blink touch
- // state tracking and/or touch-action filtering (e.g., if the touch handler
- // was removed mid-sequence), crbug.com/375940.
- touch_filtering_state_ = DROP_ALL_TOUCHES;
- pending_async_touchmove_.reset();
- if (timeout_handler_)
- timeout_handler_->Reset();
- }
+ has_handlers_ = has_handlers;
}
bool TouchEventQueue::IsPendingAckTouchStart() const {
@@ -651,25 +638,12 @@ bool TouchEventQueue::IsPendingAckTouchStart() const {
}
void TouchEventQueue::SetAckTimeoutEnabled(bool enabled) {
- // The timeout handler is valid only if explicitly supported in the config.
- if (!timeout_handler_)
- return;
-
- if (ack_timeout_enabled_ == enabled)
- return;
-
- ack_timeout_enabled_ = enabled;
-
- if (enabled)
- return;
+ if (timeout_handler_)
+ timeout_handler_->SetEnabled(enabled);
+}
- if (touch_filtering_state_ == FORWARD_TOUCHES_UNTIL_TIMEOUT)
- touch_filtering_state_ = FORWARD_ALL_TOUCHES;
- // Only reset the |timeout_handler_| if the timer is running and has not yet
- // timed out. This ensures that an already timed out sequence is properly
- // flushed by the handler.
- if (timeout_handler_ && timeout_handler_->IsTimeoutTimerRunning())
- timeout_handler_->Reset();
+bool TouchEventQueue::IsAckTimeoutEnabled() const {
+ return timeout_handler_ && timeout_handler_->enabled();
}
bool TouchEventQueue::HasPendingAsyncTouchMoveForTesting() const {
@@ -689,8 +663,7 @@ void TouchEventQueue::FlushQueue() {
DCHECK(!dispatching_touch_ack_);
DCHECK(!dispatching_touch_);
pending_async_touchmove_.reset();
- if (touch_filtering_state_ != DROP_ALL_TOUCHES)
- touch_filtering_state_ = DROP_TOUCHES_IN_SEQUENCE;
+ drop_remaining_touches_in_sequence_ = true;
while (!touch_queue_.empty())
PopTouchEventToClient(INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
}
@@ -711,7 +684,7 @@ void TouchEventQueue::AckTouchEventToClient(
const ui::LatencyInfo* optional_latency_info) {
DCHECK(acked_event);
DCHECK(!dispatching_touch_ack_);
- UpdateTouchAckStates(acked_event->coalesced_event().event, ack_result);
+ UpdateTouchConsumerStates(acked_event->coalesced_event().event, ack_result);
// Note that acking the touch-event may result in multiple gestures being sent
// to the renderer, or touch-events being queued.
@@ -750,19 +723,25 @@ TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
if (touchmove_slop_suppressor_->FilterEvent(event))
return ACK_WITH_NOT_CONSUMED;
- if (touch_filtering_state_ == DROP_ALL_TOUCHES)
- return ACK_WITH_NO_CONSUMER_EXISTS;
+ if (WebTouchEventTraits::IsTouchSequenceStart(event)) {
+ touch_consumer_states_.clear();
+ send_touch_events_async_ = false;
+ pending_async_touchmove_.reset();
+ touch_sequence_start_position_ = gfx::PointF(event.touches[0].position);
+ drop_remaining_touches_in_sequence_ = false;
+ if (!has_handlers_) {
+ drop_remaining_touches_in_sequence_ = true;
+ return ACK_WITH_NO_CONSUMER_EXISTS;
+ }
+ }
- if (touch_filtering_state_ == DROP_TOUCHES_IN_SEQUENCE &&
+ if (drop_remaining_touches_in_sequence_ &&
event.type != WebInputEvent::TouchCancel) {
- if (WebTouchEventTraits::IsTouchSequenceStart(event))
- return FORWARD_TO_RENDERER;
return ACK_WITH_NO_CONSUMER_EXISTS;
}
- // Touch press events should always be forwarded to the renderer.
if (event.type == WebInputEvent::TouchStart)
- return FORWARD_TO_RENDERER;
+ return has_handlers_ ? FORWARD_TO_RENDERER : ACK_WITH_NO_CONSUMER_EXISTS;
for (unsigned int i = 0; i < event.touchesLength; ++i) {
const WebTouchPoint& point = event.touches[i];
@@ -770,22 +749,15 @@ TouchEventQueue::FilterBeforeForwarding(const WebTouchEvent& event) {
if (point.state == WebTouchPoint::StateStationary)
continue;
- if (touch_ack_states_.count(point.id) > 0) {
- if (touch_ack_states_.find(point.id)->second !=
- INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
- return FORWARD_TO_RENDERER;
- } else {
- // If the ACK status of a point is unknown, then the event should be
- // forwarded to the renderer.
+ if (touch_consumer_states_.has_bit(point.id))
return FORWARD_TO_RENDERER;
- }
}
return ACK_WITH_NO_CONSUMER_EXISTS;
}
-void TouchEventQueue::UpdateTouchAckStates(const WebTouchEvent& event,
- InputEventAckState ack_result) {
+void TouchEventQueue::UpdateTouchConsumerStates(const WebTouchEvent& event,
+ InputEventAckState ack_result) {
// Update the ACK status for each touch point in the ACKed event.
if (event.type == WebInputEvent::TouchEnd ||
event.type == WebInputEvent::TouchCancel) {
@@ -794,31 +766,19 @@ void TouchEventQueue::UpdateTouchAckStates(const WebTouchEvent& event,
const WebTouchPoint& point = event.touches[i];
if (point.state == WebTouchPoint::StateReleased ||
point.state == WebTouchPoint::StateCancelled)
- touch_ack_states_.erase(point.id);
+ touch_consumer_states_.clear_bit(point.id);
}
} else if (event.type == WebInputEvent::TouchStart) {
for (unsigned i = 0; i < event.touchesLength; ++i) {
const WebTouchPoint& point = event.touches[i];
- if (point.state == WebTouchPoint::StatePressed)
- touch_ack_states_[point.id] = ack_result;
+ if (point.state == WebTouchPoint::StatePressed) {
+ if (ack_result != INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
+ touch_consumer_states_.mark_bit(point.id);
+ else
+ touch_consumer_states_.clear_bit(point.id);
+ }
}
}
}
-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

Powered by Google App Engine
This is Rietveld 408576698