blob: af3613806593f8999bc20b426bf0556aa4dc7655 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/input/synthetic_gesture_controller.h"
#include <utility>
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/common/input_messages.h"
#include "content/public/browser/render_widget_host.h"
namespace content {
SyntheticGestureController::SyntheticGestureController(
Delegate* delegate,
std::unique_ptr<SyntheticGestureTarget> gesture_target)
: delegate_(delegate),
gesture_target_(std::move(gesture_target)),
weak_ptr_factory_(this) {
DCHECK(delegate_);
}
SyntheticGestureController::~SyntheticGestureController() {
if (!pending_gesture_queue_.IsEmpty())
GestureCompleted(SyntheticGesture::GESTURE_FINISHED);
}
void SyntheticGestureController::QueueSyntheticGesture(
std::unique_ptr<SyntheticGesture> synthetic_gesture,
OnGestureCompleteCallback completion_callback) {
DCHECK(synthetic_gesture);
bool was_empty = pending_gesture_queue_.IsEmpty();
pending_gesture_queue_.Push(std::move(synthetic_gesture),
std::move(completion_callback));
if (was_empty)
StartGesture(*pending_gesture_queue_.FrontGesture());
}
void SyntheticGestureController::StartTimer(bool high_frequency) {
dispatch_timer_.Start(
FROM_HERE,
base::TimeDelta::FromMicroseconds(high_frequency ? 8333 : 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;
if (!pending_gesture_queue_.is_current_gesture_complete()) {
SyntheticGesture::Result result =
pending_gesture_queue_.FrontGesture()->ForwardInputEvents(
timestamp, gesture_target_.get());
if (result == SyntheticGesture::GESTURE_RUNNING) {
return true;
}
pending_gesture_queue_.mark_current_gesture_complete(result);
}
if (!delegate_->HasGestureStopped())
return true;
StopGesture(*pending_gesture_queue_.FrontGesture(),
pending_gesture_queue_.current_gesture_result());
return !pending_gesture_queue_.IsEmpty();
}
void SyntheticGestureController::StartGesture(const SyntheticGesture& gesture) {
TRACE_EVENT_ASYNC_BEGIN0("input,benchmark",
"SyntheticGestureController::running",
&gesture);
if (!dispatch_timer_.IsRunning())
StartTimer(gesture.AllowHighFrequencyDispatch());
}
void SyntheticGestureController::StopGesture(
const SyntheticGesture& gesture,
SyntheticGesture::Result result) {
DCHECK_NE(result, SyntheticGesture::GESTURE_RUNNING);
TRACE_EVENT_ASYNC_END0("input,benchmark",
"SyntheticGestureController::running",
&gesture);
dispatch_timer_.Stop();
if (result != SyntheticGesture::GESTURE_FINISHED) {
GestureCompleted(result);
return;
}
// If the gesture finished successfully, wait until all the input has been
// propagated throughout the entire input pipeline before we resolve the
// completion callback. This ensures all the effects of this gesture are
// visible to subsequent input (e.g. OOPIF hit testing).
gesture.WaitForTargetAck(
base::BindOnce(&SyntheticGestureController::GestureCompleted,
weak_ptr_factory_.GetWeakPtr(),
SyntheticGesture::GESTURE_FINISHED),
gesture_target_.get());
}
void SyntheticGestureController::GestureCompleted(
SyntheticGesture::Result result) {
pending_gesture_queue_.FrontCallback().Run(result);
pending_gesture_queue_.Pop();
if (!pending_gesture_queue_.IsEmpty())
StartGesture(*pending_gesture_queue_.FrontGesture());
}
SyntheticGestureController::GestureAndCallbackQueue::GestureAndCallbackQueue() {
}
SyntheticGestureController::GestureAndCallbackQueue::
~GestureAndCallbackQueue() {
}
} // namespace content