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 313