Index: ui/base/gestures/gesture_recognizer_impl.cc |
diff --git a/ui/base/gestures/gesture_recognizer_impl.cc b/ui/base/gestures/gesture_recognizer_impl.cc |
index 990a188924c288ea26af604ca34817b6e623c0f4..718f0442af8b1e8731215c45c2f2a37230a52d7c 100644 |
--- a/ui/base/gestures/gesture_recognizer_impl.cc |
+++ b/ui/base/gestures/gesture_recognizer_impl.cc |
@@ -51,10 +51,27 @@ class MirroredTouchEvent : public TouchEvent { |
} |
private: |
- |
DISALLOW_COPY_AND_ASSIGN(MirroredTouchEvent); |
}; |
+class QueuedTouchEvent : public MirroredTouchEvent { |
+ public: |
+ QueuedTouchEvent(const TouchEvent* real, TouchStatus status) |
+ : MirroredTouchEvent(real), |
+ status_(status) { |
+ } |
+ |
+ virtual ~QueuedTouchEvent() { |
+ } |
+ |
+ TouchStatus status() const { return status_; } |
+ |
+ private: |
+ TouchStatus status_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(QueuedTouchEvent); |
+}; |
+ |
// A mirrored event, except for the type, which is always ET_TOUCH_CANCELLED. |
class CancelledTouchEvent : public MirroredTouchEvent { |
public: |
@@ -227,10 +244,8 @@ GestureSequence* GestureRecognizerImpl::GetGestureSequenceForConsumer( |
return gesture_sequence; |
} |
-GestureSequence::Gestures* GestureRecognizerImpl::ProcessTouchEventForGesture( |
- const TouchEvent& event, |
- ui::TouchStatus status, |
- GestureConsumer* target) { |
+void GestureRecognizerImpl::SetupTargets(const TouchEvent& event, |
+ GestureConsumer* target) { |
if (event.type() == ui::ET_TOUCH_RELEASED || |
event.type() == ui::ET_TOUCH_CANCELLED) { |
touch_id_target_[event.touch_id()] = NULL; |
@@ -239,6 +254,42 @@ GestureSequence::Gestures* GestureRecognizerImpl::ProcessTouchEventForGesture( |
if (target) |
touch_id_target_for_gestures_[event.touch_id()] = target; |
} |
+} |
+ |
+GestureSequence::Gestures* GestureRecognizerImpl::AdvanceTouchQueueByOne( |
+ GestureConsumer* consumer, |
+ ui::TouchStatus status) { |
+ CHECK(event_queue_[consumer]); |
+ CHECK(!event_queue_[consumer]->empty()); |
+ |
+ ScopedPop pop(event_queue_[consumer]); |
+ TouchEvent* event = event_queue_[consumer]->front(); |
+ GestureSequence* sequence = GetGestureSequenceForConsumer(consumer); |
+ if (status != ui::TOUCH_STATUS_UNKNOWN && |
+ event->type() == ui::ET_TOUCH_RELEASED) { |
+ // A touch release was was processed (e.g. preventDefault()ed by a |
+ // web-page), but we still need to process a touch cancel. |
+ CancelledTouchEvent cancelled(event); |
+ return sequence->ProcessTouchEventForGesture(cancelled, |
+ ui::TOUCH_STATUS_UNKNOWN); |
+ } |
+ return sequence->ProcessTouchEventForGesture(*event, status); |
+} |
+ |
+GestureSequence::Gestures* GestureRecognizerImpl::ProcessTouchEventForGesture( |
+ const TouchEvent& event, |
+ ui::TouchStatus status, |
+ GestureConsumer* target) { |
+ if (event_queue_[target] && event_queue_[target]->size() > 0) { |
+ // There are some queued touch-events for this target. Processing |event| |
+ // before those queued events will result in unexpected gestures. So |
+ // postpone the processing of the events until the queued events have been |
+ // processed. |
+ event_queue_[target]->push(new QueuedTouchEvent(&event, status)); |
+ return NULL; |
+ } |
+ |
+ SetupTargets(event, target); |
GestureSequence* gesture_sequence = GetGestureSequenceForConsumer(target); |
return gesture_sequence->ProcessTouchEventForGesture(event, status); |
@@ -248,7 +299,10 @@ void GestureRecognizerImpl::QueueTouchEventForGesture(GestureConsumer* consumer, |
const TouchEvent& event) { |
if (!event_queue_[consumer]) |
event_queue_[consumer] = new std::queue<TouchEvent*>(); |
- event_queue_[consumer]->push(new MirroredTouchEvent(&event)); |
+ event_queue_[consumer]->push( |
+ new QueuedTouchEvent(&event, TOUCH_STATUS_QUEUED)); |
+ |
+ SetupTargets(event, consumer); |
} |
GestureSequence::Gestures* GestureRecognizerImpl::AdvanceTouchQueue( |
@@ -259,22 +313,30 @@ GestureSequence::Gestures* GestureRecognizerImpl::AdvanceTouchQueue( |
return NULL; |
} |
- ScopedPop pop(event_queue_[consumer]); |
- TouchEvent* event = event_queue_[consumer]->front(); |
- |
- GestureSequence* sequence = GetGestureSequenceForConsumer(consumer); |
- |
- if (processed && event->type() == ui::ET_TOUCH_RELEASED) { |
- // A touch release was was processed (e.g. preventDefault()ed by a |
- // web-page), but we still need to process a touch cancel. |
- CancelledTouchEvent cancelled(event); |
- return sequence->ProcessTouchEventForGesture(cancelled, |
- ui::TOUCH_STATUS_UNKNOWN); |
+ scoped_ptr<GestureSequence::Gestures> gestures( |
+ AdvanceTouchQueueByOne(consumer, processed ? TOUCH_STATUS_CONTINUE : |
+ TOUCH_STATUS_UNKNOWN)); |
+ |
+ // Are there any queued touch-events that should be auto-dequeued? |
+ while (!event_queue_[consumer]->empty()) { |
+ QueuedTouchEvent* event = |
+ static_cast<QueuedTouchEvent*>(event_queue_[consumer]->front()); |
+ if (event->status() == TOUCH_STATUS_QUEUED) |
+ break; |
+ |
+ GestureSequence::Gestures* current_gestures = AdvanceTouchQueueByOne( |
+ consumer, event->status()); |
+ if (current_gestures) { |
+ if (!gestures.get()) { |
+ gestures.reset(current_gestures); |
+ } else { |
+ gestures->insert(gestures->end(), current_gestures->begin(), |
+ current_gestures->end()); |
+ } |
+ } |
} |
- return sequence->ProcessTouchEventForGesture( |
- *event, |
- processed ? ui::TOUCH_STATUS_CONTINUE : ui::TOUCH_STATUS_UNKNOWN); |
+ return gestures.release(); |
} |
void GestureRecognizerImpl::FlushTouchQueue(GestureConsumer* consumer) { |