| Index: content/browser/renderer_host/input/synthetic_gesture_controller.cc
|
| diff --git a/content/browser/renderer_host/input/synthetic_gesture_controller.cc b/content/browser/renderer_host/input/synthetic_gesture_controller.cc
|
| index 1ab65e7fa8733a96fadce29efaa916fd17701690..f6503e866ac3489c5720c08e95d871f65081a688 100644
|
| --- a/content/browser/renderer_host/input/synthetic_gesture_controller.cc
|
| +++ b/content/browser/renderer_host/input/synthetic_gesture_controller.cc
|
| @@ -41,18 +41,41 @@ void SyntheticGestureController::QueueSyntheticGesture(
|
| }
|
|
|
| void SyntheticGestureController::RequestBeginFrame() {
|
| + DCHECK(!dispatch_timer_.IsRunning());
|
| delegate_->RequestBeginFrameForSynthesizedInput(
|
| base::BindOnce(&SyntheticGestureController::OnBeginFrame,
|
| weak_ptr_factory_.GetWeakPtr()));
|
| }
|
|
|
| void SyntheticGestureController::OnBeginFrame() {
|
| - // TODO(sad): Instead of dispatching the events immediately, dispatch after an
|
| - // offset.
|
| - DispatchNextEvent();
|
| + // In order to make sure we get consistent results across runs, we attempt to
|
| + // start the timer at a fixed offset from the vsync. Starting the timer
|
| + // shortly after a begin-frame is likely to produce latency close to the worst
|
| + // cases. We feel 2 milliseconds is a good offset for this.
|
| + constexpr base::TimeDelta kSynthesizedDispatchDelay =
|
| + base::TimeDelta::FromMilliseconds(2);
|
| + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::BindOnce(&SyntheticGestureController::StartTimer,
|
| + weak_ptr_factory_.GetWeakPtr()),
|
| + kSynthesizedDispatchDelay);
|
| +}
|
| +
|
| +void SyntheticGestureController::StartTimer() {
|
| + // TODO(sad): Change the interval to allow sending multiple events per begin
|
| + // frame.
|
| + dispatch_timer_.Start(
|
| + FROM_HERE, base::TimeDelta::FromMicroseconds(16666),
|
| + base::BindRepeating(
|
| + [](base::WeakPtr<SyntheticGestureController> weak_ptr) {
|
| + if (weak_ptr)
|
| + weak_ptr->DispatchNextEvent(base::TimeTicks::Now());
|
| + },
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| }
|
|
|
| bool SyntheticGestureController::DispatchNextEvent(base::TimeTicks timestamp) {
|
| + DCHECK(dispatch_timer_.IsRunning());
|
| TRACE_EVENT0("input", "SyntheticGestureController::Flush");
|
| if (pending_gesture_queue_.IsEmpty())
|
| return false;
|
| @@ -63,23 +86,22 @@ bool SyntheticGestureController::DispatchNextEvent(base::TimeTicks timestamp) {
|
| timestamp, gesture_target_.get());
|
|
|
| if (result == SyntheticGesture::GESTURE_RUNNING) {
|
| - RequestBeginFrame();
|
| return true;
|
| }
|
| pending_gesture_queue_.mark_current_gesture_complete(result);
|
| }
|
|
|
| - if (!delegate_->HasGestureStopped()) {
|
| - RequestBeginFrame();
|
| + if (!delegate_->HasGestureStopped())
|
| return true;
|
| - }
|
|
|
| StopGesture(*pending_gesture_queue_.FrontGesture(),
|
| pending_gesture_queue_.FrontCallback(),
|
| pending_gesture_queue_.current_gesture_result());
|
| pending_gesture_queue_.Pop();
|
| - if (pending_gesture_queue_.IsEmpty())
|
| + if (pending_gesture_queue_.IsEmpty()) {
|
| + dispatch_timer_.Stop();
|
| return false;
|
| + }
|
| StartGesture(*pending_gesture_queue_.FrontGesture());
|
| return true;
|
| }
|
| @@ -88,7 +110,8 @@ void SyntheticGestureController::StartGesture(const SyntheticGesture& gesture) {
|
| TRACE_EVENT_ASYNC_BEGIN0("input,benchmark",
|
| "SyntheticGestureController::running",
|
| &gesture);
|
| - RequestBeginFrame();
|
| + if (!dispatch_timer_.IsRunning())
|
| + RequestBeginFrame();
|
| }
|
|
|
| void SyntheticGestureController::StopGesture(
|
|
|