#include "third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h"
#include <utility>
#include "base/check_op.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/types/optional_ref.h"
#include "base/types/pass_key.h"
#include "build/build_config.h"
#include "cc/base/features.h"
#include "cc/input/browser_controls_offset_tags_info.h"
#include "cc/metrics/event_metrics.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/paint_holding_reason.h"
#include "components/viz/common/features.h"
#include "services/tracing/public/cpp/perfetto/flow_event_utils.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
#include "third_party/blink/public/common/input/web_input_event_attribution.h"
#include "third_party/blink/public/common/input/web_keyboard_event.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/platform/scheduler/public/agent_group_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/compositor_thread_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/widget_scheduler.h"
#include "third_party/blink/renderer/platform/widget/frame_widget.h"
#include "third_party/blink/renderer/platform/widget/input/elastic_overscroll_controller.h"
#include "third_party/blink/renderer/platform/widget/input/main_thread_event_queue.h"
#include "third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.h"
#include "third_party/blink/renderer/platform/widget/widget_base.h"
#include "third_party/blink/renderer/platform/widget/widget_base_client.h"
#if BUILDFLAG(IS_ANDROID)
#include "third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_compositor_registry.h"
#include "third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.h"
#endif
namespace blink {
ChromeLatencyInfo;
TrackEvent;
namespace {
const base::TimeDelta kEventCountsTimerDelay = …;
const base::TimeDelta kFirstPaintMaxAcceptableDelay = …;
mojom::blink::DidOverscrollParamsPtr ToDidOverscrollParams(
const InputHandlerProxy::DidOverscrollParams* overscroll_params) { … }
void CallCallback(
mojom::blink::WidgetInputHandler::DispatchEventCallback callback,
mojom::blink::InputEventResultState result_state,
const ui::LatencyInfo& latency_info,
mojom::blink::DidOverscrollParamsPtr overscroll_params,
std::optional<cc::TouchAction> touch_action) { … }
mojom::blink::InputEventResultState InputEventDispositionToAck(
InputHandlerProxy::EventDisposition disposition) { … }
}
#if BUILDFLAG(IS_ANDROID)
class SynchronousCompositorProxyRegistry
: public SynchronousCompositorRegistry {
public:
explicit SynchronousCompositorProxyRegistry(
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
base::PlatformThreadId io_thread_id,
base::PlatformThreadId main_thread_id)
: compositor_thread_default_task_runner_(
std::move(compositor_task_runner)),
io_thread_id_(io_thread_id),
main_thread_id_(main_thread_id) {}
~SynchronousCompositorProxyRegistry() override {
DCHECK(!proxy_);
}
void CreateProxy(InputHandlerProxy* handler) {
DCHECK(compositor_thread_default_task_runner_->BelongsToCurrentThread());
proxy_ = std::make_unique<SynchronousCompositorProxy>(handler);
proxy_->Init();
if (base::FeatureList::IsEnabled(::features::kWebViewEnableADPF)) {
Vector<base::PlatformThreadId> renderer_thread_ids;
renderer_thread_ids.push_back(base::PlatformThread::CurrentId());
if (io_thread_id_ != base::kInvalidThreadId) {
renderer_thread_ids.push_back(io_thread_id_);
}
if (main_thread_id_ != base::kInvalidThreadId &&
base::FeatureList::IsEnabled(
::features::kWebViewEnableADPFRendererMain)) {
renderer_thread_ids.push_back(main_thread_id_);
}
proxy_->SetThreadIds(renderer_thread_ids);
}
if (sink_)
proxy_->SetLayerTreeFrameSink(sink_);
}
SynchronousCompositorProxy* proxy() { return proxy_.get(); }
void RegisterLayerTreeFrameSink(
SynchronousLayerTreeFrameSink* layer_tree_frame_sink) override {
DCHECK(compositor_thread_default_task_runner_->BelongsToCurrentThread());
DCHECK_EQ(nullptr, sink_);
sink_ = layer_tree_frame_sink;
if (proxy_)
proxy_->SetLayerTreeFrameSink(layer_tree_frame_sink);
}
void UnregisterLayerTreeFrameSink(
SynchronousLayerTreeFrameSink* layer_tree_frame_sink) override {
DCHECK(compositor_thread_default_task_runner_->BelongsToCurrentThread());
DCHECK_EQ(layer_tree_frame_sink, sink_);
sink_ = nullptr;
}
void DestroyProxy() {
DCHECK(compositor_thread_default_task_runner_->BelongsToCurrentThread());
proxy_.reset();
}
private:
scoped_refptr<base::SingleThreadTaskRunner>
compositor_thread_default_task_runner_;
std::unique_ptr<SynchronousCompositorProxy> proxy_;
raw_ptr<SynchronousLayerTreeFrameSink> sink_ = nullptr;
base::PlatformThreadId io_thread_id_;
base::PlatformThreadId main_thread_id_;
};
#endif
scoped_refptr<WidgetInputHandlerManager> WidgetInputHandlerManager::Create(
base::WeakPtr<WidgetBase> widget,
base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
frame_widget_input_handler,
bool never_composited,
CompositorThreadScheduler* compositor_thread_scheduler,
scoped_refptr<scheduler::WidgetScheduler> widget_scheduler,
bool uses_input_handler,
bool allow_scroll_resampling,
base::PlatformThreadId io_thread_id,
base::PlatformThreadId main_thread_id) { … }
WidgetInputHandlerManager::WidgetInputHandlerManager(
base::PassKey<WidgetInputHandlerManager>,
base::WeakPtr<WidgetBase> widget,
base::WeakPtr<mojom::blink::FrameWidgetInputHandler>
frame_widget_input_handler,
bool never_composited,
CompositorThreadScheduler* compositor_thread_scheduler,
scoped_refptr<scheduler::WidgetScheduler> widget_scheduler,
bool allow_scroll_resampling,
base::PlatformThreadId io_thread_id,
base::PlatformThreadId main_thread_id)
: … { … }
void WidgetInputHandlerManager::DidFirstVisuallyNonEmptyPaint(
const base::TimeTicks& first_paint_time) { … }
void WidgetInputHandlerManager::InitInputHandler() { … }
WidgetInputHandlerManager::~WidgetInputHandlerManager() = default;
void WidgetInputHandlerManager::AddInterface(
mojo::PendingReceiver<mojom::blink::WidgetInputHandler> receiver,
mojo::PendingRemote<mojom::blink::WidgetInputHandlerHost> host) { … }
bool WidgetInputHandlerManager::HandleInputEvent(
const WebCoalescedInputEvent& event,
std::unique_ptr<cc::EventMetrics> metrics,
HandledEventCallback handled_callback) { … }
void WidgetInputHandlerManager::InputEventsDispatched(bool raf_aligned) { … }
void WidgetInputHandlerManager::SetNeedsMainFrame() { … }
bool WidgetInputHandlerManager::RequestedMainFramePending() { … }
void WidgetInputHandlerManager::WillShutdown() { … }
void WidgetInputHandlerManager::FindScrollTargetOnMainThread(
const gfx::PointF& point,
ElementAtPointCallback callback) { … }
void WidgetInputHandlerManager::DidStartScrollingViewport() { … }
void WidgetInputHandlerManager::SetAllowedTouchAction(
cc::TouchAction touch_action) { … }
void WidgetInputHandlerManager::ProcessTouchAction(
cc::TouchAction touch_action) { … }
mojom::blink::WidgetInputHandlerHost*
WidgetInputHandlerManager::GetWidgetInputHandlerHost() { … }
#if BUILDFLAG(IS_ANDROID)
void WidgetInputHandlerManager::AttachSynchronousCompositor(
mojo::PendingRemote<mojom::blink::SynchronousCompositorControlHost>
control_host,
mojo::PendingAssociatedRemote<mojom::blink::SynchronousCompositorHost> host,
mojo::PendingAssociatedReceiver<mojom::blink::SynchronousCompositor>
compositor_request) {
DCHECK(synchronous_compositor_registry_);
if (synchronous_compositor_registry_->proxy()) {
synchronous_compositor_registry_->proxy()->BindChannel(
std::move(control_host), std::move(host),
std::move(compositor_request));
}
}
#endif
void WidgetInputHandlerManager::ObserveGestureEventOnMainThread(
const WebGestureEvent& gesture_event,
const cc::InputHandlerScrollResult& scroll_result) { … }
void WidgetInputHandlerManager::LogInputTimingUMA() { … }
void WidgetInputHandlerManager::RecordEventMetricsForPaintTiming(
std::optional<base::TimeTicks> first_paint_time) { … }
void WidgetInputHandlerManager::StartFirstPaintMaxDelayTimer() { … }
void WidgetInputHandlerManager::DispatchScrollGestureToCompositor(
std::unique_ptr<WebGestureEvent> event) { … }
void WidgetInputHandlerManager::
HandleInputEventWithLatencyOnInputHandlingThread(
std::unique_ptr<WebCoalescedInputEvent> event) { … }
void WidgetInputHandlerManager::DispatchEventOnInputThreadForTesting(
std::unique_ptr<blink::WebCoalescedInputEvent> event,
mojom::blink::WidgetInputHandler::DispatchEventCallback callback) { … }
void WidgetInputHandlerManager::DispatchEvent(
std::unique_ptr<WebCoalescedInputEvent> event,
mojom::blink::WidgetInputHandler::DispatchEventCallback callback) { … }
void WidgetInputHandlerManager::InvokeInputProcessedCallback() { … }
static void WaitForInputProcessedFromMain(base::WeakPtr<WidgetBase> widget) { … }
void WidgetInputHandlerManager::WaitForInputProcessed(
base::OnceClosure callback) { … }
void WidgetInputHandlerManager::InitializeInputEventSuppressionStates() { … }
void WidgetInputHandlerManager::OnDeferMainFrameUpdatesChanged(bool status) { … }
void WidgetInputHandlerManager::OnDeferCommitsChanged(
bool status,
cc::PaintHoldingReason reason) { … }
void WidgetInputHandlerManager::InitOnInputHandlingThread(
const base::WeakPtr<cc::CompositorDelegateForInput>& compositor_delegate,
bool sync_compositing) { … }
void WidgetInputHandlerManager::BindChannel(
mojo::PendingReceiver<mojom::blink::WidgetInputHandler> receiver) { … }
void WidgetInputHandlerManager::DispatchDirectlyToWidget(
std::unique_ptr<WebCoalescedInputEvent> event,
std::unique_ptr<cc::EventMetrics> metrics,
mojom::blink::WidgetInputHandler::DispatchEventCallback callback) { … }
void WidgetInputHandlerManager::FindScrollTargetReply(
std::unique_ptr<WebCoalescedInputEvent> event,
std::unique_ptr<cc::EventMetrics> metrics,
mojom::blink::WidgetInputHandler::DispatchEventCallback browser_callback,
cc::ElementId hit_test_result) { … }
void WidgetInputHandlerManager::SendDroppedPointerDownCounts() { … }
void WidgetInputHandlerManager::DidHandleInputEventSentToCompositor(
mojom::blink::WidgetInputHandler::DispatchEventCallback callback,
InputHandlerProxy::EventDisposition event_disposition,
std::unique_ptr<WebCoalescedInputEvent> event,
std::unique_ptr<InputHandlerProxy::DidOverscrollParams> overscroll_params,
const WebInputEventAttribution& attribution,
std::unique_ptr<cc::EventMetrics> metrics) { … }
void WidgetInputHandlerManager::DidHandleInputEventSentToMainFromWidgetBase(
mojom::blink::WidgetInputHandler::DispatchEventCallback callback,
mojom::blink::InputEventResultState ack_state,
const ui::LatencyInfo& latency_info,
std::unique_ptr<blink::InputHandlerProxy::DidOverscrollParams>
overscroll_params,
std::optional<cc::TouchAction> touch_action) { … }
void WidgetInputHandlerManager::DidHandleInputEventSentToMain(
mojom::blink::WidgetInputHandler::DispatchEventCallback callback,
std::optional<cc::TouchAction> touch_action_from_compositor,
mojom::blink::InputEventResultState ack_state,
const ui::LatencyInfo& latency_info,
mojom::blink::DidOverscrollParamsPtr overscroll_params,
std::optional<cc::TouchAction> touch_action_from_main) { … }
void WidgetInputHandlerManager::ObserveGestureEventOnInputHandlingThread(
const WebGestureEvent& gesture_event,
const cc::InputHandlerScrollResult& scroll_result) { … }
const scoped_refptr<base::SingleThreadTaskRunner>&
WidgetInputHandlerManager::InputThreadTaskRunner(TaskRunnerType type) const { … }
#if BUILDFLAG(IS_ANDROID)
SynchronousCompositorRegistry*
WidgetInputHandlerManager::GetSynchronousCompositorRegistry() {
DCHECK(synchronous_compositor_registry_);
return synchronous_compositor_registry_.get();
}
#endif
void WidgetInputHandlerManager::ClearClient() { … }
void WidgetInputHandlerManager::UpdateBrowserControlsState(
cc::BrowserControlsState constraints,
cc::BrowserControlsState current,
bool animate,
base::optional_ref<const cc::BrowserControlsOffsetTagsInfo>
offset_tags_info) { … }
void WidgetInputHandlerManager::FlushCompositorQueueForTesting() { … }
void WidgetInputHandlerManager::FlushMainThreadQueueForTesting(
base::OnceClosure done) { … }
void WidgetInputHandlerManager::FlushEventQueuesForTesting(
base::OnceClosure done_callback) { … }
}