Chromium Code Reviews| Index: ui/events/gestures/gesture_recognizer_impl.cc |
| diff --git a/ui/events/gestures/gesture_recognizer_impl.cc b/ui/events/gestures/gesture_recognizer_impl.cc |
| index 7f27c8f78be3b62f686d58e8b0f0a7b0887b0c9e..ee404bc29e421c62d04c9dc5faa325b9002f5c37 100644 |
| --- a/ui/events/gestures/gesture_recognizer_impl.cc |
| +++ b/ui/events/gestures/gesture_recognizer_impl.cc |
| @@ -129,8 +129,68 @@ void GestureRecognizerImpl::CancelActiveTouchesExcept( |
| } |
| } |
| -void GestureRecognizerImpl::TransferEventsTo(GestureConsumer* current_consumer, |
| +void GestureRecognizerImpl::BeginDragAndDrop(GestureConsumer* current_consumer, |
| GestureConsumer* new_consumer) { |
| + // This method transfers the gesture stream from |current_consumer| to |
| + // |new_consumer|, while ensuring that both retain a touch event stream which |
| + // is reasonably valid. In order to do this we |
| + // - record what pointers are currently down on |current_consumer| |
| + // - cancel touches on consumers other than |current_consumer| |
| + // - move the gesture provider from |current_consumer| to |new_consumer| |
| + // - synthesize touch presses on |current_consumer|, to get the state of its |
| + // new, empty gesture provider in line with the touch state of the consumer |
| + // itself |
| + // - synthesize touch cancels on |current_consumer| |
| + // - retarget the pointers that were previously targeted to |
| + // |current_consumer| to |new_consumer|. |
| + // NOTE: This currently doesn't synthesize touch press events on |
| + // |new_consumer|, so the event stream it sees is still invalid. |
| + DCHECK(current_consumer); |
| + DCHECK(new_consumer); |
| + GestureEventHelper* helper = FindDispatchHelperForConsumer(current_consumer); |
| + |
| + std::vector<int> touchids_targeted_at_current; |
| + |
| + for (const auto& touch_id_target: touch_id_target_) { |
| + if (touch_id_target.second == current_consumer) |
| + touchids_targeted_at_current.push_back(touch_id_target.first); |
| + } |
| + |
| + CancelActiveTouchesExcept(current_consumer); |
| + |
| + std::vector<std::unique_ptr<TouchEvent>> pressing_touches = |
| + GetEventPerPointForConsumer(current_consumer, ET_TOUCH_PRESSED); |
| + std::vector<std::unique_ptr<TouchEvent>> cancelling_touches = |
| + GetEventPerPointForConsumer(current_consumer, ET_TOUCH_CANCELLED); |
| + |
| + TransferConsumer(current_consumer, new_consumer, &consumer_gesture_provider_); |
| + |
| + if (!helper) |
| + return; |
| + |
| + // We're now in a situation where current_consumer has no gesture recognizer, |
| + // but has some pointers down which need cancelling. In order to ensure that |
| + // the GR sees a valid event stream, synthesize a touch press per pointer, and |
| + // then synthesize a touch cancel per pointer. These extra touch presses will |
| + // be filtered out in the RenderWidgetHostViewAura. |
| + |
| + for (std::unique_ptr<TouchEvent>& event : pressing_touches) |
| + helper->DispatchSyntheticTouchEvent(event.get()); |
|
sadrul
2016/05/03 18:38:16
We really shouldn't dispatch a second set of touch
tdresser
2016/05/03 18:56:42
That would mean we'd need to relax this:
https://c
sadrul
2016/05/04 13:28:18
If not overly complicated, then yeah, I would go w
|
| + |
| + for (std::unique_ptr<TouchEvent>& event : cancelling_touches) |
| + helper->DispatchSyntheticTouchEvent(event.get()); |
| + |
| + for (int touch_id : touchids_targeted_at_current) |
| + touch_id_target_[touch_id] = new_consumer; |
| +} |
| + |
| + |
| +void GestureRecognizerImpl::BeginTabDrag(GestureConsumer* current_consumer, |
| + GestureConsumer* new_consumer) { |
| + // Tab Drag requires that the touches on |current_consumer| not be |
| + // cancelled. We transfer the gesture provider from |current_consumer| to |
| + // |new_consumer| without bothering to make the event stream valid for either |
| + // consumer. |
| DCHECK(current_consumer); |
| DCHECK(new_consumer); |
| @@ -154,31 +214,40 @@ bool GestureRecognizerImpl::GetLastTouchPointForTarget( |
| return true; |
| } |
| -bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer* consumer) { |
| - bool cancelled_touch = false; |
| +std::vector<std::unique_ptr<TouchEvent>> |
| +GestureRecognizerImpl::GetEventPerPointForConsumer(GestureConsumer* consumer, |
| + EventType type) { |
| + std::vector<std::unique_ptr<TouchEvent>> cancelling_touches; |
| if (consumer_gesture_provider_.count(consumer) == 0) |
| - return false; |
| + return cancelling_touches; |
| const MotionEventAura& pointer_state = |
| consumer_gesture_provider_[consumer]->pointer_state(); |
| if (pointer_state.GetPointerCount() == 0) |
| - return false; |
| - // pointer_state is modified every time after DispatchCancelTouchEvent. |
| - std::unique_ptr<MotionEvent> pointer_state_clone = pointer_state.Clone(); |
| - for (size_t i = 0; i < pointer_state_clone->GetPointerCount(); ++i) { |
| - TouchEvent touch_event(ui::ET_TOUCH_CANCELLED, gfx::Point(), |
| - ui::EF_IS_SYNTHESIZED, |
| - pointer_state_clone->GetPointerId(i), |
| - ui::EventTimeForNow(), 0.0f, 0.0f, 0.0f, 0.0f); |
| - gfx::PointF point(pointer_state_clone->GetX(i), |
| - pointer_state_clone->GetY(i)); |
| - touch_event.set_location_f(point); |
| - touch_event.set_root_location_f(point); |
| - GestureEventHelper* helper = FindDispatchHelperForConsumer(consumer); |
| - if (helper) |
| - helper->DispatchCancelTouchEvent(consumer, &touch_event); |
| - cancelled_touch = true; |
| + return cancelling_touches; |
| + for (size_t i = 0; i < pointer_state.GetPointerCount(); ++i) { |
| + std::unique_ptr<TouchEvent> touch_event(new TouchEvent( |
| + type, gfx::Point(), EF_IS_SYNTHESIZED, pointer_state.GetPointerId(i), |
| + EventTimeForNow(), 0.0f, 0.0f, 0.0f, 0.0f)); |
| + gfx::PointF point(pointer_state.GetX(i), pointer_state.GetY(i)); |
| + touch_event->set_location_f(point); |
| + touch_event->set_root_location_f(point); |
| + cancelling_touches.push_back(std::move(touch_event)); |
| } |
| - return cancelled_touch; |
| + return cancelling_touches; |
| +} |
| + |
| +bool GestureRecognizerImpl::CancelActiveTouches(GestureConsumer* consumer) { |
| + GestureEventHelper* helper = |
| + FindDispatchHelperForConsumer(consumer); |
| + |
| + if (!helper) |
| + return false; |
| + |
| + std::vector<std::unique_ptr<TouchEvent>> cancelling_touches = |
| + GetEventPerPointForConsumer(consumer, ET_TOUCH_CANCELLED); |
| + for (const std::unique_ptr<TouchEvent>& cancelling_touch : cancelling_touches) |
| + helper->DispatchSyntheticTouchEvent(cancelling_touch.get()); |
| + return cancelling_touches.size() > 0U; |
| } |
| //////////////////////////////////////////////////////////////////////////////// |