| 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 40a99c5131fbfb82c14a0b3cbbfb5f0a271a3a52..1760b26eed28b5aba1b927db28b25cf6ba36fe89 100644
 | 
| --- a/content/renderer/input/main_thread_event_queue_unittest.cc
 | 
| +++ b/content/renderer/input/main_thread_event_queue_unittest.cc
 | 
| @@ -52,13 +52,53 @@ const char* kCoalescedCountHistogram =
 | 
|  
 | 
|  }  // namespace
 | 
|  
 | 
| +class HandledTask {
 | 
| + public:
 | 
| +  virtual ~HandledTask() {}
 | 
| +
 | 
| +  virtual blink::WebCoalescedInputEvent* taskAsEvent() = 0;
 | 
| +  virtual unsigned taskAsClosure() const = 0;
 | 
| +};
 | 
| +
 | 
| +class HandledEvent : public HandledTask {
 | 
| + public:
 | 
| +  explicit HandledEvent(const blink::WebCoalescedInputEvent* event)
 | 
| +      : event_(event->event(), event->getCoalescedEventsPointers()) {}
 | 
| +  ~HandledEvent() override {}
 | 
| +
 | 
| +  blink::WebCoalescedInputEvent* taskAsEvent() override { return &event_; }
 | 
| +  unsigned taskAsClosure() const override {
 | 
| +    NOTREACHED();
 | 
| +    return 0;
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  blink::WebCoalescedInputEvent event_;
 | 
| +};
 | 
| +
 | 
| +class HandledClosure : public HandledTask {
 | 
| + public:
 | 
| +  explicit HandledClosure(unsigned closure_id) : closure_id_(closure_id) {}
 | 
| +  ~HandledClosure() override {}
 | 
| +
 | 
| +  blink::WebCoalescedInputEvent* taskAsEvent() override {
 | 
| +    NOTREACHED();
 | 
| +    return nullptr;
 | 
| +  }
 | 
| +  unsigned taskAsClosure() const override { return closure_id_; }
 | 
| +
 | 
| + private:
 | 
| +  unsigned closure_id_;
 | 
| +};
 | 
| +
 | 
|  class MainThreadEventQueueTest : public testing::TestWithParam<unsigned>,
 | 
|                                   public MainThreadEventQueueClient {
 | 
|   public:
 | 
|    MainThreadEventQueueTest()
 | 
|        : main_task_runner_(new base::TestSimpleTaskRunner()),
 | 
|          raf_aligned_input_setting_(GetParam()),
 | 
| -        needs_main_frame_(false) {
 | 
| +        needs_main_frame_(false),
 | 
| +        closure_count_(0) {
 | 
|      std::vector<base::StringPiece> features;
 | 
|      std::vector<base::StringPiece> disabled_features;
 | 
|      if (raf_aligned_input_setting_ & kRafAlignedEnabledTouch) {
 | 
| @@ -86,8 +126,9 @@ class MainThreadEventQueueTest : public testing::TestWithParam<unsigned>,
 | 
|                                 const ui::LatencyInfo& latency,
 | 
|                                 InputEventDispatchType type) override {
 | 
|      EXPECT_EQ(kTestRoutingID, routing_id);
 | 
| -    handled_events_.push_back(blink::WebCoalescedInputEvent(
 | 
| -        event->event(), event->getCoalescedEventsPointers()));
 | 
| +
 | 
| +    std::unique_ptr<HandledTask> handled_event(new HandledEvent(event));
 | 
| +    handled_tasks_.push_back(std::move(handled_event));
 | 
|  
 | 
|      queue_->EventHandled(event->event().type(),
 | 
|                           blink::WebInputEventResult::HandledApplication,
 | 
| @@ -107,9 +148,20 @@ class MainThreadEventQueueTest : public testing::TestWithParam<unsigned>,
 | 
|                                 ack_result);
 | 
|    }
 | 
|  
 | 
| +  void RunClosure(unsigned closure_id) {
 | 
| +    std::unique_ptr<HandledTask> closure(new HandledClosure(closure_id));
 | 
| +    handled_tasks_.push_back(std::move(closure));
 | 
| +  }
 | 
| +
 | 
| +  void QueueClosure() {
 | 
| +    unsigned closure_id = ++closure_count_;
 | 
| +    queue_->QueueClosure(base::Bind(&MainThreadEventQueueTest::RunClosure,
 | 
| +                                    base::Unretained(this), closure_id));
 | 
| +  }
 | 
| +
 | 
|    void NeedsMainFrame(int routing_id) override { needs_main_frame_ = true; }
 | 
|  
 | 
| -  WebInputEventQueue<EventWithDispatchType>& event_queue() {
 | 
| +  MainThreadEventQueueTaskList& event_queue() {
 | 
|      return queue_->shared_state_.events_;
 | 
|    }
 | 
|  
 | 
| @@ -143,12 +195,13 @@ class MainThreadEventQueueTest : public testing::TestWithParam<unsigned>,
 | 
|    scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_;
 | 
|    blink::scheduler::MockRendererScheduler renderer_scheduler_;
 | 
|    scoped_refptr<MainThreadEventQueue> queue_;
 | 
| -  std::vector<blink::WebCoalescedInputEvent> handled_events_;
 | 
| +  std::vector<std::unique_ptr<HandledTask>> handled_tasks_;
 | 
|  
 | 
|    std::vector<uint32_t> additional_acked_events_;
 | 
|    int raf_aligned_input_setting_;
 | 
|    bool needs_main_frame_;
 | 
|    base::TimeTicks frame_time_;
 | 
| +  unsigned closure_count_;
 | 
|  };
 | 
|  
 | 
|  TEST_P(MainThreadEventQueueTest, NonBlockingWheel) {
 | 
| @@ -173,17 +226,19 @@ TEST_P(MainThreadEventQueueTest, NonBlockingWheel) {
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| -  EXPECT_EQ(2u, handled_events_.size());
 | 
| -  for (const auto& coalesced_event : handled_events_) {
 | 
| -    EXPECT_EQ(2u, coalesced_event.coalescedEventSize());
 | 
| +  EXPECT_EQ(2u, handled_tasks_.size());
 | 
| +  for (const auto& task : handled_tasks_) {
 | 
| +    EXPECT_EQ(2u, task->taskAsEvent()->coalescedEventSize());
 | 
|    }
 | 
|  
 | 
|    {
 | 
| -    EXPECT_EQ(kEvents[0].size(), handled_events_.at(0).event().size());
 | 
| -    EXPECT_EQ(kEvents[0].type(), handled_events_.at(0).event().type());
 | 
| +    EXPECT_EQ(kEvents[0].size(),
 | 
| +              handled_tasks_.at(0)->taskAsEvent()->event().size());
 | 
| +    EXPECT_EQ(kEvents[0].type(),
 | 
| +              handled_tasks_.at(0)->taskAsEvent()->event().type());
 | 
|      const WebMouseWheelEvent* last_wheel_event =
 | 
|          static_cast<const WebMouseWheelEvent*>(
 | 
| -            handled_events_.at(0).eventPointer());
 | 
| +            handled_tasks_.at(0)->taskAsEvent()->eventPointer());
 | 
|      EXPECT_EQ(WebInputEvent::DispatchType::ListenersNonBlockingPassive,
 | 
|                last_wheel_event->dispatchType);
 | 
|      WebMouseWheelEvent coalesced_event = kEvents[0];
 | 
| @@ -196,7 +251,7 @@ TEST_P(MainThreadEventQueueTest, NonBlockingWheel) {
 | 
|    {
 | 
|      WebMouseWheelEvent coalesced_event = kEvents[0];
 | 
|      std::vector<const WebInputEvent*> coalesced_events =
 | 
| -        handled_events_[0].getCoalescedEventsPointers();
 | 
| +        handled_tasks_[0]->taskAsEvent()->getCoalescedEventsPointers();
 | 
|      const WebMouseWheelEvent* coalesced_wheel_event0 =
 | 
|          static_cast<const WebMouseWheelEvent*>(coalesced_events[0]);
 | 
|      coalesced_event.dispatchType =
 | 
| @@ -214,7 +269,7 @@ TEST_P(MainThreadEventQueueTest, NonBlockingWheel) {
 | 
|    {
 | 
|      const WebMouseWheelEvent* last_wheel_event =
 | 
|          static_cast<const WebMouseWheelEvent*>(
 | 
| -            handled_events_.at(1).eventPointer());
 | 
| +            handled_tasks_.at(1)->taskAsEvent()->eventPointer());
 | 
|      WebMouseWheelEvent coalesced_event = kEvents[2];
 | 
|      ui::Coalesce(kEvents[3], &coalesced_event);
 | 
|      coalesced_event.dispatchType =
 | 
| @@ -225,7 +280,7 @@ TEST_P(MainThreadEventQueueTest, NonBlockingWheel) {
 | 
|    {
 | 
|      WebMouseWheelEvent coalesced_event = kEvents[2];
 | 
|      std::vector<const WebInputEvent*> coalesced_events =
 | 
| -        handled_events_[1].getCoalescedEventsPointers();
 | 
| +        handled_tasks_[1]->taskAsEvent()->getCoalescedEventsPointers();
 | 
|      const WebMouseWheelEvent* coalesced_wheel_event0 =
 | 
|          static_cast<const WebMouseWheelEvent*>(coalesced_events[0]);
 | 
|      coalesced_event.dispatchType =
 | 
| @@ -264,44 +319,50 @@ TEST_P(MainThreadEventQueueTest, NonBlockingTouch) {
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| -  EXPECT_EQ(3u, handled_events_.size());
 | 
| -
 | 
| -  EXPECT_EQ(kEvents[0].size(), handled_events_.at(0).event().size());
 | 
| -  EXPECT_EQ(kEvents[0].type(), handled_events_.at(0).event().type());
 | 
| -  const WebTouchEvent* last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(0).eventPointer());
 | 
| +  EXPECT_EQ(3u, handled_tasks_.size());
 | 
| +
 | 
| +  EXPECT_EQ(kEvents[0].size(),
 | 
| +            handled_tasks_.at(0)->taskAsEvent()->event().size());
 | 
| +  EXPECT_EQ(kEvents[0].type(),
 | 
| +            handled_tasks_.at(0)->taskAsEvent()->event().type());
 | 
| +  const WebTouchEvent* last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(0)->taskAsEvent()->eventPointer());
 | 
|    kEvents[0].dispatchType =
 | 
|        WebInputEvent::DispatchType::ListenersNonBlockingPassive;
 | 
|    EXPECT_EQ(kEvents[0], *last_touch_event);
 | 
|  
 | 
|    {
 | 
| -    EXPECT_EQ(1u, handled_events_[0].coalescedEventSize());
 | 
| +    EXPECT_EQ(1u, handled_tasks_[0]->taskAsEvent()->coalescedEventSize());
 | 
|      const WebTouchEvent* coalesced_touch_event =
 | 
|          static_cast<const WebTouchEvent*>(
 | 
| -            handled_events_[0].getCoalescedEventsPointers()[0]);
 | 
| +            handled_tasks_[0]->taskAsEvent()->getCoalescedEventsPointers()[0]);
 | 
|      EXPECT_EQ(kEvents[0], *coalesced_touch_event);
 | 
|    }
 | 
|  
 | 
| -  EXPECT_EQ(kEvents[1].size(), handled_events_.at(1).event().size());
 | 
| -  EXPECT_EQ(kEvents[1].type(), handled_events_.at(1).event().type());
 | 
| -  last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(1).eventPointer());
 | 
| +  EXPECT_EQ(kEvents[1].size(),
 | 
| +            handled_tasks_.at(1)->taskAsEvent()->event().size());
 | 
| +  EXPECT_EQ(kEvents[1].type(),
 | 
| +            handled_tasks_.at(1)->taskAsEvent()->event().type());
 | 
| +  last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(1)->taskAsEvent()->eventPointer());
 | 
|    kEvents[1].dispatchType =
 | 
|        WebInputEvent::DispatchType::ListenersNonBlockingPassive;
 | 
|    EXPECT_EQ(kEvents[1], *last_touch_event);
 | 
|  
 | 
|    {
 | 
| -    EXPECT_EQ(1u, handled_events_[1].coalescedEventSize());
 | 
| +    EXPECT_EQ(1u, handled_tasks_[1]->taskAsEvent()->coalescedEventSize());
 | 
|      const WebTouchEvent* coalesced_touch_event =
 | 
|          static_cast<const WebTouchEvent*>(
 | 
| -            handled_events_[1].getCoalescedEventsPointers()[0]);
 | 
| +            handled_tasks_[1]->taskAsEvent()->getCoalescedEventsPointers()[0]);
 | 
|      EXPECT_EQ(kEvents[1], *coalesced_touch_event);
 | 
|    }
 | 
|  
 | 
| -  EXPECT_EQ(kEvents[2].size(), handled_events_.at(1).event().size());
 | 
| -  EXPECT_EQ(kEvents[2].type(), handled_events_.at(2).event().type());
 | 
| -  last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(2).eventPointer());
 | 
| +  EXPECT_EQ(kEvents[2].size(),
 | 
| +            handled_tasks_.at(1)->taskAsEvent()->event().size());
 | 
| +  EXPECT_EQ(kEvents[2].type(),
 | 
| +            handled_tasks_.at(2)->taskAsEvent()->event().type());
 | 
| +  last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(2)->taskAsEvent()->eventPointer());
 | 
|    WebTouchEvent coalesced_event = kEvents[2];
 | 
|    ui::Coalesce(kEvents[3], &coalesced_event);
 | 
|    coalesced_event.dispatchType =
 | 
| @@ -309,10 +370,10 @@ TEST_P(MainThreadEventQueueTest, NonBlockingTouch) {
 | 
|    EXPECT_EQ(coalesced_event, *last_touch_event);
 | 
|  
 | 
|    {
 | 
| -    EXPECT_EQ(2u, handled_events_[2].coalescedEventSize());
 | 
| +    EXPECT_EQ(2u, handled_tasks_[2]->taskAsEvent()->coalescedEventSize());
 | 
|      WebTouchEvent coalesced_event = kEvents[2];
 | 
|      std::vector<const WebInputEvent*> coalesced_events =
 | 
| -        handled_events_[2].getCoalescedEventsPointers();
 | 
| +        handled_tasks_[2]->taskAsEvent()->getCoalescedEventsPointers();
 | 
|      const WebTouchEvent* coalesced_touch_event0 =
 | 
|          static_cast<const WebTouchEvent*>(coalesced_events[0]);
 | 
|      coalesced_event.dispatchType =
 | 
| @@ -360,8 +421,8 @@ TEST_P(MainThreadEventQueueTest, BlockingTouch) {
 | 
|    EXPECT_EQ(kEvents[1].uniqueTouchEventId, additional_acked_events_.at(0));
 | 
|    EXPECT_EQ(kEvents[2].uniqueTouchEventId, additional_acked_events_.at(1));
 | 
|  
 | 
| -  const WebTouchEvent* last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(1).eventPointer());
 | 
| +  const WebTouchEvent* last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(1)->taskAsEvent()->eventPointer());
 | 
|    EXPECT_EQ(kEvents[3].uniqueTouchEventId,
 | 
|              last_touch_event->uniqueTouchEventId);
 | 
|  
 | 
| @@ -399,13 +460,15 @@ TEST_P(MainThreadEventQueueTest, InterleavedEvents) {
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| -  EXPECT_EQ(2u, handled_events_.size());
 | 
| +  EXPECT_EQ(2u, handled_tasks_.size());
 | 
|    {
 | 
| -    EXPECT_EQ(kWheelEvents[0].size(), handled_events_.at(0).event().size());
 | 
| -    EXPECT_EQ(kWheelEvents[0].type(), handled_events_.at(0).event().type());
 | 
| +    EXPECT_EQ(kWheelEvents[0].size(),
 | 
| +              handled_tasks_.at(0)->taskAsEvent()->event().size());
 | 
| +    EXPECT_EQ(kWheelEvents[0].type(),
 | 
| +              handled_tasks_.at(0)->taskAsEvent()->event().type());
 | 
|      const WebMouseWheelEvent* last_wheel_event =
 | 
|          static_cast<const WebMouseWheelEvent*>(
 | 
| -            handled_events_.at(0).eventPointer());
 | 
| +            handled_tasks_.at(0)->taskAsEvent()->eventPointer());
 | 
|      EXPECT_EQ(WebInputEvent::DispatchType::ListenersNonBlockingPassive,
 | 
|                last_wheel_event->dispatchType);
 | 
|      WebMouseWheelEvent coalesced_event = kWheelEvents[0];
 | 
| @@ -415,10 +478,12 @@ TEST_P(MainThreadEventQueueTest, InterleavedEvents) {
 | 
|      EXPECT_EQ(coalesced_event, *last_wheel_event);
 | 
|    }
 | 
|    {
 | 
| -    EXPECT_EQ(kTouchEvents[0].size(), handled_events_.at(1).event().size());
 | 
| -    EXPECT_EQ(kTouchEvents[0].type(), handled_events_.at(1).event().type());
 | 
| -    const WebTouchEvent* last_touch_event =
 | 
| -        static_cast<const WebTouchEvent*>(handled_events_.at(1).eventPointer());
 | 
| +    EXPECT_EQ(kTouchEvents[0].size(),
 | 
| +              handled_tasks_.at(1)->taskAsEvent()->event().size());
 | 
| +    EXPECT_EQ(kTouchEvents[0].type(),
 | 
| +              handled_tasks_.at(1)->taskAsEvent()->event().type());
 | 
| +    const WebTouchEvent* last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +        handled_tasks_.at(1)->taskAsEvent()->eventPointer());
 | 
|      WebTouchEvent coalesced_event = kTouchEvents[0];
 | 
|      ui::Coalesce(kTouchEvents[1], &coalesced_event);
 | 
|      coalesced_event.dispatchType =
 | 
| @@ -441,9 +506,10 @@ TEST_P(MainThreadEventQueueTest, RafAlignedMouseInput) {
 | 
|    WebMouseEvent mouseUp =
 | 
|        SyntheticWebMouseEventBuilder::Build(WebInputEvent::MouseUp, 10, 10, 0);
 | 
|  
 | 
| -  WebMouseWheelEvent wheelEvents[2] = {
 | 
| +  WebMouseWheelEvent wheelEvents[3] = {
 | 
|        SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, 53, 0, false),
 | 
|        SyntheticWebMouseWheelEventBuilder::Build(20, 20, 0, 53, 0, false),
 | 
| +      SyntheticWebMouseWheelEventBuilder::Build(20, 20, 0, 53, 1, false),
 | 
|    };
 | 
|  
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
| @@ -466,20 +532,35 @@ TEST_P(MainThreadEventQueueTest, RafAlignedMouseInput) {
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|  
 | 
| -  // Simulate the rAF running before the PostTask occurs. The first rAF
 | 
| -  // shouldn't do anything.
 | 
| +  // Simulate the rAF running before the PostTask occurs. The rAF
 | 
| +  // will consume everything.
 | 
|    HandleEvent(mouseDown, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 | 
|    HandleEvent(wheelEvents[0], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 | 
|    EXPECT_EQ(2u, event_queue().size());
 | 
|    EXPECT_TRUE(needs_main_frame_);
 | 
|    RunSimulatedRafOnce();
 | 
|    EXPECT_FALSE(needs_main_frame_);
 | 
| -  EXPECT_EQ(2u, event_queue().size());
 | 
| +  EXPECT_EQ(0u, event_queue().size());
 | 
| +  main_task_runner_->RunUntilIdle();
 | 
| +
 | 
| +  // Simulate event consumption but no rAF signal. The mouse wheel events
 | 
| +  // should still be in the queue.
 | 
| +  handled_tasks_.clear();
 | 
| +  HandleEvent(mouseDown, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 | 
| +  HandleEvent(wheelEvents[0], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 | 
| +  HandleEvent(mouseUp, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 | 
| +  HandleEvent(wheelEvents[2], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 | 
| +  HandleEvent(wheelEvents[0], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 | 
| +  EXPECT_EQ(5u, event_queue().size());
 | 
| +  EXPECT_TRUE(needs_main_frame_);
 | 
|    main_task_runner_->RunUntilIdle();
 | 
|    EXPECT_TRUE(needs_main_frame_);
 | 
| -  EXPECT_EQ(1u, event_queue().size());
 | 
| -  RunPendingTasksWithSimulatedRaf();
 | 
| -  EXPECT_EQ(0u, event_queue().size());
 | 
| +  EXPECT_EQ(2u, event_queue().size());
 | 
| +  RunSimulatedRafOnce();
 | 
| +  EXPECT_EQ(wheelEvents[2].modifiers(),
 | 
| +            handled_tasks_.at(3)->taskAsEvent()->event().modifiers());
 | 
| +  EXPECT_EQ(wheelEvents[0].modifiers(),
 | 
| +            handled_tasks_.at(4)->taskAsEvent()->event().modifiers());
 | 
|  }
 | 
|  
 | 
|  TEST_P(MainThreadEventQueueTest, RafAlignedTouchInput) {
 | 
| @@ -511,17 +592,28 @@ TEST_P(MainThreadEventQueueTest, RafAlignedTouchInput) {
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|  
 | 
| -  // Simulate the rAF running before the PostTask occurs. The first rAF
 | 
| -  // shouldn't do anything.
 | 
| +  // Simulate the rAF running before the PostTask occurs. The rAF
 | 
| +  // will consume everything.
 | 
|    HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 | 
|    HandleEvent(kEvents[1], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 | 
|    EXPECT_EQ(2u, event_queue().size());
 | 
|    EXPECT_TRUE(needs_main_frame_);
 | 
|    RunSimulatedRafOnce();
 | 
|    EXPECT_FALSE(needs_main_frame_);
 | 
| -  EXPECT_EQ(2u, event_queue().size());
 | 
| -  RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| +  main_task_runner_->RunUntilIdle();
 | 
| +
 | 
| +  // Simulate event consumption but no rAF signal. The touch events
 | 
| +  // should still be in the queue.
 | 
| +  handled_tasks_.clear();
 | 
| +  HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 | 
| +  HandleEvent(kEvents[1], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
 | 
| +  EXPECT_EQ(2u, event_queue().size());
 | 
| +  EXPECT_TRUE(needs_main_frame_);
 | 
| +  main_task_runner_->RunUntilIdle();
 | 
| +  EXPECT_TRUE(needs_main_frame_);
 | 
| +  EXPECT_EQ(1u, event_queue().size());
 | 
| +  RunSimulatedRafOnce();
 | 
|  
 | 
|    // Simulate the touch move being discrete
 | 
|    kEvents[0].touchStartOrFirstTouchMove = true;
 | 
| @@ -648,12 +740,14 @@ TEST_P(MainThreadEventQueueTest, BlockingTouchesDuringFling) {
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| -  EXPECT_EQ(1u, handled_events_.size());
 | 
| -  EXPECT_EQ(kEvents.size(), handled_events_.at(0).event().size());
 | 
| -  EXPECT_EQ(kEvents.type(), handled_events_.at(0).event().type());
 | 
| +  EXPECT_EQ(1u, handled_tasks_.size());
 | 
| +  EXPECT_EQ(kEvents.size(),
 | 
| +            handled_tasks_.at(0)->taskAsEvent()->event().size());
 | 
| +  EXPECT_EQ(kEvents.type(),
 | 
| +            handled_tasks_.at(0)->taskAsEvent()->event().type());
 | 
|    EXPECT_TRUE(last_touch_start_forced_nonblocking_due_to_fling());
 | 
| -  const WebTouchEvent* last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(0).eventPointer());
 | 
| +  const WebTouchEvent* last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(0)->taskAsEvent()->eventPointer());
 | 
|    kEvents.dispatchType = WebInputEvent::ListenersForcedNonBlockingDueToFling;
 | 
|    EXPECT_EQ(kEvents, *last_touch_event);
 | 
|  
 | 
| @@ -665,12 +759,14 @@ TEST_P(MainThreadEventQueueTest, BlockingTouchesDuringFling) {
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| -  EXPECT_EQ(2u, handled_events_.size());
 | 
| -  EXPECT_EQ(kEvents.size(), handled_events_.at(1).event().size());
 | 
| -  EXPECT_EQ(kEvents.type(), handled_events_.at(1).event().type());
 | 
| +  EXPECT_EQ(2u, handled_tasks_.size());
 | 
| +  EXPECT_EQ(kEvents.size(),
 | 
| +            handled_tasks_.at(1)->taskAsEvent()->event().size());
 | 
| +  EXPECT_EQ(kEvents.type(),
 | 
| +            handled_tasks_.at(1)->taskAsEvent()->event().type());
 | 
|    EXPECT_TRUE(last_touch_start_forced_nonblocking_due_to_fling());
 | 
| -  last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(1).eventPointer());
 | 
| +  last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(1)->taskAsEvent()->eventPointer());
 | 
|    kEvents.dispatchType = WebInputEvent::ListenersForcedNonBlockingDueToFling;
 | 
|    EXPECT_EQ(kEvents, *last_touch_event);
 | 
|  
 | 
| @@ -680,12 +776,14 @@ TEST_P(MainThreadEventQueueTest, BlockingTouchesDuringFling) {
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| -  EXPECT_EQ(3u, handled_events_.size());
 | 
| -  EXPECT_EQ(kEvents.size(), handled_events_.at(2).event().size());
 | 
| -  EXPECT_EQ(kEvents.type(), handled_events_.at(2).event().type());
 | 
| +  EXPECT_EQ(3u, handled_tasks_.size());
 | 
| +  EXPECT_EQ(kEvents.size(),
 | 
| +            handled_tasks_.at(2)->taskAsEvent()->event().size());
 | 
| +  EXPECT_EQ(kEvents.type(),
 | 
| +            handled_tasks_.at(2)->taskAsEvent()->event().type());
 | 
|    EXPECT_EQ(kEvents.dispatchType, WebInputEvent::Blocking);
 | 
| -  last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(2).eventPointer());
 | 
| +  last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(2)->taskAsEvent()->eventPointer());
 | 
|    EXPECT_EQ(kEvents, *last_touch_event);
 | 
|  
 | 
|    kEvents.ReleasePoint(0);
 | 
| @@ -693,12 +791,14 @@ TEST_P(MainThreadEventQueueTest, BlockingTouchesDuringFling) {
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| -  EXPECT_EQ(4u, handled_events_.size());
 | 
| -  EXPECT_EQ(kEvents.size(), handled_events_.at(3).event().size());
 | 
| -  EXPECT_EQ(kEvents.type(), handled_events_.at(3).event().type());
 | 
| +  EXPECT_EQ(4u, handled_tasks_.size());
 | 
| +  EXPECT_EQ(kEvents.size(),
 | 
| +            handled_tasks_.at(3)->taskAsEvent()->event().size());
 | 
| +  EXPECT_EQ(kEvents.type(),
 | 
| +            handled_tasks_.at(3)->taskAsEvent()->event().type());
 | 
|    EXPECT_EQ(kEvents.dispatchType, WebInputEvent::Blocking);
 | 
| -  last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(3).eventPointer());
 | 
| +  last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(3)->taskAsEvent()->eventPointer());
 | 
|    EXPECT_EQ(kEvents, *last_touch_event);
 | 
|  }
 | 
|  
 | 
| @@ -712,13 +812,15 @@ TEST_P(MainThreadEventQueueTest, BlockingTouchesOutsideFling) {
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| -  EXPECT_EQ(1u, handled_events_.size());
 | 
| -  EXPECT_EQ(kEvents.size(), handled_events_.at(0).event().size());
 | 
| -  EXPECT_EQ(kEvents.type(), handled_events_.at(0).event().type());
 | 
| +  EXPECT_EQ(1u, handled_tasks_.size());
 | 
| +  EXPECT_EQ(kEvents.size(),
 | 
| +            handled_tasks_.at(0)->taskAsEvent()->event().size());
 | 
| +  EXPECT_EQ(kEvents.type(),
 | 
| +            handled_tasks_.at(0)->taskAsEvent()->event().type());
 | 
|    EXPECT_EQ(kEvents.dispatchType, WebInputEvent::Blocking);
 | 
|    EXPECT_FALSE(last_touch_start_forced_nonblocking_due_to_fling());
 | 
| -  const WebTouchEvent* last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(0).eventPointer());
 | 
| +  const WebTouchEvent* last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(0)->taskAsEvent()->eventPointer());
 | 
|    EXPECT_EQ(kEvents, *last_touch_event);
 | 
|  
 | 
|    set_enable_fling_passive_listener_flag(false);
 | 
| @@ -726,13 +828,15 @@ TEST_P(MainThreadEventQueueTest, BlockingTouchesOutsideFling) {
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| -  EXPECT_EQ(2u, handled_events_.size());
 | 
| -  EXPECT_EQ(kEvents.size(), handled_events_.at(1).event().size());
 | 
| -  EXPECT_EQ(kEvents.type(), handled_events_.at(1).event().type());
 | 
| +  EXPECT_EQ(2u, handled_tasks_.size());
 | 
| +  EXPECT_EQ(kEvents.size(),
 | 
| +            handled_tasks_.at(1)->taskAsEvent()->event().size());
 | 
| +  EXPECT_EQ(kEvents.type(),
 | 
| +            handled_tasks_.at(1)->taskAsEvent()->event().type());
 | 
|    EXPECT_EQ(kEvents.dispatchType, WebInputEvent::Blocking);
 | 
|    EXPECT_FALSE(last_touch_start_forced_nonblocking_due_to_fling());
 | 
| -  last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(1).eventPointer());
 | 
| +  last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(1)->taskAsEvent()->eventPointer());
 | 
|    EXPECT_EQ(kEvents, *last_touch_event);
 | 
|  
 | 
|    set_enable_fling_passive_listener_flag(true);
 | 
| @@ -740,13 +844,15 @@ TEST_P(MainThreadEventQueueTest, BlockingTouchesOutsideFling) {
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| -  EXPECT_EQ(3u, handled_events_.size());
 | 
| -  EXPECT_EQ(kEvents.size(), handled_events_.at(2).event().size());
 | 
| -  EXPECT_EQ(kEvents.type(), handled_events_.at(2).event().type());
 | 
| +  EXPECT_EQ(3u, handled_tasks_.size());
 | 
| +  EXPECT_EQ(kEvents.size(),
 | 
| +            handled_tasks_.at(2)->taskAsEvent()->event().size());
 | 
| +  EXPECT_EQ(kEvents.type(),
 | 
| +            handled_tasks_.at(2)->taskAsEvent()->event().type());
 | 
|    EXPECT_EQ(kEvents.dispatchType, WebInputEvent::Blocking);
 | 
|    EXPECT_FALSE(last_touch_start_forced_nonblocking_due_to_fling());
 | 
| -  last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(2).eventPointer());
 | 
| +  last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(2)->taskAsEvent()->eventPointer());
 | 
|    EXPECT_EQ(kEvents, *last_touch_event);
 | 
|  
 | 
|    kEvents.MovePoint(0, 30, 30);
 | 
| @@ -754,13 +860,15 @@ TEST_P(MainThreadEventQueueTest, BlockingTouchesOutsideFling) {
 | 
|    RunPendingTasksWithSimulatedRaf();
 | 
|    EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
|    EXPECT_EQ(0u, event_queue().size());
 | 
| -  EXPECT_EQ(4u, handled_events_.size());
 | 
| -  EXPECT_EQ(kEvents.size(), handled_events_.at(3).event().size());
 | 
| -  EXPECT_EQ(kEvents.type(), handled_events_.at(3).event().type());
 | 
| +  EXPECT_EQ(4u, handled_tasks_.size());
 | 
| +  EXPECT_EQ(kEvents.size(),
 | 
| +            handled_tasks_.at(3)->taskAsEvent()->event().size());
 | 
| +  EXPECT_EQ(kEvents.type(),
 | 
| +            handled_tasks_.at(3)->taskAsEvent()->event().type());
 | 
|    EXPECT_EQ(kEvents.dispatchType, WebInputEvent::Blocking);
 | 
|    EXPECT_FALSE(last_touch_start_forced_nonblocking_due_to_fling());
 | 
| -  last_touch_event =
 | 
| -      static_cast<const WebTouchEvent*>(handled_events_.at(3).eventPointer());
 | 
| +  last_touch_event = static_cast<const WebTouchEvent*>(
 | 
| +      handled_tasks_.at(3)->taskAsEvent()->eventPointer());
 | 
|    EXPECT_EQ(kEvents, *last_touch_event);
 | 
|  }
 | 
|  
 | 
| @@ -836,4 +944,93 @@ TEST_F(MainThreadEventQueueInitializationTest,
 | 
|              main_thread_responsiveness_threshold());
 | 
|  }
 | 
|  
 | 
| +TEST_P(MainThreadEventQueueTest, QueuingTwoClosures) {
 | 
| +  EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
| +  EXPECT_EQ(0u, event_queue().size());
 | 
| +
 | 
| +  QueueClosure();
 | 
| +  QueueClosure();
 | 
| +  EXPECT_EQ(2u, event_queue().size());
 | 
| +  EXPECT_TRUE(main_task_runner_->HasPendingTask());
 | 
| +  EXPECT_FALSE(needs_main_frame_);
 | 
| +  main_task_runner_->RunUntilIdle();
 | 
| +  EXPECT_EQ(1u, handled_tasks_.at(0)->taskAsClosure());
 | 
| +  EXPECT_EQ(2u, handled_tasks_.at(1)->taskAsClosure());
 | 
| +}
 | 
| +
 | 
| +TEST_P(MainThreadEventQueueTest, QueuingClosureWithRafEvent) {
 | 
| +  SyntheticWebTouchEvent kEvents[2];
 | 
| +  kEvents[0].PressPoint(10, 10);
 | 
| +  kEvents[1].PressPoint(10, 10);
 | 
| +  kEvents[1].MovePoint(0, 20, 20);
 | 
| +
 | 
| +  // Simulate queueuing closure, event, closure, raf aligned event.
 | 
| +  EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
| +  EXPECT_EQ(0u, event_queue().size());
 | 
| +  QueueClosure();
 | 
| +  EXPECT_EQ(1u, event_queue().size());
 | 
| +  EXPECT_TRUE(main_task_runner_->HasPendingTask());
 | 
| +  EXPECT_FALSE(needs_main_frame_);
 | 
| +
 | 
| +  EXPECT_FALSE(HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED));
 | 
| +  QueueClosure();
 | 
| +  EXPECT_EQ(3u, event_queue().size());
 | 
| +  EXPECT_TRUE(main_task_runner_->HasPendingTask());
 | 
| +  EXPECT_FALSE(needs_main_frame_);
 | 
| +  EXPECT_FALSE(HandleEvent(kEvents[1], INPUT_EVENT_ACK_STATE_NOT_CONSUMED));
 | 
| +  EXPECT_EQ(4u, event_queue().size());
 | 
| +
 | 
| +  if ((raf_aligned_input_setting_ & kRafAlignedEnabledTouch) != 0) {
 | 
| +    EXPECT_TRUE(needs_main_frame_);
 | 
| +    main_task_runner_->RunUntilIdle();
 | 
| +
 | 
| +    // The queue should still have the rAF event.
 | 
| +    EXPECT_TRUE(needs_main_frame_);
 | 
| +    EXPECT_EQ(1u, event_queue().size());
 | 
| +    RunPendingTasksWithSimulatedRaf();
 | 
| +  } else {
 | 
| +    EXPECT_FALSE(needs_main_frame_);
 | 
| +    main_task_runner_->RunUntilIdle();
 | 
| +  }
 | 
| +
 | 
| +  EXPECT_EQ(0u, event_queue().size());
 | 
| +  EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
| +  EXPECT_FALSE(needs_main_frame_);
 | 
| +
 | 
| +  EXPECT_EQ(1u, handled_tasks_.at(0)->taskAsClosure());
 | 
| +  EXPECT_EQ(kEvents[0].type(),
 | 
| +            handled_tasks_.at(1)->taskAsEvent()->event().type());
 | 
| +  EXPECT_EQ(2u, handled_tasks_.at(2)->taskAsClosure());
 | 
| +  EXPECT_EQ(kEvents[1].type(),
 | 
| +            handled_tasks_.at(3)->taskAsEvent()->event().type());
 | 
| +}
 | 
| +
 | 
| +TEST_P(MainThreadEventQueueTest, QueuingClosuresBetweenEvents) {
 | 
| +  SyntheticWebTouchEvent kEvents[2];
 | 
| +  kEvents[0].PressPoint(10, 10);
 | 
| +  kEvents[1].PressPoint(10, 10);
 | 
| +  kEvents[1].ReleasePoint(0);
 | 
| +
 | 
| +  EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
| +  EXPECT_EQ(0u, event_queue().size());
 | 
| +
 | 
| +  EXPECT_FALSE(HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED));
 | 
| +  QueueClosure();
 | 
| +  QueueClosure();
 | 
| +  EXPECT_FALSE(HandleEvent(kEvents[1], INPUT_EVENT_ACK_STATE_NOT_CONSUMED));
 | 
| +  EXPECT_EQ(4u, event_queue().size());
 | 
| +  EXPECT_FALSE(needs_main_frame_);
 | 
| +  main_task_runner_->RunUntilIdle();
 | 
| +  EXPECT_EQ(0u, event_queue().size());
 | 
| +  EXPECT_FALSE(main_task_runner_->HasPendingTask());
 | 
| +  EXPECT_FALSE(needs_main_frame_);
 | 
| +
 | 
| +  EXPECT_EQ(kEvents[0].type(),
 | 
| +            handled_tasks_.at(0)->taskAsEvent()->event().type());
 | 
| +  EXPECT_EQ(1u, handled_tasks_.at(1)->taskAsClosure());
 | 
| +  EXPECT_EQ(2u, handled_tasks_.at(2)->taskAsClosure());
 | 
| +  EXPECT_EQ(kEvents[1].type(),
 | 
| +            handled_tasks_.at(3)->taskAsEvent()->event().type());
 | 
| +}
 | 
| +
 | 
|  }  // namespace content
 | 
| 
 |