Flutter Engine
The Flutter Engine
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
5#include "flutter/fml/logging.h"
6
7#include <algorithm>
8
9#include "flutter/shell/platform/windows/direct_manipulation.h"
10#include "flutter/shell/platform/windows/flutter_window.h"
11#include "flutter/shell/platform/windows/window_binding_handler_delegate.h"
12
13#define RETURN_IF_FAILED(operation) \
14 if (FAILED(operation)) { \
15 FML_LOG(ERROR) << #operation << " failed"; \
16 manager_ = nullptr; \
17 updateManager_ = nullptr; \
18 viewport_ = nullptr; \
19 return -1; \
20 }
21
22#define WARN_IF_FAILED(operation) \
23 if (FAILED(operation)) { \
24 FML_LOG(ERROR) << #operation << " failed"; \
25 }
26
27namespace flutter {
28
29int32_t DirectManipulationEventHandler::GetDeviceId() {
30 return (int32_t) reinterpret_cast<int64_t>(this);
31}
32
34 void** ppv) {
35 if ((iid == IID_IUnknown) ||
36 (iid == IID_IDirectManipulationViewportEventHandler)) {
37 *ppv = static_cast<IDirectManipulationViewportEventHandler*>(this);
38 AddRef();
39 return S_OK;
40 } else if (iid == IID_IDirectManipulationInteractionEventHandler) {
41 *ppv = static_cast<IDirectManipulationInteractionEventHandler*>(this);
42 AddRef();
43 return S_OK;
44 }
45 return E_NOINTERFACE;
46}
47
48DirectManipulationEventHandler::GestureData
49DirectManipulationEventHandler::ConvertToGestureData(float transform[6]) {
50 // DirectManipulation provides updates with very high precision. If the user
51 // holds their fingers steady on a trackpad, DirectManipulation sends
52 // jittery updates. This calculation will reduce the precision of the scale
53 // value of the event to avoid jitter.
54 const int mantissa_bits_chop = 2;
55 const float factor = (1 << mantissa_bits_chop) + 1;
56 float c = factor * transform[0];
57 return GestureData{
58 c - (c - transform[0]), // scale
59 transform[4], // pan_x
60 transform[5], // pan_y
61 };
62}
63
65 IDirectManipulationViewport* viewport,
66 DIRECTMANIPULATION_STATUS current,
67 DIRECTMANIPULATION_STATUS previous) {
68 if (during_synthesized_reset_) {
69 during_synthesized_reset_ = current != DIRECTMANIPULATION_READY;
70 return S_OK;
71 }
72 during_inertia_ = current == DIRECTMANIPULATION_INERTIA;
73 if (current == DIRECTMANIPULATION_RUNNING) {
74 IDirectManipulationContent* content;
75 HRESULT hr = viewport->GetPrimaryContent(IID_PPV_ARGS(&content));
76 if (SUCCEEDED(hr)) {
77 float transform[6];
78 hr = content->GetContentTransform(transform, ARRAYSIZE(transform));
79 if (SUCCEEDED(hr)) {
80 initial_gesture_data_ = ConvertToGestureData(transform);
81 } else {
82 FML_LOG(ERROR) << "GetContentTransform failed";
83 }
84 } else {
85 FML_LOG(ERROR) << "GetPrimaryContent failed";
86 }
87 if (owner_->binding_handler_delegate) {
88 owner_->binding_handler_delegate->OnPointerPanZoomStart(GetDeviceId());
89 }
90 } else if (previous == DIRECTMANIPULATION_RUNNING) {
91 // Reset deltas to ensure only inertia values will be compared later.
92 last_pan_delta_x_ = 0.0;
93 last_pan_delta_y_ = 0.0;
94 if (owner_->binding_handler_delegate) {
95 owner_->binding_handler_delegate->OnPointerPanZoomEnd(GetDeviceId());
96 }
97 } else if (previous == DIRECTMANIPULATION_INERTIA) {
98 if (owner_->binding_handler_delegate &&
99 (std::max)(std::abs(last_pan_delta_x_), std::abs(last_pan_delta_y_)) >
100 0.01) {
101 owner_->binding_handler_delegate->OnScrollInertiaCancel(GetDeviceId());
102 }
103 // Need to reset the content transform to its original position
104 // so that we are ready for the next gesture.
105 // Use during_synthesized_reset_ flag to prevent sending reset also to the
106 // framework.
107 during_synthesized_reset_ = true;
108 last_pan_x_ = 0.0;
109 last_pan_y_ = 0.0;
110 last_pan_delta_x_ = 0.0;
111 last_pan_delta_y_ = 0.0;
112 RECT rect;
113 HRESULT hr = viewport->GetViewportRect(&rect);
114 if (FAILED(hr)) {
115 FML_LOG(ERROR) << "Failed to get the current viewport rect";
116 return E_FAIL;
117 }
118 hr = viewport->ZoomToRect(rect.left, rect.top, rect.right, rect.bottom,
119 false);
120 if (FAILED(hr)) {
121 FML_LOG(ERROR) << "Failed to reset the gesture using ZoomToRect";
122 return E_FAIL;
123 }
124 }
125 return S_OK;
126}
127
129 IDirectManipulationViewport* viewport) {
130 return S_OK;
131}
132
134 IDirectManipulationViewport* viewport,
135 IDirectManipulationContent* content) {
136 float transform[6];
137 HRESULT hr = content->GetContentTransform(transform, ARRAYSIZE(transform));
138 if (FAILED(hr)) {
139 FML_LOG(ERROR) << "GetContentTransform failed";
140 return S_OK;
141 }
142 if (!during_synthesized_reset_) {
143 GestureData data = ConvertToGestureData(transform);
144 float scale = data.scale / initial_gesture_data_.scale;
145 float pan_x = data.pan_x - initial_gesture_data_.pan_x;
146 float pan_y = data.pan_y - initial_gesture_data_.pan_y;
147 last_pan_delta_x_ = pan_x - last_pan_x_;
148 last_pan_delta_y_ = pan_y - last_pan_y_;
149 last_pan_x_ = pan_x;
150 last_pan_y_ = pan_y;
151 if (owner_->binding_handler_delegate && !during_inertia_) {
153 GetDeviceId(), pan_x, pan_y, scale, 0);
154 }
155 }
156 return S_OK;
157}
158
160 IDirectManipulationViewport2* viewport,
161 DIRECTMANIPULATION_INTERACTION_TYPE interaction) {
162 return S_OK;
163}
164
166 RefCountedThreadSafe::AddRef();
167 return 0;
168}
169
171 RefCountedThreadSafe::Release();
172 return 0;
173}
174
176 : window_(window) {}
177
178int DirectManipulationOwner::Init(unsigned int width, unsigned int height) {
179 RETURN_IF_FAILED(CoCreateInstance(CLSID_DirectManipulationManager, nullptr,
180 CLSCTX_INPROC_SERVER,
181 IID_IDirectManipulationManager, &manager_));
182 RETURN_IF_FAILED(manager_->GetUpdateManager(
183 IID_IDirectManipulationUpdateManager, &updateManager_));
184 RETURN_IF_FAILED(manager_->CreateViewport(nullptr, window_->GetWindowHandle(),
185 IID_IDirectManipulationViewport,
186 &viewport_));
187 DIRECTMANIPULATION_CONFIGURATION configuration =
188 DIRECTMANIPULATION_CONFIGURATION_INTERACTION |
189 DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X |
190 DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_Y |
191 DIRECTMANIPULATION_CONFIGURATION_SCALING |
192 DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_INERTIA;
193 RETURN_IF_FAILED(viewport_->ActivateConfiguration(configuration));
194 RETURN_IF_FAILED(viewport_->SetViewportOptions(
195 DIRECTMANIPULATION_VIEWPORT_OPTIONS_MANUALUPDATE));
196 handler_ = fml::MakeRefCounted<DirectManipulationEventHandler>(this);
197 RETURN_IF_FAILED(viewport_->AddEventHandler(
198 window_->GetWindowHandle(), handler_.get(), &viewportHandlerCookie_));
199 RECT rect = {0, 0, (LONG)width, (LONG)height};
200 RETURN_IF_FAILED(viewport_->SetViewportRect(&rect));
201 RETURN_IF_FAILED(manager_->Activate(window_->GetWindowHandle()));
202 RETURN_IF_FAILED(viewport_->Enable());
203 RETURN_IF_FAILED(updateManager_->Update(nullptr));
204 return 0;
205}
206
208 unsigned int height) {
209 if (viewport_) {
210 RECT rect = {0, 0, (LONG)width, (LONG)height};
211 WARN_IF_FAILED(viewport_->SetViewportRect(&rect));
212 }
213}
214
216 if (handler_) {
217 handler_->owner_ = nullptr;
218 }
219
220 if (viewport_) {
221 WARN_IF_FAILED(viewport_->Disable());
222 WARN_IF_FAILED(viewport_->Disable());
223 WARN_IF_FAILED(viewport_->RemoveEventHandler(viewportHandlerCookie_));
224 WARN_IF_FAILED(viewport_->Abandon());
225 }
226
227 if (window_ && manager_) {
228 WARN_IF_FAILED(manager_->Deactivate(window_->GetWindowHandle()));
229 }
230
231 handler_ = nullptr;
232 viewport_ = nullptr;
233 updateManager_ = nullptr;
234 manager_ = nullptr;
235 window_ = nullptr;
236}
237
239 if (viewport_) {
240 viewport_->SetContact(contactId);
241 }
242}
243
246 binding_handler_delegate = delegate;
247}
248
250 if (updateManager_) {
251 HRESULT hr = updateManager_->Update(nullptr);
252 if (FAILED(hr)) {
253 FML_LOG(ERROR) << "updateManager_->Update failed";
254 auto error = GetLastError();
255 FML_LOG(ERROR) << error;
256 LPWSTR message = nullptr;
257 size_t size = FormatMessageW(
258 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
259 FORMAT_MESSAGE_IGNORE_INSERTS,
260 NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
261 reinterpret_cast<LPWSTR>(&message), 0, NULL);
263 }
264 }
265}
266
267} // 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:45
const uint8_t uint32_t uint32_t GError ** error
#define FML_LOG(severity)
Definition: logging.h:82
static float max(float r, float g, float b)
Definition: hsl.cpp:49
union flutter::testing::@2836::KeyboardChange::@76 content
Win32Message message
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
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: switches.h:41
it will be possible to load the file into Perfetto s trace viewer 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
Definition: switches.h:259
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition: SkVx.h:707
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition: p3.cpp:47
int32_t height
int32_t width
const Scalar scale
#define ERROR(message)
Definition: elf_loader.cc:260
#define SUCCEEDED(hr)
long LONG
Definition: windows_types.h:23
unsigned int UINT
Definition: windows_types.h:32
WINBASEAPI _Check_return_ _Post_equals_last_error_ DWORD WINAPI GetLastError(VOID)
DWORD ULONG
Definition: windows_types.h:40
#define FAILED(hr)