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