Flutter Engine
flutter_windows_view.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/shell/platform/windows/flutter_windows_view.h"
6 
7 #include <chrono>
8 
9 #include "flutter/shell/platform/windows/keyboard_key_channel_handler.h"
10 #include "flutter/shell/platform/windows/keyboard_key_embedder_handler.h"
11 #include "flutter/shell/platform/windows/text_input_plugin.h"
12 
13 namespace flutter {
14 
15 /// Returns true if the surface will be updated as part of the resize process.
16 ///
17 /// This is called on window resize to determine if the platform thread needs
18 /// to be blocked until the frame with the right size has been rendered. It
19 /// should be kept in-sync with how the engine deals with a new surface request
20 /// as seen in `CreateOrUpdateSurface` in `GPUSurfaceGL`.
21 static bool SurfaceWillUpdate(size_t cur_width,
22  size_t cur_height,
23  size_t target_width,
24  size_t target_height) {
25  // TODO (https://github.com/flutter/flutter/issues/65061) : Avoid special
26  // handling for zero dimensions.
27  bool non_zero_target_dims = target_height > 0 && target_width > 0;
28  bool not_same_size =
29  (cur_height != target_height) || (cur_width != target_width);
30  return non_zero_target_dims && not_same_size;
31 }
32 
34  std::unique_ptr<WindowBindingHandler> window_binding) {
35  // Take the binding handler, and give it a pointer back to self.
36  binding_handler_ = std::move(window_binding);
37  binding_handler_->SetView(this);
38 
39  render_target_ = std::make_unique<WindowsRenderTarget>(
40  binding_handler_->GetRenderTarget());
41 }
42 
45 }
46 
48  std::unique_ptr<FlutterWindowsEngine> engine) {
49  engine_ = std::move(engine);
50 
51  engine_->SetView(this);
52 
53  internal_plugin_registrar_ =
54  std::make_unique<flutter::PluginRegistrar>(engine_->GetRegistrar());
55 
56  // Set up the system channel handlers.
57  auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
58  InitializeKeyboard();
59  platform_handler_ = PlatformHandler::Create(internal_plugin_messenger, this);
60  cursor_handler_ = std::make_unique<flutter::CursorHandler>(
61  internal_plugin_messenger, binding_handler_.get());
62 
63  PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds();
64 
65  SendWindowMetrics(bounds.width, bounds.height,
66  binding_handler_->GetDpiScale());
67 }
68 
70  flutter::BinaryMessenger* messenger,
73  // There must be only one handler that receives |SendInput|, i.e. only one
74  // handler that might redispatch events. (See the documentation of
75  // |KeyboardKeyHandler| to learn about redispatching.)
76  //
77  // Whether an event is a redispatched event is decided by calculating the hash
78  // of the event. In order to allow the same real event in the future, the
79  // handler is "toggled" when events pass through, therefore the redispatching
80  // algorithm does not allow more than 1 handler that takes |SendInput|.
81  auto key_handler =
82  std::make_unique<flutter::KeyboardKeyHandler>(dispatch_event);
83  key_handler->AddDelegate(std::make_unique<KeyboardKeyEmbedderHandler>(
85  void* user_data) {
86  return engine_->SendKeyEvent(event, callback, user_data);
87  },
88  get_key_state));
89  key_handler->AddDelegate(
90  std::make_unique<KeyboardKeyChannelHandler>(messenger));
91  AddKeyboardHandler(std::move(key_handler));
93  std::make_unique<flutter::TextInputPlugin>(messenger, this));
94 }
95 
97  std::unique_ptr<flutter::KeyboardHandlerBase> handler) {
98  keyboard_handlers_.push_back(std::move(handler));
99 }
100 
102  // Called on an engine-controlled (non-platform) thread.
103  std::unique_lock<std::mutex> lock(resize_mutex_);
104 
105  if (resize_status_ != ResizeState::kResizeStarted) {
106  return kWindowFrameBufferID;
107  }
108 
109  if (resize_target_width_ == width && resize_target_height_ == height) {
110  // Platform thread is blocked for the entire duration until the
111  // resize_status_ is set to kDone.
112  engine_->surface_manager()->ResizeSurface(GetRenderTarget(), width, height);
113  engine_->surface_manager()->MakeCurrent();
114  resize_status_ = ResizeState::kFrameGenerated;
115  }
116 
117  return kWindowFrameBufferID;
118 }
119 
121  if (resize_status_ == ResizeState::kDone) {
122  // Request new frame
123  // TODO(knopp): Replace with more specific call once there is API for it
124  // https://github.com/flutter/flutter/issues/69716
125  SendWindowMetrics(resize_target_width_, resize_target_height_,
126  binding_handler_->GetDpiScale());
127  }
128 }
129 
131  keyboard_handlers_.clear();
132  InitializeKeyboard();
133 }
134 
136  // Called on the platform thread.
137  std::unique_lock<std::mutex> lock(resize_mutex_);
138 
139  if (!engine_->surface_manager()) {
140  SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
141  return;
142  }
143 
144  EGLint surface_width, surface_height;
145  engine_->surface_manager()->GetSurfaceDimensions(&surface_width,
146  &surface_height);
147 
148  bool surface_will_update =
149  SurfaceWillUpdate(surface_width, surface_height, width, height);
150  if (surface_will_update) {
151  resize_status_ = ResizeState::kResizeStarted;
152  resize_target_width_ = width;
153  resize_target_height_ = height;
154  }
155 
156  SendWindowMetrics(width, height, binding_handler_->GetDpiScale());
157 
158  if (surface_will_update) {
159  // Block the platform thread until:
160  // 1. GetFrameBufferId is called with the right frame size.
161  // 2. Any pending SwapBuffers calls have been invoked.
162  resize_cv_.wait(lock, [&resize_status = resize_status_] {
163  return resize_status == ResizeState::kDone;
164  });
165  }
166 }
167 
169  double y,
170  FlutterPointerDeviceKind device_kind,
171  int32_t device_id) {
172  SendPointerMove(x, y, GetOrCreatePointerState(device_kind, device_id));
173 }
174 
176  double x,
177  double y,
178  FlutterPointerDeviceKind device_kind,
179  int32_t device_id,
180  FlutterPointerMouseButtons flutter_button) {
181  if (flutter_button != 0) {
182  auto state = GetOrCreatePointerState(device_kind, device_id);
183  state->buttons |= flutter_button;
184  SendPointerDown(x, y, state);
185  }
186 }
187 
189  double x,
190  double y,
191  FlutterPointerDeviceKind device_kind,
192  int32_t device_id,
193  FlutterPointerMouseButtons flutter_button) {
194  if (flutter_button != 0) {
195  auto state = GetOrCreatePointerState(device_kind, device_id);
196  state->buttons &= ~flutter_button;
197  SendPointerUp(x, y, state);
198  }
199 }
200 
202  int32_t device_id) {
203  SendPointerLeave(GetOrCreatePointerState(device_kind, device_id));
204 }
205 
206 void FlutterWindowsView::OnText(const std::u16string& text) {
207  SendText(text);
208 }
209 
211  int scancode,
212  int action,
213  char32_t character,
214  bool extended,
215  bool was_down) {
216  return SendKey(key, scancode, action, character, extended, was_down);
217 }
218 
220  SendComposeBegin();
221 }
222 
224  SendComposeCommit();
225 }
226 
228  SendComposeEnd();
229 }
230 
231 void FlutterWindowsView::OnComposeChange(const std::u16string& text,
232  int cursor_pos) {
233  SendComposeChange(text, cursor_pos);
234 }
235 
237  double y,
238  double delta_x,
239  double delta_y,
240  int scroll_offset_multiplier,
241  FlutterPointerDeviceKind device_kind,
242  int32_t device_id) {
243  SendScroll(x, y, delta_x, delta_y, scroll_offset_multiplier, device_kind,
244  device_id);
245 }
246 
248  SendPlatformBrightnessChanged();
249 }
250 
252  engine_->UpdateSemanticsEnabled(enabled);
253 }
254 
256  binding_handler_->OnCursorRectUpdated(rect);
257 }
258 
260  binding_handler_->OnResetImeComposing();
261 }
262 
263 void FlutterWindowsView::InitializeKeyboard() {
264  auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
265 #ifdef WINUWP
266  flutter::KeyboardKeyHandler::EventDispatcher dispatch_event = nullptr;
268  nullptr;
269 #else
270  flutter::KeyboardKeyHandler::EventDispatcher dispatch_event = SendInput;
272  GetKeyState;
273 #endif
274  RegisterKeyboardHandlers(internal_plugin_messenger, dispatch_event,
275  get_key_state);
276 }
277 
278 // Sends new size information to FlutterEngine.
279 void FlutterWindowsView::SendWindowMetrics(size_t width,
280  size_t height,
281  double dpiScale) const {
282  FlutterWindowMetricsEvent event = {};
283  event.struct_size = sizeof(event);
284  event.width = width;
285  event.height = height;
286  event.pixel_ratio = dpiScale;
287  engine_->SendWindowMetricsEvent(event);
288 }
289 
291  PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds();
292 
293  SendWindowMetrics(bounds.width, bounds.height,
294  binding_handler_->GetDpiScale());
295 }
296 
297 FlutterWindowsView::PointerState* FlutterWindowsView::GetOrCreatePointerState(
298  FlutterPointerDeviceKind device_kind,
299  int32_t device_id) {
300  // Create a virtual pointer ID that is unique across all device types
301  // to prevent pointers from clashing in the engine's converter
302  // (lib/ui/window/pointer_data_packet_converter.cc)
303  int32_t pointer_id = (static_cast<int32_t>(device_kind) << 28) | device_id;
304 
305  auto [it, added] = pointer_states_.try_emplace(pointer_id, nullptr);
306  if (added) {
307  auto state = std::make_unique<PointerState>();
308  state->device_kind = device_kind;
309  state->pointer_id = pointer_id;
310  it->second = std::move(state);
311  }
312 
313  return it->second.get();
314 }
315 
316 // Set's |event_data|'s phase to either kMove or kHover depending on the current
317 // primary mouse button state.
318 void FlutterWindowsView::SetEventPhaseFromCursorButtonState(
319  FlutterPointerEvent* event_data,
320  const PointerState* state) const {
321  // For details about this logic, see FlutterPointerPhase in the embedder.h
322  // file.
323  if (state->buttons == 0) {
324  event_data->phase = state->flutter_state_is_down
327  } else {
328  event_data->phase = state->flutter_state_is_down
331  }
332 }
333 
334 void FlutterWindowsView::SendPointerMove(double x,
335  double y,
336  PointerState* state) {
337  FlutterPointerEvent event = {};
338  event.x = x;
339  event.y = y;
340 
341  SetEventPhaseFromCursorButtonState(&event, state);
342  SendPointerEventWithData(event, state);
343 }
344 
345 void FlutterWindowsView::SendPointerDown(double x,
346  double y,
347  PointerState* state) {
348  FlutterPointerEvent event = {};
349  event.x = x;
350  event.y = y;
351 
352  SetEventPhaseFromCursorButtonState(&event, state);
353  SendPointerEventWithData(event, state);
354 
355  state->flutter_state_is_down = true;
356 }
357 
358 void FlutterWindowsView::SendPointerUp(double x,
359  double y,
360  PointerState* state) {
361  FlutterPointerEvent event = {};
362  event.x = x;
363  event.y = y;
364 
365  SetEventPhaseFromCursorButtonState(&event, state);
366  SendPointerEventWithData(event, state);
367  if (event.phase == FlutterPointerPhase::kUp) {
368  state->flutter_state_is_down = false;
369  }
370 }
371 
372 void FlutterWindowsView::SendPointerLeave(PointerState* state) {
373  FlutterPointerEvent event = {};
375  SendPointerEventWithData(event, state);
376 }
377 
378 void FlutterWindowsView::SendText(const std::u16string& text) {
379  for (const auto& handler : keyboard_handlers_) {
380  handler->TextHook(this, text);
381  }
382 }
383 
384 bool FlutterWindowsView::SendKey(int key,
385  int scancode,
386  int action,
387  char32_t character,
388  bool extended,
389  bool was_down) {
390  for (const auto& handler : keyboard_handlers_) {
391  if (handler->KeyboardHook(this, key, scancode, action, character, extended,
392  was_down)) {
393  // key event was handled, so don't send to other handlers.
394  return true;
395  }
396  }
397  return false;
398 }
399 
400 void FlutterWindowsView::SendComposeBegin() {
401  for (const auto& handler : keyboard_handlers_) {
402  handler->ComposeBeginHook();
403  }
404 }
405 
406 void FlutterWindowsView::SendComposeCommit() {
407  for (const auto& handler : keyboard_handlers_) {
408  handler->ComposeCommitHook();
409  }
410 }
411 
412 void FlutterWindowsView::SendComposeEnd() {
413  for (const auto& handler : keyboard_handlers_) {
414  handler->ComposeEndHook();
415  }
416 }
417 
418 void FlutterWindowsView::SendComposeChange(const std::u16string& text,
419  int cursor_pos) {
420  for (const auto& handler : keyboard_handlers_) {
421  handler->ComposeChangeHook(text, cursor_pos);
422  }
423 }
424 
425 void FlutterWindowsView::SendScroll(double x,
426  double y,
427  double delta_x,
428  double delta_y,
429  int scroll_offset_multiplier,
430  FlutterPointerDeviceKind device_kind,
431  int32_t device_id) {
432  auto state = GetOrCreatePointerState(device_kind, device_id);
433 
434  FlutterPointerEvent event = {};
435  event.x = x;
436  event.y = y;
438  event.scroll_delta_x = delta_x * scroll_offset_multiplier;
439  event.scroll_delta_y = delta_y * scroll_offset_multiplier;
440  SetEventPhaseFromCursorButtonState(&event, state);
441  SendPointerEventWithData(event, state);
442 }
443 
444 void FlutterWindowsView::SendPointerEventWithData(
445  const FlutterPointerEvent& event_data,
446  PointerState* state) {
447  // If sending anything other than an add, and the pointer isn't already added,
448  // synthesize an add to satisfy Flutter's expectations about events.
449  if (!state->flutter_state_is_added &&
450  event_data.phase != FlutterPointerPhase::kAdd) {
451  FlutterPointerEvent event = {};
453  event.x = event_data.x;
454  event.y = event_data.y;
455  event.buttons = 0;
456  SendPointerEventWithData(event, state);
457  }
458 
459  // Don't double-add (e.g., if events are delivered out of order, so an add has
460  // already been synthesized).
461  if (state->flutter_state_is_added &&
462  event_data.phase == FlutterPointerPhase::kAdd) {
463  return;
464  }
465 
466  FlutterPointerEvent event = event_data;
467  event.device_kind = state->device_kind;
468  event.device = state->pointer_id;
469  event.buttons = state->buttons;
470 
471  // Set metadata that's always the same regardless of the event.
472  event.struct_size = sizeof(event);
473  event.timestamp =
474  std::chrono::duration_cast<std::chrono::microseconds>(
475  std::chrono::high_resolution_clock::now().time_since_epoch())
476  .count();
477 
478  engine_->SendPointerEvent(event);
479 
480  if (event_data.phase == FlutterPointerPhase::kAdd) {
481  state->flutter_state_is_added = true;
482  } else if (event_data.phase == FlutterPointerPhase::kRemove) {
483  auto it = pointer_states_.find(state->pointer_id);
484  if (it != pointer_states_.end()) {
485  pointer_states_.erase(it);
486  }
487  }
488 }
489 
490 void FlutterWindowsView::SendPlatformBrightnessChanged() {
491  engine_->task_runner()->RunNowOrPostTask(
492  [this]() { engine_->ReloadPlatformBrightness(); });
493 };
494 
496  return engine_->surface_manager()->MakeCurrent();
497 }
498 
500  return engine_->surface_manager()->MakeResourceCurrent();
501 }
502 
504  return engine_->surface_manager()->ClearContext();
505 }
506 
508  // Called on an engine-controlled (non-platform) thread.
509  std::unique_lock<std::mutex> lock(resize_mutex_);
510 
511  switch (resize_status_) {
512  // SwapBuffer requests during resize are ignored until the frame with the
513  // right dimensions has been generated. This is marked with
514  // kFrameGenerated resize status.
515  case ResizeState::kResizeStarted:
516  return false;
517  case ResizeState::kFrameGenerated: {
518  bool visible = binding_handler_->IsVisible();
519  bool swap_buffers_result;
520  // For visible windows swap the buffers while resize handler is waiting.
521  // For invisible windows unblock the handler first and then swap buffers.
522  // SwapBuffers waits for vsync and there's no point doing that for
523  // invisible windows.
524  if (visible) {
525  swap_buffers_result = engine_->surface_manager()->SwapBuffers();
526  }
527  resize_status_ = ResizeState::kDone;
528  lock.unlock();
529  resize_cv_.notify_all();
530  binding_handler_->OnWindowResized();
531  if (!visible) {
532  swap_buffers_result = engine_->surface_manager()->SwapBuffers();
533  }
534  return swap_buffers_result;
535  }
536  case ResizeState::kDone:
537  default:
538  return engine_->surface_manager()->SwapBuffers();
539  }
540 }
541 
542 bool FlutterWindowsView::PresentSoftwareBitmap(const void* allocation,
543  size_t row_bytes,
544  size_t height) {
545  return binding_handler_->OnBitmapSurfaceUpdated(allocation, row_bytes,
546  height);
547 }
548 
550  if (engine_ && engine_->surface_manager()) {
551  PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds();
552  engine_->surface_manager()->CreateSurface(GetRenderTarget(), bounds.width,
553  bounds.height);
554  }
555 }
556 
558  if (engine_ && engine_->surface_manager()) {
559  engine_->surface_manager()->DestroySurface();
560  }
561 }
562 
564  return render_target_.get();
565 }
566 
568  return binding_handler_->GetPlatformWindow();
569 }
570 
572  return engine_.get();
573 }
574 
575 } // namespace flutter
FlutterPointerMouseButtons
Definition: embedder.h:631
void OnPointerDown(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, FlutterPointerMouseButtons button) override
FlutterWindowsView(std::unique_ptr< WindowBindingHandler > window_binding)
virtual void OnUpdateSemanticsEnabled(bool enabled) override
static bool SurfaceWillUpdate(size_t cur_width, size_t cur_height, size_t target_width, size_t target_height)
double y
The y coordinate of the pointer event in physical pixels.
Definition: embedder.h:658
void OnPointerUp(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, FlutterPointerMouseButtons button) override
void * user_data
char32_t character
std::variant< HWND > WindowsRenderTarget
void OnCursorRectUpdated(const Rect &rect) override
constexpr uint32_t kWindowFrameBufferID
std::function< UINT(UINT cInputs, LPINPUT pInputs, int cbSize)> EventDispatcher
void OnComposeChange(const std::u16string &text, int cursor_pos) override
FlutterPointerDeviceKind
The device type that created a pointer event.
Definition: embedder.h:623
FlKeyEvent FlKeyResponderAsyncCallback callback
FlKeyEvent * event
void SetEngine(std::unique_ptr< FlutterWindowsEngine > engine)
void OnText(const std::u16string &) override
void OnPointerLeave(FlutterPointerDeviceKind device_kind, int32_t device_id=0) override
SemanticsAction action
The pointer moved while up.
Definition: embedder.h:619
void AddKeyboardHandler(std::unique_ptr< flutter::KeyboardHandlerBase > handler)
void OnPointerMove(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id) override
int32_t width
size_t struct_size
The size of this struct. Must be sizeof(FlutterWindowMetricsEvent).
Definition: embedder.h:565
Definition: embedder.h:612
double x
The x coordinate of the pointer event in physical pixels.
Definition: embedder.h:656
bool PresentSoftwareBitmap(const void *allocation, size_t row_bytes, size_t height)
int32_t height
std::u16string text
void(* FlutterKeyEventCallback)(bool, void *)
Definition: embedder.h:748
uint32_t GetFrameBufferId(size_t width, size_t height)
bool OnKey(int key, int scancode, int action, char32_t character, bool extended, bool was_down) override
PlatformWindow GetPlatformWindow() const
FlutterPointerDeviceKind device_kind
Definition: embedder.h:672
WindowsRenderTarget * GetRenderTarget() const
virtual void RegisterKeyboardHandlers(flutter::BinaryMessenger *messenger, flutter::KeyboardKeyHandler::EventDispatcher dispatch_event, flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state)
FlutterPointerPhase phase
Definition: embedder.h:650
AtkStateType state
static std::unique_ptr< PlatformHandler > Create(BinaryMessenger *messenger, FlutterWindowsView *view)
void OnScroll(double x, double y, double delta_x, double delta_y, int scroll_offset_multiplier, FlutterPointerDeviceKind device_kind, int32_t device_id) override
FlutterWindowsEngine * GetEngine()
void OnWindowSizeChanged(size_t width, size_t height) override