| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright (c) 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 <vector> | 
 |    6  | 
 |    7 #include "base/memory/scoped_ptr.h" | 
 |    8 #include "content/browser/renderer_host/input/browser_input_event.h" | 
 |    9 #include "content/browser/renderer_host/input/input_queue.h" | 
 |   10 #include "content/browser/renderer_host/input/input_queue_client.h" | 
 |   11 #include "content/common/input/event_packet.h" | 
 |   12 #include "content/common/input/input_event.h" | 
 |   13 #include "content/common/input/ipc_input_event_payload.h" | 
 |   14 #include "content/common/input/web_input_event_payload.h" | 
 |   15 #include "content/common/input_messages.h" | 
 |   16 #include "testing/gtest/include/gtest/gtest.h" | 
 |   17 #include "ui/base/latency_info.h" | 
 |   18  | 
 |   19 namespace content { | 
 |   20 namespace { | 
 |   21  | 
 |   22 using WebKit::WebGestureEvent; | 
 |   23 using WebKit::WebInputEvent; | 
 |   24 using WebKit::WebKeyboardEvent; | 
 |   25 using WebKit::WebMouseEvent; | 
 |   26 using WebKit::WebMouseWheelEvent; | 
 |   27 using WebKit::WebTouchEvent; | 
 |   28  | 
 |   29 class InputQueueTest : public testing::Test, | 
 |   30                        public InputQueueClient, | 
 |   31                        public BrowserInputEventClient { | 
 |   32  public: | 
 |   33   InputQueueTest() | 
 |   34       : queue_(new InputQueue(this)), | 
 |   35         routing_id_(0), | 
 |   36         num_flush_completions_(0), | 
 |   37         num_flush_requests_(0), | 
 |   38         num_packet_deliveries_(0), | 
 |   39         next_input_id_(1) {} | 
 |   40  | 
 |   41   // InputQueueClient | 
 |   42   virtual void Deliver(const EventPacket& packet) OVERRIDE { | 
 |   43     EXPECT_LT(0u, packet.size()); | 
 |   44     ++num_packet_deliveries_; | 
 |   45     current_packet_id_ = packet.id(); | 
 |   46     current_packet_dispositions_.resize(packet.size(), INPUT_EVENT_UNHANDLED); | 
 |   47   } | 
 |   48  | 
 |   49   virtual void DidFinishFlush() OVERRIDE { ++num_flush_completions_; } | 
 |   50   virtual void SetNeedsFlush() OVERRIDE { ++num_flush_requests_; } | 
 |   51  | 
 |   52   // BrowserInputEventClient | 
 |   53   virtual void OnDispatched(const BrowserInputEvent& event, | 
 |   54                             InputEventDisposition disposition) OVERRIDE { | 
 |   55     acked_dispositions_.push_back(disposition); | 
 |   56   } | 
 |   57  | 
 |   58   virtual void OnDispatched( | 
 |   59       const BrowserInputEvent& event, | 
 |   60       InputEventDisposition disposition, | 
 |   61       ScopedVector<BrowserInputEvent>* followup) OVERRIDE { | 
 |   62     acked_followup_dispositions_.push_back(disposition); | 
 |   63     if (event_to_inject_) | 
 |   64       followup->push_back(event_to_inject_.release()); | 
 |   65   } | 
 |   66  | 
 |   67   int num_flush_requests() const { return num_flush_requests_; } | 
 |   68   int num_flush_completions() const { return num_flush_completions_; } | 
 |   69   int num_packet_deliveries() const { return num_packet_deliveries_; } | 
 |   70  | 
 |   71  protected: | 
 |   72   scoped_ptr<BrowserInputEvent> CreateIPCInputEvent(IPC::Message* message) { | 
 |   73     return BrowserInputEvent::Create( | 
 |   74         NextInputID(), | 
 |   75         IPCInputEventPayload::Create(make_scoped_ptr(message)), | 
 |   76         this); | 
 |   77   } | 
 |   78  | 
 |   79   scoped_ptr<BrowserInputEvent> CreateWebInputEvent( | 
 |   80       WebInputEvent::Type web_type) { | 
 |   81     WebKit::WebMouseEvent mouse; | 
 |   82     WebKit::WebMouseWheelEvent wheel; | 
 |   83     WebKit::WebTouchEvent touch; | 
 |   84     WebKit::WebGestureEvent gesture; | 
 |   85     WebKit::WebKeyboardEvent keyboard; | 
 |   86  | 
 |   87     WebKit::WebInputEvent* web_event = NULL; | 
 |   88     if (WebInputEvent::isMouseEventType(web_type)) | 
 |   89       web_event = &mouse; | 
 |   90     else if (WebInputEvent::isKeyboardEventType(web_type)) | 
 |   91       web_event = &keyboard; | 
 |   92     else if (WebInputEvent::isTouchEventType(web_type)) | 
 |   93       web_event = &touch; | 
 |   94     else if (WebInputEvent::isGestureEventType(web_type)) | 
 |   95       web_event = &gesture; | 
 |   96     else | 
 |   97       web_event = &wheel; | 
 |   98     web_event->type = web_type; | 
 |   99  | 
 |  100     return BrowserInputEvent::Create( | 
 |  101         NextInputID(), | 
 |  102         WebInputEventPayload::Create(*web_event, ui::LatencyInfo(), false), | 
 |  103         this); | 
 |  104   } | 
 |  105  | 
 |  106   void QueueEvent(IPC::Message* message) { | 
 |  107     queue_->QueueEvent(CreateIPCInputEvent(message)); | 
 |  108   } | 
 |  109  | 
 |  110   void QueueEvent(WebInputEvent::Type web_type) { | 
 |  111     queue_->QueueEvent(CreateWebInputEvent(web_type)); | 
 |  112   } | 
 |  113  | 
 |  114   bool Flush(InputEventDisposition disposition) { | 
 |  115     StartFlush(); | 
 |  116     return FinishFlush(disposition); | 
 |  117   } | 
 |  118  | 
 |  119   void StartFlush() { | 
 |  120     acked_dispositions_.clear(); | 
 |  121     acked_followup_dispositions_.clear(); | 
 |  122     current_packet_id_ = 0; | 
 |  123     current_packet_dispositions_.clear(); | 
 |  124     queue_->BeginFlush(); | 
 |  125   } | 
 |  126  | 
 |  127   bool FinishFlush(InputEventDisposition disposition) { | 
 |  128     if (!current_packet_id_) | 
 |  129       return false; | 
 |  130     current_packet_dispositions_ = InputEventDispositions( | 
 |  131         current_packet_dispositions_.size(), disposition); | 
 |  132     return InputQueue::ACK_OK == | 
 |  133            queue_->OnEventPacketAck(current_packet_id_, | 
 |  134                                     current_packet_dispositions_); | 
 |  135   } | 
 |  136  | 
 |  137   int64 NextInputID() { return next_input_id_++; } | 
 |  138  | 
 |  139   scoped_ptr<InputQueue> queue_; | 
 |  140  | 
 |  141   int routing_id_; | 
 |  142   int64 current_packet_id_; | 
 |  143   InputEventDispositions current_packet_dispositions_; | 
 |  144  | 
 |  145   InputEventDispositions acked_dispositions_; | 
 |  146   InputEventDispositions acked_followup_dispositions_; | 
 |  147   scoped_ptr<BrowserInputEvent> event_to_inject_; | 
 |  148  | 
 |  149   int num_flush_completions_; | 
 |  150   int num_flush_requests_; | 
 |  151   int num_packet_deliveries_; | 
 |  152   int next_input_id_; | 
 |  153 }; | 
 |  154  | 
 |  155 TEST_F(InputQueueTest, SetNeedsFlushOnQueueEvent) { | 
 |  156   EXPECT_EQ(0, num_flush_requests()); | 
 |  157  | 
 |  158   QueueEvent(WebInputEvent::MouseDown); | 
 |  159   EXPECT_EQ(1, num_flush_requests()); | 
 |  160  | 
 |  161   // Additional queued events should not trigger additional flush requests. | 
 |  162   QueueEvent(WebInputEvent::MouseUp); | 
 |  163   EXPECT_EQ(1, num_flush_requests()); | 
 |  164   QueueEvent(WebInputEvent::TouchStart); | 
 |  165   EXPECT_EQ(1, num_flush_requests()); | 
 |  166 } | 
 |  167  | 
 |  168 TEST_F(InputQueueTest, NoSetNeedsFlushOnQueueIfFlushing) { | 
 |  169   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  170   EXPECT_EQ(1, num_flush_requests()); | 
 |  171  | 
 |  172   StartFlush(); | 
 |  173   EXPECT_EQ(1, num_flush_requests()); | 
 |  174   EXPECT_EQ(1, num_packet_deliveries()); | 
 |  175  | 
 |  176   // Events queued after a flush will not trigger an additional flush request. | 
 |  177   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  178   EXPECT_EQ(1, num_flush_requests()); | 
 |  179   QueueEvent(WebInputEvent::GestureScrollEnd); | 
 |  180   EXPECT_EQ(1, num_flush_requests()); | 
 |  181 } | 
 |  182  | 
 |  183 TEST_F(InputQueueTest, SetNeedsFlushAfterDidFinishFlushIfEventsQueued) { | 
 |  184   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  185   EXPECT_EQ(1, num_flush_requests()); | 
 |  186  | 
 |  187   StartFlush(); | 
 |  188   EXPECT_EQ(1, num_packet_deliveries()); | 
 |  189  | 
 |  190   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  191   EXPECT_EQ(1, num_flush_requests()); | 
 |  192  | 
 |  193   // An additional flush request is sent for the event queued after the flush. | 
 |  194   ASSERT_TRUE(current_packet_id_); | 
 |  195   ASSERT_TRUE(FinishFlush(INPUT_EVENT_IMPL_THREAD_CONSUMED)); | 
 |  196   EXPECT_EQ(1, num_flush_completions()); | 
 |  197   EXPECT_EQ(2, num_flush_requests()); | 
 |  198 } | 
 |  199  | 
 |  200 TEST_F(InputQueueTest, EventPacketSentAfterFlush) { | 
 |  201   EXPECT_EQ(0, num_packet_deliveries()); | 
 |  202   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  203   EXPECT_EQ(0, num_packet_deliveries()); | 
 |  204   StartFlush(); | 
 |  205   EXPECT_EQ(1, num_packet_deliveries()); | 
 |  206 } | 
 |  207  | 
 |  208 TEST_F(InputQueueTest, AcksHandledInProperOrder) { | 
 |  209   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  210   QueueEvent(WebInputEvent::GestureScrollEnd); | 
 |  211   QueueEvent(WebInputEvent::GestureFlingStart); | 
 |  212  | 
 |  213   queue_->BeginFlush(); | 
 |  214   ASSERT_EQ(3u, current_packet_dispositions_.size()); | 
 |  215   current_packet_dispositions_[0] = INPUT_EVENT_IMPL_THREAD_CONSUMED; | 
 |  216   current_packet_dispositions_[1] = INPUT_EVENT_MAIN_THREAD_CONSUMED; | 
 |  217   current_packet_dispositions_[2] = INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS; | 
 |  218   queue_->OnEventPacketAck(current_packet_id_, current_packet_dispositions_); | 
 |  219   EXPECT_EQ(1, num_flush_completions()); | 
 |  220  | 
 |  221   ASSERT_EQ(3u, acked_dispositions_.size()); | 
 |  222   EXPECT_EQ(acked_dispositions_[0], INPUT_EVENT_IMPL_THREAD_CONSUMED); | 
 |  223   EXPECT_EQ(acked_dispositions_[1], INPUT_EVENT_MAIN_THREAD_CONSUMED); | 
 |  224   EXPECT_EQ(acked_dispositions_[2], INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS); | 
 |  225 } | 
 |  226  | 
 |  227 TEST_F(InputQueueTest, FollowupWhenFollowupEventNotConsumed) { | 
 |  228   InputEventDisposition unconsumed_dispositions[] = { | 
 |  229     INPUT_EVENT_IMPL_THREAD_NO_CONSUMER_EXISTS, | 
 |  230     INPUT_EVENT_MAIN_THREAD_NOT_PREVENT_DEFAULTED, | 
 |  231     INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS | 
 |  232   }; | 
 |  233   for (size_t i = 0; i < arraysize(unconsumed_dispositions); ++i) { | 
 |  234     QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  235     QueueEvent(WebInputEvent::TouchStart); | 
 |  236     QueueEvent(WebInputEvent::TouchMove); | 
 |  237  | 
 |  238     Flush(unconsumed_dispositions[i]); | 
 |  239     EXPECT_EQ(1u, acked_dispositions_.size()) << i; | 
 |  240     EXPECT_EQ(2u, acked_followup_dispositions_.size()) << i; | 
 |  241   } | 
 |  242 } | 
 |  243  | 
 |  244 TEST_F(InputQueueTest, NoFollowupWhenFollowupEventConsumed) { | 
 |  245   InputEventDisposition consumed_dispositions[] = { | 
 |  246     INPUT_EVENT_IMPL_THREAD_CONSUMED, | 
 |  247     INPUT_EVENT_MAIN_THREAD_PREVENT_DEFAULTED, | 
 |  248     INPUT_EVENT_MAIN_THREAD_CONSUMED | 
 |  249   }; | 
 |  250   for (size_t i = 0; i < arraysize(consumed_dispositions); ++i) { | 
 |  251     QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  252     QueueEvent(WebInputEvent::TouchStart); | 
 |  253     QueueEvent(WebInputEvent::TouchMove); | 
 |  254  | 
 |  255     Flush(consumed_dispositions[i]); | 
 |  256     EXPECT_EQ(3u, acked_dispositions_.size()) << i; | 
 |  257     EXPECT_EQ(0u, acked_followup_dispositions_.size()) << i; | 
 |  258   } | 
 |  259 } | 
 |  260  | 
 |  261 TEST_F(InputQueueTest, FlushOnEmptyQueueIgnored) { | 
 |  262   Flush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | 
 |  263   EXPECT_EQ(0, num_flush_requests()); | 
 |  264   EXPECT_EQ(0, num_flush_completions()); | 
 |  265  | 
 |  266   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  267   Flush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | 
 |  268   EXPECT_EQ(1, num_flush_requests()); | 
 |  269   EXPECT_EQ(1, num_flush_completions()); | 
 |  270  | 
 |  271   Flush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | 
 |  272   EXPECT_EQ(1, num_flush_requests()); | 
 |  273   EXPECT_EQ(1, num_flush_completions()); | 
 |  274 } | 
 |  275  | 
 |  276 TEST_F(InputQueueTest, FlushContinuesUntilAllEventsProcessed) { | 
 |  277   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  278   QueueEvent(WebInputEvent::GestureScrollEnd); | 
 |  279   QueueEvent(WebInputEvent::GestureFlingStart); | 
 |  280  | 
 |  281   EXPECT_EQ(1, num_flush_requests()); | 
 |  282   Flush(INPUT_EVENT_COULD_NOT_DELIVER); | 
 |  283   EXPECT_EQ(0, num_flush_completions()); | 
 |  284  | 
 |  285   FinishFlush(INPUT_EVENT_COULD_NOT_DELIVER); | 
 |  286   EXPECT_EQ(0, num_flush_completions()); | 
 |  287  | 
 |  288   ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED)); | 
 |  289   EXPECT_EQ(1, num_flush_completions()); | 
 |  290 } | 
 |  291  | 
 |  292 TEST_F(InputQueueTest, InvalidPacketAckIgnored) { | 
 |  293   // Packet never flushed, any ack should be ignored. | 
 |  294   InputQueue::AckResult result = | 
 |  295       queue_->OnEventPacketAck(0, InputEventDispositions()); | 
 |  296   EXPECT_EQ(InputQueue::ACK_UNEXPECTED, result); | 
 |  297  | 
 |  298   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  299   StartFlush(); | 
 |  300   // Tamper with the sent packet by adding an extra event. | 
 |  301   current_packet_dispositions_.push_back(INPUT_EVENT_MAIN_THREAD_CONSUMED); | 
 |  302   bool valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | 
 |  303   EXPECT_EQ(0, num_flush_completions()); | 
 |  304   EXPECT_FALSE(valid_packet_ack); | 
 |  305  | 
 |  306   // Fix the packet. | 
 |  307   current_packet_dispositions_.pop_back(); | 
 |  308   valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | 
 |  309   EXPECT_EQ(1, num_flush_completions()); | 
 |  310   EXPECT_TRUE(valid_packet_ack); | 
 |  311  | 
 |  312   // Tamper with the packet by changing the id. | 
 |  313   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  314   StartFlush(); | 
 |  315   int64 packet_ack_id = -1; | 
 |  316   std::swap(current_packet_id_, packet_ack_id); | 
 |  317   valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | 
 |  318   EXPECT_EQ(1, num_flush_completions()); | 
 |  319   EXPECT_FALSE(valid_packet_ack); | 
 |  320  | 
 |  321   // Fix the packet. | 
 |  322   std::swap(current_packet_id_, packet_ack_id); | 
 |  323   valid_packet_ack = FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED); | 
 |  324   EXPECT_EQ(2, num_flush_completions()); | 
 |  325   EXPECT_TRUE(valid_packet_ack); | 
 |  326 } | 
 |  327  | 
 |  328 TEST_F(InputQueueTest, InjectedEventsAckedBeforeDidFinishFlush) { | 
 |  329   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  330   QueueEvent(WebInputEvent::TouchMove); | 
 |  331  | 
 |  332   event_to_inject_ = CreateIPCInputEvent(new InputMsg_Copy(routing_id_)); | 
 |  333   Flush(INPUT_EVENT_IMPL_THREAD_NO_CONSUMER_EXISTS); | 
 |  334   EXPECT_EQ(0, num_flush_completions()); | 
 |  335  | 
 |  336   // The injected event should now be in the event packet. | 
 |  337   EXPECT_EQ(1u, current_packet_dispositions_.size()); | 
 |  338   EXPECT_EQ(1u, acked_followup_dispositions_.size()); | 
 |  339   ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED)); | 
 |  340   EXPECT_EQ(1, num_flush_completions()); | 
 |  341  | 
 |  342   QueueEvent(WebInputEvent::GestureScrollBegin); | 
 |  343   QueueEvent(WebInputEvent::TouchStart); | 
 |  344   event_to_inject_ = CreateWebInputEvent(WebInputEvent::TouchMove); | 
 |  345   Flush(INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS); | 
 |  346   // |event_to_inject_| is now in the event packet. | 
 |  347   EXPECT_EQ(1u, acked_followup_dispositions_.size()); | 
 |  348   EXPECT_EQ(1u, current_packet_dispositions_.size()); | 
 |  349  | 
 |  350   event_to_inject_ = CreateWebInputEvent(WebInputEvent::TouchMove); | 
 |  351   // the next |event_to_inject_| is now in the event packet. | 
 |  352   ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_NO_CONSUMER_EXISTS)); | 
 |  353  | 
 |  354   EXPECT_EQ(2u, acked_followup_dispositions_.size()); | 
 |  355   EXPECT_EQ(1u, current_packet_dispositions_.size()); | 
 |  356   EXPECT_EQ(1, num_flush_completions()); | 
 |  357  | 
 |  358   ASSERT_TRUE(FinishFlush(INPUT_EVENT_MAIN_THREAD_CONSUMED)); | 
 |  359   EXPECT_EQ(2, num_flush_completions()); | 
 |  360 } | 
 |  361  | 
 |  362 }  // namespace | 
 |  363 }  // namespace content | 
| OLD | NEW |