Flutter Windows Embedder
flutter_windows_view.h
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 #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOWS_VIEW_H_
6 #define FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOWS_VIEW_H_
7 
8 #include <atomic>
9 #include <memory>
10 #include <mutex>
11 #include <string>
12 #include <unordered_map>
13 #include <utility>
14 #include <vector>
15 
16 #include "flutter/fml/closure.h"
17 #include "flutter/fml/macros.h"
18 #include "flutter/shell/geometry/geometry.h"
20 #include "flutter/shell/platform/embedder/embedder.h"
28 
29 namespace flutter {
30 
31 // A unique identifier for a view.
32 using FlutterViewId = int64_t;
33 
34 // Optional delegate for views that are sized to contents.
36  public:
37  // This method is called from the raster thread
38  // after the view's surface has been resized but
39  // before the frame has been presented on the view.
40  virtual void DidUpdateViewSize(int32_t width, int32_t height) = 0;
41 
42  // Return the work area that the view can be laid out within.
43  virtual WindowRect GetWorkArea() const = 0;
44 };
45 
46 // An OS-windowing neutral abstration for a Flutter view that works
47 // with win32 HWNDs.
49  public:
50  // Creates a FlutterWindowsView with the given implementor of
51  // WindowBindingHandler.
54  FlutterWindowsEngine* engine,
55  std::unique_ptr<WindowBindingHandler> window_binding,
56  bool is_sized_to_content,
57  const BoxConstraints& box_constraints,
58  FlutterWindowsViewSizingDelegate* sizing_delegate = nullptr,
59  std::shared_ptr<WindowsProcTable> windows_proc_table = nullptr);
60 
61  virtual ~FlutterWindowsView();
62 
63  // Get the view's unique identifier.
64  FlutterViewId view_id() const;
65 
66  // Whether this view is the implicit view.
67  //
68  // The implicit view is a special view for backwards compatibility.
69  // The engine assumes it can always render to this view, even if the app has
70  // destroyed the window for this view.
71  //
72  // Today, the implicit view is the first view that is created. It is the only
73  // view that can be created before the engine is launched.
74  //
75  // The embedder must ignore presents to this view before it is created and
76  // after it is destroyed.
77  //
78  // See:
79  // https://api.flutter.dev/flutter/dart-ui/PlatformDispatcher/implicitView.html
80  bool IsImplicitView() const;
81 
82  // Create a rendering surface for Flutter engine to draw into.
83  //
84  // This is a no-op if using software rasterization.
85  void CreateRenderSurface();
86 
87  // Get the EGL surface that backs the Flutter view.
88  //
89  // This might be nullptr or an invalid surface.
90  egl::WindowSurface* surface() const;
91 
92  // Return the currently configured HWND.
93  virtual HWND GetWindowHandle() const;
94 
95  // Returns the engine backing this view.
97 
98  // Tells the engine to generate a new frame
99  void ForceRedraw();
100 
101  // Callback to clear a previously presented software bitmap.
102  virtual bool ClearSoftwareBitmap();
103 
104  // Callback for presenting a software bitmap.
105  virtual bool PresentSoftwareBitmap(const void* allocation,
106  size_t row_bytes,
107  size_t height);
108 
109  // Creates a window metric for this view.
110  //
111  // Used to notify the engine of a view's current size and device pixel ratio.
112  FlutterWindowMetricsEvent CreateWindowMetricsEvent() const;
113 
114  // Send initial bounds to embedder. Must occur after engine has initialized.
115  //
116  // This is a no-op if this is not the implicit view. Non-implicit views'
117  // initial window metrics are sent when the view is added to the engine.
118  void SendInitialBounds();
119 
120  // Set the text of the alert, and create it if it does not yet exist.
121  virtual void AnnounceAlert(const std::wstring& text);
122 
123  // |WindowBindingHandlerDelegate|
124  void OnHighContrastChanged() override;
125 
126  // Called on the raster thread when |CompositorOpenGL| receives an empty
127  // frame. Returns true if the frame can be presented.
128  //
129  // This destroys and then re-creates the view's surface if a resize is
130  // pending.
131  bool OnEmptyFrameGenerated();
132 
133  // Called on the raster thread when |CompositorOpenGL| receives a frame.
134  // Returns true if the frame can be presented.
135  //
136  // This destroys and then re-creates the view's surface if a resize is pending
137  // and |width| and |height| match the target size.
138  bool OnFrameGenerated(size_t width, size_t height);
139 
140  // Called on the raster thread after |CompositorOpenGL| presents a frame.
141  //
142  // This completes a view resize if one is pending.
143  virtual void OnFramePresented();
144 
145  // Set a callback that is invoked on the platform thread after the first
146  // frame is presented for this view. The callback is called exactly once
147  // and then cleared. This can be used to defer showing the host window
148  // until the first frame is rendered, avoiding a blank window flash.
149  void SetFirstFrameCallback(fml::closure callback);
150 
151  // |WindowBindingHandlerDelegate|
152  bool OnWindowSizeChanged(size_t width, size_t height) override;
153 
154  // Enables or disables content-based sizing for this view.
155  //
156  // When enabled, the view ignores externally-driven resizes and instead
157  // sizes itself to the rendered content after each frame. When disabled,
158  // the view follows the normal platform-driven resize flow.
159  //
160  // This may be called on any thread.
161  void SetSizedToContent(bool sized_to_content);
162 
163  // Returns true if the view is currently sized to its rendered content.
164  //
165  // This may be called from the platform or raster threads.
166  bool IsSizedToContent() const;
167 
168  // |WindowBindingHandlerDelegate|
169  void OnWindowRepaint() override;
170 
171  // |WindowBindingHandlerDelegate|
172  void OnPointerMove(double x,
173  double y,
174  FlutterPointerDeviceKind device_kind,
175  int32_t device_id,
176  uint64_t buttons,
177  uint32_t rotation,
178  uint32_t pressure,
179  int modifiers_state) override;
180 
181  // |WindowBindingHandlerDelegate|
182  void OnPointerDown(double x,
183  double y,
184  FlutterPointerDeviceKind device_kind,
185  int32_t device_id,
186  uint64_t buttons,
187  uint32_t rotation,
188  uint32_t pressure) override;
189 
190  // |WindowBindingHandlerDelegate|
191  void OnPointerUp(double x,
192  double y,
193  FlutterPointerDeviceKind device_kind,
194  int32_t device_id,
195  uint64_t buttons) override;
196 
197  // |WindowBindingHandlerDelegate|
198  void OnPointerLeave(double x,
199  double y,
200  FlutterPointerDeviceKind device_kind,
201  int32_t device_id = 0) override;
202 
203  // |WindowBindingHandlerDelegate|
204  virtual void OnPointerPanZoomStart(int32_t device_id) override;
205 
206  // |WindowBindingHandlerDelegate|
207  virtual void OnPointerPanZoomUpdate(int32_t device_id,
208  double pan_x,
209  double pan_y,
210  double scale,
211  double rotation) override;
212 
213  // |WindowBindingHandlerDelegate|
214  virtual void OnPointerPanZoomEnd(int32_t device_id) override;
215 
216  // |WindowBindingHandlerDelegate|
217  void OnText(const std::u16string&) override;
218 
219  // |WindowBindingHandlerDelegate|
220  void OnKey(int key,
221  int scancode,
222  int action,
223  char32_t character,
224  bool extended,
225  bool was_down,
226  KeyEventCallback callback) override;
227 
228  // |WindowBindingHandlerDelegate|
229  void OnFocus(FlutterViewFocusState focus_state,
230  FlutterViewFocusDirection direction) override;
231 
232  // |WindowBindingHandlerDelegate|
233  void OnComposeBegin() override;
234 
235  // |WindowBindingHandlerDelegate|
236  void OnComposeCommit() override;
237 
238  // |WindowBindingHandlerDelegate|
239  void OnComposeEnd() override;
240 
241  // |WindowBindingHandlerDelegate|
242  void OnComposeChange(const std::u16string& text, int cursor_pos) override;
243 
244  // |WindowBindingHandlerDelegate|
245  void OnScroll(double x,
246  double y,
247  double delta_x,
248  double delta_y,
249  int scroll_offset_multiplier,
250  FlutterPointerDeviceKind device_kind,
251  int32_t device_id) override;
252 
253  // |WindowBindingHandlerDelegate|
254  void OnScrollInertiaCancel(int32_t device_id) override;
255 
256  // |WindowBindingHandlerDelegate|
257  virtual void OnUpdateSemanticsEnabled(bool enabled) override;
258 
259  // |WindowBindingHandlerDelegate|
260  virtual gfx::NativeViewAccessible GetNativeViewAccessible() override;
261 
262  // Notifies the delegate of the updated the cursor rect in Flutter root view
263  // coordinates.
264  virtual void OnCursorRectUpdated(const Rect& rect);
265 
266  // Notifies the delegate that the system IME composing state should be reset.
267  virtual void OnResetImeComposing();
268 
269  // Called when a WM_ONCOMPOSITIONCHANGED message is received.
271 
272  // Get a pointer to the alert node for this view.
273  ui::AXPlatformNodeWin* AlertNode() const;
274 
275  // |WindowBindingHandlerDelegate|
276  virtual ui::AXFragmentRootDelegateWin* GetAxFragmentRootDelegate() override;
277 
278  // Called to re/set the accessibility bridge pointer.
279  virtual void UpdateSemanticsEnabled(bool enabled);
280 
281  std::weak_ptr<AccessibilityBridgeWindows> accessibility_bridge() {
282  return accessibility_bridge_;
283  }
284 
285  // |WindowBindingHandlerDelegate|
286  void OnWindowStateEvent(HWND hwnd, WindowStateEvent event) override;
287 
288  // Focus the view.
289  // Returns true if the view was focused.
290  virtual bool Focus();
291 
292  protected:
293  virtual void NotifyWinEventWrapper(ui::AXPlatformNodeWin* node,
294  ax::mojom::Event event);
295 
296  // Create an AccessibilityBridgeWindows using this view.
297  virtual std::shared_ptr<AccessibilityBridgeWindows>
299 
300  private:
301  // Allows setting the surface in tests.
302  friend class ViewModifier;
303 
304  // Struct holding the state of an individual pointer. The engine doesn't keep
305  // track of which buttons have been pressed, so it's the embedding's
306  // responsibility.
307  struct PointerState {
308  // The device kind.
309  FlutterPointerDeviceKind device_kind = kFlutterPointerDeviceKindMouse;
310 
311  // A virtual pointer ID that is unique across all device kinds.
312  int32_t pointer_id = 0;
313 
314  // True if the last event sent to Flutter had at least one button pressed.
315  bool flutter_state_is_down = false;
316 
317  // True if kAdd has been sent to Flutter. Used to determine whether
318  // to send a kAdd event before sending an incoming pointer event, since
319  // Flutter expects pointers to be added before events are sent for them.
320  bool flutter_state_is_added = false;
321 
322  // The currently pressed buttons, as represented in FlutterPointerEvent.
323  uint64_t buttons = 0;
324 
325  // The x position where the last pan/zoom started.
326  double pan_zoom_start_x = 0;
327 
328  // The y position where the last pan/zoom started.
329  double pan_zoom_start_y = 0;
330 
331  // The clockwise rotation of the current pointer, from 0-359.
332  uint32_t rotation = 0;
333 
334  // The pressure of the current pointer from 0-1024.
335  uint32_t pressure = 0;
336  };
337 
338  // States a resize event can be in.
339  enum class ResizeState {
340  // When a resize event has started but is in progress.
341  kResizeStarted,
342  // After a resize event starts and the framework has been notified to
343  // generate a frame for the right size.
344  kFrameGenerated,
345  // Default state for when no resize is in progress. Also used to indicate
346  // that during a resize event, a frame with the right size has been rendered
347  // and the buffers have been swapped.
348  kDone,
349  };
350 
351  // Resize the surface to the desired size.
352  //
353  // If the dimensions have changed, this destroys the original surface and
354  // creates a new one.
355  //
356  // This must be run on the raster thread. This binds the surface to the
357  // current thread.
358  //
359  // Width and height are the surface's desired physical pixel dimensions.
360  bool ResizeRenderSurface(size_t width, size_t height);
361 
362  // Sends a window metrics update to the Flutter engine using current window
363  // dimensions in physical pixels.
364  void SendWindowMetrics(size_t width, size_t height, double pixel_ratio) const;
365 
366  // Reports a mouse movement to Flutter engine.
367  void SendPointerMove(double x, double y, PointerState* state);
368 
369  // Reports mouse press to Flutter engine.
370  void SendPointerDown(double x, double y, PointerState* state);
371 
372  // Reports mouse release to Flutter engine.
373  void SendPointerUp(double x, double y, PointerState* state);
374 
375  // Reports mouse left the window client area.
376  //
377  // Win32 api doesn't have "mouse enter" event. Therefore, there is no
378  // SendPointerEnter method. A mouse enter event is tracked then the "move"
379  // event is called.
380  void SendPointerLeave(double x, double y, PointerState* state);
381 
382  void SendPointerPanZoomStart(int32_t device_id, double x, double y);
383 
384  void SendPointerPanZoomUpdate(int32_t device_id,
385  double pan_x,
386  double pan_y,
387  double scale,
388  double rotation);
389 
390  void SendPointerPanZoomEnd(int32_t device_id);
391 
392  // Reports a keyboard character to Flutter engine.
393  void SendText(const std::u16string&);
394 
395  // Reports a raw keyboard message to Flutter engine.
396  void SendKey(int key,
397  int scancode,
398  int action,
399  char32_t character,
400  bool extended,
401  bool was_down,
403 
404  // Reports a focus event to Flutter engine.
405  void SendFocus(FlutterViewFocusState focus_state,
406  FlutterViewFocusDirection direction);
407 
408  // Reports an IME compose begin event.
409  //
410  // Triggered when the user begins editing composing text using a multi-step
411  // input method such as in CJK text input.
412  void SendComposeBegin();
413 
414  // Reports an IME compose commit event.
415  //
416  // Triggered when the user commits the current composing text while using a
417  // multi-step input method such as in CJK text input. Composing continues with
418  // the next keypress.
419  void SendComposeCommit();
420 
421  // Reports an IME compose end event.
422  //
423  // Triggered when the user commits the composing text while using a multi-step
424  // input method such as in CJK text input.
425  void SendComposeEnd();
426 
427  // Reports an IME composing region change event.
428  //
429  // Triggered when the user edits the composing text while using a multi-step
430  // input method such as in CJK text input.
431  void SendComposeChange(const std::u16string& text, int cursor_pos);
432 
433  // Reports scroll wheel events to Flutter engine.
434  void SendScroll(double x,
435  double y,
436  double delta_x,
437  double delta_y,
438  int scroll_offset_multiplier,
439  FlutterPointerDeviceKind device_kind,
440  int32_t device_id);
441 
442  // Reports scroll inertia cancel events to Flutter engine.
443  void SendScrollInertiaCancel(int32_t device_id, double x, double y);
444 
445  // Creates a PointerState object unless it already exists.
446  PointerState* GetOrCreatePointerState(FlutterPointerDeviceKind device_kind,
447  int32_t device_id);
448 
449  // Sets |event_data|'s phase to either kMove or kHover depending on the
450  // current primary mouse button state.
451  void SetEventPhaseFromCursorButtonState(FlutterPointerEvent* event_data,
452  const PointerState* state) const;
453 
454  // Sends a pointer event to the Flutter engine based on given data. Since
455  // all input messages are passed in physical pixel values, no translation is
456  // needed before passing on to engine.
457  void SendPointerEventWithData(const FlutterPointerEvent& event_data,
458  PointerState* state);
459 
460  // Fires |first_frame_callback_| on the platform thread if set, then clears
461  // it. Called from the raster thread after a frame is presented.
462  void FireFirstFrameCallbackIfSet();
463 
464  // If true, rendering to the window should synchronize with the vsync
465  // to prevent screen tearing.
466  bool NeedsVsync() const;
467 
468  // Gets the constraints for this view.
469  BoxConstraints GetConstraints() const;
470 
471  // The view's unique identifier.
472  FlutterViewId view_id_;
473 
474  // The engine associated with this view.
475  FlutterWindowsEngine* engine_ = nullptr;
476 
477  // Mocks win32 APIs.
478  std::shared_ptr<WindowsProcTable> windows_proc_table_;
479 
480  // The EGL surface backing the view.
481  //
482  // Null if using software rasterization, the surface hasn't been created yet,
483  // or if surface creation failed.
484  std::unique_ptr<egl::WindowSurface> surface_ = nullptr;
485 
486  // Keeps track of pointer states in relation to the window.
487  std::unordered_map<int32_t, std::unique_ptr<PointerState>> pointer_states_;
488 
489  // Currently configured WindowBindingHandler for view.
490  std::unique_ptr<WindowBindingHandler> binding_handler_;
491 
492  // Protects resize_status_, resize_target_width_ and resize_target_height_.
493  std::mutex resize_mutex_;
494 
495  // Indicates the state of a window resize event. Platform thread will be
496  // blocked while this is not done. Guarded by resize_mutex_.
497  ResizeState resize_status_ = ResizeState::kDone;
498 
499  // Target for the window width. Valid when resize_pending_ is set. Guarded by
500  // resize_mutex_.
501  size_t resize_target_width_ = 0;
502 
503  // Target for the window width. Valid when resize_pending_ is set. Guarded by
504  // resize_mutex_.
505  size_t resize_target_height_ = 0;
506 
507  // True when flutter's semantics tree is enabled.
508  bool semantics_enabled_ = false;
509 
510  // The accessibility bridge associated with this view.
511  std::shared_ptr<AccessibilityBridgeWindows> accessibility_bridge_;
512 
513  // If `true`, the view is sized to its content via a sizing delegate.
514  // If `false`, the view is sized by its parent HWND.
515  std::atomic<bool> is_sized_to_content_{false};
516 
517  // The constraints for this view.
518  BoxConstraints box_constraints_;
519 
520  // Optional sizing delegate for views that are sized to content.
521  FlutterWindowsViewSizingDelegate* sizing_delegate_ = nullptr;
522 
523  // Mutex protecting |first_frame_callback_|.
524  std::mutex first_frame_callback_mutex_;
525 
526  // Callback invoked on the platform thread after the first frame is
527  // presented. Set via |SetFirstFrameCallback| and cleared after invocation.
528  fml::closure first_frame_callback_;
529 
530  FML_DISALLOW_COPY_AND_ASSIGN(FlutterWindowsView);
531 };
532 
533 } // namespace flutter
534 
535 #endif // FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOWS_VIEW_H_
virtual void OnPointerPanZoomStart(int32_t device_id) override
virtual void UpdateSemanticsEnabled(bool enabled)
virtual ui::AXFragmentRootDelegateWin * GetAxFragmentRootDelegate() override
void OnScrollInertiaCancel(int32_t device_id) override
virtual std::shared_ptr< AccessibilityBridgeWindows > CreateAccessibilityBridge()
void SetSizedToContent(bool sized_to_content)
ui::AXPlatformNodeWin * AlertNode() const
void OnPointerDown(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, uint64_t buttons, uint32_t rotation, uint32_t pressure) override
std::weak_ptr< AccessibilityBridgeWindows > accessibility_bridge()
virtual void OnUpdateSemanticsEnabled(bool enabled) override
void OnPointerLeave(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id=0) override
virtual void NotifyWinEventWrapper(ui::AXPlatformNodeWin *node, ax::mojom::Event event)
void SetFirstFrameCallback(fml::closure callback)
FlutterWindowsEngine * GetEngine() const
void OnScroll(double x, double y, double delta_x, double delta_y, int scroll_offset_multiplier, FlutterPointerDeviceKind device_kind, int32_t device_id) override
void OnWindowStateEvent(HWND hwnd, WindowStateEvent event) override
virtual void OnPointerPanZoomEnd(int32_t device_id) override
void OnPointerMove(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, uint64_t buttons, uint32_t rotation, uint32_t pressure, int modifiers_state) override
FlutterWindowMetricsEvent CreateWindowMetricsEvent() const
FlutterWindowsView(FlutterViewId view_id, FlutterWindowsEngine *engine, std::unique_ptr< WindowBindingHandler > window_binding, bool is_sized_to_content, const BoxConstraints &box_constraints, FlutterWindowsViewSizingDelegate *sizing_delegate=nullptr, std::shared_ptr< WindowsProcTable > windows_proc_table=nullptr)
virtual void AnnounceAlert(const std::wstring &text)
void OnPointerUp(double x, double y, FlutterPointerDeviceKind device_kind, int32_t device_id, uint64_t buttons) override
virtual bool PresentSoftwareBitmap(const void *allocation, size_t row_bytes, size_t height)
void OnFocus(FlutterViewFocusState focus_state, FlutterViewFocusDirection direction) override
virtual HWND GetWindowHandle() const
egl::WindowSurface * surface() const
bool OnWindowSizeChanged(size_t width, size_t height) override
void OnText(const std::u16string &) override
virtual void OnPointerPanZoomUpdate(int32_t device_id, double pan_x, double pan_y, double scale, double rotation) override
void OnComposeChange(const std::u16string &text, int cursor_pos) override
virtual gfx::NativeViewAccessible GetNativeViewAccessible() override
virtual void OnCursorRectUpdated(const Rect &rect)
void OnKey(int key, int scancode, int action, char32_t character, bool extended, bool was_down, KeyEventCallback callback) override
bool OnFrameGenerated(size_t width, size_t height)
virtual WindowRect GetWorkArea() const =0
virtual void DidUpdateViewSize(int32_t width, int32_t height)=0
FlutterDesktopBinaryReply callback
std::u16string text
WindowStateEvent
An event representing a change in window state that may update the.
int64_t FlutterViewId