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