| 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
|
|
|