mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
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.
This commit is contained in:
parent
d27ff811b9
commit
91eab23eb3
@ -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
|
||||
|
||||
@ -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",
|
||||
]
|
||||
|
||||
@ -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() {}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -90,15 +90,20 @@ FlutterLocale CovertToFlutterLocale(const LanguageInfo& info) {
|
||||
} // namespace
|
||||
|
||||
FlutterWindowsEngine::FlutterWindowsEngine(const FlutterProjectBundle& project)
|
||||
: project_(std::make_unique<FlutterProjectBundle>(project)) {
|
||||
: project_(std::make_unique<FlutterProjectBundle>(project)),
|
||||
aot_data_(nullptr, nullptr) {
|
||||
embedder_api_.struct_size = sizeof(FlutterEngineProcTable);
|
||||
FlutterEngineGetProcAddresses(&embedder_api_);
|
||||
|
||||
task_runner_ = std::make_unique<Win32TaskRunner>(
|
||||
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<LanguageInfo> languages = GetPreferredLanguageInfo();
|
||||
std::vector<FlutterLocale> 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.
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include <vector>
|
||||
|
||||
#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<FlutterProjectBundle> project_;
|
||||
|
||||
// AOT data, if any.
|
||||
|
||||
112
shell/platform/windows/flutter_windows_engine_unittests.cc
Normal file
112
shell/platform/windows/flutter_windows_engine_unittests.cc
Normal file
@ -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<FlutterWindowsEngine> 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<FlutterWindowsEngine>(project);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(FlutterWindowsEngine, SendPlatformMessageWithoutResponse) {
|
||||
std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
|
||||
EngineEmbedderApiModifier modifier(engine.get());
|
||||
|
||||
const char* channel = "test";
|
||||
const std::vector<uint8_t> 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<FlutterWindowsEngine> engine = GetTestEngine();
|
||||
EngineEmbedderApiModifier modifier(engine.get());
|
||||
|
||||
const char* channel = "test";
|
||||
const std::vector<uint8_t> test_message = {1, 2, 3, 4};
|
||||
auto* dummy_response_handle =
|
||||
reinterpret_cast<FlutterPlatformMessageResponseHandle*>(5);
|
||||
const FlutterDesktopBinaryReply reply_handler = [](auto... args) {};
|
||||
void* reply_user_data = reinterpret_cast<void*>(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
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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<void(const FlutterTask*)>;
|
||||
// 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, std::deque<Task>, 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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user