From 91eab23eb324e83e230bde0faaa85709150e71ff Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Tue, 3 Nov 2020 14:36:18 -0800 Subject: [PATCH] Switch Windows embedding to proc table embedder API (#22211) Switches the Windows embedding from the standard C API to the new proctable version, to allow for unit testing of the embedding layer separately from the embedder APIs implementation. This includes moving some engine messaging that was still in flutter_windows to the C++ engine class to better encapsulate the proc table. --- ci/licenses_golden/licenses_flutter | 1 + shell/platform/windows/BUILD.gn | 6 + .../windows/flutter_project_bundle.cc | 13 +- .../platform/windows/flutter_project_bundle.h | 10 +- shell/platform/windows/flutter_windows.cc | 34 +----- .../windows/flutter_windows_engine.cc | 83 +++++++++++-- .../platform/windows/flutter_windows_engine.h | 31 ++++- .../flutter_windows_engine_unittests.cc | 112 ++++++++++++++++++ .../platform/windows/flutter_windows_view.cc | 8 +- .../testing/engine_embedder_api_modifier.h | 30 +++++ shell/platform/windows/win32_task_runner.cc | 7 +- shell/platform/windows/win32_task_runner.h | 13 +- 12 files changed, 281 insertions(+), 67 deletions(-) create mode 100644 shell/platform/windows/flutter_windows_engine_unittests.cc create mode 100644 shell/platform/windows/testing/engine_embedder_api_modifier.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index f00657c2158..890afa28c66 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 66b578cf0fa..e4945ddd364 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 4790697b585..cbd82933834 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 72ee38d12fd..332b0060a9c 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 d5963a21226..88785507175 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 7516c6a5af0..2641e98c2e9 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 49c0fc7f2a8..045cea0df4b 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 00000000000..18401ea11ee --- /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 415f074a8e9..1ef5c033fca 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 00000000000..a06f1df5ae6 --- /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 6322131fc5f..9f6d26db86b 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 a35490a8563..61a5ab7f00e 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