Index: ui/events/gesture_detection/touch_disposition_gesture_filter.cc |
diff --git a/ui/events/gesture_detection/touch_disposition_gesture_filter.cc b/ui/events/gesture_detection/touch_disposition_gesture_filter.cc |
index fcb92d495d4bca53df5016a50209ccfe95328076..cda31031f64a3eaab805704007902541fb665b34 100644 |
--- a/ui/events/gesture_detection/touch_disposition_gesture_filter.cc |
+++ b/ui/events/gesture_detection/touch_disposition_gesture_filter.cc |
@@ -12,8 +12,8 @@ namespace ui { |
namespace { |
// A BitSet32 is used for tracking dropped gesture types. |
-COMPILE_ASSERT(ET_GESTURE_TYPE_END - ET_GESTURE_TYPE_START < 32, |
- gesture_type_count_too_large); |
+static_assert(ET_GESTURE_TYPE_END - ET_GESTURE_TYPE_START < 32, |
+ "gesture type count too large"); |
GestureEventData CreateGesture(EventType type, |
int motion_event_id, |
@@ -166,24 +166,51 @@ TouchDispositionGestureFilter::OnGesturePacket( |
return SUCCESS; |
} |
+ // Check the packet's unique_touch_event_id is valid and unique. |
+ if (!Tail().empty()) { |
+ DCHECK_NE(packet.unique_touch_event_id(), |
+ Tail().back().unique_touch_event_id()); |
+ } |
+ if (!Head().empty()) { |
+ DCHECK_NE(packet.unique_touch_event_id(), |
+ Head().front().unique_touch_event_id()); |
+ } |
+ |
Tail().push(packet); |
return SUCCESS; |
} |
-void TouchDispositionGestureFilter::OnTouchEventAck(bool event_consumed) { |
- // Spurious touch acks from the renderer should not trigger a crash. |
+void TouchDispositionGestureFilter::OnTouchEventAck(uint32 unique_event_id, |
+ bool event_consumed) { |
+ // Spurious asynchronous acks should not trigger a crash. |
if (IsEmpty() || (Head().empty() && sequences_.size() == 1)) |
return; |
if (Head().empty()) |
PopGestureSequence(); |
- GestureSequence& sequence = Head(); |
+ if (!Tail().empty() && |
+ Tail().back().unique_touch_event_id() == unique_event_id) { |
+ Tail().back().Ack(event_consumed); |
+ if (sequences_.size() == 1 && Tail().size() == 1) |
+ SendAckedEvents(); |
+ } else { |
+ DCHECK(!Head().empty()); |
+ DCHECK_EQ(Head().front().unique_touch_event_id(), unique_event_id); |
+ Head().front().Ack(event_consumed); |
+ SendAckedEvents(); |
+ } |
+} |
- // Dispatch the packet corresponding to the ack'ed touch, as well as any |
- // additional timeout-based packets queued before the ack was received. |
+void TouchDispositionGestureFilter::SendAckedEvents() { |
+ // Dispatch all packets corresponding to ack'ed touches, as well as |
+ // any pending timeout-based packets. |
bool touch_packet_for_current_ack_handled = false; |
- while (!sequence.empty()) { |
+ while (!IsEmpty() && (!Head().empty() || sequences_.size() != 1)) { |
+ if (Head().empty()) |
+ PopGestureSequence(); |
+ GestureSequence& sequence = Head(); |
+ |
DCHECK_NE(sequence.front().gesture_source(), |
GestureEventDataPacket::UNDEFINED); |
DCHECK_NE(sequence.front().gesture_source(), |
@@ -191,17 +218,21 @@ void TouchDispositionGestureFilter::OnTouchEventAck(bool event_consumed) { |
GestureEventDataPacket::GestureSource source = |
sequence.front().gesture_source(); |
+ GestureEventDataPacket::AckState ack_state = sequence.front().ack_state(); |
+ |
if (source != GestureEventDataPacket::TOUCH_TIMEOUT) { |
- // We should handle at most one non-timeout based packet. |
- if (touch_packet_for_current_ack_handled) |
+ // We've sent all packets which aren't pending their ack. |
+ if (ack_state == GestureEventDataPacket::AckState::PENDING) |
break; |
- state_.OnTouchEventAck(event_consumed, IsTouchStartEvent(source)); |
- touch_packet_for_current_ack_handled = true; |
+ state_.OnTouchEventAck( |
+ ack_state == GestureEventDataPacket::AckState::CONSUMED, |
+ IsTouchStartEvent(source)); |
} |
// We need to pop the current sequence before sending the packet, because |
// sending the packet could result in this method being re-entered (e.g. on |
// Aura, we could trigger a touch-cancel). As popping the sequence destroys |
// the packet, we copy the packet before popping it. |
+ touch_packet_for_current_ack_handled = true; |
const GestureEventDataPacket packet = sequence.front(); |
sequence.pop(); |
FilterAndSendPacket(packet); |
@@ -314,6 +345,15 @@ void TouchDispositionGestureFilter::SendGesture( |
ending_event_primary_tool_type_ = event.primary_tool_type; |
needs_scroll_ending_event_ = true; |
break; |
+ case ET_GESTURE_SCROLL_UPDATE: |
+ if (state_.HasFilteredGestureType(ET_GESTURE_SCROLL_UPDATE)) { |
+ GestureEventData modified_event(ET_GESTURE_SCROLL_UPDATE, event); |
+ modified_event.details |
+ .mark_previous_scroll_update_in_sequence_prevented(); |
+ client_->ForwardGestureEvent(modified_event); |
+ return; |
+ } |
+ break; |
case ET_GESTURE_SCROLL_END: |
needs_scroll_ending_event_ = false; |
break; |
@@ -418,10 +458,17 @@ bool TouchDispositionGestureFilter::GestureHandlingState::Filter( |
last_gesture_of_type_dropped_.has_bit( |
GetGestureTypeIndex(antecedent_event_type)))) { |
last_gesture_of_type_dropped_.mark_bit(GetGestureTypeIndex(gesture_type)); |
+ any_gesture_of_type_dropped_.mark_bit(GetGestureTypeIndex(gesture_type)); |
return true; |
} |
last_gesture_of_type_dropped_.clear_bit(GetGestureTypeIndex(gesture_type)); |
return false; |
} |
+bool TouchDispositionGestureFilter::GestureHandlingState:: |
+ HasFilteredGestureType(EventType gesture_type) const { |
+ return any_gesture_of_type_dropped_.has_bit( |
+ GetGestureTypeIndex(gesture_type)); |
+} |
+ |
} // namespace content |