| 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/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
27 namespace flutter {
28
29 int32_t DirectManipulationEventHandler::GetDeviceId() {
30 return (int32_t) reinterpret_cast<int64_t>(this);
31 }
32
33 STDMETHODIMP DirectManipulationEventHandler::QueryInterface(REFIID iid,
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
48 DirectManipulationEventHandler::GestureData
49 DirectManipulationEventHandler::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
64 HRESULT DirectManipulationEventHandler::OnViewportStatusChanged(
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
128 HRESULT DirectManipulationEventHandler::OnViewportUpdated(
129 IDirectManipulationViewport* viewport) {
130 return S_OK;
131 }
132
133 HRESULT DirectManipulationEventHandler::OnContentUpdated(
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_) {
152 owner_->binding_handler_delegate->OnPointerPanZoomUpdate(
153 GetDeviceId(), pan_x, pan_y, scale, 0);
154 }
155 }
156 return S_OK;
157 }
158
159 HRESULT DirectManipulationEventHandler::OnInteraction(
160 IDirectManipulationViewport2* viewport,
161 DIRECTMANIPULATION_INTERACTION_TYPE interaction) {
162 return S_OK;
163 }
164
165 ULONG STDMETHODCALLTYPE DirectManipulationEventHandler::AddRef() {
166 RefCountedThreadSafe::AddRef();
167 return 0;
168 }
169
170 ULONG STDMETHODCALLTYPE DirectManipulationEventHandler::Release() {
171 RefCountedThreadSafe::Release();
172 return 0;
173 }
174
175 DirectManipulationOwner::DirectManipulationOwner(FlutterWindow* window)
176 : window_(window) {}
177
178 int 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
207 void DirectManipulationOwner::ResizeViewport(unsigned int width,
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
215 void DirectManipulationOwner::Destroy() {
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
238 void DirectManipulationOwner::SetContact(UINT contactId) {
239 if (viewport_) {
240 viewport_->SetContact(contactId);
241 }
242 }
243
244 void DirectManipulationOwner::SetBindingHandlerDelegate(
245 WindowBindingHandlerDelegate* delegate) {
246 binding_handler_delegate = delegate;
247 }
248
249 void DirectManipulationOwner::Update() {
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);
262 FML_LOG(ERROR) << message;
263 }
264 }
265 }
266
267 } // namespace flutter
flutter::DirectManipulationEventHandler::Release
ULONG STDMETHODCALLTYPE Release() override
Definition: direct_manipulation.cc:170
flutter::DirectManipulationEventHandler::OnViewportUpdated
HRESULT STDMETHODCALLTYPE OnViewportUpdated(IDirectManipulationViewport *viewport) override
Definition: direct_manipulation.cc:128
flutter::DirectManipulationEventHandler::QueryInterface
STDMETHODIMP QueryInterface(REFIID iid, void **ppv) override
Definition: direct_manipulation.cc:33
flutter::DirectManipulationEventHandler::OnInteraction
HRESULT STDMETHODCALLTYPE OnInteraction(IDirectManipulationViewport2 *viewport, DIRECTMANIPULATION_INTERACTION_TYPE interaction) override
Definition: direct_manipulation.cc:159
flutter::DirectManipulationEventHandler::AddRef
ULONG STDMETHODCALLTYPE AddRef() override
Definition: direct_manipulation.cc:165
flutter::DirectManipulationEventHandler::OnViewportStatusChanged
HRESULT STDMETHODCALLTYPE OnViewportStatusChanged(IDirectManipulationViewport *viewport, DIRECTMANIPULATION_STATUS current, DIRECTMANIPULATION_STATUS previous) override
Definition: direct_manipulation.cc:64
flutter::DirectManipulationEventHandler::OnContentUpdated
HRESULT STDMETHODCALLTYPE OnContentUpdated(IDirectManipulationViewport *viewport, IDirectManipulationContent *content) override
Definition: direct_manipulation.cc:133
flutter::DirectManipulationOwner::SetContact
virtual void SetContact(UINT contactId)
Definition: direct_manipulation.cc:238
flutter::DirectManipulationOwner::SetBindingHandlerDelegate
void SetBindingHandlerDelegate(WindowBindingHandlerDelegate *binding_handler_delegate)
Definition: direct_manipulation.cc:244
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:178
flutter::DirectManipulationOwner::ResizeViewport
void ResizeViewport(unsigned int width, unsigned int height)
Definition: direct_manipulation.cc:207
flutter::DirectManipulationOwner::Update
void Update()
Definition: direct_manipulation.cc:249
flutter::DirectManipulationOwner::DirectManipulationOwner
DirectManipulationOwner(FlutterWindow *window)
Definition: direct_manipulation.cc:175
flutter::DirectManipulationOwner::Destroy
void Destroy()
Definition: direct_manipulation.cc:215
flutter::FlutterWindow
Definition: flutter_window.h:36
flutter::FlutterWindow::GetWindowHandle
virtual HWND GetWindowHandle() override
Definition: flutter_window.cc:463
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:22
RETURN_IF_FAILED
#define RETURN_IF_FAILED(operation)
Definition: direct_manipulation.cc:13
direct_manipulation.h
flutter_window.h
content
union flutter::testing::@88::KeyboardChange::@0 content
message
Win32Message message
Definition: keyboard_unittests.cc:137
flutter
Definition: accessibility_bridge_windows.cc:11
window_binding_handler_delegate.h