Flutter Engine
The Flutter Engine
pointer_data_dispatcher.h
Go to the documentation of this file.
1// Copyright 2013 The Flutter 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#ifndef FLUTTER_SHELL_COMMON_POINTER_DATA_DISPATCHER_H_
6#define FLUTTER_SHELL_COMMON_POINTER_DATA_DISPATCHER_H_
7
8#include "flutter/runtime/runtime_controller.h"
9#include "flutter/shell/common/animator.h"
10
11namespace flutter {
12
13class PointerDataDispatcher;
14
15//------------------------------------------------------------------------------
16/// The `Engine` pointer data dispatcher that forwards the packet received from
17/// `PlatformView::DispatchPointerDataPacket` on the platform thread, to
18/// `Window::DispatchPointerDataPacket` on the UI thread.
19///
20/// This class is used to filter the packets so the Flutter framework on the UI
21/// thread will receive packets with some desired properties. See
22/// `SmoothPointerDataDispatcher` for an example which filters irregularly
23/// delivered packets, and dispatches them in sync with the VSYNC signal.
24///
25/// This object will be owned by the engine because it relies on the engine's
26/// `Animator` (which owns `VsyncWaiter`) and `RuntimeController` to do the
27/// filtering. This object is currently designed to be only called from the UI
28/// thread (no thread safety is guaranteed).
29///
30/// The `PlatformView` decides which subclass of `PointerDataDispatcher` is
31/// constructed by sending a `PointerDataDispatcherMaker` to the engine's
32/// constructor in `Shell::CreateShellOnPlatformThread`. This is needed because:
33/// (1) Different platforms (e.g., Android, iOS) have different dispatchers
34/// so the decision has to be made per `PlatformView`.
35/// (2) The `PlatformView` can only be accessed from the PlatformThread while
36/// this class (as owned by engine) can only be accessed in the UI thread.
37/// Hence `PlatformView` creates a `PointerDataDispatchMaker` on the
38/// platform thread, and sends it to the UI thread for the final
39/// construction of the `PointerDataDispatcher`.
41 public:
42 /// The interface for Engine to implement.
43 class Delegate {
44 public:
45 /// Actually dispatch the packet using Engine's `animator_` and
46 /// `runtime_controller_`.
47 virtual void DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
48 uint64_t trace_flow_id) = 0;
49
50 //--------------------------------------------------------------------------
51 /// @brief Schedule a secondary callback to be executed right after the
52 /// main `VsyncWaiter::AsyncWaitForVsync` callback (which is added
53 /// by `Animator::RequestFrame`).
54 ///
55 /// Like the callback in `AsyncWaitForVsync`, this callback is
56 /// only scheduled to be called once per |id|, and it will be
57 /// called in the UI thread. If there is no AsyncWaitForVsync
58 /// callback (`Animator::RequestFrame` is not called), this
59 /// secondary callback will still be executed at vsync.
60 ///
61 /// This callback is used to provide the vsync signal needed by
62 /// `SmoothPointerDataDispatcher`, and for `Animator` input flow
63 /// events.
65 uintptr_t id,
66 const fml::closure& callback) = 0;
67 };
68
69 //----------------------------------------------------------------------------
70 /// @brief Signal that `PlatformView` has a packet to be dispatched.
71 ///
72 /// @param[in] packet The `PointerDataPacket` to be dispatched.
73 /// @param[in] trace_flow_id The id for `Animator::EnqueueTraceFlowId`.
74 virtual void DispatchPacket(std::unique_ptr<PointerDataPacket> packet,
75 uint64_t trace_flow_id) = 0;
76
77 //----------------------------------------------------------------------------
78 /// @brief Default destructor.
80};
81
82//------------------------------------------------------------------------------
83/// The default dispatcher that forwards the packet without any modification.
84///
86 public:
88 : delegate_(delegate) {}
89
90 // |PointerDataDispatcer|
91 void DispatchPacket(std::unique_ptr<PointerDataPacket> packet,
92 uint64_t trace_flow_id) override;
93
95
96 protected:
98
100};
101
102//------------------------------------------------------------------------------
103/// A dispatcher that may temporarily store and defer the last received
104/// PointerDataPacket if multiple packets are received in one VSYNC. The
105/// deferred packet will be sent in the next vsync in order to smooth out the
106/// events. This filters out irregular input events delivery to provide a smooth
107/// scroll on iPhone X/Xs.
108///
109/// It works as follows:
110///
111/// When `DispatchPacket` is called while a previous pointer data dispatch is
112/// still in progress (its frame isn't finished yet), it means that an input
113/// event is delivered to us too fast. That potentially means a later event will
114/// be too late which could cause the missing of a frame. Hence we'll cache it
115/// in `pending_packet_` for the next frame to smooth it out.
116///
117/// If the input event is sent to us regularly at the same rate of VSYNC (say
118/// at 60Hz), this would be identical to `DefaultPointerDataDispatcher` where
119/// `runtime_controller_->DispatchPointerDataPacket` is always called right
120/// away. That's because `is_pointer_data_in_progress_` will always be false
121/// when `DispatchPacket` is called since it will be cleared by the end of a
122/// frame through `ScheduleSecondaryVsyncCallback`. This is the case for all
123/// Android/iOS devices before iPhone X/XS.
124///
125/// If the input event is irregular, but with a random latency of no more than
126/// one frame, this would guarantee that we'll miss at most 1 frame. Without
127/// this, we could miss half of the frames.
128///
129/// If the input event is delivered at a higher rate than that of VSYNC, this
130/// would at most add a latency of one event delivery. For example, if the
131/// input event is delivered at 120Hz (this is only true for iPad pro, not even
132/// iPhone X), this may delay the handling of an input event by 8ms.
133///
134/// The assumption of this solution is that the sampling itself is still
135/// regular. Only the event delivery is allowed to be irregular. So far this
136/// assumption seems to hold on all devices. If it's changed in the future,
137/// we'll need a different solution.
138///
139/// See also input_events_unittests.cc where we test all our claims above.
141 public:
142 explicit SmoothPointerDataDispatcher(Delegate& delegate);
143
144 // |PointerDataDispatcer|
145 void DispatchPacket(std::unique_ptr<PointerDataPacket> packet,
146 uint64_t trace_flow_id) override;
147
149
150 private:
151 void DispatchPendingPacket();
152 void ScheduleSecondaryVsyncCallback();
153
154 // If non-null, this will be a pending pointer data packet for the next frame
155 // to consume. This is used to smooth out the irregular drag events delivery.
156 // See also `DispatchPointerDataPacket` and input_events_unittests.cc.
157 std::unique_ptr<PointerDataPacket> pending_packet_;
158 int pending_trace_flow_id_ = -1;
159 bool is_pointer_data_in_progress_ = false;
160
161 // WeakPtrFactory must be the last member.
163 FML_DISALLOW_COPY_AND_ASSIGN(SmoothPointerDataDispatcher);
164};
165
166//--------------------------------------------------------------------------
167/// @brief Signature for constructing PointerDataDispatcher.
168///
169/// @param[in] delegate the `Flutter::Engine`
170///
172 std::function<std::unique_ptr<PointerDataDispatcher>(
174
175} // namespace flutter
176
177#endif // FLUTTER_SHELL_COMMON_POINTER_DATA_DISPATCHER_H_
FML_DISALLOW_COPY_AND_ASSIGN(DefaultPointerDataDispatcher)
void DispatchPacket(std::unique_ptr< PointerDataPacket > packet, uint64_t trace_flow_id) override
Signal that PlatformView has a packet to be dispatched.
The interface for Engine to implement.
virtual void DoDispatchPacket(std::unique_ptr< PointerDataPacket > packet, uint64_t trace_flow_id)=0
virtual void ScheduleSecondaryVsyncCallback(uintptr_t id, const fml::closure &callback)=0
Schedule a secondary callback to be executed right after the main VsyncWaiter::AsyncWaitForVsync call...
virtual void DispatchPacket(std::unique_ptr< PointerDataPacket > packet, uint64_t trace_flow_id)=0
Signal that PlatformView has a packet to be dispatched.
virtual ~PointerDataDispatcher()
Default destructor.
void DispatchPacket(std::unique_ptr< PointerDataPacket > packet, uint64_t trace_flow_id) override
Signal that PlatformView has a packet to be dispatched.
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
std::function< std::unique_ptr< PointerDataDispatcher >(PointerDataDispatcher::Delegate &)> PointerDataDispatcherMaker
Signature for constructing PointerDataDispatcher.
std::function< void()> closure
Definition: closure.h:14