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

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

Issue 156783006: Consuming a touch move prevents only the next scroll update. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address rbyers' comments. Created 6 years, 10 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_disposition_gesture_filter.cc
diff --git a/content/browser/renderer_host/input/touch_disposition_gesture_filter.cc b/content/browser/renderer_host/input/touch_disposition_gesture_filter.cc
index 35db76779b68b34b26912e864c09b3983abf38ee..ef283eb763f6914d46655c5256f14535a19b85a8 100644
--- a/content/browser/renderer_host/input/touch_disposition_gesture_filter.cc
+++ b/content/browser/renderer_host/input/touch_disposition_gesture_filter.cc
@@ -24,6 +24,73 @@ WebGestureEvent CreateGesture(WebInputEvent::Type type) {
return event;
}
+struct DispositionHandlingInfo {
+ // A bitwise-OR of |RequiredTouches|.
+ int required_touches;
+ blink::WebInputEvent::Type antecedent_event_type;
+
+ DispositionHandlingInfo(int required_touches)
+ : required_touches(required_touches) {}
+
+ DispositionHandlingInfo(int required_touches,
+ blink::WebInputEvent::Type antecedent_event_type)
+ : required_touches(required_touches),
+ antecedent_event_type(antecedent_event_type) {}
+};
+
+DispositionHandlingInfo Info(int required_touches) {
+ return DispositionHandlingInfo(required_touches);
+}
+
+DispositionHandlingInfo Info(int required_touches,
+ blink::WebInputEvent::Type antecedent_event_type) {
+ return DispositionHandlingInfo(required_touches, antecedent_event_type);
+}
+
+// This approach to disposition handling is described at http://goo.gl/5G8PWJ.
+DispositionHandlingInfo GetDispositionHandlingInfo(
+ blink::WebInputEvent::Type type) {
+ switch (type) {
+ case WebInputEvent::GestureTapDown:
+ return Info(RT_START);
+ case WebInputEvent::GestureTapCancel:
+ return Info(RT_START);
+ case WebInputEvent::GestureShowPress:
+ return Info(RT_START);
+ case WebInputEvent::GestureLongPress:
+ return Info(RT_START);
+ case WebInputEvent::GestureLongTap:
+ return Info(RT_START | RT_CURRENT);
+ case WebInputEvent::GestureTap:
+ return Info(RT_START | RT_CURRENT, WebInputEvent::GestureTapUnconfirmed);
+ case WebInputEvent::GestureTwoFingerTap:
+ return Info(RT_START | RT_CURRENT);
+ case WebInputEvent::GestureTapUnconfirmed:
+ return Info(RT_START | RT_CURRENT);
+ case WebInputEvent::GestureDoubleTap:
+ return Info(RT_START | RT_CURRENT, WebInputEvent::GestureTapUnconfirmed);
+ case WebInputEvent::GestureScrollBegin:
+ return Info(RT_START | RT_CURRENT);
+ case WebInputEvent::GestureScrollUpdate:
+ return Info(RT_CURRENT, WebInputEvent::GestureScrollBegin);
+ case WebInputEvent::GestureScrollEnd:
+ return Info(RT_NONE, WebInputEvent::GestureScrollBegin);
+ case WebInputEvent::GestureFlingStart:
+ return Info(RT_NONE, WebInputEvent::GestureScrollBegin);
+ case WebInputEvent::GestureFlingCancel:
+ return Info(RT_NONE, WebInputEvent::GestureFlingStart);
+ case WebInputEvent::GesturePinchBegin:
+ return Info(RT_START, WebInputEvent::GestureScrollBegin);
+ case WebInputEvent::GesturePinchUpdate:
+ return Info(RT_CURRENT, WebInputEvent::GesturePinchBegin);
+ case WebInputEvent::GesturePinchEnd:
+ return Info(RT_NONE, WebInputEvent::GesturePinchBegin);
+ default:
+ NOTREACHED();
+ return Info(RT_NONE);
+ }
+}
+
} // namespace
// TouchDispositionGestureFilter
@@ -41,23 +108,22 @@ TouchDispositionGestureFilter::~TouchDispositionGestureFilter() {}
TouchDispositionGestureFilter::PacketResult
TouchDispositionGestureFilter::OnGestureEventPacket(
const GestureEventPacket& packet) {
- if (packet.gesture_source() == GestureEventPacket::INVALID)
+ if (packet.gesture_source() == GestureEventPacket::UNDEFINED)
return INVALID_PACKET_TYPE;
- if (packet.gesture_source() == GestureEventPacket::TOUCH_BEGIN)
+ if (packet.gesture_source() == GestureEventPacket::TOUCH_SEQUENCE_BEGIN)
sequences_.push(GestureSequence());
- if (IsEmpty())
+ if (packet.gesture_source() == GestureEventPacket::INVALID || IsEmpty())
jdduke (slow) 2014/02/14 16:59:52 Please move this |GestureEventPacket::INVALID| che
tdresser 2014/02/14 17:56:11 Done.
return INVALID_PACKET_ORDER;
- if (packet.gesture_source() == GestureEventPacket::TOUCH_TIMEOUT) {
- // Handle the timeout packet immediately if the packet preceding the
- // timeout has already been dispatched.
- if (Tail().IsEmpty()) {
- if (!Tail().IsGesturePrevented())
- SendPacket(packet);
- return SUCCESS;
- }
+ if (packet.gesture_source() == GestureEventPacket::TOUCH_TIMEOUT &&
+ Tail().IsEmpty()) {
+ // Handle the timeout packet immediately if the packet preceding the timeout
+ // has already been dispatched.
+ FilterAndSendPacket(
+ packet, Tail().state(), INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ return SUCCESS;
}
Tail().Push(packet);
@@ -73,48 +139,52 @@ void TouchDispositionGestureFilter::OnTouchEventAck(
if (Head().IsEmpty()) {
CancelTapIfNecessary();
CancelFlingIfNecessary();
+ last_event_of_type_dropped_.clear();
jdduke (slow) 2014/02/14 16:59:52 Does std::set typically deallocate memory hear (un
tdresser 2014/02/14 17:56:11 Yeah, this does deallocate memory. I was initially
sequences_.pop();
}
GestureSequence& sequence = Head();
- sequence.UpdateState(ack_state);
// Dispatch the packet corresponding to the ack'ed touch, as well as any
// additional timeout-based packets queued before the ack was received.
bool touch_packet_for_current_ack_handled = false;
while (!sequence.IsEmpty()) {
const GestureEventPacket& packet = sequence.Front();
+ DCHECK(packet.gesture_source() != GestureEventPacket::UNDEFINED);
jdduke (slow) 2014/02/14 16:59:52 DCHECK_NE
tdresser 2014/02/14 17:56:11 Done.
+ DCHECK(packet.gesture_source() != GestureEventPacket::INVALID);
- if (packet.gesture_source() == GestureEventPacket::TOUCH_BEGIN ||
- packet.gesture_source() == GestureEventPacket::TOUCH) {
+ if (packet.gesture_source() != GestureEventPacket::TOUCH_TIMEOUT) {
// We should handle at most one touch-based packet corresponding to a
jdduke (slow) 2014/02/14 16:59:52 Hmm, I realize this was my comment, but maybe chan
tdresser 2014/02/14 17:56:11 Done.
// given ack.
if (touch_packet_for_current_ack_handled)
break;
+ sequence.UpdateState(packet.gesture_source(), ack_state);
touch_packet_for_current_ack_handled = true;
}
-
- if (!sequence.IsGesturePrevented())
- SendPacket(packet);
-
+ FilterAndSendPacket(packet, sequence.state(), ack_state);
sequence.Pop();
}
DCHECK(touch_packet_for_current_ack_handled);
-
- // Immediately cancel a TapDown if TouchStart went unconsumed, but a
- // subsequent TouchMove is consumed.
- if (sequence.IsGesturePrevented())
- CancelTapIfNecessary();
}
bool TouchDispositionGestureFilter::IsEmpty() const {
return sequences_.empty();
}
-void TouchDispositionGestureFilter::SendPacket(
- const GestureEventPacket& packet) {
- for (size_t i = 0; i < packet.gesture_count(); ++i)
- SendGesture(packet.gesture(i));
+void TouchDispositionGestureFilter::FilterAndSendPacket(
+ const GestureEventPacket& packet,
+ const GestureSequence::GestureHandlingState& sequence_state,
+ InputEventAckState ack_state) {
+ for (size_t i = 0; i < packet.gesture_count(); ++i) {
+ const blink::WebGestureEvent& gesture = packet.gesture(i);
+ if (IsGesturePrevented(gesture.type, ack_state, sequence_state)) {
+ last_event_of_type_dropped_.insert(gesture.type);
+ CancelTapIfNecessary();
+ continue;
+ }
+ last_event_of_type_dropped_.erase(gesture.type);
+ SendGesture(gesture);
+ }
}
void TouchDispositionGestureFilter::SendGesture(const WebGestureEvent& event) {
@@ -124,6 +194,7 @@ void TouchDispositionGestureFilter::SendGesture(const WebGestureEvent& event) {
CancelFlingIfNecessary();
break;
case WebInputEvent::GestureTapDown:
+ DCHECK(!needs_tap_ending_event_);
needs_tap_ending_event_ = true;
break;
case WebInputEvent::GestureTapCancel:
@@ -165,6 +236,12 @@ void TouchDispositionGestureFilter::CancelFlingIfNecessary() {
DCHECK(!needs_fling_ending_event_);
}
+TouchDispositionGestureFilter::GestureSequence::GestureHandlingState::
+ GestureHandlingState()
+ : seen_ack(false),
+ start_consumed(false),
+ no_consumer(false) {}
+
TouchDispositionGestureFilter::GestureSequence&
TouchDispositionGestureFilter::Head() {
DCHECK(!sequences_.empty());
@@ -177,11 +254,7 @@ TouchDispositionGestureFilter::Tail() {
return sequences_.back();
}
-
-// TouchDispositionGestureFilter::GestureSequence
jdduke (slow) 2014/02/14 16:59:52 Hmm, did we still want this comment?
tdresser 2014/02/14 17:56:11 Readded.
-
-TouchDispositionGestureFilter::GestureSequence::GestureSequence()
- : state_(PENDING) {}
+TouchDispositionGestureFilter::GestureSequence::GestureSequence() {}
TouchDispositionGestureFilter::GestureSequence::~GestureSequence() {}
@@ -202,25 +275,46 @@ TouchDispositionGestureFilter::GestureSequence::Front() const {
}
void TouchDispositionGestureFilter::GestureSequence::UpdateState(
+ GestureEventPacket::GestureSource gesture_source,
jdduke (slow) 2014/02/14 16:59:52 Can't tell if this is aligned.
tdresser 2014/02/14 17:56:11 It is.
InputEventAckState ack_state) {
DCHECK_NE(INPUT_EVENT_ACK_STATE_UNKNOWN, ack_state);
// Permanent states will not be affected by subsequent ack's.
- if (state_ != PENDING && state_ != ALLOWED_UNTIL_PREVENTED)
+ if (state_.no_consumer || state_.start_consumed)
return;
// |NO_CONSUMER| should only be effective when the *first* touch is ack'ed.
- if (state_ == PENDING &&
- ack_state == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS)
- state_ = ALWAYS_ALLOWED;
- else if (ack_state == INPUT_EVENT_ACK_STATE_CONSUMED)
- state_ = ALWAYS_PREVENTED;
- else
- state_ = ALLOWED_UNTIL_PREVENTED;
-}
-
-bool TouchDispositionGestureFilter::GestureSequence::IsGesturePrevented()
- const {
- return state_ == ALWAYS_PREVENTED;
+ if (!state_.seen_ack &&
+ ack_state == INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) {
+ state_.no_consumer = true;
+ } else if (ack_state == INPUT_EVENT_ACK_STATE_CONSUMED) {
+ if (gesture_source == GestureEventPacket::TOUCH_SEQUENCE_BEGIN ||
+ gesture_source == GestureEventPacket::TOUCH_BEGIN) {
+ state_.start_consumed = true;
+ }
+ }
+ state_.seen_ack = true;
+}
+
+bool TouchDispositionGestureFilter::IsGesturePrevented(
+ WebInputEvent::Type gesture_type,
+ InputEventAckState current,
+ const GestureSequence::GestureHandlingState& state) const {
+
+ if (state.no_consumer)
+ return false;
+
+ DispositionHandlingInfo disposition_handling_info =
+ GetDispositionHandlingInfo(gesture_type);
+
+ int required_touches = disposition_handling_info.required_touches;
+ bool current_consumed = current == INPUT_EVENT_ACK_STATE_CONSUMED;
+ if ((required_touches & RT_START && state.start_consumed) ||
+ (required_touches & RT_CURRENT && current_consumed) ||
+ (last_event_of_type_dropped_.count(
+ disposition_handling_info.antecedent_event_type) > 0)) {
+ return true;
+ }
+ return false;
}
bool TouchDispositionGestureFilter::GestureSequence::IsEmpty() const {

Powered by Google App Engine
This is Rietveld 408576698