Skip to content

Commit

Permalink
Add FlutterDesktopWindowProperties to the public API (#133)
Browse files Browse the repository at this point in the history
* Refactor using FlutterProjectBundle

* Unsupport relative paths

* Reland the support for relative paths

* Add FlutterDesktopWindowProperties to the public API

* Document undocumented public APIs

* Rebase and resolve conflicts

* Enable FlutterTizenEngineTest.Run_Twice

* Add documentation
  • Loading branch information
swift-kim committed Sep 1, 2022
1 parent e75f26f commit 436b450
Show file tree
Hide file tree
Showing 17 changed files with 418 additions and 235 deletions.
2 changes: 2 additions & 0 deletions shell/platform/tizen/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ _flutter_tizen_source = [
"channels/navigation_channel.cc",
"channels/platform_view_channel.cc",
"channels/text_input_channel.cc",
"flutter_project_bundle.cc",
"flutter_tizen.cc",
"flutter_tizen_engine.cc",
"flutter_tizen_texture_registrar.cc",
Expand Down Expand Up @@ -139,6 +140,7 @@ template("embedder_for_profile") {
libs += [
"base-utils-i18n",
"capi-appfw-application",
"capi-appfw-app-common",
"capi-base-common",
"capi-system-info",
"capi-system-system-settings",
Expand Down
1 change: 1 addition & 0 deletions shell/platform/tizen/external_texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <atomic>
#include <memory>

#include "flutter/shell/platform/common/public/flutter_texture_registrar.h"
#include "flutter/shell/platform/embedder/embedder.h"

Expand Down
101 changes: 101 additions & 0 deletions shell/platform/tizen/flutter_project_bundle.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.
// 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_project_bundle.h"

#ifdef __X64_SHELL__
#include "flutter/shell/platform/common/path_utils.h"
#else
#include <app_common.h>
#endif

#include <filesystem>

#include "flutter/shell/platform/tizen/tizen_log.h"

namespace flutter {

#ifndef __X64_SHELL__
namespace {

// Returns the path of the directory containing the app binary, or an empty
// string if the directory cannot be found.
std::filesystem::path GetExecutableDirectory() {
auto res_path = app_get_resource_path();
if (res_path == nullptr) {
return std::filesystem::path();
}
auto bin_path = std::filesystem::path(res_path) / ".." / "bin";
free(res_path);
return bin_path.lexically_normal();
}

} // namespace
#endif

FlutterProjectBundle::FlutterProjectBundle(
const FlutterDesktopEngineProperties& properties)
: assets_path_(properties.assets_path),
icu_path_(properties.icu_data_path) {
if (properties.aot_library_path != nullptr) {
aot_library_path_ = std::filesystem::path(properties.aot_library_path);
}

// Resolve any relative paths.
if (assets_path_.is_relative() || icu_path_.is_relative() ||
(!aot_library_path_.empty() && aot_library_path_.is_relative())) {
std::filesystem::path executable_location = GetExecutableDirectory();
if (executable_location.empty()) {
FT_LOGE("Unable to find executable location to resolve resource paths.");
assets_path_ = std::filesystem::path();
icu_path_ = std::filesystem::path();
} else {
assets_path_ = std::filesystem::path(executable_location) / assets_path_;
icu_path_ = std::filesystem::path(executable_location) / icu_path_;
if (!aot_library_path_.empty()) {
aot_library_path_ =
std::filesystem::path(executable_location) / aot_library_path_;
}
}
}

switches_.insert(switches_.end(), properties.switches,
properties.switches + properties.switches_count);
}

bool FlutterProjectBundle::HasValidPaths() {
return !assets_path_.empty() && !icu_path_.empty();
}

// 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(
const FlutterEngineProcTable& engine_procs) {
if (aot_library_path_.empty()) {
FT_LOGE(
"Attempted to load AOT data, but no aot_library_path was provided.");
return UniqueAotDataPtr(nullptr, nullptr);
}
if (!std::filesystem::exists(aot_library_path_)) {
FT_LOGE("Can't load AOT data from %s; no such file.",
aot_library_path_.u8string().c_str());
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 = engine_procs.CreateAOTData(&source, &data);
if (result != kSuccess) {
FT_LOGE("Failed to load AOT data from: %s", path_string.c_str());
return UniqueAotDataPtr(nullptr, nullptr);
}
return UniqueAotDataPtr(data, engine_procs.CollectAOTData);
}

FlutterProjectBundle::~FlutterProjectBundle() {}

} // namespace flutter
62 changes: 62 additions & 0 deletions shell/platform/tizen/flutter_project_bundle.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2021 Samsung Electronics Co., Ltd. All rights reserved.
// 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.

#ifndef EMBEDDER_FLUTTER_PROJECT_BUNDLE_H_
#define EMBEDDER_FLUTTER_PROJECT_BUNDLE_H_

#include <filesystem>
#include <string>
#include <vector>

#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/tizen/public/flutter_tizen.h"

namespace flutter {

using UniqueAotDataPtr =
std::unique_ptr<_FlutterEngineAOTData, FlutterEngineCollectAOTDataFnPtr>;

// The data associated with a Flutter project needed to run it in an engine.
class FlutterProjectBundle {
public:
// Creates a new project bundle from the given properties.
//
// Treats any relative paths as relative to the directory of the app binary.
explicit FlutterProjectBundle(
const FlutterDesktopEngineProperties& properties);

~FlutterProjectBundle();

// Whether or not the bundle is valid. This does not check that the paths
// exist, or contain valid data, just that paths were able to be constructed.
bool HasValidPaths();

// Returns the path to the assets directory.
const std::filesystem::path& assets_path() { return assets_path_; }

// Returns the path to the ICU data file.
const std::filesystem::path& icu_path() { return icu_path_; }

// Returns any switches that should be passed to the engine.
const std::vector<std::string> switches() { return switches_; }

// Attempts to load AOT data for this bundle. The returned data must be
// retained until any engine instance it is passed to has been shut down.
//
// Logs and returns nullptr on failure.
UniqueAotDataPtr LoadAotData(const FlutterEngineProcTable& engine_procs);

private:
std::filesystem::path assets_path_;
std::filesystem::path icu_path_;
std::vector<std::string> switches_ = {};

// Path to the AOT library file, if any.
std::filesystem::path aot_library_path_;
};

} // namespace flutter

#endif // EMBEDDER_FLUTTER_PROJECT_BUNDLE_H_
15 changes: 11 additions & 4 deletions shell/platform/tizen/flutter_tizen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "flutter/shell/platform/common/client_wrapper/include/flutter/plugin_registrar.h"
#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h"
#include "flutter/shell/platform/common/incoming_message_dispatcher.h"
#include "flutter/shell/platform/tizen/flutter_project_bundle.h"
#include "flutter/shell/platform/tizen/flutter_tizen_engine.h"
#include "flutter/shell/platform/tizen/public/flutter_platform_view.h"
#include "flutter/shell/platform/tizen/tizen_log.h"
Expand All @@ -25,12 +26,18 @@ static FlutterDesktopEngineRef HandleForEngine(
}

FlutterDesktopEngineRef FlutterDesktopRunEngine(
const FlutterDesktopEngineProperties& engine_properties,
bool headed) {
const FlutterDesktopWindowProperties& window_properties,
const FlutterDesktopEngineProperties& engine_properties) {
flutter::StartLogging();

auto engine = std::make_unique<flutter::FlutterTizenEngine>(headed);
if (!engine->RunEngine(engine_properties)) {
flutter::FlutterProjectBundle project(engine_properties);
auto engine = std::make_unique<flutter::FlutterTizenEngine>(project);
if (window_properties.headed) {
engine->InitializeRenderer(window_properties.x, window_properties.y,
window_properties.width,
window_properties.height);
}
if (!engine->RunEngine()) {
FT_LOGE("Failed to run the Flutter engine.");
return nullptr;
}
Expand Down
97 changes: 42 additions & 55 deletions shell/platform/tizen/flutter_tizen_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#include "flutter_tizen_engine.h"

#include <filesystem>
#include <algorithm>
#include <string>
#include <vector>

Expand Down Expand Up @@ -33,7 +33,9 @@ constexpr double kProfileFactor = 1.0;

} // namespace

FlutterTizenEngine::FlutterTizenEngine(bool headed) {
FlutterTizenEngine::FlutterTizenEngine(const FlutterProjectBundle& project)
: project_(std::make_unique<FlutterProjectBundle>(project)),
aot_data_(nullptr, nullptr) {
embedder_api_.struct_size = sizeof(FlutterEngineProcTable);
FlutterEngineGetProcAddresses(&embedder_api_);

Expand All @@ -55,19 +57,20 @@ FlutterTizenEngine::FlutterTizenEngine(bool headed) {

plugin_registrar_ = std::make_unique<FlutterDesktopPluginRegistrar>();
plugin_registrar_->engine = this;

if (headed) {
InitializeRenderer();
}
}

FlutterTizenEngine::~FlutterTizenEngine() {
renderer = nullptr;
}

void FlutterTizenEngine::InitializeRenderer() {
void FlutterTizenEngine::InitializeRenderer(int32_t x,
int32_t y,
int32_t width,
int32_t height) {
TizenRenderer::WindowGeometry geometry = {x, y, width, height};

#ifdef TIZEN_RENDERER_EVAS_GL
renderer = std::make_unique<TizenRendererEvasGL>(*this);
renderer = std::make_unique<TizenRendererEvasGL>(geometry, *this);

render_loop_ = std::make_unique<TizenRenderEventLoop>(
std::this_thread::get_id(), // main thread
Expand All @@ -78,7 +81,7 @@ void FlutterTizenEngine::InitializeRenderer() {
},
renderer.get());
#else
renderer = std::make_unique<TizenRendererEcoreWl2>(*this);
renderer = std::make_unique<TizenRendererEcoreWl2>(geometry, *this);

tizen_vsync_waiter_ = std::make_unique<TizenVsyncWaiter>(this);
#endif
Expand All @@ -88,52 +91,42 @@ void FlutterTizenEngine::NotifyLowMemoryWarning() {
embedder_api_.NotifyLowMemoryWarning(engine_);
}

// Attempts to load AOT data from the given path, which must be absolute and
// non-empty. Logs and returns nullptr on failure.
UniqueAotDataPtr FlutterTizenEngine::LoadAotData(std::string aot_data_path) {
if (aot_data_path.empty()) {
FT_LOGE(
"Attempted to load AOT data, but no aot_library_path was provided.");
return nullptr;
}
if (!std::filesystem::exists(aot_data_path)) {
FT_LOGE("Can't load AOT data from %s; no such file.",
aot_data_path.c_str());
return nullptr;
}
FlutterEngineAOTDataSource source = {};
source.type = kFlutterEngineAOTDataSourceTypeElfPath;
source.elf_path = aot_data_path.c_str();
FlutterEngineAOTData data = nullptr;
auto result = embedder_api_.CreateAOTData(&source, &data);
if (result != kSuccess) {
FT_LOGE("Failed to load AOT data from: %s", aot_data_path.c_str());
return nullptr;
bool FlutterTizenEngine::RunEngine() {
if (engine_ != nullptr) {
FT_LOGE("The engine has already started.");
return false;
}
return UniqueAotDataPtr(data);
}

bool FlutterTizenEngine::RunEngine(
const FlutterDesktopEngineProperties& engine_properties) {
if (IsHeaded() && !renderer->IsValid()) {
FT_LOGE("The display was not valid.");
return false;
}

if (!project_->HasValidPaths()) {
FT_LOGE("Missing or unresolvable paths to assets.");
return false;
}
std::string assets_path_string = project_->assets_path().u8string();
std::string icu_path_string = project_->icu_path().u8string();
if (embedder_api_.RunsAOTCompiledDartCode()) {
aot_data_ = project_->LoadAotData(embedder_api_);
if (!aot_data_) {
FT_LOGE("Unable to start engine without AOT data.");
return false;
}
}

// FlutterProjectArgs is expecting a full argv, so when processing it for
// flags the first item is treated as the executable and ignored. Add a dummy
// value so that all provided arguments are used.
std::vector<std::string> switches = project_->switches();
std::vector<const char*> argv = {"placeholder"};
if (engine_properties.switches_count > 0) {
argv.insert(argv.end(), &engine_properties.switches[0],
&engine_properties.switches[engine_properties.switches_count]);
}
std::transform(
switches.begin(), switches.end(), std::back_inserter(argv),
[](const std::string& arg) -> const char* { return arg.c_str(); });

for (size_t i = 0; i < engine_properties.switches_count; ++i) {
auto str = std::string{engine_properties.switches[i]};
if (str.find("verbose-logging") != std::string::npos) {
SetMinLoggingLevel(DLOG_INFO);
}
if (std::find(switches.begin(), switches.end(), "verbose-logging") !=
switches.end()) {
SetMinLoggingLevel(DLOG_INFO);
}

// Configure task runners.
Expand Down Expand Up @@ -173,10 +166,10 @@ bool FlutterTizenEngine::RunEngine(

FlutterProjectArgs args = {};
args.struct_size = sizeof(FlutterProjectArgs);
args.assets_path = engine_properties.assets_path;
args.icu_data_path = engine_properties.icu_data_path;
args.assets_path = assets_path_string.c_str();
args.icu_data_path = icu_path_string.c_str();
args.command_line_argc = static_cast<int>(argv.size());
args.command_line_argv = &argv[0];
args.command_line_argv = argv.size() > 0 ? argv.data() : nullptr;
args.platform_message_callback =
[](const FlutterPlatformMessage* engine_message, void* user_data) {
if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) {
Expand All @@ -198,13 +191,7 @@ bool FlutterTizenEngine::RunEngine(
};
}
#endif

if (embedder_api_.RunsAOTCompiledDartCode()) {
aot_data_ = LoadAotData(engine_properties.aot_library_path);
if (!aot_data_) {
FT_LOGE("Unable to start engine without AOT data.");
return false;
}
if (aot_data_) {
args.aot_data = aot_data_.get();
}

Expand Down Expand Up @@ -357,7 +344,7 @@ void FlutterTizenEngine::SetWindowOrientation(int32_t degree) {
renderer->SetRotate(degree);
// Compute renderer transformation based on the angle of rotation.
double rad = (360 - degree) * M_PI / 180;
auto geometry = renderer->GetGeometry();
auto geometry = renderer->GetCurrentGeometry();
double width = geometry.w;
double height = geometry.h;

Expand Down
Loading

0 comments on commit 436b450

Please sign in to comment.