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 
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 
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 
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 
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 
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 
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 
246  WindowBindingHandlerDelegate* delegate) {
247  binding_handler_delegate = delegate;
248 }
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);
263  FML_LOG(ERROR) << WCharBufferToString(message);
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)
union flutter::testing::@93::KeyboardChange::@0 content
Win32Message message
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