Skip to content

Commit

Permalink
Add DartProject for Windows embedding API (#17210)
Browse files Browse the repository at this point in the history
This is a step toward aligning the API with macOS, and will make it easier to add the precompiled library later for release mode (since it can just be added to the project directory, without any code changes required for wrapper clients).

At the C API, uses a struct instead of individual arguments, mirroring a change that was already made on the Linux side to make the C API cleaner.

Functional changes in addition to the restructuring:

adds relative path support, as was recently added for GLFW
Uses wstring, rather than string, for paths; the conversion to UTF-8 is actually a potential problem on Windows, so pushing it into the embedding allows us the possibility of removing it later (if we can figure out a good solution at the embedder.h layer) without API breakage.
The old APIs used by the standard runner are left in place for now to avoid breaking the template on an engine roll. Once the framework template has been updated, the old API paths will be removed.
  • Loading branch information
stuartmorgan committed Mar 23, 2020
1 parent 8a8b298 commit 33a21d1
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 100 deletions.
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1145,9 +1145,11 @@ FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.cc
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.h
FILE: ../../../flutter/shell/platform/windows/angle_surface_manager.cc
FILE: ../../../flutter/shell/platform/windows/angle_surface_manager.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/dart_project_unittests.cc
FILE: ../../../flutter/shell/platform/windows/client_wrapper/flutter_view_controller.cc
FILE: ../../../flutter/shell/platform/windows/client_wrapper/flutter_view_controller_unittests.cc
FILE: ../../../flutter/shell/platform/windows/client_wrapper/flutter_view_unittests.cc
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/dart_project.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ FLUTTER_EXPORT
* guarantee, and are subject to change without notice.
*
* Note: This property WILL BE REMOVED in the future. If you use this property, please see
* https://github.com/flutter/flutter/issue/38569.
* https://github.com/flutter/flutter/issues/38569.
*/
@property(nullable) NSArray<NSString*>* engineSwitches;

Expand Down
2 changes: 2 additions & 0 deletions shell/platform/windows/client_wrapper/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import("//flutter/shell/platform/common/cpp/client_wrapper/publish.gni")
import("//flutter/testing/testing.gni")

_wrapper_includes = [
"include/flutter/dart_project.h",
"include/flutter/flutter_view_controller.h",
"include/flutter/flutter_view.h",
"include/flutter/plugin_registrar_windows.h",
Expand Down Expand Up @@ -69,6 +70,7 @@ executable("client_wrapper_windows_unittests") {
testonly = true

sources = [
"dart_project_unittests.cc",
"flutter_view_controller_unittests.cc",
"flutter_view_unittests.cc",
"plugin_registrar_windows_unittests.cc",
Expand Down
46 changes: 46 additions & 0 deletions shell/platform/windows/client_wrapper/dart_project_unittests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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 <memory>
#include <string>

#include "flutter/shell/platform/windows/client_wrapper/include/flutter/dart_project.h"
#include "gtest/gtest.h"

namespace flutter {

class DartProjectTest : public ::testing::Test {
protected:
// Wrapper for accessing private icu_data_path.
std::wstring GetProjectIcuDataPath(const DartProject& project) {
return project.icu_data_path();
}

// Wrapper for accessing private assets_path.
std::wstring GetProjectAssetsPath(const DartProject& project) {
return project.assets_path();
}

// Wrapper for accessing private engine_switches.
std::vector<std::string> GetProjectEngineSwitches(
const DartProject& project) {
return project.engine_switches();
}
};

TEST_F(DartProjectTest, StandardProjectFormat) {
DartProject project(L"test");
EXPECT_EQ(GetProjectIcuDataPath(project), L"test\\icudtl.dat");
EXPECT_EQ(GetProjectAssetsPath(project), L"test\\flutter_assets");
}

TEST_F(DartProjectTest, Switches) {
DartProject project(L"test");
std::vector<std::string> switches = {"--foo", "--bar"};
project.SetEngineSwitches(switches);
EXPECT_EQ(GetProjectEngineSwitches(project).size(), 2);
EXPECT_EQ(GetProjectEngineSwitches(project)[0], "--foo");
}

} // namespace flutter
30 changes: 26 additions & 4 deletions shell/platform/windows/client_wrapper/flutter_view_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,35 @@

namespace flutter {

FlutterViewController::FlutterViewController(int width,
int height,
const DartProject& project) {
std::vector<const char*> switches;
std::transform(
project.engine_switches().begin(), project.engine_switches().end(),
std::back_inserter(switches),
[](const std::string& arg) -> const char* { return arg.c_str(); });
size_t switch_count = switches.size();

FlutterDesktopEngineProperties properties = {};
properties.assets_path = project.assets_path().c_str();
properties.icu_data_path = project.icu_data_path().c_str();
properties.switches = switch_count > 0 ? switches.data() : nullptr;
properties.switches_count = switch_count;
controller_ = FlutterDesktopCreateViewController(width, height, properties);
if (!controller_) {
std::cerr << "Failed to create view controller." << std::endl;
return;
}
view_ = std::make_unique<FlutterView>(FlutterDesktopGetView(controller_));
}

FlutterViewController::FlutterViewController(
const std::string& icu_data_path,
int width,
int height,
const std::string& assets_path,
const std::vector<std::string>& arguments)
: icu_data_path_(icu_data_path) {
const std::vector<std::string>& arguments) {
if (controller_) {
std::cerr << "Only one Flutter view can exist at a time." << std::endl;
}
Expand All @@ -26,8 +48,8 @@ FlutterViewController::FlutterViewController(
[](const std::string& arg) -> const char* { return arg.c_str(); });
size_t arg_count = engine_arguments.size();

controller_ = FlutterDesktopCreateViewController(
width, height, assets_path.c_str(), icu_data_path_.c_str(),
controller_ = FlutterDesktopCreateViewControllerLegacy(
width, height, assets_path.c_str(), icu_data_path.c_str(),
arg_count > 0 ? &engine_arguments[0] : nullptr, arg_count);
if (!controller_) {
std::cerr << "Failed to create view controller." << std::endl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,16 @@ namespace {
// Stub implementation to validate calls to the API.
class TestWindowsApi : public testing::StubFlutterWindowsApi {
FlutterDesktopViewControllerRef CreateViewController(
int initial_width,
int initial_height,
const char* assets_path,
const char* icu_data_path,
const char** arguments,
size_t argument_count) override {
int width,
int height,
const FlutterDesktopEngineProperties& engine_properties) override {
return reinterpret_cast<FlutterDesktopViewControllerRef>(1);
}
};

} // namespace

TEST(FlutterViewControllerTest, CreateDestroy) {
TEST(FlutterViewControllerTest, CreateDestroyLegacy) {
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
std::make_unique<TestWindowsApi>());
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
Expand All @@ -38,13 +35,20 @@ TEST(FlutterViewControllerTest, CreateDestroy) {
}
}

TEST(FlutterViewControllerTest, CreateDestroy) {
DartProject project(L"data");
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
std::make_unique<TestWindowsApi>());
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
{ FlutterViewController controller(100, 100, project); }
}

TEST(FlutterViewControllerTest, GetView) {
std::string icu_data_path = "fake_path_to_icu";
DartProject project(L"data");
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
std::make_unique<TestWindowsApi>());
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
FlutterViewController controller("", 100, 100, "",
std::vector<std::string>{});
FlutterViewController controller(100, 100, project);
EXPECT_NE(controller.view(), nullptr);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// 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 FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_DART_PROJECT_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_DART_PROJECT_H_

#include <string>
#include <vector>

namespace flutter {

// A set of Flutter and Dart assets used to initialize a Flutter engine.
class DartProject {
public:
// Creates a DartProject from a directory path. The directory should contain
// the following top-level items:
// - icudtl.dat (provided as a resource by the Flutter tool)
// - flutter_assets (as built by the Flutter tool)
//
// The path can either be absolute, or relative to the directory containing
// the running executable.
explicit DartProject(const std::wstring& path) {
assets_path_ = path + L"\\flutter_assets";
icu_data_path_ = path + L"\\icudtl.dat";
}

~DartProject() = default;

// Switches to pass to the Flutter engine. See
// https://github.com/flutter/engine/blob/master/shell/common/switches.h
// for details. Not all switches will apply to embedding mode. Switches have
// not stability guarantee, and are subject to change without notice.
//
// Note: This WILL BE REMOVED in the future. If you call this, please see
// https://github.com/flutter/flutter/issues/38569.
void SetEngineSwitches(const std::vector<std::string>& switches) {
engine_switches_ = switches;
}

private:
// Accessors for internals are private, so that they can be changed if more
// flexible options for project structures are needed later without it
// being a breaking change. Provide access to internal classes that need
// them.
friend class FlutterViewController;
friend class DartProjectTest;

const std::wstring& assets_path() const { return assets_path_; }
const std::wstring& icu_data_path() const { return icu_data_path_; }
const std::vector<std::string>& engine_switches() const {
return engine_switches_;
}

// The path to the assets directory.
std::wstring assets_path_;
// The path to the ICU data.
std::wstring icu_data_path_;
// Switches to pass to the engine.
std::vector<std::string> engine_switches_;
};

} // namespace flutter

#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_DART_PROJECT_H_
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <string>
#include <vector>

#include "dart_project.h"
#include "flutter_view.h"
#include "plugin_registrar.h"
#include "plugin_registry.h"
Expand All @@ -24,20 +25,15 @@ namespace flutter {
// methods in the C API directly, as this class will do that internally.
class FlutterViewController : public PluginRegistry {
public:
// There must be only one instance of this class in an application at any
// given time, as Flutter does not support multiple engines in one process,
// or multiple views in one engine.

// Creates a FlutterView that can be parented into a Windows View hierarchy
// either using HWNDs or in the future into a CoreWindow, or using compositor.

// The |assets_path| is the path to the flutter_assets folder for the Flutter
// application to be run. |icu_data_path| is the path to the icudtl.dat file
// for the version of Flutter you are using.
//
// The |arguments| are passed to the Flutter engine. See:
// https://github.com/flutter/engine/blob/master/shell/common/switches.h for
// for details. Not all arguments will apply to desktop.
// |dart_project| will be used to configure the engine backing this view.
explicit FlutterViewController(int width,
int height,
const DartProject& project);

// DEPRECATED. Will be removed soon; use the version above.
explicit FlutterViewController(const std::string& icu_data_path,
int width,
int height,
Expand Down Expand Up @@ -65,10 +61,6 @@ class FlutterViewController : public PluginRegistry {
const std::string& plugin_name) override;

private:
// The path to the ICU data file. Set at creation time since it is the same
// for any view created.
std::string icu_data_path_;

// Handle for interacting with the C API's view controller, if any.
FlutterDesktopViewControllerRef controller_ = nullptr;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,29 @@ ScopedStubFlutterWindowsApi::~ScopedStubFlutterWindowsApi() {
// Forwarding dummy implementations of the C API.

FlutterDesktopViewControllerRef FlutterDesktopCreateViewController(
int width,
int height,
const FlutterDesktopEngineProperties& engine_properties) {
if (s_stub_implementation) {
return s_stub_implementation->CreateViewController(width, height,
engine_properties);
}
return nullptr;
}

FlutterDesktopViewControllerRef FlutterDesktopCreateViewControllerLegacy(
int initial_width,
int initial_height,
const char* assets_path,
const char* icu_data_path,
const char** arguments,
size_t argument_count) {
if (s_stub_implementation) {
// This stub will be removed shortly, and the current tests don't need the
// arguments, so there's no need to translate them to engine_properties.
FlutterDesktopEngineProperties engine_properties;
return s_stub_implementation->CreateViewController(
initial_width, initial_height, assets_path, icu_data_path, arguments,
argument_count);
initial_width, initial_height, engine_properties);
}
return nullptr;
}
Expand Down Expand Up @@ -78,13 +91,10 @@ HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef controller) {
return reinterpret_cast<HWND>(-1);
}

FlutterDesktopEngineRef FlutterDesktopRunEngine(const char* assets_path,
const char* icu_data_path,
const char** arguments,
size_t argument_count) {
FlutterDesktopEngineRef FlutterDesktopRunEngine(
const FlutterDesktopEngineProperties& engine_properties) {
if (s_stub_implementation) {
return s_stub_implementation->RunEngine(assets_path, icu_data_path,
arguments, argument_count);
return s_stub_implementation->RunEngine(engine_properties);
}
return nullptr;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,11 @@ class StubFlutterWindowsApi {

virtual ~StubFlutterWindowsApi() {}

// Called for FlutterDesktopCreateView.
// Called for FlutterDesktopCreateViewController.
virtual FlutterDesktopViewControllerRef CreateViewController(
int initial_width,
int initial_height,
const char* assets_path,
const char* icu_data_path,
const char** arguments,
size_t argument_count) {
int width,
int height,
const FlutterDesktopEngineProperties& engine_properties) {
return nullptr;
}

Expand All @@ -50,10 +47,8 @@ class StubFlutterWindowsApi {
virtual HWND ViewGetHWND() { return reinterpret_cast<HWND>(1); }

// Called for FlutterDesktopRunEngine.
virtual FlutterDesktopEngineRef RunEngine(const char* assets_path,
const char* icu_data_path,
const char** arguments,
size_t argument_count) {
virtual FlutterDesktopEngineRef RunEngine(
const FlutterDesktopEngineProperties& engine_properties) {
return nullptr;
}

Expand Down
Loading

0 comments on commit 33a21d1

Please sign in to comment.