diff --git a/BUILD.gn b/BUILD.gn index 75a0036ccac39..95fc681312e7c 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -152,10 +152,15 @@ group("flutter") { } if (is_win) { - public_deps += [ - "//flutter/shell/platform/windows:flutter_windows_unittests", - "//flutter/shell/platform/windows/client_wrapper:client_wrapper_windows_unittests", - ] + if (target_os == "winuwp") { + # TODO: Add winnup variant of the unit tests here; see + # https://github.com/flutter/flutter/issues/70197 + } else { + public_deps += [ + "//flutter/shell/platform/windows:flutter_windows_unittests", + "//flutter/shell/platform/windows/client_wrapper:client_wrapper_windows_unittests", + ] + } } } } diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 28b7135dfc04d..e87e78e4dbadd 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1408,9 +1408,18 @@ FILE: ../../../flutter/shell/platform/windows/flutter_windows_engine.h FILE: ../../../flutter/shell/platform/windows/flutter_windows_engine_unittests.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.h +FILE: ../../../flutter/shell/platform/windows/flutter_windows_win32.cc +FILE: ../../../flutter/shell/platform/windows/flutter_windows_winuwp.cc 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/platform_handler_unittests.cc +FILE: ../../../flutter/shell/platform/windows/platform_handler_win32.cc +FILE: ../../../flutter/shell/platform/windows/platform_handler_win32.h +FILE: ../../../flutter/shell/platform/windows/platform_handler_winuwp.cc +FILE: ../../../flutter/shell/platform/windows/platform_handler_winuwp.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 @@ -1418,6 +1427,12 @@ FILE: ../../../flutter/shell/platform/windows/string_conversion_unittests.cc FILE: ../../../flutter/shell/platform/windows/system_utils.h FILE: ../../../flutter/shell/platform/windows/system_utils_unittests.cc FILE: ../../../flutter/shell/platform/windows/system_utils_win32.cc +FILE: ../../../flutter/shell/platform/windows/system_utils_winuwp.cc +FILE: ../../../flutter/shell/platform/windows/task_runner.h +FILE: ../../../flutter/shell/platform/windows/task_runner_win32.cc +FILE: ../../../flutter/shell/platform/windows/task_runner_win32.h +FILE: ../../../flutter/shell/platform/windows/task_runner_winuwp.cc +FILE: ../../../flutter/shell/platform/windows/task_runner_winuwp.h 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 @@ -1426,10 +1441,6 @@ 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_proc_delegate_manager.cc diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index e4945ddd364d9..873125ad4ebef 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -29,14 +29,20 @@ source_set("flutter_windows_headers") { public_deps = [ "//flutter/shell/platform/common/cpp:common_cpp_library_headers" ] - configs += - [ "//flutter/shell/platform/common/cpp:desktop_library_implementation" ] + if (target_os == "winuwp") { + configs += + [ "//flutter/shell/platform/common/cpp:desktop_library_implementation" ] + } else { + configs += + [ "//flutter/shell/platform/common/cpp:desktop_library_implementation" ] + } public_configs = [ "//flutter/shell/platform/common/cpp:relative_flutter_library_headers" ] } source_set("flutter_windows_source") { + # Common Windows sources. sources = [ "angle_surface_manager.cc", "angle_surface_manager.h", @@ -52,29 +58,48 @@ source_set("flutter_windows_source") { "key_event_handler.cc", "key_event_handler.h", "keyboard_hook_handler.h", + "platform_handler.cc", + "platform_handler.h", "string_conversion.cc", "string_conversion.h", "system_utils.h", - "system_utils_win32.cc", + "task_runner.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", - "win32_window_proc_delegate_manager.cc", - "win32_window_proc_delegate_manager.h", "window_binding_handler.h", "window_binding_handler_delegate.h", "window_state.h", ] + # Target-specific sources. + if (target_os == "winuwp") { + sources += [ + "flutter_windows_winuwp.cc", + "platform_handler_winuwp.cc", + "platform_handler_winuwp.h", + "system_utils_winuwp.cc", + "task_runner_winuwp.cc", + "task_runner_winuwp.h", + ] + } else { + sources += [ + "flutter_windows_win32.cc", + "platform_handler_win32.cc", + "platform_handler_win32.h", + "system_utils_win32.cc", + "task_runner_win32.cc", + "task_runner_win32.h", + "win32_dpi_utils.cc", + "win32_dpi_utils.h", + "win32_flutter_window.cc", + "win32_flutter_window.h", + "win32_window.cc", + "win32_window.h", + "win32_window_proc_delegate_manager.cc", + "win32_window_proc_delegate_manager.h", + ] + } + configs += [ "//flutter/shell/platform/common/cpp:desktop_library_implementation", "//third_party/angle:gl_prototypes", @@ -116,40 +141,51 @@ shared_library("flutter_windows") { public_configs = [ "//flutter:config" ] } +shared_library("flutter_windows_winuwp") { + deps = [ ":flutter_windows_source" ] + libs = [ "windowsapp.lib" ] + public_configs = [ "//flutter:config" ] +} + test_fixtures("flutter_windows_fixtures") { fixtures = [] } -executable("flutter_windows_unittests") { - testonly = true - - sources = [ - "flutter_project_bundle_unittests.cc", - "flutter_windows_engine_unittests.cc", - "string_conversion_unittests.cc", - "system_utils_unittests.cc", - "testing/engine_embedder_api_modifier.h", - "testing/mock_win32_window.cc", - "testing/mock_win32_window.h", - "testing/win32_flutter_window_test.cc", - "testing/win32_flutter_window_test.h", - "win32_dpi_utils_unittests.cc", - "win32_flutter_window_unittests.cc", - "win32_window_proc_delegate_manager_unittests.cc", - "win32_window_unittests.cc", - ] - - public_configs = [ "//flutter:config" ] - - deps = [ - ":flutter_windows_fixtures", - ":flutter_windows_headers", - ":flutter_windows_source", - "//flutter/shell/platform/embedder:embedder_as_internal_library", - "//flutter/shell/platform/embedder:embedder_test_utils", - "//flutter/testing", - "//third_party/rapidjson", - ] +if (target_os == "winuwp") { + # disabled until the uwp implementation is present +} else { + executable("flutter_windows_unittests") { + testonly = true + + sources = [ + "flutter_project_bundle_unittests.cc", + "flutter_windows_engine_unittests.cc", + "string_conversion_unittests.cc", + "system_utils_unittests.cc", + "testing/engine_embedder_api_modifier.h", + "testing/mock_win32_window.cc", + "testing/mock_win32_window.h", + "testing/win32_flutter_window_test.cc", + "testing/win32_flutter_window_test.h", + "win32_dpi_utils_unittests.cc", + "win32_flutter_window_unittests.cc", + "win32_window_proc_delegate_manager_unittests.cc", + "win32_window_unittests.cc", + ] + + public_configs = [ "//flutter:config" ] + + deps = [ + ":flutter_windows_fixtures", + ":flutter_windows_headers", + ":flutter_windows_source", + "//flutter/shell/platform/common/cpp:common_cpp", + "//flutter/shell/platform/embedder:embedder_as_internal_library", + "//flutter/shell/platform/embedder:embedder_test_utils", + "//flutter/testing", + "//third_party/rapidjson", + ] + } } shared_library("flutter_windows_glfw") { @@ -168,11 +204,20 @@ group("windows_glfw") { } group("windows") { - deps = [ - ":flutter_windows", - ":publish_headers_windows", - "//flutter/shell/platform/windows/client_wrapper:publish_wrapper_windows", - ] + if (target_os == "winuwp") { + deps = [ + ":flutter_windows_winuwp", + ":publish_headers_windows", + "//flutter/shell/platform/windows/client_wrapper:publish_wrapper_windows", + ] + } else { + deps = [ + ":flutter_windows", + ":publish_headers_windows", + "//flutter/shell/platform/windows/client_wrapper:publish_wrapper_windows", + ] + } + if (build_glfw_shell) { deps += [ ":windows_glfw" ] } diff --git a/shell/platform/windows/client_wrapper/flutter_engine.cc b/shell/platform/windows/client_wrapper/flutter_engine.cc index a1fc0c4659066..12ca29743c695 100644 --- a/shell/platform/windows/client_wrapper/flutter_engine.cc +++ b/shell/platform/windows/client_wrapper/flutter_engine.cc @@ -64,9 +64,11 @@ void FlutterEngine::ShutDown() { engine_ = nullptr; } +#ifndef WINUWP std::chrono::nanoseconds FlutterEngine::ProcessMessages() { return std::chrono::nanoseconds(FlutterDesktopEngineProcessMessages(engine_)); } +#endif void FlutterEngine::ReloadSystemFonts() { FlutterDesktopEngineReloadSystemFonts(engine_); diff --git a/shell/platform/windows/client_wrapper/flutter_view_controller.cc b/shell/platform/windows/client_wrapper/flutter_view_controller.cc index 5cb9fe98623e1..2724b27881f22 100644 --- a/shell/platform/windows/client_wrapper/flutter_view_controller.cc +++ b/shell/platform/windows/client_wrapper/flutter_view_controller.cc @@ -29,6 +29,7 @@ FlutterViewController::~FlutterViewController() { } } +#ifndef WINUWP std::optional FlutterViewController::HandleTopLevelWindowProc( HWND hwnd, UINT message, @@ -39,5 +40,6 @@ std::optional FlutterViewController::HandleTopLevelWindowProc( controller_, hwnd, message, wparam, lparam, &result); return handled ? result : std::optional(std::nullopt); } +#endif } // namespace flutter diff --git a/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h b/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h index 7231fb790b450..f39a7e70c980e 100644 --- a/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h +++ b/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h @@ -46,6 +46,7 @@ class FlutterViewController { // Returns the view managed by this controller. FlutterView* view() { return view_.get(); } +#ifndef WINUWP // Allows the Flutter engine and any interested plugins an opportunity to // handle the given message. // @@ -55,6 +56,7 @@ class FlutterViewController { UINT message, WPARAM wparam, LPARAM lparam); +#endif private: // Handle for interacting with the C API's view controller, if any. diff --git a/shell/platform/windows/flutter_project_bundle.cc b/shell/platform/windows/flutter_project_bundle.cc index cbd8293383472..071f1d012ef86 100644 --- a/shell/platform/windows/flutter_project_bundle.cc +++ b/shell/platform/windows/flutter_project_bundle.cc @@ -7,7 +7,7 @@ #include #include -#include "flutter/shell/platform/common/cpp/engine_switches.h" +#include "flutter/shell/platform/common/cpp/engine_switches.h" // nogncheck #include "flutter/shell/platform/common/cpp/path_utils.h" namespace flutter { diff --git a/shell/platform/windows/flutter_windows.cc b/shell/platform/windows/flutter_windows.cc index 88785507175c6..177d103f7bc30 100644 --- a/shell/platform/windows/flutter_windows.cc +++ b/shell/platform/windows/flutter_windows.cc @@ -22,9 +22,6 @@ #include "flutter/shell/platform/windows/flutter_project_bundle.h" #include "flutter/shell/platform/windows/flutter_windows_engine.h" #include "flutter/shell/platform/windows/flutter_windows_view.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_task_runner.h" #include "flutter/shell/platform/windows/window_binding_handler.h" #include "flutter/shell/platform/windows/window_state.h" @@ -52,32 +49,6 @@ static FlutterDesktopViewRef HandleForView(flutter::FlutterWindowsView* view) { return reinterpret_cast(view); } -FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate( - int width, - int height, - FlutterDesktopEngineRef engine) { - std::unique_ptr window_wrapper = - std::make_unique(width, height); - - auto state = std::make_unique(); - state->view = - std::make_unique(std::move(window_wrapper)); - state->view->CreateRenderSurface(); - - // Take ownership of the engine, starting it if necessary. - state->view->SetEngine( - std::unique_ptr(EngineFromHandle(engine))); - if (!state->view->GetEngine()->running()) { - if (!state->view->GetEngine()->RunWithEntrypoint(nullptr)) { - return nullptr; - } - } - - // Must happen after engine is running. - state->view->SendInitialBounds(); - return state.release(); -} - void FlutterDesktopViewControllerDestroy( FlutterDesktopViewControllerRef controller) { delete controller; @@ -93,23 +64,6 @@ FlutterDesktopViewRef FlutterDesktopViewControllerGetView( return HandleForView(controller->view.get()); } -bool FlutterDesktopViewControllerHandleTopLevelWindowProc( - FlutterDesktopViewControllerRef controller, - HWND hwnd, - UINT message, - WPARAM wparam, - LPARAM lparam, - LRESULT* result) { - std::optional delegate_result = - controller->view->GetEngine() - ->window_proc_delegate_manager() - ->OnTopLevelWindowProc(hwnd, message, wparam, lparam); - if (delegate_result) { - *result = *delegate_result; - } - return delegate_result.has_value(); -} - FlutterDesktopEngineRef FlutterDesktopEngineCreate( const FlutterDesktopEngineProperties& engine_properties) { flutter::FlutterProjectBundle project(engine_properties); @@ -132,10 +86,6 @@ bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine, return EngineFromHandle(engine)->RunWithEntrypoint(entry_point); } -uint64_t FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine) { - return EngineFromHandle(engine)->task_runner()->ProcessTasks().count(); -} - void FlutterDesktopEngineReloadSystemFonts(FlutterDesktopEngineRef engine) { EngineFromHandle(engine)->ReloadSystemFonts(); } @@ -164,29 +114,6 @@ FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView( return HandleForView(registrar->engine->view()); } -void FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate( - FlutterDesktopPluginRegistrarRef registrar, - FlutterDesktopWindowProcCallback delegate, - void* user_data) { - registrar->engine->window_proc_delegate_manager() - ->RegisterTopLevelWindowProcDelegate(delegate, user_data); -} - -void FlutterDesktopPluginRegistrarUnregisterTopLevelWindowProcDelegate( - FlutterDesktopPluginRegistrarRef registrar, - FlutterDesktopWindowProcCallback delegate) { - registrar->engine->window_proc_delegate_manager() - ->UnregisterTopLevelWindowProcDelegate(delegate); -} - -UINT FlutterDesktopGetDpiForHWND(HWND hwnd) { - return flutter::GetDpiForHWND(hwnd); -} - -UINT FlutterDesktopGetDpiForMonitor(HMONITOR monitor) { - return flutter::GetDpiForMonitor(monitor); -} - void FlutterDesktopResyncOutputStreams() { FILE* unused; if (freopen_s(&unused, "CONOUT$", "w", stdout)) { diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 6fdee48b1e9b4..a284baa6f9da9 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -15,6 +15,7 @@ #include "flutter/shell/platform/windows/flutter_windows_view.h" #include "flutter/shell/platform/windows/string_conversion.h" #include "flutter/shell/platform/windows/system_utils.h" +#include "flutter/shell/platform/windows/task_runner.h" #include "third_party/rapidjson/include/rapidjson/document.h" namespace flutter { @@ -99,7 +100,7 @@ FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project) embedder_api_.struct_size = sizeof(FlutterEngineProcTable); FlutterEngineGetProcAddresses(&embedder_api_); - task_runner_ = std::make_unique( + task_runner_ = TaskRunner::Create( GetCurrentThreadId(), embedder_api_.GetCurrentTime, [this](const auto* task) { if (!engine_) { @@ -121,8 +122,10 @@ FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project) messenger_wrapper_ = std::make_unique(messenger_.get()); message_dispatcher_ = std::make_unique(messenger_.get()); +#ifndef WINUWP window_proc_delegate_manager_ = std::make_unique(); +#endif // Set up internal channels. // TODO: Replace this with an embedder.h API. See @@ -175,12 +178,12 @@ bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { platform_task_runner.user_data = task_runner_.get(); platform_task_runner.runs_task_on_current_thread_callback = [](void* user_data) -> bool { - return static_cast(user_data)->RunsTasksOnCurrentThread(); + return static_cast(user_data)->RunsTasksOnCurrentThread(); }; platform_task_runner.post_task_callback = [](FlutterTask task, uint64_t target_time_nanos, void* user_data) -> void { - static_cast(user_data)->PostTask(task, target_time_nanos); + static_cast(user_data)->PostTask(task, target_time_nanos); }; FlutterCustomTaskRunners custom_task_runners = {}; custom_task_runners.struct_size = sizeof(FlutterCustomTaskRunners); @@ -201,7 +204,9 @@ bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { auto host = static_cast(user_data); return host->HandlePlatformMessage(engine_message); }; + args.custom_task_runners = &custom_task_runners; + if (aot_data_) { args.aot_data = aot_data_.get(); } diff --git a/shell/platform/windows/flutter_windows_engine.h b/shell/platform/windows/flutter_windows_engine.h index 58a0a3a671211..86fe2c9a20978 100644 --- a/shell/platform/windows/flutter_windows_engine.h +++ b/shell/platform/windows/flutter_windows_engine.h @@ -16,11 +16,14 @@ #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/flutter_project_bundle.h" #include "flutter/shell/platform/windows/public/flutter_windows.h" -#include "flutter/shell/platform/windows/win32_task_runner.h" -#include "flutter/shell/platform/windows/win32_window_proc_delegate_manager.h" +#include "flutter/shell/platform/windows/task_runner.h" #include "flutter/shell/platform/windows/window_state.h" #include "third_party/rapidjson/include/rapidjson/document.h" +#ifndef WINUWP +#include "flutter/shell/platform/windows/win32_window_proc_delegate_manager.h" // nogncheck +#endif + namespace flutter { class FlutterWindowsView; @@ -75,11 +78,13 @@ class FlutterWindowsEngine { return message_dispatcher_.get(); } - Win32TaskRunner* task_runner() { return task_runner_.get(); } + TaskRunner* task_runner() { return task_runner_.get(); } +#ifndef WINUWP Win32WindowProcDelegateManager* window_proc_delegate_manager() { return window_proc_delegate_manager_.get(); } +#endif // Informs the engine that the window metrics have changed. void SendWindowMetricsEvent(const FlutterWindowMetricsEvent& event); @@ -132,7 +137,7 @@ class FlutterWindowsEngine { FlutterWindowsView* view_ = nullptr; // Task runner for tasks posted from the engine. - std::unique_ptr task_runner_; + std::unique_ptr task_runner_; // The plugin messenger handle given to API clients. std::unique_ptr messenger_; @@ -154,8 +159,10 @@ class FlutterWindowsEngine { FlutterDesktopOnPluginRegistrarDestroyed plugin_registrar_destruction_callback_ = nullptr; +#ifndef WINUWP // The manager for WindowProc delegate registration and callbacks. std::unique_ptr window_proc_delegate_manager_; +#endif }; } // namespace flutter diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 1ef5c033fcae6..bcac661aa17fb 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -39,8 +39,7 @@ void FlutterWindowsView::SetEngine( 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); + platform_handler_ = PlatformHandler::Create(internal_plugin_messenger, this); cursor_handler_ = std::make_unique( internal_plugin_messenger, binding_handler_.get()); diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h index f4e1186c6e034..4863ef7b1a30f 100644 --- a/shell/platform/windows/flutter_windows_view.h +++ b/shell/platform/windows/flutter_windows_view.h @@ -18,9 +18,9 @@ #include "flutter/shell/platform/windows/flutter_windows_engine.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/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" diff --git a/shell/platform/windows/flutter_windows_win32.cc b/shell/platform/windows/flutter_windows_win32.cc new file mode 100644 index 0000000000000..4ee427eac5144 --- /dev/null +++ b/shell/platform/windows/flutter_windows_win32.cc @@ -0,0 +1,99 @@ +// 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. + +#include "flutter/shell/platform/windows/public/flutter_windows.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "flutter/shell/platform/windows/task_runner_win32.h" +#include "flutter/shell/platform/windows/win32_dpi_utils.h" +#include "flutter/shell/platform/windows/win32_flutter_window.h" + +// Returns the engine corresponding to the given opaque API handle. +static flutter::FlutterWindowsEngine* EngineFromHandle( + FlutterDesktopEngineRef ref) { + return reinterpret_cast(ref); +} + +FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate( + int width, + int height, + FlutterDesktopEngineRef engine) { + std::unique_ptr window_wrapper = + std::make_unique(width, height); + + auto state = std::make_unique(); + state->view = + std::make_unique(std::move(window_wrapper)); + state->view->CreateRenderSurface(); + + // Take ownership of the engine, starting it if necessary. + state->view->SetEngine( + std::unique_ptr(EngineFromHandle(engine))); + if (!state->view->GetEngine()->running()) { + if (!state->view->GetEngine()->RunWithEntrypoint(nullptr)) { + return nullptr; + } + } + + // Must happen after engine is running. + state->view->SendInitialBounds(); + return state.release(); +} + +bool FlutterDesktopViewControllerHandleTopLevelWindowProc( + FlutterDesktopViewControllerRef controller, + HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam, + LRESULT* result) { + std::optional delegate_result = + controller->view->GetEngine() + ->window_proc_delegate_manager() + ->OnTopLevelWindowProc(hwnd, message, wparam, lparam); + if (delegate_result) { + *result = *delegate_result; + } + return delegate_result.has_value(); +} + +uint64_t FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine) { + return static_cast( + EngineFromHandle(engine)->task_runner()) + ->ProcessTasks() + .count(); +} + +void FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate( + FlutterDesktopPluginRegistrarRef registrar, + FlutterDesktopWindowProcCallback delegate, + void* user_data) { + registrar->engine->window_proc_delegate_manager() + ->RegisterTopLevelWindowProcDelegate(delegate, user_data); +} + +void FlutterDesktopPluginRegistrarUnregisterTopLevelWindowProcDelegate( + FlutterDesktopPluginRegistrarRef registrar, + FlutterDesktopWindowProcCallback delegate) { + registrar->engine->window_proc_delegate_manager() + ->UnregisterTopLevelWindowProcDelegate(delegate); +} + +UINT FlutterDesktopGetDpiForHWND(HWND hwnd) { + return flutter::GetDpiForHWND(hwnd); +} + +UINT FlutterDesktopGetDpiForMonitor(HMONITOR monitor) { + return flutter::GetDpiForMonitor(monitor); +} diff --git a/shell/platform/windows/flutter_windows_winuwp.cc b/shell/platform/windows/flutter_windows_winuwp.cc new file mode 100644 index 0000000000000..35cd27e25f661 --- /dev/null +++ b/shell/platform/windows/flutter_windows_winuwp.cc @@ -0,0 +1,45 @@ +// 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. + +#include "flutter/shell/platform/windows/public/flutter_windows.h" + +#include + +#include +#include +#include +#include +#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" + +FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate( + int width, + int height, + FlutterDesktopEngineRef engine) { + // TODO add WINUWP implementation. + return nullptr; +} + +uint64_t FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine) { + // TODO add WINUWP implementation. + return 0; +} + +void FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate( + FlutterDesktopPluginRegistrarRef registrar, + FlutterDesktopWindowProcCallback delegate, + void* user_data) { + // TODO add WINUWP implementation. +} + +void FlutterDesktopPluginRegistrarUnregisterTopLevelWindowProcDelegate( + FlutterDesktopPluginRegistrarRef registrar, + FlutterDesktopWindowProcCallback delegate) { + // TODO add WINUWP implementation. +} diff --git a/shell/platform/windows/platform_handler.cc b/shell/platform/windows/platform_handler.cc new file mode 100644 index 0000000000000..6267583a80a7e --- /dev/null +++ b/shell/platform/windows/platform_handler.cc @@ -0,0 +1,62 @@ +// 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. + +#include "flutter/shell/platform/windows/platform_handler.h" + +#include "flutter/shell/platform/common/cpp/json_method_codec.h" + +static constexpr char kChannelName[] = "flutter/platform"; + +static constexpr char kGetClipboardDataMethod[] = "Clipboard.getData"; +static constexpr char kSetClipboardDataMethod[] = "Clipboard.setData"; + +static constexpr char kTextPlainFormat[] = "text/plain"; +static constexpr char kTextKey[] = "text"; + +static constexpr char kUnknownClipboardFormatMessage[] = + "Unknown clipboard format"; + +namespace flutter { + +PlatformHandler::PlatformHandler(BinaryMessenger* messenger) + : channel_(std::make_unique>( + messenger, + kChannelName, + &JsonMethodCodec::GetInstance())) { + channel_->SetMethodCallHandler( + [this](const MethodCall& call, + std::unique_ptr> result) { + HandleMethodCall(call, std::move(result)); + }); +} + +PlatformHandler::~PlatformHandler() = default; + +void PlatformHandler::HandleMethodCall( + const MethodCall& method_call, + std::unique_ptr> result) { + const std::string& method = method_call.method_name(); + if (method.compare(kGetClipboardDataMethod) == 0) { + // Only one string argument is expected. + const rapidjson::Value& format = method_call.arguments()[0]; + + if (strcmp(format.GetString(), kTextPlainFormat) != 0) { + result->Error(kClipboardError, kUnknownClipboardFormatMessage); + return; + } + GetPlainText(std::move(result), kTextKey); + } else if (method.compare(kSetClipboardDataMethod) == 0) { + const rapidjson::Value& document = *method_call.arguments(); + rapidjson::Value::ConstMemberIterator itr = document.FindMember(kTextKey); + if (itr == document.MemberEnd()) { + result->Error(kClipboardError, kUnknownClipboardFormatMessage); + return; + } + SetPlainText(itr->value.GetString(), std::move(result)); + } else { + result->NotImplemented(); + } +} + +} // namespace flutter diff --git a/shell/platform/windows/platform_handler.h b/shell/platform/windows/platform_handler.h new file mode 100644 index 0000000000000..b7268023a8e21 --- /dev/null +++ b/shell/platform/windows/platform_handler.h @@ -0,0 +1,55 @@ +// 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_PLATFORM_HANDLER_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_H_ + +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h" +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/method_channel.h" +#include "rapidjson/document.h" + +namespace flutter { + +class FlutterWindowsView; + +// Handler for internal system channels. +class PlatformHandler { + public: + explicit PlatformHandler(BinaryMessenger* messenger); + + virtual ~PlatformHandler(); + + // Creates a new platform handler using the given messenger and view. + static std::unique_ptr Create(BinaryMessenger* messenger, + FlutterWindowsView* view); + + protected: + // Gets plain text from the clipboard and provides it to |result| as the + // value in a dictionary with the given |key|. + virtual void GetPlainText( + std::unique_ptr> result, + std::string_view key) = 0; + + // Sets the clipboard's plain text to |text|, and reports the result (either + // an error, or null for success) to |result|. + virtual void SetPlainText( + const std::string& text, + std::unique_ptr> result) = 0; + + // A error type to use for error responses. + static constexpr char kClipboardError[] = "Clipboard error"; + + private: + // Called when a method is called on |channel_|; + void HandleMethodCall( + const MethodCall& method_call, + std::unique_ptr> result); + + // The MethodChannel used for communication with the Flutter engine. + std::unique_ptr> channel_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_H_ diff --git a/shell/platform/windows/platform_handler_unittests.cc b/shell/platform/windows/platform_handler_unittests.cc new file mode 100644 index 0000000000000..78b348b8a84d0 --- /dev/null +++ b/shell/platform/windows/platform_handler_unittests.cc @@ -0,0 +1,155 @@ +// 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. + +#include "flutter/shell/platform/windows/platform_handler.h" + +#include + +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h" +#include "flutter/shell/platform/common/cpp/json_method_codec.h" +#include "flutter/shell/platform/windows/testing/test_binary_messenger.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "rapidjson/document.h" + +namespace flutter { +namespace testing { + +namespace { +using ::testing::_; + +static constexpr char kChannelName[] = "flutter/platform"; + +static constexpr char kGetClipboardDataMethod[] = "Clipboard.getData"; +static constexpr char kSetClipboardDataMethod[] = "Clipboard.setData"; + +static constexpr char kTextPlainFormat[] = "text/plain"; + +// Test implementation of PlatformHandler to allow testing the PlatformHandler +// logic. +class TestPlatformHandler : public PlatformHandler { + public: + explicit TestPlatformHandler(BinaryMessenger* messenger) + : PlatformHandler(messenger) {} + + virtual ~TestPlatformHandler() {} + + // |PlatformHandler| + MOCK_METHOD2(GetPlainText, + void(std::unique_ptr>, + const char*)); + MOCK_METHOD2(SetPlainText, + void(const std::string&, + std::unique_ptr>)); +}; + +// Mock result to inspect results of PlatformHandler calls. +class MockMethodResult : public MethodResult { + public: + MOCK_METHOD1(SuccessInternal, void(const rapidjson::Document*)); + MOCK_METHOD3(ErrorInternal, + void(const std::string&, + const std::string&, + const rapidjson::Document*)); + MOCK_METHOD0(NotImplementedInternal, void()); +}; + +} // namespace + +TEST(PlatformHandler, GettingTextCallsThrough) { + TestBinaryMessenger messenger; + TestPlatformHandler platform_handler(&messenger); + + auto args = std::make_unique(rapidjson::kArrayType); + auto& allocator = args->GetAllocator(); + args->PushBack(kTextPlainFormat, allocator); + auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( + MethodCall(kGetClipboardDataMethod, + std::move(args))); + + // Set up a handler to call a response on |result| so that it doesn't log + // on destruction about leaking. + ON_CALL(platform_handler, GetPlainText) + .WillByDefault( + [](std::unique_ptr> result, + auto key) { result->NotImplemented(); }); + + EXPECT_CALL(platform_handler, GetPlainText(_, ::testing::StrEq("text"))); + EXPECT_TRUE(messenger.SimulateEngineMessage( + kChannelName, encoded->data(), encoded->size(), + [](const uint8_t* reply, size_t reply_size) {})); +} + +TEST(PlatformHandler, RejectsGettingUnknownTypes) { + TestBinaryMessenger messenger; + TestPlatformHandler platform_handler(&messenger); + + auto args = std::make_unique(rapidjson::kArrayType); + auto& allocator = args->GetAllocator(); + args->PushBack("madeup/contenttype", allocator); + auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( + MethodCall(kGetClipboardDataMethod, + std::move(args))); + + MockMethodResult result; + // Requsting an unknow content type is an error. + EXPECT_CALL(result, ErrorInternal(_, _, _)); + EXPECT_TRUE(messenger.SimulateEngineMessage( + kChannelName, encoded->data(), encoded->size(), + [&](const uint8_t* reply, size_t reply_size) { + JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( + reply, reply_size, &result); + })); +} + +TEST(PlatformHandler, SettingTextCallsThrough) { + TestBinaryMessenger messenger; + TestPlatformHandler platform_handler(&messenger); + + auto args = std::make_unique(rapidjson::kObjectType); + auto& allocator = args->GetAllocator(); + args->AddMember("text", "hello", allocator); + auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( + MethodCall(kSetClipboardDataMethod, + std::move(args))); + + // Set up a handler to call a response on |result| so that it doesn't log + // on destruction about leaking. + ON_CALL(platform_handler, SetPlainText) + .WillByDefault( + [](auto value, + std::unique_ptr> result) { + result->NotImplemented(); + }); + + EXPECT_CALL(platform_handler, SetPlainText(::testing::StrEq("hello"), _)); + EXPECT_TRUE(messenger.SimulateEngineMessage( + kChannelName, encoded->data(), encoded->size(), + [](const uint8_t* reply, size_t reply_size) {})); +} + +TEST(PlatformHandler, RejectsSettingUnknownTypes) { + TestBinaryMessenger messenger; + TestPlatformHandler platform_handler(&messenger); + + auto args = std::make_unique(rapidjson::kObjectType); + auto& allocator = args->GetAllocator(); + args->AddMember("madeuptype", "hello", allocator); + auto encoded = JsonMethodCodec::GetInstance().EncodeMethodCall( + MethodCall(kSetClipboardDataMethod, + std::move(args))); + + MockMethodResult result; + // Requsting an unknow content type is an error. + EXPECT_CALL(result, ErrorInternal(_, _, _)); + EXPECT_TRUE(messenger.SimulateEngineMessage( + kChannelName, encoded->data(), encoded->size(), + [&](const uint8_t* reply, size_t reply_size) { + JsonMethodCodec::GetInstance().DecodeAndProcessResponseEnvelope( + reply, reply_size, &result); + })); +} + +} // namespace testing +} // namespace flutter diff --git a/shell/platform/windows/win32_platform_handler.cc b/shell/platform/windows/platform_handler_win32.cc similarity index 57% rename from shell/platform/windows/win32_platform_handler.cc rename to shell/platform/windows/platform_handler_win32.cc index 63543dfb8de16..b4f0ea351601e 100644 --- a/shell/platform/windows/win32_platform_handler.cc +++ b/shell/platform/windows/platform_handler_win32.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/win32_platform_handler.h" +#include "flutter/shell/platform/windows/platform_handler_win32.h" #include @@ -10,22 +10,9 @@ #include #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" -static constexpr char kChannelName[] = "flutter/platform"; - -static constexpr char kGetClipboardDataMethod[] = "Clipboard.getData"; -static constexpr char kSetClipboardDataMethod[] = "Clipboard.setData"; - -static constexpr char kTextPlainFormat[] = "text/plain"; -static constexpr char kTextKey[] = "text"; - -static constexpr char kClipboardError[] = "Clipboard error"; -static constexpr char kUnknownClipboardFormatMessage[] = - "Unknown clipboard format"; - namespace flutter { namespace { @@ -198,88 +185,67 @@ bool ScopedClipboard::SetString(const std::wstring string) { } // namespace -PlatformHandler::PlatformHandler(flutter::BinaryMessenger* messenger, - FlutterWindowsView* view) - : channel_(std::make_unique>( - messenger, - kChannelName, - &flutter::JsonMethodCodec::GetInstance())), - view_(view) { - channel_->SetMethodCallHandler( - [this]( - const flutter::MethodCall& call, - std::unique_ptr> result) { - HandleMethodCall(call, std::move(result)); - }); +// static +std::unique_ptr PlatformHandler::Create( + BinaryMessenger* messenger, + FlutterWindowsView* view) { + return std::make_unique(messenger, view); } -void PlatformHandler::HandleMethodCall( - const flutter::MethodCall& method_call, - std::unique_ptr> result) { - const std::string& method = method_call.method_name(); - if (method.compare(kGetClipboardDataMethod) == 0) { - // Only one string argument is expected. - const rapidjson::Value& format = method_call.arguments()[0]; - - if (strcmp(format.GetString(), kTextPlainFormat) != 0) { - result->Error(kClipboardError, kUnknownClipboardFormatMessage); - return; - } - ScopedClipboard clipboard; - if (!clipboard.Open(std::get(*view_->GetRenderTarget()))) { - rapidjson::Document error_code; - error_code.SetInt(::GetLastError()); - result->Error(kClipboardError, "Unable to open clipboard", error_code); - return; - } - if (!clipboard.HasString()) { - result->Success(rapidjson::Document()); - return; - } - std::optional clipboard_string = clipboard.GetString(); - if (!clipboard_string) { - rapidjson::Document error_code; - error_code.SetInt(::GetLastError()); - result->Error(kClipboardError, "Unable to get clipboard data", - error_code); - return; - } - - rapidjson::Document document; - document.SetObject(); - rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); - document.AddMember( - rapidjson::Value(kTextKey, allocator), - rapidjson::Value(Utf8FromUtf16(*clipboard_string), allocator), - allocator); - result->Success(document); - } else if (method.compare(kSetClipboardDataMethod) == 0) { - const rapidjson::Value& document = *method_call.arguments(); - rapidjson::Value::ConstMemberIterator itr = document.FindMember(kTextKey); - if (itr == document.MemberEnd()) { - result->Error(kClipboardError, kUnknownClipboardFormatMessage); - return; - } +PlatformHandlerWin32::PlatformHandlerWin32(BinaryMessenger* messenger, + FlutterWindowsView* view) + : PlatformHandler(messenger), view_(view) {} + +PlatformHandlerWin32::~PlatformHandlerWin32() = default; + +void PlatformHandlerWin32::GetPlainText( + std::unique_ptr> result, + std::string_view key) { + ScopedClipboard clipboard; + if (!clipboard.Open(std::get(*view_->GetRenderTarget()))) { + rapidjson::Document error_code; + error_code.SetInt(::GetLastError()); + result->Error(kClipboardError, "Unable to open clipboard", error_code); + return; + } + if (!clipboard.HasString()) { + result->Success(rapidjson::Document()); + return; + } + std::optional clipboard_string = clipboard.GetString(); + if (!clipboard_string) { + rapidjson::Document error_code; + error_code.SetInt(::GetLastError()); + result->Error(kClipboardError, "Unable to get clipboard data", error_code); + return; + } - ScopedClipboard clipboard; + rapidjson::Document document; + document.SetObject(); + rapidjson::Document::AllocatorType& allocator = document.GetAllocator(); + document.AddMember( + rapidjson::Value(key.data(), allocator), + rapidjson::Value(Utf8FromUtf16(*clipboard_string), allocator), allocator); + result->Success(document); +} - if (!clipboard.Open(std::get(*view_->GetRenderTarget()))) { - rapidjson::Document error_code; - error_code.SetInt(::GetLastError()); - result->Error(kClipboardError, "Unable to open clipboard", error_code); - return; - } - if (!clipboard.SetString(Utf16FromUtf8(itr->value.GetString()))) { - rapidjson::Document error_code; - error_code.SetInt(::GetLastError()); - result->Error(kClipboardError, "Unable to set clipboard data", - error_code); - return; - } - result->Success(); - } else { - result->NotImplemented(); +void PlatformHandlerWin32::SetPlainText( + const std::string& text, + std::unique_ptr> result) { + ScopedClipboard clipboard; + if (!clipboard.Open(std::get(*view_->GetRenderTarget()))) { + rapidjson::Document error_code; + error_code.SetInt(::GetLastError()); + result->Error(kClipboardError, "Unable to open clipboard", error_code); + return; + } + if (!clipboard.SetString(Utf16FromUtf8(text))) { + rapidjson::Document error_code; + error_code.SetInt(::GetLastError()); + result->Error(kClipboardError, "Unable to set clipboard data", error_code); + return; } + result->Success(); } } // namespace flutter diff --git a/shell/platform/windows/platform_handler_win32.h b/shell/platform/windows/platform_handler_win32.h new file mode 100644 index 0000000000000..ad8ec92ed5e37 --- /dev/null +++ b/shell/platform/windows/platform_handler_win32.h @@ -0,0 +1,43 @@ +// 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_PLATFORM_HANDLER_WIN32_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_WIN32_H_ + +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h" +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/method_channel.h" +#include "flutter/shell/platform/windows/flutter_windows_view.h" +#include "flutter/shell/platform/windows/platform_handler.h" +#include "rapidjson/document.h" + +namespace flutter { + +class FlutterWindowsView; + +// Win32 implementation of PlatformHandler. +class PlatformHandlerWin32 : public PlatformHandler { + public: + explicit PlatformHandlerWin32(BinaryMessenger* messenger, + FlutterWindowsView* view); + + virtual ~PlatformHandlerWin32(); + + protected: + // |PlatformHandler| + void GetPlainText(std::unique_ptr> result, + std::string_view key) override; + + // |PlatformHandler| + void SetPlainText( + const std::string& text, + std::unique_ptr> result) override; + + private: + // A reference to the Flutter view. + FlutterWindowsView* view_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_WIN32_H_ diff --git a/shell/platform/windows/platform_handler_winuwp.cc b/shell/platform/windows/platform_handler_winuwp.cc new file mode 100644 index 0000000000000..e984d1fc9fd79 --- /dev/null +++ b/shell/platform/windows/platform_handler_winuwp.cc @@ -0,0 +1,38 @@ +// 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. + +#include "flutter/shell/platform/windows/platform_handler_winuwp.h" + +#include "flutter/shell/platform/windows/flutter_windows_view.h" + +namespace flutter { + +// static +std::unique_ptr PlatformHandler::Create( + BinaryMessenger* messenger, + FlutterWindowsView* view) { + return std::make_unique(messenger, view); +} + +PlatformHandlerWinUwp::PlatformHandlerWinUwp(BinaryMessenger* messenger, + FlutterWindowsView* view) + : PlatformHandler(messenger), view_(view) {} + +PlatformHandlerWinUwp::~PlatformHandlerWinUwp() = default; + +void PlatformHandlerWinUwp::GetPlainText( + std::unique_ptr> result, + std::string_view key) { + // TODO: Implement. See https://github.com/flutter/flutter/issues/70214. + result->NotImplemented(); +} + +void PlatformHandlerWinUwp::SetPlainText( + const std::string& text, + std::unique_ptr> result) { + // TODO: Implement. See https://github.com/flutter/flutter/issues/70214. + result->NotImplemented(); +} + +} // namespace flutter diff --git a/shell/platform/windows/platform_handler_winuwp.h b/shell/platform/windows/platform_handler_winuwp.h new file mode 100644 index 0000000000000..f8b2b221e1961 --- /dev/null +++ b/shell/platform/windows/platform_handler_winuwp.h @@ -0,0 +1,43 @@ +// 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_PLATFORM_HANDLER_WINUWP_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_WINUWP_H_ + +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h" +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/method_channel.h" +#include "flutter/shell/platform/windows/flutter_windows_view.h" +#include "flutter/shell/platform/windows/platform_handler.h" +#include "rapidjson/document.h" + +namespace flutter { + +class FlutterWindowsView; + +// UWP implementation of PlatformHandler. +class PlatformHandlerWinUwp : public PlatformHandler { + public: + explicit PlatformHandlerWinUwp(BinaryMessenger* messenger, + FlutterWindowsView* view); + + virtual ~PlatformHandlerWinUwp(); + + protected: + // |PlatformHandler| + void GetPlainText(std::unique_ptr> result, + std::string_view key) override; + + // |PlatformHandler| + void SetPlainText( + const std::string& text, + std::unique_ptr> result) override; + + private: + // A reference to the Flutter view. + FlutterWindowsView* view_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_WINUWP_H_ diff --git a/shell/platform/windows/public/flutter_windows.h b/shell/platform/windows/public/flutter_windows.h index 2c53e1740df52..dbcaf8df17035 100644 --- a/shell/platform/windows/public/flutter_windows.h +++ b/shell/platform/windows/public/flutter_windows.h @@ -92,6 +92,7 @@ FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine( FLUTTER_EXPORT FlutterDesktopViewRef FlutterDesktopViewControllerGetView(FlutterDesktopViewControllerRef controller); +#ifndef WINUWP // Allows the Flutter engine and any interested plugins an opportunity to // handle the given message. // @@ -104,6 +105,7 @@ FLUTTER_EXPORT bool FlutterDesktopViewControllerHandleTopLevelWindowProc( WPARAM wparam, LPARAM lparam, LRESULT* result); +#endif // ========== Engine ========== @@ -132,6 +134,7 @@ FLUTTER_EXPORT bool FlutterDesktopEngineDestroy(FlutterDesktopEngineRef engine); FLUTTER_EXPORT bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine, const char* entry_point); +#ifndef WINUWP // Processes any pending events in the Flutter engine, and returns the // number of nanoseconds until the next scheduled event (or max, if none). // @@ -140,6 +143,7 @@ FLUTTER_EXPORT bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine, // last return value from this function. FLUTTER_EXPORT uint64_t FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine); +#endif FLUTTER_EXPORT void FlutterDesktopEngineReloadSystemFonts( FlutterDesktopEngineRef engine); diff --git a/shell/platform/windows/system_utils_winuwp.cc b/shell/platform/windows/system_utils_winuwp.cc new file mode 100644 index 0000000000000..85278dc0a6dd5 --- /dev/null +++ b/shell/platform/windows/system_utils_winuwp.cc @@ -0,0 +1,51 @@ +// 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. + +#include "flutter/shell/platform/windows/system_utils.h" + +#include + +#include + +#include "flutter/shell/platform/windows/string_conversion.h" + +namespace flutter { + +std::vector GetPreferredLanguageInfo() { + std::vector languages = GetPreferredLanguages(); + std::vector language_info; + // TODO populate via WinRT + return language_info; +} + +std::vector GetPreferredLanguages() { + std::vector languages; + // TODO populate via WinRT + return languages; +} + +LanguageInfo ParseLanguageName(std::wstring language_name) { + LanguageInfo info; + + // TODO populate via WinRT + return info; +} + +std::wstring GetUserTimeFormat() { + // Rather than do the call-allocate-call-free dance, just use a sufficiently + // large buffer to handle any reasonable time format string. + const int kBufferSize = 100; + wchar_t buffer[kBufferSize]; + if (::GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_STIMEFORMAT, buffer, + kBufferSize) == 0) { + return std::wstring(); + } + return std::wstring(buffer, kBufferSize); +} + +bool Prefer24HourTime(std::wstring time_format) { + return time_format.find(L"H") != std::wstring::npos; +} + +} // namespace flutter diff --git a/shell/platform/windows/task_runner.h b/shell/platform/windows/task_runner.h new file mode 100644 index 0000000000000..9d2c22b9043c0 --- /dev/null +++ b/shell/platform/windows/task_runner.h @@ -0,0 +1,43 @@ +// 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_TASK_RUNNER_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_H_ + +#include + +#include +#include + +#include "flutter/shell/platform/embedder/embedder.h" + +namespace flutter { + +typedef uint64_t (*CurrentTimeProc)(); + +// Abstract custom task runner for scheduling custom tasks. +class TaskRunner { + public: + using TaskExpiredCallback = std::function; + + virtual ~TaskRunner() = default; + + // Returns if the current thread is the UI thread. + virtual bool RunsTasksOnCurrentThread() const = 0; + + // Post a Flutter engine tasks to the event loop for delayed execution. + virtual void PostTask(FlutterTask flutter_task, + uint64_t flutter_target_time_nanos) = 0; + + // Creates a new task runner with the given main thread ID, current time + // provider, and callback for tasks that are ready to be run. + static std::unique_ptr Create( + DWORD main_thread_id, + CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired); +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_H_ diff --git a/shell/platform/windows/win32_task_runner.cc b/shell/platform/windows/task_runner_win32.cc similarity index 81% rename from shell/platform/windows/win32_task_runner.cc rename to shell/platform/windows/task_runner_win32.cc index 9f6d26db86b91..bb1fe147707de 100644 --- a/shell/platform/windows/win32_task_runner.cc +++ b/shell/platform/windows/task_runner_win32.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/win32_task_runner.h" +#include "flutter/shell/platform/windows/task_runner_win32.h" #include #include @@ -10,20 +10,29 @@ namespace flutter { -Win32TaskRunner::Win32TaskRunner(DWORD main_thread_id, +// static +std::unique_ptr TaskRunner::Create( + DWORD main_thread_id, + CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) { + return std::make_unique(main_thread_id, get_current_time, + on_task_expired); +} + +TaskRunnerWin32::TaskRunnerWin32(DWORD main_thread_id, CurrentTimeProc get_current_time, const TaskExpiredCallback& on_task_expired) : main_thread_id_(main_thread_id), get_current_time_(get_current_time), on_task_expired_(std::move(on_task_expired)) {} -Win32TaskRunner::~Win32TaskRunner() = default; +TaskRunnerWin32::~TaskRunnerWin32() = default; -bool Win32TaskRunner::RunsTasksOnCurrentThread() const { +bool TaskRunnerWin32::RunsTasksOnCurrentThread() const { return GetCurrentThreadId() == main_thread_id_; } -std::chrono::nanoseconds Win32TaskRunner::ProcessTasks() { +std::chrono::nanoseconds TaskRunnerWin32::ProcessTasks() { const TaskTimePoint now = TaskTimePoint::clock::now(); std::vector expired_tasks; @@ -68,14 +77,14 @@ std::chrono::nanoseconds Win32TaskRunner::ProcessTasks() { } } -Win32TaskRunner::TaskTimePoint Win32TaskRunner::TimePointFromFlutterTime( +TaskRunnerWin32::TaskTimePoint TaskRunnerWin32::TimePointFromFlutterTime( uint64_t flutter_target_time_nanos) const { const auto now = TaskTimePoint::clock::now(); const auto flutter_duration = flutter_target_time_nanos - get_current_time_(); return now + std::chrono::nanoseconds(flutter_duration); } -void Win32TaskRunner::PostTask(FlutterTask flutter_task, +void TaskRunnerWin32::PostTask(FlutterTask flutter_task, uint64_t flutter_target_time_nanos) { static std::atomic_uint64_t sGlobalTaskOrder(0); diff --git a/shell/platform/windows/win32_task_runner.h b/shell/platform/windows/task_runner_win32.h similarity index 68% rename from shell/platform/windows/win32_task_runner.h rename to shell/platform/windows/task_runner_win32.h index 61a5ab7f00e9c..1ac2f64b861c5 100644 --- a/shell/platform/windows/win32_task_runner.h +++ b/shell/platform/windows/task_runner_win32.h @@ -2,8 +2,8 @@ // 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_WIN32_TASK_RUNNER_H_ -#define FLUTTER_SHELL_PLATFORM_WINDOWS_WIN32_TASK_RUNNER_H_ +#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WIN32_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WIN32_H_ #include @@ -15,31 +15,31 @@ #include #include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/windows/task_runner.h" namespace flutter { -typedef uint64_t (*CurrentTimeProc)(); // A custom task runner that integrates with user32 GetMessage semantics so that // host app can own its own message loop and flutter still gets to process // tasks on a timely basis. -class Win32TaskRunner { +class TaskRunnerWin32 : public TaskRunner { public: - using TaskExpiredCallback = std::function; // Creates a new task runner with the given main thread ID, current time // provider, and callback for tasks that are ready to be run. - Win32TaskRunner(DWORD main_thread_id, + TaskRunnerWin32(DWORD main_thread_id, CurrentTimeProc get_current_time, const TaskExpiredCallback& on_task_expired); - ~Win32TaskRunner(); + virtual ~TaskRunnerWin32(); - // Returns if the current thread is the thread used by the win32 event loop. - bool RunsTasksOnCurrentThread() const; + // |TaskRunner| + bool RunsTasksOnCurrentThread() const override; - std::chrono::nanoseconds ProcessTasks(); + // |TaskRunner| + void PostTask(FlutterTask flutter_task, + uint64_t flutter_target_time_nanos) override; - // Post a Flutter engine tasks to the event loop for delayed execution. - void PostTask(FlutterTask flutter_task, uint64_t flutter_target_time_nanos); + std::chrono::nanoseconds ProcessTasks(); private: using TaskTimePoint = std::chrono::steady_clock::time_point; @@ -68,11 +68,11 @@ class Win32TaskRunner { std::mutex task_queue_mutex_; std::priority_queue, Task::Comparer> task_queue_; - Win32TaskRunner(const Win32TaskRunner&) = delete; + TaskRunnerWin32(const TaskRunnerWin32&) = delete; - Win32TaskRunner& operator=(const Win32TaskRunner&) = delete; + TaskRunnerWin32& operator=(const TaskRunnerWin32&) = delete; }; } // namespace flutter -#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_WIN32_TASK_RUNNER_H_ +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TASK_RUNNER_WIN32_H_ diff --git a/shell/platform/windows/task_runner_winuwp.cc b/shell/platform/windows/task_runner_winuwp.cc new file mode 100644 index 0000000000000..a2fbe7040c412 --- /dev/null +++ b/shell/platform/windows/task_runner_winuwp.cc @@ -0,0 +1,44 @@ +// 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. + +#include "flutter/shell/platform/windows/task_runner_winuwp.h" + +#include +#include + +namespace flutter { + +// static +std::unique_ptr TaskRunner::Create( + DWORD main_thread_id, + CurrentTimeProc get_current_time, + const TaskExpiredCallback& on_task_expired) { + return std::make_unique(main_thread_id, on_task_expired); +} + +TaskRunnerWinUwp::TaskRunnerWinUwp(DWORD main_thread_id, + const TaskExpiredCallback& on_task_expired) + : main_thread_id_(main_thread_id), + on_task_expired_(std::move(on_task_expired)) { + dispatcher_ = + winrt::Windows::UI::Core::CoreWindow::GetForCurrentThread().Dispatcher(); +} + +TaskRunnerWinUwp::~TaskRunnerWinUwp() = default; + +bool TaskRunnerWinUwp::RunsTasksOnCurrentThread() const { + return GetCurrentThreadId() == main_thread_id_; +} + +void TaskRunnerWinUwp::PostTask(FlutterTask flutter_task, + uint64_t flutter_target_time_nanos) { + // TODO: Handle the target time. See + // https://github.com/flutter/flutter/issues/70890. + + dispatcher_.RunAsync( + winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, + [this, flutter_task]() { on_task_expired_(&flutter_task); }); +} + +} // namespace flutter diff --git a/shell/platform/windows/task_runner_winuwp.h b/shell/platform/windows/task_runner_winuwp.h new file mode 100644 index 0000000000000..49bdb4da587ce --- /dev/null +++ b/shell/platform/windows/task_runner_winuwp.h @@ -0,0 +1,49 @@ +// 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_WINRT_TASK_RUNNER_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_WINRT_TASK_RUNNER_H_ + +#include + +#include + +#include +#include +#include + +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/windows/task_runner.h" + +namespace flutter { + +// A custom task runner that uses a CoreDispatcher to schedule +// flutter tasks. +class TaskRunnerWinUwp : public TaskRunner { + public: + TaskRunnerWinUwp(DWORD main_thread_id, + const TaskExpiredCallback& on_task_expired); + + ~TaskRunnerWinUwp(); + + TaskRunnerWinUwp(const TaskRunnerWinUwp&) = delete; + TaskRunnerWinUwp& operator=(const TaskRunnerWinUwp&) = delete; + + // |TaskRunner| + bool RunsTasksOnCurrentThread() const override; + + // |TaskRunner| + void PostTask(FlutterTask flutter_task, + uint64_t flutter_target_time_nanos) override; + + private: + DWORD main_thread_id_; + TaskExpiredCallback on_task_expired_; + + winrt::Windows::UI::Core::CoreDispatcher dispatcher_{nullptr}; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_WINRT_TASK_RUNNER_H_ diff --git a/shell/platform/windows/testing/test_binary_messenger.h b/shell/platform/windows/testing/test_binary_messenger.h new file mode 100644 index 0000000000000..157a1e8f1f12d --- /dev/null +++ b/shell/platform/windows/testing/test_binary_messenger.h @@ -0,0 +1,80 @@ +// 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_TESTING_TEST_BINARY_MESSENGER_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_TEST_BINARY_MESSENGER_H_ + +#include +#include +#include +#include + +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h" + +namespace flutter { + +// A trivial BinaryMessenger implementation for use in tests. +class TestBinaryMessenger : public BinaryMessenger { + public: + using SendHandler = std::function; + + // Creates a new messenge that forwards all calls to |send_handler|. + explicit TestBinaryMessenger(SendHandler send_handler = nullptr) + : send_handler_(std::move(send_handler)) {} + + virtual ~TestBinaryMessenger() = default; + + // Prevent copying. + TestBinaryMessenger(TestBinaryMessenger const&) = delete; + TestBinaryMessenger& operator=(TestBinaryMessenger const&) = delete; + + // Simulates a message from the engine on the given channel. + // + // Returns false if no handler is registered on that channel. + bool SimulateEngineMessage(const std::string& channel, + const uint8_t* message, + size_t message_size, + BinaryReply reply) { + auto handler = registered_handlers_.find(channel); + if (handler == registered_handlers_.end()) { + return false; + } + (handler->second)(message, message_size, reply); + return true; + } + + // |flutter::BinaryMessenger| + void Send(const std::string& channel, + const uint8_t* message, + size_t message_size, + BinaryReply reply) const override { + // If something under test sends a message, the test should be handling it. + assert(send_handler_); + send_handler_(channel, message, message_size, reply); + } + + // |flutter::BinaryMessenger| + void SetMessageHandler(const std::string& channel, + BinaryMessageHandler handler) override { + if (handler) { + registered_handlers_[channel] = handler; + } else { + registered_handlers_.erase(channel); + } + } + + private: + // Handler to call for SendMessage. + SendHandler send_handler_; + + // Mapping of channel name to registered handlers. + std::map registered_handlers_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_TESTING_TEST_BINARY_MESSENGER_H_ diff --git a/shell/platform/windows/win32_platform_handler.h b/shell/platform/windows/win32_platform_handler.h deleted file mode 100644 index bcf939edd4174..0000000000000 --- a/shell/platform/windows/win32_platform_handler.h +++ /dev/null @@ -1,38 +0,0 @@ -// 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_PLATFORM_HANDLER_H_ -#define FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_H_ - -#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h" -#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/method_channel.h" -#include "flutter/shell/platform/windows/public/flutter_windows.h" -#include "rapidjson/document.h" - -namespace flutter { - -class FlutterWindowsView; - -// Handler for internal system channels. -class PlatformHandler { - public: - explicit PlatformHandler(flutter::BinaryMessenger* messenger, - FlutterWindowsView* view); - - private: - // Called when a method is called on |channel_|; - void HandleMethodCall( - const flutter::MethodCall& method_call, - std::unique_ptr> result); - - // The MethodChannel used for communication with the Flutter engine. - std::unique_ptr> channel_; - - // A reference to the win32 window. - FlutterWindowsView* view_; -}; - -} // namespace flutter - -#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_PLATFORM_HANDLER_H_ diff --git a/tools/gn b/tools/gn index 1ad5536f678e3..f7b69306619da 100755 --- a/tools/gn +++ b/tools/gn @@ -143,6 +143,8 @@ def to_gn_args(args): elif args.target_os == 'fuchsia': gn_args['target_os'] = 'fuchsia' gn_args['flutter_enable_legacy_fuchsia_embedder'] = args.fuchsia_legacy + elif args.target_os == 'winuwp': + gn_args['target_os'] = 'winuwp' elif args.target_os is not None: gn_args['target_os'] = args.target_os @@ -328,6 +330,7 @@ def parse_args(args): parser.add_argument('--fuchsia', dest='target_os', action='store_const', const='fuchsia') parser.add_argument('--fuchsia-legacy', default=True, action='store_true') parser.add_argument('--no-fuchsia-legacy', dest='fuchsia_legacy', action='store_false') + parser.add_argument('--winuwp', dest='target_os', action='store_const', const='winuwp') parser.add_argument('--linux-cpu', type=str, choices=['x64', 'x86', 'arm64', 'arm']) parser.add_argument('--fuchsia-cpu', type=str, choices=['x64', 'arm64'], default = 'x64')