blob: 261eb0f6b980f7834ffd81ab58e6261b0871a85d [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_test_context.h"
#include <utility>
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/paths.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/shell/platform/embedder/tests/embedder_assertions.h"
#include "flutter/testing/testing.h"
#include "third_party/dart/runtime/bin/elf_loader.h"
#include "third_party/skia/include/core/SkSurface.h"
namespace flutter {
namespace testing {
EmbedderTestContext::EmbedderTestContext(std::string assets_path)
: assets_path_(std::move(assets_path)),
aot_symbols_(
LoadELFSymbolFromFixturesIfNeccessary(kDefaultAOTAppELFFileName)),
native_resolver_(std::make_shared<TestDartNativeResolver>()) {
SetupAOTMappingsIfNecessary();
SetupAOTDataIfNecessary();
isolate_create_callbacks_.push_back(
[weak_resolver =
std::weak_ptr<TestDartNativeResolver>{native_resolver_}]() {
if (auto resolver = weak_resolver.lock()) {
resolver->SetNativeResolverForIsolate();
}
});
}
EmbedderTestContext::~EmbedderTestContext() = default;
void EmbedderTestContext::SetupAOTMappingsIfNecessary() {
if (!DartVM::IsRunningPrecompiledCode()) {
return;
}
vm_snapshot_data_ =
std::make_unique<fml::NonOwnedMapping>(aot_symbols_.vm_snapshot_data, 0u);
vm_snapshot_instructions_ = std::make_unique<fml::NonOwnedMapping>(
aot_symbols_.vm_snapshot_instrs, 0u);
isolate_snapshot_data_ =
std::make_unique<fml::NonOwnedMapping>(aot_symbols_.vm_isolate_data, 0u);
isolate_snapshot_instructions_ = std::make_unique<fml::NonOwnedMapping>(
aot_symbols_.vm_isolate_instrs, 0u);
}
void EmbedderTestContext::SetupAOTDataIfNecessary() {
if (!DartVM::IsRunningPrecompiledCode()) {
return;
}
FlutterEngineAOTDataSource data_in = {};
FlutterEngineAOTData data_out = nullptr;
const auto elf_path = fml::paths::JoinPaths(
{GetFixturesPath(), testing::kDefaultAOTAppELFFileName});
data_in.type = kFlutterEngineAOTDataSourceTypeElfPath;
data_in.elf_path = elf_path.c_str();
ASSERT_EQ(FlutterEngineCreateAOTData(&data_in, &data_out), kSuccess);
aot_data_.reset(data_out);
}
const std::string& EmbedderTestContext::GetAssetsPath() const {
return assets_path_;
}
const fml::Mapping* EmbedderTestContext::GetVMSnapshotData() const {
return vm_snapshot_data_.get();
}
const fml::Mapping* EmbedderTestContext::GetVMSnapshotInstructions() const {
return vm_snapshot_instructions_.get();
}
const fml::Mapping* EmbedderTestContext::GetIsolateSnapshotData() const {
return isolate_snapshot_data_.get();
}
const fml::Mapping* EmbedderTestContext::GetIsolateSnapshotInstructions()
const {
return isolate_snapshot_instructions_.get();
}
FlutterEngineAOTData EmbedderTestContext::GetAOTData() const {
return aot_data_.get();
}
void EmbedderTestContext::SetRootSurfaceTransformation(SkMatrix matrix) {
root_surface_transformation_ = matrix;
}
void EmbedderTestContext::AddIsolateCreateCallback(
const fml::closure& closure) {
if (closure) {
isolate_create_callbacks_.push_back(closure);
}
}
VoidCallback EmbedderTestContext::GetIsolateCreateCallbackHook() {
return [](void* user_data) {
reinterpret_cast<EmbedderTestContext*>(user_data)
->FireIsolateCreateCallbacks();
};
}
void EmbedderTestContext::FireIsolateCreateCallbacks() {
for (auto closure : isolate_create_callbacks_) {
closure();
}
}
void EmbedderTestContext::AddNativeCallback(const char* name,
Dart_NativeFunction function) {
native_resolver_->AddNativeCallback({name}, function);
}
void EmbedderTestContext::SetSemanticsNodeCallback(
SemanticsNodeCallback update_semantics_node_callback) {
update_semantics_node_callback_ = std::move(update_semantics_node_callback);
}
void EmbedderTestContext::SetSemanticsCustomActionCallback(
SemanticsActionCallback update_semantics_custom_action_callback) {
update_semantics_custom_action_callback_ =
std::move(update_semantics_custom_action_callback);
}
void EmbedderTestContext::SetPlatformMessageCallback(
const std::function<void(const FlutterPlatformMessage*)>& callback) {
platform_message_callback_ = callback;
}
void EmbedderTestContext::PlatformMessageCallback(
const FlutterPlatformMessage* message) {
if (platform_message_callback_) {
platform_message_callback_(message);
}
}
void EmbedderTestContext::SetLogMessageCallback(
const LogMessageCallback& callback) {
log_message_callback_ = callback;
}
FlutterUpdateSemanticsNodeCallback
EmbedderTestContext::GetUpdateSemanticsNodeCallbackHook() {
return [](const FlutterSemanticsNode* semantics_node, void* user_data) {
auto context = reinterpret_cast<EmbedderTestContext*>(user_data);
if (auto callback = context->update_semantics_node_callback_) {
callback(semantics_node);
}
};
}
FlutterUpdateSemanticsCustomActionCallback
EmbedderTestContext::GetUpdateSemanticsCustomActionCallbackHook() {
return [](const FlutterSemanticsCustomAction* action, void* user_data) {
auto context = reinterpret_cast<EmbedderTestContext*>(user_data);
if (auto callback = context->update_semantics_custom_action_callback_) {
callback(action);
}
};
}
FlutterLogMessageCallback EmbedderTestContext::GetLogMessageCallbackHook() {
return [](const char* tag, const char* message, void* user_data) {
auto context = reinterpret_cast<EmbedderTestContext*>(user_data);
if (auto callback = context->log_message_callback_) {
callback(tag, message);
}
};
}
FlutterComputePlatformResolvedLocaleCallback
EmbedderTestContext::GetComputePlatformResolvedLocaleCallbackHook() {
return [](const FlutterLocale** supported_locales,
size_t length) -> const FlutterLocale* {
return supported_locales[0];
};
}
FlutterTransformation EmbedderTestContext::GetRootSurfaceTransformation() {
return FlutterTransformationMake(root_surface_transformation_);
}
EmbedderTestCompositor& EmbedderTestContext::GetCompositor() {
FML_CHECK(compositor_)
<< "Accessed the compositor on a context where one was not set up. Use "
"the config builder to set up a context with a custom compositor.";
return *compositor_;
}
void EmbedderTestContext::SetNextSceneCallback(
const NextSceneCallback& next_scene_callback) {
if (compositor_) {
compositor_->SetNextSceneCallback(next_scene_callback);
return;
}
next_scene_callback_ = next_scene_callback;
}
std::future<sk_sp<SkImage>> EmbedderTestContext::GetNextSceneImage() {
std::promise<sk_sp<SkImage>> promise;
auto future = promise.get_future();
SetNextSceneCallback(
fml::MakeCopyable([promise = std::move(promise)](auto image) mutable {
promise.set_value(image);
}));
return future;
}
/// @note Procedure doesn't copy all closures.
void EmbedderTestContext::FireRootSurfacePresentCallbackIfPresent(
const std::function<sk_sp<SkImage>(void)>& image_callback) {
if (!next_scene_callback_) {
return;
}
auto callback = next_scene_callback_;
next_scene_callback_ = nullptr;
callback(image_callback());
}
void EmbedderTestContext::SetVsyncCallback(
std::function<void(intptr_t)> callback) {
vsync_callback_ = std::move(callback);
}
void EmbedderTestContext::RunVsyncCallback(intptr_t baton) {
vsync_callback_(baton);
}
} // namespace testing
} // namespace flutter