diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 057c045413f57..60751e774da1a 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1306,29 +1306,33 @@ FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flu FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h FILE: ../../../flutter/shell/platform/windows/client_wrapper/plugin_registrar_windows_unittests.cc -FILE: ../../../flutter/shell/platform/windows/dpi_utils.cc -FILE: ../../../flutter/shell/platform/windows/dpi_utils.h -FILE: ../../../flutter/shell/platform/windows/dpi_utils_unittests.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows.cc +FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.cc +FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.h FILE: ../../../flutter/shell/platform/windows/key_event_handler.cc FILE: ../../../flutter/shell/platform/windows/key_event_handler.h FILE: ../../../flutter/shell/platform/windows/keyboard_hook_handler.h -FILE: ../../../flutter/shell/platform/windows/platform_handler.cc -FILE: ../../../flutter/shell/platform/windows/platform_handler.h FILE: ../../../flutter/shell/platform/windows/public/flutter_windows.h FILE: ../../../flutter/shell/platform/windows/string_conversion.cc FILE: ../../../flutter/shell/platform/windows/string_conversion.h FILE: ../../../flutter/shell/platform/windows/string_conversion_unittests.cc FILE: ../../../flutter/shell/platform/windows/text_input_plugin.cc FILE: ../../../flutter/shell/platform/windows/text_input_plugin.h +FILE: ../../../flutter/shell/platform/windows/win32_dpi_utils.cc +FILE: ../../../flutter/shell/platform/windows/win32_dpi_utils.h +FILE: ../../../flutter/shell/platform/windows/win32_dpi_utils_unittests.cc FILE: ../../../flutter/shell/platform/windows/win32_flutter_window.cc FILE: ../../../flutter/shell/platform/windows/win32_flutter_window.h FILE: ../../../flutter/shell/platform/windows/win32_flutter_window_unittests.cc +FILE: ../../../flutter/shell/platform/windows/win32_platform_handler.cc +FILE: ../../../flutter/shell/platform/windows/win32_platform_handler.h FILE: ../../../flutter/shell/platform/windows/win32_task_runner.cc FILE: ../../../flutter/shell/platform/windows/win32_task_runner.h FILE: ../../../flutter/shell/platform/windows/win32_window.cc FILE: ../../../flutter/shell/platform/windows/win32_window.h FILE: ../../../flutter/shell/platform/windows/win32_window_unittests.cc +FILE: ../../../flutter/shell/platform/windows/window_binding_handler.h +FILE: ../../../flutter/shell/platform/windows/window_binding_handler_delegate.h FILE: ../../../flutter/shell/platform/windows/window_state.h FILE: ../../../flutter/shell/profiling/sampling_profiler.cc FILE: ../../../flutter/shell/profiling/sampling_profiler.h diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 248d3ccdc24c7..a5760a2522e6c 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -41,24 +41,28 @@ source_set("flutter_windows_source") { sources = [ "angle_surface_manager.cc", "angle_surface_manager.h", - "dpi_utils.cc", - "dpi_utils.h", "flutter_windows.cc", + "flutter_windows_view.cc", + "flutter_windows_view.h", "key_event_handler.cc", "key_event_handler.h", "keyboard_hook_handler.h", - "platform_handler.cc", - "platform_handler.h", "string_conversion.cc", "string_conversion.h", "text_input_plugin.cc", "text_input_plugin.h", + "win32_dpi_utils.cc", + "win32_dpi_utils.h", "win32_flutter_window.cc", "win32_flutter_window.h", + "win32_platform_handler.cc", + "win32_platform_handler.h", "win32_task_runner.cc", "win32_task_runner.h", "win32_window.cc", "win32_window.h", + "window_binding_handler.h", + "window_binding_handler_delegate.h", "window_state.h", ] @@ -110,12 +114,12 @@ executable("flutter_windows_unittests") { testonly = true sources = [ - "dpi_utils_unittests.cc", "string_conversion_unittests.cc", "testing/win32_flutter_window_test.cc", "testing/win32_flutter_window_test.h", "testing/win32_window_test.cc", "testing/win32_window_test.h", + "win32_dpi_utils_unittests.cc", "win32_flutter_window_unittests.cc", "win32_window_unittests.cc", ] diff --git a/shell/platform/windows/angle_surface_manager.cc b/shell/platform/windows/angle_surface_manager.cc index df520d37680b7..cc046281e8114 100644 --- a/shell/platform/windows/angle_surface_manager.cc +++ b/shell/platform/windows/angle_surface_manager.cc @@ -169,46 +169,52 @@ void AngleSurfaceManager::CleanUp() { } } -EGLSurface AngleSurfaceManager::CreateSurface(HWND window) { - if (!window || !initialize_succeeded_) { - return EGL_NO_SURFACE; +bool AngleSurfaceManager::CreateSurface(WindowsRenderTarget* render_target) { + if (!render_target || !initialize_succeeded_) { + return false; } EGLSurface surface = EGL_NO_SURFACE; const EGLint surfaceAttributes[] = {EGL_NONE}; - surface = eglCreateWindowSurface(egl_display_, egl_config_, - static_cast(window), - surfaceAttributes); + surface = eglCreateWindowSurface( + egl_display_, egl_config_, + static_cast(std::get(*render_target)), + surfaceAttributes); if (surface == EGL_NO_SURFACE) { std::cerr << "Surface creation failed." << std::endl; } - return surface; + render_surface_ = surface; + return true; } -void AngleSurfaceManager::GetSurfaceDimensions(const EGLSurface surface, - EGLint* width, - EGLint* height) { - if (surface == EGL_NO_SURFACE || !initialize_succeeded_) { +void AngleSurfaceManager::GetSurfaceDimensions(EGLint* width, EGLint* height) { + if (render_surface_ == EGL_NO_SURFACE || !initialize_succeeded_) { width = 0; height = 0; return; } - eglQuerySurface(egl_display_, surface, EGL_WIDTH, width); - eglQuerySurface(egl_display_, surface, EGL_HEIGHT, height); + eglQuerySurface(egl_display_, render_surface_, EGL_WIDTH, width); + eglQuerySurface(egl_display_, render_surface_, EGL_HEIGHT, height); } -void AngleSurfaceManager::DestroySurface(const EGLSurface surface) { - if (egl_display_ != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE) { - eglDestroySurface(egl_display_, surface); +void AngleSurfaceManager::DestroySurface() { + if (egl_display_ != EGL_NO_DISPLAY && render_surface_ != EGL_NO_SURFACE) { + eglDestroySurface(egl_display_, render_surface_); } + render_surface_ = EGL_NO_SURFACE; +} + +bool AngleSurfaceManager::MakeCurrent() { + return (eglMakeCurrent(egl_display_, render_surface_, render_surface_, + egl_context_) == EGL_TRUE); } -bool AngleSurfaceManager::MakeCurrent(const EGLSurface surface) { - return (eglMakeCurrent(egl_display_, surface, surface, egl_context_) == +bool AngleSurfaceManager::ClearContext() { + return (eglMakeCurrent(egl_display_, nullptr, nullptr, egl_context_) == EGL_TRUE); } @@ -217,8 +223,8 @@ bool AngleSurfaceManager::MakeResourceCurrent() { egl_resource_context_) == EGL_TRUE); } -EGLBoolean AngleSurfaceManager::SwapBuffers(const EGLSurface surface) { - return (eglSwapBuffers(egl_display_, surface)); +EGLBoolean AngleSurfaceManager::SwapBuffers() { + return (eglSwapBuffers(egl_display_, render_surface_)); } } // namespace flutter diff --git a/shell/platform/windows/angle_surface_manager.h b/shell/platform/windows/angle_surface_manager.h index 21c0648203a73..a6a5fc213c3d4 100644 --- a/shell/platform/windows/angle_surface_manager.h +++ b/shell/platform/windows/angle_surface_manager.h @@ -15,9 +15,11 @@ // Windows platform specific includes #include +#include "window_binding_handler.h" + namespace flutter { -// An manager for inializing ANGLE correctly and using it to create and +// A manager for inializing ANGLE correctly and using it to create and // destroy surfaces class AngleSurfaceManager { public: @@ -28,23 +30,24 @@ class AngleSurfaceManager { AngleSurfaceManager(const AngleSurfaceManager&) = delete; AngleSurfaceManager& operator=(const AngleSurfaceManager&) = delete; - // Creates and returns an EGLSurface wrapper and backing DirectX 11 SwapChain - // asociated with window, in the appropriate format for display in a - // HWND-backed window. - EGLSurface CreateSurface(HWND window); + // Creates an EGLSurface wrapper and backing DirectX 11 SwapChain + // asociated with window, in the appropriate format for display. + // Target represents the visual entity to bind to. + bool CreateSurface(WindowsRenderTarget* render_target); // queries EGL for the dimensions of surface in physical // pixels returning width and height as out params. - void GetSurfaceDimensions(const EGLSurface surface, - EGLint* width, - EGLint* height); + void GetSurfaceDimensions(EGLint* width, EGLint* height); // Releases the pass-in EGLSurface wrapping and backing resources if not null. - void DestroySurface(const EGLSurface surface); + void DestroySurface(); // Binds egl_context_ to the current rendering thread and to the draw and read // surfaces returning a boolean result reflecting success. - bool MakeCurrent(const EGLSurface surface); + bool MakeCurrent(); + + // Clears current egl_context_ + bool ClearContext(); // Binds egl_resource_context_ to the current rendering thread and to the draw // and read surfaces returning a boolean result reflecting success. @@ -52,7 +55,7 @@ class AngleSurfaceManager { // Swaps the front and back buffers of the DX11 swapchain backing surface if // not null. - EGLBoolean SwapBuffers(const EGLSurface surface); + EGLBoolean SwapBuffers(); private: bool Initialize(); @@ -75,6 +78,9 @@ class AngleSurfaceManager { // State representing success or failure of display initialization used when // creating surfaces. bool initialize_succeeded_; + + // Current render_surface that engine will draw into. + EGLSurface render_surface_ = EGL_NO_SURFACE; }; } // namespace flutter diff --git a/shell/platform/windows/flutter_windows.cc b/shell/platform/windows/flutter_windows.cc index 52319db72d52b..b3dec79eb20cd 100644 --- a/shell/platform/windows/flutter_windows.cc +++ b/shell/platform/windows/flutter_windows.cc @@ -19,13 +19,15 @@ #include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h" #include "flutter/shell/platform/common/cpp/path_utils.h" #include "flutter/shell/platform/embedder/embedder.h" -#include "flutter/shell/platform/windows/dpi_utils.h" +#include "flutter/shell/platform/windows/flutter_windows_view.h" #include "flutter/shell/platform/windows/key_event_handler.h" #include "flutter/shell/platform/windows/keyboard_hook_handler.h" -#include "flutter/shell/platform/windows/platform_handler.h" #include "flutter/shell/platform/windows/text_input_plugin.h" +#include "flutter/shell/platform/windows/win32_dpi_utils.h" #include "flutter/shell/platform/windows/win32_flutter_window.h" +#include "flutter/shell/platform/windows/win32_platform_handler.h" #include "flutter/shell/platform/windows/win32_task_runner.h" +#include "flutter/shell/platform/windows/window_binding_handler.h" #include "flutter/shell/platform/windows/window_state.h" static_assert(FLUTTER_ENGINE_VERSION == 1, ""); @@ -66,7 +68,7 @@ UniqueAotDataPtr LoadAotData(std::filesystem::path aot_data_path) { // Returns the state object for the engine, or null on failure to start the // engine. static std::unique_ptr RunFlutterEngine( - flutter::Win32FlutterWindow* window, + flutter::FlutterWindowsView* view, const FlutterDesktopEngineProperties& engine_properties) { auto state = std::make_unique(); @@ -79,22 +81,22 @@ static std::unique_ptr RunFlutterEngine( &engine_properties.switches[engine_properties.switches_count]); } - window->CreateRenderSurface(); + view->CreateRenderSurface(); // Provide the necessary callbacks for rendering within a win32 child window. FlutterRendererConfig config = {}; config.type = kOpenGL; config.open_gl.struct_size = sizeof(config.open_gl); config.open_gl.make_current = [](void* user_data) -> bool { - auto host = static_cast(user_data); + auto host = static_cast(user_data); return host->MakeCurrent(); }; config.open_gl.clear_current = [](void* user_data) -> bool { - auto host = static_cast(user_data); + auto host = static_cast(user_data); return host->ClearContext(); }; config.open_gl.present = [](void* user_data) -> bool { - auto host = static_cast(user_data); + auto host = static_cast(user_data); return host->SwapBuffers(); }; config.open_gl.fbo_callback = [](void* user_data) -> uint32_t { return 0; }; @@ -103,7 +105,7 @@ static std::unique_ptr RunFlutterEngine( return reinterpret_cast(eglGetProcAddress(what)); }; config.open_gl.make_resource_current = [](void* user_data) -> bool { - auto host = static_cast(user_data); + auto host = static_cast(user_data); return host->MakeResourceCurrent(); }; @@ -178,7 +180,7 @@ static std::unique_ptr RunFlutterEngine( args.platform_message_callback = [](const FlutterPlatformMessage* engine_message, void* user_data) -> void { - auto window = reinterpret_cast(user_data); + auto window = reinterpret_cast(user_data); return window->HandlePlatformMessage(engine_message); }; args.custom_task_runners = &custom_task_runners; @@ -188,7 +190,7 @@ static std::unique_ptr RunFlutterEngine( FLUTTER_API_SYMBOL(FlutterEngine) engine = nullptr; auto result = - FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, &args, window, &engine); + FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, &args, view, &engine); if (result != kSuccess || engine == nullptr) { std::cerr << "Failed to start Flutter engine: error " << result << std::endl; @@ -202,8 +204,12 @@ FlutterDesktopViewControllerRef FlutterDesktopCreateViewController( int width, int height, const FlutterDesktopEngineProperties& engine_properties) { + std::unique_ptr window_wrapper = + std::make_unique(width, height); + FlutterDesktopViewControllerRef state = - flutter::Win32FlutterWindow::CreateWin32FlutterWindow(width, height); + flutter::FlutterWindowsView::CreateFlutterWindowsView( + std::move(window_wrapper)); auto engine_state = RunFlutterEngine(state->view.get(), engine_properties); @@ -261,8 +267,8 @@ FlutterDesktopViewRef FlutterDesktopGetView( return controller->view_wrapper.get(); } -HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view) { - return view->window->GetWindowHandle(); +HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view_ref) { + return std::get(*view_ref->view->GetRenderTarget()); } UINT FlutterDesktopGetDpiForHWND(HWND hwnd) { @@ -316,7 +322,7 @@ void FlutterDesktopRegistrarSetDestructionHandler( FlutterDesktopViewRef FlutterDesktopRegistrarGetView( FlutterDesktopPluginRegistrarRef registrar) { - return registrar->window; + return registrar->view; } bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger, diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc new file mode 100644 index 0000000000000..4f6f55e12dc58 --- /dev/null +++ b/shell/platform/windows/flutter_windows_view.cc @@ -0,0 +1,334 @@ +#include "flutter/shell/platform/windows/flutter_windows_view.h" + +#include + +namespace flutter { + +FlutterWindowsView::FlutterWindowsView() { + surface_manager_ = std::make_unique(); +} + +FlutterWindowsView::~FlutterWindowsView() { + DestroyRenderSurface(); + if (plugin_registrar_ && plugin_registrar_->destruction_handler) { + plugin_registrar_->destruction_handler(plugin_registrar_.get()); + } +} + +FlutterDesktopViewControllerRef FlutterWindowsView::CreateFlutterWindowsView( + std::unique_ptr windowbinding) { + auto state = std::make_unique(); + state->view = std::make_unique(); + + // FlutterWindowsView instance owns windowbinding + state->view->binding_handler_ = std::move(windowbinding); + + // a window wrapper for the state block, distinct from the + // window_wrapper handed to plugin_registrar. + state->view_wrapper = std::make_unique(); + + // Give the binding handler a pointer back to this | FlutterWindowsView | + state->view->binding_handler_->SetView(state->view.get()); + + // opaque pointer to FlutterWindowsView + state->view_wrapper->view = state->view.get(); + + state->view->render_target_ = std::make_unique( + state->view->binding_handler_->GetRenderTarget()); + + return state.release(); +} + +void FlutterWindowsView::SetState(FLUTTER_API_SYMBOL(FlutterEngine) eng) { + engine_ = eng; + + auto messenger = std::make_unique(); + message_dispatcher_ = + std::make_unique(messenger.get()); + messenger->engine = engine_; + messenger->dispatcher = message_dispatcher_.get(); + + window_wrapper_ = std::make_unique(); + window_wrapper_->view = this; + plugin_registrar_ = std::make_unique(); + plugin_registrar_->messenger = std::move(messenger); + plugin_registrar_->view = window_wrapper_.get(); + + internal_plugin_registrar_ = + std::make_unique(plugin_registrar_.get()); + + // Set up the keyboard handlers. + auto internal_plugin_messenger = internal_plugin_registrar_->messenger(); + keyboard_hook_handlers_.push_back( + std::make_unique(internal_plugin_messenger)); + keyboard_hook_handlers_.push_back( + std::make_unique(internal_plugin_messenger)); + platform_handler_ = std::make_unique( + internal_plugin_messenger, this); + + PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds(); + + SendWindowMetrics(bounds.width, bounds.height, + binding_handler_->GetDpiScale()); +} + +FlutterDesktopPluginRegistrarRef FlutterWindowsView::GetRegistrar() { + return plugin_registrar_.get(); +} + +// Converts a FlutterPlatformMessage to an equivalent FlutterDesktopMessage. +static FlutterDesktopMessage ConvertToDesktopMessage( + const FlutterPlatformMessage& engine_message) { + FlutterDesktopMessage message = {}; + message.struct_size = sizeof(message); + message.channel = engine_message.channel; + message.message = engine_message.message; + message.message_size = engine_message.message_size; + message.response_handle = engine_message.response_handle; + return message; +} + +// The Flutter Engine calls out to this function when new platform messages +// are available. +void FlutterWindowsView::HandlePlatformMessage( + const FlutterPlatformMessage* engine_message) { + if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) { + std::cerr << "Invalid message size received. Expected: " + << sizeof(FlutterPlatformMessage) << " but received " + << engine_message->struct_size << std::endl; + return; + } + + auto message = ConvertToDesktopMessage(*engine_message); + + message_dispatcher_->HandleMessage( + message, [this] {}, [this] {}); +} + +void FlutterWindowsView::OnWindowSizeChanged(size_t width, + size_t height) const { + SendWindowMetrics(width, height, binding_handler_->GetDpiScale()); +} + +void FlutterWindowsView::OnPointerMove(double x, double y) { + SendPointerMove(x, y); +} + +void FlutterWindowsView::OnPointerDown( + double x, + double y, + FlutterPointerMouseButtons flutter_button) { + if (flutter_button != 0) { + uint64_t mouse_buttons = mouse_state_.buttons | flutter_button; + SetMouseButtons(mouse_buttons); + SendPointerDown(x, y); + } +} + +void FlutterWindowsView::OnPointerUp( + double x, + double y, + FlutterPointerMouseButtons flutter_button) { + if (flutter_button != 0) { + uint64_t mouse_buttons = mouse_state_.buttons & ~flutter_button; + SetMouseButtons(mouse_buttons); + SendPointerUp(x, y); + } +} + +void FlutterWindowsView::OnPointerLeave() { + SendPointerLeave(); +} + +void FlutterWindowsView::OnText(const std::u16string& text) { + SendText(text); +} + +void FlutterWindowsView::OnKey(int key, + int scancode, + int action, + char32_t character) { + SendKey(key, scancode, action, character); +} + +void FlutterWindowsView::OnScroll(double x, + double y, + double delta_x, + double delta_y, + int scroll_offset_multiplier) { + SendScroll(x, y, delta_x, delta_y, scroll_offset_multiplier); +} + +void FlutterWindowsView::OnFontChange() { + if (engine_ == nullptr) { + return; + } + FlutterEngineReloadSystemFonts(engine_); +} + +// Sends new size information to FlutterEngine. +void FlutterWindowsView::SendWindowMetrics(size_t width, + size_t height, + double dpiScale) const { + if (engine_ == nullptr) { + return; + } + + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(event); + event.width = width; + event.height = height; + event.pixel_ratio = dpiScale; + auto result = FlutterEngineSendWindowMetricsEvent(engine_, &event); +} + +// Set's |event_data|'s phase to either kMove or kHover depending on the current +// primary mouse button state. +void FlutterWindowsView::SetEventPhaseFromCursorButtonState( + FlutterPointerEvent* event_data) const { + // For details about this logic, see FlutterPointerPhase in the embedder.h + // file. + event_data->phase = + mouse_state_.buttons == 0 + ? mouse_state_.flutter_state_is_down ? FlutterPointerPhase::kUp + : FlutterPointerPhase::kHover + : mouse_state_.flutter_state_is_down ? FlutterPointerPhase::kMove + : FlutterPointerPhase::kDown; +} + +void FlutterWindowsView::SendPointerMove(double x, double y) { + FlutterPointerEvent event = {}; + event.x = x; + event.y = y; + SetEventPhaseFromCursorButtonState(&event); + SendPointerEventWithData(event); +} + +void FlutterWindowsView::SendPointerDown(double x, double y) { + FlutterPointerEvent event = {}; + SetEventPhaseFromCursorButtonState(&event); + event.x = x; + event.y = y; + SendPointerEventWithData(event); + SetMouseFlutterStateDown(true); +} + +void FlutterWindowsView::SendPointerUp(double x, double y) { + FlutterPointerEvent event = {}; + SetEventPhaseFromCursorButtonState(&event); + event.x = x; + event.y = y; + SendPointerEventWithData(event); + if (event.phase == FlutterPointerPhase::kUp) { + SetMouseFlutterStateDown(false); + } +} + +void FlutterWindowsView::SendPointerLeave() { + FlutterPointerEvent event = {}; + event.phase = FlutterPointerPhase::kRemove; + SendPointerEventWithData(event); +} + +void FlutterWindowsView::SendText(const std::u16string& text) { + for (const auto& handler : keyboard_hook_handlers_) { + handler->TextHook(this, text); + } +} + +void FlutterWindowsView::SendKey(int key, + int scancode, + int action, + char32_t character) { + for (const auto& handler : keyboard_hook_handlers_) { + handler->KeyboardHook(this, key, scancode, action, character); + } +} + +void FlutterWindowsView::SendScroll(double x, + double y, + double delta_x, + double delta_y, + int scroll_offset_multiplier) { + FlutterPointerEvent event = {}; + SetEventPhaseFromCursorButtonState(&event); + event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll; + event.x = x; + event.y = y; + event.scroll_delta_x = delta_x * scroll_offset_multiplier; + event.scroll_delta_y = delta_y * scroll_offset_multiplier; + SendPointerEventWithData(event); +} + +void FlutterWindowsView::SendPointerEventWithData( + const FlutterPointerEvent& event_data) { + // If sending anything other than an add, and the pointer isn't already added, + // synthesize an add to satisfy Flutter's expectations about events. + if (!mouse_state_.flutter_state_is_added && + event_data.phase != FlutterPointerPhase::kAdd) { + FlutterPointerEvent event = {}; + event.phase = FlutterPointerPhase::kAdd; + event.x = event_data.x; + event.y = event_data.y; + event.buttons = 0; + SendPointerEventWithData(event); + } + // Don't double-add (e.g., if events are delivered out of order, so an add has + // already been synthesized). + if (mouse_state_.flutter_state_is_added && + event_data.phase == FlutterPointerPhase::kAdd) { + return; + } + + FlutterPointerEvent event = event_data; + event.device_kind = kFlutterPointerDeviceKindMouse; + event.buttons = mouse_state_.buttons; + + // Set metadata that's always the same regardless of the event. + event.struct_size = sizeof(event); + event.timestamp = + std::chrono::duration_cast( + std::chrono::high_resolution_clock::now().time_since_epoch()) + .count(); + + FlutterEngineSendPointerEvent(engine_, &event, 1); + + if (event_data.phase == FlutterPointerPhase::kAdd) { + SetMouseFlutterStateAdded(true); + } else if (event_data.phase == FlutterPointerPhase::kRemove) { + SetMouseFlutterStateAdded(false); + ResetMouseState(); + } +} + +bool FlutterWindowsView::MakeCurrent() { + return surface_manager_->MakeCurrent(); +} + +bool FlutterWindowsView::MakeResourceCurrent() { + return surface_manager_->MakeResourceCurrent(); +} + +bool FlutterWindowsView::ClearContext() { + return surface_manager_->ClearContext(); +} + +bool FlutterWindowsView::SwapBuffers() { + return surface_manager_->SwapBuffers(); +} + +void FlutterWindowsView::CreateRenderSurface() { + surface_manager_->CreateSurface(render_target_.get()); +} + +void FlutterWindowsView::DestroyRenderSurface() { + if (surface_manager_) { + surface_manager_->DestroySurface(); + } +} + +WindowsRenderTarget* FlutterWindowsView::GetRenderTarget() { + return render_target_.get(); +} + +} // namespace flutter diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h new file mode 100644 index 0000000000000..9a7b0994d2438 --- /dev/null +++ b/shell/platform/windows/flutter_windows_view.h @@ -0,0 +1,222 @@ +// 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 + +#include +#include + +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h" +#include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h" +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/windows/angle_surface_manager.h" +#include "flutter/shell/platform/windows/key_event_handler.h" +#include "flutter/shell/platform/windows/keyboard_hook_handler.h" +#include "flutter/shell/platform/windows/public/flutter_windows.h" +#include "flutter/shell/platform/windows/text_input_plugin.h" +#include "flutter/shell/platform/windows/win32_platform_handler.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" + +namespace flutter { + +// An OS-windowing neutral abstration for flutter +// view that works with win32 hwnds and Windows::UI::Composition visuals. +class FlutterWindowsView : public WindowBindingHandlerDelegate { + public: + FlutterWindowsView(); + + ~FlutterWindowsView(); + + // Factory for creating FlutterWindowsView requiring an implementator of + // WindowBindingHandler. In order for object to render Flutter content + // the SetState method must be called with a valid FlutterEngine instance. + static FlutterDesktopViewControllerRef CreateFlutterWindowsView( + std::unique_ptr window_binding); + + // Configures the window instance with an instance of a running Flutter + // engine. + void SetState(FLUTTER_API_SYMBOL(FlutterEngine) state); + + // Returns the currently configured Plugin Registrar. + FlutterDesktopPluginRegistrarRef GetRegistrar(); + + // Callback passed to Flutter engine for notifying window of platform + // messages. + void HandlePlatformMessage(const FlutterPlatformMessage*); + + // Creates rendering surface for Flutter engine to draw into. + // Should be called before calling FlutterEngineRun using this view. + void CreateRenderSurface(); + + // Destroys current rendering surface if one has been allocated. + void DestroyRenderSurface(); + + // Return the currently configured WindowsRenderTarget. + WindowsRenderTarget* GetRenderTarget(); + + // Callbacks for clearing context, settings context and swapping buffers. + bool ClearContext(); + bool MakeCurrent(); + bool MakeResourceCurrent(); + bool SwapBuffers(); + + // |WindowBindingHandlerDelegate| + void OnWindowSizeChanged(size_t width, size_t height) const override; + + // |WindowBindingHandlerDelegate| + void OnPointerMove(double x, double y) override; + + // |WindowBindingHandlerDelegate| + void OnPointerDown(double x, + double y, + FlutterPointerMouseButtons button) override; + + // |WindowBindingHandlerDelegate| + void OnPointerUp(double x, + double y, + FlutterPointerMouseButtons button) override; + + // |WindowBindingHandlerDelegate| + void OnPointerLeave() override; + + // |WindowBindingHandlerDelegate| + void OnText(const std::u16string&) override; + + // |WindowBindingHandlerDelegate| + void OnKey(int key, int scancode, int action, char32_t character) override; + + // |WindowBindingHandlerDelegate| + void OnScroll(double x, + double y, + double delta_x, + double delta_y, + int scroll_offset_multiplier) override; + + // |WindowBindingHandlerDelegate| + void OnFontChange() override; + + private: + // Struct holding the mouse state. The engine doesn't keep track of which + // mouse buttons have been pressed, so it's the embedding's responsibility. + struct MouseState { + // True if the last event sent to Flutter had at least one mouse 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 mouse 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; + }; + + // Sends a window metrics update to the Flutter engine using current window + // dimensions in physical + void SendWindowMetrics(size_t width, size_t height, double dpiscale) const; + + // Reports a mouse movement to Flutter engine. + void SendPointerMove(double x, double y); + + // Reports mouse press to Flutter engine. + void SendPointerDown(double x, double y); + + // Reports mouse release to Flutter engine. + void SendPointerUp(double x, double y); + + // 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(); + + // 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); + + // Reports scroll wheel events to Flutter engine. + void SendScroll(double x, + double y, + double delta_x, + double delta_y, + int scroll_offset_multiplier); + + // Sets |event_data|'s phase to either kMove or kHover depending on the + // current primary mouse button state. + void SetEventPhaseFromCursorButtonState( + FlutterPointerEvent* event_data) 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); + + // Resets the mouse state to its default values. + void ResetMouseState() { mouse_state_ = MouseState(); } + + // Updates the mouse state to whether the last event to Flutter had at least + // one mouse button pressed. + void SetMouseFlutterStateDown(bool is_down) { + mouse_state_.flutter_state_is_down = is_down; + } + + // Updates the mouse state to whether the last event to Flutter was a kAdd + // event. + void SetMouseFlutterStateAdded(bool is_added) { + mouse_state_.flutter_state_is_added = is_added; + } + + // Updates the currently pressed buttons. + void SetMouseButtons(uint64_t buttons) { mouse_state_.buttons = buttons; } + + // Currently configured WindowsRenderTarget for this view used by + // surface_manager for creation of render surfaces and bound to the physical + // os window. + std::unique_ptr render_target_; + + // An object used for intializing Angle and creating / destroying render + // surfaces. Surface creation functionality requires a valid render_target. + std::unique_ptr surface_manager_; + + // The handle to the Flutter engine instance. + FLUTTER_API_SYMBOL(FlutterEngine) engine_ = nullptr; + + // Keeps track of mouse state in relation to the window. + MouseState mouse_state_; + + // The window handle given to API clients. + std::unique_ptr window_wrapper_; + + // The plugin registrar handle given to API clients. + std::unique_ptr plugin_registrar_; + + // Message dispatch manager for messages from the Flutter engine. + std::unique_ptr message_dispatcher_; + + // The plugin registrar managing internal plugins. + std::unique_ptr internal_plugin_registrar_; + + // Handlers for keyboard events from Windows. + std::vector> + keyboard_hook_handlers_; + + // Handler for the flutter/platform channel. + std::unique_ptr platform_handler_; + + // Currently configured WindowBindingHandler for view. + std::unique_ptr binding_handler_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_FLUTTER_WINDOWS_VIEW_H_ diff --git a/shell/platform/windows/key_event_handler.cc b/shell/platform/windows/key_event_handler.cc index 3747a9f5a05a0..9b562f8f0944e 100644 --- a/shell/platform/windows/key_event_handler.cc +++ b/shell/platform/windows/key_event_handler.cc @@ -92,10 +92,10 @@ KeyEventHandler::KeyEventHandler(flutter::BinaryMessenger* messenger) KeyEventHandler::~KeyEventHandler() = default; -void KeyEventHandler::TextHook(Win32FlutterWindow* window, +void KeyEventHandler::TextHook(FlutterWindowsView* view, const std::u16string& code_point) {} -void KeyEventHandler::KeyboardHook(Win32FlutterWindow* window, +void KeyEventHandler::KeyboardHook(FlutterWindowsView* view, int key, int scancode, int action, diff --git a/shell/platform/windows/key_event_handler.h b/shell/platform/windows/key_event_handler.h index 6e9a77f1d3514..9a1b2752288e9 100644 --- a/shell/platform/windows/key_event_handler.h +++ b/shell/platform/windows/key_event_handler.h @@ -16,7 +16,7 @@ namespace flutter { -class Win32FlutterWindow; +class FlutterWindowsView; // Implements a KeyboardHookHandler // @@ -28,14 +28,14 @@ class KeyEventHandler : public KeyboardHookHandler { virtual ~KeyEventHandler(); // |KeyboardHookHandler| - void KeyboardHook(Win32FlutterWindow* window, + void KeyboardHook(FlutterWindowsView* window, int key, int scancode, int action, char32_t character) override; // |KeyboardHookHandler| - void TextHook(Win32FlutterWindow* window, + void TextHook(FlutterWindowsView* window, const std::u16string& text) override; private: diff --git a/shell/platform/windows/keyboard_hook_handler.h b/shell/platform/windows/keyboard_hook_handler.h index aa574a545d64e..b36ad3a6d7d82 100644 --- a/shell/platform/windows/keyboard_hook_handler.h +++ b/shell/platform/windows/keyboard_hook_handler.h @@ -11,7 +11,7 @@ namespace flutter { -class Win32FlutterWindow; +class FlutterWindowsView; // Abstract class for handling keyboard input events. class KeyboardHookHandler { @@ -19,14 +19,14 @@ class KeyboardHookHandler { virtual ~KeyboardHookHandler() = default; // A function for hooking into keyboard input. - virtual void KeyboardHook(Win32FlutterWindow* window, + virtual void KeyboardHook(FlutterWindowsView* view, int key, int scancode, int action, char32_t character) = 0; // A function for hooking into Unicode text input. - virtual void TextHook(Win32FlutterWindow* window, + virtual void TextHook(FlutterWindowsView* view, const std::u16string& text) = 0; }; diff --git a/shell/platform/windows/text_input_plugin.cc b/shell/platform/windows/text_input_plugin.cc index 7f3127a286448..46849b0672d44 100644 --- a/shell/platform/windows/text_input_plugin.cc +++ b/shell/platform/windows/text_input_plugin.cc @@ -43,7 +43,7 @@ static constexpr char kInternalConsistencyError[] = namespace flutter { -void TextInputPlugin::TextHook(Win32FlutterWindow* window, +void TextInputPlugin::TextHook(FlutterWindowsView* view, const std::u16string& text) { if (active_model_ == nullptr) { return; @@ -52,7 +52,7 @@ void TextInputPlugin::TextHook(Win32FlutterWindow* window, SendStateUpdate(*active_model_); } -void TextInputPlugin::KeyboardHook(Win32FlutterWindow* window, +void TextInputPlugin::KeyboardHook(FlutterWindowsView* view, int key, int scancode, int action, diff --git a/shell/platform/windows/text_input_plugin.h b/shell/platform/windows/text_input_plugin.h index 5acdaf25de6f0..c0b2452ecd310 100644 --- a/shell/platform/windows/text_input_plugin.h +++ b/shell/platform/windows/text_input_plugin.h @@ -17,7 +17,7 @@ namespace flutter { -class Win32FlutterWindow; +class FlutterWindowsView; // Implements a text input plugin. // @@ -29,15 +29,14 @@ class TextInputPlugin : public KeyboardHookHandler { virtual ~TextInputPlugin(); // |KeyboardHookHandler| - void KeyboardHook(Win32FlutterWindow* window, + void KeyboardHook(FlutterWindowsView* view, int key, int scancode, int action, char32_t character) override; // |KeyboardHookHandler| - void TextHook(Win32FlutterWindow* window, - const std::u16string& text) override; + void TextHook(FlutterWindowsView* view, const std::u16string& text) override; private: // Sends the current state of the given model to the Flutter engine. diff --git a/shell/platform/windows/dpi_utils.cc b/shell/platform/windows/win32_dpi_utils.cc similarity index 99% rename from shell/platform/windows/dpi_utils.cc rename to shell/platform/windows/win32_dpi_utils.cc index 20b706ef2fa95..8fe994c463b18 100644 --- a/shell/platform/windows/dpi_utils.cc +++ b/shell/platform/windows/win32_dpi_utils.cc @@ -1,4 +1,4 @@ -#include "dpi_utils.h" +#include "win32_dpi_utils.h" namespace flutter { diff --git a/shell/platform/windows/dpi_utils.h b/shell/platform/windows/win32_dpi_utils.h similarity index 100% rename from shell/platform/windows/dpi_utils.h rename to shell/platform/windows/win32_dpi_utils.h diff --git a/shell/platform/windows/dpi_utils_unittests.cc b/shell/platform/windows/win32_dpi_utils_unittests.cc similarity index 89% rename from shell/platform/windows/dpi_utils_unittests.cc rename to shell/platform/windows/win32_dpi_utils_unittests.cc index d69da0588827b..90a580bb95318 100644 --- a/shell/platform/windows/dpi_utils_unittests.cc +++ b/shell/platform/windows/win32_dpi_utils_unittests.cc @@ -1,6 +1,6 @@ #include -#include "flutter/shell/platform/windows/dpi_utils.h" +#include "flutter/shell/platform/windows/win32_dpi_utils.h" #include "gtest/gtest.h" namespace flutter { diff --git a/shell/platform/windows/win32_flutter_window.cc b/shell/platform/windows/win32_flutter_window.cc index 4976a70b064d0..a05e5ebfa3c23 100644 --- a/shell/platform/windows/win32_flutter_window.cc +++ b/shell/platform/windows/win32_flutter_window.cc @@ -8,76 +8,31 @@ namespace flutter { // constant for machines running at 100% scaling. constexpr int base_dpi = 96; -Win32FlutterWindow::Win32FlutterWindow(int width, int height) { - surface_manager = std::make_unique(); - Win32Window::InitializeChild("FLUTTERVIEW", width, height); -} +// TODO: See if this can be queried from the OS; this value is chosen +// arbitrarily to get something that feels reasonable. +constexpr int kScrollOffsetMultiplier = 20; -Win32FlutterWindow::~Win32FlutterWindow() { - DestroyRenderSurface(); - if (plugin_registrar_ && plugin_registrar_->destruction_handler) { - plugin_registrar_->destruction_handler(plugin_registrar_.get()); - } +Win32FlutterWindow::Win32FlutterWindow(int width, int height) + : binding_handler_delegate_(nullptr) { + Win32Window::InitializeChild("FLUTTERVIEW", width, height); } -FlutterDesktopViewControllerRef Win32FlutterWindow::CreateWin32FlutterWindow( - const int width, - const int height) { - auto state = std::make_unique(); - state->view = std::make_unique(width, height); +Win32FlutterWindow::~Win32FlutterWindow() {} - // a window wrapper for the state block, distinct from the - // window_wrapper handed to plugin_registrar. - state->view_wrapper = std::make_unique(); - state->view_wrapper->window = state->view.get(); - return state.release(); +void Win32FlutterWindow::SetView(WindowBindingHandlerDelegate* window) { + binding_handler_delegate_ = window; } -void Win32FlutterWindow::SetState(FLUTTER_API_SYMBOL(FlutterEngine) eng) { - engine_ = eng; - - auto messenger = std::make_unique(); - message_dispatcher_ = - std::make_unique(messenger.get()); - messenger->engine = engine_; - messenger->dispatcher = message_dispatcher_.get(); - - window_wrapper_ = std::make_unique(); - window_wrapper_->window = this; - - plugin_registrar_ = std::make_unique(); - plugin_registrar_->messenger = std::move(messenger); - plugin_registrar_->window = window_wrapper_.get(); - - internal_plugin_registrar_ = - std::make_unique(plugin_registrar_.get()); - - // Set up the keyboard handlers. - auto internal_plugin_messenger = internal_plugin_registrar_->messenger(); - keyboard_hook_handlers_.push_back( - std::make_unique(internal_plugin_messenger)); - keyboard_hook_handlers_.push_back( - std::make_unique(internal_plugin_messenger)); - platform_handler_ = std::make_unique( - internal_plugin_messenger, this); - - process_events_ = true; +WindowsRenderTarget Win32FlutterWindow::GetRenderTarget() { + return WindowsRenderTarget(GetWindowHandle()); } -FlutterDesktopPluginRegistrarRef Win32FlutterWindow::GetRegistrar() { - return plugin_registrar_.get(); +float Win32FlutterWindow::GetDpiScale() { + return static_cast(GetCurrentDPI()) / static_cast(base_dpi); } -// Converts a FlutterPlatformMessage to an equivalent FlutterDesktopMessage. -static FlutterDesktopMessage ConvertToDesktopMessage( - const FlutterPlatformMessage& engine_message) { - FlutterDesktopMessage message = {}; - message.struct_size = sizeof(message); - message.channel = engine_message.channel; - message.message = engine_message.message; - message.message_size = engine_message.message_size; - message.response_handle = engine_message.response_handle; - return message; +PhysicalWindowBounds Win32FlutterWindow::GetPhysicalWindowBounds() { + return {GetCurrentWidth(), GetCurrentHeight()}; } // Translates button codes from Win32 API to FlutterPointerMouseButtons. @@ -101,265 +56,62 @@ static uint64_t ConvertWinButtonToFlutterButton(UINT button) { return 0; } -// The Flutter Engine calls out to this function when new platform messages -// are available. -void Win32FlutterWindow::HandlePlatformMessage( - const FlutterPlatformMessage* engine_message) { - if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) { - std::cerr << "Invalid message size received. Expected: " - << sizeof(FlutterPlatformMessage) << " but received " - << engine_message->struct_size << std::endl; - return; - } - - auto message = ConvertToDesktopMessage(*engine_message); - - message_dispatcher_->HandleMessage( - message, [this] { this->process_events_ = false; }, - [this] { this->process_events_ = true; }); -} - void Win32FlutterWindow::OnDpiScale(unsigned int dpi){}; // When DesktopWindow notifies that a WM_Size message has come in // lets FlutterEngine know about the new size. void Win32FlutterWindow::OnResize(unsigned int width, unsigned int height) { - SendWindowMetrics(); + if (binding_handler_delegate_ != nullptr) { + binding_handler_delegate_->OnWindowSizeChanged(width, height); + } } void Win32FlutterWindow::OnPointerMove(double x, double y) { - if (process_events_) { - SendPointerMove(x, y); - } + binding_handler_delegate_->OnPointerMove(x, y); } void Win32FlutterWindow::OnPointerDown(double x, double y, UINT button) { - if (process_events_) { - uint64_t flutter_button = ConvertWinButtonToFlutterButton(button); - if (flutter_button != 0) { - uint64_t mouse_buttons = GetMouseState().buttons | flutter_button; - SetMouseButtons(mouse_buttons); - SendPointerDown(x, y); - } + uint64_t flutter_button = ConvertWinButtonToFlutterButton(button); + if (flutter_button != 0) { + binding_handler_delegate_->OnPointerDown( + x, y, static_cast(flutter_button)); } } void Win32FlutterWindow::OnPointerUp(double x, double y, UINT button) { - if (process_events_) { - uint64_t flutter_button = ConvertWinButtonToFlutterButton(button); - if (flutter_button != 0) { - uint64_t mouse_buttons = GetMouseState().buttons & ~flutter_button; - SetMouseButtons(mouse_buttons); - SendPointerUp(x, y); - } + uint64_t flutter_button = ConvertWinButtonToFlutterButton(button); + if (flutter_button != 0) { + binding_handler_delegate_->OnPointerUp( + x, y, static_cast(flutter_button)); } } void Win32FlutterWindow::OnPointerLeave() { - if (process_events_) { - SendPointerLeave(); - } + binding_handler_delegate_->OnPointerLeave(); } void Win32FlutterWindow::OnText(const std::u16string& text) { - if (process_events_) { - SendText(text); - } + binding_handler_delegate_->OnText(text); } void Win32FlutterWindow::OnKey(int key, int scancode, int action, char32_t character) { - if (process_events_) { - SendKey(key, scancode, action, character); - } + binding_handler_delegate_->OnKey(key, scancode, action, character); } void Win32FlutterWindow::OnScroll(double delta_x, double delta_y) { - if (process_events_) { - SendScroll(delta_x, delta_y); - } -} - -void Win32FlutterWindow::OnFontChange() { - if (engine_ == nullptr) { - return; - } - FlutterEngineReloadSystemFonts(engine_); -} - -// Sends new size information to FlutterEngine. -void Win32FlutterWindow::SendWindowMetrics() { - if (engine_ == nullptr) { - return; - } - - FlutterWindowMetricsEvent event = {}; - event.struct_size = sizeof(event); - event.width = GetCurrentWidth(); - event.height = GetCurrentHeight(); - event.pixel_ratio = static_cast(GetCurrentDPI()) / base_dpi; - auto result = FlutterEngineSendWindowMetricsEvent(engine_, &event); -} - -// Updates |event_data| with the current location of the mouse cursor. -void Win32FlutterWindow::SetEventLocationFromCursorPosition( - FlutterPointerEvent* event_data) { POINT point; GetCursorPos(&point); ScreenToClient(GetWindowHandle(), &point); - - event_data->x = point.x; - event_data->y = point.y; -} - -// Set's |event_data|'s phase to either kMove or kHover depending on the current -// primary mouse button state. -void Win32FlutterWindow::SetEventPhaseFromCursorButtonState( - FlutterPointerEvent* event_data) { - MouseState state = GetMouseState(); - // For details about this logic, see FlutterPointerPhase in the embedder.h - // file. - event_data->phase = state.buttons == 0 ? state.flutter_state_is_down - ? FlutterPointerPhase::kUp - : FlutterPointerPhase::kHover - : state.flutter_state_is_down - ? FlutterPointerPhase::kMove - : FlutterPointerPhase::kDown; -} - -void Win32FlutterWindow::SendPointerMove(double x, double y) { - FlutterPointerEvent event = {}; - event.x = x; - event.y = y; - SetEventPhaseFromCursorButtonState(&event); - SendPointerEventWithData(event); + binding_handler_delegate_->OnScroll(point.x, point.y, delta_x, delta_y, + kScrollOffsetMultiplier); } -void Win32FlutterWindow::SendPointerDown(double x, double y) { - FlutterPointerEvent event = {}; - SetEventPhaseFromCursorButtonState(&event); - event.x = x; - event.y = y; - SendPointerEventWithData(event); - SetMouseFlutterStateDown(true); -} - -void Win32FlutterWindow::SendPointerUp(double x, double y) { - FlutterPointerEvent event = {}; - SetEventPhaseFromCursorButtonState(&event); - event.x = x; - event.y = y; - SendPointerEventWithData(event); - if (event.phase == FlutterPointerPhase::kUp) { - SetMouseFlutterStateDown(false); - } -} - -void Win32FlutterWindow::SendPointerLeave() { - FlutterPointerEvent event = {}; - event.phase = FlutterPointerPhase::kRemove; - SendPointerEventWithData(event); -} - -void Win32FlutterWindow::SendText(const std::u16string& text) { - for (const auto& handler : keyboard_hook_handlers_) { - handler->TextHook(this, text); - } -} - -void Win32FlutterWindow::SendKey(int key, - int scancode, - int action, - char32_t character) { - for (const auto& handler : keyboard_hook_handlers_) { - handler->KeyboardHook(this, key, scancode, action, character); - } -} - -void Win32FlutterWindow::SendScroll(double delta_x, double delta_y) { - FlutterPointerEvent event = {}; - SetEventLocationFromCursorPosition(&event); - SetEventPhaseFromCursorButtonState(&event); - event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll; - // TODO: See if this can be queried from the OS; this value is chosen - // arbitrarily to get something that feels reasonable. - const int kScrollOffsetMultiplier = 20; - event.scroll_delta_x = delta_x * kScrollOffsetMultiplier; - event.scroll_delta_y = delta_y * kScrollOffsetMultiplier; - SendPointerEventWithData(event); -} - -void Win32FlutterWindow::SendPointerEventWithData( - const FlutterPointerEvent& event_data) { - MouseState mouse_state = GetMouseState(); - // If sending anything other than an add, and the pointer isn't already added, - // synthesize an add to satisfy Flutter's expectations about events. - if (!mouse_state.flutter_state_is_added && - event_data.phase != FlutterPointerPhase::kAdd) { - FlutterPointerEvent event = {}; - event.phase = FlutterPointerPhase::kAdd; - event.x = event_data.x; - event.y = event_data.y; - event.buttons = 0; - SendPointerEventWithData(event); - } - // Don't double-add (e.g., if events are delivered out of order, so an add has - // already been synthesized). - if (mouse_state.flutter_state_is_added && - event_data.phase == FlutterPointerPhase::kAdd) { - return; - } - - FlutterPointerEvent event = event_data; - event.device_kind = kFlutterPointerDeviceKindMouse; - event.buttons = mouse_state.buttons; - - // Set metadata that's always the same regardless of the event. - event.struct_size = sizeof(event); - event.timestamp = - std::chrono::duration_cast( - std::chrono::high_resolution_clock::now().time_since_epoch()) - .count(); - - FlutterEngineSendPointerEvent(engine_, &event, 1); - - if (event_data.phase == FlutterPointerPhase::kAdd) { - SetMouseFlutterStateAdded(true); - } else if (event_data.phase == FlutterPointerPhase::kRemove) { - SetMouseFlutterStateAdded(false); - ResetMouseState(); - } -} - -bool Win32FlutterWindow::MakeCurrent() { - return surface_manager->MakeCurrent(render_surface); -} - -bool Win32FlutterWindow::MakeResourceCurrent() { - return surface_manager->MakeResourceCurrent(); -} - -bool Win32FlutterWindow::ClearContext() { - return surface_manager->MakeCurrent(nullptr); -} - -bool Win32FlutterWindow::SwapBuffers() { - return surface_manager->SwapBuffers(render_surface); -} - -void Win32FlutterWindow::CreateRenderSurface() { - if (surface_manager && render_surface == EGL_NO_SURFACE) { - render_surface = surface_manager->CreateSurface(GetWindowHandle()); - } +void Win32FlutterWindow::OnFontChange() { + binding_handler_delegate_->OnFontChange(); } -void Win32FlutterWindow::DestroyRenderSurface() { - if (surface_manager) { - surface_manager->DestroySurface(render_surface); - } - render_surface = EGL_NO_SURFACE; -} } // namespace flutter diff --git a/shell/platform/windows/win32_flutter_window.h b/shell/platform/windows/win32_flutter_window.h index aff194a0e5ea4..150a6edd485fb 100644 --- a/shell/platform/windows/win32_flutter_window.h +++ b/shell/platform/windows/win32_flutter_window.h @@ -7,20 +7,15 @@ #include +#include #include #include -#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h" -#include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h" #include "flutter/shell/platform/embedder/embedder.h" -#include "flutter/shell/platform/windows/angle_surface_manager.h" -#include "flutter/shell/platform/windows/key_event_handler.h" -#include "flutter/shell/platform/windows/keyboard_hook_handler.h" -#include "flutter/shell/platform/windows/platform_handler.h" -#include "flutter/shell/platform/windows/public/flutter_windows.h" -#include "flutter/shell/platform/windows/text_input_plugin.h" + +#include "flutter/shell/platform/windows/flutter_windows_view.h" #include "flutter/shell/platform/windows/win32_window.h" -#include "flutter/shell/platform/windows/window_state.h" +#include "flutter/shell/platform/windows/window_binding_handler.h" namespace flutter { @@ -28,16 +23,13 @@ namespace flutter { // future, there will likely be a CoreWindow-based FlutterWindow as well. At // the point may make sense to dependency inject the native window rather than // inherit. -class Win32FlutterWindow : public Win32Window { +class Win32FlutterWindow : public Win32Window, public WindowBindingHandler { public: // Create flutter Window for use as child window Win32FlutterWindow(int width, int height); virtual ~Win32FlutterWindow(); - static FlutterDesktopViewControllerRef CreateWin32FlutterWindow(int width, - int height); - // |Win32Window| void OnDpiScale(unsigned int dpi) override; @@ -68,109 +60,21 @@ class Win32FlutterWindow : public Win32Window { // |Win32Window| void OnFontChange() override; - // Configures the window instance with an instance of a running Flutter engine - // returning a configured FlutterDesktopWindowControllerRef. - void SetState(FLUTTER_API_SYMBOL(FlutterEngine) state); - - // Returns the currently configured Plugin Registrar. - FlutterDesktopPluginRegistrarRef GetRegistrar(); - - // Callback passed to Flutter engine for notifying window of platform - // messages. - void HandlePlatformMessage(const FlutterPlatformMessage*); - - // Create a surface for Flutter engine to render into. - void CreateRenderSurface(); - - // Callbacks for clearing context, settings context and swapping buffers. - bool ClearContext(); - bool MakeCurrent(); - bool MakeResourceCurrent(); - bool SwapBuffers(); - - // Sends a window metrics update to the Flutter engine using current window - // dimensions in physical - void SendWindowMetrics(); - - private: - // Destroy current rendering surface if one has been allocated. - void DestroyRenderSurface(); - - // Reports a mouse movement to Flutter engine. - void SendPointerMove(double x, double y); - - // Reports mouse press to Flutter engine. - void SendPointerDown(double x, double y); - - // Reports mouse release to Flutter engine. - void SendPointerUp(double x, double y); - - // 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(); - - // Reports text input to Flutter engine. - void SendText(const std::u16string& text); - - // Reports a raw keyboard message to Flutter engine. - void SendKey(int key, int scancode, int action, char32_t character); - - // Reports scroll wheel events to Flutter engine. - void SendScroll(double delta_x, double delta_y); - - // Updates |event_data| with the current location of the mouse cursor. - void SetEventLocationFromCursorPosition(FlutterPointerEvent* event_data); - - // Set's |event_data|'s phase to either kMove or kHover depending on the - // current - // primary mouse button state. - void SetEventPhaseFromCursorButtonState(FlutterPointerEvent* event_data); - - // Sends a pointer event to the Flutter engine based on givern 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); - - std::unique_ptr surface_manager = nullptr; - EGLSurface render_surface = EGL_NO_SURFACE; - - // state of the mouse button - bool pointer_is_down_ = false; - - // The handle to the Flutter engine instance. - FLUTTER_API_SYMBOL(FlutterEngine) engine_ = nullptr; - - // Whether or not to track mouse movements to send kHover events. - bool hover_tracking_is_enabled_ = false; - - // Whether or not the pointer has been added (or if tracking is enabled, has - // been added since it was last removed). - bool pointer_currently_added_ = false; - - // The window handle given to API clients. - std::unique_ptr window_wrapper_; - - // The plugin registrar handle given to API clients. - std::unique_ptr plugin_registrar_; - - // Message dispatch manager for messages from the Flutter engine. - std::unique_ptr message_dispatcher_; + // |FlutterWindowBindingHandler| + void SetView(WindowBindingHandlerDelegate* view) override; - // The plugin registrar managing internal plugins. - std::unique_ptr internal_plugin_registrar_; + // |FlutterWindowBindingHandler| + WindowsRenderTarget GetRenderTarget() override; - // Handlers for keyboard events from Windows. - std::vector> - keyboard_hook_handlers_; + // |FlutterWindowBindingHandler| + float GetDpiScale() override; - // Handler for the flutter/platform channel. - std::unique_ptr platform_handler_; + // |FlutterWindowBindingHandler| + PhysicalWindowBounds GetPhysicalWindowBounds() override; - // should we forword input messages or not - bool process_events_ = false; + // A pointer to a FlutterWindowsView that can be used to update engine + // windowing and input state. + WindowBindingHandlerDelegate* binding_handler_delegate_; }; } // namespace flutter diff --git a/shell/platform/windows/platform_handler.cc b/shell/platform/windows/win32_platform_handler.cc similarity index 95% rename from shell/platform/windows/platform_handler.cc rename to shell/platform/windows/win32_platform_handler.cc index c4b83130a785b..a9efc31f9a2d7 100644 --- a/shell/platform/windows/platform_handler.cc +++ b/shell/platform/windows/win32_platform_handler.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/shell/platform/windows/platform_handler.h" +#include "flutter/shell/platform/windows/win32_platform_handler.h" #include @@ -10,8 +10,8 @@ #include #include "flutter/shell/platform/common/cpp/json_method_codec.h" +#include "flutter/shell/platform/windows/flutter_windows_view.h" #include "flutter/shell/platform/windows/string_conversion.h" -#include "flutter/shell/platform/windows/win32_flutter_window.h" static constexpr char kChannelName[] = "flutter/platform"; @@ -198,12 +198,12 @@ bool ScopedClipboard::SetString(const std::wstring string) { } // namespace PlatformHandler::PlatformHandler(flutter::BinaryMessenger* messenger, - Win32FlutterWindow* window) + FlutterWindowsView* view) : channel_(std::make_unique>( messenger, kChannelName, &flutter::JsonMethodCodec::GetInstance())), - window_(window) { + view_(view) { channel_->SetMethodCallHandler( [this]( const flutter::MethodCall& call, @@ -224,9 +224,8 @@ void PlatformHandler::HandleMethodCall( result->Error(kClipboardError, kUnknownClipboardFormatMessage); return; } - ScopedClipboard clipboard; - if (!clipboard.Open(window_->GetWindowHandle())) { + if (!clipboard.Open(std::get(*view_->GetRenderTarget()))) { rapidjson::Document error_code; error_code.SetInt(::GetLastError()); result->Error(kClipboardError, "Unable to open clipboard", &error_code); @@ -263,7 +262,8 @@ void PlatformHandler::HandleMethodCall( } ScopedClipboard clipboard; - if (!clipboard.Open(window_->GetWindowHandle())) { + + if (!clipboard.Open(std::get(*view_->GetRenderTarget()))) { rapidjson::Document error_code; error_code.SetInt(::GetLastError()); result->Error(kClipboardError, "Unable to open clipboard", &error_code); diff --git a/shell/platform/windows/platform_handler.h b/shell/platform/windows/win32_platform_handler.h similarity index 91% rename from shell/platform/windows/platform_handler.h rename to shell/platform/windows/win32_platform_handler.h index 8cb09a80666a7..bcf939edd4174 100644 --- a/shell/platform/windows/platform_handler.h +++ b/shell/platform/windows/win32_platform_handler.h @@ -12,13 +12,13 @@ namespace flutter { -class Win32FlutterWindow; +class FlutterWindowsView; // Handler for internal system channels. class PlatformHandler { public: explicit PlatformHandler(flutter::BinaryMessenger* messenger, - Win32FlutterWindow* window); + FlutterWindowsView* view); private: // Called when a method is called on |channel_|; @@ -30,7 +30,7 @@ class PlatformHandler { std::unique_ptr> channel_; // A reference to the win32 window. - Win32FlutterWindow* window_; + FlutterWindowsView* view_; }; } // namespace flutter diff --git a/shell/platform/windows/win32_window.cc b/shell/platform/windows/win32_window.cc index e4cf979167b73..08da305aa9206 100644 --- a/shell/platform/windows/win32_window.cc +++ b/shell/platform/windows/win32_window.cc @@ -4,7 +4,7 @@ #include "flutter/shell/platform/windows/win32_window.h" -#include "dpi_utils.h" +#include "win32_dpi_utils.h" namespace flutter { diff --git a/shell/platform/windows/win32_window.h b/shell/platform/windows/win32_window.h index d4481d89e2a68..91da3f333794c 100644 --- a/shell/platform/windows/win32_window.h +++ b/shell/platform/windows/win32_window.h @@ -13,22 +13,6 @@ namespace flutter { -// Struct holding the mouse state. The engine doesn't keep track of which mouse -// buttons have been pressed, so it's the embedding's responsibility. -struct MouseState { - // True if the last event sent to Flutter had at least one mouse 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 mouse 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; -}; - // A class abstraction for a high DPI aware Win32 Window. Intended to be // inherited from by classes that wish to specialize with custom // rendering and input handling. @@ -120,27 +104,6 @@ class Win32Window { UINT GetCurrentHeight(); - // Gets the current mouse state. - MouseState GetMouseState() { return mouse_state_; } - - // Resets the mouse state to its default values. - void ResetMouseState() { mouse_state_ = MouseState(); } - - // Updates the mouse state to whether the last event to Flutter had at least - // one mouse button pressed. - void SetMouseFlutterStateDown(bool is_down) { - mouse_state_.flutter_state_is_down = is_down; - } - - // Updates the mouse state to whether the last event to Flutter was a kAdd - // event. - void SetMouseFlutterStateAdded(bool is_added) { - mouse_state_.flutter_state_is_added = is_added; - } - - // Updates the currently pressed buttons. - void SetMouseButtons(uint64_t buttons) { mouse_state_.buttons = buttons; } - private: // Release OS resources asociated with window. void Destroy(); @@ -170,9 +133,6 @@ class Win32Window { // Set to true to be notified when the mouse leaves the window. bool tracking_mouse_leave_ = false; - // Keeps track of mouse state in relation to the window. - MouseState mouse_state_; - // Keeps track of the last key code produced by a WM_KEYDOWN or WM_SYSKEYDOWN // message. int keycode_for_char_message_ = 0; diff --git a/shell/platform/windows/window_binding_handler.h b/shell/platform/windows/window_binding_handler.h new file mode 100644 index 0000000000000..730c3dd821a37 --- /dev/null +++ b/shell/platform/windows/window_binding_handler.h @@ -0,0 +1,52 @@ +// 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_WINDOW_BINDING_HANDLER_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOW_BINDING_HANDLER_H_ + +#include "flutter/shell/platform/windows/public/flutter_windows.h" + +#include +#include + +#include + +#include "flutter/shell/platform/windows/window_binding_handler_delegate.h" + +namespace flutter { + +class FlutterWindowsView; + +// Structure containing physical bounds of a Window +struct PhysicalWindowBounds { + size_t width; + size_t height; +}; + +using WindowsRenderTarget = std::variant< + /*winrt::Windows::UI::Composition::SpriteVisual, */ HWND>; + +// Abstract class for binding Windows platform windows to Flutter views. +class WindowBindingHandler { + public: + virtual ~WindowBindingHandler() = default; + + // Sets the delegate used to communicate state changes from window to view + // such as key presses, mouse position updates etc. + virtual void SetView(WindowBindingHandlerDelegate* view) = 0; + + // Returns a valid WindowsRenderTarget representing the backing + // window. + virtual WindowsRenderTarget GetRenderTarget() = 0; + + // Returns the scale factor for the backing window. + virtual float GetDpiScale() = 0; + + // Returns the bounds of the backing window in physical pixels. + virtual PhysicalWindowBounds GetPhysicalWindowBounds() = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOW_BINDING_HANDLER_H_ diff --git a/shell/platform/windows/window_binding_handler_delegate.h b/shell/platform/windows/window_binding_handler_delegate.h new file mode 100644 index 0000000000000..3ff8f7e889de5 --- /dev/null +++ b/shell/platform/windows/window_binding_handler_delegate.h @@ -0,0 +1,61 @@ +// 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_WINDOW_BINDING_HANDLER_DELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOW_BINDING_HANDLER_DELEGATE_H_ + +#include "flutter/shell/platform/embedder/embedder.h" + +namespace flutter { + +class WindowBindingHandlerDelegate { + public: + // Notifies delegate that backing window size has changed. + // Typically called by currently configured WindowBindingHandler + virtual void OnWindowSizeChanged(size_t width, size_t height) const = 0; + + // Notifies delegate that backing window mouse has moved. + // Typically called by currently configured WindowBindingHandler + virtual void OnPointerMove(double x, double y) = 0; + + // Notifies delegate that backing window mouse pointer button has been + // pressed. Typically called by currently configured WindowBindingHandler + virtual void OnPointerDown(double x, + double y, + FlutterPointerMouseButtons button) = 0; + + // Notifies delegate that backing window mouse pointer button has been + // released. Typically called by currently configured WindowBindingHandler + virtual void OnPointerUp(double x, + double y, + FlutterPointerMouseButtons button) = 0; + + // Notifies delegate that backing window mouse pointer has left the window. + // Typically called by currently configured WindowBindingHandler + virtual void OnPointerLeave() = 0; + + // Notifies delegate that backing window has received text. + // Typically called by currently configured WindowBindingHandler + virtual void OnText(const std::u16string&) = 0; + + // Notifies delegate that backing window size has received key press. + // Typically called by currently configured WindowBindingHandler + virtual void OnKey(int key, int scancode, int action, char32_t character) = 0; + + // Notifies delegate that backing window size has recevied scroll. + // Typically called by currently configured WindowBindingHandler + virtual void OnScroll(double x, + double y, + double delta_x, + double delta_y, + int scroll_offset_multiplier) = 0; + + // Notifies delegate that backing window size has had system font change. + // Typically called by currently configured WindowBindingHandler + virtual void OnFontChange() = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOW_BINDING_HANDLER_DELEGATE_H_ diff --git a/shell/platform/windows/window_state.h b/shell/platform/windows/window_state.h index 61721fa1f21b9..d1eceb866f507 100644 --- a/shell/platform/windows/window_state.h +++ b/shell/platform/windows/window_state.h @@ -10,19 +10,19 @@ #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/key_event_handler.h" #include "flutter/shell/platform/windows/keyboard_hook_handler.h" -#include "flutter/shell/platform/windows/platform_handler.h" #include "flutter/shell/platform/windows/text_input_plugin.h" +#include "flutter/shell/platform/windows/win32_platform_handler.h" #include "flutter/shell/platform/windows/win32_task_runner.h" namespace flutter { -struct Win32FlutterWindow; +struct FlutterWindowsView; } // Struct for storing state within an instance of the windows native (HWND or // CoreWindow) Window. struct FlutterDesktopViewControllerState { - // The win32 window that owns this state object. - std::unique_ptr view; + // The view that owns this state object. + std::unique_ptr view; // The state associate with the engine backing the view. std::unique_ptr engine_state; @@ -35,8 +35,8 @@ struct FlutterDesktopViewControllerState { // controller so that it can be provided to plugins without giving them access // to all of the controller-based functionality. struct FlutterDesktopView { - // The window that (indirectly) owns this state object. - flutter::Win32FlutterWindow* window; + // The view that (indirectly) owns this state object. + flutter::FlutterWindowsView* view; }; struct AotDataDeleter { @@ -64,8 +64,8 @@ struct FlutterDesktopPluginRegistrar { // The plugin messenger handle given to API clients. std::unique_ptr messenger; - // The handle for the window associated with this registrar. - FlutterDesktopView* window; + // The handle for the view associated with this registrar. + FlutterDesktopView* view; // Callback to be called on registrar destruction. FlutterDesktopOnRegistrarDestroyed destruction_handler;