| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOWS_VIEW_H_ |
| #define FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOWS_VIEW_H_ |
| |
| #include <memory> |
| #include <mutex> |
| #include <string> |
| #include <unordered_map> |
| #include <utility> |
| #include <vector> |
| |
| #include "flutter/fml/macros.h" |
| #include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h" |
| #include "flutter/shell/platform/common/geometry.h" |
| #include "flutter/shell/platform/embedder/embedder.h" |
| #include "flutter/shell/platform/windows/accessibility_bridge_windows.h" |
| #include "flutter/shell/platform/windows/flutter_windows_engine.h" |
| #include "flutter/shell/platform/windows/public/flutter_windows.h" |
| #include "flutter/shell/platform/windows/window_binding_handler.h" |
| #include "flutter/shell/platform/windows/window_binding_handler_delegate.h" |
| #include "flutter/shell/platform/windows/window_state.h" |
| #include "flutter/shell/platform/windows/windows_proc_table.h" |
| |
| namespace flutter { |
| |
| // A unique identifier for a view. |
| using FlutterViewId = int64_t; |
| |
| // An OS-windowing neutral abstration for a Flutter view that works |
| // with win32 HWNDs. |
| class FlutterWindowsView : public WindowBindingHandlerDelegate { |
| public: |
| // Creates a FlutterWindowsView with the given implementor of |
| // WindowBindingHandler. |
| FlutterWindowsView( |
| FlutterViewId view_id, |
| FlutterWindowsEngine* engine, |
| std::unique_ptr<WindowBindingHandler> window_binding, |
| std::shared_ptr<WindowsProcTable> windows_proc_table = nullptr); |
| |
| virtual ~FlutterWindowsView(); |
| |
| // Get the view's unique identifier. |
| FlutterViewId view_id() const; |
| |
| // Whether this view is the implicit view. |
| // |
| // The implicit view is a special view for backwards compatibility. |
| // The engine assumes it can always render to this view, even if the app has |
| // destroyed the window for this view. |
| // |
| // Today, the implicit view is the first view that is created. It is the only |
| // view that can be created before the engine is launched. |
| // |
| // The embedder must ignore presents to this view before it is created and |
| // after it is destroyed. |
| // |
| // See: |
| // https://api.flutter.dev/flutter/dart-ui/PlatformDispatcher/implicitView.html |
| bool IsImplicitView() const; |
| |
| // Create a rendering surface for Flutter engine to draw into. |
| // |
| // This is a no-op if using software rasterization. |
| void CreateRenderSurface(); |
| |
| // Get the EGL surface that backs the Flutter view. |
| // |
| // This might be nullptr or an invalid surface. |
| egl::WindowSurface* surface() const; |
| |
| // Return the currently configured HWND. |
| virtual HWND GetWindowHandle() const; |
| |
| // Returns the engine backing this view. |
| FlutterWindowsEngine* GetEngine() const; |
| |
| // Tells the engine to generate a new frame |
| void ForceRedraw(); |
| |
| // Callback to clear a previously presented software bitmap. |
| virtual bool ClearSoftwareBitmap(); |
| |
| // Callback for presenting a software bitmap. |
| virtual bool PresentSoftwareBitmap(const void* allocation, |
| size_t row_bytes, |
| size_t height); |
| |
| // Creates a window metric for this view. |
| // |
| // Used to notify the engine of a view's current size and device pixel ratio. |
| FlutterWindowMetricsEvent CreateWindowMetricsEvent() const; |
| |
| // Send initial bounds to embedder. Must occur after engine has initialized. |
| // |
| // This is a no-op if this is not the implicit view. Non-implicit views' |
| // initial window metrics are sent when the view is added to the engine. |
| void SendInitialBounds(); |
| |
| // Set the text of the alert, and create it if it does not yet exist. |
| void AnnounceAlert(const std::wstring& text); |
| |
| // |WindowBindingHandlerDelegate| |
| void OnHighContrastChanged() override; |
| |
| // Called on the raster thread when |CompositorOpenGL| receives an empty |
| // frame. Returns true if the frame can be presented. |
| // |
| // This destroys and then re-creates the view's surface if a resize is |
| // pending. |
| bool OnEmptyFrameGenerated(); |
| |
| // Called on the raster thread when |CompositorOpenGL| receives a frame. |
| // Returns true if the frame can be presented. |
| // |
| // This destroys and then re-creates the view's surface if a resize is pending |
| // and |width| and |height| match the target size. |
| bool OnFrameGenerated(size_t width, size_t height); |
| |
| // Called on the raster thread after |CompositorOpenGL| presents a frame. |
| // |
| // This completes a view resize if one is pending. |
| virtual void OnFramePresented(); |
| |
| // Sets the cursor that should be used when the mouse is over the Flutter |
| // content. See mouse_cursor.dart for the values and meanings of cursor_name. |
| void UpdateFlutterCursor(const std::string& cursor_name); |
| |
| // Sets the cursor directly from a cursor handle. |
| void SetFlutterCursor(HCURSOR cursor); |
| |
| // |WindowBindingHandlerDelegate| |
| bool OnWindowSizeChanged(size_t width, size_t height) override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnWindowRepaint() override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnPointerMove(double x, |
| double y, |
| FlutterPointerDeviceKind device_kind, |
| int32_t device_id, |
| int modifiers_state) override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnPointerDown(double x, |
| double y, |
| FlutterPointerDeviceKind device_kind, |
| int32_t device_id, |
| FlutterPointerMouseButtons button) override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnPointerUp(double x, |
| double y, |
| FlutterPointerDeviceKind device_kind, |
| int32_t device_id, |
| FlutterPointerMouseButtons button) override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnPointerLeave(double x, |
| double y, |
| FlutterPointerDeviceKind device_kind, |
| int32_t device_id = 0) override; |
| |
| // |WindowBindingHandlerDelegate| |
| virtual void OnPointerPanZoomStart(int32_t device_id) override; |
| |
| // |WindowBindingHandlerDelegate| |
| virtual void OnPointerPanZoomUpdate(int32_t device_id, |
| double pan_x, |
| double pan_y, |
| double scale, |
| double rotation) override; |
| |
| // |WindowBindingHandlerDelegate| |
| virtual void OnPointerPanZoomEnd(int32_t device_id) override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnText(const std::u16string&) override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnKey(int key, |
| int scancode, |
| int action, |
| char32_t character, |
| bool extended, |
| bool was_down, |
| KeyEventCallback callback) override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnComposeBegin() override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnComposeCommit() override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnComposeEnd() override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnComposeChange(const std::u16string& text, int cursor_pos) override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnScroll(double x, |
| double y, |
| double delta_x, |
| double delta_y, |
| int scroll_offset_multiplier, |
| FlutterPointerDeviceKind device_kind, |
| int32_t device_id) override; |
| |
| // |WindowBindingHandlerDelegate| |
| void OnScrollInertiaCancel(int32_t device_id) override; |
| |
| // |WindowBindingHandlerDelegate| |
| virtual void OnUpdateSemanticsEnabled(bool enabled) override; |
| |
| // |WindowBindingHandlerDelegate| |
| virtual gfx::NativeViewAccessible GetNativeViewAccessible() override; |
| |
| // Notifies the delegate of the updated the cursor rect in Flutter root view |
| // coordinates. |
| virtual void OnCursorRectUpdated(const Rect& rect); |
| |
| // Notifies the delegate that the system IME composing state should be reset. |
| virtual void OnResetImeComposing(); |
| |
| // Called when a WM_ONCOMPOSITIONCHANGED message is received. |
| void OnDwmCompositionChanged(); |
| |
| // Get a pointer to the alert node for this view. |
| ui::AXPlatformNodeWin* AlertNode() const; |
| |
| // |WindowBindingHandlerDelegate| |
| virtual ui::AXFragmentRootDelegateWin* GetAxFragmentRootDelegate() override; |
| |
| // Called to re/set the accessibility bridge pointer. |
| virtual void UpdateSemanticsEnabled(bool enabled); |
| |
| std::weak_ptr<AccessibilityBridgeWindows> accessibility_bridge() { |
| return accessibility_bridge_; |
| } |
| |
| // |WindowBindingHandlerDelegate| |
| void OnWindowStateEvent(HWND hwnd, WindowStateEvent event) override; |
| |
| protected: |
| virtual void NotifyWinEventWrapper(ui::AXPlatformNodeWin* node, |
| ax::mojom::Event event); |
| |
| // Create an AccessibilityBridgeWindows using this view. |
| virtual std::shared_ptr<AccessibilityBridgeWindows> |
| CreateAccessibilityBridge(); |
| |
| private: |
| // Allows setting the surface in tests. |
| friend class ViewModifier; |
| |
| // Struct holding the state of an individual pointer. The engine doesn't keep |
| // track of which buttons have been pressed, so it's the embedding's |
| // responsibility. |
| struct PointerState { |
| // The device kind. |
| FlutterPointerDeviceKind device_kind = kFlutterPointerDeviceKindMouse; |
| |
| // A virtual pointer ID that is unique across all device kinds. |
| int32_t pointer_id = 0; |
| |
| // True if the last event sent to Flutter had at least one button pressed. |
| bool flutter_state_is_down = false; |
| |
| // True if kAdd has been sent to Flutter. Used to determine whether |
| // to send a kAdd event before sending an incoming pointer event, since |
| // Flutter expects pointers to be added before events are sent for them. |
| bool flutter_state_is_added = false; |
| |
| // The currently pressed buttons, as represented in FlutterPointerEvent. |
| uint64_t buttons = 0; |
| |
| // The x position where the last pan/zoom started. |
| double pan_zoom_start_x = 0; |
| |
| // The y position where the last pan/zoom started. |
| double pan_zoom_start_y = 0; |
| }; |
| |
| // States a resize event can be in. |
| enum class ResizeState { |
| // When a resize event has started but is in progress. |
| kResizeStarted, |
| // After a resize event starts and the framework has been notified to |
| // generate a frame for the right size. |
| kFrameGenerated, |
| // Default state for when no resize is in progress. Also used to indicate |
| // that during a resize event, a frame with the right size has been rendered |
| // and the buffers have been swapped. |
| kDone, |
| }; |
| |
| // Resize the surface to the desired size. |
| // |
| // If the dimensions have changed, this destroys the original surface and |
| // creates a new one. |
| // |
| // This must be run on the raster thread. This binds the surface to the |
| // current thread. |
| // |
| // Width and height are the surface's desired physical pixel dimensions. |
| bool ResizeRenderSurface(size_t width, size_t height); |
| |
| // Sends a window metrics update to the Flutter engine using current window |
| // dimensions in physical pixels. |
| void SendWindowMetrics(size_t width, size_t height, double pixel_ratio) const; |
| |
| // Reports a mouse movement to Flutter engine. |
| void SendPointerMove(double x, double y, PointerState* state); |
| |
| // Reports mouse press to Flutter engine. |
| void SendPointerDown(double x, double y, PointerState* state); |
| |
| // Reports mouse release to Flutter engine. |
| void SendPointerUp(double x, double y, PointerState* state); |
| |
| // Reports mouse left the window client area. |
| // |
| // Win32 api doesn't have "mouse enter" event. Therefore, there is no |
| // SendPointerEnter method. A mouse enter event is tracked then the "move" |
| // event is called. |
| void SendPointerLeave(double x, double y, PointerState* state); |
| |
| void SendPointerPanZoomStart(int32_t device_id, double x, double y); |
| |
| void SendPointerPanZoomUpdate(int32_t device_id, |
| double pan_x, |
| double pan_y, |
| double scale, |
| double rotation); |
| |
| void SendPointerPanZoomEnd(int32_t device_id); |
| |
| // Reports a keyboard character to Flutter engine. |
| void SendText(const std::u16string&); |
| |
| // Reports a raw keyboard message to Flutter engine. |
| void SendKey(int key, |
| int scancode, |
| int action, |
| char32_t character, |
| bool extended, |
| bool was_down, |
| KeyEventCallback callback); |
| |
| // Reports an IME compose begin event. |
| // |
| // Triggered when the user begins editing composing text using a multi-step |
| // input method such as in CJK text input. |
| void SendComposeBegin(); |
| |
| // Reports an IME compose commit event. |
| // |
| // Triggered when the user commits the current composing text while using a |
| // multi-step input method such as in CJK text input. Composing continues with |
| // the next keypress. |
| void SendComposeCommit(); |
| |
| // Reports an IME compose end event. |
| // |
| // Triggered when the user commits the composing text while using a multi-step |
| // input method such as in CJK text input. |
| void SendComposeEnd(); |
| |
| // Reports an IME composing region change event. |
| // |
| // Triggered when the user edits the composing text while using a multi-step |
| // input method such as in CJK text input. |
| void SendComposeChange(const std::u16string& text, int cursor_pos); |
| |
| // Reports scroll wheel events to Flutter engine. |
| void SendScroll(double x, |
| double y, |
| double delta_x, |
| double delta_y, |
| int scroll_offset_multiplier, |
| FlutterPointerDeviceKind device_kind, |
| int32_t device_id); |
| |
| // Reports scroll inertia cancel events to Flutter engine. |
| void SendScrollInertiaCancel(int32_t device_id, double x, double y); |
| |
| // Creates a PointerState object unless it already exists. |
| PointerState* GetOrCreatePointerState(FlutterPointerDeviceKind device_kind, |
| int32_t device_id); |
| |
| // Sets |event_data|'s phase to either kMove or kHover depending on the |
| // current primary mouse button state. |
| void SetEventPhaseFromCursorButtonState(FlutterPointerEvent* event_data, |
| const PointerState* state) const; |
| |
| // Sends a pointer event to the Flutter engine based on given data. Since |
| // all input messages are passed in physical pixel values, no translation is |
| // needed before passing on to engine. |
| void SendPointerEventWithData(const FlutterPointerEvent& event_data, |
| PointerState* state); |
| |
| // If true, rendering to the window should synchronize with the vsync |
| // to prevent screen tearing. |
| bool NeedsVsync() const; |
| |
| // The view's unique identifier. |
| FlutterViewId view_id_; |
| |
| // The engine associated with this view. |
| FlutterWindowsEngine* engine_ = nullptr; |
| |
| // Mocks win32 APIs. |
| std::shared_ptr<WindowsProcTable> windows_proc_table_; |
| |
| // The EGL surface backing the view. |
| // |
| // Null if using software rasterization, the surface hasn't been created yet, |
| // or if surface creation failed. |
| std::unique_ptr<egl::WindowSurface> surface_ = nullptr; |
| |
| // Keeps track of pointer states in relation to the window. |
| std::unordered_map<int32_t, std::unique_ptr<PointerState>> pointer_states_; |
| |
| // Currently configured WindowBindingHandler for view. |
| std::unique_ptr<WindowBindingHandler> binding_handler_; |
| |
| // Resize events are synchronized using this mutex and the corresponding |
| // condition variable. |
| std::mutex resize_mutex_; |
| std::condition_variable resize_cv_; |
| |
| // Indicates the state of a window resize event. Platform thread will be |
| // blocked while this is not done. Guarded by resize_mutex_. |
| ResizeState resize_status_ = ResizeState::kDone; |
| |
| // Target for the window width. Valid when resize_pending_ is set. Guarded by |
| // resize_mutex_. |
| size_t resize_target_width_ = 0; |
| |
| // Target for the window width. Valid when resize_pending_ is set. Guarded by |
| // resize_mutex_. |
| size_t resize_target_height_ = 0; |
| |
| // True when flutter's semantics tree is enabled. |
| bool semantics_enabled_ = false; |
| |
| // The accessibility bridge associated with this view. |
| std::shared_ptr<AccessibilityBridgeWindows> accessibility_bridge_; |
| |
| FML_DISALLOW_COPY_AND_ASSIGN(FlutterWindowsView); |
| }; |
| |
| } // namespace flutter |
| |
| #endif // FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOWS_VIEW_H_ |