blob: fa99c15e5a7e79e05748d585eddd7a129ed1eec0 [file] [log] [blame]
// 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/embedder/tests/embedder_config_builder.h"
#include "flutter/common/constants.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "tests/embedder_test_context.h"
#include "third_party/skia/include/core/SkImage.h"
namespace flutter::testing {
EmbedderConfigBuilder::EmbedderConfigBuilder(
EmbedderTestContext& context,
InitializationPreference preference)
: context_(context) {
project_args_.struct_size = sizeof(project_args_);
project_args_.shutdown_dart_vm_when_done = true;
project_args_.platform_message_callback =
[](const FlutterPlatformMessage* message, void* context) {
reinterpret_cast<EmbedderTestContext*>(context)
->PlatformMessageCallback(message);
};
custom_task_runners_.struct_size = sizeof(FlutterCustomTaskRunners);
// The first argument is always the executable name. Don't make tests have to
// do this manually.
AddCommandLineArgument("embedder_unittest");
if (preference != InitializationPreference::kNoInitialize) {
SetAssetsPath();
SetIsolateCreateCallbackHook();
SetSemanticsCallbackHooks();
SetLogMessageCallbackHook();
SetLocalizationCallbackHooks();
SetChannelUpdateCallbackHook();
AddCommandLineArgument("--disable-vm-service");
if (preference == InitializationPreference::kSnapshotsInitialize ||
preference == InitializationPreference::kMultiAOTInitialize) {
SetSnapshots();
}
if (preference == InitializationPreference::kAOTDataInitialize ||
preference == InitializationPreference::kMultiAOTInitialize) {
SetAOTDataElf();
}
}
}
EmbedderConfigBuilder::~EmbedderConfigBuilder() = default;
FlutterProjectArgs& EmbedderConfigBuilder::GetProjectArgs() {
return project_args_;
}
void EmbedderConfigBuilder::SetAssetsPath() {
project_args_.assets_path = context_.GetAssetsPath().c_str();
}
void EmbedderConfigBuilder::SetSnapshots() {
if (auto mapping = context_.GetVMSnapshotData()) {
project_args_.vm_snapshot_data = mapping->GetMapping();
project_args_.vm_snapshot_data_size = mapping->GetSize();
}
if (auto mapping = context_.GetVMSnapshotInstructions()) {
project_args_.vm_snapshot_instructions = mapping->GetMapping();
project_args_.vm_snapshot_instructions_size = mapping->GetSize();
}
if (auto mapping = context_.GetIsolateSnapshotData()) {
project_args_.isolate_snapshot_data = mapping->GetMapping();
project_args_.isolate_snapshot_data_size = mapping->GetSize();
}
if (auto mapping = context_.GetIsolateSnapshotInstructions()) {
project_args_.isolate_snapshot_instructions = mapping->GetMapping();
project_args_.isolate_snapshot_instructions_size = mapping->GetSize();
}
}
void EmbedderConfigBuilder::SetAOTDataElf() {
project_args_.aot_data = context_.GetAOTData();
}
void EmbedderConfigBuilder::SetIsolateCreateCallbackHook() {
project_args_.root_isolate_create_callback =
EmbedderTestContext::GetIsolateCreateCallbackHook();
}
void EmbedderConfigBuilder::SetSemanticsCallbackHooks() {
project_args_.update_semantics_callback2 =
context_.GetUpdateSemanticsCallback2Hook();
project_args_.update_semantics_callback =
context_.GetUpdateSemanticsCallbackHook();
project_args_.update_semantics_node_callback =
context_.GetUpdateSemanticsNodeCallbackHook();
project_args_.update_semantics_custom_action_callback =
context_.GetUpdateSemanticsCustomActionCallbackHook();
}
void EmbedderConfigBuilder::SetLogMessageCallbackHook() {
project_args_.log_message_callback =
EmbedderTestContext::GetLogMessageCallbackHook();
}
void EmbedderConfigBuilder::SetChannelUpdateCallbackHook() {
project_args_.channel_update_callback =
context_.GetChannelUpdateCallbackHook();
}
void EmbedderConfigBuilder::SetLogTag(std::string tag) {
log_tag_ = std::move(tag);
project_args_.log_tag = log_tag_.c_str();
}
void EmbedderConfigBuilder::SetLocalizationCallbackHooks() {
project_args_.compute_platform_resolved_locale_callback =
EmbedderTestContext::GetComputePlatformResolvedLocaleCallbackHook();
}
void EmbedderConfigBuilder::SetExecutableName(std::string executable_name) {
if (executable_name.empty()) {
return;
}
command_line_arguments_[0] = std::move(executable_name);
}
void EmbedderConfigBuilder::SetDartEntrypoint(std::string entrypoint) {
if (entrypoint.empty()) {
return;
}
dart_entrypoint_ = std::move(entrypoint);
project_args_.custom_dart_entrypoint = dart_entrypoint_.c_str();
}
void EmbedderConfigBuilder::AddCommandLineArgument(std::string arg) {
if (arg.empty()) {
return;
}
command_line_arguments_.emplace_back(std::move(arg));
}
void EmbedderConfigBuilder::AddDartEntrypointArgument(std::string arg) {
if (arg.empty()) {
return;
}
dart_entrypoint_arguments_.emplace_back(std::move(arg));
}
void EmbedderConfigBuilder::SetPlatformTaskRunner(
const FlutterTaskRunnerDescription* runner) {
if (runner == nullptr) {
return;
}
custom_task_runners_.platform_task_runner = runner;
project_args_.custom_task_runners = &custom_task_runners_;
}
void EmbedderConfigBuilder::SetupVsyncCallback() {
project_args_.vsync_callback = [](void* user_data, intptr_t baton) {
auto context = reinterpret_cast<EmbedderTestContext*>(user_data);
context->RunVsyncCallback(baton);
};
}
void EmbedderConfigBuilder::SetRenderTaskRunner(
const FlutterTaskRunnerDescription* runner) {
if (runner == nullptr) {
return;
}
custom_task_runners_.render_task_runner = runner;
project_args_.custom_task_runners = &custom_task_runners_;
}
void EmbedderConfigBuilder::SetPlatformMessageCallback(
const std::function<void(const FlutterPlatformMessage*)>& callback) {
context_.SetPlatformMessageCallback(callback);
}
void EmbedderConfigBuilder::SetCompositor(bool avoid_backing_store_cache,
bool use_present_layers_callback) {
context_.SetupCompositor();
auto& compositor = context_.GetCompositor();
compositor_.struct_size = sizeof(compositor_);
compositor_.user_data = &compositor;
compositor_.create_backing_store_callback =
[](const FlutterBackingStoreConfig* config, //
FlutterBackingStore* backing_store_out, //
void* user_data //
) {
return reinterpret_cast<EmbedderTestCompositor*>(user_data)
->CreateBackingStore(config, backing_store_out);
};
compositor_.collect_backing_store_callback =
[](const FlutterBackingStore* backing_store, //
void* user_data //
) {
return reinterpret_cast<EmbedderTestCompositor*>(user_data)
->CollectBackingStore(backing_store);
};
if (use_present_layers_callback) {
compositor_.present_layers_callback = [](const FlutterLayer** layers,
size_t layers_count,
void* user_data) {
auto compositor = reinterpret_cast<EmbedderTestCompositor*>(user_data);
// The present layers callback is incompatible with multiple views;
// it can only be used to render the implicit view.
return compositor->Present(kFlutterImplicitViewId, layers, layers_count);
};
} else {
compositor_.present_view_callback = [](const FlutterPresentViewInfo* info) {
auto compositor =
reinterpret_cast<EmbedderTestCompositor*>(info->user_data);
return compositor->Present(info->view_id, info->layers,
info->layers_count);
};
}
compositor_.avoid_backing_store_cache = avoid_backing_store_cache;
project_args_.compositor = &compositor_;
}
FlutterCompositor& EmbedderConfigBuilder::GetCompositor() {
return compositor_;
}
void EmbedderConfigBuilder::SetRenderTargetType(
EmbedderTestBackingStoreProducer::RenderTargetType type,
FlutterSoftwarePixelFormat software_pixfmt) {
context_.GetCompositor().SetRenderTargetType(type, software_pixfmt);
}
UniqueEngine EmbedderConfigBuilder::LaunchEngine() const {
return SetupEngine(true);
}
UniqueEngine EmbedderConfigBuilder::InitializeEngine() const {
return SetupEngine(false);
}
UniqueEngine EmbedderConfigBuilder::SetupEngine(bool run) const {
FlutterEngine engine = nullptr;
FlutterProjectArgs project_args = project_args_;
std::vector<const char*> args;
args.reserve(command_line_arguments_.size());
for (const auto& arg : command_line_arguments_) {
args.push_back(arg.c_str());
}
if (!args.empty()) {
project_args.command_line_argv = args.data();
project_args.command_line_argc = args.size();
} else {
// Clear it out in case this is not the first engine launch from the
// embedder config builder.
project_args.command_line_argv = nullptr;
project_args.command_line_argc = 0;
}
std::vector<const char*> dart_args;
dart_args.reserve(dart_entrypoint_arguments_.size());
for (const auto& arg : dart_entrypoint_arguments_) {
dart_args.push_back(arg.c_str());
}
if (!dart_args.empty()) {
project_args.dart_entrypoint_argv = dart_args.data();
project_args.dart_entrypoint_argc = dart_args.size();
} else {
// Clear it out in case this is not the first engine launch from the
// embedder config builder.
project_args.dart_entrypoint_argv = nullptr;
project_args.dart_entrypoint_argc = 0;
}
auto result = run ? FlutterEngineRun(FLUTTER_ENGINE_VERSION,
&context_.GetRendererConfig(),
&project_args, &context_, &engine)
: FlutterEngineInitialize(
FLUTTER_ENGINE_VERSION, &context_.GetRendererConfig(),
&project_args, &context_, &engine);
if (result != kSuccess) {
return {};
}
return UniqueEngine{engine};
}
} // namespace flutter::testing