Home | History | Annotate | Download | only in input
      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, &params));
    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, &params));
    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, &params));
    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