- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / gpu / input_event_filter_unittest.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <new>
6 #include <utility>
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/message_loop/message_loop.h"
11 #include "content/common/input_messages.h"
12 #include "content/common/view_messages.h"
13 #include "content/renderer/gpu/input_event_filter.h"
14 #include "ipc/ipc_test_sink.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 using WebKit::WebInputEvent;
18 using WebKit::WebMouseEvent;
19
20 namespace content {
21 namespace {
22
23 const int kTestRoutingID = 13;
24
25 class InputEventRecorder {
26  public:
27   InputEventRecorder()
28       : filter_(NULL),
29         handle_events_(false),
30         send_to_widget_(false) {
31   }
32
33   void set_filter(InputEventFilter* filter) { filter_ = filter; }
34   void set_handle_events(bool value) { handle_events_ = value; }
35   void set_send_to_widget(bool value) { send_to_widget_ = value; }
36
37   size_t record_count() const { return records_.size(); }
38
39   const WebInputEvent* record_at(size_t i) const {
40     const Record& record = records_[i];
41     return reinterpret_cast<const WebInputEvent*>(&record.event_data[0]);
42   }
43
44   void Clear() {
45     records_.clear();
46   }
47
48   InputEventAckState HandleInputEvent(int routing_id,
49                                       const WebInputEvent* event,
50                                       const ui::LatencyInfo& latency_info) {
51     DCHECK_EQ(kTestRoutingID, routing_id);
52
53     records_.push_back(Record(event));
54
55     if (handle_events_) {
56       return INPUT_EVENT_ACK_STATE_CONSUMED;
57     } else {
58       return send_to_widget_ ? INPUT_EVENT_ACK_STATE_NOT_CONSUMED
59                              : INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS;
60     }
61   }
62
63  private:
64   struct Record {
65     Record(const WebInputEvent* event) {
66       const char* ptr = reinterpret_cast<const char*>(event);
67       event_data.assign(ptr, ptr + event->size);
68     }
69     std::vector<char> event_data;
70   };
71
72   InputEventFilter* filter_;
73   bool handle_events_;
74   bool send_to_widget_;
75   std::vector<Record> records_;
76 };
77
78 class IPCMessageRecorder : public IPC::Listener {
79  public:
80   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
81     messages_.push_back(message);
82     return true;
83   }
84
85   size_t message_count() const { return messages_.size(); }
86
87   const IPC::Message& message_at(size_t i) const {
88     return messages_[i];
89   }
90
91   void Clear() {
92     messages_.clear();
93   }
94
95  private:
96   std::vector<IPC::Message> messages_;
97 };
98
99 void InitMouseEvent(WebMouseEvent* event, WebInputEvent::Type type,
100                     int x, int y) {
101   // Avoid valgrind false positives by initializing memory completely.
102   memset(event, 0, sizeof(*event));
103
104   new (event) WebMouseEvent();
105   event->type = type;
106   event->x = x;
107   event->y = y;
108 }
109
110 void AddMessagesToFilter(IPC::ChannelProxy::MessageFilter* message_filter,
111                          const std::vector<IPC::Message>& events) {
112   for (size_t i = 0; i < events.size(); ++i) {
113     message_filter->OnMessageReceived(events[i]);
114   }
115
116   base::MessageLoop::current()->RunUntilIdle();
117 }
118
119 void AddEventsToFilter(IPC::ChannelProxy::MessageFilter* message_filter,
120                        const WebMouseEvent events[],
121                        size_t count) {
122   std::vector<IPC::Message> messages;
123   for (size_t i = 0; i < count; ++i) {
124     messages.push_back(
125         InputMsg_HandleInputEvent(
126             kTestRoutingID, &events[i], ui::LatencyInfo(), false));
127   }
128
129   AddMessagesToFilter(message_filter, messages);
130 }
131
132 }  // namespace
133
134 class InputEventFilterTest : public testing::Test {
135  public:
136   virtual void SetUp() OVERRIDE {
137     filter_ = new InputEventFilter(
138         &message_recorder_,
139         message_loop_.message_loop_proxy());
140     filter_->SetBoundHandler(
141         base::Bind(&InputEventRecorder::HandleInputEvent,
142             base::Unretained(&event_recorder_)));
143
144     event_recorder_.set_filter(filter_.get());
145
146     filter_->OnFilterAdded(&ipc_sink_);
147   }
148
149
150  protected:
151   base::MessageLoop message_loop_;
152
153   // Used to record IPCs sent by the filter to the RenderWidgetHost.
154   IPC::TestSink ipc_sink_;
155
156   // Used to record IPCs forwarded by the filter to the main thread.
157   IPCMessageRecorder message_recorder_;
158
159   // Used to record WebInputEvents delivered to the handler.
160   InputEventRecorder event_recorder_;
161
162   scoped_refptr<InputEventFilter> filter_;
163 };
164
165 TEST_F(InputEventFilterTest, Basic) {
166   WebMouseEvent kEvents[3];
167   InitMouseEvent(&kEvents[0], WebInputEvent::MouseDown, 10, 10);
168   InitMouseEvent(&kEvents[1], WebInputEvent::MouseMove, 20, 20);
169   InitMouseEvent(&kEvents[2], WebInputEvent::MouseUp, 30, 30);
170
171   AddEventsToFilter(filter_.get(), kEvents, arraysize(kEvents));
172   EXPECT_EQ(0U, ipc_sink_.message_count());
173   EXPECT_EQ(0U, event_recorder_.record_count());
174   EXPECT_EQ(0U, message_recorder_.message_count());
175
176   filter_->DidAddInputHandler(kTestRoutingID, NULL);
177
178   AddEventsToFilter(filter_.get(), kEvents, arraysize(kEvents));
179   ASSERT_EQ(arraysize(kEvents), ipc_sink_.message_count());
180   ASSERT_EQ(arraysize(kEvents), event_recorder_.record_count());
181   EXPECT_EQ(0U, message_recorder_.message_count());
182
183   for (size_t i = 0; i < arraysize(kEvents); ++i) {
184     const IPC::Message* message = ipc_sink_.GetMessageAt(i);
185     EXPECT_EQ(kTestRoutingID, message->routing_id());
186     EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type());
187
188     WebInputEvent::Type event_type = WebInputEvent::Undefined;
189     InputEventAckState ack_result = INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
190     ui::LatencyInfo latency_info;
191     EXPECT_TRUE(InputHostMsg_HandleInputEvent_ACK::Read(message,
192                                                         &event_type,
193                                                         &ack_result,
194                                                         &latency_info));
195     EXPECT_EQ(kEvents[i].type, event_type);
196     EXPECT_EQ(ack_result, INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS);
197
198     const WebInputEvent* event = event_recorder_.record_at(i);
199     ASSERT_TRUE(event);
200
201     EXPECT_EQ(kEvents[i].size, event->size);
202     EXPECT_TRUE(memcmp(&kEvents[i], event, event->size) == 0);
203   }
204
205   event_recorder_.set_send_to_widget(true);
206
207   AddEventsToFilter(filter_.get(), kEvents, arraysize(kEvents));
208   EXPECT_EQ(arraysize(kEvents), ipc_sink_.message_count());
209   EXPECT_EQ(2 * arraysize(kEvents), event_recorder_.record_count());
210   EXPECT_EQ(arraysize(kEvents), message_recorder_.message_count());
211
212   for (size_t i = 0; i < arraysize(kEvents); ++i) {
213     const IPC::Message& message = message_recorder_.message_at(i);
214
215     ASSERT_EQ(InputMsg_HandleInputEvent::ID, message.type());
216     const WebInputEvent* event = NULL;
217     ui::LatencyInfo latency_info;
218     bool is_kbd_shortcut;
219     EXPECT_TRUE(InputMsg_HandleInputEvent::Read(
220         &message, &event, &latency_info, &is_kbd_shortcut));
221
222     EXPECT_EQ(kEvents[i].size, event->size);
223     EXPECT_TRUE(memcmp(&kEvents[i], event, event->size) == 0);
224   }
225
226   // Now reset everything, and test that DidHandleInputEvent is called.
227
228   ipc_sink_.ClearMessages();
229   event_recorder_.Clear();
230   message_recorder_.Clear();
231
232   event_recorder_.set_handle_events(true);
233
234   AddEventsToFilter(filter_.get(), kEvents, arraysize(kEvents));
235   EXPECT_EQ(arraysize(kEvents), ipc_sink_.message_count());
236   EXPECT_EQ(arraysize(kEvents), event_recorder_.record_count());
237   EXPECT_EQ(0U, message_recorder_.message_count());
238
239   for (size_t i = 0; i < arraysize(kEvents); ++i) {
240     const IPC::Message* message = ipc_sink_.GetMessageAt(i);
241     EXPECT_EQ(kTestRoutingID, message->routing_id());
242     EXPECT_EQ(InputHostMsg_HandleInputEvent_ACK::ID, message->type());
243
244     WebInputEvent::Type event_type = WebInputEvent::Undefined;
245     InputEventAckState ack_result = INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
246     ui::LatencyInfo latency_info;
247     EXPECT_TRUE(InputHostMsg_HandleInputEvent_ACK::Read(message,
248                                                         &event_type,
249                                                         &ack_result,
250                                                         &latency_info));
251     EXPECT_EQ(kEvents[i].type, event_type);
252     EXPECT_EQ(ack_result, INPUT_EVENT_ACK_STATE_CONSUMED);
253   }
254
255   filter_->OnFilterRemoved();
256 }
257
258 TEST_F(InputEventFilterTest, PreserveRelativeOrder) {
259   filter_->DidAddInputHandler(kTestRoutingID, NULL);
260   event_recorder_.set_send_to_widget(true);
261
262
263   WebMouseEvent mouse_down;
264   mouse_down.type = WebMouseEvent::MouseDown;
265   WebMouseEvent mouse_up;
266   mouse_up.type = WebMouseEvent::MouseUp;
267
268   std::vector<IPC::Message> messages;
269   messages.push_back(InputMsg_HandleInputEvent(kTestRoutingID,
270                                               &mouse_down,
271                                               ui::LatencyInfo(),
272                                               false));
273   // Control where input events are delivered.
274   messages.push_back(InputMsg_MouseCaptureLost(kTestRoutingID));
275   messages.push_back(InputMsg_SetFocus(kTestRoutingID, true));
276
277   // Editing operations
278   messages.push_back(InputMsg_Undo(kTestRoutingID));
279   messages.push_back(InputMsg_Redo(kTestRoutingID));
280   messages.push_back(InputMsg_Cut(kTestRoutingID));
281   messages.push_back(InputMsg_Copy(kTestRoutingID));
282 #if defined(OS_MACOSX)
283   messages.push_back(InputMsg_CopyToFindPboard(kTestRoutingID));
284 #endif
285   messages.push_back(InputMsg_Paste(kTestRoutingID));
286   messages.push_back(InputMsg_PasteAndMatchStyle(kTestRoutingID));
287   messages.push_back(InputMsg_Delete(kTestRoutingID));
288   messages.push_back(InputMsg_Replace(kTestRoutingID, string16()));
289   messages.push_back(InputMsg_ReplaceMisspelling(kTestRoutingID,
290                                                      string16()));
291   messages.push_back(InputMsg_Delete(kTestRoutingID));
292   messages.push_back(InputMsg_SelectAll(kTestRoutingID));
293   messages.push_back(InputMsg_Unselect(kTestRoutingID));
294   messages.push_back(InputMsg_SelectRange(kTestRoutingID,
295                                          gfx::Point(), gfx::Point()));
296   messages.push_back(InputMsg_MoveCaret(kTestRoutingID, gfx::Point()));
297
298   messages.push_back(InputMsg_HandleInputEvent(kTestRoutingID,
299                                               &mouse_up,
300                                               ui::LatencyInfo(),
301                                               false));
302   AddMessagesToFilter(filter_.get(), messages);
303
304   // We should have sent all messages back to the main thread and preserved
305   // their relative order.
306   ASSERT_EQ(message_recorder_.message_count(), messages.size());
307   for (size_t i = 0; i < messages.size(); ++i) {
308     EXPECT_EQ(message_recorder_.message_at(i).type(), messages[i].type()) << i;
309   }
310 }
311
312 }  // namespace content