| Flutter Windows Embedder |

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/wchar_util.h"
12 #include "flutter/shell/platform/windows/window_binding_handler_delegate.h"
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
28 namespace flutter {
29
30 int32_t DirectManipulationEventHandler::GetDeviceId() {
31 return (int32_t)reinterpret_cast<int64_t>(this);
32 }
33
34 STDMETHODIMP DirectManipulationEventHandler::QueryInterface(REFIID iid,
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
49 DirectManipulationEventHandler::GestureData
50 DirectManipulationEventHandler::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
65 HRESULT DirectManipulationEventHandler::OnViewportStatusChanged(
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
129 HRESULT DirectManipulationEventHandler::OnViewportUpdated(
130 IDirectManipulationViewport* viewport) {
131 return S_OK;
132 }
133
134 HRESULT DirectManipulationEventHandler::OnContentUpdated(
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_) {
153 owner_->binding_handler_delegate->OnPointerPanZoomUpdate(
154 GetDeviceId(), pan_x, pan_y, scale, 0);
155 }
156 }
157 return S_OK;
158 }
159
160 HRESULT DirectManipulationEventHandler::OnInteraction(
161 IDirectManipulationViewport2* viewport,
162 DIRECTMANIPULATION_INTERACTION_TYPE interaction) {
163 return S_OK;
164 }
165
166 ULONG STDMETHODCALLTYPE DirectManipulationEventHandler::AddRef() {
167 RefCountedThreadSafe::AddRef();
168 return 0;
169 }
170
171 ULONG STDMETHODCALLTYPE DirectManipulationEventHandler::Release() {
172 RefCountedThreadSafe::Release();
173 return 0;
174 }
175
176 DirectManipulationOwner::DirectManipulationOwner(FlutterWindow* window)
177 : window_(window) {}
178
179 int 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
208 void DirectManipulationOwner::ResizeViewport(unsigned int width,
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
216 void DirectManipulationOwner::Destroy() {
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
239 void DirectManipulationOwner::SetContact(UINT contactId) {
240 if (viewport_) {
241 viewport_->SetContact(contactId);
242 }
243 }
244
245 void DirectManipulationOwner::SetBindingHandlerDelegate(
246 WindowBindingHandlerDelegate* delegate) {
247 binding_handler_delegate = delegate;
248 }
249
250 void DirectManipulationOwner::Update() {
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);
263 FML_LOG(ERROR) << WCharBufferToString(message);
264 }
265 }
266 }
267
268 } // namespace flutter
flutter::DirectManipulationEventHandler::Release
ULONG STDMETHODCALLTYPE Release() override
Definition: direct_manipulation.cc:171
flutter::DirectManipulationEventHandler::OnViewportUpdated
HRESULT STDMETHODCALLTYPE OnViewportUpdated(IDirectManipulationViewport *viewport) override
Definition: direct_manipulation.cc:129
flutter::DirectManipulationEventHandler::QueryInterface
STDMETHODIMP QueryInterface(REFIID iid, void **ppv) override
Definition: direct_manipulation.cc:34
flutter::DirectManipulationEventHandler::OnInteraction
HRESULT STDMETHODCALLTYPE OnInteraction(IDirectManipulationViewport2 *viewport, DIRECTMANIPULATION_INTERACTION_TYPE interaction) override
Definition: direct_manipulation.cc:160
flutter::DirectManipulationEventHandler::AddRef
ULONG STDMETHODCALLTYPE AddRef() override
Definition: direct_manipulation.cc:166
flutter::DirectManipulationEventHandler::OnViewportStatusChanged
HRESULT STDMETHODCALLTYPE OnViewportStatusChanged(IDirectManipulationViewport *viewport, DIRECTMANIPULATION_STATUS current, DIRECTMANIPULATION_STATUS previous) override
Definition: direct_manipulation.cc:65
flutter::DirectManipulationEventHandler::OnContentUpdated
HRESULT STDMETHODCALLTYPE OnContentUpdated(IDirectManipulationViewport *viewport, IDirectManipulationContent *content) override
Definition: direct_manipulation.cc:134
flutter::DirectManipulationOwner::SetContact
virtual void SetContact(UINT contactId)
Definition: direct_manipulation.cc:239
flutter::DirectManipulationOwner::SetBindingHandlerDelegate
void SetBindingHandlerDelegate(WindowBindingHandlerDelegate *binding_handler_delegate)
Definition: direct_manipulation.cc:245
flutter::DirectManipulationOwner::binding_handler_delegate
WindowBindingHandlerDelegate * binding_handler_delegate
Definition: direct_manipulation.h:46
flutter::DirectManipulationOwner::Init
int Init(unsigned int width, unsigned int height)
Definition: direct_manipulation.cc:179
flutter::DirectManipulationOwner::ResizeViewport
void ResizeViewport(unsigned int width, unsigned int height)
Definition: direct_manipulation.cc:208
flutter::DirectManipulationOwner::Update
void Update()
Definition: direct_manipulation.cc:250
flutter::DirectManipulationOwner::DirectManipulationOwner
DirectManipulationOwner(FlutterWindow *window)
Definition: direct_manipulation.cc:176
flutter::DirectManipulationOwner::Destroy
void Destroy()
Definition: direct_manipulation.cc:216
flutter::FlutterWindow
Definition: flutter_window.h:38
flutter::FlutterWindow::GetWindowHandle
virtual HWND GetWindowHandle() override
Definition: flutter_window.cc:443
flutter::WindowBindingHandlerDelegate
Definition: window_binding_handler_delegate.h:18
flutter::WindowBindingHandlerDelegate::OnPointerPanZoomStart
virtual void OnPointerPanZoomStart(int32_t device_id)=0
flutter::WindowBindingHandlerDelegate::OnPointerPanZoomEnd
virtual void OnPointerPanZoomEnd(int32_t device_id)=0
flutter::WindowBindingHandlerDelegate::OnScrollInertiaCancel
virtual void OnScrollInertiaCancel(int32_t device_id)=0
flutter::WindowBindingHandlerDelegate::OnPointerPanZoomUpdate
virtual void OnPointerPanZoomUpdate(int32_t device_id, double pan_x, double pan_y, double scale, double rotation)=0
WARN_IF_FAILED
#define WARN_IF_FAILED(operation)
Definition: direct_manipulation.cc:23
RETURN_IF_FAILED
#define RETURN_IF_FAILED(operation)
Definition: direct_manipulation.cc:14
direct_manipulation.h
flutter_window.h
content
union flutter::testing::@100::KeyboardChange::@0 content
message
Win32Message message
Definition: keyboard_unittests.cc:137
flutter
Definition: accessibility_bridge_windows.cc:11
flutter::WCharBufferToString
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
wchar_util.h
window_binding_handler_delegate.h