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 
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 
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 
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 
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 
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 
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 
245  WindowBindingHandlerDelegate* delegate) {
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);
262  FML_LOG(ERROR) << message;
263  }
264  }
265 }
266 
267 } // namespace flutter
flutter::DirectManipulationEventHandler::QueryInterface
STDMETHODIMP QueryInterface(REFIID iid, void **ppv) override
Definition: direct_manipulation.cc:33
flutter::DirectManipulationOwner::SetContact
virtual void SetContact(UINT contactId)
Definition: direct_manipulation.cc:238
direct_manipulation.h
flutter::FlutterWindow::GetWindowHandle
virtual HWND GetWindowHandle() override
Definition: flutter_window.cc:463
flutter::DirectManipulationEventHandler::Release
ULONG STDMETHODCALLTYPE Release() override
Definition: direct_manipulation.cc:170
flutter::WindowBindingHandlerDelegate::OnPointerPanZoomEnd
virtual void OnPointerPanZoomEnd(int32_t device_id)=0
flutter::DirectManipulationEventHandler::OnViewportUpdated
HRESULT STDMETHODCALLTYPE OnViewportUpdated(IDirectManipulationViewport *viewport) override
Definition: direct_manipulation.cc:128
flutter::DirectManipulationEventHandler::OnInteraction
HRESULT STDMETHODCALLTYPE OnInteraction(IDirectManipulationViewport2 *viewport, DIRECTMANIPULATION_INTERACTION_TYPE interaction) override
Definition: direct_manipulation.cc:159
flutter::DirectManipulationOwner::SetBindingHandlerDelegate
void SetBindingHandlerDelegate(WindowBindingHandlerDelegate *binding_handler_delegate)
Definition: direct_manipulation.cc:244
flutter::WindowBindingHandlerDelegate
Definition: window_binding_handler_delegate.h:18
flutter::DirectManipulationOwner::DirectManipulationOwner
DirectManipulationOwner(FlutterWindow *window)
Definition: direct_manipulation.cc:175
WARN_IF_FAILED
#define WARN_IF_FAILED(operation)
Definition: direct_manipulation.cc:22
flutter_window.h
flutter::DirectManipulationOwner::Update
void Update()
Definition: direct_manipulation.cc:249
flutter::WindowBindingHandlerDelegate::OnPointerPanZoomUpdate
virtual void OnPointerPanZoomUpdate(int32_t device_id, double pan_x, double pan_y, double scale, double rotation)=0
flutter
Definition: accessibility_bridge_windows.cc:11
RETURN_IF_FAILED
#define RETURN_IF_FAILED(operation)
Definition: direct_manipulation.cc:13
flutter::WindowBindingHandlerDelegate::OnScrollInertiaCancel
virtual void OnScrollInertiaCancel(int32_t device_id)=0
flutter::DirectManipulationOwner::binding_handler_delegate
WindowBindingHandlerDelegate * binding_handler_delegate
Definition: direct_manipulation.h:46
flutter::DirectManipulationEventHandler::AddRef
ULONG STDMETHODCALLTYPE AddRef() override
Definition: direct_manipulation.cc:165
content
union flutter::testing::@87::KeyboardChange::@0 content
flutter::DirectManipulationEventHandler::OnViewportStatusChanged
HRESULT STDMETHODCALLTYPE OnViewportStatusChanged(IDirectManipulationViewport *viewport, DIRECTMANIPULATION_STATUS current, DIRECTMANIPULATION_STATUS previous) override
Definition: direct_manipulation.cc:64
flutter::WindowBindingHandlerDelegate::OnPointerPanZoomStart
virtual void OnPointerPanZoomStart(int32_t device_id)=0
flutter::DirectManipulationOwner::Init
int Init(unsigned int width, unsigned int height)
Definition: direct_manipulation.cc:178
flutter::DirectManipulationOwner::Destroy
void Destroy()
Definition: direct_manipulation.cc:215
message
Win32Message message
Definition: keyboard_unittests.cc:137
flutter::FlutterWindow
Definition: flutter_window.h:35
flutter::DirectManipulationEventHandler::OnContentUpdated
HRESULT STDMETHODCALLTYPE OnContentUpdated(IDirectManipulationViewport *viewport, IDirectManipulationContent *content) override
Definition: direct_manipulation.cc:133
window_binding_handler_delegate.h
flutter::DirectManipulationOwner::ResizeViewport
void ResizeViewport(unsigned int width, unsigned int height)
Definition: direct_manipulation.cc:207