Home | History | Annotate | Download | only in gpu
      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