diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index f13271aa91373..3df50cf9c4205 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1400,6 +1400,7 @@ FILE: ../../../flutter/shell/platform/windows/flutter_project_bundle_unittests.c FILE: ../../../flutter/shell/platform/windows/flutter_windows.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_engine.cc 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/key_event_handler.cc diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 66b578cf0fa49..e4945ddd364d9 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -82,6 +82,8 @@ source_set("flutter_windows_source") { public_configs = [ ":relative_angle_headers" ] + defines = [ "FLUTTER_ENGINE_NO_PROTOTYPES" ] + deps = [ ":flutter_windows_headers", "//flutter/shell/platform/common/cpp:common_cpp", @@ -123,8 +125,10 @@ executable("flutter_windows_unittests") { 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", @@ -141,6 +145,8 @@ executable("flutter_windows_unittests") { ":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", ] diff --git a/shell/platform/windows/flutter_project_bundle.cc b/shell/platform/windows/flutter_project_bundle.cc index 4790697b585e8..cbd8293383472 100644 --- a/shell/platform/windows/flutter_project_bundle.cc +++ b/shell/platform/windows/flutter_project_bundle.cc @@ -52,29 +52,30 @@ bool FlutterProjectBundle::HasValidPaths() { // Attempts to load AOT data from the given path, which must be absolute and // non-empty. Logs and returns nullptr on failure. -UniqueAotDataPtr FlutterProjectBundle::LoadAotData() { +UniqueAotDataPtr FlutterProjectBundle::LoadAotData( + const FlutterEngineProcTable& engine_procs) { if (aot_library_path_.empty()) { std::cerr << "Attempted to load AOT data, but no aot_library_path was provided." << std::endl; - return nullptr; + return UniqueAotDataPtr(nullptr, nullptr); } if (!std::filesystem::exists(aot_library_path_)) { std::cerr << "Can't load AOT data from " << aot_library_path_.u8string() << "; no such file." << std::endl; - return nullptr; + return UniqueAotDataPtr(nullptr, nullptr); } std::string path_string = aot_library_path_.u8string(); FlutterEngineAOTDataSource source = {}; source.type = kFlutterEngineAOTDataSourceTypeElfPath; source.elf_path = path_string.c_str(); FlutterEngineAOTData data = nullptr; - auto result = FlutterEngineCreateAOTData(&source, &data); + auto result = engine_procs.CreateAOTData(&source, &data); if (result != kSuccess) { std::cerr << "Failed to load AOT data from: " << path_string << std::endl; - return nullptr; + return UniqueAotDataPtr(nullptr, nullptr); } - return UniqueAotDataPtr(data); + return UniqueAotDataPtr(data, engine_procs.CollectAOTData); } FlutterProjectBundle::~FlutterProjectBundle() {} diff --git a/shell/platform/windows/flutter_project_bundle.h b/shell/platform/windows/flutter_project_bundle.h index 72ee38d12fdb8..332b0060a9c30 100644 --- a/shell/platform/windows/flutter_project_bundle.h +++ b/shell/platform/windows/flutter_project_bundle.h @@ -14,12 +14,8 @@ namespace flutter { -struct AotDataDeleter { - void operator()(FlutterEngineAOTData aot_data) { - FlutterEngineCollectAOTData(aot_data); - } -}; -using UniqueAotDataPtr = std::unique_ptr<_FlutterEngineAOTData, AotDataDeleter>; +using UniqueAotDataPtr = + std::unique_ptr<_FlutterEngineAOTData, FlutterEngineCollectAOTDataFnPtr>; // The data associated with a Flutter project needed to run it in an engine. class FlutterProjectBundle { @@ -49,7 +45,7 @@ class FlutterProjectBundle { // retained until any engine instance it is passed to has been shut down. // // Logs and returns nullptr on failure. - UniqueAotDataPtr LoadAotData(); + UniqueAotDataPtr LoadAotData(const FlutterEngineProcTable& engine_procs); // Returns the command line arguments to be passed through to the Dart // entrypoint. diff --git a/shell/platform/windows/flutter_windows.cc b/shell/platform/windows/flutter_windows.cc index d5963a2122632..88785507175c6 100644 --- a/shell/platform/windows/flutter_windows.cc +++ b/shell/platform/windows/flutter_windows.cc @@ -137,7 +137,7 @@ uint64_t FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine) { } void FlutterDesktopEngineReloadSystemFonts(FlutterDesktopEngineRef engine) { - FlutterEngineReloadSystemFonts(EngineFromHandle(engine)->engine()); + EngineFromHandle(engine)->ReloadSystemFonts(); } FlutterDesktopPluginRegistrarRef FlutterDesktopEngineGetPluginRegistrar( @@ -217,33 +217,8 @@ bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger, const size_t message_size, const FlutterDesktopBinaryReply reply, void* user_data) { - FlutterPlatformMessageResponseHandle* response_handle = nullptr; - if (reply != nullptr && user_data != nullptr) { - FlutterEngineResult result = FlutterPlatformMessageCreateResponseHandle( - messenger->engine->engine(), reply, user_data, &response_handle); - if (result != kSuccess) { - std::cout << "Failed to create response handle\n"; - return false; - } - } - - FlutterPlatformMessage platform_message = { - sizeof(FlutterPlatformMessage), - channel, - message, - message_size, - response_handle, - }; - - FlutterEngineResult message_result = FlutterEngineSendPlatformMessage( - messenger->engine->engine(), &platform_message); - - if (response_handle != nullptr) { - FlutterPlatformMessageReleaseResponseHandle(messenger->engine->engine(), - response_handle); - } - - return message_result == kSuccess; + return messenger->engine->SendPlatformMessage(channel, message, message_size, + reply, user_data); } bool FlutterDesktopMessengerSend(FlutterDesktopMessengerRef messenger, @@ -259,8 +234,7 @@ void FlutterDesktopMessengerSendResponse( const FlutterDesktopMessageResponseHandle* handle, const uint8_t* data, size_t data_length) { - FlutterEngineSendPlatformMessageResponse(messenger->engine->engine(), handle, - data, data_length); + messenger->engine->SendPlatformMessageResponse(handle, data, data_length); } void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger, diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 7516c6a5af0c4..2641e98c2e979 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -90,15 +90,20 @@ FlutterLocale CovertToFlutterLocale(const LanguageInfo& info) { } // namespace FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project) - : project_(std::make_unique(project)) { + : project_(std::make_unique(project)), + aot_data_(nullptr, nullptr) { + embedder_api_.struct_size = sizeof(FlutterEngineProcTable); + FlutterEngineGetProcAddresses(&embedder_api_); + task_runner_ = std::make_unique( - GetCurrentThreadId(), [this](const auto* task) { + GetCurrentThreadId(), embedder_api_.GetCurrentTime, + [this](const auto* task) { if (!engine_) { std::cerr << "Cannot post an engine task when engine is not running." << std::endl; return; } - if (FlutterEngineRunTask(engine_, task) != kSuccess) { + if (embedder_api_.RunTask(engine_, task) != kSuccess) { std::cerr << "Failed to post an engine task." << std::endl; } }); @@ -126,8 +131,8 @@ bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { } std::string assets_path_string = project_->assets_path().u8string(); std::string icu_path_string = project_->icu_path().u8string(); - if (FlutterEngineRunsAOTCompiledDartCode()) { - aot_data_ = project_->LoadAotData(); + if (embedder_api_.RunsAOTCompiledDartCode()) { + aot_data_ = project_->LoadAotData(embedder_api_); if (!aot_data_) { std::cerr << "Unable to start engine without AOT data." << std::endl; return false; @@ -193,8 +198,8 @@ bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { FlutterRendererConfig renderer_config = GetRendererConfig(); - auto result = FlutterEngineRun(FLUTTER_ENGINE_VERSION, &renderer_config, - &args, this, &engine_); + auto result = embedder_api_.Run(FLUTTER_ENGINE_VERSION, &renderer_config, + &args, this, &engine_); if (result != kSuccess || engine_ == nullptr) { std::cerr << "Failed to start Flutter engine: error " << result << std::endl; @@ -211,7 +216,7 @@ bool FlutterWindowsEngine::Stop() { if (plugin_registrar_destruction_callback_) { plugin_registrar_destruction_callback_(plugin_registrar_.get()); } - FlutterEngineResult result = FlutterEngineShutdown(engine_); + FlutterEngineResult result = embedder_api_.Shutdown(engine_); engine_ = nullptr; return (result == kSuccess); } @@ -232,6 +237,60 @@ void FlutterWindowsEngine::SetPluginRegistrarDestructionCallback( plugin_registrar_destruction_callback_ = callback; } +void FlutterWindowsEngine::SendWindowMetricsEvent( + const FlutterWindowMetricsEvent& event) { + if (engine_) { + embedder_api_.SendWindowMetricsEvent(engine_, &event); + } +} + +void FlutterWindowsEngine::SendPointerEvent(const FlutterPointerEvent& event) { + if (engine_) { + embedder_api_.SendPointerEvent(engine_, &event, 1); + } +} + +bool FlutterWindowsEngine::SendPlatformMessage( + const char* channel, + const uint8_t* message, + const size_t message_size, + const FlutterDesktopBinaryReply reply, + void* user_data) { + FlutterPlatformMessageResponseHandle* response_handle = nullptr; + if (reply != nullptr && user_data != nullptr) { + FlutterEngineResult result = + embedder_api_.PlatformMessageCreateResponseHandle( + engine_, reply, user_data, &response_handle); + if (result != kSuccess) { + std::cout << "Failed to create response handle\n"; + return false; + } + } + + FlutterPlatformMessage platform_message = { + sizeof(FlutterPlatformMessage), + channel, + message, + message_size, + response_handle, + }; + + FlutterEngineResult message_result = + embedder_api_.SendPlatformMessage(engine_, &platform_message); + if (response_handle != nullptr) { + embedder_api_.PlatformMessageReleaseResponseHandle(engine_, + response_handle); + } + return message_result == kSuccess; +} + +void FlutterWindowsEngine::SendPlatformMessageResponse( + const FlutterDesktopMessageResponseHandle* handle, + const uint8_t* data, + size_t data_length) { + embedder_api_.SendPlatformMessageResponse(engine_, handle, data, data_length); +} + void FlutterWindowsEngine::HandlePlatformMessage( const FlutterPlatformMessage* engine_message) { if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) { @@ -247,6 +306,10 @@ void FlutterWindowsEngine::HandlePlatformMessage( message, [this] {}, [this] {}); } +void FlutterWindowsEngine::ReloadSystemFonts() { + embedder_api_.ReloadSystemFonts(engine_); +} + void FlutterWindowsEngine::SendSystemSettings() { std::vector languages = GetPreferredLanguageInfo(); std::vector flutter_locales; @@ -261,8 +324,8 @@ void FlutterWindowsEngine::SendSystemSettings() { flutter_locales.begin(), flutter_locales.end(), std::back_inserter(flutter_locale_list), [](const auto& arg) -> const auto* { return &arg; }); - FlutterEngineUpdateLocales(engine_, flutter_locale_list.data(), - flutter_locale_list.size()); + embedder_api_.UpdateLocales(engine_, flutter_locale_list.data(), + flutter_locale_list.size()); // TODO: Send 'flutter/settings' channel settings here as well. } diff --git a/shell/platform/windows/flutter_windows_engine.h b/shell/platform/windows/flutter_windows_engine.h index 49c0fc7f2a8cf..045cea0df4bc5 100644 --- a/shell/platform/windows/flutter_windows_engine.h +++ b/shell/platform/windows/flutter_windows_engine.h @@ -11,6 +11,7 @@ #include #include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h" +#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" @@ -65,8 +66,6 @@ class FlutterWindowsEngine { void SetPluginRegistrarDestructionCallback( FlutterDesktopOnPluginRegistrarDestroyed callback); - FLUTTER_API_SYMBOL(FlutterEngine) engine() { return engine_; } - FlutterDesktopMessengerRef messenger() { return messenger_.get(); } IncomingMessageDispatcher* message_dispatcher() { @@ -79,11 +78,37 @@ class FlutterWindowsEngine { return window_proc_delegate_manager_.get(); } + // Informs the engine that the window metrics have changed. + void SendWindowMetricsEvent(const FlutterWindowMetricsEvent& event); + + // Informs the engine of an incoming pointer event. + void SendPointerEvent(const FlutterPointerEvent& event); + + // Sends the given message to the engine, calling |reply| with |user_data| + // when a reponse is received from the engine if they are non-null. + bool SendPlatformMessage(const char* channel, + const uint8_t* message, + const size_t message_size, + const FlutterDesktopBinaryReply reply, + void* user_data); + + // Sends the given data as the response to an earlier platform message. + void SendPlatformMessageResponse( + const FlutterDesktopMessageResponseHandle* handle, + const uint8_t* data, + size_t data_length); + // Callback passed to Flutter engine for notifying window of platform // messages. void HandlePlatformMessage(const FlutterPlatformMessage*); + // Informs the engine that the system font list has changed. + void ReloadSystemFonts(); + private: + // Allows swapping out embedder_api_ calls in tests. + friend class EngineEmbedderApiModifier; + // Sends system settings (e.g., locale) to the engine. // // Should be called just after the engine is run, and after any relevant @@ -93,6 +118,8 @@ class FlutterWindowsEngine { // The handle to the embedder.h engine instance. FLUTTER_API_SYMBOL(FlutterEngine) engine_ = nullptr; + FlutterEngineProcTable embedder_api_ = {}; + std::unique_ptr project_; // AOT data, if any. diff --git a/shell/platform/windows/flutter_windows_engine_unittests.cc b/shell/platform/windows/flutter_windows_engine_unittests.cc new file mode 100644 index 0000000000000..18401ea11ee54 --- /dev/null +++ b/shell/platform/windows/flutter_windows_engine_unittests.cc @@ -0,0 +1,112 @@ +// 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/flutter_windows_engine.h" + +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" +#include "flutter/shell/platform/windows/testing/engine_embedder_api_modifier.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +namespace { +// Returns an engine instance configured with dummy project path values. +std::unique_ptr GetTestEngine() { + FlutterDesktopEngineProperties properties = {}; + properties.assets_path = L"C:\\foo\\flutter_assets"; + properties.icu_data_path = L"C:\\foo\\icudtl.dat"; + properties.aot_library_path = L"C:\\foo\\aot.so"; + FlutterProjectBundle project(properties); + return std::make_unique(project); +} +} // namespace + +TEST(FlutterWindowsEngine, SendPlatformMessageWithoutResponse) { + std::unique_ptr engine = GetTestEngine(); + EngineEmbedderApiModifier modifier(engine.get()); + + const char* channel = "test"; + const std::vector test_message = {1, 2, 3, 4}; + + // Without a respones, SendPlatformMessage should be a simple passthrough. + bool called = false; + modifier.embedder_api().SendPlatformMessage = MOCK_ENGINE_PROC( + SendPlatformMessage, ([&called, test_message](auto engine, auto message) { + called = true; + EXPECT_STREQ(message->channel, "test"); + EXPECT_EQ(message->message_size, test_message.size()); + EXPECT_EQ(memcmp(message->message, test_message.data(), + message->message_size), + 0); + EXPECT_EQ(message->response_handle, nullptr); + return kSuccess; + })); + + engine->SendPlatformMessage(channel, test_message.data(), test_message.size(), + nullptr, nullptr); + EXPECT_TRUE(called); +} + +TEST(FlutterWindowsEngine, SendPlatformMessageWithResponse) { + std::unique_ptr engine = GetTestEngine(); + EngineEmbedderApiModifier modifier(engine.get()); + + const char* channel = "test"; + const std::vector test_message = {1, 2, 3, 4}; + auto* dummy_response_handle = + reinterpret_cast(5); + const FlutterDesktopBinaryReply reply_handler = [](auto... args) {}; + void* reply_user_data = reinterpret_cast(6); + + // When a response is requested, a handle should be created, passed as part + // of the message, and then released. + bool create_response_handle_called = false; + modifier.embedder_api().PlatformMessageCreateResponseHandle = + MOCK_ENGINE_PROC( + PlatformMessageCreateResponseHandle, + ([&create_response_handle_called, &reply_handler, reply_user_data, + dummy_response_handle](auto engine, auto reply, auto user_data, + auto response_handle) { + create_response_handle_called = true; + EXPECT_EQ(reply, reply_handler); + EXPECT_EQ(user_data, reply_user_data); + EXPECT_NE(response_handle, nullptr); + *response_handle = dummy_response_handle; + return kSuccess; + })); + bool release_response_handle_called = false; + modifier.embedder_api().PlatformMessageReleaseResponseHandle = + MOCK_ENGINE_PROC( + PlatformMessageReleaseResponseHandle, + ([&release_response_handle_called, dummy_response_handle]( + auto engine, auto response_handle) { + release_response_handle_called = true; + EXPECT_EQ(response_handle, dummy_response_handle); + return kSuccess; + })); + bool send_message_called = false; + modifier.embedder_api().SendPlatformMessage = MOCK_ENGINE_PROC( + SendPlatformMessage, ([&send_message_called, test_message, + dummy_response_handle](auto engine, auto message) { + send_message_called = true; + EXPECT_STREQ(message->channel, "test"); + EXPECT_EQ(message->message_size, test_message.size()); + EXPECT_EQ(memcmp(message->message, test_message.data(), + message->message_size), + 0); + EXPECT_EQ(message->response_handle, dummy_response_handle); + return kSuccess; + })); + + engine->SendPlatformMessage(channel, test_message.data(), test_message.size(), + reply_handler, reply_user_data); + EXPECT_TRUE(create_response_handle_called); + EXPECT_TRUE(release_response_handle_called); + EXPECT_TRUE(send_message_called); +} + +} // namespace testing +} // namespace flutter diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 415f074a8e99f..1ef5c033fcae6 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -109,16 +109,12 @@ void FlutterWindowsView::OnScroll(double x, void FlutterWindowsView::SendWindowMetrics(size_t width, size_t height, double dpiScale) const { - if (engine_->engine() == nullptr) { - return; - } - FlutterWindowMetricsEvent event = {}; event.struct_size = sizeof(event); event.width = width; event.height = height; event.pixel_ratio = dpiScale; - auto result = FlutterEngineSendWindowMetricsEvent(engine_->engine(), &event); + engine_->SendWindowMetricsEvent(event); } void FlutterWindowsView::SendInitialBounds() { @@ -237,7 +233,7 @@ void FlutterWindowsView::SendPointerEventWithData( std::chrono::high_resolution_clock::now().time_since_epoch()) .count(); - FlutterEngineSendPointerEvent(engine_->engine(), &event, 1); + engine_->SendPointerEvent(event); if (event_data.phase == FlutterPointerPhase::kAdd) { SetMouseFlutterStateAdded(true); diff --git a/shell/platform/windows/testing/engine_embedder_api_modifier.h b/shell/platform/windows/testing/engine_embedder_api_modifier.h new file mode 100644 index 0000000000000..a06f1df5ae6c5 --- /dev/null +++ b/shell/platform/windows/testing/engine_embedder_api_modifier.h @@ -0,0 +1,30 @@ +// 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/flutter_windows_engine.h" + +namespace flutter { + +// A test utility class providing the ability to access and alter the embedder +// API proc table for an engine instance. +// +// This simply provides a way to access the normally-private embedder proc +// table, so the lifetime of any changes made to the proc table is that of the +// engine object, not this helper. +class EngineEmbedderApiModifier { + public: + explicit EngineEmbedderApiModifier(FlutterWindowsEngine* engine) + : engine_(engine) {} + + // Returns the engine's embedder API proc table, allowing for modification. + // + // Modifications are to the engine, and will last for the lifetime of the + // engine unless overwritten again. + FlutterEngineProcTable& embedder_api() { return engine_->embedder_api_; } + + private: + FlutterWindowsEngine* engine_; +}; + +} // namespace flutter diff --git a/shell/platform/windows/win32_task_runner.cc b/shell/platform/windows/win32_task_runner.cc index 6322131fc5fe2..9f6d26db86b91 100644 --- a/shell/platform/windows/win32_task_runner.cc +++ b/shell/platform/windows/win32_task_runner.cc @@ -11,8 +11,10 @@ namespace flutter { Win32TaskRunner::Win32TaskRunner(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; @@ -67,10 +69,9 @@ std::chrono::nanoseconds Win32TaskRunner::ProcessTasks() { } Win32TaskRunner::TaskTimePoint Win32TaskRunner::TimePointFromFlutterTime( - uint64_t flutter_target_time_nanos) { + uint64_t flutter_target_time_nanos) const { const auto now = TaskTimePoint::clock::now(); - const auto flutter_duration = - flutter_target_time_nanos - FlutterEngineGetCurrentTime(); + const auto flutter_duration = flutter_target_time_nanos - get_current_time_(); return now + std::chrono::nanoseconds(flutter_duration); } diff --git a/shell/platform/windows/win32_task_runner.h b/shell/platform/windows/win32_task_runner.h index a35490a8563b1..61a5ab7f00e9c 100644 --- a/shell/platform/windows/win32_task_runner.h +++ b/shell/platform/windows/win32_task_runner.h @@ -18,13 +18,17 @@ 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 { 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, + CurrentTimeProc get_current_time, const TaskExpiredCallback& on_task_expired); ~Win32TaskRunner(); @@ -53,7 +57,13 @@ class Win32TaskRunner { } }; }; + + // Returns a TaskTimePoint computed from the given target time from Flutter. + TaskTimePoint TimePointFromFlutterTime( + uint64_t flutter_target_time_nanos) const; + DWORD main_thread_id_; + CurrentTimeProc get_current_time_; TaskExpiredCallback on_task_expired_; std::mutex task_queue_mutex_; std::priority_queue, Task::Comparer> task_queue_; @@ -61,9 +71,6 @@ class Win32TaskRunner { Win32TaskRunner(const Win32TaskRunner&) = delete; Win32TaskRunner& operator=(const Win32TaskRunner&) = delete; - - static TaskTimePoint TimePointFromFlutterTime( - uint64_t flutter_target_time_nanos); }; } // namespace flutter