File: input_handler_proxy.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (480 lines) | stat: -rw-r--r-- 21,479 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WIDGET_INPUT_INPUT_HANDLER_PROXY_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WIDGET_INPUT_INPUT_HANDLER_PROXY_H_

#include <memory>

#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "base/types/optional_ref.h"
#include "cc/input/browser_controls_offset_tag_modifications.h"
#include "cc/input/browser_controls_state.h"
#include "cc/input/input_handler.h"
#include "cc/input/snap_fling_controller.h"
#include "cc/paint/element_id.h"
#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
#include "third_party/blink/public/common/input/web_gesture_event.h"
#include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/renderer/platform/platform_export.h"

namespace base {
class TickClock;
}

namespace cc {
class EventMetrics;
}

namespace ui {
class LatencyInfo;
}

namespace blink {
class WebInputEventAttribution;
class WebMouseWheelEvent;
class WebTouchEvent;
class ElasticOverscrollController;
}  // namespace blink

namespace blink {

namespace test {
class InputHandlerProxyTest;
class InputHandlerProxyEventQueueTest;
class InputHandlerProxyMomentumScrollJankTest;
class InputHandlerProxyForceHandlingOnMainThread;
class TestInputHandlerProxy;
class UnifiedScrollingInputHandlerProxyTest;
}  // namespace test

class CompositorThreadEventQueue;
class EventWithCallback;
class InputHandlerProxyClient;
class ScrollPredictor;
class CursorControlHandler;

class SynchronousInputHandler {
 public:
  virtual ~SynchronousInputHandler() {}

  // Informs the Android WebView embedder of the current root scroll and page
  // scale state.
  virtual void UpdateRootLayerState(const gfx::PointF& total_scroll_offset,
                                    const gfx::PointF& max_scroll_offset,
                                    const gfx::SizeF& scrollable_size,
                                    float page_scale_factor,
                                    float min_page_scale_factor,
                                    float max_page_scale_factor) = 0;
};

// This class is a proxy between the blink web input events for a WebWidget and
// the compositor's input handling logic. InputHandlerProxy instances live
// entirely on the compositor thread if one exists; however, it can exist on
// the main thread in web tests where only a single thread is used.
// Each InputHandler instance handles input events intended for a specific
// WebWidget.
//
// Android WebView requires synchronous scrolling from the WebView application.
// This class provides support for that behaviour. The WebView embedder will
// act as the InputHandler for controlling the timing of input (fling)
// animations.
class PLATFORM_EXPORT InputHandlerProxy : public cc::InputHandlerClient,
                                          public cc::SnapFlingClient {
 public:
  InputHandlerProxy(cc::InputHandler& input_handler,
                    InputHandlerProxyClient* client);
  InputHandlerProxy(const InputHandlerProxy&) = delete;
  InputHandlerProxy& operator=(const InputHandlerProxy&) = delete;
  ~InputHandlerProxy() override;

  ElasticOverscrollController* elastic_overscroll_controller() {
    return elastic_overscroll_controller_.get();
  }

  // TODO(dtapuska): Eventually move this to mojo.
  struct DidOverscrollParams {
    gfx::Vector2dF accumulated_overscroll;
    gfx::Vector2dF latest_overscroll_delta;
    gfx::Vector2dF current_fling_velocity;
    gfx::PointF causal_event_viewport_point;
    cc::OverscrollBehavior overscroll_behavior;
  };

  // Result codes returned to the client indicating the status of handling the
  // event on the compositor. Used to determine further event handling behavior
  // (i.e. should the event be forwarded to the main thread, ACK'ed to the
  // browser, etc.).
  enum EventDisposition {
    // The event was handled on the compositor and should not be forwarded to
    // the main thread.
    DID_HANDLE,

    // The compositor could not handle the event but the event may still be
    // valid for handling so it should be forwarded to the main thread.
    DID_NOT_HANDLE,

    // Set only from a touchstart that occurred while a fling was in progress.
    // Indicates that the rest of the touch stream should be sent non-blocking
    // to ensure the scroll remains smooth. Since it's non-blocking, the event
    // will be ACK'ed to the browser before being dispatched to the main
    // thread.
    // TODO(bokan): It's not clear that we need a separate status for this
    // case, why can't we just use the DID_NOT_HANDLE_NON_BLOCKING below?
    DID_NOT_HANDLE_NON_BLOCKING_DUE_TO_FLING,

    // Set to indicate that the event needs to be sent to the main thread (e.g.
    // because the touch event hits a touch-event handler) but the compositor
    // has determined it shouldn't be cancellable (e.g. the event handler is
    // passive). Because it isn't cancellable, the event (and future events)
    // will be sent non-blocking and be acked to the browser before being
    // dispatchehd to the main thread.
    DID_NOT_HANDLE_NON_BLOCKING,

    // The compositor didn't handle the event but has determined the main
    // thread doesn't care about the event either (e.g. it's a touch event and
    // the hit point doesn't have a touch handler). In this case, we should ACK
    // the event immediately. Both this and DID_HANDLE will avoid forwarding
    // the event to the main thread and ACK immediately; the difference is that
    // DROP_EVENT tells the client the event wasn't consumed. For example, the
    // browser may choose to use this to avoid forwarding touch events if there
    // isn't a consumer for them (and send only the scroll events).
    DROP_EVENT,

    // Used only in scroll unification; the compositor couldn't determine the
    // scroll node to handle the event and requires a second try with an
    // ElementId provided by a hit test in Blink.
    REQUIRES_MAIN_THREAD_HIT_TEST,
  };
  using EventDispositionCallback = base::OnceCallback<void(
      EventDisposition,
      std::unique_ptr<blink::WebCoalescedInputEvent> event,
      std::unique_ptr<DidOverscrollParams>,
      const blink::WebInputEventAttribution&,
      std::unique_ptr<cc::EventMetrics> metrics)>;
  // Virtual for mocking in tests.
  virtual void HandleInputEventWithLatencyInfo(
      std::unique_ptr<blink::WebCoalescedInputEvent> event,
      std::unique_ptr<cc::EventMetrics> metrics,
      EventDispositionCallback callback);

  // In scroll unification, a scroll begin event may initially return unhandled
  // due to requiring the main thread to perform a hit test. In that case, the
  // client will perform the hit test by calling into Blink. When it has a
  // result, it can try handling the event again by calling back through this
  // method.
  void ContinueScrollBeginAfterMainThreadHitTest(
      std::unique_ptr<blink::WebCoalescedInputEvent> event,
      std::unique_ptr<cc::EventMetrics> metrics,
      EventDispositionCallback callback,
      cc::ElementId hit_tests_result);

  // Handles creating synthetic gesture events. It is currently used for
  // creating gesture event equivalents for mouse events on a composited
  // scrollbar. `original_metrics` contains metrics for the original mouse event
  // and is used to generated metrics for the new gesture event.
  void InjectScrollbarGestureScroll(
      const blink::WebInputEvent::Type type,
      const gfx::PointF& position_in_widget,
      const cc::InputHandlerPointerResult& pointer_result,
      const ui::LatencyInfo& latency_info,
      const base::TimeTicks now,
      const cc::EventMetrics* original_metrics);

  // Attempts to perform attribution of the given WebInputEvent to a target
  // frame. Intended for simple impl-side hit testing.
  blink::WebInputEventAttribution PerformEventAttribution(
      const blink::WebInputEvent& event);

  // SynchronousInputHandler needs to be informed of root layer updates.
  void SetSynchronousInputHandler(
      SynchronousInputHandler* synchronous_input_handler);

  // Called when the synchronous input handler wants to change the root scroll
  // offset. Since it has the final say, this overrides values from compositor-
  // controlled behaviour. After the offset is applied, the
  // SynchronousInputHandler should be given back the result in case it differs
  // from what was sent.
  void SynchronouslySetRootScrollOffset(
      const gfx::PointF& root_offset);

  // Similar to SetRootScrollOffset above, to control the zoom level, ie scale
  // factor. Note |magnify_delta| is an incremental rather than absolute value.
  // SynchronousInputHandler should be given back the resulting absolute value.
  void SynchronouslyZoomBy(float magnify_delta,
                           const gfx::Point& anchor);

  // Defers posting BeginMainFrame tasks. This is used during the main thread
  // hit test for a GestureScrollBegin, to avoid posting a frame before the
  // compositor thread has had a chance to update the scroll offset.
  void SetDeferBeginMainFrame(bool defer_begin_main_frame) const;

  void RequestCallbackAfterEventQueueFlushed(base::OnceClosure callback);

  // cc::InputHandlerClient implementation.
  void WillShutdown() override;
  void Animate(base::TimeTicks time) override;
  void ReconcileElasticOverscrollAndRootScroll() override;
  void SetPrefersReducedMotion(bool prefers_reduced_motion) override;
  void UpdateRootLayerStateForSynchronousInputHandler(
      const gfx::PointF& total_scroll_offset,
      const gfx::PointF& max_scroll_offset,
      const gfx::SizeF& scrollable_size,
      float page_scale_factor,
      float min_page_scale_factor,
      float max_page_scale_factor) override;
  void DeliverInputForBeginFrame(const viz::BeginFrameArgs& args) override;
  void DeliverInputForHighLatencyMode() override;
  void DeliverInputForDeadline() override;
  void DidFinishImplFrame() override;
  bool HasQueuedInput() const override;
  void SetScrollEventDispatchMode(
      cc::InputHandlerClient::ScrollEventDispatchMode mode,
      double scroll_deadline_ratio) override;

  // SnapFlingClient implementation.
  bool GetSnapFlingInfoAndSetAnimatingSnapTarget(
      const gfx::Vector2dF& current_delta,
      const gfx::Vector2dF& natural_displacement,
      gfx::PointF* initial_offset,
      gfx::PointF* target_offset) const override;
  gfx::PointF ScrollByForSnapFling(const gfx::Vector2dF& delta) override;
  void ScrollEndForSnapFling(bool did_finish) override;
  void RequestAnimationForSnapFling() override;

  void UpdateBrowserControlsState(
      cc::BrowserControlsState constraints,
      cc::BrowserControlsState current,
      bool animate,
      base::optional_ref<const cc::BrowserControlsOffsetTagModifications>
          offset_tag_modifications);

  bool gesture_scroll_on_impl_thread_for_testing() const {
    return handling_gesture_on_impl_thread_;
  }

  blink::WebGestureDevice currently_active_gesture_device() const {
    return currently_active_gesture_device_.value();
  }

  // Immediately dispatches all queued events.
  void FlushQueuedEventsForTesting();

 private:
  friend class test::TestInputHandlerProxy;
  friend class test::InputHandlerProxyTest;
  friend class test::UnifiedScrollingInputHandlerProxyTest;
  friend class test::InputHandlerProxyEventQueueTest;
  friend class test::InputHandlerProxyMomentumScrollJankTest;
  friend class test::InputHandlerProxyForceHandlingOnMainThread;

  void DispatchSingleInputEvent(std::unique_ptr<EventWithCallback>);
  void DispatchQueuedInputEvents(bool frame_aligned);
  void UpdateElasticOverscroll();

  // Helper functions for handling more complicated input events.
  EventDisposition HandleMouseWheel(const blink::WebMouseWheelEvent& event);
  EventDisposition HandleGestureScrollBegin(
      const blink::WebGestureEvent& event);
  EventDisposition HandleGestureScrollUpdate(
      const blink::WebGestureEvent& event,
      cc::EventMetrics* metrics,
      int64_t trace_id);
  EventDisposition HandleGestureScrollEnd(const blink::WebGestureEvent& event);
  EventDisposition HandleTouchStart(EventWithCallback* event_with_callback);
  EventDisposition HandleTouchMove(EventWithCallback* event_with_callback);
  EventDisposition HandleTouchEnd(EventWithCallback* event_with_callback);

  const cc::InputHandlerPointerResult HandlePointerDown(
      EventWithCallback* event_with_callback,
      const gfx::PointF& position);
  const cc::InputHandlerPointerResult HandlePointerMove(
      EventWithCallback* event_with_callback,
      const gfx::PointF& position,
      bool should_cancel_scrollbar_drag);
  const cc::InputHandlerPointerResult HandlePointerUp(
      EventWithCallback* event_with_callback,
      const gfx::PointF& position);

  void InputHandlerScrollEnd();

  // Request a frame of animation from the InputHandler or
  // SynchronousInputHandler. They can provide that by calling Animate().
  void RequestAnimation();

  // Used to send overscroll messages to the browser. It bundles the overscroll
  // params with with event ack.
  void HandleOverscroll(const gfx::PointF& causal_event_viewport_point,
                        const cc::InputHandlerScrollResult& scroll_result);

  // Update the elastic overscroll controller with |gesture_event|.
  void HandleScrollElasticityOverscroll(
      const blink::WebGestureEvent& gesture_event,
      const cc::InputHandlerScrollResult& scroll_result);

  // Overrides the internal clock for testing.
  // This doesn't take the ownership of the clock. |tick_clock| must outlive the
  // InputHandlerProxy instance.
  void SetTickClockForTesting(const base::TickClock* tick_clock);

  // |is_touching_scrolling_layer| indicates if one of the points that has
  // been touched hits a currently scrolling layer. |allowed_touch_action| is
  // the touch_action we are sure will be allowed for the given touch event.
  EventDisposition HitTestTouchEvent(const blink::WebTouchEvent& touch_event,
                                     bool* is_touching_scrolling_layer,
                                     cc::TouchAction* allowed_touch_action);

  EventDisposition RouteToTypeSpecificHandler(
      EventWithCallback* event_with_callback);

  void set_event_attribution_enabled(bool enabled) {
    event_attribution_enabled_ = enabled;
  }

  void RecordScrollBegin(blink::WebGestureDevice device,
                         uint32_t main_thread_hit_tested_reasons,
                         uint32_t main_thread_repaint_reasons,
                         bool raster_inducing = false);

  bool HasQueuedEventsReadyForDispatch(bool frame_aligned) const;

  // If `scroll_predictor_` can generate a new prediction, this will generate
  // a synthetic GestureScrollUpdate using previous input events. This will then
  // be dispatched. We only do this while scrolling and after main-thread hit
  // testing has completed.
  void GenerateAndDispatchSytheticScrollPrediction(
      const viz::BeginFrameArgs& args);

  raw_ptr<InputHandlerProxyClient> client_;

  // The input handler object is owned by the compositor delegate. The input
  // handler must call WillShutdown() on this class before it is deleted at
  // which point this pointer will be cleared.
  raw_ptr<cc::InputHandler> input_handler_;

  raw_ptr<SynchronousInputHandler> synchronous_input_handler_;

  // This should be true when a pinch is in progress. The sequence of events is
  // as follows: GSB GPB GSU GPU ... GPE GSE.
  bool handling_gesture_on_impl_thread_;

  bool gesture_pinch_in_progress_ = false;
  bool in_inertial_scrolling_ = false;
  bool scroll_sequence_ignored_;
  std::optional<EventDisposition> main_thread_touch_sequence_start_disposition_;

  // Used to animate rubber-band/bounce over-scroll effect.
  std::unique_ptr<ElasticOverscrollController> elastic_overscroll_controller_;

  // The merged result of the last touch event with previous touch events
  // within a single touch sequence. This value will get returned for
  // subsequent TouchMove events to allow passive events not to block
  // scrolling.
  std::optional<EventDisposition> touch_result_;

  // The result of the last mouse wheel event in a wheel phase sequence. This
  // value is used to determine whether the next wheel scroll is blocked on the
  // Main thread or not.
  std::optional<EventDisposition> mouse_wheel_result_;

  // Used to record overscroll notifications while an event is being
  // dispatched.  If the event causes overscroll, the overscroll metadata is
  // bundled in the event ack, saving an IPC.
  std::unique_ptr<DidOverscrollParams> current_overscroll_params_;

  std::unique_ptr<CompositorThreadEventQueue> compositor_event_queue_;

  // Set only when the compositor input handler is handling a gesture. Tells
  // which source device is currently performing a gesture based scroll.
  std::optional<blink::WebGestureDevice> currently_active_gesture_device_;
  // Set only when the compositor input handler is handling a gesture. Denotes
  // which modifiers were present on the `WebInputEvent` so they can be applied
  // in GenerateAndDispatchSytheticScrollPrediction.
  std::optional<int> currently_active_gesture_scroll_modifiers_;

  base::OnceClosure queue_flushed_callback_;

  // Tracks whether the first scroll update gesture event has been seen after a
  // scroll begin. This is set/reset when scroll gestures are processed in
  // HandleInputEventWithLatencyInfo and shouldn't be used outside the scope
  // of that method.
  bool has_seen_first_gesture_scroll_update_after_begin_;

  // Whether the last injected scroll gesture was a GestureScrollBegin. Used to
  // determine which GestureScrollUpdate is the first in a gesture sequence for
  // latency classification. This is separate from
  // |is_first_gesture_scroll_update_| and is used to determine which type of
  // latency component should be added for injected GestureScrollUpdates.
  bool last_injected_gesture_was_begin_;

  raw_ptr<const base::TickClock> tick_clock_;

  std::unique_ptr<cc::SnapFlingController> snap_fling_controller_;

  std::unique_ptr<ScrollPredictor> scroll_predictor_;

  // These flags are set for the SkipTouchEventFilter experiment. The
  // experiment either skips filtering discrete (touch start/end) events to the
  // main thread, or all events (touch start/end/move).
  bool skip_touch_filter_discrete_ = false;
  bool skip_touch_filter_all_ = false;

  // This is set when the input handler proxy has requested that the client
  // perform a hit test for a scroll begin on the main thread. During that
  // time, scroll updates need to be queued. The reply from the main thread
  // will come by calling ContinueScrollBeginAfterMainThreadHitTest where the
  // queue will be flushed and this bit cleared. Used only in scroll
  // unification.
  uint32_t scroll_begin_main_thread_hit_test_reasons_ =
      cc::MainThreadScrollingReason::kNotScrollingOnMain;

  // This bit can be used to disable event attribution in cases where the
  // hit test information is unnecessary (e.g. tests).
  bool event_attribution_enabled_ = true;

  // This tracks whether the user has set prefers reduced motion.
  bool prefers_reduced_motion_ = false;

  // Swipe to move cursor feature.
  std::unique_ptr<CursorControlHandler> cursor_control_handler_;

  // The most recent viz::BeginFrameArgs that was received in
  // DeliverInputForBeginFrame. Which will be the active frame for all
  // subsequent events arriving in HandleInputEventWithLatencyInfo. If frame
  // production stops this will be outdated.
  viz::BeginFrameArgs current_begin_frame_args_;

  // When true, scroll events arriving in HandleInputEventWithLatencyInfo
  // will be enqueued to be dispatched during the next
  // DeliverInputForBeginFrame. When false, the scroll events will be dispatched
  // immediately. This will occur if DeliverInputForBeginFrame was called while
  // scrolling, with an empty `compositor_event_queue_`, until frame production
  // has started, or completed.
  bool enqueue_scroll_events_ = true;

  // `cc::InputHandlerClient::ScrollEventDispatchMode::kEnqueueScrollEvents`:
  // Scroll events arriving in `HandleInputEventWithLatencyInfo` will be
  // enqueued to be dispatched during the next `DeliverInputForBeginFrame`.
  //
  // `cc::InputHandlerClient::ScrollEventDispatchMode::kDispatchScrollEventsImmediately`:
  // Scroll events arriving in HandleInputEventWithLatencyInfo will be
  // dispatched immediately, if `DeliverInputForBeginFrame` was called while
  // scrolling, with no input events in the queue. This will occur until frame
  // production has started, or completed.
  //
  // `cc::InputHandlerClient::ScrollEventDispatchMode::kUseScrollPredictorForEmptyQueue`:
  // If `compositor_event_queue_` is empty when `DeliverInputForBeginFrame` is
  // called, while we are scrolling. We will use `scroll_predictor_` to
  // generate a new prediction. We will then dispatch a synthetic
  // `GestureScrollUpdate` using the prediction.
  cc::InputHandlerClient::ScrollEventDispatchMode scroll_event_dispatch_mode_ =
      cc::InputHandlerClient::ScrollEventDispatchMode::kEnqueueScrollEvents;

  double scroll_deadline_ratio_ = 0.333;
};

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WIDGET_INPUT_INPUT_HANDLER_PROXY_H_