Chromium Code Reviews| Index: content/browser/renderer_host/render_widget_host_unittest.cc |
| diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc |
| index 979cc669802d54bf6b5568a97ff0745b7e76f8a3..f998d830ecf457bf1cb5877a438bdaa176762ec7 100644 |
| --- a/content/browser/renderer_host/render_widget_host_unittest.cc |
| +++ b/content/browser/renderer_host/render_widget_host_unittest.cc |
| @@ -48,6 +48,7 @@ using base::TimeDelta; |
| using blink::WebGestureEvent; |
| using blink::WebInputEvent; |
| using blink::WebKeyboardEvent; |
| +using blink::WebMouseEvent; |
| using blink::WebMouseWheelEvent; |
| using blink::WebTouchEvent; |
| using blink::WebTouchPoint; |
| @@ -199,6 +200,7 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl { |
| : RenderWidgetHostImpl(delegate, process, routing_id, false), |
| unresponsive_timer_fired_(false) { |
| input_router_impl_ = static_cast<InputRouterImpl*>(input_router_.get()); |
| + acked_touch_event_type_ = blink::WebInputEvent::Undefined; |
| } |
| // Allow poking at a few private members. |
| @@ -261,6 +263,18 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl { |
| return touch_event_queue().empty(); |
| } |
| + virtual void OnTouchEventAck( |
|
jdduke (slow)
2014/04/10 16:49:46
Is there a reason you didn't re-use the touch ack
dgozman
2014/04/10 17:38:03
Touch emulator handles ack before view and consume
jdduke (slow)
2014/04/10 17:40:22
Of course, silly me! Still lgtm :)
|
| + const TouchEventWithLatencyInfo& event, |
| + InputEventAckState ack_result) OVERRIDE { |
| + // Sniff touch acks. |
| + acked_touch_event_type_ = event.event.type; |
| + RenderWidgetHostImpl::OnTouchEventAck(event, ack_result); |
| + } |
| + |
| + WebInputEvent::Type acked_touch_event_type() const { |
| + return acked_touch_event_type_; |
| + } |
| + |
| bool ScrollStateIsContentScrolling() const { |
| return scroll_state() == OverscrollController::STATE_CONTENT_SCROLLING; |
| } |
| @@ -321,6 +335,7 @@ class MockRenderWidgetHost : public RenderWidgetHostImpl { |
| private: |
| bool unresponsive_timer_fired_; |
| + WebInputEvent::Type acked_touch_event_type_; |
| // |input_router_impl_| and |mock_input_router_| are owned by |
| // RenderWidgetHostImpl. The handles below are provided for convenience so |
| @@ -582,7 +597,10 @@ class RenderWidgetHostTest : public testing::Test { |
| RenderWidgetHostTest() |
| : process_(NULL), |
| handle_key_press_event_(false), |
| - handle_mouse_event_(false) { |
| + handle_mouse_event_(false), |
| + simulated_event_time_delta_seconds_(0) { |
| + last_simulated_event_time_seconds_ = |
| + (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF(); |
| } |
| virtual ~RenderWidgetHostTest() { |
| } |
| @@ -645,10 +663,20 @@ class RenderWidgetHostTest : public testing::Test { |
| host_->OnMessageReceived(*response); |
| } |
| + double GetNextSimulatedEventTimeSeconds() { |
| + last_simulated_event_time_seconds_ += simulated_event_time_delta_seconds_; |
| + return last_simulated_event_time_seconds_; |
| + } |
| + |
| void SimulateKeyboardEvent(WebInputEvent::Type type) { |
| - WebKeyboardEvent event = SyntheticWebKeyboardEventBuilder::Build(type); |
| - NativeWebKeyboardEvent native_event; |
| - memcpy(&native_event, &event, sizeof(event)); |
| + SimulateKeyboardEvent(type, 0); |
| + } |
| + |
| + void SimulateKeyboardEvent(WebInputEvent::Type type, int modifiers) { |
| + WebKeyboardEvent event = SyntheticWebKeyboardEventBuilder::Build(type); |
| + event.modifiers = modifiers; |
| + NativeWebKeyboardEvent native_event; |
| + memcpy(&native_event, &event, sizeof(event)); |
| host_->ForwardKeyboardEvent(native_event); |
| } |
| @@ -679,11 +707,17 @@ class RenderWidgetHostTest : public testing::Test { |
| } |
| void SimulateMouseMove(int x, int y, int modifiers) { |
| - host_->ForwardMouseEvent( |
| - SyntheticWebMouseEventBuilder::Build(WebInputEvent::MouseMove, |
| - x, |
| - y, |
| - modifiers)); |
| + SimulateMouseEvent(WebInputEvent::MouseMove, x, y, modifiers, false); |
| + } |
| + |
| + void SimulateMouseEvent( |
| + WebInputEvent::Type type, int x, int y, int modifiers, bool pressed) { |
| + WebMouseEvent event = |
| + SyntheticWebMouseEventBuilder::Build(type, x, y, modifiers); |
| + if (pressed) |
| + event.button = WebMouseEvent::ButtonLeft; |
| + event.timeStampSeconds = GetNextSimulatedEventTimeSeconds(); |
| + host_->ForwardMouseEvent(event); |
| } |
| void SimulateWheelEventWithPhase(WebMouseWheelEvent::Phase phase) { |
| @@ -788,6 +822,8 @@ class RenderWidgetHostTest : public testing::Test { |
| scoped_ptr<gfx::Screen> screen_; |
| bool handle_key_press_event_; |
| bool handle_mouse_event_; |
| + double last_simulated_event_time_seconds_; |
| + double simulated_event_time_delta_seconds_; |
| private: |
| SyntheticWebTouchEvent touch_event_; |
| @@ -2381,6 +2417,203 @@ TEST_F(RenderWidgetHostTest, OverscrollResetsOnBlur) { |
| process_->sink().ClearMessages(); |
| } |
| +std::string GetInputMessageTypes(RenderWidgetHostProcess* process) { |
| + const WebInputEvent* event = NULL; |
| + ui::LatencyInfo latency_info; |
| + bool is_keyboard_shortcut; |
| + std::string result; |
| + for (size_t i = 0; i < process->sink().message_count(); ++i) { |
| + const IPC::Message *message = process->sink().GetMessageAt(i); |
| + EXPECT_EQ(InputMsg_HandleInputEvent::ID, message->type()); |
| + EXPECT_TRUE(InputMsg_HandleInputEvent::Read( |
| + message, &event, &latency_info, &is_keyboard_shortcut)); |
| + if (i != 0) |
| + result += " "; |
| + result += WebInputEventTraits::GetName(event->type); |
| + } |
| + process->sink().ClearMessages(); |
| + return result; |
| +} |
| + |
| +TEST_F(RenderWidgetHostTest, TouchEmulator) { |
| + simulated_event_time_delta_seconds_ = 0.1; |
| + host_->DisableGestureDebounce(); |
| + // Immediately ack all touches instead of sending them to the renderer. |
| + host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false)); |
| + host_->OnMessageReceived( |
| + ViewHostMsg_SetTouchEventEmulationEnabled(0, true, true)); |
| + process_->sink().ClearMessages(); |
| + view_->set_bounds(gfx::Rect(0, 0, 400, 200)); |
| + view_->Show(); |
| + |
| + SimulateMouseEvent(WebInputEvent::MouseMove, 10, 10, 0, false); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + // Mouse press becomes touch start which in turn becomes tap. |
| + SimulateMouseEvent(WebInputEvent::MouseDown, 10, 10, 0, true); |
| + EXPECT_EQ(WebInputEvent::TouchStart, host_->acked_touch_event_type()); |
| + EXPECT_EQ("GestureTapDown", GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GestureTapDown, |
| + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| + |
| + // Mouse drag generates touch move, cancels tap and starts scroll. |
| + SimulateMouseEvent(WebInputEvent::MouseMove, 10, 30, 0, true); |
| + EXPECT_EQ(WebInputEvent::TouchMove, host_->acked_touch_event_type()); |
| + EXPECT_EQ( |
| + "GestureTapCancel GestureScrollBegin GestureScrollUpdate", |
| + GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GestureTapCancel, |
| + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| + SendInputEventACK(WebInputEvent::GestureScrollBegin, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + // Mouse drag with shift becomes pinch. |
| + SimulateMouseEvent( |
| + WebInputEvent::MouseMove, 10, 40, WebInputEvent::ShiftKey, true); |
| + EXPECT_EQ(WebInputEvent::TouchMove, host_->acked_touch_event_type()); |
| + EXPECT_EQ("GesturePinchBegin", |
| + GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GesturePinchBegin, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + SimulateMouseEvent( |
| + WebInputEvent::MouseMove, 10, 50, WebInputEvent::ShiftKey, true); |
| + EXPECT_EQ(WebInputEvent::TouchMove, host_->acked_touch_event_type()); |
| + EXPECT_EQ("GesturePinchUpdate", |
| + GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GesturePinchUpdate, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + // Mouse drag without shift becomes scroll again. |
| + SimulateMouseEvent(WebInputEvent::MouseMove, 10, 60, 0, true); |
| + EXPECT_EQ(WebInputEvent::TouchMove, host_->acked_touch_event_type()); |
| + EXPECT_EQ("GesturePinchEnd GestureScrollUpdate", |
| + GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + SimulateMouseEvent(WebInputEvent::MouseMove, 10, 70, 0, true); |
| + EXPECT_EQ(WebInputEvent::TouchMove, host_->acked_touch_event_type()); |
| + EXPECT_EQ("GestureScrollUpdate", |
| + GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + SimulateMouseEvent(WebInputEvent::MouseUp, 10, 70, 0, true); |
| + EXPECT_EQ(WebInputEvent::TouchEnd, host_->acked_touch_event_type()); |
| + EXPECT_EQ("GestureScrollEnd", GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GestureScrollEnd, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + // Mouse move does nothing. |
| + SimulateMouseEvent(WebInputEvent::MouseMove, 10, 80, 0, false); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + // Another mouse down continues scroll. |
| + SimulateMouseEvent(WebInputEvent::MouseDown, 10, 80, 0, true); |
| + EXPECT_EQ(WebInputEvent::TouchStart, host_->acked_touch_event_type()); |
| + EXPECT_EQ("GestureTapDown", GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GestureTapDown, |
| + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + SimulateMouseEvent(WebInputEvent::MouseMove, 10, 100, 0, true); |
| + EXPECT_EQ(WebInputEvent::TouchMove, host_->acked_touch_event_type()); |
| + EXPECT_EQ( |
| + "GestureTapCancel GestureScrollBegin GestureScrollUpdate", |
| + GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GestureTapCancel, |
| + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| + SendInputEventACK(WebInputEvent::GestureScrollBegin, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + // Another pinch. |
| + SimulateMouseEvent( |
| + WebInputEvent::MouseMove, 10, 110, WebInputEvent::ShiftKey, true); |
| + EXPECT_EQ(WebInputEvent::TouchMove, host_->acked_touch_event_type()); |
| + EXPECT_EQ("GesturePinchBegin", |
| + GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GesturePinchBegin, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + SimulateMouseEvent( |
| + WebInputEvent::MouseMove, 10, 120, WebInputEvent::ShiftKey, true); |
| + EXPECT_EQ(WebInputEvent::TouchMove, host_->acked_touch_event_type()); |
| + EXPECT_EQ("GesturePinchUpdate", |
| + GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GesturePinchUpdate, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + // Turn off emulation during a pinch. |
| + host_->OnMessageReceived( |
| + ViewHostMsg_SetTouchEventEmulationEnabled(0, false, false)); |
| + EXPECT_EQ(WebInputEvent::TouchCancel, host_->acked_touch_event_type()); |
| + EXPECT_EQ("GesturePinchEnd GestureScrollEnd", |
| + GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GesturePinchEnd, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + SendInputEventACK(WebInputEvent::GestureScrollEnd, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + // Mouse event should pass untouched. |
| + SimulateMouseEvent( |
| + WebInputEvent::MouseMove, 10, 10, WebInputEvent::ShiftKey, true); |
| + EXPECT_EQ("MouseMove", GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::MouseMove, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + // Turn on emulation. |
| + host_->OnMessageReceived( |
| + ViewHostMsg_SetTouchEventEmulationEnabled(0, true, true)); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + // Another touch. |
| + SimulateMouseEvent(WebInputEvent::MouseDown, 10, 10, 0, true); |
| + EXPECT_EQ(WebInputEvent::TouchStart, host_->acked_touch_event_type()); |
| + EXPECT_EQ("GestureTapDown", GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GestureTapDown, |
| + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| + |
| + // Scroll. |
| + SimulateMouseEvent(WebInputEvent::MouseMove, 10, 30, 0, true); |
| + EXPECT_EQ(WebInputEvent::TouchMove, host_->acked_touch_event_type()); |
| + EXPECT_EQ( |
| + "GestureTapCancel GestureScrollBegin GestureScrollUpdate", |
| + GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GestureTapCancel, |
| + INPUT_EVENT_ACK_STATE_NOT_CONSUMED); |
| + SendInputEventACK(WebInputEvent::GestureScrollBegin, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + SendInputEventACK(WebInputEvent::GestureScrollUpdate, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + |
| + // Turn off emulation during a scroll. |
| + host_->OnMessageReceived( |
| + ViewHostMsg_SetTouchEventEmulationEnabled(0, false, false)); |
| + EXPECT_EQ(WebInputEvent::TouchCancel, host_->acked_touch_event_type()); |
| + |
| + EXPECT_EQ("GestureScrollEnd", GetInputMessageTypes(process_)); |
| + SendInputEventACK(WebInputEvent::GestureScrollEnd, |
| + INPUT_EVENT_ACK_STATE_CONSUMED); |
| + EXPECT_EQ(0U, process_->sink().message_count()); |
| +} |
| + |
| #define TEST_InputRouterRoutes_NOARGS(INPUTMSG) \ |
| TEST_F(RenderWidgetHostTest, InputRouterRoutes##INPUTMSG) { \ |
| host_->SetupForInputRouterTest(); \ |