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