| Index: content/renderer/input/main_thread_event_queue_unittest.cc | 
| diff --git a/content/renderer/input/main_thread_event_queue_unittest.cc b/content/renderer/input/main_thread_event_queue_unittest.cc | 
| index 9cf7b0227fc5a3bf5d3dbef7f394649001dca522..5fbf8b0a7cb441ec3a37725df1594ad7b3708249 100644 | 
| --- a/content/renderer/input/main_thread_event_queue_unittest.cc | 
| +++ b/content/renderer/input/main_thread_event_queue_unittest.cc | 
| @@ -9,6 +9,7 @@ | 
| #include <vector> | 
|  | 
| #include "base/macros.h" | 
| +#include "base/test/test_simple_task_runner.h" | 
| #include "build/build_config.h" | 
| #include "content/common/input/synthetic_web_input_event_builders.h" | 
| #include "content/renderer/input/main_thread_event_queue.h" | 
| @@ -19,6 +20,16 @@ using blink::WebMouseEvent; | 
| using blink::WebMouseWheelEvent; | 
| using blink::WebTouchEvent; | 
|  | 
| +namespace blink { | 
| +bool operator==(const WebMouseWheelEvent& lhs, const WebMouseWheelEvent& rhs) { | 
| +  return memcmp(&lhs, &rhs, lhs.size) == 0; | 
| +} | 
| + | 
| +bool operator==(const WebTouchEvent& lhs, const WebTouchEvent& rhs) { | 
| +  return memcmp(&lhs, &rhs, lhs.size) == 0; | 
| +} | 
| +}  // namespace blink | 
| + | 
| namespace content { | 
| namespace { | 
|  | 
| @@ -28,16 +39,19 @@ const int kTestRoutingID = 13; | 
| class MainThreadEventQueueTest : public testing::Test, | 
| public MainThreadEventQueueClient { | 
| public: | 
| -  MainThreadEventQueueTest() : queue_(kTestRoutingID, this) {} | 
| - | 
| -  void SendEventToMainThread(int routing_id, | 
| -                             const blink::WebInputEvent* event, | 
| -                             const ui::LatencyInfo& latency, | 
| -                             InputEventDispatchType type) override { | 
| -    ASSERT_EQ(kTestRoutingID, routing_id); | 
| -    const unsigned char* eventPtr = | 
| -        reinterpret_cast<const unsigned char*>(event); | 
| -    last_event_.assign(eventPtr, eventPtr + event->size); | 
| +  MainThreadEventQueueTest() | 
| +      : main_task_runner_(new base::TestSimpleTaskRunner()), | 
| +        queue_( | 
| +            new MainThreadEventQueue(kTestRoutingID, this, main_task_runner_)) { | 
| +  } | 
| + | 
| +  void HandleEventOnMainThread(int routing_id, | 
| +                               const blink::WebInputEvent* event, | 
| +                               const ui::LatencyInfo& latency, | 
| +                               InputEventDispatchType type) override { | 
| +    EXPECT_EQ(kTestRoutingID, routing_id); | 
| +    handled_events_.push_back(WebInputEventTraits::Clone(*event)); | 
| +    queue_->EventHandled(event->type, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| } | 
|  | 
| void SendInputEventAck(int routing_id, | 
| @@ -48,14 +62,13 @@ class MainThreadEventQueueTest : public testing::Test, | 
| } | 
|  | 
| WebInputEventQueue<EventWithDispatchType>& event_queue() { | 
| -    return queue_.events_; | 
| +    return queue_->events_; | 
| } | 
|  | 
| -  bool eventPendingToMain() const { return queue_.sent_notification_to_main_; } | 
| - | 
| protected: | 
| -  MainThreadEventQueue queue_; | 
| -  std::vector<unsigned char> last_event_; | 
| +  scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_; | 
| +  scoped_refptr<MainThreadEventQueue> queue_; | 
| +  std::vector<ScopedWebInputEvent> handled_events_; | 
| std::vector<uint32_t> additional_acked_events_; | 
| }; | 
|  | 
| @@ -67,36 +80,46 @@ TEST_F(MainThreadEventQueueTest, NonBlockingWheel) { | 
| SyntheticWebMouseWheelEventBuilder::Build(30, 30, 0, 53, 1, false), | 
| }; | 
|  | 
| -  ASSERT_FALSE(eventPendingToMain()); | 
| -  queue_.HandleEvent(&kEvents[0], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| -  ASSERT_TRUE(eventPendingToMain()); | 
| -  queue_.HandleEvent(&kEvents[1], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| -  ASSERT_EQ(kEvents[0].size, last_event_.size()); | 
| -  kEvents[0].dispatchType = | 
| -      WebInputEvent::DispatchType::ListenersNonBlockingPassive; | 
| -  ASSERT_TRUE(memcmp(&last_event_[0], &kEvents[0], kEvents[0].size) == 0); | 
| -  queue_.EventHandled(blink::WebInputEvent::MouseWheel, | 
| -                      INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| -  ASSERT_EQ(kEvents[1].size, last_event_.size()); | 
| -  kEvents[1].dispatchType = | 
| -      WebInputEvent::DispatchType::ListenersNonBlockingPassive; | 
| -  ASSERT_TRUE(memcmp(&last_event_[0], &kEvents[1], kEvents[1].size) == 0); | 
| -  ASSERT_TRUE(eventPendingToMain()); | 
| -  queue_.EventHandled(blink::WebInputEvent::MouseWheel, | 
| -                      INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| -  ASSERT_FALSE(eventPendingToMain()); | 
| +  EXPECT_FALSE(main_task_runner_->HasPendingTask()); | 
| +  EXPECT_EQ(0u, event_queue().size()); | 
| +  queue_->HandleEvent(&kEvents[0], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  queue_->HandleEvent(&kEvents[1], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  queue_->HandleEvent(&kEvents[2], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  queue_->HandleEvent(&kEvents[3], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  EXPECT_EQ(2u, event_queue().size()); | 
| +  EXPECT_TRUE(main_task_runner_->HasPendingTask()); | 
| +  main_task_runner_->RunUntilIdle(); | 
| +  EXPECT_FALSE(main_task_runner_->HasPendingTask()); | 
| +  EXPECT_EQ(0u, event_queue().size()); | 
| +  EXPECT_EQ(2u, handled_events_.size()); | 
|  | 
| -  // Ensure that coalescing takes place. | 
| -  queue_.HandleEvent(&kEvents[0], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| -  queue_.HandleEvent(&kEvents[2], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| -  queue_.HandleEvent(&kEvents[3], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| -  ASSERT_EQ(1u, event_queue().size()); | 
| -  ASSERT_TRUE(eventPendingToMain()); | 
| +  { | 
| +    EXPECT_EQ(kEvents[0].size, handled_events_.at(0)->size); | 
| +    EXPECT_EQ(kEvents[0].type, handled_events_.at(0)->type); | 
| +    const WebMouseWheelEvent* last_wheel_event = | 
| +        static_cast<const WebMouseWheelEvent*>(handled_events_.at(0).get()); | 
| +    EXPECT_EQ(WebInputEvent::DispatchType::ListenersNonBlockingPassive, | 
| +              last_wheel_event->dispatchType); | 
| +    WebMouseWheelEvent coalesced_event = kEvents[0]; | 
| +    internal::Coalesce(kEvents[1], &coalesced_event); | 
| +    coalesced_event.dispatchType = | 
| +        WebInputEvent::DispatchType::ListenersNonBlockingPassive; | 
| +    EXPECT_EQ(coalesced_event, *last_wheel_event); | 
| +  } | 
| + | 
| +  { | 
| +    const WebMouseWheelEvent* last_wheel_event = | 
| +        static_cast<const WebMouseWheelEvent*>(handled_events_.at(1).get()); | 
| +    WebMouseWheelEvent coalesced_event = kEvents[2]; | 
| +    internal::Coalesce(kEvents[3], &coalesced_event); | 
| +    coalesced_event.dispatchType = | 
| +        WebInputEvent::DispatchType::ListenersNonBlockingPassive; | 
| +    EXPECT_EQ(coalesced_event, *last_wheel_event); | 
| +  } | 
| } | 
|  | 
| TEST_F(MainThreadEventQueueTest, NonBlockingTouch) { | 
| @@ -109,37 +132,47 @@ TEST_F(MainThreadEventQueueTest, NonBlockingTouch) { | 
| kEvents[2].MovePoint(0, 30, 30); | 
| kEvents[3].PressPoint(10, 10); | 
| kEvents[3].MovePoint(0, 35, 35); | 
| +  queue_->HandleEvent(&kEvents[0], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  queue_->HandleEvent(&kEvents[1], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  queue_->HandleEvent(&kEvents[2], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  queue_->HandleEvent(&kEvents[3], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| + | 
| +  EXPECT_EQ(3u, event_queue().size()); | 
| +  EXPECT_TRUE(main_task_runner_->HasPendingTask()); | 
| +  main_task_runner_->RunUntilIdle(); | 
| +  EXPECT_FALSE(main_task_runner_->HasPendingTask()); | 
| +  EXPECT_EQ(0u, event_queue().size()); | 
| +  EXPECT_EQ(3u, handled_events_.size()); | 
|  | 
| -  ASSERT_FALSE(eventPendingToMain()); | 
| -  queue_.HandleEvent(&kEvents[0], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| -  ASSERT_TRUE(eventPendingToMain()); | 
| -  queue_.HandleEvent(&kEvents[1], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| -  ASSERT_EQ(kEvents[0].size, last_event_.size()); | 
| +  EXPECT_EQ(kEvents[0].size, handled_events_.at(0)->size); | 
| +  EXPECT_EQ(kEvents[0].type, handled_events_.at(0)->type); | 
| +  const WebTouchEvent* last_touch_event = | 
| +      static_cast<const WebTouchEvent*>(handled_events_.at(0).get()); | 
| kEvents[0].dispatchType = | 
| WebInputEvent::DispatchType::ListenersNonBlockingPassive; | 
| -  ASSERT_TRUE(memcmp(&last_event_[0], &kEvents[0], kEvents[0].size) == 0); | 
| -  queue_.EventHandled(blink::WebInputEvent::TouchStart, | 
| -                      INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| -  ASSERT_EQ(kEvents[1].size, last_event_.size()); | 
| +  EXPECT_EQ(kEvents[0], *last_touch_event); | 
| + | 
| +  EXPECT_EQ(kEvents[1].size, handled_events_.at(1)->size); | 
| +  EXPECT_EQ(kEvents[1].type, handled_events_.at(1)->type); | 
| +  last_touch_event = | 
| +      static_cast<const WebTouchEvent*>(handled_events_.at(1).get()); | 
| kEvents[1].dispatchType = | 
| WebInputEvent::DispatchType::ListenersNonBlockingPassive; | 
| -  ASSERT_TRUE(memcmp(&last_event_[0], &kEvents[1], kEvents[1].size) == 0); | 
| -  ASSERT_TRUE(eventPendingToMain()); | 
| -  queue_.EventHandled(blink::WebInputEvent::TouchMove, | 
| -                      INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| -  ASSERT_FALSE(eventPendingToMain()); | 
| +  EXPECT_EQ(kEvents[1], *last_touch_event); | 
|  | 
| -  // Ensure that coalescing takes place. | 
| -  queue_.HandleEvent(&kEvents[0], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| -  queue_.HandleEvent(&kEvents[2], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| -  queue_.HandleEvent(&kEvents[3], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| -  ASSERT_EQ(1u, event_queue().size()); | 
| -  ASSERT_TRUE(eventPendingToMain()); | 
| +  EXPECT_EQ(kEvents[2].size, handled_events_.at(1)->size); | 
| +  EXPECT_EQ(kEvents[2].type, handled_events_.at(2)->type); | 
| +  last_touch_event = | 
| +      static_cast<const WebTouchEvent*>(handled_events_.at(2).get()); | 
| +  WebTouchEvent coalesced_event = kEvents[2]; | 
| +  internal::Coalesce(kEvents[3], &coalesced_event); | 
| +  coalesced_event.dispatchType = | 
| +      WebInputEvent::DispatchType::ListenersNonBlockingPassive; | 
| +  EXPECT_EQ(coalesced_event, *last_touch_event); | 
| } | 
|  | 
| TEST_F(MainThreadEventQueueTest, BlockingTouch) { | 
| @@ -151,25 +184,79 @@ TEST_F(MainThreadEventQueueTest, BlockingTouch) { | 
| kEvents[2].MovePoint(0, 30, 30); | 
| kEvents[3].PressPoint(10, 10); | 
| kEvents[3].MovePoint(0, 35, 35); | 
| - | 
| -  ASSERT_FALSE(eventPendingToMain()); | 
| // Ensure that coalescing takes place. | 
| -  queue_.HandleEvent(&kEvents[0], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| -  queue_.HandleEvent(&kEvents[1], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| -  queue_.HandleEvent(&kEvents[2], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| -  queue_.HandleEvent(&kEvents[3], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| -                     INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| -  ASSERT_EQ(1u, event_queue().size()); | 
| -  ASSERT_TRUE(eventPendingToMain()); | 
| -  queue_.EventHandled(kEvents[0].type, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| -  ASSERT_EQ(0u, event_queue().size()); | 
| -  queue_.EventHandled(kEvents[1].type, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| -  ASSERT_EQ(2u, additional_acked_events_.size()); | 
| -  ASSERT_EQ(kEvents[2].uniqueTouchEventId, additional_acked_events_.at(0)); | 
| -  ASSERT_EQ(kEvents[3].uniqueTouchEventId, additional_acked_events_.at(1)); | 
| +  queue_->HandleEvent(&kEvents[0], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  queue_->HandleEvent(&kEvents[1], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| +  queue_->HandleEvent(&kEvents[2], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| +  queue_->HandleEvent(&kEvents[3], ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_NOT_CONSUMED); | 
| +  EXPECT_EQ(2u, event_queue().size()); | 
| +  EXPECT_TRUE(main_task_runner_->HasPendingTask()); | 
| +  main_task_runner_->RunUntilIdle(); | 
| +  EXPECT_EQ(0u, event_queue().size()); | 
| +  EXPECT_EQ(2u, additional_acked_events_.size()); | 
| +  EXPECT_EQ(kEvents[2].uniqueTouchEventId, additional_acked_events_.at(0)); | 
| +  EXPECT_EQ(kEvents[3].uniqueTouchEventId, additional_acked_events_.at(1)); | 
| +} | 
| + | 
| +TEST_F(MainThreadEventQueueTest, InterleavedEvents) { | 
| +  WebMouseWheelEvent kWheelEvents[2] = { | 
| +      SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, 53, 0, false), | 
| +      SyntheticWebMouseWheelEventBuilder::Build(20, 20, 0, 53, 0, false), | 
| +  }; | 
| +  SyntheticWebTouchEvent kTouchEvents[2]; | 
| +  kTouchEvents[0].PressPoint(10, 10); | 
| +  kTouchEvents[0].MovePoint(0, 20, 20); | 
| +  kTouchEvents[1].PressPoint(10, 10); | 
| +  kTouchEvents[1].MovePoint(0, 30, 30); | 
| + | 
| +  EXPECT_FALSE(main_task_runner_->HasPendingTask()); | 
| +  EXPECT_EQ(0u, event_queue().size()); | 
| +  queue_->HandleEvent(&kWheelEvents[0], ui::LatencyInfo(), | 
| +                      DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  queue_->HandleEvent(&kTouchEvents[0], ui::LatencyInfo(), | 
| +                      DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  queue_->HandleEvent(&kWheelEvents[1], ui::LatencyInfo(), | 
| +                      DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  queue_->HandleEvent(&kTouchEvents[1], ui::LatencyInfo(), | 
| +                      DISPATCH_TYPE_BLOCKING, | 
| +                      INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING); | 
| +  EXPECT_EQ(2u, event_queue().size()); | 
| +  EXPECT_TRUE(main_task_runner_->HasPendingTask()); | 
| +  main_task_runner_->RunUntilIdle(); | 
| +  EXPECT_FALSE(main_task_runner_->HasPendingTask()); | 
| +  EXPECT_EQ(0u, event_queue().size()); | 
| +  EXPECT_EQ(2u, handled_events_.size()); | 
| +  { | 
| +    EXPECT_EQ(kWheelEvents[0].size, handled_events_.at(0)->size); | 
| +    EXPECT_EQ(kWheelEvents[0].type, handled_events_.at(0)->type); | 
| +    const WebMouseWheelEvent* last_wheel_event = | 
| +        static_cast<const WebMouseWheelEvent*>(handled_events_.at(0).get()); | 
| +    EXPECT_EQ(WebInputEvent::DispatchType::ListenersNonBlockingPassive, | 
| +              last_wheel_event->dispatchType); | 
| +    WebMouseWheelEvent coalesced_event = kWheelEvents[0]; | 
| +    internal::Coalesce(kWheelEvents[1], &coalesced_event); | 
| +    coalesced_event.dispatchType = | 
| +        WebInputEvent::DispatchType::ListenersNonBlockingPassive; | 
| +    EXPECT_EQ(coalesced_event, *last_wheel_event); | 
| +  } | 
| +  { | 
| +    EXPECT_EQ(kTouchEvents[0].size, handled_events_.at(1)->size); | 
| +    EXPECT_EQ(kTouchEvents[0].type, handled_events_.at(1)->type); | 
| +    const WebTouchEvent* last_touch_event = | 
| +        static_cast<const WebTouchEvent*>(handled_events_.at(1).get()); | 
| +    WebTouchEvent coalesced_event = kTouchEvents[0]; | 
| +    internal::Coalesce(kTouchEvents[1], &coalesced_event); | 
| +    coalesced_event.dispatchType = | 
| +        WebInputEvent::DispatchType::ListenersNonBlockingPassive; | 
| +    EXPECT_EQ(coalesced_event, *last_touch_event); | 
| +  } | 
| } | 
|  | 
| }  // namespace content | 
|  |