Commit dc60e34a authored by malaykeshav's avatar malaykeshav Committed by Commit bot

Routes touch ACK events to the correct GestureProvider

Currently a call to |GestureRecognizerImpl::TransferEventsTo()| can lead
to an incorrect state for touch events. Specifically, the event ACKS are
getting routed to a different reference of GestureProvider from the one
where the original events were routed to.

This patch stores a mapping of every event that was dispatched along
with its corresponding GestureProvider. This allows the event ACKS to be
routed correctly despite a call made to |TransferEventsTo()|.

BUG=698843
COMPONENT=Gesture Recognizer, Touch Gestures, Drag and Drop

Review-Url: https://codereview.chromium.org/2789203006
Cr-Commit-Position: refs/heads/master@{#462925}
parent 13745d8f
...@@ -4690,5 +4690,65 @@ TEST_F(GestureRecognizerTest, GestureEventTwoWindowsActive) { ...@@ -4690,5 +4690,65 @@ TEST_F(GestureRecognizerTest, GestureEventTwoWindowsActive) {
EXPECT_FALSE(queued_delegate->tap_down()); EXPECT_FALSE(queued_delegate->tap_down());
} }
// Test for crbug/698843. Checks whether the events are routed to the correct
// consumer in the event of TransferEventsTo() function call.
TEST_F(GestureRecognizerTest, TransferEventsToRoutesAckCorrectly) {
std::unique_ptr<QueueTouchEventDelegate> delegate_1(
new QueueTouchEventDelegate(host()->dispatcher()));
TimedEvents tes;
const int kTouchId = 7;
gfx::Rect bounds(0, 0, 1000, 1000);
std::unique_ptr<aura::Window> window_1(CreateTestWindowWithDelegate(
delegate_1.get(), -1234, bounds, root_window()));
delegate_1->set_window(window_1.get());
delegate_1->Reset();
ui::TouchEvent press(
ui::ET_TOUCH_PRESSED, gfx::Point(512, 512), tes.Now(),
ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, kTouchId));
DispatchEventUsingWindowDispatcher(&press);
// Create a new consumer and Touch event delegate.
std::unique_ptr<QueueTouchEventDelegate> delegate_2(
new QueueTouchEventDelegate(host()->dispatcher()));
std::unique_ptr<aura::Window> window_2(CreateTestWindowWithDelegate(
delegate_2.get(), -2345, bounds, root_window()));
delegate_2->set_window(window_2.get());
// Transfer event sequence from previous window to the new window.
ui::GestureRecognizer::Get()->TransferEventsTo(
window_1.get(), window_2.get(),
ui::GestureRecognizer::ShouldCancelTouches::DontCancel);
delegate_1->Reset();
delegate_1->ReceivedAck();
// ACK for events that were dispatched before the transfer should go to the
// original consumer. See crbug/698843 for more details.
EXPECT_2_EVENTS(delegate_1->events(), ui::ET_GESTURE_BEGIN,
ui::ET_GESTURE_TAP_DOWN);
delegate_1->Reset();
ui::TouchEvent release(
ui::ET_TOUCH_RELEASED, gfx::Point(550, 512), tes.LeapForward(50),
ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, kTouchId));
DispatchEventUsingWindowDispatcher(&release);
// Events dispatched after the transfer should go to the new window.
EXPECT_0_EVENTS(delegate_1->events());
delegate_2->ReceivedAck();
// The event sequence transfer should mean that the new window receives the
// gesture sequence state.
EXPECT_3_EVENTS(delegate_2->events(), ui::ET_GESTURE_SHOW_PRESS,
ui::ET_GESTURE_TAP, ui::ET_GESTURE_END);
EXPECT_TRUE(delegate_2->tap());
}
} // namespace test } // namespace test
} // namespace aura } // namespace aura
...@@ -244,6 +244,8 @@ GestureProviderAura* GestureRecognizerImpl::GetGestureProviderForConsumer( ...@@ -244,6 +244,8 @@ GestureProviderAura* GestureRecognizerImpl::GetGestureProviderForConsumer(
void GestureRecognizerImpl::SetupTargets(const TouchEvent& event, void GestureRecognizerImpl::SetupTargets(const TouchEvent& event,
GestureConsumer* target) { GestureConsumer* target) {
event_to_gesture_provider_[event.unique_event_id()] =
GetGestureProviderForConsumer(target);
if (event.type() == ui::ET_TOUCH_RELEASED || if (event.type() == ui::ET_TOUCH_RELEASED ||
event.type() == ui::ET_TOUCH_CANCELLED) { event.type() == ui::ET_TOUCH_CANCELLED) {
touch_id_target_.erase(event.pointer_details().id); touch_id_target_.erase(event.pointer_details().id);
...@@ -280,8 +282,18 @@ GestureRecognizer::Gestures GestureRecognizerImpl::AckTouchEvent( ...@@ -280,8 +282,18 @@ GestureRecognizer::Gestures GestureRecognizerImpl::AckTouchEvent(
uint32_t unique_event_id, uint32_t unique_event_id,
ui::EventResult result, ui::EventResult result,
GestureConsumer* consumer) { GestureConsumer* consumer) {
GestureProviderAura* gesture_provider = GestureProviderAura* gesture_provider = nullptr;
GetGestureProviderForConsumer(consumer);
// Check if we have already processed this event before dispatch and have a
// consumer associated with it.
auto event_to_gesture_provider_iterator =
event_to_gesture_provider_.find(unique_event_id);
if (event_to_gesture_provider_iterator != event_to_gesture_provider_.end()) {
gesture_provider = event_to_gesture_provider_iterator->second;
event_to_gesture_provider_.erase(event_to_gesture_provider_iterator);
} else {
gesture_provider = GetGestureProviderForConsumer(consumer);
}
gesture_provider->OnTouchEventAck(unique_event_id, result != ER_UNHANDLED); gesture_provider->OnTouchEventAck(unique_event_id, result != ER_UNHANDLED);
return gesture_provider->GetAndResetPendingGestures(); return gesture_provider->GetAndResetPendingGestures();
} }
......
...@@ -88,6 +88,12 @@ class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer, ...@@ -88,6 +88,12 @@ class EVENTS_EXPORT GestureRecognizerImpl : public GestureRecognizer,
std::map<GestureConsumer*, std::unique_ptr<GestureProviderAura>> std::map<GestureConsumer*, std::unique_ptr<GestureProviderAura>>
consumer_gesture_provider_; consumer_gesture_provider_;
// Maps an event via its |unique_event_id| to the corresponding gesture
// provider. This avoids any invalid reference while routing ACKs for events
// that may arise post |TransferEventsTo()| function call.
// See http://crbug.com/698843 for more info.
std::map<uint32_t, GestureProviderAura*> event_to_gesture_provider_;
// |touch_id_target_| maps a touch-id to its target window. // |touch_id_target_| maps a touch-id to its target window.
// touch-ids are removed from |touch_id_target_| on // touch-ids are removed from |touch_id_target_| on
// ET_TOUCH_RELEASE and ET_TOUCH_CANCEL. // ET_TOUCH_RELEASE and ET_TOUCH_CANCEL.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment