Flutter Engine
 
Loading...
Searching...
No Matches
direct_manipulation.cc
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
6
7#include <algorithm>
8
13
14#define RETURN_IF_FAILED(operation) \
15 if (FAILED(operation)) { \
16 FML_LOG(ERROR) << #operation << " failed"; \
17 manager_ = nullptr; \
18 updateManager_ = nullptr; \
19 viewport_ = nullptr; \
20 return -1; \
21 }
22
23#define WARN_IF_FAILED(operation) \
24 if (FAILED(operation)) { \
25 FML_LOG(ERROR) << #operation << " failed"; \
26 }
27
28namespace flutter {
29
30int32_t DirectManipulationEventHandler::GetDeviceId() {
31 return (int32_t)reinterpret_cast<int64_t>(this);
32}
33
35 void** ppv) {
36 if ((iid == IID_IUnknown) ||
37 (iid == IID_IDirectManipulationViewportEventHandler)) {
38 *ppv = static_cast<IDirectManipulationViewportEventHandler*>(this);
39 AddRef();
40 return S_OK;
41 } else if (iid == IID_IDirectManipulationInteractionEventHandler) {
42 *ppv = static_cast<IDirectManipulationInteractionEventHandler*>(this);
43 AddRef();
44 return S_OK;
45 }
46 return E_NOINTERFACE;
47}
48
49DirectManipulationEventHandler::GestureData
50DirectManipulationEventHandler::ConvertToGestureData(float transform[6]) {
51 // DirectManipulation provides updates with very high precision. If the user
52 // holds their fingers steady on a trackpad, DirectManipulation sends
53 // jittery updates. This calculation will reduce the precision of the scale
54 // value of the event to avoid jitter.
55 const int mantissa_bits_chop = 2;
56 const float factor = (1 << mantissa_bits_chop) + 1;
57 float c = factor * transform[0];
58 return GestureData{
59 c - (c - transform[0]), // scale
60 transform[4], // pan_x
61 transform[5], // pan_y
62 };
63}
64
66 IDirectManipulationViewport* viewport,
67 DIRECTMANIPULATION_STATUS current,
68 DIRECTMANIPULATION_STATUS previous) {
69 if (during_synthesized_reset_) {
70 during_synthesized_reset_ = current != DIRECTMANIPULATION_READY;
71 return S_OK;
72 }
73 during_inertia_ = current == DIRECTMANIPULATION_INERTIA;
74 if (current == DIRECTMANIPULATION_RUNNING) {
75 IDirectManipulationContent* content;
76 HRESULT hr = viewport->GetPrimaryContent(IID_PPV_ARGS(&content));
77 if (SUCCEEDED(hr)) {
78 float transform[6];
79 hr = content->GetContentTransform(transform, ARRAYSIZE(transform));
80 if (SUCCEEDED(hr)) {
81 initial_gesture_data_ = ConvertToGestureData(transform);
82 } else {
83 FML_LOG(ERROR) << "GetContentTransform failed";
84 }
85 } else {
86 FML_LOG(ERROR) << "GetPrimaryContent failed";
87 }
88 if (owner_->binding_handler_delegate) {
89 owner_->binding_handler_delegate->OnPointerPanZoomStart(GetDeviceId());
90 }
91 } else if (previous == DIRECTMANIPULATION_RUNNING) {
92 // Reset deltas to ensure only inertia values will be compared later.
93 last_pan_delta_x_ = 0.0;
94 last_pan_delta_y_ = 0.0;
95 if (owner_->binding_handler_delegate) {
96 owner_->binding_handler_delegate->OnPointerPanZoomEnd(GetDeviceId());
97 }
98 } else if (previous == DIRECTMANIPULATION_INERTIA) {
99 if (owner_->binding_handler_delegate &&
100 (std::max)(std::abs(last_pan_delta_x_), std::abs(last_pan_delta_y_)) >
101 0.01) {
102 owner_->binding_handler_delegate->OnScrollInertiaCancel(GetDeviceId());
103 }
104 // Need to reset the content transform to its original position
105 // so that we are ready for the next gesture.
106 // Use during_synthesized_reset_ flag to prevent sending reset also to the
107 // framework.
108 during_synthesized_reset_ = true;
109 last_pan_x_ = 0.0;
110 last_pan_y_ = 0.0;
111 last_pan_delta_x_ = 0.0;
112 last_pan_delta_y_ = 0.0;
113 RECT rect;
114 HRESULT hr = viewport->GetViewportRect(&rect);
115 if (FAILED(hr)) {
116 FML_LOG(ERROR) << "Failed to get the current viewport rect";
117 return E_FAIL;
118 }
119 hr = viewport->ZoomToRect(rect.left, rect.top, rect.right, rect.bottom,
120 false);
121 if (FAILED(hr)) {
122 FML_LOG(ERROR) << "Failed to reset the gesture using ZoomToRect";
123 return E_FAIL;
124 }
125 }
126 return S_OK;
127}
128
130 IDirectManipulationViewport* viewport) {
131 return S_OK;
132}
133
135 IDirectManipulationViewport* viewport,
136 IDirectManipulationContent* content) {
137 float transform[6];
138 HRESULT hr = content->GetContentTransform(transform, ARRAYSIZE(transform));
139 if (FAILED(hr)) {
140 FML_LOG(ERROR) << "GetContentTransform failed";
141 return S_OK;
142 }
143 if (!during_synthesized_reset_) {
144 GestureData data = ConvertToGestureData(transform);
145 float scale = data.scale / initial_gesture_data_.scale;
146 float pan_x = data.pan_x - initial_gesture_data_.pan_x;
147 float pan_y = data.pan_y - initial_gesture_data_.pan_y;
148 last_pan_delta_x_ = pan_x - last_pan_x_;
149 last_pan_delta_y_ = pan_y - last_pan_y_;
150 last_pan_x_ = pan_x;
151 last_pan_y_ = pan_y;
152 if (owner_->binding_handler_delegate && !during_inertia_) {
154 GetDeviceId(), pan_x, pan_y, scale, 0);
155 }
156 }
157 return S_OK;
158}
159
161 IDirectManipulationViewport2* viewport,
162 DIRECTMANIPULATION_INTERACTION_TYPE interaction) {
163 return S_OK;
164}
165
167 RefCountedThreadSafe::AddRef();
168 return 0;
169}
170
172 RefCountedThreadSafe::Release();
173 return 0;
174}
175
178
179int DirectManipulationOwner::Init(unsigned int width, unsigned int height) {
180 RETURN_IF_FAILED(CoCreateInstance(CLSID_DirectManipulationManager, nullptr,
181 CLSCTX_INPROC_SERVER,
182 IID_IDirectManipulationManager, &manager_));
183 RETURN_IF_FAILED(manager_->GetUpdateManager(
184 IID_IDirectManipulationUpdateManager, &updateManager_));
185 RETURN_IF_FAILED(manager_->CreateViewport(nullptr, window_->GetWindowHandle(),
186 IID_IDirectManipulationViewport,
187 &viewport_));
188 DIRECTMANIPULATION_CONFIGURATION configuration =
189 DIRECTMANIPULATION_CONFIGURATION_INTERACTION |
190 DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X |
191 DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_Y |
192 DIRECTMANIPULATION_CONFIGURATION_SCALING |
193 DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_INERTIA;
194 RETURN_IF_FAILED(viewport_->ActivateConfiguration(configuration));
195 RETURN_IF_FAILED(viewport_->SetViewportOptions(
196 DIRECTMANIPULATION_VIEWPORT_OPTIONS_MANUALUPDATE));
197 handler_ = fml::MakeRefCounted<DirectManipulationEventHandler>(this);
198 RETURN_IF_FAILED(viewport_->AddEventHandler(
199 window_->GetWindowHandle(), handler_.get(), &viewportHandlerCookie_));
200 RECT rect = {0, 0, (LONG)width, (LONG)height};
201 RETURN_IF_FAILED(viewport_->SetViewportRect(&rect));
202 RETURN_IF_FAILED(manager_->Activate(window_->GetWindowHandle()));
203 RETURN_IF_FAILED(viewport_->Enable());
204 RETURN_IF_FAILED(updateManager_->Update(nullptr));
205 return 0;
206}
207
209 unsigned int height) {
210 if (viewport_) {
211 RECT rect = {0, 0, (LONG)width, (LONG)height};
212 WARN_IF_FAILED(viewport_->SetViewportRect(&rect));
213 }
214}
215
217 if (handler_) {
218 handler_->owner_ = nullptr;
219 }
220
221 if (viewport_) {
222 WARN_IF_FAILED(viewport_->Disable());
223 WARN_IF_FAILED(viewport_->Disable());
224 WARN_IF_FAILED(viewport_->RemoveEventHandler(viewportHandlerCookie_));
225 WARN_IF_FAILED(viewport_->Abandon());
226 }
227
228 if (window_ && manager_) {
229 WARN_IF_FAILED(manager_->Deactivate(window_->GetWindowHandle()));
230 }
231
232 handler_ = nullptr;
233 viewport_ = nullptr;
234 updateManager_ = nullptr;
235 manager_ = nullptr;
236 window_ = nullptr;
237}
238
240 if (viewport_) {
241 viewport_->SetContact(contactId);
242 }
243}
244
249
251 if (updateManager_) {
252 HRESULT hr = updateManager_->Update(nullptr);
253 if (FAILED(hr)) {
254 FML_LOG(ERROR) << "updateManager_->Update failed";
255 auto error = GetLastError();
256 FML_LOG(ERROR) << error;
257 LPWSTR message = nullptr;
258 size_t size = FormatMessageW(
259 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
260 FORMAT_MESSAGE_IGNORE_INSERTS,
261 NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
262 reinterpret_cast<LPWSTR>(&message), 0, NULL);
264 }
265 }
266}
267
268} // namespace flutter
ULONG STDMETHODCALLTYPE Release() override
HRESULT STDMETHODCALLTYPE OnViewportUpdated(IDirectManipulationViewport *viewport) override
STDMETHODIMP QueryInterface(REFIID iid, void **ppv) override
HRESULT STDMETHODCALLTYPE OnInteraction(IDirectManipulationViewport2 *viewport, DIRECTMANIPULATION_INTERACTION_TYPE interaction) override
ULONG STDMETHODCALLTYPE AddRef() override
HRESULT STDMETHODCALLTYPE OnViewportStatusChanged(IDirectManipulationViewport *viewport, DIRECTMANIPULATION_STATUS current, DIRECTMANIPULATION_STATUS previous) override
HRESULT STDMETHODCALLTYPE OnContentUpdated(IDirectManipulationViewport *viewport, IDirectManipulationContent *content) override
virtual void SetContact(UINT contactId)
void SetBindingHandlerDelegate(WindowBindingHandlerDelegate *binding_handler_delegate)
WindowBindingHandlerDelegate * binding_handler_delegate
int Init(unsigned int width, unsigned int height)
void ResizeViewport(unsigned int width, unsigned int height)
DirectManipulationOwner(FlutterWindow *window)
virtual HWND GetWindowHandle() override
virtual void OnPointerPanZoomStart(int32_t device_id)=0
virtual void OnPointerPanZoomEnd(int32_t device_id)=0
virtual void OnScrollInertiaCancel(int32_t device_id)=0
virtual void OnPointerPanZoomUpdate(int32_t device_id, double pan_x, double pan_y, double scale, double rotation)=0
#define WARN_IF_FAILED(operation)
#define RETURN_IF_FAILED(operation)
GLFWwindow * window
Definition main.cc:60
G_BEGIN_DECLS GBytes * message
const uint8_t uint32_t uint32_t GError ** error
#define FML_LOG(severity)
Definition logging.h:101
union flutter::testing::@2824::KeyboardChange::@78 content
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
std::string WCharBufferToString(const wchar_t *wstr)
Convert a null terminated wchar_t buffer to a std::string using Windows utilities.
Definition wchar_util.cc:11
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
int32_t height
int32_t width
#define SUCCEEDED(hr)
long LONG
unsigned int UINT
WINBASEAPI _Check_return_ _Post_equals_last_error_ DWORD WINAPI GetLastError(VOID)
DWORD ULONG
#define FAILED(hr)