| Index: content/renderer/gpu/input_event_filter_unittest.cc
|
| diff --git a/content/renderer/gpu/input_event_filter_unittest.cc b/content/renderer/gpu/input_event_filter_unittest.cc
|
| index d8e605268b04d1803597488d5b4ca7945b9a5082..7c74adfb1881069c95ccc3072947698cbc566e29 100644
|
| --- a/content/renderer/gpu/input_event_filter_unittest.cc
|
| +++ b/content/renderer/gpu/input_event_filter_unittest.cc
|
| @@ -8,6 +8,8 @@
|
|
|
| #include "base/bind.h"
|
| #include "base/message_loop/message_loop.h"
|
| +#include "content/common/input/event_packet.h"
|
| +#include "content/common/input/input_event.h"
|
| #include "content/common/input_messages.h"
|
| #include "content/common/view_messages.h"
|
| #include "content/renderer/gpu/input_event_filter.h"
|
| @@ -16,6 +18,7 @@
|
|
|
| using WebKit::WebInputEvent;
|
| using WebKit::WebMouseEvent;
|
| +using WebKit::WebTouchEvent;
|
|
|
| namespace content {
|
| namespace {
|
| @@ -107,11 +110,20 @@ void InitMouseEvent(WebMouseEvent* event, WebInputEvent::Type type,
|
| event->y = y;
|
| }
|
|
|
| +void InitTouchEvent(WebTouchEvent* event, WebInputEvent::Type type,
|
| + int touchesLength) {
|
| + // Avoid valgrind false positives by initializing memory completely.
|
| + memset(event, 0, sizeof(*event));
|
| +
|
| + new (event) WebTouchEvent();
|
| + event->type = type;
|
| + event->touchesLength = touchesLength;
|
| +}
|
| +
|
| void AddMessagesToFilter(IPC::ChannelProxy::MessageFilter* message_filter,
|
| const std::vector<IPC::Message>& events) {
|
| - for (size_t i = 0; i < events.size(); ++i) {
|
| + for (size_t i = 0; i < events.size(); ++i)
|
| message_filter->OnMessageReceived(events[i]);
|
| - }
|
|
|
| base::MessageLoop::current()->RunUntilIdle();
|
| }
|
| @@ -129,6 +141,35 @@ void AddEventsToFilter(IPC::ChannelProxy::MessageFilter* message_filter,
|
| AddMessagesToFilter(message_filter, messages);
|
| }
|
|
|
| +void AddPacketToFilter(IPC::ChannelProxy::MessageFilter* message_filter,
|
| + const EventPacket& packet) {
|
| + message_filter->OnMessageReceived(
|
| + InputMsg_HandleEventPacket(kTestRoutingID,
|
| + packet,
|
| + InputEventDispositions()));
|
| + base::MessageLoop::current()->RunUntilIdle();
|
| +}
|
| +
|
| +void AddMessagesToPacket(EventPacket* packet,
|
| + const std::vector<IPC::Message>& messages) {
|
| + for (size_t i = 0; i < messages.size(); ++i) {
|
| + const IPC::Message& message = messages[i];
|
| + scoped_ptr<InputEvent> event_from_message;
|
| + if (message.type() == InputMsg_HandleInputEvent::ID) {
|
| + InputMsg_HandleInputEvent::Param param;
|
| + ASSERT_TRUE(InputMsg_HandleInputEvent::Read(&message, ¶m));
|
| + event_from_message = InputEvent::Create(i+1,
|
| + WebInputEventPayload::Create(*param.a, param.b, param.c));
|
| + } else {
|
| + event_from_message = InputEvent::Create(i+1,
|
| + IPCInputEventPayload::Create(
|
| + make_scoped_ptr(new IPC::Message(message))));
|
| + }
|
| + ASSERT_TRUE(!!event_from_message);
|
| + packet->Add(event_from_message.Pass());
|
| + }
|
| +}
|
| +
|
| } // namespace
|
|
|
| class InputEventFilterTest : public testing::Test {
|
| @@ -148,6 +189,65 @@ class InputEventFilterTest : public testing::Test {
|
|
|
|
|
| protected:
|
| +
|
| + void CheckEventPacket(const IPC::Message* packet_message,
|
| + const EventPacket& source_packet,
|
| + const InputEventDispositions& expected_dispositions) {
|
| + EXPECT_EQ(kTestRoutingID, packet_message->routing_id());
|
| +
|
| + InputMsg_HandleEventPacket::Param param;
|
| + ASSERT_TRUE(InputMsg_HandleEventPacket::Read(packet_message, ¶m));
|
| + const EventPacket& packet = param.a;
|
| + const InputEventDispositions& dispositions = param.b;
|
| +
|
| + EXPECT_EQ(source_packet.id(), packet.id());
|
| + ASSERT_EQ(packet.size(), dispositions.size());
|
| + ASSERT_EQ(source_packet.size(), packet.size());
|
| +
|
| + for (size_t i = 0; i < packet.size(); ++i) {
|
| + const InputEvent& event = *packet.events()[i];
|
| + const InputEventDisposition disposition = dispositions[i];
|
| + EXPECT_EQ(source_packet.events()[i]->id(), event.id());
|
| + EXPECT_EQ(source_packet.events()[i]->payload()->GetType(),
|
| + event.payload()->GetType());
|
| + EXPECT_EQ(expected_dispositions[i], disposition) << i;
|
| + }
|
| + }
|
| +
|
| + void CheckEventPacketAck(
|
| + const IPC::Message* packet_message,
|
| + const EventPacket& source_packet,
|
| + const InputEventDispositions& expected_dispositions) {
|
| + EXPECT_EQ(kTestRoutingID, packet_message->routing_id());
|
| +
|
| + InputHostMsg_HandleEventPacket_ACK::Param param;
|
| + ASSERT_TRUE(
|
| + InputHostMsg_HandleEventPacket_ACK::Read(packet_message, ¶m));
|
| + const int64 packet_ack_id = param.a;
|
| + const InputEventDispositions& dispositions = param.b;
|
| +
|
| + EXPECT_EQ(source_packet.id(), packet_ack_id);
|
| + EXPECT_EQ(expected_dispositions, dispositions);
|
| + }
|
| +
|
| + void CheckEventPacket(const IPC::Message* packet_message,
|
| + const EventPacket& source_packet,
|
| + InputEventDisposition expected_disposition) {
|
| + CheckEventPacket(
|
| + packet_message,
|
| + source_packet,
|
| + InputEventDispositions(source_packet.size(), expected_disposition));
|
| + }
|
| +
|
| + void CheckEventPacketAck(const IPC::Message* packet_message,
|
| + const EventPacket& source_packet,
|
| + InputEventDisposition expected_disposition) {
|
| + CheckEventPacketAck(
|
| + packet_message,
|
| + source_packet,
|
| + InputEventDispositions(source_packet.size(), expected_disposition));
|
| + }
|
| +
|
| base::MessageLoop message_loop_;
|
|
|
| // Used to record IPCs sent by the filter to the RenderWidgetHost.
|
| @@ -188,10 +288,8 @@ TEST_F(InputEventFilterTest, Basic) {
|
| WebInputEvent::Type event_type = WebInputEvent::Undefined;
|
| InputEventAckState ack_result = INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
|
| ui::LatencyInfo latency_info;
|
| - EXPECT_TRUE(InputHostMsg_HandleInputEvent_ACK::Read(message,
|
| - &event_type,
|
| - &ack_result,
|
| - &latency_info));
|
| + EXPECT_TRUE(InputHostMsg_HandleInputEvent_ACK::Read(
|
| + message, &event_type, &ack_result, &latency_info));
|
| EXPECT_EQ(kEvents[i].type, event_type);
|
| EXPECT_EQ(ack_result, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
|
|
|
| @@ -267,9 +365,9 @@ TEST_F(InputEventFilterTest, PreserveRelativeOrder) {
|
|
|
| std::vector<IPC::Message> messages;
|
| messages.push_back(InputMsg_HandleInputEvent(kTestRoutingID,
|
| - &mouse_down,
|
| - ui::LatencyInfo(),
|
| - false));
|
| + &mouse_down,
|
| + ui::LatencyInfo(),
|
| + false));
|
| // Control where input events are delivered.
|
| messages.push_back(InputMsg_MouseCaptureLost(kTestRoutingID));
|
| messages.push_back(InputMsg_SetFocus(kTestRoutingID, true));
|
| @@ -296,9 +394,9 @@ TEST_F(InputEventFilterTest, PreserveRelativeOrder) {
|
| messages.push_back(InputMsg_MoveCaret(kTestRoutingID, gfx::Point()));
|
|
|
| messages.push_back(InputMsg_HandleInputEvent(kTestRoutingID,
|
| - &mouse_up,
|
| - ui::LatencyInfo(),
|
| - false));
|
| + &mouse_up,
|
| + ui::LatencyInfo(),
|
| + false));
|
| AddMessagesToFilter(filter_.get(), messages);
|
|
|
| // We should have sent all messages back to the main thread and preserved
|
| @@ -307,6 +405,188 @@ TEST_F(InputEventFilterTest, PreserveRelativeOrder) {
|
| for (size_t i = 0; i < messages.size(); ++i) {
|
| EXPECT_EQ(message_recorder_.message_at(i).type(), messages[i].type()) << i;
|
| }
|
| +
|
| + message_recorder_.Clear();
|
| +
|
| + // Now test ordering for packets.
|
| + EventPacket packet;
|
| + packet.set_id(1);
|
| + AddMessagesToPacket(&packet, messages);
|
| + AddPacketToFilter(filter_.get(), packet);
|
| +
|
| + // We should have sent the packet sent back to the main thread, with message
|
| + // order preserved.
|
| + ASSERT_EQ(1U, message_recorder_.message_count());
|
| +
|
| + // The first bounced WebInputEvent message will send the entire packet to
|
| + // the main thread; all subsequents events that are only handled on the main
|
| + // thread will be marked accordingly.
|
| + InputEventDispositions expected_dispositions(
|
| + messages.size(), INPUT_EVENT_IMPL_THREAD_BOUNCE_TO_MAIN);
|
| + // The final WebInputEvent is marked undeliverable; WebInputEvents should
|
| + // always be offered to the impl thread first, in order.
|
| + expected_dispositions.back() = INPUT_EVENT_COULD_NOT_DELIVER;
|
| +
|
| + {
|
| + SCOPED_TRACE("EventPacketBounceToMain");
|
| + CheckEventPacket(&message_recorder_.message_at(0),
|
| + packet,
|
| + expected_dispositions);
|
| + }
|
| +
|
| + message_recorder_.Clear();
|
| +
|
| + // Remove the first WebInputEvent; all main-thread bound messages will be
|
| + // sent to main singly until a WebInputEvent is reached, which will finish
|
| + // the packet processing.
|
| + messages.erase(messages.begin());
|
| + event_recorder_.set_handle_events(true);
|
| +
|
| + EventPacket next_packet;
|
| + packet.set_id(2);
|
| + AddMessagesToPacket(&next_packet, messages);
|
| + AddPacketToFilter(filter_.get(), next_packet);
|
| + ASSERT_EQ(messages.size() - 1, message_recorder_.message_count());
|
| + ASSERT_EQ(1U, ipc_sink_.message_count());
|
| +
|
| + expected_dispositions =
|
| + InputEventDispositions(messages.size(), INPUT_EVENT_MAIN_THREAD_CONSUMED);
|
| + expected_dispositions.back() = INPUT_EVENT_IMPL_THREAD_CONSUMED;
|
| +
|
| + {
|
| + SCOPED_TRACE("EventPacketImplConsumed");
|
| + CheckEventPacketAck(ipc_sink_.GetMessageAt(0),
|
| + next_packet,
|
| + expected_dispositions);
|
| + }
|
| +}
|
| +
|
| +TEST_F(InputEventFilterTest, EventPacketBasic) {
|
| + WebMouseEvent kEvents[3];
|
| + InitMouseEvent(&kEvents[0], WebInputEvent::MouseDown, 10, 10);
|
| + InitMouseEvent(&kEvents[1], WebInputEvent::MouseMove, 20, 20);
|
| + InitMouseEvent(&kEvents[2], WebInputEvent::MouseUp, 30, 30);
|
| +
|
| + EventPacket packet;
|
| + packet.set_id(13);
|
| + for (size_t i = 0; i < arraysize(kEvents); ++i) {
|
| + ASSERT_TRUE(
|
| + packet.Add(InputEvent::Create(i+1, WebInputEventPayload::Create(
|
| + kEvents[i], ui::LatencyInfo(), false))));
|
| + }
|
| +
|
| + AddPacketToFilter(filter_.get(), packet);
|
| + EXPECT_EQ(0U, ipc_sink_.message_count());
|
| + EXPECT_EQ(0U, event_recorder_.record_count());
|
| + EXPECT_EQ(0U, message_recorder_.message_count());
|
| +
|
| + filter_->DidAddInputHandler(kTestRoutingID, NULL);
|
| +
|
| + AddPacketToFilter(filter_.get(), packet);
|
| + // The packet is not forwarded to the the listener.
|
| + ASSERT_EQ(1U, ipc_sink_.message_count());
|
| + ASSERT_EQ(arraysize(kEvents), event_recorder_.record_count());
|
| + EXPECT_EQ(0U, message_recorder_.message_count());
|
| +
|
| + {
|
| + SCOPED_TRACE("EventPacketImplNoConsumer");
|
| + CheckEventPacketAck(ipc_sink_.GetMessageAt(0),
|
| + packet,
|
| + INPUT_EVENT_IMPL_THREAD_NO_CONSUMER_EXISTS);
|
| + }
|
| +
|
| + event_recorder_.set_send_to_widget(true);
|
| +
|
| + AddPacketToFilter(filter_.get(), packet);
|
| + // The entire packet is forwarded to the the listener; only the first event is
|
| + // offered to the event handler.
|
| + EXPECT_EQ(1U, ipc_sink_.message_count());
|
| + EXPECT_EQ(arraysize(kEvents) + 1, event_recorder_.record_count());
|
| + EXPECT_EQ(1U, message_recorder_.message_count());
|
| +
|
| + InputEventDispositions expected_dispositions;
|
| + expected_dispositions.push_back(INPUT_EVENT_IMPL_THREAD_BOUNCE_TO_MAIN);
|
| + expected_dispositions.push_back(INPUT_EVENT_COULD_NOT_DELIVER);
|
| + expected_dispositions.push_back(INPUT_EVENT_COULD_NOT_DELIVER);
|
| + {
|
| + SCOPED_TRACE("EventPacketBounceToMain");
|
| + CheckEventPacket(&message_recorder_.message_at(0),
|
| + packet,
|
| + expected_dispositions);
|
| + }
|
| +
|
| + ipc_sink_.ClearMessages();
|
| + event_recorder_.Clear();
|
| + message_recorder_.Clear();
|
| +
|
| + event_recorder_.set_handle_events(true);
|
| +
|
| + AddPacketToFilter(filter_.get(), packet);
|
| + // The packet is not forwarded to the listener; all events are offered to the
|
| + // event handler.
|
| + EXPECT_EQ(1U, ipc_sink_.message_count());
|
| + EXPECT_EQ(arraysize(kEvents), event_recorder_.record_count());
|
| + EXPECT_EQ(0U, message_recorder_.message_count());
|
| +
|
| + {
|
| + SCOPED_TRACE("EventPacketImplConsumed");
|
| + CheckEventPacketAck(ipc_sink_.GetMessageAt(0),
|
| + packet,
|
| + INPUT_EVENT_IMPL_THREAD_CONSUMED);
|
| + }
|
| +
|
| + filter_->OnFilterRemoved();
|
| +}
|
| +
|
| +TEST_F(InputEventFilterTest, EventPacketWithFollowup) {
|
| + WebTouchEvent kTouchEvent;
|
| + WebMouseEvent kMouseEvents[2];
|
| + InitTouchEvent(&kTouchEvent, WebInputEvent::TouchStart, 1);
|
| + InitMouseEvent(&kMouseEvents[0], WebInputEvent::MouseDown, 10, 10);
|
| + InitMouseEvent(&kMouseEvents[1], WebInputEvent::MouseMove, 20, 20);
|
| + const WebInputEvent* kEvents[3] = {
|
| + &kMouseEvents[0],
|
| + &kTouchEvent,
|
| + &kMouseEvents[1]
|
| + };
|
| +
|
| + EventPacket packet;
|
| + packet.set_id(7);
|
| + for (size_t i = 0; i < arraysize(kEvents); ++i) {
|
| + ASSERT_TRUE(packet.Add(InputEvent::Create(i+1,
|
| + WebInputEventPayload::Create(*kEvents[i], ui::LatencyInfo(), false))));
|
| + }
|
| + ASSERT_TRUE(packet.Add(
|
| + InputEvent::Create(arraysize(kEvents)+1,
|
| + IPCInputEventPayload::Create(
|
| + scoped_ptr<IPC::Message>(new InputMsg_Undo(kTestRoutingID))))));
|
| +
|
| + event_recorder_.set_handle_events(false);
|
| + event_recorder_.set_send_to_widget(false);
|
| +
|
| + filter_->DidAddInputHandler(kTestRoutingID, NULL);
|
| +
|
| + AddPacketToFilter(filter_.get(), packet);
|
| +
|
| + // The unhandled, injecting touch event prevents subsequent event handling.
|
| + EXPECT_EQ(1U, ipc_sink_.message_count());
|
| + EXPECT_EQ(arraysize(kEvents) - 1, event_recorder_.record_count());
|
| + EXPECT_EQ(0U, message_recorder_.message_count());
|
| +
|
| + InputEventDispositions expected_dispositions;
|
| + expected_dispositions.push_back(INPUT_EVENT_IMPL_THREAD_NO_CONSUMER_EXISTS);
|
| + expected_dispositions.push_back(INPUT_EVENT_IMPL_THREAD_NO_CONSUMER_EXISTS);
|
| + expected_dispositions.push_back(INPUT_EVENT_COULD_NOT_DELIVER);
|
| + expected_dispositions.push_back(INPUT_EVENT_COULD_NOT_DELIVER);
|
| +
|
| + {
|
| + SCOPED_TRACE("EventPacketImplWithFollowup");
|
| + CheckEventPacketAck(ipc_sink_.GetMessageAt(0),
|
| + packet,
|
| + expected_dispositions);
|
| + }
|
| +
|
| + filter_->OnFilterRemoved();
|
| }
|
|
|
| } // namespace content
|
|
|