1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/check_op.h"
11 #include "base/feature_list.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/notreached.h"
14 #include "cc/base/features.h"
15 #include "cc/metrics/event_metrics.h"
16 #include "cc/trees/layer_tree_host.h"
17 #include "services/tracing/public/cpp/perfetto/flow_event_utils.h"
18 #include "third_party/blink/public/common/input/web_coalesced_input_event.h"
19 #include "third_party/blink/public/common/input/web_input_event_attribution.h"
20 #include "third_party/blink/public/common/input/web_keyboard_event.h"
21 #include "third_party/blink/public/platform/platform.h"
22 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
23 #include "third_party/blink/public/platform/scheduler/web_widget_scheduler.h"
24 #include "third_party/blink/renderer/platform/widget/frame_widget.h"
25 #include "third_party/blink/renderer/platform/widget/input/elastic_overscroll_controller.h"
26 #include "third_party/blink/renderer/platform/widget/input/main_thread_event_queue.h"
27 #include "third_party/blink/renderer/platform/widget/input/widget_input_handler_impl.h"
28 #include "third_party/blink/renderer/platform/widget/widget_base.h"
29 #include "third_party/blink/renderer/platform/widget/widget_base_client.h"
30 
31 #if defined(OS_ANDROID)
32 #include "third_party/blink/renderer/platform/widget/compositing/android_webview/synchronous_compositor_registry.h"
33 #include "third_party/blink/renderer/platform/widget/input/synchronous_compositor_proxy.h"
34 #endif
35 
36 namespace blink {
37 
38 using ::perfetto::protos::pbzero::ChromeLatencyInfo;
39 using ::perfetto::protos::pbzero::TrackEvent;
40 
41 namespace {
42 
ToDidOverscrollParams(const InputHandlerProxy::DidOverscrollParams * overscroll_params)43 mojom::blink::DidOverscrollParamsPtr ToDidOverscrollParams(
44     const InputHandlerProxy::DidOverscrollParams* overscroll_params) {
45   if (!overscroll_params)
46     return nullptr;
47   return mojom::blink::DidOverscrollParams::New(
48       overscroll_params->accumulated_overscroll,
49       overscroll_params->latest_overscroll_delta,
50       overscroll_params->current_fling_velocity,
51       overscroll_params->causal_event_viewport_point,
52       overscroll_params->overscroll_behavior);
53 }
54 
CallCallback(mojom::blink::WidgetInputHandler::DispatchEventCallback callback,mojom::blink::InputEventResultState result_state,const ui::LatencyInfo & latency_info,mojom::blink::DidOverscrollParamsPtr overscroll_params,base::Optional<cc::TouchAction> touch_action)55 void CallCallback(
56     mojom::blink::WidgetInputHandler::DispatchEventCallback callback,
57     mojom::blink::InputEventResultState result_state,
58     const ui::LatencyInfo& latency_info,
59     mojom::blink::DidOverscrollParamsPtr overscroll_params,
60     base::Optional<cc::TouchAction> touch_action) {
61   ui::LatencyInfo::TraceIntermediateFlowEvents(
62       {latency_info}, ChromeLatencyInfo::STEP_HANDLED_INPUT_EVENT_IMPL);
63   std::move(callback).Run(
64       mojom::blink::InputEventResultSource::kMainThread, latency_info,
65       result_state, std::move(overscroll_params),
66       touch_action
67           ? mojom::blink::TouchActionOptional::New(touch_action.value())
68           : nullptr);
69 }
70 
InputEventDispositionToAck(InputHandlerProxy::EventDisposition disposition)71 mojom::blink::InputEventResultState InputEventDispositionToAck(
72     InputHandlerProxy::EventDisposition disposition) {
73   switch (disposition) {
74     case InputHandlerProxy::DID_HANDLE:
75       return mojom::blink::InputEventResultState::kConsumed;
76     case InputHandlerProxy::DID_NOT_HANDLE:
77       return mojom::blink::InputEventResultState::kNotConsumed;
78     case InputHandlerProxy::DID_NOT_HANDLE_NON_BLOCKING_DUE_TO_FLING:
79       return mojom::blink::InputEventResultState::kSetNonBlockingDueToFling;
80     case InputHandlerProxy::DROP_EVENT:
81       return mojom::blink::InputEventResultState::kNoConsumerExists;
82     case InputHandlerProxy::DID_HANDLE_NON_BLOCKING:
83       return mojom::blink::InputEventResultState::kSetNonBlocking;
84     case InputHandlerProxy::DID_HANDLE_SHOULD_BUBBLE:
85       return mojom::blink::InputEventResultState::kConsumedShouldBubble;
86     case InputHandlerProxy::REQUIRES_MAIN_THREAD_HIT_TEST:
87     default:
88       NOTREACHED();
89       return mojom::blink::InputEventResultState::kUnknown;
90   }
91 }
92 
ScrollBeginFromScrollUpdate(const WebGestureEvent & gesture_update)93 std::unique_ptr<blink::WebGestureEvent> ScrollBeginFromScrollUpdate(
94     const WebGestureEvent& gesture_update) {
95   DCHECK(gesture_update.GetType() == WebInputEvent::Type::kGestureScrollUpdate);
96 
97   auto scroll_begin = std::make_unique<WebGestureEvent>(gesture_update);
98   scroll_begin->SetType(WebInputEvent::Type::kGestureScrollBegin);
99 
100   scroll_begin->data.scroll_begin.delta_x_hint =
101       gesture_update.data.scroll_update.delta_x;
102   scroll_begin->data.scroll_begin.delta_y_hint =
103       gesture_update.data.scroll_update.delta_y;
104   scroll_begin->data.scroll_begin.delta_hint_units =
105       gesture_update.data.scroll_update.delta_units;
106   scroll_begin->data.scroll_begin.target_viewport = false;
107   scroll_begin->data.scroll_begin.inertial_phase =
108       gesture_update.data.scroll_update.inertial_phase;
109   scroll_begin->data.scroll_begin.synthetic = false;
110   scroll_begin->data.scroll_begin.pointer_count = 0;
111   scroll_begin->data.scroll_begin.scrollable_area_element_id = 0;
112 
113   return scroll_begin;
114 }
115 
116 }  // namespace
117 
118 #if defined(OS_ANDROID)
119 class SynchronousCompositorProxyRegistry
120     : public SynchronousCompositorRegistry {
121  public:
SynchronousCompositorProxyRegistry(scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner)122   explicit SynchronousCompositorProxyRegistry(
123       scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner)
124       : compositor_task_runner_(std::move(compositor_task_runner)) {}
125 
~SynchronousCompositorProxyRegistry()126   ~SynchronousCompositorProxyRegistry() override {
127     // Ensure the proxy has already been release on the compositor thread
128     // before destroying this object.
129     DCHECK(!proxy_);
130   }
131 
CreateProxy(SynchronousInputHandlerProxy * handler)132   void CreateProxy(SynchronousInputHandlerProxy* handler) {
133     DCHECK(compositor_task_runner_->BelongsToCurrentThread());
134     proxy_ = std::make_unique<SynchronousCompositorProxy>(handler);
135     proxy_->Init();
136 
137     if (sink_)
138       proxy_->SetLayerTreeFrameSink(sink_);
139   }
140 
proxy()141   SynchronousCompositorProxy* proxy() { return proxy_.get(); }
142 
RegisterLayerTreeFrameSink(SynchronousLayerTreeFrameSink * layer_tree_frame_sink)143   void RegisterLayerTreeFrameSink(
144       SynchronousLayerTreeFrameSink* layer_tree_frame_sink) override {
145     DCHECK(compositor_task_runner_->BelongsToCurrentThread());
146     DCHECK_EQ(nullptr, sink_);
147     sink_ = layer_tree_frame_sink;
148     if (proxy_)
149       proxy_->SetLayerTreeFrameSink(layer_tree_frame_sink);
150   }
151 
UnregisterLayerTreeFrameSink(SynchronousLayerTreeFrameSink * layer_tree_frame_sink)152   void UnregisterLayerTreeFrameSink(
153       SynchronousLayerTreeFrameSink* layer_tree_frame_sink) override {
154     DCHECK(compositor_task_runner_->BelongsToCurrentThread());
155     DCHECK_EQ(layer_tree_frame_sink, sink_);
156     sink_ = nullptr;
157   }
158 
DestroyProxy()159   void DestroyProxy() {
160     DCHECK(compositor_task_runner_->BelongsToCurrentThread());
161     proxy_.reset();
162   }
163 
164  private:
165   scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
166   std::unique_ptr<SynchronousCompositorProxy> proxy_;
167   SynchronousLayerTreeFrameSink* sink_ = nullptr;
168 };
169 
170 #endif
171 
Create(base::WeakPtr<WidgetBase> widget,bool never_composited,scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,scheduler::WebThreadScheduler * main_thread_scheduler,bool uses_input_handler)172 scoped_refptr<WidgetInputHandlerManager> WidgetInputHandlerManager::Create(
173     base::WeakPtr<WidgetBase> widget,
174     bool never_composited,
175     scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
176     scheduler::WebThreadScheduler* main_thread_scheduler,
177     bool uses_input_handler) {
178   scoped_refptr<WidgetInputHandlerManager> manager =
179       new WidgetInputHandlerManager(std::move(widget), never_composited,
180                                     std::move(compositor_task_runner),
181                                     main_thread_scheduler);
182   if (uses_input_handler)
183     manager->InitInputHandler();
184 
185   // A compositor thread implies we're using an input handler.
186   DCHECK(!manager->compositor_task_runner_ || uses_input_handler);
187   // Conversely, if we don't use an input handler we must not have a compositor
188   // thread.
189   DCHECK(uses_input_handler || !manager->compositor_task_runner_);
190 
191   return manager;
192 }
193 
WidgetInputHandlerManager(base::WeakPtr<WidgetBase> widget,bool never_composited,scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,scheduler::WebThreadScheduler * main_thread_scheduler)194 WidgetInputHandlerManager::WidgetInputHandlerManager(
195     base::WeakPtr<WidgetBase> widget,
196     bool never_composited,
197     scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
198     scheduler::WebThreadScheduler* main_thread_scheduler)
199     : widget_(widget),
200       widget_scheduler_(main_thread_scheduler->CreateWidgetScheduler()),
201       main_thread_scheduler_(main_thread_scheduler),
202       input_event_queue_(base::MakeRefCounted<MainThreadEventQueue>(
203           this,
204           widget_scheduler_->InputTaskRunner(),
205           main_thread_scheduler,
206           /*allow_raf_aligned_input=*/!never_composited)),
207       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
208       compositor_task_runner_(std::move(compositor_task_runner)) {
209 #if defined(OS_ANDROID)
210   if (compositor_task_runner_) {
211     synchronous_compositor_registry_ =
212         std::make_unique<SynchronousCompositorProxyRegistry>(
213             compositor_task_runner_);
214   }
215 #endif
216 }
217 
InitInputHandler()218 void WidgetInputHandlerManager::InitInputHandler() {
219   bool sync_compositing = false;
220 #if defined(OS_ANDROID)
221   sync_compositing =
222       Platform::Current()->IsSynchronousCompositingEnabledForAndroidWebView();
223 #endif
224   uses_input_handler_ = true;
225   base::OnceClosure init_closure = base::BindOnce(
226       &WidgetInputHandlerManager::InitOnInputHandlingThread, this,
227       widget_->LayerTreeHost()->GetDelegateForInput(), sync_compositing);
228   InputThreadTaskRunner()->PostTask(FROM_HERE, std::move(init_closure));
229 }
230 
231 WidgetInputHandlerManager::~WidgetInputHandlerManager() = default;
232 
AddInterface(mojo::PendingReceiver<mojom::blink::WidgetInputHandler> receiver,mojo::PendingRemote<mojom::blink::WidgetInputHandlerHost> host)233 void WidgetInputHandlerManager::AddInterface(
234     mojo::PendingReceiver<mojom::blink::WidgetInputHandler> receiver,
235     mojo::PendingRemote<mojom::blink::WidgetInputHandlerHost> host) {
236   if (compositor_task_runner_) {
237     host_ = mojo::SharedRemote<mojom::blink::WidgetInputHandlerHost>(
238         std::move(host), compositor_task_runner_);
239     // Mojo channel bound on compositor thread.
240     compositor_task_runner_->PostTask(
241         FROM_HERE, base::BindOnce(&WidgetInputHandlerManager::BindChannel, this,
242                                   std::move(receiver)));
243   } else {
244     host_ = mojo::SharedRemote<mojom::blink::WidgetInputHandlerHost>(
245         std::move(host));
246     // Mojo channel bound on main thread.
247     BindChannel(std::move(receiver));
248   }
249 }
250 
HandleInputEvent(const WebCoalescedInputEvent & event,std::unique_ptr<cc::EventMetrics> metrics,HandledEventCallback handled_callback)251 bool WidgetInputHandlerManager::HandleInputEvent(
252     const WebCoalescedInputEvent& event,
253     std::unique_ptr<cc::EventMetrics> metrics,
254     HandledEventCallback handled_callback) {
255   WidgetBaseInputHandler::HandledEventCallback blink_callback = base::BindOnce(
256       [](HandledEventCallback callback,
257          blink::mojom::InputEventResultState ack_state,
258          const ui::LatencyInfo& latency_info,
259          std::unique_ptr<InputHandlerProxy::DidOverscrollParams>
260              overscroll_params,
261          base::Optional<cc::TouchAction> touch_action) {
262         if (!callback)
263           return;
264         std::move(callback).Run(ack_state, latency_info,
265                                 ToDidOverscrollParams(overscroll_params.get()),
266                                 touch_action);
267       },
268       std::move(handled_callback));
269   widget_->input_handler().HandleInputEvent(event, std::move(metrics),
270                                             std::move(blink_callback));
271   return true;
272 }
273 
SetNeedsMainFrame()274 void WidgetInputHandlerManager::SetNeedsMainFrame() {
275   widget_->client()->ScheduleAnimation();
276 }
277 
WillShutdown()278 void WidgetInputHandlerManager::WillShutdown() {
279 #if defined(OS_ANDROID)
280   if (synchronous_compositor_registry_)
281     synchronous_compositor_registry_->DestroyProxy();
282 #endif
283   input_handler_proxy_.reset();
284 }
285 
DispatchNonBlockingEventToMainThread(std::unique_ptr<WebCoalescedInputEvent> event,const WebInputEventAttribution & attribution,std::unique_ptr<cc::EventMetrics> metrics)286 void WidgetInputHandlerManager::DispatchNonBlockingEventToMainThread(
287     std::unique_ptr<WebCoalescedInputEvent> event,
288     const WebInputEventAttribution& attribution,
289     std::unique_ptr<cc::EventMetrics> metrics) {
290   DCHECK(input_event_queue_);
291   input_event_queue_->HandleEvent(
292       std::move(event), MainThreadEventQueue::DispatchType::kNonBlocking,
293       mojom::blink::InputEventResultState::kSetNonBlocking, attribution,
294       std::move(metrics), HandledEventCallback());
295 }
296 
FindScrollTargetOnMainThread(const gfx::PointF & point,ElementAtPointCallback callback)297 void WidgetInputHandlerManager::FindScrollTargetOnMainThread(
298     const gfx::PointF& point,
299     ElementAtPointCallback callback) {
300   TRACE_EVENT2("input",
301                "WidgetInputHandlerManager::FindScrollTargetOnMainThread",
302                "point.x", point.x(), "point.y", point.y());
303   DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
304   DCHECK(base::FeatureList::IsEnabled(::features::kScrollUnification));
305 
306   uint64_t element_id =
307       widget_->client()->FrameWidget()->GetScrollableContainerIdAt(point);
308 
309   InputThreadTaskRunner()->PostTask(
310       FROM_HERE, base::BindOnce(std::move(callback), element_id));
311 }
312 
DidAnimateForInput()313 void WidgetInputHandlerManager::DidAnimateForInput() {
314   main_thread_scheduler_->DidAnimateForInputOnCompositorThread();
315 }
316 
DidStartScrollingViewport()317 void WidgetInputHandlerManager::DidStartScrollingViewport() {
318   mojom::blink::WidgetInputHandlerHost* host = GetWidgetInputHandlerHost();
319   if (!host)
320     return;
321   host->DidStartScrollingViewport();
322 }
323 
GenerateScrollBeginAndSendToMainThread(const WebGestureEvent & update_event,const WebInputEventAttribution & attribution,const cc::EventMetrics * update_metrics)324 void WidgetInputHandlerManager::GenerateScrollBeginAndSendToMainThread(
325     const WebGestureEvent& update_event,
326     const WebInputEventAttribution& attribution,
327     const cc::EventMetrics* update_metrics) {
328   DCHECK_EQ(update_event.GetType(), WebInputEvent::Type::kGestureScrollUpdate);
329   auto event = std::make_unique<WebCoalescedInputEvent>(
330       ScrollBeginFromScrollUpdate(update_event), ui::LatencyInfo());
331   base::TimeTicks metrics_time_stamp = update_metrics
332                                            ? update_metrics->time_stamp()
333                                            : event->Event().TimeStamp();
334   std::unique_ptr<cc::EventMetrics> metrics = cc::EventMetrics::Create(
335       event->Event().GetTypeAsUiEventType(), base::nullopt, metrics_time_stamp,
336       event->Event().GetScrollInputType());
337 
338   DispatchNonBlockingEventToMainThread(std::move(event), attribution,
339                                        std::move(metrics));
340 }
341 
SetAllowedTouchAction(cc::TouchAction touch_action,uint32_t unique_touch_event_id,InputHandlerProxy::EventDisposition event_disposition)342 void WidgetInputHandlerManager::SetAllowedTouchAction(
343     cc::TouchAction touch_action,
344     uint32_t unique_touch_event_id,
345     InputHandlerProxy::EventDisposition event_disposition) {
346   allowed_touch_action_ = touch_action;
347 }
348 
ProcessTouchAction(cc::TouchAction touch_action)349 void WidgetInputHandlerManager::ProcessTouchAction(
350     cc::TouchAction touch_action) {
351   if (mojom::blink::WidgetInputHandlerHost* host = GetWidgetInputHandlerHost())
352     host->SetTouchActionFromMain(touch_action);
353 }
354 
355 mojom::blink::WidgetInputHandlerHost*
GetWidgetInputHandlerHost()356 WidgetInputHandlerManager::GetWidgetInputHandlerHost() {
357   if (host_)
358     return host_.get();
359   return nullptr;
360 }
361 
AttachSynchronousCompositor(mojo::PendingRemote<mojom::blink::SynchronousCompositorControlHost> control_host,mojo::PendingAssociatedRemote<mojom::blink::SynchronousCompositorHost> host,mojo::PendingAssociatedReceiver<mojom::blink::SynchronousCompositor> compositor_request)362 void WidgetInputHandlerManager::AttachSynchronousCompositor(
363     mojo::PendingRemote<mojom::blink::SynchronousCompositorControlHost>
364         control_host,
365     mojo::PendingAssociatedRemote<mojom::blink::SynchronousCompositorHost> host,
366     mojo::PendingAssociatedReceiver<mojom::blink::SynchronousCompositor>
367         compositor_request) {
368 #if defined(OS_ANDROID)
369   DCHECK(synchronous_compositor_registry_);
370   if (synchronous_compositor_registry_->proxy()) {
371     synchronous_compositor_registry_->proxy()->BindChannel(
372         std::move(control_host), std::move(host),
373         std::move(compositor_request));
374   }
375 #endif
376 }
377 
ObserveGestureEventOnMainThread(const WebGestureEvent & gesture_event,const cc::InputHandlerScrollResult & scroll_result)378 void WidgetInputHandlerManager::ObserveGestureEventOnMainThread(
379     const WebGestureEvent& gesture_event,
380     const cc::InputHandlerScrollResult& scroll_result) {
381   base::OnceClosure observe_gesture_event_closure = base::BindOnce(
382       &WidgetInputHandlerManager::ObserveGestureEventOnInputHandlingThread,
383       this, gesture_event, scroll_result);
384   InputThreadTaskRunner()->PostTask(FROM_HERE,
385                                     std::move(observe_gesture_event_closure));
386 }
387 
LogInputTimingUMA()388 void WidgetInputHandlerManager::LogInputTimingUMA() {
389   if (!have_emitted_uma_) {
390     InitialInputTiming lifecycle_state = InitialInputTiming::kBeforeLifecycle;
391     if (!(renderer_deferral_state_ &
392           (unsigned)RenderingDeferralBits::kDeferMainFrameUpdates)) {
393       if (renderer_deferral_state_ &
394           (unsigned)RenderingDeferralBits::kDeferCommits) {
395         lifecycle_state = InitialInputTiming::kBeforeCommit;
396       } else {
397         lifecycle_state = InitialInputTiming::kAfterCommit;
398       }
399     }
400     UMA_HISTOGRAM_ENUMERATION("PaintHolding.InputTiming2", lifecycle_state);
401     have_emitted_uma_ = true;
402   }
403 }
404 
DispatchScrollGestureToCompositor(std::unique_ptr<WebGestureEvent> event)405 void WidgetInputHandlerManager::DispatchScrollGestureToCompositor(
406     std::unique_ptr<WebGestureEvent> event) {
407   DCHECK(base::FeatureList::IsEnabled(features::kScrollUnification));
408   std::unique_ptr<WebCoalescedInputEvent> web_scoped_gesture_event =
409       std::make_unique<WebCoalescedInputEvent>(std::move(event),
410                                                ui::LatencyInfo());
411   // input thread task runner is |main_thread_task_runner_| only in tests
412   InputThreadTaskRunner()->PostTask(
413       FROM_HERE,
414       base::BindOnce(&WidgetInputHandlerManager::
415                          HandleInputEventWithLatencyOnInputHandlingThread,
416                      this, std::move(web_scoped_gesture_event)));
417 }
418 
419 void WidgetInputHandlerManager::
HandleInputEventWithLatencyOnInputHandlingThread(std::unique_ptr<WebCoalescedInputEvent> event)420     HandleInputEventWithLatencyOnInputHandlingThread(
421         std::unique_ptr<WebCoalescedInputEvent> event) {
422   DCHECK(base::FeatureList::IsEnabled(features::kScrollUnification));
423   DCHECK(input_handler_proxy_);
424   input_handler_proxy_->HandleInputEventWithLatencyInfo(
425       std::move(event), nullptr, base::DoNothing());
426 }
427 
DispatchEvent(std::unique_ptr<WebCoalescedInputEvent> event,mojom::blink::WidgetInputHandler::DispatchEventCallback callback)428 void WidgetInputHandlerManager::DispatchEvent(
429     std::unique_ptr<WebCoalescedInputEvent> event,
430     mojom::blink::WidgetInputHandler::DispatchEventCallback callback) {
431   bool event_is_move =
432       event->Event().GetType() == WebInputEvent::Type::kMouseMove ||
433       event->Event().GetType() == WebInputEvent::Type::kPointerMove;
434   if (!event_is_move)
435     LogInputTimingUMA();
436 
437   // Drop input if we are deferring a rendering pipeline phase, unless it's a
438   // move event.
439   // We don't want users interacting with stuff they can't see, so we drop it.
440   // We allow moves because we need to keep the current pointer location up
441   // to date. Tests and other code can allow pre-commit input through the
442   // "allow-pre-commit-input" command line flag.
443   // TODO(schenney): Also allow scrolls? This would make some tests not flaky,
444   // it seems, because they sometimes crash on seeing a scroll update/end
445   // without a begin. Scrolling, pinch-zoom etc. don't seem dangerous.
446   if (renderer_deferral_state_ && !allow_pre_commit_input_ && !event_is_move) {
447     if (callback) {
448       std::move(callback).Run(
449           mojom::blink::InputEventResultSource::kMainThread, ui::LatencyInfo(),
450           mojom::blink::InputEventResultState::kNotConsumed, nullptr, nullptr);
451     }
452     return;
453   }
454 
455   // If TimeTicks is not consistent across processes we cannot use the event's
456   // platform timestamp in this process. Instead use the time that the event is
457   // received as the event's timestamp.
458   if (!base::TimeTicks::IsConsistentAcrossProcesses()) {
459     event->EventPointer()->SetTimeStamp(base::TimeTicks::Now());
460   }
461 
462   base::Optional<cc::EventMetrics::ScrollUpdateType> scroll_update_type;
463   if (event->Event().GetType() == WebInputEvent::Type::kGestureScrollBegin) {
464     has_seen_first_gesture_scroll_update_after_begin_ = false;
465   } else if (event->Event().GetType() ==
466              WebInputEvent::Type::kGestureScrollUpdate) {
467     if (has_seen_first_gesture_scroll_update_after_begin_) {
468       scroll_update_type = cc::EventMetrics::ScrollUpdateType::kContinued;
469     } else {
470       scroll_update_type = cc::EventMetrics::ScrollUpdateType::kStarted;
471       has_seen_first_gesture_scroll_update_after_begin_ = true;
472     }
473   }
474   std::unique_ptr<cc::EventMetrics> metrics = cc::EventMetrics::Create(
475       event->Event().GetTypeAsUiEventType(), scroll_update_type,
476       event->Event().TimeStamp(), event->Event().GetScrollInputType());
477 
478   if (uses_input_handler_) {
479     // If the input_handler_proxy has disappeared ensure we just ack event.
480     if (!input_handler_proxy_) {
481       if (callback) {
482         std::move(callback).Run(
483             mojom::blink::InputEventResultSource::kMainThread,
484             ui::LatencyInfo(),
485             mojom::blink::InputEventResultState::kNotConsumed, nullptr,
486             nullptr);
487       }
488       return;
489     }
490 
491     // The InputHandlerProxy will be the first to try handling the event on the
492     // compositor thread. It will respond to this class by calling
493     // DidHandleInputEventSentToCompositor with the result of its attempt. Based
494     // on the resulting disposition, DidHandleInputEventSentToCompositor will
495     // either ACK the event as handled to the browser or forward it to the main
496     // thread.
497     input_handler_proxy_->HandleInputEventWithLatencyInfo(
498         std::move(event), std::move(metrics),
499         base::BindOnce(
500             &WidgetInputHandlerManager::DidHandleInputEventSentToCompositor,
501             this, std::move(callback)));
502   } else {
503     DCHECK(!input_handler_proxy_);
504     DispatchDirectlyToWidget(std::move(event), std::move(metrics),
505                              std::move(callback));
506   }
507 }
508 
InvokeInputProcessedCallback()509 void WidgetInputHandlerManager::InvokeInputProcessedCallback() {
510   DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
511 
512   // We can call this method even if we didn't request a callback (e.g. when
513   // the renderer becomes hidden).
514   if (!input_processed_callback_)
515     return;
516 
517   // The handler's method needs to respond to the mojo message so it needs to
518   // run on the input handling thread.  Even if we're already on the correct
519   // thread, we PostTask for symmetry.
520   InputThreadTaskRunner()->PostTask(FROM_HERE,
521                                     std::move(input_processed_callback_));
522 }
523 
WaitForInputProcessedFromMain(base::WeakPtr<WidgetBase> widget)524 static void WaitForInputProcessedFromMain(base::WeakPtr<WidgetBase> widget) {
525   // If the widget is destroyed while we're posting to the main thread, the
526   // Mojo message will be acked in WidgetInputHandlerImpl's destructor.
527   if (!widget)
528     return;
529 
530   WidgetInputHandlerManager* manager = widget->widget_input_handler_manager();
531 
532   // TODO(bokan): Temporary to unblock synthetic gesture events running under
533   // VR. https://crbug.com/940063
534   bool ack_immediately = widget->client()->ShouldAckSyntheticInputImmediately();
535 
536   // If the WidgetBase is hidden, we won't produce compositor frames for it
537   // so just ACK the input to prevent blocking the browser indefinitely.
538   if (widget->is_hidden() || ack_immediately) {
539     manager->InvokeInputProcessedCallback();
540     return;
541   }
542 
543   auto redraw_complete_callback =
544       base::BindOnce(&WidgetInputHandlerManager::InvokeInputProcessedCallback,
545                      manager->AsWeakPtr());
546 
547   // Since wheel-events can kick off animations, we can not consider
548   // all observable effects of an input gesture to be processed
549   // when the CompositorFrame caused by that input has been produced, send, and
550   // displayed. Therefore, explicitly request the presentation *after* any
551   // ongoing scroll-animation ends. After the scroll-animation ends (if any),
552   // the call will force a commit and redraw and callback when the
553   // CompositorFrame has been displayed in the display service. Some examples of
554   // non-trivial effects that require waiting that long: committing
555   // NonFastScrollRegions to the compositor, sending touch-action rects to the
556   // browser, and sending updated surface information to the display compositor
557   // for up-to-date OOPIF hit-testing.
558 
559   widget->RequestPresentationAfterScrollAnimationEnd(
560       std::move(redraw_complete_callback));
561 }
562 
WaitForInputProcessed(base::OnceClosure callback)563 void WidgetInputHandlerManager::WaitForInputProcessed(
564     base::OnceClosure callback) {
565   // Note, this will be called from the mojo-bound thread which could be either
566   // main or compositor.
567   DCHECK(!input_processed_callback_);
568   input_processed_callback_ = std::move(callback);
569 
570   // We mustn't touch widget_ from the impl thread so post all the setup
571   // to the main thread. Make sure the callback runs after all the queued events
572   // are dispatched.
573   input_event_queue_->QueueClosure(
574       base::BindOnce(&WaitForInputProcessedFromMain, widget_));
575 }
576 
DidNavigate()577 void WidgetInputHandlerManager::DidNavigate() {
578   renderer_deferral_state_ = 0;
579   have_emitted_uma_ = false;
580 }
581 
OnDeferMainFrameUpdatesChanged(bool status)582 void WidgetInputHandlerManager::OnDeferMainFrameUpdatesChanged(bool status) {
583   if (status) {
584     renderer_deferral_state_ |=
585         static_cast<uint16_t>(RenderingDeferralBits::kDeferMainFrameUpdates);
586   } else {
587     renderer_deferral_state_ &=
588         ~static_cast<uint16_t>(RenderingDeferralBits::kDeferMainFrameUpdates);
589   }
590 }
591 
OnDeferCommitsChanged(bool status)592 void WidgetInputHandlerManager::OnDeferCommitsChanged(bool status) {
593   if (status) {
594     renderer_deferral_state_ |=
595         static_cast<uint16_t>(RenderingDeferralBits::kDeferCommits);
596   } else {
597     renderer_deferral_state_ &=
598         ~static_cast<uint16_t>(RenderingDeferralBits::kDeferCommits);
599   }
600 }
601 
InitOnInputHandlingThread(const base::WeakPtr<cc::CompositorDelegateForInput> & compositor_delegate,bool sync_compositing)602 void WidgetInputHandlerManager::InitOnInputHandlingThread(
603     const base::WeakPtr<cc::CompositorDelegateForInput>& compositor_delegate,
604     bool sync_compositing) {
605   DCHECK(InputThreadTaskRunner()->BelongsToCurrentThread());
606   DCHECK(uses_input_handler_);
607 
608   // It is possible that the input_handler has already been destroyed before
609   // this Init() call was invoked. If so, early out.
610   if (!compositor_delegate)
611     return;
612 
613   // The input handler is created and ownership is passed to the compositor
614   // delegate; hence we only receive a WeakPtr back.
615   base::WeakPtr<cc::InputHandler> input_handler =
616       cc::InputHandler::Create(*compositor_delegate);
617   DCHECK(input_handler);
618 
619   input_handler_proxy_ =
620       std::make_unique<InputHandlerProxy>(*input_handler.get(), this);
621 
622 #if defined(OS_ANDROID)
623   if (sync_compositing) {
624     DCHECK(synchronous_compositor_registry_);
625     synchronous_compositor_registry_->CreateProxy(input_handler_proxy_.get());
626   }
627 #endif
628 }
629 
BindChannel(mojo::PendingReceiver<mojom::blink::WidgetInputHandler> receiver)630 void WidgetInputHandlerManager::BindChannel(
631     mojo::PendingReceiver<mojom::blink::WidgetInputHandler> receiver) {
632   if (!receiver.is_valid())
633     return;
634   // Don't pass the |input_event_queue_| on if we don't have a
635   // |compositor_task_runner_| as events might get out of order.
636   WidgetInputHandlerImpl* handler = new WidgetInputHandlerImpl(
637       this, main_thread_task_runner_,
638       compositor_task_runner_ ? input_event_queue_ : nullptr, widget_);
639   handler->SetReceiver(std::move(receiver));
640 }
641 
DispatchDirectlyToWidget(std::unique_ptr<WebCoalescedInputEvent> event,std::unique_ptr<cc::EventMetrics> metrics,mojom::blink::WidgetInputHandler::DispatchEventCallback callback)642 void WidgetInputHandlerManager::DispatchDirectlyToWidget(
643     std::unique_ptr<WebCoalescedInputEvent> event,
644     std::unique_ptr<cc::EventMetrics> metrics,
645     mojom::blink::WidgetInputHandler::DispatchEventCallback callback) {
646   // This path should only be taken by non-frame WidgetBase that don't use a
647   // compositor (e.g. popups, plugins). Events bounds for a frame WidgetBase
648   // must be passed through the InputHandlerProxy first.
649   DCHECK(!uses_input_handler_);
650 
651   // Input messages must not be processed if the WidgetBase was destroyed or
652   // was just recreated for a provisional frame.
653   if (!widget_ || widget_->IsForProvisionalFrame()) {
654     if (callback) {
655       std::move(callback).Run(mojom::blink::InputEventResultSource::kMainThread,
656                               event->latency_info(),
657                               mojom::blink::InputEventResultState::kNotConsumed,
658                               nullptr, nullptr);
659     }
660     return;
661   }
662 
663   auto send_callback = base::BindOnce(
664       &WidgetInputHandlerManager::DidHandleInputEventSentToMainFromWidgetBase,
665       this, std::move(callback));
666 
667   widget_->input_handler().HandleInputEvent(*event, std::move(metrics),
668                                             std::move(send_callback));
669 }
670 
FindScrollTargetReply(std::unique_ptr<WebCoalescedInputEvent> event,std::unique_ptr<cc::EventMetrics> metrics,mojom::blink::WidgetInputHandler::DispatchEventCallback browser_callback,uint64_t hit_test_result)671 void WidgetInputHandlerManager::FindScrollTargetReply(
672     std::unique_ptr<WebCoalescedInputEvent> event,
673     std::unique_ptr<cc::EventMetrics> metrics,
674     mojom::blink::WidgetInputHandler::DispatchEventCallback browser_callback,
675     uint64_t hit_test_result) {
676   TRACE_EVENT1("input", "WidgetInputHandlerManager::FindScrollTargetReply",
677                "hit_test_result", hit_test_result);
678   DCHECK(InputThreadTaskRunner()->BelongsToCurrentThread());
679   DCHECK(base::FeatureList::IsEnabled(::features::kScrollUnification));
680 
681   // If the input_handler was destroyed in the mean time just ACK the event as
682   // unconsumed to the browser and drop further handling.
683   if (!input_handler_proxy_) {
684     std::move(browser_callback)
685         .Run(mojom::blink::InputEventResultSource::kMainThread,
686              ui::LatencyInfo(),
687              mojom::blink::InputEventResultState::kNotConsumed, nullptr,
688              nullptr);
689     return;
690   }
691 
692   input_handler_proxy_->ContinueScrollBeginAfterMainThreadHitTest(
693       std::move(event), std::move(metrics),
694       base::BindOnce(
695           &WidgetInputHandlerManager::DidHandleInputEventSentToCompositor, this,
696           std::move(browser_callback)),
697       hit_test_result);
698 }
699 
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)700 void WidgetInputHandlerManager::DidHandleInputEventSentToCompositor(
701     mojom::blink::WidgetInputHandler::DispatchEventCallback callback,
702     InputHandlerProxy::EventDisposition event_disposition,
703     std::unique_ptr<WebCoalescedInputEvent> event,
704     std::unique_ptr<InputHandlerProxy::DidOverscrollParams> overscroll_params,
705     const WebInputEventAttribution& attribution,
706     std::unique_ptr<cc::EventMetrics> metrics) {
707   TRACE_EVENT1("input",
708                "WidgetInputHandlerManager::DidHandleInputEventSentToCompositor",
709                "Disposition", event_disposition);
710   DCHECK(InputThreadTaskRunner()->BelongsToCurrentThread());
711 
712   ui::LatencyInfo::TraceIntermediateFlowEvents(
713       {event->latency_info()},
714       ChromeLatencyInfo::STEP_DID_HANDLE_INPUT_AND_OVERSCROLL);
715 
716   if (event_disposition == InputHandlerProxy::REQUIRES_MAIN_THREAD_HIT_TEST) {
717     TRACE_EVENT_INSTANT0("input", "PostingHitTestToMainThread",
718                          TRACE_EVENT_SCOPE_THREAD);
719     // TODO(bokan): We're going to need to perform a hit test on the main thread
720     // before we can continue handling the event. This is the critical path of a
721     // scroll so we should probably ensure the scheduler can prioritize it
722     // accordingly. https://crbug.com/1082618.
723     DCHECK(base::FeatureList::IsEnabled(::features::kScrollUnification));
724     DCHECK_EQ(event->Event().GetType(),
725               WebInputEvent::Type::kGestureScrollBegin);
726     DCHECK(input_handler_proxy_);
727 
728     gfx::PointF event_position =
729         static_cast<const WebGestureEvent&>(event->Event()).PositionInWidget();
730 
731     ElementAtPointCallback result_callback = base::BindOnce(
732         &WidgetInputHandlerManager::FindScrollTargetReply, this->AsWeakPtr(),
733         std::move(event), std::move(metrics), std::move(callback));
734 
735     main_thread_task_runner_->PostTask(
736         FROM_HERE,
737         base::BindOnce(&WidgetInputHandlerManager::FindScrollTargetOnMainThread,
738                        this, event_position, std::move(result_callback)));
739     return;
740   }
741 
742   mojom::blink::InputEventResultState ack_state =
743       InputEventDispositionToAck(event_disposition);
744   if (ack_state == mojom::blink::InputEventResultState::kConsumed) {
745     main_thread_scheduler_->DidHandleInputEventOnCompositorThread(
746         event->Event(), scheduler::WebThreadScheduler::InputEventState::
747                             EVENT_CONSUMED_BY_COMPOSITOR);
748   } else if (MainThreadEventQueue::IsForwardedAndSchedulerKnown(ack_state)) {
749     main_thread_scheduler_->DidHandleInputEventOnCompositorThread(
750         event->Event(), scheduler::WebThreadScheduler::InputEventState::
751                             EVENT_FORWARDED_TO_MAIN_THREAD);
752   }
753 
754   if (ack_state == mojom::blink::InputEventResultState::kSetNonBlocking ||
755       ack_state ==
756           mojom::blink::InputEventResultState::kSetNonBlockingDueToFling ||
757       ack_state == mojom::blink::InputEventResultState::kNotConsumed) {
758     DCHECK(!overscroll_params);
759     DCHECK(!event->latency_info().coalesced());
760     MainThreadEventQueue::DispatchType dispatch_type =
761         callback.is_null() ? MainThreadEventQueue::DispatchType::kNonBlocking
762                            : MainThreadEventQueue::DispatchType::kBlocking;
763     HandledEventCallback handled_event = base::BindOnce(
764         &WidgetInputHandlerManager::DidHandleInputEventSentToMain, this,
765         std::move(callback));
766     input_event_queue_->HandleEvent(std::move(event), dispatch_type, ack_state,
767                                     attribution, std::move(metrics),
768                                     std::move(handled_event));
769     return;
770   }
771 
772   if (callback) {
773     std::move(callback).Run(
774         mojom::blink::InputEventResultSource::kCompositorThread,
775         event->latency_info(), ack_state,
776         ToDidOverscrollParams(overscroll_params.get()),
777         allowed_touch_action_ ? mojom::blink::TouchActionOptional::New(
778                                     allowed_touch_action_.value())
779                               : nullptr);
780   }
781 }
782 
DidHandleInputEventSentToMainFromWidgetBase(mojom::blink::WidgetInputHandler::DispatchEventCallback callback,mojom::blink::InputEventResultState ack_state,const ui::LatencyInfo & latency_info,std::unique_ptr<blink::InputHandlerProxy::DidOverscrollParams> overscroll_params,base::Optional<cc::TouchAction> touch_action)783 void WidgetInputHandlerManager::DidHandleInputEventSentToMainFromWidgetBase(
784     mojom::blink::WidgetInputHandler::DispatchEventCallback callback,
785     mojom::blink::InputEventResultState ack_state,
786     const ui::LatencyInfo& latency_info,
787     std::unique_ptr<blink::InputHandlerProxy::DidOverscrollParams>
788         overscroll_params,
789     base::Optional<cc::TouchAction> touch_action) {
790   DidHandleInputEventSentToMain(std::move(callback), ack_state, latency_info,
791                                 ToDidOverscrollParams(overscroll_params.get()),
792                                 touch_action);
793 }
794 
DidHandleInputEventSentToMain(mojom::blink::WidgetInputHandler::DispatchEventCallback callback,mojom::blink::InputEventResultState ack_state,const ui::LatencyInfo & latency_info,mojom::blink::DidOverscrollParamsPtr overscroll_params,base::Optional<cc::TouchAction> touch_action)795 void WidgetInputHandlerManager::DidHandleInputEventSentToMain(
796     mojom::blink::WidgetInputHandler::DispatchEventCallback callback,
797     mojom::blink::InputEventResultState ack_state,
798     const ui::LatencyInfo& latency_info,
799     mojom::blink::DidOverscrollParamsPtr overscroll_params,
800     base::Optional<cc::TouchAction> touch_action) {
801   if (!callback)
802     return;
803 
804   TRACE_EVENT1("input",
805                "WidgetInputHandlerManager::DidHandleInputEventSentToMain",
806                "ack_state", ack_state);
807   ui::LatencyInfo::TraceIntermediateFlowEvents(
808       {latency_info}, ChromeLatencyInfo::STEP_HANDLED_INPUT_EVENT_MAIN_OR_IMPL);
809 
810   if (!touch_action.has_value()) {
811     TRACE_EVENT_INSTANT0("input", "Using allowed_touch_action",
812                          TRACE_EVENT_SCOPE_THREAD);
813     touch_action = allowed_touch_action_;
814     allowed_touch_action_.reset();
815   }
816   // This method is called from either the main thread or the compositor thread.
817   bool is_compositor_thread = compositor_task_runner_ &&
818                               compositor_task_runner_->BelongsToCurrentThread();
819 
820   // If there is a compositor task runner and the current thread isn't the
821   // compositor thread proxy it over to the compositor thread.
822   if (compositor_task_runner_ && !is_compositor_thread) {
823     TRACE_EVENT_INSTANT0("input", "PostingToCompositor",
824                          TRACE_EVENT_SCOPE_THREAD);
825     compositor_task_runner_->PostTask(
826         FROM_HERE, base::BindOnce(CallCallback, std::move(callback), ack_state,
827                                   latency_info, std::move(overscroll_params),
828                                   touch_action));
829   } else {
830     // Otherwise call the callback immediately.
831     std::move(callback).Run(
832         is_compositor_thread
833             ? mojom::blink::InputEventResultSource::kCompositorThread
834             : mojom::blink::InputEventResultSource::kMainThread,
835         latency_info, ack_state, std::move(overscroll_params),
836         touch_action
837             ? mojom::blink::TouchActionOptional::New(touch_action.value())
838             : nullptr);
839   }
840 }
841 
ObserveGestureEventOnInputHandlingThread(const WebGestureEvent & gesture_event,const cc::InputHandlerScrollResult & scroll_result)842 void WidgetInputHandlerManager::ObserveGestureEventOnInputHandlingThread(
843     const WebGestureEvent& gesture_event,
844     const cc::InputHandlerScrollResult& scroll_result) {
845   if (!input_handler_proxy_)
846     return;
847   DCHECK(input_handler_proxy_->elastic_overscroll_controller());
848   input_handler_proxy_->elastic_overscroll_controller()
849       ->ObserveGestureEventAndResult(gesture_event, scroll_result);
850 }
851 
852 const scoped_refptr<base::SingleThreadTaskRunner>&
InputThreadTaskRunner() const853 WidgetInputHandlerManager::InputThreadTaskRunner() const {
854   if (compositor_task_runner_)
855     return compositor_task_runner_;
856   return main_thread_task_runner_;
857 }
858 
859 #if defined(OS_ANDROID)
860 SynchronousCompositorRegistry*
GetSynchronousCompositorRegistry()861 WidgetInputHandlerManager::GetSynchronousCompositorRegistry() {
862   DCHECK(synchronous_compositor_registry_);
863   return synchronous_compositor_registry_.get();
864 }
865 #endif
866 
ClearClient()867 void WidgetInputHandlerManager::ClearClient() {
868   input_event_queue_->ClearClient();
869 }
870 
871 }  // namespace blink
872