blob: 5e5f20d3e036e03c689eb8a0a51c4ce92ae1c756 [file] [log] [blame]
// Copyright 2017 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.
#ifndef CONTENT_RENDERER_INPUT_WIDGET_INPUT_HANDLER_MANAGER_H_
#define CONTENT_RENDERER_INPUT_WIDGET_INPUT_HANDLER_MANAGER_H_
#include <atomic>
#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
#include "content/common/input/input_handler.mojom.h"
#include "content/renderer/render_frame_impl.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/shared_remote.h"
#include "ui/events/blink/input_handler_proxy.h"
#include "ui/events/blink/input_handler_proxy_client.h"
namespace blink {
namespace scheduler {
class WebThreadScheduler;
} // namespace scheduler
} // namespace blink
namespace gfx {
struct PresentationFeedback;
} // namespace gfx
namespace content {
class MainThreadEventQueue;
class SynchronousCompositorRegistry;
class SynchronousCompositorProxyRegistry;
// This class maintains the compositor InputHandlerProxy and is
// responsible for passing input events on the compositor and main threads.
// The lifecycle of this object matches that of the RenderWidget.
class CONTENT_EXPORT WidgetInputHandlerManager final
: public base::RefCountedThreadSafe<WidgetInputHandlerManager>,
public ui::InputHandlerProxyClient,
public base::SupportsWeakPtr<WidgetInputHandlerManager> {
// Used in UMA metrics reporting. Do not re-order, and rename the metric if
// additional states are required.
enum class InitialInputTiming {
// Input comes before lifecycle update
kBeforeLifecycle = 0,
// Input is before commit
kBeforeCommit = 1,
// Input comes only after commit
kAfterCommit = 2,
kMaxValue = kAfterCommit
};
// For use in bitfields to keep track of what, if anything, the rendering
// pipeline is currently deferring. Input is suppressed if anything is
// being deferred, and we use the combination of states to correctly report
// UMA for input that is suppressed.
enum class RenderingDeferralBits {
kDeferMainFrameUpdates = 1,
kDeferCommits = 2
};
public:
static scoped_refptr<WidgetInputHandlerManager> Create(
base::WeakPtr<RenderWidget> render_widget,
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
blink::scheduler::WebThreadScheduler* main_thread_scheduler,
bool needs_input_handler);
void AddAssociatedInterface(
mojo::PendingAssociatedReceiver<mojom::WidgetInputHandler> receiver,
mojo::PendingRemote<mojom::WidgetInputHandlerHost> host);
void AddInterface(mojo::PendingReceiver<mojom::WidgetInputHandler> receiver,
mojo::PendingRemote<mojom::WidgetInputHandlerHost> host);
// InputHandlerProxyClient overrides.
void WillShutdown() override;
void DispatchNonBlockingEventToMainThread(
ui::WebScopedInputEvent event,
const ui::LatencyInfo& latency_info) override;
void DidOverscroll(
const gfx::Vector2dF& accumulated_overscroll,
const gfx::Vector2dF& latest_overscroll_delta,
const gfx::Vector2dF& current_fling_velocity,
const gfx::PointF& causal_event_viewport_point,
const cc::OverscrollBehavior& overscroll_behavior) override;
void DidAnimateForInput() override;
void DidStartScrollingViewport() override;
void GenerateScrollBeginAndSendToMainThread(
const blink::WebGestureEvent& update_event) override;
void SetWhiteListedTouchAction(
cc::TouchAction touch_action,
uint32_t unique_touch_event_id,
ui::InputHandlerProxy::EventDisposition event_disposition) override;
void ObserveGestureEventOnMainThread(
const blink::WebGestureEvent& gesture_event,
const cc::InputHandlerScrollResult& scroll_result);
void DispatchEvent(std::unique_ptr<content::InputEvent> event,
mojom::WidgetInputHandler::DispatchEventCallback callback);
void ProcessTouchAction(cc::TouchAction touch_action);
mojom::WidgetInputHandlerHost* GetWidgetInputHandlerHost();
void AttachSynchronousCompositor(
mojo::PendingRemote<mojom::SynchronousCompositorControlHost> control_host,
mojo::PendingAssociatedRemote<mojom::SynchronousCompositorHost> host,
mojo::PendingAssociatedReceiver<mojom::SynchronousCompositor>
compositor_request);
#if defined(OS_ANDROID)
content::SynchronousCompositorRegistry* GetSynchronousCompositorRegistry();
#endif
void InvokeInputProcessedCallback();
void InputWasProcessed(const gfx::PresentationFeedback& feedback);
void WaitForInputProcessed(base::OnceClosure callback);
void FallbackCursorModeLockCursor(bool left, bool right, bool up, bool down);
void FallbackCursorModeSetCursorVisibility(bool visible);
// Called when the RenderWidget is notified of a navigation. Resets
// the renderer pipeline deferral status, and resets the UMA recorder for
// time of first input.
void DidNavigate();
// Called to inform us when the system starts or stops main frame updates.
void OnDeferMainFrameUpdatesChanged(bool);
// Called to inform us when the system starts or stops deferring commits.
void OnDeferCommitsChanged(bool);
// Allow tests, headless etc. to have input events processed before the
// compositor is ready to commit frames.
// TODO(schenney): Fix this somehow, forcing all tests to wait for
// hit test regions.
void AllowPreCommitInput() { allow_pre_commit_input_ = true; }
protected:
friend class base::RefCountedThreadSafe<WidgetInputHandlerManager>;
~WidgetInputHandlerManager() override;
private:
WidgetInputHandlerManager(
base::WeakPtr<RenderWidget> render_widget,
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
blink::scheduler::WebThreadScheduler* main_thread_scheduler);
void InitInputHandler();
void InitOnInputHandlingThread(
const base::WeakPtr<cc::InputHandler>& input_handler,
bool smooth_scroll_enabled,
bool sync_compositing);
void BindAssociatedChannel(
mojo::PendingAssociatedReceiver<mojom::WidgetInputHandler> receiver);
void BindChannel(mojo::PendingReceiver<mojom::WidgetInputHandler> receiver);
void HandleInputEvent(
const ui::WebScopedInputEvent& event,
const ui::LatencyInfo& latency,
mojom::WidgetInputHandler::DispatchEventCallback callback);
void DidHandleInputEventAndOverscroll(
mojom::WidgetInputHandler::DispatchEventCallback callback,
ui::InputHandlerProxy::EventDisposition event_disposition,
ui::WebScopedInputEvent input_event,
const ui::LatencyInfo& latency_info,
std::unique_ptr<ui::DidOverscrollParams> overscroll_params);
void HandledInputEvent(
mojom::WidgetInputHandler::DispatchEventCallback callback,
InputEventAckState ack_state,
const ui::LatencyInfo& latency_info,
std::unique_ptr<ui::DidOverscrollParams> overscroll_params,
base::Optional<cc::TouchAction> touch_action);
void ObserveGestureEventOnInputHandlingThread(
const blink::WebGestureEvent& gesture_event,
const cc::InputHandlerScrollResult& scroll_result);
// Returns the task runner for the thread that receives input. i.e. the
// "Mojo-bound" thread.
const scoped_refptr<base::SingleThreadTaskRunner>& InputThreadTaskRunner()
const;
void LogInputTimingUMA();
// Only valid to be called on the main thread.
base::WeakPtr<RenderWidget> render_widget_;
blink::scheduler::WebThreadScheduler* main_thread_scheduler_;
// InputHandlerProxy is only interacted with on the compositor
// thread.
std::unique_ptr<ui::InputHandlerProxy> input_handler_proxy_;
// The WidgetInputHandlerHost is bound on the compositor task runner
// but class can be called on the compositor and main thread.
mojo::SharedRemote<mojom::WidgetInputHandlerHost> host_;
// Host that was passed as part of the FrameInputHandler associated
// channel.
mojo::SharedRemote<mojom::WidgetInputHandlerHost> associated_host_;
// Any thread can access these variables.
scoped_refptr<MainThreadEventQueue> input_event_queue_;
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
base::Optional<cc::TouchAction> white_listed_touch_action_;
// Callback used to respond to the WaitForInputProcessed Mojo message. This
// callback is set from and must be invoked from the Mojo-bound thread (i.e.
// the InputThreadTaskRunner thread), it will invoke the Mojo reply.
base::OnceClosure input_processed_callback_;
// Whether this widget uses an InputHandler or forwards all input to the
// WebWidget (Popups, Plugins).
bool uses_input_handler_ = false;
// State tracking which parts of the rendering pipeline are currently
// deferred. We use this state to suppress all events until the user can see
// the content; that is, while rendering stages are being deferred and
// this value is zero.
// Move events are still processed to allow tracking of mouse position.
// Metrics also report the lifecycle state when the first non-move event is
// seen.
// This is a bitfield, using the bit values from RenderingDeferralBits.
// The compositor thread accesses this value when processing input (to decide
// whether to suppress input) and the renderer thread accesses it when the
// status of deferrals changes, so it needs to be thread safe.
std::atomic<uint16_t> renderer_deferral_state_{0};
// Allow input suppression to be disabled for tests and non-browser uses
// of chromium that do not wait for the first commit, or that may never
// commit. Over time, tests should be fixed so they provide additional
// coverage for input suppression: crbug.com/987626
bool allow_pre_commit_input_ = false;
// Control of UMA. We emit one UMA metric per navigation telling us
// whether any non-move input arrived before we starting updating the page or
// displaying content to the user.
bool have_emitted_uma_ = false;
#if defined(OS_ANDROID)
std::unique_ptr<SynchronousCompositorProxyRegistry>
synchronous_compositor_registry_;
#endif
DISALLOW_COPY_AND_ASSIGN(WidgetInputHandlerManager);
};
} // namespace content
#endif // CONTENT_RENDERER_INPUT_WIDGET_INPUT_HANDLER_MANAGER_H_