| // 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 |