| 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 d5036cfec1dbd991c21d2ef94518a6ef30f05c72..f0b9384e65220ae827905aeeeb2ffc5f8a7926b2 100644
|
| --- a/content/renderer/input/main_thread_event_queue_unittest.cc
|
| +++ b/content/renderer/input/main_thread_event_queue_unittest.cc
|
| @@ -9,6 +9,8 @@
|
| #include <vector>
|
|
|
| #include "base/macros.h"
|
| +#include "base/test/histogram_tester.h"
|
| +#include "base/test/scoped_feature_list.h"
|
| #include "base/test/test_simple_task_runner.h"
|
| #include "build/build_config.h"
|
| #include "content/common/input/synthetic_web_input_event_builders.h"
|
| @@ -36,17 +38,26 @@ namespace content {
|
| namespace {
|
|
|
| const int kTestRoutingID = 13;
|
| -}
|
| +const char* kCoalescedCountHistogram =
|
| + "Event.MainThreadEventQueue.CoalescedCount";
|
| +
|
| +} // namespace
|
|
|
| -class MainThreadEventQueueTest : public testing::Test,
|
| +class MainThreadEventQueueTest : public testing::TestWithParam<bool>,
|
| public MainThreadEventQueueClient {
|
| public:
|
| MainThreadEventQueueTest()
|
| : main_task_runner_(new base::TestSimpleTaskRunner()),
|
| - queue_(new MainThreadEventQueue(kTestRoutingID,
|
| - this,
|
| - main_task_runner_,
|
| - &renderer_scheduler_)) {}
|
| + handle_raf_aligned_input_(GetParam()),
|
| + needs_main_frame_(false) {
|
| + if (handle_raf_aligned_input_)
|
| + feature_list_.InitAndEnableFeature(features::kRafAlignedInputEvents);
|
| + }
|
| +
|
| + void SetUp() override {
|
| + queue_ = new MainThreadEventQueue(kTestRoutingID, this, main_task_runner_,
|
| + &renderer_scheduler_);
|
| + }
|
|
|
| void HandleEventOnMainThread(int routing_id,
|
| const blink::WebInputEvent* event,
|
| @@ -69,8 +80,10 @@ class MainThreadEventQueueTest : public testing::Test,
|
| ui::LatencyInfo(), DISPATCH_TYPE_BLOCKING, ack_result);
|
| }
|
|
|
| + void NeedsMainFrame(int routing_id) override { needs_main_frame_ = true; }
|
| +
|
| WebInputEventQueue<EventWithDispatchType>& event_queue() {
|
| - return queue_->events_;
|
| + return queue_->shared_state_.events_;
|
| }
|
|
|
| void set_is_flinging(bool is_flinging) {
|
| @@ -85,15 +98,35 @@ class MainThreadEventQueueTest : public testing::Test,
|
| queue_->enable_fling_passive_listener_flag_ = enable_flag;
|
| }
|
|
|
| + void RunPendingTasksWithSimulatedRaf() {
|
| + while (needs_main_frame_ || main_task_runner_->HasPendingTask()) {
|
| + main_task_runner_->RunUntilIdle();
|
| + needs_main_frame_ = false;
|
| + queue_->DispatchRafAlignedInput();
|
| + }
|
| + }
|
| +
|
| + void RunSimulatedRafOnce() {
|
| + if (needs_main_frame_) {
|
| + needs_main_frame_ = false;
|
| + queue_->DispatchRafAlignedInput();
|
| + }
|
| + }
|
| +
|
| protected:
|
| + base::test::ScopedFeatureList feature_list_;
|
| scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_;
|
| blink::scheduler::MockRendererScheduler renderer_scheduler_;
|
| scoped_refptr<MainThreadEventQueue> queue_;
|
| std::vector<ui::ScopedWebInputEvent> handled_events_;
|
| std::vector<uint32_t> additional_acked_events_;
|
| + bool handle_raf_aligned_input_;
|
| + bool needs_main_frame_;
|
| };
|
|
|
| -TEST_F(MainThreadEventQueueTest, NonBlockingWheel) {
|
| +TEST_P(MainThreadEventQueueTest, NonBlockingWheel) {
|
| + base::HistogramTester histogram_tester;
|
| +
|
| WebMouseWheelEvent kEvents[4] = {
|
| SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, 53, 0, false),
|
| SyntheticWebMouseWheelEventBuilder::Build(20, 20, 0, 53, 0, false),
|
| @@ -108,8 +141,8 @@ TEST_F(MainThreadEventQueueTest, NonBlockingWheel) {
|
| HandleEvent(event, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
|
|
|
| EXPECT_EQ(2u, event_queue().size());
|
| - EXPECT_TRUE(main_task_runner_->HasPendingTask());
|
| - main_task_runner_->RunUntilIdle();
|
| + EXPECT_EQ(handle_raf_aligned_input_, !main_task_runner_->HasPendingTask());
|
| + RunPendingTasksWithSimulatedRaf();
|
| EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| EXPECT_EQ(0u, event_queue().size());
|
| EXPECT_EQ(2u, handled_events_.size());
|
| @@ -137,9 +170,12 @@ TEST_F(MainThreadEventQueueTest, NonBlockingWheel) {
|
| WebInputEvent::DispatchType::ListenersNonBlockingPassive;
|
| EXPECT_EQ(coalesced_event, *last_wheel_event);
|
| }
|
| + histogram_tester.ExpectUniqueSample(kCoalescedCountHistogram, 1, 2);
|
| }
|
|
|
| -TEST_F(MainThreadEventQueueTest, NonBlockingTouch) {
|
| +TEST_P(MainThreadEventQueueTest, NonBlockingTouch) {
|
| + base::HistogramTester histogram_tester;
|
| +
|
| SyntheticWebTouchEvent kEvents[4];
|
| kEvents[0].PressPoint(10, 10);
|
| kEvents[1].PressPoint(10, 10);
|
| @@ -155,7 +191,7 @@ TEST_F(MainThreadEventQueueTest, NonBlockingTouch) {
|
|
|
| EXPECT_EQ(3u, event_queue().size());
|
| EXPECT_TRUE(main_task_runner_->HasPendingTask());
|
| - main_task_runner_->RunUntilIdle();
|
| + RunPendingTasksWithSimulatedRaf();
|
| EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| EXPECT_EQ(0u, event_queue().size());
|
| EXPECT_EQ(3u, handled_events_.size());
|
| @@ -185,9 +221,13 @@ TEST_F(MainThreadEventQueueTest, NonBlockingTouch) {
|
| coalesced_event.dispatchType =
|
| WebInputEvent::DispatchType::ListenersNonBlockingPassive;
|
| EXPECT_EQ(coalesced_event, *last_touch_event);
|
| + histogram_tester.ExpectBucketCount(kCoalescedCountHistogram, 0, 1);
|
| + histogram_tester.ExpectBucketCount(kCoalescedCountHistogram, 1, 1);
|
| }
|
|
|
| -TEST_F(MainThreadEventQueueTest, BlockingTouch) {
|
| +TEST_P(MainThreadEventQueueTest, BlockingTouch) {
|
| + base::HistogramTester histogram_tester;
|
| +
|
| SyntheticWebTouchEvent kEvents[4];
|
| kEvents[0].PressPoint(10, 10);
|
| kEvents[1].PressPoint(10, 10);
|
| @@ -207,14 +247,17 @@ TEST_F(MainThreadEventQueueTest, BlockingTouch) {
|
|
|
| EXPECT_EQ(2u, event_queue().size());
|
| EXPECT_TRUE(main_task_runner_->HasPendingTask());
|
| - main_task_runner_->RunUntilIdle();
|
| + RunPendingTasksWithSimulatedRaf();
|
| +
|
| 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));
|
| +
|
| + histogram_tester.ExpectUniqueSample(kCoalescedCountHistogram, 2, 1);
|
| }
|
|
|
| -TEST_F(MainThreadEventQueueTest, InterleavedEvents) {
|
| +TEST_P(MainThreadEventQueueTest, InterleavedEvents) {
|
| WebMouseWheelEvent kWheelEvents[2] = {
|
| SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, 53, 0, false),
|
| SyntheticWebMouseWheelEventBuilder::Build(20, 20, 0, 53, 0, false),
|
| @@ -234,8 +277,8 @@ TEST_F(MainThreadEventQueueTest, InterleavedEvents) {
|
| HandleEvent(kTouchEvents[1], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
|
|
|
| EXPECT_EQ(2u, event_queue().size());
|
| - EXPECT_TRUE(main_task_runner_->HasPendingTask());
|
| - main_task_runner_->RunUntilIdle();
|
| + EXPECT_EQ(handle_raf_aligned_input_, !main_task_runner_->HasPendingTask());
|
| + RunPendingTasksWithSimulatedRaf();
|
| EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| EXPECT_EQ(0u, event_queue().size());
|
| EXPECT_EQ(2u, handled_events_.size());
|
| @@ -265,7 +308,134 @@ TEST_F(MainThreadEventQueueTest, InterleavedEvents) {
|
| }
|
| }
|
|
|
| -TEST_F(MainThreadEventQueueTest, BlockingTouchesDuringFling) {
|
| +TEST_P(MainThreadEventQueueTest, RafAlignedMouseInput) {
|
| + // Don't run the test when we aren't supporting rAF aligned input.
|
| + if (!handle_raf_aligned_input_)
|
| + return;
|
| +
|
| + WebMouseEvent mouseDown =
|
| + SyntheticWebMouseEventBuilder::Build(WebInputEvent::MouseDown, 10, 10, 0);
|
| +
|
| + WebMouseEvent mouseMove =
|
| + SyntheticWebMouseEventBuilder::Build(WebInputEvent::MouseMove, 10, 10, 0);
|
| +
|
| + WebMouseEvent mouseUp =
|
| + SyntheticWebMouseEventBuilder::Build(WebInputEvent::MouseUp, 10, 10, 0);
|
| +
|
| + WebMouseWheelEvent wheelEvents[2] = {
|
| + SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, 53, 0, false),
|
| + SyntheticWebMouseWheelEventBuilder::Build(20, 20, 0, 53, 0, false),
|
| + };
|
| +
|
| + EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| + EXPECT_EQ(0u, event_queue().size());
|
| +
|
| + // Simulate enqueing a discrete event, followed by continuous events and
|
| + // then a discrete event. The last discrete event should flush the
|
| + // continuous events so the aren't aligned to rAF and are processed
|
| + // immediately.
|
| + HandleEvent(mouseDown, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
|
| + HandleEvent(mouseMove, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
|
| + HandleEvent(wheelEvents[0], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
|
| + HandleEvent(wheelEvents[1], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
|
| + HandleEvent(mouseUp, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
|
| +
|
| + EXPECT_EQ(4u, event_queue().size());
|
| + EXPECT_TRUE(main_task_runner_->HasPendingTask());
|
| + EXPECT_TRUE(needs_main_frame_);
|
| + main_task_runner_->RunUntilIdle();
|
| + EXPECT_EQ(0u, event_queue().size());
|
| + RunPendingTasksWithSimulatedRaf();
|
| +
|
| + // Simulate the rAF running before the PostTask occurs. The first rAF
|
| + // shouldn't do anything.
|
| + 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());
|
| + main_task_runner_->RunUntilIdle();
|
| + EXPECT_TRUE(needs_main_frame_);
|
| + EXPECT_EQ(1u, event_queue().size());
|
| + RunPendingTasksWithSimulatedRaf();
|
| + EXPECT_EQ(0u, event_queue().size());
|
| +}
|
| +
|
| +TEST_P(MainThreadEventQueueTest, RafAlignedTouchInput) {
|
| + // Don't run the test when we aren't supporting rAF aligned input.
|
| + if (!handle_raf_aligned_input_)
|
| + return;
|
| +
|
| + SyntheticWebTouchEvent kEvents[3];
|
| + kEvents[0].PressPoint(10, 10);
|
| + kEvents[1].PressPoint(10, 10);
|
| + kEvents[1].MovePoint(0, 50, 50);
|
| + kEvents[2].PressPoint(10, 10);
|
| + kEvents[2].ReleasePoint(0);
|
| +
|
| + EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| + EXPECT_EQ(0u, event_queue().size());
|
| +
|
| + // Simulate enqueing a discrete event, followed by continuous events and
|
| + // then a discrete event. The last discrete event should flush the
|
| + // continuous events so the aren't aligned to rAF and are processed
|
| + // immediately.
|
| + for (SyntheticWebTouchEvent& event : kEvents)
|
| + HandleEvent(event, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
|
| +
|
| + EXPECT_EQ(3u, event_queue().size());
|
| + EXPECT_TRUE(main_task_runner_->HasPendingTask());
|
| + EXPECT_TRUE(needs_main_frame_);
|
| + main_task_runner_->RunUntilIdle();
|
| + EXPECT_EQ(0u, event_queue().size());
|
| + RunPendingTasksWithSimulatedRaf();
|
| +
|
| + // Simulate the rAF running before the PostTask occurs. The first rAF
|
| + // shouldn't do anything.
|
| + 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());
|
| +}
|
| +
|
| +TEST_P(MainThreadEventQueueTest, RafAlignedMaxSize) {
|
| + // Don't run the test when we aren't supporting rAF aligned input.
|
| + if (!handle_raf_aligned_input_)
|
| + return;
|
| +
|
| + const size_t kNumEventsToQueue = 16;
|
| + WebMouseWheelEvent mouseEvent =
|
| + SyntheticWebMouseWheelEventBuilder::Build(10, 10, 0, 53, 0, false);
|
| +
|
| + EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| + EXPECT_EQ(0u, event_queue().size());
|
| +
|
| + for (size_t i = 0; i < kNumEventsToQueue; ++i) {
|
| + mouseEvent.modifiers = i;
|
| + HandleEvent(mouseEvent, INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
|
| + }
|
| +
|
| + // There is a maximum number of events we handle in a rAF. kNumEventsToQueue
|
| + // exceeds that. Ensure that two rAF calls need to run.
|
| + EXPECT_EQ(kNumEventsToQueue, event_queue().size());
|
| + EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| + EXPECT_TRUE(needs_main_frame_);
|
| + RunSimulatedRafOnce();
|
| + EXPECT_TRUE(needs_main_frame_);
|
| + EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| + RunSimulatedRafOnce();
|
| + EXPECT_EQ(0u, event_queue().size());
|
| + EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| +}
|
| +
|
| +TEST_P(MainThreadEventQueueTest, BlockingTouchesDuringFling) {
|
| SyntheticWebTouchEvent kEvents[1];
|
| kEvents[0].PressPoint(10, 10);
|
| kEvents[0].touchStartOrFirstTouchMove = true;
|
| @@ -274,7 +444,7 @@ TEST_F(MainThreadEventQueueTest, BlockingTouchesDuringFling) {
|
|
|
| EXPECT_FALSE(last_touch_start_forced_nonblocking_due_to_fling());
|
| HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| - main_task_runner_->RunUntilIdle();
|
| + RunPendingTasksWithSimulatedRaf();
|
| EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| EXPECT_EQ(0u, event_queue().size());
|
| EXPECT_EQ(1u, handled_events_.size());
|
| @@ -289,7 +459,7 @@ TEST_F(MainThreadEventQueueTest, BlockingTouchesDuringFling) {
|
|
|
| kEvents[0].MovePoint(0, 30, 30);
|
| HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| - main_task_runner_->RunUntilIdle();
|
| + RunPendingTasksWithSimulatedRaf();
|
| EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| EXPECT_EQ(0u, event_queue().size());
|
| EXPECT_EQ(2u, handled_events_.size());
|
| @@ -305,7 +475,7 @@ TEST_F(MainThreadEventQueueTest, BlockingTouchesDuringFling) {
|
| kEvents[0].MovePoint(0, 50, 50);
|
| kEvents[0].touchStartOrFirstTouchMove = false;
|
| HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| - main_task_runner_->RunUntilIdle();
|
| + RunPendingTasksWithSimulatedRaf();
|
| EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| EXPECT_EQ(0u, event_queue().size());
|
| EXPECT_EQ(3u, handled_events_.size());
|
| @@ -319,7 +489,7 @@ TEST_F(MainThreadEventQueueTest, BlockingTouchesDuringFling) {
|
|
|
| kEvents[0].ReleasePoint(0);
|
| HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| - main_task_runner_->RunUntilIdle();
|
| + RunPendingTasksWithSimulatedRaf();
|
| EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| EXPECT_EQ(0u, event_queue().size());
|
| EXPECT_EQ(4u, handled_events_.size());
|
| @@ -332,7 +502,7 @@ TEST_F(MainThreadEventQueueTest, BlockingTouchesDuringFling) {
|
| EXPECT_EQ(kEvents[0], *last_touch_event);
|
| }
|
|
|
| -TEST_F(MainThreadEventQueueTest, BlockingTouchesOutsideFling) {
|
| +TEST_P(MainThreadEventQueueTest, BlockingTouchesOutsideFling) {
|
| SyntheticWebTouchEvent kEvents[1];
|
| kEvents[0].PressPoint(10, 10);
|
| kEvents[0].touchStartOrFirstTouchMove = true;
|
| @@ -340,7 +510,7 @@ TEST_F(MainThreadEventQueueTest, BlockingTouchesOutsideFling) {
|
| set_enable_fling_passive_listener_flag(false);
|
|
|
| HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| - main_task_runner_->RunUntilIdle();
|
| + RunPendingTasksWithSimulatedRaf();
|
| EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| EXPECT_EQ(0u, event_queue().size());
|
| EXPECT_EQ(1u, handled_events_.size());
|
| @@ -356,7 +526,7 @@ TEST_F(MainThreadEventQueueTest, BlockingTouchesOutsideFling) {
|
| set_is_flinging(true);
|
| set_enable_fling_passive_listener_flag(false);
|
| HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| - main_task_runner_->RunUntilIdle();
|
| + RunPendingTasksWithSimulatedRaf();
|
| EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| EXPECT_EQ(0u, event_queue().size());
|
| EXPECT_EQ(2u, handled_events_.size());
|
| @@ -373,7 +543,7 @@ TEST_F(MainThreadEventQueueTest, BlockingTouchesOutsideFling) {
|
| set_is_flinging(false);
|
| set_enable_fling_passive_listener_flag(true);
|
| HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| - main_task_runner_->RunUntilIdle();
|
| + RunPendingTasksWithSimulatedRaf();
|
| EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| EXPECT_EQ(0u, event_queue().size());
|
| EXPECT_EQ(3u, handled_events_.size());
|
| @@ -389,7 +559,7 @@ TEST_F(MainThreadEventQueueTest, BlockingTouchesOutsideFling) {
|
|
|
| kEvents[0].MovePoint(0, 30, 30);
|
| HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| - main_task_runner_->RunUntilIdle();
|
| + RunPendingTasksWithSimulatedRaf();
|
| EXPECT_FALSE(main_task_runner_->HasPendingTask());
|
| EXPECT_EQ(0u, event_queue().size());
|
| EXPECT_EQ(4u, handled_events_.size());
|
| @@ -403,4 +573,10 @@ TEST_F(MainThreadEventQueueTest, BlockingTouchesOutsideFling) {
|
| EXPECT_EQ(kEvents[0], *last_touch_event);
|
| }
|
|
|
| -} // namespace content
|
| +// The boolean parameterized test varies whether rAF aligned input
|
| +// is enabled or not.
|
| +INSTANTIATE_TEST_CASE_P(MainThreadEventQueueTests,
|
| + MainThreadEventQueueTest,
|
| + testing::Bool());
|
| +
|
| +} // namespace content
|
|
|