diff --git a/windows/flutter/ephemeral/.plugin_symlinks/package_info_plus b/windows/flutter/ephemeral/.plugin_symlinks/package_info_plus new file mode 120000 index 0000000..984868f --- /dev/null +++ b/windows/flutter/ephemeral/.plugin_symlinks/package_info_plus @@ -0,0 +1 @@ +C:/Users/Jacques/AppData/Local/Pub/Cache/hosted/pub.dev/package_info_plus-9.0.0/ \ No newline at end of file diff --git a/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows b/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows new file mode 120000 index 0000000..95cbc89 --- /dev/null +++ b/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows @@ -0,0 +1 @@ +C:/Users/Jacques/AppData/Local/Pub/Cache/hosted/pub.dev/path_provider_windows-2.3.0/ \ No newline at end of file diff --git a/windows/flutter/ephemeral/.plugin_symlinks/shared_preferences_windows b/windows/flutter/ephemeral/.plugin_symlinks/shared_preferences_windows new file mode 120000 index 0000000..99f4a7c --- /dev/null +++ b/windows/flutter/ephemeral/.plugin_symlinks/shared_preferences_windows @@ -0,0 +1 @@ +C:/Users/Jacques/AppData/Local/Pub/Cache/hosted/pub.dev/shared_preferences_windows-2.4.1/ \ No newline at end of file diff --git a/windows/flutter/ephemeral/.plugin_symlinks/video_player_win b/windows/flutter/ephemeral/.plugin_symlinks/video_player_win new file mode 120000 index 0000000..fd3ba88 --- /dev/null +++ b/windows/flutter/ephemeral/.plugin_symlinks/video_player_win @@ -0,0 +1 @@ +C:/Users/Jacques/AppData/Local/Pub/Cache/hosted/pub.dev/video_player_win-3.2.2/ \ No newline at end of file diff --git a/windows/flutter/ephemeral/.plugin_symlinks/wakelock_plus b/windows/flutter/ephemeral/.plugin_symlinks/wakelock_plus new file mode 120000 index 0000000..12edcc1 --- /dev/null +++ b/windows/flutter/ephemeral/.plugin_symlinks/wakelock_plus @@ -0,0 +1 @@ +C:/Users/Jacques/AppData/Local/Pub/Cache/hosted/pub.dev/wakelock_plus-1.4.0/ \ No newline at end of file diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/binary_messenger_impl.h b/windows/flutter/ephemeral/cpp_client_wrapper/binary_messenger_impl.h new file mode 100644 index 0000000..6558665 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/binary_messenger_impl.h @@ -0,0 +1,50 @@ +// 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_COMMON_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_ + +#include + +#include +#include + +#include "include/flutter/binary_messenger.h" + +namespace flutter { + +// Wrapper around a FlutterDesktopMessengerRef that implements the +// BinaryMessenger API. +class BinaryMessengerImpl : public BinaryMessenger { + public: + explicit BinaryMessengerImpl(FlutterDesktopMessengerRef core_messenger); + + virtual ~BinaryMessengerImpl(); + + // Prevent copying. + BinaryMessengerImpl(BinaryMessengerImpl const&) = delete; + BinaryMessengerImpl& operator=(BinaryMessengerImpl const&) = delete; + + // |flutter::BinaryMessenger| + void Send(const std::string& channel, + const uint8_t* message, + size_t message_size, + BinaryReply reply) const override; + + // |flutter::BinaryMessenger| + void SetMessageHandler(const std::string& channel, + BinaryMessageHandler handler) override; + + private: + // Handle for interacting with the C API. + FlutterDesktopMessengerRef messenger_; + + // A map from channel names to the BinaryMessageHandler that should be called + // for incoming messages on that channel. + std::map handlers_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_BINARY_MESSENGER_IMPL_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/byte_buffer_streams.h b/windows/flutter/ephemeral/cpp_client_wrapper/byte_buffer_streams.h new file mode 100644 index 0000000..55b01c8 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/byte_buffer_streams.h @@ -0,0 +1,102 @@ +// 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_COMMON_CLIENT_WRAPPER_BYTE_BUFFER_STREAMS_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_BYTE_BUFFER_STREAMS_H_ + +#include +#include +#include +#include +#include + +#include "include/flutter/byte_streams.h" + +namespace flutter { + +// Implementation of ByteStreamReader base on a byte array. +class ByteBufferStreamReader : public ByteStreamReader { + public: + // Createa a reader reading from |bytes|, which must have a length of |size|. + // |bytes| must remain valid for the lifetime of this object. + explicit ByteBufferStreamReader(const uint8_t* bytes, size_t size) + : bytes_(bytes), size_(size) {} + + virtual ~ByteBufferStreamReader() = default; + + // |ByteStreamReader| + uint8_t ReadByte() override { + if (location_ >= size_) { + std::cerr << "Invalid read in StandardCodecByteStreamReader" << std::endl; + return 0; + } + return bytes_[location_++]; + } + + // |ByteStreamReader| + void ReadBytes(uint8_t* buffer, size_t length) override { + if (location_ + length > size_) { + std::cerr << "Invalid read in StandardCodecByteStreamReader" << std::endl; + return; + } + std::memcpy(buffer, &bytes_[location_], length); + location_ += length; + } + + // |ByteStreamReader| + void ReadAlignment(uint8_t alignment) override { + uint8_t mod = location_ % alignment; + if (mod) { + location_ += alignment - mod; + } + } + + private: + // The buffer to read from. + const uint8_t* bytes_; + // The total size of the buffer. + size_t size_; + // The current read location. + size_t location_ = 0; +}; + +// Implementation of ByteStreamWriter based on a byte array. +class ByteBufferStreamWriter : public ByteStreamWriter { + public: + // Creates a writer that writes into |buffer|. + // |buffer| must remain valid for the lifetime of this object. + explicit ByteBufferStreamWriter(std::vector* buffer) + : bytes_(buffer) { + assert(buffer); + } + + virtual ~ByteBufferStreamWriter() = default; + + // |ByteStreamWriter| + void WriteByte(uint8_t byte) { bytes_->push_back(byte); } + + // |ByteStreamWriter| + void WriteBytes(const uint8_t* bytes, size_t length) { + assert(length > 0); + bytes_->insert(bytes_->end(), bytes, bytes + length); + } + + // |ByteStreamWriter| + void WriteAlignment(uint8_t alignment) { + uint8_t mod = bytes_->size() % alignment; + if (mod) { + for (int i = 0; i < alignment - mod; ++i) { + WriteByte(0); + } + } + } + + private: + // The buffer to write to. + std::vector* bytes_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_BYTE_BUFFER_STREAMS_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/core_implementations.cc b/windows/flutter/ephemeral/cpp_client_wrapper/core_implementations.cc new file mode 100644 index 0000000..f682f1b --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/core_implementations.cc @@ -0,0 +1,284 @@ +// 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. + +// This file contains the implementations of any class in the wrapper that +// - is not fully inline, and +// - is necessary for all clients of the wrapper (either app or plugin). +// It exists instead of the usual structure of having some_class_name.cc files +// so that changes to the set of things that need non-header implementations +// are not breaking changes for the template. +// +// If https://github.com/flutter/flutter/issues/57146 is fixed, this can be +// removed in favor of the normal structure since templates will no longer +// manually include files. + +#include +#include +#include + +#include "binary_messenger_impl.h" +#include "include/flutter/engine_method_result.h" +#include "include/flutter/method_channel.h" +#include "include/flutter/standard_method_codec.h" +#include "texture_registrar_impl.h" + +namespace flutter { + +// ========== binary_messenger_impl.h ========== + +namespace { + +using FlutterDesktopMessengerScopedLock = + std::unique_ptr; + +// Passes |message| to |user_data|, which must be a BinaryMessageHandler, along +// with a BinaryReply that will send a response on |message|'s response handle. +// +// This serves as an adaptor between the function-pointer-based message callback +// interface provided by the C API and the std::function-based message handler +// interface of BinaryMessenger. +void ForwardToHandler(FlutterDesktopMessengerRef messenger, + const FlutterDesktopMessage* message, + void* user_data) { + auto* response_handle = message->response_handle; + auto messenger_ptr = std::shared_ptr( + FlutterDesktopMessengerAddRef(messenger), + &FlutterDesktopMessengerRelease); + BinaryReply reply_handler = [messenger_ptr, response_handle]( + const uint8_t* reply, + size_t reply_size) mutable { + // Note: This lambda can be called on any thread. + auto lock = FlutterDesktopMessengerScopedLock( + FlutterDesktopMessengerLock(messenger_ptr.get()), + &FlutterDesktopMessengerUnlock); + if (!FlutterDesktopMessengerIsAvailable(messenger_ptr.get())) { + // Drop reply if it comes in after the engine is destroyed. + return; + } + if (!response_handle) { + std::cerr << "Error: Response can be set only once. Ignoring " + "duplicate response." + << std::endl; + return; + } + FlutterDesktopMessengerSendResponse(messenger_ptr.get(), response_handle, + reply, reply_size); + // The engine frees the response handle once + // FlutterDesktopSendMessageResponse is called. + response_handle = nullptr; + }; + + const BinaryMessageHandler& message_handler = + *static_cast(user_data); + + message_handler(message->message, message->message_size, + std::move(reply_handler)); +} +} // namespace + +BinaryMessengerImpl::BinaryMessengerImpl( + FlutterDesktopMessengerRef core_messenger) + : messenger_(core_messenger) {} + +BinaryMessengerImpl::~BinaryMessengerImpl() = default; + +void BinaryMessengerImpl::Send(const std::string& channel, + const uint8_t* message, + size_t message_size, + BinaryReply reply) const { + if (reply == nullptr) { + FlutterDesktopMessengerSend(messenger_, channel.c_str(), message, + message_size); + return; + } + struct Captures { + BinaryReply reply; + }; + auto captures = new Captures(); + captures->reply = reply; + + auto message_reply = [](const uint8_t* data, size_t data_size, + void* user_data) { + auto captures = reinterpret_cast(user_data); + captures->reply(data, data_size); + delete captures; + }; + bool result = FlutterDesktopMessengerSendWithReply( + messenger_, channel.c_str(), message, message_size, message_reply, + captures); + if (!result) { + delete captures; + } +} + +void BinaryMessengerImpl::SetMessageHandler(const std::string& channel, + BinaryMessageHandler handler) { + if (!handler) { + handlers_.erase(channel); + FlutterDesktopMessengerSetCallback(messenger_, channel.c_str(), nullptr, + nullptr); + return; + } + // Save the handler, to keep it alive. + handlers_[channel] = std::move(handler); + BinaryMessageHandler* message_handler = &handlers_[channel]; + // Set an adaptor callback that will invoke the handler. + FlutterDesktopMessengerSetCallback(messenger_, channel.c_str(), + ForwardToHandler, message_handler); +} + +// ========== engine_method_result.h ========== + +namespace internal { + +ReplyManager::ReplyManager(BinaryReply reply_handler) + : reply_handler_(std::move(reply_handler)) { + assert(reply_handler_); +} + +ReplyManager::~ReplyManager() { + if (reply_handler_) { + // Warn, rather than send a not-implemented response, since the engine may + // no longer be valid at this point. + std::cerr + << "Warning: Failed to respond to a message. This is a memory leak." + << std::endl; + } +} + +void ReplyManager::SendResponseData(const std::vector* data) { + if (!reply_handler_) { + std::cerr + << "Error: Only one of Success, Error, or NotImplemented can be " + "called," + << " and it can be called exactly once. Ignoring duplicate result." + << std::endl; + return; + } + + const uint8_t* message = data && !data->empty() ? data->data() : nullptr; + size_t message_size = data ? data->size() : 0; + reply_handler_(message, message_size); + reply_handler_ = nullptr; +} + +} // namespace internal + +// ========== method_channel.h ========== + +namespace { + +constexpr char kControlChannelName[] = "dev.flutter/channel-buffers"; +constexpr char kResizeMethod[] = "resize"; +constexpr char kOverflowMethod[] = "overflow"; + +} // namespace + +namespace internal { + +void ResizeChannel(BinaryMessenger* messenger, std::string name, int new_size) { + auto control_channel = std::make_unique>( + messenger, kControlChannelName, &StandardMethodCodec::GetInstance()); + + // The deserialization logic handles only 32 bits values, see + // https://github.com/flutter/engine/blob/93e8901490e78c7ba7e319cce4470d9c6478c6dc/lib/ui/channel_buffers.dart#L495. + control_channel->InvokeMethod( + kResizeMethod, std::make_unique(EncodableList{ + EncodableValue(name), + EncodableValue(static_cast(new_size)), + })); +} + +void SetChannelWarnsOnOverflow(BinaryMessenger* messenger, + std::string name, + bool warns) { + auto control_channel = std::make_unique>( + messenger, kControlChannelName, &StandardMethodCodec::GetInstance()); + + control_channel->InvokeMethod(kOverflowMethod, + std::make_unique(EncodableList{ + EncodableValue(name), + EncodableValue(!warns), + })); +} + +} // namespace internal + +// ========== texture_registrar_impl.h ========== + +TextureRegistrarImpl::TextureRegistrarImpl( + FlutterDesktopTextureRegistrarRef texture_registrar_ref) + : texture_registrar_ref_(texture_registrar_ref) {} + +TextureRegistrarImpl::~TextureRegistrarImpl() = default; + +int64_t TextureRegistrarImpl::RegisterTexture(TextureVariant* texture) { + FlutterDesktopTextureInfo info = {}; + if (auto pixel_buffer_texture = std::get_if(texture)) { + info.type = kFlutterDesktopPixelBufferTexture; + info.pixel_buffer_config.user_data = pixel_buffer_texture; + info.pixel_buffer_config.callback = + [](size_t width, size_t height, + void* user_data) -> const FlutterDesktopPixelBuffer* { + auto texture = static_cast(user_data); + return texture->CopyPixelBuffer(width, height); + }; + } else if (auto gpu_surface_texture = + std::get_if(texture)) { + info.type = kFlutterDesktopGpuSurfaceTexture; + info.gpu_surface_config.struct_size = + sizeof(FlutterDesktopGpuSurfaceTextureConfig); + info.gpu_surface_config.type = gpu_surface_texture->surface_type(); + info.gpu_surface_config.user_data = gpu_surface_texture; + info.gpu_surface_config.callback = + [](size_t width, size_t height, + void* user_data) -> const FlutterDesktopGpuSurfaceDescriptor* { + auto texture = static_cast(user_data); + return texture->ObtainDescriptor(width, height); + }; + } else { + std::cerr << "Attempting to register unknown texture variant." << std::endl; + return -1; + } + + int64_t texture_id = FlutterDesktopTextureRegistrarRegisterExternalTexture( + texture_registrar_ref_, &info); + return texture_id; +} // namespace flutter + +bool TextureRegistrarImpl::MarkTextureFrameAvailable(int64_t texture_id) { + return FlutterDesktopTextureRegistrarMarkExternalTextureFrameAvailable( + texture_registrar_ref_, texture_id); +} + +void TextureRegistrarImpl::UnregisterTexture(int64_t texture_id, + std::function callback) { + if (callback == nullptr) { + FlutterDesktopTextureRegistrarUnregisterExternalTexture( + texture_registrar_ref_, texture_id, nullptr, nullptr); + return; + } + + struct Captures { + std::function callback; + }; + auto captures = new Captures(); + captures->callback = std::move(callback); + FlutterDesktopTextureRegistrarUnregisterExternalTexture( + texture_registrar_ref_, texture_id, + [](void* opaque) { + auto captures = reinterpret_cast(opaque); + captures->callback(); + delete captures; + }, + captures); +} + +bool TextureRegistrarImpl::UnregisterTexture(int64_t texture_id) { + UnregisterTexture(texture_id, nullptr); + return true; +} + +} // namespace flutter diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/engine_method_result.cc b/windows/flutter/ephemeral/cpp_client_wrapper/engine_method_result.cc new file mode 100644 index 0000000..65eaf5d --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/engine_method_result.cc @@ -0,0 +1,11 @@ +// 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. + +// This file is deprecated in favor of core_implementations.cc. This is a +// temporary forwarding implementation so that the switch to +// core_implementations.cc isn't an immediate breaking change, allowing for the +// template to be updated to include it and update the template version before +// removing this file. + +#include "core_implementations.cc" diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/flutter_engine.cc b/windows/flutter/ephemeral/cpp_client_wrapper/flutter_engine.cc new file mode 100644 index 0000000..2287d41 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/flutter_engine.cc @@ -0,0 +1,126 @@ +// 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 "include/flutter/flutter_engine.h" + +#include +#include + +#include "binary_messenger_impl.h" +#include "flutter_windows.h" + +namespace flutter { + +FlutterEngine::FlutterEngine(const DartProject& project) { + FlutterDesktopEngineProperties c_engine_properties = {}; + c_engine_properties.assets_path = project.assets_path().c_str(); + c_engine_properties.icu_data_path = project.icu_data_path().c_str(); + c_engine_properties.aot_library_path = project.aot_library_path().c_str(); + c_engine_properties.dart_entrypoint = project.dart_entrypoint().c_str(); + c_engine_properties.gpu_preference = + static_cast(project.gpu_preference()); + c_engine_properties.ui_thread_policy = + static_cast(project.ui_thread_policy()); + + const std::vector& entrypoint_args = + project.dart_entrypoint_arguments(); + std::vector entrypoint_argv; + std::transform( + entrypoint_args.begin(), entrypoint_args.end(), + std::back_inserter(entrypoint_argv), + [](const std::string& arg) -> const char* { return arg.c_str(); }); + + c_engine_properties.dart_entrypoint_argc = + static_cast(entrypoint_argv.size()); + c_engine_properties.dart_entrypoint_argv = + entrypoint_argv.empty() ? nullptr : entrypoint_argv.data(); + + engine_ = FlutterDesktopEngineCreate(&c_engine_properties); + + auto core_messenger = FlutterDesktopEngineGetMessenger(engine_); + messenger_ = std::make_unique(core_messenger); +} + +FlutterEngine::~FlutterEngine() { + ShutDown(); +} + +bool FlutterEngine::Run() { + return Run(nullptr); +} + +bool FlutterEngine::Run(const char* entry_point) { + if (!engine_) { + std::cerr << "Cannot run an engine that failed creation." << std::endl; + return false; + } + if (run_succeeded_) { + std::cerr << "Cannot run an engine more than once." << std::endl; + return false; + } + bool run_succeeded = FlutterDesktopEngineRun(engine_, entry_point); + if (!run_succeeded) { + std::cerr << "Failed to start engine." << std::endl; + } + run_succeeded_ = true; + return run_succeeded; +} + +void FlutterEngine::ShutDown() { + if (engine_ && owns_engine_) { + FlutterDesktopEngineDestroy(engine_); + } + engine_ = nullptr; +} + +std::chrono::nanoseconds FlutterEngine::ProcessMessages() { + return std::chrono::nanoseconds(FlutterDesktopEngineProcessMessages(engine_)); +} + +void FlutterEngine::ReloadSystemFonts() { + FlutterDesktopEngineReloadSystemFonts(engine_); +} + +FlutterDesktopPluginRegistrarRef FlutterEngine::GetRegistrarForPlugin( + const std::string& plugin_name) { + if (!engine_) { + std::cerr << "Cannot get plugin registrar on an engine that isn't running; " + "call Run first." + << std::endl; + return nullptr; + } + return FlutterDesktopEngineGetPluginRegistrar(engine_, plugin_name.c_str()); +} + +void FlutterEngine::SetNextFrameCallback(std::function callback) { + next_frame_callback_ = std::move(callback); + FlutterDesktopEngineSetNextFrameCallback( + engine_, + [](void* user_data) { + FlutterEngine* self = static_cast(user_data); + self->next_frame_callback_(); + self->next_frame_callback_ = nullptr; + }, + this); +} + +std::optional FlutterEngine::ProcessExternalWindowMessage( + HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + LRESULT result; + if (FlutterDesktopEngineProcessExternalWindowMessage( + engine_, hwnd, message, wparam, lparam, &result)) { + return result; + } + return std::nullopt; +} + +FlutterDesktopEngineRef FlutterEngine::RelinquishEngine() { + owns_engine_ = false; + return engine_; +} + +} // namespace flutter diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/flutter_view_controller.cc b/windows/flutter/ephemeral/cpp_client_wrapper/flutter_view_controller.cc new file mode 100644 index 0000000..98c65e1 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/flutter_view_controller.cc @@ -0,0 +1,53 @@ +// 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 "include/flutter/flutter_view_controller.h" + +#include +#include + +namespace flutter { + +FlutterViewController::FlutterViewController(int width, + int height, + const DartProject& project) { + engine_ = std::make_shared(project); + controller_ = FlutterDesktopViewControllerCreate(width, height, + engine_->RelinquishEngine()); + if (!controller_) { + std::cerr << "Failed to create view controller." << std::endl; + return; + } + view_ = std::make_unique( + FlutterDesktopViewControllerGetView(controller_)); +} + +FlutterViewController::~FlutterViewController() { + if (controller_) { + FlutterDesktopViewControllerDestroy(controller_); + } +} + +FlutterViewId FlutterViewController::view_id() const { + auto view_id = FlutterDesktopViewControllerGetViewId(controller_); + + return static_cast(view_id); +} + +void FlutterViewController::ForceRedraw() { + FlutterDesktopViewControllerForceRedraw(controller_); +} + +std::optional FlutterViewController::HandleTopLevelWindowProc( + HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + LRESULT result; + bool handled = FlutterDesktopViewControllerHandleTopLevelWindowProc( + controller_, hwnd, message, wparam, lparam, &result); + return handled ? result : std::optional(std::nullopt); +} + +} // namespace flutter diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/basic_message_channel.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/basic_message_channel.h new file mode 100644 index 0000000..27c6cc9 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/basic_message_channel.h @@ -0,0 +1,149 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BASIC_MESSAGE_CHANNEL_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BASIC_MESSAGE_CHANNEL_H_ + +#include +#include +#include + +#include "binary_messenger.h" +#include "message_codec.h" + +namespace flutter { + +namespace internal { +// Internal helper functions used by BasicMessageChannel and MethodChannel. + +// Adjusts the number of messages that will get buffered when sending messages +// to channels that aren't fully set up yet. For example, the engine isn't +// running yet or the channel's message handler isn't set up on the Dart side +// yet. +void ResizeChannel(BinaryMessenger* messenger, std::string name, int new_size); + +// Defines whether the channel should show warning messages when discarding +// messages due to overflow. +// +// When |warns| is false, the channel is expected to overflow and warning +// messages will not be shown. +void SetChannelWarnsOnOverflow(BinaryMessenger* messenger, + std::string name, + bool warns); + +} // namespace internal + +class EncodableValue; + +// A message reply callback. +// +// Used for submitting a reply back to a Flutter message sender. +template +using MessageReply = std::function; + +// A handler for receiving a message from the Flutter engine. +// +// Implementations must asynchronously call reply exactly once with the reply +// to the message. +template +using MessageHandler = + std::function& reply)>; + +// A channel for communicating with the Flutter engine by sending asynchronous +// messages. +template +class BasicMessageChannel { + public: + // Creates an instance that sends and receives method calls on the channel + // named |name|, encoded with |codec| and dispatched via |messenger|. + BasicMessageChannel(BinaryMessenger* messenger, + const std::string& name, + const MessageCodec* codec) + : messenger_(messenger), name_(name), codec_(codec) {} + + ~BasicMessageChannel() = default; + + // Prevent copying. + BasicMessageChannel(BasicMessageChannel const&) = delete; + BasicMessageChannel& operator=(BasicMessageChannel const&) = delete; + + // Sends a message to the Flutter engine on this channel. + void Send(const T& message) { + std::unique_ptr> raw_message = + codec_->EncodeMessage(message); + messenger_->Send(name_, raw_message->data(), raw_message->size()); + } + + // Sends a message to the Flutter engine on this channel expecting a reply. + void Send(const T& message, BinaryReply reply) { + std::unique_ptr> raw_message = + codec_->EncodeMessage(message); + messenger_->Send(name_, raw_message->data(), raw_message->size(), + std::move(reply)); + } + + // Registers a handler that should be called any time a message is + // received on this channel. A null handler will remove any previous handler. + // + // Note that the BasicMessageChannel does not own the handler, and will not + // unregister it on destruction, so the caller is responsible for + // unregistering explicitly if it should no longer be called. + void SetMessageHandler(const MessageHandler& handler) const { + if (!handler) { + messenger_->SetMessageHandler(name_, nullptr); + return; + } + const auto* codec = codec_; + std::string channel_name = name_; + BinaryMessageHandler binary_handler = [handler, codec, channel_name]( + const uint8_t* binary_message, + const size_t binary_message_size, + const BinaryReply& binary_reply) { + // Use this channel's codec to decode the message and build a reply + // handler. + std::unique_ptr message = + codec->DecodeMessage(binary_message, binary_message_size); + if (!message) { + std::cerr << "Unable to decode message on channel " << channel_name + << std::endl; + binary_reply(nullptr, 0); + return; + } + + MessageReply unencoded_reply = [binary_reply, + codec](const T& unencoded_response) { + auto binary_response = codec->EncodeMessage(unencoded_response); + binary_reply(binary_response->data(), binary_response->size()); + }; + handler(*message, std::move(unencoded_reply)); + }; + messenger_->SetMessageHandler(name_, std::move(binary_handler)); + } + + // Adjusts the number of messages that will get buffered when sending messages + // to channels that aren't fully set up yet. For example, the engine isn't + // running yet or the channel's message handler isn't set up on the Dart side + // yet. + void Resize(int new_size) { + internal::ResizeChannel(messenger_, name_, new_size); + } + + // Defines whether the channel should show warning messages when discarding + // messages due to overflow. + // + // When |warns| is false, the channel is expected to overflow and warning + // messages will not be shown. + void SetWarnsOnOverflow(bool warns) { + internal::SetChannelWarnsOnOverflow(messenger_, name_, warns); + } + + private: + BinaryMessenger* messenger_; + std::string name_; + const MessageCodec* codec_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BASIC_MESSAGE_CHANNEL_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/binary_messenger.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/binary_messenger.h new file mode 100644 index 0000000..d552b49 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/binary_messenger.h @@ -0,0 +1,52 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BINARY_MESSENGER_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BINARY_MESSENGER_H_ + +#include +#include + +namespace flutter { + +// A binary message reply callback. +// +// Used for submitting a binary reply back to a Flutter message sender. +typedef std::function + BinaryReply; + +// A message handler callback. +// +// Used for receiving messages from Flutter and providing an asynchronous reply. +typedef std::function< + void(const uint8_t* message, size_t message_size, BinaryReply reply)> + BinaryMessageHandler; + +// A protocol for a class that handles communication of binary data on named +// channels to and from the Flutter engine. +class BinaryMessenger { + public: + virtual ~BinaryMessenger() = default; + + // Sends a binary message to the Flutter engine on the specified channel. + // + // If |reply| is provided, it will be called back with the response from the + // engine. + virtual void Send(const std::string& channel, + const uint8_t* message, + size_t message_size, + BinaryReply reply = nullptr) const = 0; + + // Registers a message handler for incoming binary messages from the Flutter + // side on the specified channel. + // + // Replaces any existing handler. Provide a null handler to unregister the + // existing handler. + virtual void SetMessageHandler(const std::string& channel, + BinaryMessageHandler handler) = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BINARY_MESSENGER_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/byte_streams.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/byte_streams.h new file mode 100644 index 0000000..3360bab --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/byte_streams.h @@ -0,0 +1,85 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BYTE_STREAMS_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BYTE_STREAMS_H_ + +// Interfaces for interacting with a stream of bytes, for use in codecs. + +namespace flutter { + +// An interface for a class that reads from a byte stream. +class ByteStreamReader { + public: + explicit ByteStreamReader() = default; + virtual ~ByteStreamReader() = default; + + // Reads and returns the next byte from the stream. + virtual uint8_t ReadByte() = 0; + + // Reads the next |length| bytes from the stream into |buffer|. The caller + // is responsible for ensuring that |buffer| is large enough. + virtual void ReadBytes(uint8_t* buffer, size_t length) = 0; + + // Advances the read cursor to the next multiple of |alignment| relative to + // the start of the stream, unless it is already aligned. + virtual void ReadAlignment(uint8_t alignment) = 0; + + // Reads and returns the next 32-bit integer from the stream. + int32_t ReadInt32() { + int32_t value = 0; + ReadBytes(reinterpret_cast(&value), 4); + return value; + } + + // Reads and returns the next 64-bit integer from the stream. + int64_t ReadInt64() { + int64_t value = 0; + ReadBytes(reinterpret_cast(&value), 8); + return value; + } + + // Reads and returns the next 64-bit floating point number from the stream. + double ReadDouble() { + double value = 0; + ReadBytes(reinterpret_cast(&value), 8); + return value; + } +}; + +// An interface for a class that writes to a byte stream. +class ByteStreamWriter { + public: + explicit ByteStreamWriter() = default; + virtual ~ByteStreamWriter() = default; + + // Writes |byte| to the stream. + virtual void WriteByte(uint8_t byte) = 0; + + // Writes the next |length| bytes from |bytes| to the stream + virtual void WriteBytes(const uint8_t* bytes, size_t length) = 0; + + // Writes 0s until the next multiple of |alignment| relative to the start + // of the stream, unless the write positition is already aligned. + virtual void WriteAlignment(uint8_t alignment) = 0; + + // Writes the given 32-bit int to the stream. + void WriteInt32(int32_t value) { + WriteBytes(reinterpret_cast(&value), 4); + } + + // Writes the given 64-bit int to the stream. + void WriteInt64(int64_t value) { + WriteBytes(reinterpret_cast(&value), 8); + } + + // Writes the given 36-bit double to the stream. + void WriteDouble(double value) { + WriteBytes(reinterpret_cast(&value), 8); + } +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_BYTE_STREAMS_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/dart_project.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/dart_project.h new file mode 100644 index 0000000..8d18146 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/dart_project.h @@ -0,0 +1,145 @@ +// 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 +#include + +namespace flutter { + +// Configures how the Flutter engine selects a GPU. +enum class GpuPreference { + // No preference. + NoPreference, + // Prefer energy efficiency over performance, such as an integrated GPU. + // This falls back to a high performance GPU if no low power GPU is + // available. + LowPowerPreference, +}; + +// Configures the thread policy for running the UI isolate. +enum class UIThreadPolicy { + // Default value. Currently will run the UI isolate on separate thread, + // later will be changed to running the UI isolate on platform thread. + Default, + // Run the UI isolate on platform thread. + RunOnPlatformThread, + // Run the UI isolate on a separate thread. + RunOnSeparateThread, +}; + +// A set of Flutter and Dart assets used to initialize a Flutter engine. +class DartProject { + public: + // Creates a DartProject from a series of absolute paths. + // The three paths are: + // - assets_path: Path to the assets directory as built by the Flutter tool. + // - icu_data_path: Path to the icudtl.dat file. + // - aot_library_path: Path to the AOT snapshot file. + // + // The paths may either be absolute or relative to the directory containing + // the running executable. + explicit DartProject(const std::wstring& assets_path, + const std::wstring& icu_data_path, + const std::wstring& aot_library_path) { + assets_path_ = assets_path; + icu_data_path_ = icu_data_path; + aot_library_path_ = aot_library_path; + } + + // 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) + // - app.so, for an AOT build (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"; + aot_library_path_ = path + L"\\app.so"; + } + + ~DartProject() = default; + + // Sets the Dart entrypoint to the specified value. + // + // If not set, the default entrypoint (main) is used. Custom Dart entrypoints + // must be decorated with `@pragma('vm:entry-point')`. + void set_dart_entrypoint(const std::string& entrypoint) { + if (entrypoint.empty()) { + return; + } + dart_entrypoint_ = entrypoint; + } + + // Returns the Dart entrypoint. + const std::string& dart_entrypoint() const { return dart_entrypoint_; } + + // Sets the command line arguments that should be passed to the Dart + // entrypoint. + void set_dart_entrypoint_arguments(std::vector arguments) { + dart_entrypoint_arguments_ = std::move(arguments); + } + + // Returns any command line arguments that should be passed to the Dart + // entrypoint. + const std::vector& dart_entrypoint_arguments() const { + return dart_entrypoint_arguments_; + } + + // Sets the GPU usage preference for flutter engine. + void set_gpu_preference(GpuPreference gpu_preference) { + gpu_preference_ = gpu_preference; + } + + // Returns the project's GPU preference. + // Defaults to NoPreference. + GpuPreference gpu_preference() const { return gpu_preference_; } + + // Sets the thread policy for UI isolate. + void set_ui_thread_policy(UIThreadPolicy policy) { + ui_thread_policy_ = policy; + } + + // Returns the policy for UI isolate. + // Defaults to UIThreadPolicy::Default. + UIThreadPolicy ui_thread_policy() const { return ui_thread_policy_; } + + 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 FlutterEngine; + 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::wstring& aot_library_path() const { return aot_library_path_; } + + // The path to the assets directory. + std::wstring assets_path_; + // The path to the ICU data. + std::wstring icu_data_path_; + // The path to the AOT library. This will always return a path, but non-AOT + // builds will not be expected to actually have a library at that path. + std::wstring aot_library_path_; + // The Dart entrypoint to launch. + std::string dart_entrypoint_; + // The list of arguments to pass through to the Dart entrypoint. + std::vector dart_entrypoint_arguments_; + // The preference for GPU to be used by flutter engine. + GpuPreference gpu_preference_ = GpuPreference::NoPreference; + // Thread policy for UI isolate. + UIThreadPolicy ui_thread_policy_ = UIThreadPolicy::Default; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_DART_PROJECT_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/encodable_value.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/encodable_value.h new file mode 100644 index 0000000..e6eacad --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/encodable_value.h @@ -0,0 +1,274 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +// Unless overridden, attempt to detect the RTTI state from the compiler. +#ifndef FLUTTER_ENABLE_RTTI +#if defined(_MSC_VER) +#ifdef _CPPRTTI +#define FLUTTER_ENABLE_RTTI 1 +#endif +#elif defined(__clang__) +#if __has_feature(cxx_rtti) +#define FLUTTER_ENABLE_RTTI 1 +#endif +#elif defined(__GNUC__) +#ifdef __GXX_RTTI +#define FLUTTER_ENABLE_RTTI 1 +#endif +#endif +#endif // #ifndef FLUTTER_ENABLE_RTTI + +namespace flutter { + +static_assert(sizeof(double) == 8, "EncodableValue requires a 64-bit double"); + +// A container for arbitrary types in EncodableValue. +// +// This is used in conjunction with StandardCodecExtension to allow using other +// types with a StandardMethodCodec/StandardMessageCodec. It is implicitly +// convertible to EncodableValue, so constructing an EncodableValue from a +// custom type can generally be written as: +// CustomEncodableValue(MyType(...)) +// rather than: +// EncodableValue(CustomEncodableValue(MyType(...))) +// +// For extracting received custom types, it is implicitly convertible to +// std::any. For example: +// const MyType& my_type_value = +// std::any_cast(std::get(value)); +// +// If RTTI is enabled, different extension types can be checked with type(): +// if (custom_value->type() == typeid(SomeData)) { ... } +// Clients that wish to disable RTTI would need to decide on another approach +// for distinguishing types (e.g., in StandardCodecExtension::WriteValueOfType) +// if multiple custom types are needed. For instance, wrapping all of the +// extension types in an EncodableValue-style variant, and only ever storing +// that variant in CustomEncodableValue. +class CustomEncodableValue { + public: + explicit CustomEncodableValue(const std::any& value) : value_(value) {} + ~CustomEncodableValue() = default; + + // Allow implicit conversion to std::any to allow direct use of any_cast. + // NOLINTNEXTLINE(google-explicit-constructor) + operator std::any&() { return value_; } + // NOLINTNEXTLINE(google-explicit-constructor) + operator const std::any&() const { return value_; } + +#if defined(FLUTTER_ENABLE_RTTI) && FLUTTER_ENABLE_RTTI + // Passthrough to std::any's type(). + const std::type_info& type() const noexcept { return value_.type(); } +#endif + + // This operator exists only to provide a stable ordering for use as a + // std::map key, to satisfy the compiler requirements for EncodableValue. + // It does not attempt to provide useful ordering semantics, and using a + // custom value as a map key is not recommended. + bool operator<(const CustomEncodableValue& other) const { + return this < &other; + } + bool operator==(const CustomEncodableValue& other) const { + return this == &other; + } + + private: + std::any value_; +}; + +class EncodableValue; + +// Convenience type aliases. +using EncodableList = std::vector; +using EncodableMap = std::map; + +namespace internal { +// The base class for EncodableValue. Do not use this directly; it exists only +// for EncodableValue to inherit from. +// +// Do not change the order or indexes of the items here; see the comment on +// EncodableValue +using EncodableValueVariant = std::variant, + std::vector, + std::vector, + std::vector, + EncodableList, + EncodableMap, + CustomEncodableValue, + std::vector>; +} // namespace internal + +// An object that can contain any value or collection type supported by +// Flutter's standard method codec. +// +// For details, see: +// https://api.flutter.dev/flutter/services/StandardMessageCodec-class.html +// +// As an example, the following Dart structure: +// { +// 'flag': true, +// 'name': 'Thing', +// 'values': [1, 2.0, 4], +// } +// would correspond to: +// EncodableValue(EncodableMap{ +// {EncodableValue("flag"), EncodableValue(true)}, +// {EncodableValue("name"), EncodableValue("Thing")}, +// {EncodableValue("values"), EncodableValue(EncodableList{ +// EncodableValue(1), +// EncodableValue(2.0), +// EncodableValue(4), +// })}, +// }) +// +// The primary API surface for this object is std::variant. For instance, +// getting a string value from an EncodableValue, with type checking: +// if (std::holds_alternative(value)) { +// std::string some_string = std::get(value); +// } +// +// The order/indexes of the variant types is part of the API surface, and is +// guaranteed not to change. +// +// The variant types are mapped with Dart types in following ways: +// std::monostate -> null +// bool -> bool +// int32_t -> int +// int64_t -> int +// double -> double +// std::string -> String +// std::vector -> Uint8List +// std::vector -> Int32List +// std::vector -> Int64List +// std::vector -> Float32List +// std::vector -> Float64List +// EncodableList -> List +// EncodableMap -> Map +class EncodableValue : public internal::EncodableValueVariant { + public: + // Rely on std::variant for most of the constructors/operators. + using super = internal::EncodableValueVariant; + using super::super; + using super::operator=; + + explicit EncodableValue() = default; + + // Avoid the C++17 pitfall of conversion from char* to bool. Should not be + // needed for C++20. + explicit EncodableValue(const char* string) : super(std::string(string)) {} + EncodableValue& operator=(const char* other) { + *this = std::string(other); + return *this; + } + + // Allow implicit conversion from CustomEncodableValue; the only reason to + // make a CustomEncodableValue (which can only be constructed explicitly) is + // to use it with EncodableValue, so the risk of unintended conversions is + // minimal, and it avoids the need for the verbose: + // EncodableValue(CustomEncodableValue(...)). + // NOLINTNEXTLINE(google-explicit-constructor) + EncodableValue(const CustomEncodableValue& v) : super(v) {} + + // Override the conversion constructors from std::variant to make them + // explicit, to avoid implicit conversion. + // + // While implicit conversion can be convenient in some cases, it can have very + // surprising effects. E.g., calling a function that takes an EncodableValue + // but accidentally passing an EncodableValue* would, instead of failing to + // compile, go through a pointer->bool->EncodableValue(bool) chain and + // silently call the function with a temp-constructed EncodableValue(true). + template + constexpr explicit EncodableValue(T&& t) noexcept : super(t) {} + + // Returns true if the value is null. Convenience wrapper since unlike the + // other types, std::monostate uses aren't self-documenting. + bool IsNull() const { return std::holds_alternative(*this); } + + // Convenience method to simplify handling objects received from Flutter + // where the values may be larger than 32-bit, since they have the same type + // on the Dart side, but will be either 32-bit or 64-bit here depending on + // the value. + // + // Calling this method if the value doesn't contain either an int32_t or an + // int64_t will throw an exception. + int64_t LongValue() const { + if (std::holds_alternative(*this)) { + return std::get(*this); + } + return std::get(*this); + } + +// The C++ Standard Library implementations can get into issues with recursive +// constraint satisfaction when (among other things) objects of this type (which +// is an `std::variant` subclass) are put into containers like `std::vector`. +// +// A definition of `operator<` is provided to break that recursion. However, in +// C++20 with the latest compilers (Clang compilers newer than 20 and the latest +// GCC variants, see https://gcc.godbolt.org/z/KM6n6qane) requiring that that +// the `std::three_way_comparable` constraint be satisfied requires the +// provision of `operator<=>` to do the same thing. +// +// The code below makes this translation unit be safe to include from both C++17 +// and C++20 translation units while also using the newest compilers. +// +// The correctness of the compiler's gripes with this code and the subsequent +// need for these workarounds is not fully understood or explored. If you run +// into issues with this code again, the following breadcrumbs may prove +// useful. If you cannot access some or all of these links, the compiler +// explorer link above should serve a reduced test case to base an investigation +// off of. +// +// * b/423885648#comment8 +// * b/423885648#comment19 +// * cl/542631351 +// * cl/542541552 +// * https://github.com/flutter/engine/pull/43091 +// +#if __cplusplus >= 202002L + friend std::partial_ordering operator<=>(const EncodableValue& lhs, + const EncodableValue& rhs) { + auto& lv = static_cast(lhs); + auto& rv = static_cast(rhs); + + if (lv < rv) { + return std::partial_ordering::less; + } + + if (rv < lv) { + return std::partial_ordering::greater; + } + + if (lv == rv) { + return std::partial_ordering::equivalent; + } + + return std::partial_ordering::unordered; + } +#else // __cplusplus >= 202002L + friend bool operator<(const EncodableValue& lhs, const EncodableValue& rhs) { + return static_cast(lhs) < static_cast(rhs); + } +#endif // __cplusplus >= 202002L +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENCODABLE_VALUE_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/engine_method_result.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/engine_method_result.h new file mode 100644 index 0000000..3cc8b6a --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/engine_method_result.h @@ -0,0 +1,86 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENGINE_METHOD_RESULT_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENGINE_METHOD_RESULT_H_ + +#include +#include +#include + +#include "binary_messenger.h" +#include "method_codec.h" +#include "method_result.h" + +namespace flutter { + +namespace internal { +// Manages the one-time sending of response data. This is an internal helper +// class for EngineMethodResult, separated out since the implementation doesn't +// vary based on the template type. +class ReplyManager { + public: + explicit ReplyManager(BinaryReply reply_handler_); + ~ReplyManager(); + + // Prevent copying. + ReplyManager(ReplyManager const&) = delete; + ReplyManager& operator=(ReplyManager const&) = delete; + + // Sends the given response data (which must either be nullptr, which + // indicates an unhandled method, or a response serialized with |codec_|) to + // the engine. + void SendResponseData(const std::vector* data); + + private: + BinaryReply reply_handler_; +}; +} // namespace internal + +// Implemention of MethodResult that sends a response to the Flutter engine +// exactly once, encoded using a given codec. +template +class EngineMethodResult : public MethodResult { + public: + // Creates a result object that will send results to |reply_handler|, encoded + // using |codec|. The |codec| pointer must remain valid for as long as this + // object exists. + EngineMethodResult(BinaryReply reply_handler, const MethodCodec* codec) + : reply_manager_( + std::make_unique(std::move(reply_handler))), + codec_(codec) {} + + ~EngineMethodResult() = default; + + protected: + // |flutter::MethodResult| + void SuccessInternal(const T* result) override { + std::unique_ptr> data = + codec_->EncodeSuccessEnvelope(result); + reply_manager_->SendResponseData(data.get()); + } + + // |flutter::MethodResult| + void ErrorInternal(const std::string& error_code, + const std::string& error_message, + const T* error_details) override { + std::unique_ptr> data = + codec_->EncodeErrorEnvelope(error_code, error_message, error_details); + reply_manager_->SendResponseData(data.get()); + } + + // |flutter::MethodResult| + void NotImplementedInternal() override { + reply_manager_->SendResponseData(nullptr); + } + + private: + std::unique_ptr reply_manager_; + + const MethodCodec* codec_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_ENGINE_METHOD_RESULT_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_channel.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_channel.h new file mode 100644 index 0000000..7d0d259 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_channel.h @@ -0,0 +1,181 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_CHANNEL_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_CHANNEL_H_ + +#include +#include +#include + +#include "binary_messenger.h" +#include "engine_method_result.h" +#include "event_sink.h" +#include "event_stream_handler.h" + +namespace flutter { + +class EncodableValue; + +// A named channel for communicating with the Flutter application using +// asynchronous event streams. Incoming requests for event stream setup are +// decoded from binary on receipt, and C++ responses and events are encoded into +// binary before being transmitted back to Flutter. The MethodCodec used must be +// compatible with the one used by the Flutter application. This can be achieved +// by creating an EventChannel +// ("https://api.flutter.dev/flutter/services/EventChannel-class.html") +// counterpart of this channel on the Dart side. +// The C++ type of stream configuration arguments, events, and error details are +// templated, but only values supported by the specified MethodCodec can be +// used. +template +class EventChannel { + public: + // Creates an instance that sends and receives event handler on the channel + // named |name|, encoded with |codec| and dispatched via |messenger|. + EventChannel(BinaryMessenger* messenger, + const std::string& name, + const MethodCodec* codec) + : messenger_(messenger), name_(name), codec_(codec) {} + ~EventChannel() = default; + + // Prevent copying. + EventChannel(EventChannel const&) = delete; + EventChannel& operator=(EventChannel const&) = delete; + + // Registers a stream handler on this channel. + // If no handler has been registered, any incoming stream setup requests will + // be handled silently by providing an empty stream. + // + // Note that the EventChannel does not own the handler and will not + // unregister it on destruction. The caller is responsible for unregistering + // the handler if it should no longer be called. + void SetStreamHandler(std::unique_ptr> handler) { + if (!handler) { + messenger_->SetMessageHandler(name_, nullptr); + return; + } + + // std::function requires a copyable lambda, so convert to a shared pointer. + // This is safe since only one copy of the shared_pointer will ever be + // accessed. + std::shared_ptr> shared_handler(handler.release()); + const MethodCodec* codec = codec_; + const std::string channel_name = name_; + const BinaryMessenger* messenger = messenger_; + BinaryMessageHandler binary_handler = + [shared_handler, codec, channel_name, messenger, + // Mutable state to track the handler's listening status. + is_listening = false](const uint8_t* message, + const size_t message_size, + const BinaryReply& reply) mutable { + constexpr char kOnListenMethod[] = "listen"; + constexpr char kOnCancelMethod[] = "cancel"; + + std::unique_ptr> method_call = + codec->DecodeMethodCall(message, message_size); + if (!method_call) { + std::cerr + << "Unable to construct method call from message on channel: " + << channel_name << std::endl; + reply(nullptr, 0); + return; + } + + const std::string& method = method_call->method_name(); + if (method.compare(kOnListenMethod) == 0) { + if (is_listening) { + std::unique_ptr> error = + shared_handler->OnCancel(nullptr); + if (error) { + std::cerr << "Failed to cancel existing stream: " + << (error->error_code) << ", " + << (error->error_message) << ", " + << (error->error_details); + } + } + is_listening = true; + + std::unique_ptr> result; + auto sink = std::make_unique( + messenger, channel_name, codec); + std::unique_ptr> error = + shared_handler->OnListen(method_call->arguments(), + std::move(sink)); + if (error) { + result = codec->EncodeErrorEnvelope(error->error_code, + error->error_message, + error->error_details.get()); + } else { + result = codec->EncodeSuccessEnvelope(); + } + reply(result->data(), result->size()); + } else if (method.compare(kOnCancelMethod) == 0) { + std::unique_ptr> result; + if (is_listening) { + std::unique_ptr> error = + shared_handler->OnCancel(method_call->arguments()); + if (error) { + result = codec->EncodeErrorEnvelope(error->error_code, + error->error_message, + error->error_details.get()); + } else { + result = codec->EncodeSuccessEnvelope(); + } + is_listening = false; + } else { + result = codec->EncodeErrorEnvelope( + "error", "No active stream to cancel", nullptr); + } + reply(result->data(), result->size()); + } else { + reply(nullptr, 0); + } + }; + messenger_->SetMessageHandler(name_, std::move(binary_handler)); + } + + private: + class EventSinkImplementation : public EventSink { + public: + EventSinkImplementation(const BinaryMessenger* messenger, + const std::string& name, + const MethodCodec* codec) + : messenger_(messenger), name_(name), codec_(codec) {} + ~EventSinkImplementation() = default; + + // Prevent copying. + EventSinkImplementation(EventSinkImplementation const&) = delete; + EventSinkImplementation& operator=(EventSinkImplementation const&) = delete; + + private: + const BinaryMessenger* messenger_; + const std::string name_; + const MethodCodec* codec_; + + protected: + void SuccessInternal(const T* event = nullptr) override { + auto result = codec_->EncodeSuccessEnvelope(event); + messenger_->Send(name_, result->data(), result->size()); + } + + void ErrorInternal(const std::string& error_code, + const std::string& error_message, + const T* error_details) override { + auto result = + codec_->EncodeErrorEnvelope(error_code, error_message, error_details); + messenger_->Send(name_, result->data(), result->size()); + } + + void EndOfStreamInternal() override { messenger_->Send(name_, nullptr, 0); } + }; + + BinaryMessenger* messenger_; + const std::string name_; + const MethodCodec* codec_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_CHANNEL_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_sink.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_sink.h new file mode 100644 index 0000000..789be1e --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_sink.h @@ -0,0 +1,62 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_SINK_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_SINK_H_ + +namespace flutter { + +class EncodableValue; + +// Event callback. Events to be sent to Flutter application +// act as clients of this interface for sending events. +template +class EventSink { + public: + EventSink() = default; + virtual ~EventSink() = default; + + // Prevent copying. + EventSink(EventSink const&) = delete; + EventSink& operator=(EventSink const&) = delete; + + // Consumes a successful event + void Success(const T& event) { SuccessInternal(&event); } + + // Consumes a successful event. + void Success() { SuccessInternal(nullptr); } + + // Consumes an error event. + void Error(const std::string& error_code, + const std::string& error_message, + const T& error_details) { + ErrorInternal(error_code, error_message, &error_details); + } + + // Consumes an error event. + void Error(const std::string& error_code, + const std::string& error_message = "") { + ErrorInternal(error_code, error_message, nullptr); + } + + // Consumes end of stream. Ensuing calls to Success() or + // Error(), if any, are ignored. + void EndOfStream() { EndOfStreamInternal(); } + + protected: + // Implementation of the public interface, to be provided by subclasses. + virtual void SuccessInternal(const T* event = nullptr) = 0; + + // Implementation of the public interface, to be provided by subclasses. + virtual void ErrorInternal(const std::string& error_code, + const std::string& error_message, + const T* error_details) = 0; + + // Implementation of the public interface, to be provided by subclasses. + virtual void EndOfStreamInternal() = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_SINK_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_stream_handler.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_stream_handler.h new file mode 100644 index 0000000..166733d --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_stream_handler.h @@ -0,0 +1,77 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_H_ + +#include +#include + +#include "event_sink.h" + +namespace flutter { + +class EncodableValue; + +template +struct StreamHandlerError { + const std::string error_code; + const std::string error_message; + const std::unique_ptr error_details; + + StreamHandlerError(const std::string& error_code, + const std::string& error_message, + std::unique_ptr&& error_details) + : error_code(error_code), + error_message(error_message), + error_details(std::move(error_details)) {} +}; + +// Handler for stream setup and teardown requests. +// Implementations must be prepared to accept sequences of alternating calls to +// OnListen() and OnCancel(). Implementations should ideally consume no +// resources when the last such call is not OnListen(). In typical situations, +// this means that the implementation should register itself with +// platform-specific event sources OnListen() and deregister again OnCancel(). +template +class StreamHandler { + public: + StreamHandler() = default; + virtual ~StreamHandler() = default; + + // Prevent copying. + StreamHandler(StreamHandler const&) = delete; + StreamHandler& operator=(StreamHandler const&) = delete; + + // Handles a request to set up an event stream. Returns nullptr on success, + // or an error on failure. + // |arguments| is stream configuration arguments and + // |events| is an EventSink for emitting events to the Flutter receiver. + std::unique_ptr> OnListen( + const T* arguments, + std::unique_ptr>&& events) { + return OnListenInternal(arguments, std::move(events)); + } + + // Handles a request to tear down the most recently created event stream. + // Returns nullptr on success, or an error on failure. + // |arguments| is stream configuration arguments. + std::unique_ptr> OnCancel(const T* arguments) { + return OnCancelInternal(arguments); + } + + protected: + // Implementation of the public interface, to be provided by subclasses. + virtual std::unique_ptr> OnListenInternal( + const T* arguments, + std::unique_ptr>&& events) = 0; + + // Implementation of the public interface, to be provided by subclasses. + virtual std::unique_ptr> OnCancelInternal( + const T* arguments) = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_stream_handler_functions.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_stream_handler_functions.h new file mode 100644 index 0000000..74d64fc --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/event_stream_handler_functions.h @@ -0,0 +1,78 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_FUNCTIONS_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_FUNCTIONS_H_ + +#include + +#include "event_sink.h" +#include "event_stream_handler.h" + +namespace flutter { + +class EncodableValue; + +// Handler types for each of the StreamHandler setup and teardown +// requests. +template +using StreamHandlerListen = + std::function>( + const T* arguments, + std::unique_ptr>&& events)>; + +template +using StreamHandlerCancel = + std::function>(const T* arguments)>; + +// An implementation of StreamHandler that pass calls through to +// provided function objects. +template +class StreamHandlerFunctions : public StreamHandler { + public: + // Creates a handler object that calls the provided functions + // for the corresponding StreamHandler outcomes. + StreamHandlerFunctions(StreamHandlerListen on_listen, + StreamHandlerCancel on_cancel) + : on_listen_(std::move(on_listen)), on_cancel_(std::move(on_cancel)) {} + + virtual ~StreamHandlerFunctions() = default; + + // Prevent copying. + StreamHandlerFunctions(StreamHandlerFunctions const&) = delete; + StreamHandlerFunctions& operator=(StreamHandlerFunctions const&) = delete; + + protected: + // |flutter::StreamHandler| + std::unique_ptr> OnListenInternal( + const T* arguments, + std::unique_ptr>&& events) override { + if (on_listen_) { + return on_listen_(arguments, std::move(events)); + } + + auto error = std::make_unique>( + "error", "No OnListen handler set", nullptr); + return std::move(error); + } + + // |flutter::StreamHandler| + std::unique_ptr> OnCancelInternal( + const T* arguments) override { + if (on_cancel_) { + return on_cancel_(arguments); + } + + auto error = std::make_unique>( + "error", "No OnCancel handler set", nullptr); + return std::move(error); + } + + StreamHandlerListen on_listen_; + StreamHandlerCancel on_cancel_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_EVENT_STREAM_HANDLER_FUNCTIONS_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/flutter_engine.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/flutter_engine.h new file mode 100644 index 0000000..0369db3 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/flutter_engine.h @@ -0,0 +1,128 @@ +// 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_FLUTTER_ENGINE_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_ENGINE_H_ + +#include + +#include +#include +#include +#include + +#include "binary_messenger.h" +#include "dart_project.h" +#include "plugin_registrar.h" +#include "plugin_registry.h" + +namespace flutter { + +// An instance of a Flutter engine. +// +// In the future, this will be the API surface used for all interactions with +// the engine, rather than having them duplicated on FlutterViewController. +// For now it is only used in the rare case where you need a headless Flutter +// engine. +class FlutterEngine : public PluginRegistry { + public: + // Creates a new engine for running the given project. + explicit FlutterEngine(const DartProject& project); + + virtual ~FlutterEngine(); + + // Prevent copying. + FlutterEngine(FlutterEngine const&) = delete; + FlutterEngine& operator=(FlutterEngine const&) = delete; + + // Starts running the engine at the entrypoint function specified in the + // DartProject used to configure the engine, or main() by default. + bool Run(); + + // Starts running the engine, with an optional entry point. + // + // If provided, entry_point must be the name of a top-level function from the + // same Dart library that contains the app's main() function, and must be + // decorated with `@pragma(vm:entry-point)` to ensure the method is not + // tree-shaken by the Dart compiler. If not provided, defaults to main(). + bool Run(const char* entry_point); + + // Terminates the running engine. + void ShutDown(); + + // Processes any pending events in the Flutter engine, and returns the + // nanosecond delay until the next scheduled event (or max, if none). + // + // This should be called on every run of the application-level runloop, and + // a wait for native events in the runloop should never be longer than the + // last return value from this function. + std::chrono::nanoseconds ProcessMessages(); + + // Tells the engine that the system font list has changed. Should be called + // by clients when OS-level font changes happen (e.g., WM_FONTCHANGE in a + // Win32 application). + void ReloadSystemFonts(); + + // Tells the engine that the platform brightness value has changed. Should be + // called by clients when OS-level theme changes happen (e.g., + // WM_DWMCOLORIZATIONCOLORCHANGED in a Win32 application). + void ReloadPlatformBrightness(); + + // flutter::PluginRegistry: + FlutterDesktopPluginRegistrarRef GetRegistrarForPlugin( + const std::string& plugin_name) override; + + // Returns the messenger to use for creating channels to communicate with the + // Flutter engine. + // + // This pointer will remain valid for the lifetime of this instance. + BinaryMessenger* messenger() { return messenger_.get(); } + + // Schedule a callback to be called after the next frame is drawn. + // + // This must be called from the platform thread. The callback is executed only + // once on the platform thread. + void SetNextFrameCallback(std::function callback); + + // Called to pass an external window message to the engine for lifecycle + // state updates. Non-Flutter windows must call this method in their WndProc + // in order to be included in the logic for application lifecycle state + // updates. Returns a result if the message should be consumed. + std::optional ProcessExternalWindowMessage(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam); + + private: + // For access to the engine handle. + friend class FlutterViewController; + + // Gives up ownership of |engine_|, but keeps a weak reference to it. + // + // This is intended to be used by FlutterViewController, since the underlying + // C API for view controllers takes over engine ownership. + FlutterDesktopEngineRef RelinquishEngine(); + + // Handle for interacting with the C API's engine reference. + FlutterDesktopEngineRef engine_ = nullptr; + + // Messenger for communicating with the engine. + std::unique_ptr messenger_; + + // Whether or not this wrapper owns |engine_|. + bool owns_engine_ = true; + + // Whether |Run| has been called successfully. + // + // This is used to improve error messages. This can be false while the engine + // is running if the engine was started by creating a view. + bool run_succeeded_ = false; + + // The callback to execute once the next frame is drawn. + std::function next_frame_callback_ = nullptr; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_ENGINE_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/flutter_view.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/flutter_view.h new file mode 100644 index 0000000..48e7607 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/flutter_view.h @@ -0,0 +1,42 @@ +// 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_FLUTTER_VIEW_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_H_ + +#include + +namespace flutter { + +// The unique identifier for a view. +typedef int64_t FlutterViewId; + +// A view displaying Flutter content. +class FlutterView { + public: + explicit FlutterView(FlutterDesktopViewRef view) : view_(view) {} + + // Destroys this reference to the view. The underlying view is not destroyed. + virtual ~FlutterView() = default; + + // Prevent copying. + FlutterView(FlutterView const&) = delete; + FlutterView& operator=(FlutterView const&) = delete; + + // Returns the backing HWND for the view. + HWND GetNativeWindow() { return FlutterDesktopViewGetHWND(view_); } + + // Returns the DXGI adapter used for rendering or nullptr in case of error. + IDXGIAdapter* GetGraphicsAdapter() { + return FlutterDesktopViewGetGraphicsAdapter(view_); + } + + private: + // Handle for interacting with the C API's view. + FlutterDesktopViewRef view_ = nullptr; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/flutter_view_controller.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/flutter_view_controller.h new file mode 100644 index 0000000..4007534 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/flutter_view_controller.h @@ -0,0 +1,76 @@ +// 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_FLUTTER_VIEW_CONTROLLER_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_CONTROLLER_H_ + +#include +#include + +#include +#include + +#include "dart_project.h" +#include "flutter_engine.h" +#include "flutter_view.h" + +namespace flutter { + +// A controller for a view displaying Flutter content. +// +// This is the primary wrapper class for the desktop C API. +// If you use this class, you should not call any of the setup or teardown +// methods in the C API directly, as this class will do that internally. +class FlutterViewController { + public: + // Creates a FlutterView that can be parented into a Windows View hierarchy + // either using HWNDs. + // + // This also creates a new FlutterEngine. + // + // |dart_project| will be used to configure the engine backing this view. + FlutterViewController(int width, int height, const DartProject& project); + + virtual ~FlutterViewController(); + + // Prevent copying. + FlutterViewController(FlutterViewController const&) = delete; + FlutterViewController& operator=(FlutterViewController const&) = delete; + + // Returns the view controller's view ID. + FlutterViewId view_id() const; + + // Returns the engine running Flutter content in this view. + FlutterEngine* engine() const { return engine_.get(); } + + // Returns the view managed by this controller. + FlutterView* view() const { return view_.get(); } + + // Requests new frame from the engine and repaints the view. + void ForceRedraw(); + + // Allows the Flutter engine and any interested plugins an opportunity to + // handle the given message. + // + // If a result is returned, then the message was handled in such a way that + // further handling should not be done. + std::optional HandleTopLevelWindowProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam); + + private: + // Handle for interacting with the C API's view controller, if any. + FlutterDesktopViewControllerRef controller_ = nullptr; + + // The backing engine + std::shared_ptr engine_; + + // The owned FlutterView. + std::unique_ptr view_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_CONTROLLER_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/message_codec.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/message_codec.h new file mode 100644 index 0000000..c84d25f --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/message_codec.h @@ -0,0 +1,62 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_MESSAGE_CODEC_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_MESSAGE_CODEC_H_ + +#include +#include +#include + +namespace flutter { + +// Translates between a binary message and higher-level method call and +// response/error objects. +template +class MessageCodec { + public: + MessageCodec() = default; + + virtual ~MessageCodec() = default; + + // Prevent copying. + MessageCodec(MessageCodec const&) = delete; + MessageCodec& operator=(MessageCodec const&) = delete; + + // Returns the message encoded in |binary_message|, or nullptr if it cannot be + // decoded by this codec. + std::unique_ptr DecodeMessage(const uint8_t* binary_message, + const size_t message_size) const { + return std::move(DecodeMessageInternal(binary_message, message_size)); + } + + // Returns the message encoded in |binary_message|, or nullptr if it cannot be + // decoded by this codec. + std::unique_ptr DecodeMessage( + const std::vector& binary_message) const { + size_t size = binary_message.size(); + const uint8_t* data = size > 0 ? &binary_message[0] : nullptr; + return std::move(DecodeMessageInternal(data, size)); + } + + // Returns a binary encoding of the given |message|, or nullptr if the + // message cannot be serialized by this codec. + std::unique_ptr> EncodeMessage(const T& message) const { + return std::move(EncodeMessageInternal(message)); + } + + protected: + // Implementation of the public interface, to be provided by subclasses. + virtual std::unique_ptr DecodeMessageInternal( + const uint8_t* binary_message, + const size_t message_size) const = 0; + + // Implementation of the public interface, to be provided by subclasses. + virtual std::unique_ptr> EncodeMessageInternal( + const T& message) const = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_MESSAGE_CODEC_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_call.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_call.h new file mode 100644 index 0000000..3ddf71c --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_call.h @@ -0,0 +1,43 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CALL_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CALL_H_ + +#include +#include + +namespace flutter { + +class EncodableValue; + +// An object encapsulating a method call from Flutter whose arguments are of +// type T. +template +class MethodCall { + public: + // Creates a MethodCall with the given name and arguments. + MethodCall(const std::string& method_name, std::unique_ptr arguments) + : method_name_(method_name), arguments_(std::move(arguments)) {} + + virtual ~MethodCall() = default; + + // Prevent copying. + MethodCall(MethodCall const&) = delete; + MethodCall& operator=(MethodCall const&) = delete; + + // The name of the method being called. + const std::string& method_name() const { return method_name_; } + + // The arguments to the method call, or NULL if there are none. + const T* arguments() const { return arguments_.get(); } + + private: + std::string method_name_; + std::unique_ptr arguments_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CALL_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_channel.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_channel.h new file mode 100644 index 0000000..b1d551a --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_channel.h @@ -0,0 +1,151 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CHANNEL_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CHANNEL_H_ + +#include +#include + +#include "basic_message_channel.h" +#include "binary_messenger.h" +#include "engine_method_result.h" +#include "method_call.h" +#include "method_codec.h" +#include "method_result.h" + +namespace flutter { + +class EncodableValue; + +// A handler for receiving a method call from the Flutter engine. +// +// Implementations must asynchronously call exactly one of the methods on +// |result| to indicate the result of the method call. +template +using MethodCallHandler = + std::function& call, + std::unique_ptr> result)>; + +// A channel for communicating with the Flutter engine using invocation of +// asynchronous methods. +template +class MethodChannel { + public: + // Creates an instance that sends and receives method calls on the channel + // named |name|, encoded with |codec| and dispatched via |messenger|. + MethodChannel(BinaryMessenger* messenger, + const std::string& name, + const MethodCodec* codec) + : messenger_(messenger), name_(name), codec_(codec) {} + + ~MethodChannel() = default; + + // Prevent copying. + MethodChannel(MethodChannel const&) = delete; + MethodChannel& operator=(MethodChannel const&) = delete; + + // Sends a message to the Flutter engine on this channel. + // + // If |result| is provided, one of its methods will be invoked with the + // response from the engine. + void InvokeMethod(const std::string& method, + std::unique_ptr arguments, + std::unique_ptr> result = nullptr) { + MethodCall method_call(method, std::move(arguments)); + std::unique_ptr> message = + codec_->EncodeMethodCall(method_call); + if (!result) { + messenger_->Send(name_, message->data(), message->size(), nullptr); + return; + } + + // std::function requires a copyable lambda, so convert to a shared pointer. + // This is safe since only one copy of the shared_pointer will ever be + // accessed. + std::shared_ptr> shared_result(result.release()); + const auto* codec = codec_; + std::string channel_name = name_; + BinaryReply reply_handler = [shared_result, codec, channel_name]( + const uint8_t* reply, size_t reply_size) { + if (reply_size == 0) { + shared_result->NotImplemented(); + return; + } + // Use this channel's codec to decode and handle the + // reply. + bool decoded = codec->DecodeAndProcessResponseEnvelope( + reply, reply_size, shared_result.get()); + if (!decoded) { + std::cerr << "Unable to decode reply to method " + "invocation on channel " + << channel_name << std::endl; + shared_result->NotImplemented(); + } + }; + + messenger_->Send(name_, message->data(), message->size(), + std::move(reply_handler)); + } + + // Registers a handler that should be called any time a method call is + // received on this channel. A null handler will remove any previous handler. + // + // The handler will be owned by the underlying BinaryMessageHandler. + // Destroying the MethodChannel will not unregister the handler, so + // the caller is responsible for unregistering explicitly if the handler + // stops being valid before the engine is destroyed. + void SetMethodCallHandler(const MethodCallHandler& handler) const { + if (!handler) { + messenger_->SetMessageHandler(name_, nullptr); + return; + } + const auto* codec = codec_; + std::string channel_name = name_; + BinaryMessageHandler binary_handler = [handler, codec, channel_name]( + const uint8_t* message, + size_t message_size, + BinaryReply reply) { + // Use this channel's codec to decode the call and build a result handler. + auto result = + std::make_unique>(std::move(reply), codec); + std::unique_ptr> method_call = + codec->DecodeMethodCall(message, message_size); + if (!method_call) { + std::cerr << "Unable to construct method call from message on channel " + << channel_name << std::endl; + result->NotImplemented(); + return; + } + handler(*method_call, std::move(result)); + }; + messenger_->SetMessageHandler(name_, std::move(binary_handler)); + } + + // Adjusts the number of messages that will get buffered when sending messages + // to channels that aren't fully set up yet. For example, the engine isn't + // running yet or the channel's message handler isn't set up on the Dart side + // yet. + void Resize(int new_size) { + internal::ResizeChannel(messenger_, name_, new_size); + } + + // Defines whether the channel should show warning messages when discarding + // messages due to overflow. + // + // When |warns| is false, the channel is expected to overflow and warning + // messages will not be shown. + void SetWarnsOnOverflow(bool warns) { + internal::SetChannelWarnsOnOverflow(messenger_, name_, warns); + } + + private: + BinaryMessenger* messenger_; + std::string name_; + const MethodCodec* codec_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CHANNEL_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_codec.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_codec.h new file mode 100644 index 0000000..b40fa64 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_codec.h @@ -0,0 +1,111 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CODEC_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CODEC_H_ + +#include +#include +#include + +#include "method_call.h" +#include "method_result.h" + +namespace flutter { + +// Translates between a binary message and higher-level method call and +// response/error objects. +template +class MethodCodec { + public: + MethodCodec() = default; + + virtual ~MethodCodec() = default; + + // Prevent copying. + MethodCodec(MethodCodec const&) = delete; + MethodCodec& operator=(MethodCodec const&) = delete; + + // Returns the MethodCall encoded in |message|, or nullptr if it cannot be + // decoded. + std::unique_ptr> DecodeMethodCall(const uint8_t* message, + size_t message_size) const { + return std::move(DecodeMethodCallInternal(message, message_size)); + } + + // Returns the MethodCall encoded in |message|, or nullptr if it cannot be + // decoded. + std::unique_ptr> DecodeMethodCall( + const std::vector& message) const { + size_t size = message.size(); + const uint8_t* data = size > 0 ? &message[0] : nullptr; + return std::move(DecodeMethodCallInternal(data, size)); + } + + // Returns a binary encoding of the given |method_call|, or nullptr if the + // method call cannot be serialized by this codec. + std::unique_ptr> EncodeMethodCall( + const MethodCall& method_call) const { + return std::move(EncodeMethodCallInternal(method_call)); + } + + // Returns a binary encoding of |result|. |result| must be a type supported + // by the codec. + std::unique_ptr> EncodeSuccessEnvelope( + const T* result = nullptr) const { + return std::move(EncodeSuccessEnvelopeInternal(result)); + } + + // Returns a binary encoding of |error|. The |error_details| must be a type + // supported by the codec. + std::unique_ptr> EncodeErrorEnvelope( + const std::string& error_code, + const std::string& error_message = "", + const T* error_details = nullptr) const { + return std::move( + EncodeErrorEnvelopeInternal(error_code, error_message, error_details)); + } + + // Decodes the response envelope encoded in |response|, calling the + // appropriate method on |result|. + // + // Returns false if |response| cannot be decoded. In that case the caller is + // responsible for calling a |result| method. + bool DecodeAndProcessResponseEnvelope(const uint8_t* response, + size_t response_size, + MethodResult* result) const { + return DecodeAndProcessResponseEnvelopeInternal(response, response_size, + result); + } + + protected: + // Implementation of the public interface, to be provided by subclasses. + virtual std::unique_ptr> DecodeMethodCallInternal( + const uint8_t* message, + size_t message_size) const = 0; + + // Implementation of the public interface, to be provided by subclasses. + virtual std::unique_ptr> EncodeMethodCallInternal( + const MethodCall& method_call) const = 0; + + // Implementation of the public interface, to be provided by subclasses. + virtual std::unique_ptr> EncodeSuccessEnvelopeInternal( + const T* result) const = 0; + + // Implementation of the public interface, to be provided by subclasses. + virtual std::unique_ptr> EncodeErrorEnvelopeInternal( + const std::string& error_code, + const std::string& error_message, + const T* error_details) const = 0; + + // Implementation of the public interface, to be provided by subclasses. + virtual bool DecodeAndProcessResponseEnvelopeInternal( + const uint8_t* response, + size_t response_size, + MethodResult* result) const = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_CODEC_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_result.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_result.h new file mode 100644 index 0000000..05c7fe9 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_result.h @@ -0,0 +1,76 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_H_ + +#include + +namespace flutter { + +class EncodableValue; + +// Encapsulates a result returned from a MethodCall. Only one method should be +// called on any given instance. +template +class MethodResult { + public: + MethodResult() = default; + + virtual ~MethodResult() = default; + + // Prevent copying. + MethodResult(MethodResult const&) = delete; + MethodResult& operator=(MethodResult const&) = delete; + + // Sends a success response, indicating that the call completed successfully + // with the given result. + void Success(const T& result) { SuccessInternal(&result); } + + // Sends a success response, indicating that the call completed successfully + // with no result. + void Success() { SuccessInternal(nullptr); } + + // Sends an error response, indicating that the call was understood but + // handling failed in some way. + // + // error_code: A string error code describing the error. + // error_message: A user-readable error message. + // error_details: Arbitrary extra details about the error. + void Error(const std::string& error_code, + const std::string& error_message, + const T& error_details) { + ErrorInternal(error_code, error_message, &error_details); + } + + // Sends an error response, indicating that the call was understood but + // handling failed in some way. + // + // error_code: A string error code describing the error. + // error_message: A user-readable error message (optional). + void Error(const std::string& error_code, + const std::string& error_message = "") { + ErrorInternal(error_code, error_message, nullptr); + } + + // Sends a not-implemented response, indicating that the method either was not + // recognized, or has not been implemented. + void NotImplemented() { NotImplementedInternal(); } + + protected: + // Implementation of the public interface, to be provided by subclasses. + virtual void SuccessInternal(const T* result) = 0; + + // Implementation of the public interface, to be provided by subclasses. + virtual void ErrorInternal(const std::string& error_code, + const std::string& error_message, + const T* error_details) = 0; + + // Implementation of the public interface, to be provided by subclasses. + virtual void NotImplementedInternal() = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_result_functions.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_result_functions.h new file mode 100644 index 0000000..c485da3 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/method_result_functions.h @@ -0,0 +1,80 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_FUNCTIONS_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_FUNCTIONS_H_ + +#include +#include +#include + +#include "method_result.h" + +namespace flutter { + +class EncodableValue; + +// Handler types for each of the MethodResult outcomes. +template +using ResultHandlerSuccess = std::function; +template +using ResultHandlerError = std::function; +template +using ResultHandlerNotImplemented = std::function; + +// An implementation of MethodResult that pass calls through to provided +// function objects, for ease of constructing one-off result handlers. +template +class MethodResultFunctions : public MethodResult { + public: + // Creates a result object that calls the provided functions for the + // corresponding MethodResult outcomes. + MethodResultFunctions(ResultHandlerSuccess on_success, + ResultHandlerError on_error, + ResultHandlerNotImplemented on_not_implemented) + : on_success_(std::move(on_success)), + on_error_(std::move(on_error)), + on_not_implemented_(std::move(on_not_implemented)) {} + + virtual ~MethodResultFunctions() = default; + + // Prevent copying. + MethodResultFunctions(MethodResultFunctions const&) = delete; + MethodResultFunctions& operator=(MethodResultFunctions const&) = delete; + + protected: + // |flutter::MethodResult| + void SuccessInternal(const T* result) override { + if (on_success_) { + on_success_(result); + } + } + + // |flutter::MethodResult| + void ErrorInternal(const std::string& error_code, + const std::string& error_message, + const T* error_details) override { + if (on_error_) { + on_error_(error_code, error_message, error_details); + } + } + + // |flutter::MethodResult| + void NotImplementedInternal() override { + if (on_not_implemented_) { + on_not_implemented_(); + } + } + + private: + ResultHandlerSuccess on_success_; + ResultHandlerError on_error_; + ResultHandlerNotImplemented on_not_implemented_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_METHOD_RESULT_FUNCTIONS_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/plugin_registrar.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/plugin_registrar.h new file mode 100644 index 0000000..e21f472 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/plugin_registrar.h @@ -0,0 +1,131 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRAR_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRAR_H_ + +#include + +#include +#include +#include +#include + +#include "binary_messenger.h" +#include "texture_registrar.h" + +namespace flutter { + +class Plugin; + +// A object managing the registration of a plugin for various events. +// +// Currently this class has very limited functionality, but is expected to +// expand over time to more closely match the functionality of +// the Flutter mobile plugin APIs' plugin registrars. +class PluginRegistrar { + public: + // Creates a new PluginRegistrar. |core_registrar| and the messenger it + // provides must remain valid as long as this object exists. + explicit PluginRegistrar(FlutterDesktopPluginRegistrarRef core_registrar); + + virtual ~PluginRegistrar(); + + // Prevent copying. + PluginRegistrar(PluginRegistrar const&) = delete; + PluginRegistrar& operator=(PluginRegistrar const&) = delete; + + // Returns the messenger to use for creating channels to communicate with the + // Flutter engine. + // + // This pointer will remain valid for the lifetime of this instance. + BinaryMessenger* messenger() { return messenger_.get(); } + + // Returns the texture registrar to use for the plugin to render a pixel + // buffer. + TextureRegistrar* texture_registrar() { return texture_registrar_.get(); } + + // Takes ownership of |plugin|. + // + // Plugins are not required to call this method if they have other lifetime + // management, but this is a convenient place for plugins to be owned to + // ensure that they stay valid for any registered callbacks. + void AddPlugin(std::unique_ptr plugin); + + protected: + FlutterDesktopPluginRegistrarRef registrar() const { return registrar_; } + + // Destroys all owned plugins. Subclasses should call this at the beginning of + // their destructors to prevent the possibility of an owned plugin trying to + // access destroyed state during its own destruction. + void ClearPlugins(); + + private: + // Handle for interacting with the C API's registrar. + FlutterDesktopPluginRegistrarRef registrar_; + + std::unique_ptr messenger_; + + std::unique_ptr texture_registrar_; + + // Plugins registered for ownership. + std::set> plugins_; +}; + +// A plugin that can be registered for ownership by a PluginRegistrar. +class Plugin { + public: + virtual ~Plugin() = default; +}; + +// A singleton to own PluginRegistrars. This is intended for use in plugins, +// where there is no higher-level object to own a PluginRegistrar that can +// own plugin instances and ensure that they live as long as the engine they +// are registered with. +class PluginRegistrarManager { + public: + static PluginRegistrarManager* GetInstance(); + + // Prevent copying. + PluginRegistrarManager(PluginRegistrarManager const&) = delete; + PluginRegistrarManager& operator=(PluginRegistrarManager const&) = delete; + + // Returns a plugin registrar wrapper of type T, which must be a kind of + // PluginRegistrar, creating it if necessary. The returned registrar will + // live as long as the underlying FlutterDesktopPluginRegistrarRef, so + // can be used to own plugin instances. + // + // Calling this multiple times for the same registrar_ref with different + // template types results in undefined behavior. + template + T* GetRegistrar(FlutterDesktopPluginRegistrarRef registrar_ref) { + auto insert_result = + registrars_.emplace(registrar_ref, std::make_unique(registrar_ref)); + auto& registrar_pair = *(insert_result.first); + FlutterDesktopPluginRegistrarSetDestructionHandler(registrar_pair.first, + OnRegistrarDestroyed); + return static_cast(registrar_pair.second.get()); + } + + // Destroys all registrar wrappers created by the manager. + // + // This is intended primarily for use in tests. + void Reset() { registrars_.clear(); } + + private: + PluginRegistrarManager(); + + using WrapperMap = std::map>; + + static void OnRegistrarDestroyed(FlutterDesktopPluginRegistrarRef registrar); + + WrapperMap* registrars() { return ®istrars_; } + + WrapperMap registrars_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRAR_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/plugin_registrar_windows.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/plugin_registrar_windows.h new file mode 100644 index 0000000..7655b31 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/plugin_registrar_windows.h @@ -0,0 +1,151 @@ +// 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_PLUGIN_REGISTRAR_WINDOWS_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRAR_WINDOWS_H_ + +#include +#include + +#include +#include + +#include "flutter_view.h" +#include "plugin_registrar.h" + +namespace flutter { + +// A delegate callback for WindowProc delegation. +// +// Implementations should return a value only if they have handled the message +// and want to stop all further handling. +using WindowProcDelegate = std::function(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)>; + +// An extension to PluginRegistrar providing access to Windows-specific +// functionality. +class PluginRegistrarWindows : public PluginRegistrar { + public: + // Creates a new PluginRegistrar. |core_registrar| and the messenger it + // provides must remain valid as long as this object exists. + explicit PluginRegistrarWindows( + FlutterDesktopPluginRegistrarRef core_registrar) + : PluginRegistrar(core_registrar) { + FlutterDesktopViewRef implicit_view = + FlutterDesktopPluginRegistrarGetView(core_registrar); + if (implicit_view) { + implicit_view_ = std::make_unique(implicit_view); + } + } + + virtual ~PluginRegistrarWindows() { + // Must be the first call. + ClearPlugins(); + // Explicitly cleared to facilitate destruction order testing. + implicit_view_.reset(); + } + + // Prevent copying. + PluginRegistrarWindows(PluginRegistrarWindows const&) = delete; + PluginRegistrarWindows& operator=(PluginRegistrarWindows const&) = delete; + + // Returns the implicit view, or nullptr if there is no implicit view. + // + // See: + // https://api.flutter.dev/flutter/dart-ui/PlatformDispatcher/implicitView.html + // + // DEPRECATED: Use |GetViewById| instead. + FlutterView* GetView() { return implicit_view_.get(); } + + // Returns the view with the given ID, or nullptr if the view does not exist. + // + // Destroying the shared pointer destroys the reference to the view; it does + // not destroy the underlying view. + std::shared_ptr GetViewById(FlutterViewId view_id) const { + FlutterDesktopViewRef view = + FlutterDesktopPluginRegistrarGetViewById(registrar(), view_id); + if (!view) { + return nullptr; + } + + return std::make_shared(view); + } + + // Registers |delegate| to receive WindowProc callbacks for the top-level + // window containing this Flutter instance. Returns an ID that can be used to + // unregister the handler. + // + // Delegates are not guaranteed to be called: + // - The application may choose not to delegate WindowProc calls. + // - If multiple plugins are registered, the first one that returns a value + // from the delegate message will "win", and others will not be called. + // The order of delegate calls is not defined. + // + // Delegates should be implemented as narrowly as possible, only returning + // a value in cases where it's important that other delegates not run, to + // minimize the chances of conflicts between plugins. + int RegisterTopLevelWindowProcDelegate(WindowProcDelegate delegate) { + if (window_proc_delegates_.empty()) { + FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate( + registrar(), PluginRegistrarWindows::OnTopLevelWindowProc, this); + } + int delegate_id = next_window_proc_delegate_id_++; + window_proc_delegates_.emplace(delegate_id, std::move(delegate)); + return delegate_id; + } + + // Unregisters a previously registered delegate. + void UnregisterTopLevelWindowProcDelegate(int proc_id) { + window_proc_delegates_.erase(proc_id); + if (window_proc_delegates_.empty()) { + FlutterDesktopPluginRegistrarUnregisterTopLevelWindowProcDelegate( + registrar(), PluginRegistrarWindows::OnTopLevelWindowProc); + } + } + + private: + // A FlutterDesktopWindowProcCallback implementation that forwards back to + // a PluginRegistarWindows instance provided as |user_data|. + static bool OnTopLevelWindowProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam, + void* user_data, + LRESULT* result) { + const auto* registrar = static_cast(user_data); + std::optional optional_result = registrar->CallTopLevelWindowProcDelegates( + hwnd, message, wparam, lparam); + if (optional_result) { + *result = *optional_result; + } + return optional_result.has_value(); + } + + std::optional CallTopLevelWindowProcDelegates(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) const { + std::optional result; + for (const auto& pair : window_proc_delegates_) { + result = pair.second(hwnd, message, wparam, lparam); + // Stop as soon as any delegate indicates that it has handled the message. + if (result) { + break; + } + } + return result; + } + + // The associated FlutterView, if any. + std::unique_ptr implicit_view_; + + // The next ID to return from RegisterWindowProcDelegate. + int next_window_proc_delegate_id_ = 1; + + std::map window_proc_delegates_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRAR_WINDOWS_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/plugin_registry.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/plugin_registry.h new file mode 100644 index 0000000..ffc548b --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/plugin_registry.h @@ -0,0 +1,37 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRY_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRY_H_ + +#include + +#include + +namespace flutter { + +// Vends PluginRegistrars for named plugins. +// +// Plugins are identified by unique string keys, typically the name of the +// plugin's main class. +class PluginRegistry { + public: + PluginRegistry() = default; + virtual ~PluginRegistry() = default; + + // Prevent copying. + PluginRegistry(PluginRegistry const&) = delete; + PluginRegistry& operator=(PluginRegistry const&) = delete; + + // Returns the FlutterDesktopPluginRegistrarRef to register a plugin with the + // given name. + // + // The name must be unique across the application. + virtual FlutterDesktopPluginRegistrarRef GetRegistrarForPlugin( + const std::string& plugin_name) = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_PLUGIN_REGISTRY_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/standard_codec_serializer.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/standard_codec_serializer.h new file mode 100644 index 0000000..a600103 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/standard_codec_serializer.h @@ -0,0 +1,76 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_CODEC_SERIALIZER_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_CODEC_SERIALIZER_H_ + +#include "byte_streams.h" +#include "encodable_value.h" + +namespace flutter { + +// Encapsulates the logic for encoding/decoding EncodableValues to/from the +// standard codec binary representation. +// +// This can be subclassed to extend the standard codec with support for new +// types. +class StandardCodecSerializer { + public: + virtual ~StandardCodecSerializer(); + + // Returns the shared serializer instance. + static const StandardCodecSerializer& GetInstance(); + + // Prevent copying. + StandardCodecSerializer(StandardCodecSerializer const&) = delete; + StandardCodecSerializer& operator=(StandardCodecSerializer const&) = delete; + + // Reads and returns the next value from |stream|. + EncodableValue ReadValue(ByteStreamReader* stream) const; + + // Writes the encoding of |value| to |stream|, including the initial type + // discrimination byte. + // + // Can be overridden by a subclass to extend the codec. + virtual void WriteValue(const EncodableValue& value, + ByteStreamWriter* stream) const; + + protected: + // Codecs require long-lived serializers, so clients should always use + // GetInstance(). + StandardCodecSerializer(); + + // Reads and returns the next value from |stream|, whose discrimination byte + // was |type|. + // + // The discrimination byte will already have been read from the stream when + // this is called. + // + // Can be overridden by a subclass to extend the codec. + virtual EncodableValue ReadValueOfType(uint8_t type, + ByteStreamReader* stream) const; + + // Reads the variable-length size from the current position in |stream|. + size_t ReadSize(ByteStreamReader* stream) const; + + // Writes the variable-length size encoding to |stream|. + void WriteSize(size_t size, ByteStreamWriter* stream) const; + + private: + // Reads a fixed-type list whose values are of type T from the current + // position in |stream|, and returns it as the corresponding EncodableValue. + // |T| must correspond to one of the supported list value types of + // EncodableValue. + template + EncodableValue ReadVector(ByteStreamReader* stream) const; + + // Writes |vector| to |stream| as a fixed-type list. |T| must correspond to + // one of the supported list value types of EncodableValue. + template + void WriteVector(const std::vector vector, ByteStreamWriter* stream) const; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_CODEC_SERIALIZER_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/standard_message_codec.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/standard_message_codec.h new file mode 100644 index 0000000..568b391 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/standard_message_codec.h @@ -0,0 +1,57 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_MESSAGE_CODEC_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_MESSAGE_CODEC_H_ + +#include + +#include "encodable_value.h" +#include "message_codec.h" +#include "standard_codec_serializer.h" + +namespace flutter { + +// A binary message encoding/decoding mechanism for communications to/from the +// Flutter engine via message channels. +class StandardMessageCodec : public MessageCodec { + public: + // Returns an instance of the codec, optionally using a custom serializer to + // add support for more types. + // + // If provided, |serializer| must be long-lived. If no serializer is provided, + // the default will be used. + // + // The instance returned for a given |serializer| will be shared, and + // any instance returned from this will be long-lived, and can be safely + // passed to, e.g., channel constructors. + static const StandardMessageCodec& GetInstance( + const StandardCodecSerializer* serializer = nullptr); + + ~StandardMessageCodec(); + + // Prevent copying. + StandardMessageCodec(StandardMessageCodec const&) = delete; + StandardMessageCodec& operator=(StandardMessageCodec const&) = delete; + + protected: + // |flutter::MessageCodec| + std::unique_ptr DecodeMessageInternal( + const uint8_t* binary_message, + const size_t message_size) const override; + + // |flutter::MessageCodec| + std::unique_ptr> EncodeMessageInternal( + const EncodableValue& message) const override; + + private: + // Instances should be obtained via GetInstance. + explicit StandardMessageCodec(const StandardCodecSerializer* serializer); + + const StandardCodecSerializer* serializer_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_MESSAGE_CODEC_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/standard_method_codec.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/standard_method_codec.h new file mode 100644 index 0000000..b6db35e --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/standard_method_codec.h @@ -0,0 +1,73 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_METHOD_CODEC_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_METHOD_CODEC_H_ + +#include + +#include "encodable_value.h" +#include "method_call.h" +#include "method_codec.h" +#include "standard_codec_serializer.h" + +namespace flutter { + +// An implementation of MethodCodec that uses a binary serialization. +class StandardMethodCodec : public MethodCodec { + public: + // Returns an instance of the codec, optionally using a custom serializer to + // add support for more types. + // + // If provided, |serializer| must be long-lived. If no serializer is provided, + // the default will be used. + // + // The instance returned for a given |extension| will be shared, and + // any instance returned from this will be long-lived, and can be safely + // passed to, e.g., channel constructors. + static const StandardMethodCodec& GetInstance( + const StandardCodecSerializer* serializer = nullptr); + + ~StandardMethodCodec(); + + // Prevent copying. + StandardMethodCodec(StandardMethodCodec const&) = delete; + StandardMethodCodec& operator=(StandardMethodCodec const&) = delete; + + protected: + // |flutter::MethodCodec| + std::unique_ptr> DecodeMethodCallInternal( + const uint8_t* message, + size_t message_size) const override; + + // |flutter::MethodCodec| + std::unique_ptr> EncodeMethodCallInternal( + const MethodCall& method_call) const override; + + // |flutter::MethodCodec| + std::unique_ptr> EncodeSuccessEnvelopeInternal( + const EncodableValue* result) const override; + + // |flutter::MethodCodec| + std::unique_ptr> EncodeErrorEnvelopeInternal( + const std::string& error_code, + const std::string& error_message, + const EncodableValue* error_details) const override; + + // |flutter::MethodCodec| + bool DecodeAndProcessResponseEnvelopeInternal( + const uint8_t* response, + size_t response_size, + MethodResult* result) const override; + + private: + // Instances should be obtained via GetInstance. + explicit StandardMethodCodec(const StandardCodecSerializer* serializer); + + const StandardCodecSerializer* serializer_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_STANDARD_METHOD_CODEC_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/texture_registrar.h b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/texture_registrar.h new file mode 100644 index 0000000..a536dcf --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/include/flutter/texture_registrar.h @@ -0,0 +1,111 @@ +// 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_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_TEXTURE_REGISTRAR_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_TEXTURE_REGISTRAR_H_ + +#include + +#include +#include +#include +#include +#include + +namespace flutter { + +// A pixel buffer texture. +class PixelBufferTexture { + public: + // A callback used for retrieving pixel buffers. + typedef std::function + CopyBufferCallback; + + // Creates a pixel buffer texture that uses the provided |copy_buffer_cb| to + // retrieve the buffer. + // As the callback is usually invoked from the render thread, the callee must + // take care of proper synchronization. It also needs to be ensured that the + // returned buffer isn't released prior to unregistering this texture. + explicit PixelBufferTexture(CopyBufferCallback copy_buffer_callback) + : copy_buffer_callback_(std::move(copy_buffer_callback)) {} + + // Returns the callback-provided FlutterDesktopPixelBuffer that contains the + // actual pixel data. The intended surface size is specified by |width| and + // |height|. + const FlutterDesktopPixelBuffer* CopyPixelBuffer(size_t width, + size_t height) const { + return copy_buffer_callback_(width, height); + } + + private: + const CopyBufferCallback copy_buffer_callback_; +}; + +// A GPU surface-based texture. +class GpuSurfaceTexture { + public: + // A callback used for retrieving surface descriptors. + typedef std::function< + const FlutterDesktopGpuSurfaceDescriptor*(size_t width, size_t height)> + ObtainDescriptorCallback; + + GpuSurfaceTexture(FlutterDesktopGpuSurfaceType surface_type, + ObtainDescriptorCallback obtain_descriptor_callback) + : surface_type_(surface_type), + obtain_descriptor_callback_(std::move(obtain_descriptor_callback)) {} + + // Returns the callback-provided FlutterDesktopGpuSurfaceDescriptor that + // contains the surface handle. The intended surface size is specified by + // |width| and |height|. + const FlutterDesktopGpuSurfaceDescriptor* ObtainDescriptor( + size_t width, + size_t height) const { + return obtain_descriptor_callback_(width, height); + } + + // Gets the surface type. + FlutterDesktopGpuSurfaceType surface_type() const { return surface_type_; } + + private: + const FlutterDesktopGpuSurfaceType surface_type_; + const ObtainDescriptorCallback obtain_descriptor_callback_; +}; + +// The available texture variants. +// Only PixelBufferTexture is currently implemented. +// Other variants are expected to be added in the future. +typedef std::variant TextureVariant; + +// An object keeping track of external textures. +// +// Thread safety: +// It's safe to call the member methods from any thread. +class TextureRegistrar { + public: + virtual ~TextureRegistrar() = default; + + // Registers a |texture| object and returns the ID for that texture. + virtual int64_t RegisterTexture(TextureVariant* texture) = 0; + + // Notifies the flutter engine that the texture object corresponding + // to |texure_id| needs to render a new frame. + // + // For PixelBufferTextures, this will effectively make the engine invoke + // the callback that was provided upon creating the texture. + virtual bool MarkTextureFrameAvailable(int64_t texture_id) = 0; + + // Asynchronously unregisters an existing texture object. + // Upon completion, the optional |callback| gets invoked. + virtual void UnregisterTexture(int64_t texture_id, + std::function callback) = 0; + + // Unregisters an existing texture object. + // DEPRECATED: Use UnregisterTexture(texture_id, optional_callback) instead. + virtual bool UnregisterTexture(int64_t texture_id) = 0; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_INCLUDE_FLUTTER_TEXTURE_REGISTRAR_H_ diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/plugin_registrar.cc b/windows/flutter/ephemeral/cpp_client_wrapper/plugin_registrar.cc new file mode 100644 index 0000000..65fef5c --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/plugin_registrar.cc @@ -0,0 +1,62 @@ +// 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 "include/flutter/plugin_registrar.h" + +#include +#include + +#include "binary_messenger_impl.h" +#include "include/flutter/engine_method_result.h" +#include "include/flutter/method_channel.h" +#include "texture_registrar_impl.h" + +namespace flutter { + +// ===== PluginRegistrar ===== + +PluginRegistrar::PluginRegistrar(FlutterDesktopPluginRegistrarRef registrar) + : registrar_(registrar) { + auto core_messenger = FlutterDesktopPluginRegistrarGetMessenger(registrar_); + messenger_ = std::make_unique(core_messenger); + + auto texture_registrar = + FlutterDesktopRegistrarGetTextureRegistrar(registrar_); + texture_registrar_ = + std::make_unique(texture_registrar); +} + +PluginRegistrar::~PluginRegistrar() { + // This must always be the first call. + ClearPlugins(); + + // Explicitly cleared to facilitate testing of destruction order. + messenger_.reset(); +} + +void PluginRegistrar::AddPlugin(std::unique_ptr plugin) { + plugins_.insert(std::move(plugin)); +} + +void PluginRegistrar::ClearPlugins() { + plugins_.clear(); +} + +// ===== PluginRegistrarManager ===== + +// static +PluginRegistrarManager* PluginRegistrarManager::GetInstance() { + static PluginRegistrarManager* instance = new PluginRegistrarManager(); + return instance; +} + +PluginRegistrarManager::PluginRegistrarManager() = default; + +// static +void PluginRegistrarManager::OnRegistrarDestroyed( + FlutterDesktopPluginRegistrarRef registrar) { + GetInstance()->registrars()->erase(registrar); +} + +} // namespace flutter diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/readme b/windows/flutter/ephemeral/cpp_client_wrapper/readme new file mode 100644 index 0000000..56c9305 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/readme @@ -0,0 +1,9 @@ +This code is intended to be built into plugins and applications to provide +higher-level, C++ abstractions for interacting with the Flutter library. + +Over time, the goal is to move more of this code into the library in a way that +provides a usable ABI (e.g., does not use standard library in the interfaces). + +Note that this wrapper is still in early stages. Expect significant churn in +both the APIs and the structure of the wrapper (e.g., the exact set of files +that need to be built). diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/standard_codec.cc b/windows/flutter/ephemeral/cpp_client_wrapper/standard_codec.cc new file mode 100644 index 0000000..d5f4b2f --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/standard_codec.cc @@ -0,0 +1,468 @@ +// 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. + +// This file contains what would normally be standard_codec_serializer.cc, +// standard_message_codec.cc, and standard_method_codec.cc. They are grouped +// together to simplify use of the client wrapper, since the common case is +// that any client that needs one of these files needs all three. + +#include +#include +#include +#include +#include +#include + +#include "byte_buffer_streams.h" +#include "include/flutter/standard_codec_serializer.h" +#include "include/flutter/standard_message_codec.h" +#include "include/flutter/standard_method_codec.h" + +namespace flutter { + +// ===== standard_codec_serializer.h ===== + +namespace { + +// The order/values here must match the constants in message_codecs.dart. +enum class EncodedType { + kNull = 0, + kTrue, + kFalse, + kInt32, + kInt64, + kLargeInt, // No longer used. If encountered, treat as kString. + kFloat64, + kString, + kUInt8List, + kInt32List, + kInt64List, + kFloat64List, + kList, + kMap, + kFloat32List, +}; + +// Returns the encoded type that should be written when serializing |value|. +EncodedType EncodedTypeForValue(const EncodableValue& value) { + switch (value.index()) { + case 0: + return EncodedType::kNull; + case 1: + return std::get(value) ? EncodedType::kTrue : EncodedType::kFalse; + case 2: + return EncodedType::kInt32; + case 3: + return EncodedType::kInt64; + case 4: + return EncodedType::kFloat64; + case 5: + return EncodedType::kString; + case 6: + return EncodedType::kUInt8List; + case 7: + return EncodedType::kInt32List; + case 8: + return EncodedType::kInt64List; + case 9: + return EncodedType::kFloat64List; + case 10: + return EncodedType::kList; + case 11: + return EncodedType::kMap; + case 13: + return EncodedType::kFloat32List; + } + assert(false); + return EncodedType::kNull; +} + +} // namespace + +StandardCodecSerializer::StandardCodecSerializer() = default; + +StandardCodecSerializer::~StandardCodecSerializer() = default; + +const StandardCodecSerializer& StandardCodecSerializer::GetInstance() { + static StandardCodecSerializer sInstance; + return sInstance; +}; + +EncodableValue StandardCodecSerializer::ReadValue( + ByteStreamReader* stream) const { + uint8_t type = stream->ReadByte(); + return ReadValueOfType(type, stream); +} + +void StandardCodecSerializer::WriteValue(const EncodableValue& value, + ByteStreamWriter* stream) const { + stream->WriteByte(static_cast(EncodedTypeForValue(value))); + // TODO(cbracken): Consider replacing this with std::visit. + switch (value.index()) { + case 0: + case 1: + // Null and bool are encoded directly in the type. + break; + case 2: + stream->WriteInt32(std::get(value)); + break; + case 3: + stream->WriteInt64(std::get(value)); + break; + case 4: + stream->WriteAlignment(8); + stream->WriteDouble(std::get(value)); + break; + case 5: { + const auto& string_value = std::get(value); + size_t size = string_value.size(); + WriteSize(size, stream); + if (size > 0) { + stream->WriteBytes( + reinterpret_cast(string_value.data()), size); + } + break; + } + case 6: + WriteVector(std::get>(value), stream); + break; + case 7: + WriteVector(std::get>(value), stream); + break; + case 8: + WriteVector(std::get>(value), stream); + break; + case 9: + WriteVector(std::get>(value), stream); + break; + case 10: { + const auto& list = std::get(value); + WriteSize(list.size(), stream); + for (const auto& item : list) { + WriteValue(item, stream); + } + break; + } + case 11: { + const auto& map = std::get(value); + WriteSize(map.size(), stream); + for (const auto& pair : map) { + WriteValue(pair.first, stream); + WriteValue(pair.second, stream); + } + break; + } + case 12: + std::cerr + << "Unhandled custom type in StandardCodecSerializer::WriteValue. " + << "Custom types require codec extensions." << std::endl; + break; + case 13: { + WriteVector(std::get>(value), stream); + break; + } + } +} + +EncodableValue StandardCodecSerializer::ReadValueOfType( + uint8_t type, + ByteStreamReader* stream) const { + switch (static_cast(type)) { + case EncodedType::kNull: + return EncodableValue(); + case EncodedType::kTrue: + return EncodableValue(true); + case EncodedType::kFalse: + return EncodableValue(false); + case EncodedType::kInt32: + return EncodableValue(stream->ReadInt32()); + case EncodedType::kInt64: + return EncodableValue(stream->ReadInt64()); + case EncodedType::kFloat64: + stream->ReadAlignment(8); + return EncodableValue(stream->ReadDouble()); + case EncodedType::kLargeInt: + case EncodedType::kString: { + size_t size = ReadSize(stream); + std::string string_value; + string_value.resize(size); + stream->ReadBytes(reinterpret_cast(&string_value[0]), size); + return EncodableValue(string_value); + } + case EncodedType::kUInt8List: + return ReadVector(stream); + case EncodedType::kInt32List: + return ReadVector(stream); + case EncodedType::kInt64List: + return ReadVector(stream); + case EncodedType::kFloat64List: + return ReadVector(stream); + case EncodedType::kList: { + size_t length = ReadSize(stream); + EncodableList list_value; + list_value.reserve(length); + for (size_t i = 0; i < length; ++i) { + list_value.push_back(ReadValue(stream)); + } + return EncodableValue(list_value); + } + case EncodedType::kMap: { + size_t length = ReadSize(stream); + EncodableMap map_value; + for (size_t i = 0; i < length; ++i) { + EncodableValue key = ReadValue(stream); + EncodableValue value = ReadValue(stream); + map_value.emplace(std::move(key), std::move(value)); + } + return EncodableValue(map_value); + } + case EncodedType::kFloat32List: { + return ReadVector(stream); + } + } + std::cerr << "Unknown type in StandardCodecSerializer::ReadValueOfType: " + << static_cast(type) << std::endl; + return EncodableValue(); +} + +size_t StandardCodecSerializer::ReadSize(ByteStreamReader* stream) const { + uint8_t byte = stream->ReadByte(); + if (byte < 254) { + return byte; + } else if (byte == 254) { + uint16_t value = 0; + stream->ReadBytes(reinterpret_cast(&value), 2); + return value; + } else { + uint32_t value = 0; + stream->ReadBytes(reinterpret_cast(&value), 4); + return value; + } +} + +void StandardCodecSerializer::WriteSize(size_t size, + ByteStreamWriter* stream) const { + if (size < 254) { + stream->WriteByte(static_cast(size)); + } else if (size <= 0xffff) { + stream->WriteByte(254); + uint16_t value = static_cast(size); + stream->WriteBytes(reinterpret_cast(&value), 2); + } else { + stream->WriteByte(255); + uint32_t value = static_cast(size); + stream->WriteBytes(reinterpret_cast(&value), 4); + } +} + +template +EncodableValue StandardCodecSerializer::ReadVector( + ByteStreamReader* stream) const { + size_t count = ReadSize(stream); + std::vector vector; + vector.resize(count); + uint8_t type_size = static_cast(sizeof(T)); + if (type_size > 1) { + stream->ReadAlignment(type_size); + } + stream->ReadBytes(reinterpret_cast(vector.data()), + count * type_size); + return EncodableValue(vector); +} + +template +void StandardCodecSerializer::WriteVector(const std::vector vector, + ByteStreamWriter* stream) const { + size_t count = vector.size(); + WriteSize(count, stream); + if (count == 0) { + return; + } + uint8_t type_size = static_cast(sizeof(T)); + if (type_size > 1) { + stream->WriteAlignment(type_size); + } + stream->WriteBytes(reinterpret_cast(vector.data()), + count * type_size); +} + +// ===== standard_message_codec.h ===== + +// static +const StandardMessageCodec& StandardMessageCodec::GetInstance( + const StandardCodecSerializer* serializer) { + if (!serializer) { + serializer = &StandardCodecSerializer::GetInstance(); + } + static auto* sInstances = new std::map>; + auto it = sInstances->find(serializer); + if (it == sInstances->end()) { + // Uses new due to private constructor (to prevent API clients from + // accidentally passing temporary codec instances to channels). + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) + auto emplace_result = sInstances->emplace( + serializer, std::unique_ptr( + new StandardMessageCodec(serializer))); + it = emplace_result.first; + } + return *(it->second); +} + +StandardMessageCodec::StandardMessageCodec( + const StandardCodecSerializer* serializer) + : serializer_(serializer) {} + +StandardMessageCodec::~StandardMessageCodec() = default; + +std::unique_ptr StandardMessageCodec::DecodeMessageInternal( + const uint8_t* binary_message, + size_t message_size) const { + if (!binary_message) { + return std::make_unique(); + } + ByteBufferStreamReader stream(binary_message, message_size); + return std::make_unique(serializer_->ReadValue(&stream)); +} + +std::unique_ptr> +StandardMessageCodec::EncodeMessageInternal( + const EncodableValue& message) const { + auto encoded = std::make_unique>(); + ByteBufferStreamWriter stream(encoded.get()); + serializer_->WriteValue(message, &stream); + return encoded; +} + +// ===== standard_method_codec.h ===== + +// static +const StandardMethodCodec& StandardMethodCodec::GetInstance( + const StandardCodecSerializer* serializer) { + if (!serializer) { + serializer = &StandardCodecSerializer::GetInstance(); + } + static auto* sInstances = new std::map>; + auto it = sInstances->find(serializer); + if (it == sInstances->end()) { + // Uses new due to private constructor (to prevent API clients from + // accidentally passing temporary codec instances to channels). + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) + auto emplace_result = sInstances->emplace( + serializer, std::unique_ptr( + new StandardMethodCodec(serializer))); + it = emplace_result.first; + } + return *(it->second); +} + +StandardMethodCodec::StandardMethodCodec( + const StandardCodecSerializer* serializer) + : serializer_(serializer) {} + +StandardMethodCodec::~StandardMethodCodec() = default; + +std::unique_ptr> +StandardMethodCodec::DecodeMethodCallInternal(const uint8_t* message, + size_t message_size) const { + ByteBufferStreamReader stream(message, message_size); + EncodableValue method_name_value = serializer_->ReadValue(&stream); + const auto* method_name = std::get_if(&method_name_value); + if (!method_name) { + std::cerr << "Invalid method call; method name is not a string." + << std::endl; + return nullptr; + } + auto arguments = + std::make_unique(serializer_->ReadValue(&stream)); + return std::make_unique>(*method_name, + std::move(arguments)); +} + +std::unique_ptr> +StandardMethodCodec::EncodeMethodCallInternal( + const MethodCall& method_call) const { + auto encoded = std::make_unique>(); + ByteBufferStreamWriter stream(encoded.get()); + serializer_->WriteValue(EncodableValue(method_call.method_name()), &stream); + if (method_call.arguments()) { + serializer_->WriteValue(*method_call.arguments(), &stream); + } else { + serializer_->WriteValue(EncodableValue(), &stream); + } + return encoded; +} + +std::unique_ptr> +StandardMethodCodec::EncodeSuccessEnvelopeInternal( + const EncodableValue* result) const { + auto encoded = std::make_unique>(); + ByteBufferStreamWriter stream(encoded.get()); + stream.WriteByte(0); + if (result) { + serializer_->WriteValue(*result, &stream); + } else { + serializer_->WriteValue(EncodableValue(), &stream); + } + return encoded; +} + +std::unique_ptr> +StandardMethodCodec::EncodeErrorEnvelopeInternal( + const std::string& error_code, + const std::string& error_message, + const EncodableValue* error_details) const { + auto encoded = std::make_unique>(); + ByteBufferStreamWriter stream(encoded.get()); + stream.WriteByte(1); + serializer_->WriteValue(EncodableValue(error_code), &stream); + if (error_message.empty()) { + serializer_->WriteValue(EncodableValue(), &stream); + } else { + serializer_->WriteValue(EncodableValue(error_message), &stream); + } + if (error_details) { + serializer_->WriteValue(*error_details, &stream); + } else { + serializer_->WriteValue(EncodableValue(), &stream); + } + return encoded; +} + +bool StandardMethodCodec::DecodeAndProcessResponseEnvelopeInternal( + const uint8_t* response, + size_t response_size, + MethodResult* result) const { + ByteBufferStreamReader stream(response, response_size); + uint8_t flag = stream.ReadByte(); + switch (flag) { + case 0: { + EncodableValue value = serializer_->ReadValue(&stream); + if (value.IsNull()) { + result->Success(); + } else { + result->Success(value); + } + return true; + } + case 1: { + EncodableValue code = serializer_->ReadValue(&stream); + EncodableValue message = serializer_->ReadValue(&stream); + EncodableValue details = serializer_->ReadValue(&stream); + const std::string& message_string = + message.IsNull() ? "" : std::get(message); + if (details.IsNull()) { + result->Error(std::get(code), message_string); + } else { + result->Error(std::get(code), message_string, details); + } + return true; + } + default: + return false; + } +} + +} // namespace flutter diff --git a/windows/flutter/ephemeral/cpp_client_wrapper/texture_registrar_impl.h b/windows/flutter/ephemeral/cpp_client_wrapper/texture_registrar_impl.h new file mode 100644 index 0000000..bd01839 --- /dev/null +++ b/windows/flutter/ephemeral/cpp_client_wrapper/texture_registrar_impl.h @@ -0,0 +1,44 @@ +// 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_COMMON_CLIENT_WRAPPER_TEXTURE_REGISTRAR_IMPL_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_TEXTURE_REGISTRAR_IMPL_H_ + +#include "include/flutter/texture_registrar.h" + +namespace flutter { + +// Wrapper around a FlutterDesktopTextureRegistrarRef that implements the +// TextureRegistrar API. +class TextureRegistrarImpl : public TextureRegistrar { + public: + explicit TextureRegistrarImpl( + FlutterDesktopTextureRegistrarRef texture_registrar_ref); + virtual ~TextureRegistrarImpl(); + + // Prevent copying. + TextureRegistrarImpl(TextureRegistrarImpl const&) = delete; + TextureRegistrarImpl& operator=(TextureRegistrarImpl const&) = delete; + + // |flutter::TextureRegistrar| + int64_t RegisterTexture(TextureVariant* texture) override; + + // |flutter::TextureRegistrar| + bool MarkTextureFrameAvailable(int64_t texture_id) override; + + // |flutter::TextureRegistrar| + void UnregisterTexture(int64_t texture_id, + std::function callback) override; + + // |flutter::TextureRegistrar| + bool UnregisterTexture(int64_t texture_id) override; + + private: + // Handle for interacting with the C API. + FlutterDesktopTextureRegistrarRef texture_registrar_ref_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_CLIENT_WRAPPER_TEXTURE_REGISTRAR_IMPL_H_ diff --git a/windows/flutter/ephemeral/flutter_export.h b/windows/flutter/ephemeral/flutter_export.h new file mode 100644 index 0000000..d71b3fb --- /dev/null +++ b/windows/flutter/ephemeral/flutter_export.h @@ -0,0 +1,28 @@ +// 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_COMMON_PUBLIC_FLUTTER_EXPORT_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_EXPORT_H_ + +#ifdef FLUTTER_DESKTOP_LIBRARY + +// Add visibility/export annotations when building the library. +#ifdef _WIN32 +#define FLUTTER_EXPORT __declspec(dllexport) +#else +#define FLUTTER_EXPORT __attribute__((visibility("default"))) +#endif + +#else // FLUTTER_DESKTOP_LIBRARY + +// Add import annotations when consuming the library. +#ifdef _WIN32 +#define FLUTTER_EXPORT __declspec(dllimport) +#else +#define FLUTTER_EXPORT +#endif + +#endif // FLUTTER_DESKTOP_LIBRARY + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_EXPORT_H_ diff --git a/windows/flutter/ephemeral/flutter_messenger.h b/windows/flutter/ephemeral/flutter_messenger.h new file mode 100644 index 0000000..b364a57 --- /dev/null +++ b/windows/flutter/ephemeral/flutter_messenger.h @@ -0,0 +1,144 @@ +// 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_COMMON_PUBLIC_FLUTTER_MESSENGER_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_MESSENGER_H_ + +#include +#include +#include + +#include "flutter_export.h" + +#if defined(__cplusplus) +extern "C" { +#endif // defined(__cplusplus) + +// Opaque reference to a Flutter engine messenger. +typedef struct FlutterDesktopMessenger* FlutterDesktopMessengerRef; + +// Opaque handle for tracking responses to messages. +typedef struct _FlutterPlatformMessageResponseHandle + FlutterDesktopMessageResponseHandle; + +// The callback expected as a response of a binary message. +typedef void (*FlutterDesktopBinaryReply)(const uint8_t* data, + size_t data_size, + void* user_data); + +// A message received from Flutter. +typedef struct { + // Size of this struct as created by Flutter. + size_t struct_size; + // The name of the channel used for this message. + const char* channel; + // The raw message data. + const uint8_t* message; + // The length of |message|. + size_t message_size; + // The response handle. If non-null, the receiver of this message must call + // FlutterDesktopSendMessageResponse exactly once with this handle. + const FlutterDesktopMessageResponseHandle* response_handle; +} FlutterDesktopMessage; + +// Function pointer type for message handler callback registration. +// +// The user data will be whatever was passed to FlutterDesktopSetMessageHandler +// for the channel the message is received on. +typedef void (*FlutterDesktopMessageCallback)( + FlutterDesktopMessengerRef /* messenger */, + const FlutterDesktopMessage* /* message*/, + void* /* user data */); + +// Sends a binary message to the Flutter side on the specified channel. +FLUTTER_EXPORT bool FlutterDesktopMessengerSend( + FlutterDesktopMessengerRef messenger, + const char* channel, + const uint8_t* message, + const size_t message_size); + +// Sends a binary message to the Flutter side on the specified channel. +// The |reply| callback will be executed when a response is received. +FLUTTER_EXPORT bool FlutterDesktopMessengerSendWithReply( + FlutterDesktopMessengerRef messenger, + const char* channel, + const uint8_t* message, + const size_t message_size, + const FlutterDesktopBinaryReply reply, + void* user_data); + +// Sends a reply to a FlutterDesktopMessage for the given response handle. +// +// Once this has been called, |handle| is invalid and must not be used again. +FLUTTER_EXPORT void FlutterDesktopMessengerSendResponse( + FlutterDesktopMessengerRef messenger, + const FlutterDesktopMessageResponseHandle* handle, + const uint8_t* data, + size_t data_length); + +// Registers a callback function for incoming binary messages from the Flutter +// side on the specified channel. +// +// Replaces any existing callback. Provide a null handler to unregister the +// existing callback. +// +// If |user_data| is provided, it will be passed in |callback| calls. +FLUTTER_EXPORT void FlutterDesktopMessengerSetCallback( + FlutterDesktopMessengerRef messenger, + const char* channel, + FlutterDesktopMessageCallback callback, + void* user_data); + +// Increments the reference count for the |messenger|. +// +// Operation is thread-safe. +// +// See also: |FlutterDesktopMessengerRelease| +FLUTTER_EXPORT FlutterDesktopMessengerRef +FlutterDesktopMessengerAddRef(FlutterDesktopMessengerRef messenger); + +// Decrements the reference count for the |messenger|. +// +// Operation is thread-safe. +// +// See also: |FlutterDesktopMessengerAddRef| +FLUTTER_EXPORT void FlutterDesktopMessengerRelease( + FlutterDesktopMessengerRef messenger); + +// Returns `true` if the |FlutterDesktopMessengerRef| still references a running +// engine. +// +// This check should be made inside of a |FlutterDesktopMessengerLock| and +// before any other calls are made to the FlutterDesktopMessengerRef when using +// it from a thread other than the platform thread. +FLUTTER_EXPORT bool FlutterDesktopMessengerIsAvailable( + FlutterDesktopMessengerRef messenger); + +// Locks the `FlutterDesktopMessengerRef` ensuring that +// |FlutterDesktopMessengerIsAvailable| does not change while locked. +// +// All calls to the FlutterDesktopMessengerRef from threads other than the +// platform thread should happen inside of a lock. +// +// Operation is thread-safe. +// +// Returns the |messenger| value. +// +// See also: |FlutterDesktopMessengerUnlock| +FLUTTER_EXPORT FlutterDesktopMessengerRef +FlutterDesktopMessengerLock(FlutterDesktopMessengerRef messenger); + +// Unlocks the `FlutterDesktopMessengerRef`. +// +// Operation is thread-safe. +// +// See also: |FlutterDesktopMessengerLock| +FLUTTER_EXPORT void FlutterDesktopMessengerUnlock( + FlutterDesktopMessengerRef messenger); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_MESSENGER_H_ diff --git a/windows/flutter/ephemeral/flutter_plugin_registrar.h b/windows/flutter/ephemeral/flutter_plugin_registrar.h new file mode 100644 index 0000000..b084706 --- /dev/null +++ b/windows/flutter/ephemeral/flutter_plugin_registrar.h @@ -0,0 +1,45 @@ +// 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_COMMON_PUBLIC_FLUTTER_PLUGIN_REGISTRAR_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_PLUGIN_REGISTRAR_H_ + +#include +#include + +#include "flutter_export.h" +#include "flutter_messenger.h" +#include "flutter_texture_registrar.h" + +#if defined(__cplusplus) +extern "C" { +#endif // defined(__cplusplus) + +// Opaque reference to a plugin registrar. +typedef struct FlutterDesktopPluginRegistrar* FlutterDesktopPluginRegistrarRef; + +// Function pointer type for registrar destruction callback. +typedef void (*FlutterDesktopOnPluginRegistrarDestroyed)( + FlutterDesktopPluginRegistrarRef); + +// Returns the engine messenger associated with this registrar. +FLUTTER_EXPORT FlutterDesktopMessengerRef +FlutterDesktopPluginRegistrarGetMessenger( + FlutterDesktopPluginRegistrarRef registrar); + +// Returns the texture registrar associated with this registrar. +FLUTTER_EXPORT FlutterDesktopTextureRegistrarRef +FlutterDesktopRegistrarGetTextureRegistrar( + FlutterDesktopPluginRegistrarRef registrar); + +// Registers a callback to be called when the plugin registrar is destroyed. +FLUTTER_EXPORT void FlutterDesktopPluginRegistrarSetDestructionHandler( + FlutterDesktopPluginRegistrarRef registrar, + FlutterDesktopOnPluginRegistrarDestroyed callback); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_PLUGIN_REGISTRAR_H_ diff --git a/windows/flutter/ephemeral/flutter_texture_registrar.h b/windows/flutter/ephemeral/flutter_texture_registrar.h new file mode 100644 index 0000000..9979e9a --- /dev/null +++ b/windows/flutter/ephemeral/flutter_texture_registrar.h @@ -0,0 +1,187 @@ +// 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_COMMON_PUBLIC_FLUTTER_TEXTURE_REGISTRAR_H_ +#define FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_TEXTURE_REGISTRAR_H_ + +#include +#include + +#include "flutter_export.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +struct FlutterDesktopTextureRegistrar; +// Opaque reference to a texture registrar. +typedef struct FlutterDesktopTextureRegistrar* + FlutterDesktopTextureRegistrarRef; + +// Possible values for the type specified in FlutterDesktopTextureInfo. +// Additional types may be added in the future. +typedef enum { + // A Pixel buffer-based texture. + kFlutterDesktopPixelBufferTexture, + // A platform-specific GPU surface-backed texture. + kFlutterDesktopGpuSurfaceTexture +} FlutterDesktopTextureType; + +// Supported GPU surface types. +typedef enum { + // Uninitialized. + kFlutterDesktopGpuSurfaceTypeNone, + // A DXGI shared texture handle (Windows only). + // See + // https://docs.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiresource-getsharedhandle + kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle, + // A |ID3D11Texture2D| (Windows only). + kFlutterDesktopGpuSurfaceTypeD3d11Texture2D +} FlutterDesktopGpuSurfaceType; + +// Supported pixel formats. +typedef enum { + // Uninitialized. + kFlutterDesktopPixelFormatNone, + // Represents a 32-bit RGBA color format with 8 bits each for red, green, blue + // and alpha. + kFlutterDesktopPixelFormatRGBA8888, + // Represents a 32-bit BGRA color format with 8 bits each for blue, green, red + // and alpha. + kFlutterDesktopPixelFormatBGRA8888 +} FlutterDesktopPixelFormat; + +// An image buffer object. +typedef struct { + // The pixel data buffer. + const uint8_t* buffer; + // Width of the pixel buffer. + size_t width; + // Height of the pixel buffer. + size_t height; + // An optional callback that gets invoked when the |buffer| can be released. + void (*release_callback)(void* release_context); + // Opaque data passed to |release_callback|. + void* release_context; +} FlutterDesktopPixelBuffer; + +// A GPU surface descriptor. +typedef struct { + // The size of this struct. Must be + // sizeof(FlutterDesktopGpuSurfaceDescriptor). + size_t struct_size; + // The surface handle. The expected type depends on the + // |FlutterDesktopGpuSurfaceType|. + // + // Provide a |ID3D11Texture2D*| when using + // |kFlutterDesktopGpuSurfaceTypeD3d11Texture2D| or a |HANDLE| when using + // |kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle|. + // + // The referenced resource needs to stay valid until it has been opened by + // Flutter. Consider incrementing the resource's reference count in the + // |FlutterDesktopGpuSurfaceTextureCallback| and registering a + // |release_callback| for decrementing the reference count once it has been + // opened. + void* handle; + // The physical width. + size_t width; + // The physical height. + size_t height; + // The visible width. + // It might be less or equal to the physical |width|. + size_t visible_width; + // The visible height. + // It might be less or equal to the physical |height|. + size_t visible_height; + // The pixel format which might be optional depending on the surface type. + FlutterDesktopPixelFormat format; + // An optional callback that gets invoked when the |handle| has been opened. + void (*release_callback)(void* release_context); + // Opaque data passed to |release_callback|. + void* release_context; +} FlutterDesktopGpuSurfaceDescriptor; + +// The pixel buffer copy callback definition provided to +// the Flutter engine to copy the texture. +// It is invoked with the intended surface size specified by |width| and +// |height| and the |user_data| held by +// |FlutterDesktopPixelBufferTextureConfig|. +// +// As this is usually called from the render thread, the callee must take +// care of proper synchronization. It also needs to be ensured that the +// returned |FlutterDesktopPixelBuffer| isn't released prior to unregistering +// the corresponding texture. +typedef const FlutterDesktopPixelBuffer* ( + *FlutterDesktopPixelBufferTextureCallback)(size_t width, + size_t height, + void* user_data); + +// The GPU surface callback definition provided to the Flutter engine to obtain +// the surface. It is invoked with the intended surface size specified by +// |width| and |height| and the |user_data| held by +// |FlutterDesktopGpuSurfaceTextureConfig|. +typedef const FlutterDesktopGpuSurfaceDescriptor* ( + *FlutterDesktopGpuSurfaceTextureCallback)(size_t width, + size_t height, + void* user_data); + +// An object used to configure pixel buffer textures. +typedef struct { + // The callback used by the engine to copy the pixel buffer object. + FlutterDesktopPixelBufferTextureCallback callback; + // Opaque data that will get passed to the provided |callback|. + void* user_data; +} FlutterDesktopPixelBufferTextureConfig; + +// An object used to configure GPU-surface textures. +typedef struct { + // The size of this struct. Must be + // sizeof(FlutterDesktopGpuSurfaceTextureConfig). + size_t struct_size; + // The concrete surface type (e.g. + // |kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle|) + FlutterDesktopGpuSurfaceType type; + // The callback used by the engine to obtain the surface descriptor. + FlutterDesktopGpuSurfaceTextureCallback callback; + // Opaque data that will get passed to the provided |callback|. + void* user_data; +} FlutterDesktopGpuSurfaceTextureConfig; + +typedef struct { + FlutterDesktopTextureType type; + union { + FlutterDesktopPixelBufferTextureConfig pixel_buffer_config; + FlutterDesktopGpuSurfaceTextureConfig gpu_surface_config; + }; +} FlutterDesktopTextureInfo; + +// Registers a new texture with the Flutter engine and returns the texture ID. +// This function can be called from any thread. +FLUTTER_EXPORT int64_t FlutterDesktopTextureRegistrarRegisterExternalTexture( + FlutterDesktopTextureRegistrarRef texture_registrar, + const FlutterDesktopTextureInfo* info); + +// Asynchronously unregisters the texture identified by |texture_id| from the +// Flutter engine. +// An optional |callback| gets invoked upon completion. +// This function can be called from any thread. +FLUTTER_EXPORT void FlutterDesktopTextureRegistrarUnregisterExternalTexture( + FlutterDesktopTextureRegistrarRef texture_registrar, + int64_t texture_id, + void (*callback)(void* user_data), + void* user_data); + +// Marks that a new texture frame is available for a given |texture_id|. +// Returns true on success or false if the specified texture doesn't exist. +// This function can be called from any thread. +FLUTTER_EXPORT bool +FlutterDesktopTextureRegistrarMarkExternalTextureFrameAvailable( + FlutterDesktopTextureRegistrarRef texture_registrar, + int64_t texture_id); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // FLUTTER_SHELL_PLATFORM_COMMON_PUBLIC_FLUTTER_TEXTURE_REGISTRAR_H_ diff --git a/windows/flutter/ephemeral/flutter_windows.dll b/windows/flutter/ephemeral/flutter_windows.dll new file mode 100644 index 0000000..cf8076e Binary files /dev/null and b/windows/flutter/ephemeral/flutter_windows.dll differ diff --git a/windows/flutter/ephemeral/flutter_windows.dll.exp b/windows/flutter/ephemeral/flutter_windows.dll.exp new file mode 100644 index 0000000..f0c9caa Binary files /dev/null and b/windows/flutter/ephemeral/flutter_windows.dll.exp differ diff --git a/windows/flutter/ephemeral/flutter_windows.dll.lib b/windows/flutter/ephemeral/flutter_windows.dll.lib new file mode 100644 index 0000000..4bc5049 Binary files /dev/null and b/windows/flutter/ephemeral/flutter_windows.dll.lib differ diff --git a/windows/flutter/ephemeral/flutter_windows.h b/windows/flutter/ephemeral/flutter_windows.h new file mode 100644 index 0000000..2a32ef4 --- /dev/null +++ b/windows/flutter/ephemeral/flutter_windows.h @@ -0,0 +1,332 @@ +// 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_PUBLIC_FLUTTER_WINDOWS_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_PUBLIC_FLUTTER_WINDOWS_H_ + +#include +#include +#include +#include + +#include "flutter_export.h" +#include "flutter_messenger.h" +#include "flutter_plugin_registrar.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef void (*VoidCallback)(void* /* user data */); + +// Opaque reference to a Flutter view controller. +struct FlutterDesktopViewController; +typedef struct FlutterDesktopViewController* FlutterDesktopViewControllerRef; + +// Opaque reference to a Flutter window. +struct FlutterDesktopView; +typedef struct FlutterDesktopView* FlutterDesktopViewRef; + +// Opaque reference to a Flutter engine instance. +struct FlutterDesktopEngine; +typedef struct FlutterDesktopEngine* FlutterDesktopEngineRef; + +// The unique identifier for a view. +typedef int64_t FlutterDesktopViewId; + +// Configures how the Flutter engine selects a GPU. +typedef enum { + // No preference. + NoPreference, + // Prefer energy efficiency over performance, such as an integrated GPU. + // This falls back to a high performance GPU if no low power GPU is + // available. + LowPowerPreference, +} FlutterDesktopGpuPreference; + +// Configures the thread policy for running the UI isolate. +typedef enum { + // Default value. Currently will run the UI isolate on separate thread, + // later will be changed to running the UI isolate on platform thread. + Default, + // Run the UI isolate on platform thread. + RunOnPlatformThread, + // Run the UI isolate on a separate thread. + RunOnSeparateThread, +} FlutterDesktopUIThreadPolicy; + +// Properties for configuring a Flutter engine instance. +typedef struct { + // The path to the flutter_assets folder for the application to be run. + // This can either be an absolute path or a path relative to the directory + // containing the executable. + const wchar_t* assets_path; + + // The path to the icudtl.dat file for the version of Flutter you are using. + // This can either be an absolute path or a path relative to the directory + // containing the executable. + const wchar_t* icu_data_path; + + // The path to the AOT library file for your application, if any. + // This can either be an absolute path or a path relative to the directory + // containing the executable. This can be nullptr for a non-AOT build, as + // it will be ignored in that case. + const wchar_t* aot_library_path; + + // The name of the top-level Dart entrypoint function. If null or the empty + // string, 'main' is assumed. If a custom entrypoint is used, this parameter + // must specifiy the name of a top-level function in the same Dart library as + // the app's main() function. Custom entrypoint functions must be decorated + // with `@pragma('vm:entry-point')` to ensure the method is not tree-shaken + // by the Dart compiler. + const char* dart_entrypoint; + + // Number of elements in the array passed in as dart_entrypoint_argv. + int dart_entrypoint_argc; + + // Array of Dart entrypoint arguments. This is deep copied during the call + // to FlutterDesktopEngineCreate. + const char** dart_entrypoint_argv; + + // GPU choice preference + FlutterDesktopGpuPreference gpu_preference; + + // Policy for the thread that runs UI isolate. + FlutterDesktopUIThreadPolicy ui_thread_policy; +} FlutterDesktopEngineProperties; + +// ========== View Controller ========== + +// Creates a view that hosts and displays the given engine instance. +// +// This takes ownership of |engine|, so FlutterDesktopEngineDestroy should no +// longer be called on it, as it will be called internally when the view +// controller is destroyed. If creating the view controller fails, the engine +// will be destroyed immediately. +// +// If |engine| is not already running, the view controller will start running +// it automatically before displaying the window. +// +// The caller owns the returned reference, and is responsible for calling +// FlutterDesktopViewControllerDestroy. Returns a null pointer in the event of +// an error. +// +// The Win32 implementation accepts width, height with view hookup explicitly +// performed using the caller using HWND parenting. +FLUTTER_EXPORT FlutterDesktopViewControllerRef +FlutterDesktopViewControllerCreate(int width, + int height, + FlutterDesktopEngineRef engine); + +// Shuts down the engine instance associated with |controller|, and cleans up +// associated state. +// +// |controller| is no longer valid after this call. +FLUTTER_EXPORT void FlutterDesktopViewControllerDestroy( + FlutterDesktopViewControllerRef controller); + +// Returns the view controller's view ID. +FLUTTER_EXPORT FlutterDesktopViewId FlutterDesktopViewControllerGetViewId( + FlutterDesktopViewControllerRef view_controller); + +// Returns the handle for the engine running in FlutterDesktopViewControllerRef. +// +// Its lifetime is the same as the |controller|'s. +FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine( + FlutterDesktopViewControllerRef controller); + +// Returns the view managed by the given controller. +FLUTTER_EXPORT FlutterDesktopViewRef +FlutterDesktopViewControllerGetView(FlutterDesktopViewControllerRef controller); + +// Requests new frame from the engine and repaints the view. +FLUTTER_EXPORT void FlutterDesktopViewControllerForceRedraw( + FlutterDesktopViewControllerRef controller); + +// Allows the Flutter engine and any interested plugins an opportunity to +// handle the given message. +// +// If the WindowProc was handled and further handling should stop, this returns +// true and |result| will be populated. |result| is not set if returning false. +FLUTTER_EXPORT bool FlutterDesktopViewControllerHandleTopLevelWindowProc( + FlutterDesktopViewControllerRef controller, + HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam, + LRESULT* result); + +// ========== Engine ========== + +// Creates a Flutter engine with the given properties. +// +// The caller owns the returned reference, and is responsible for calling +// FlutterDesktopEngineDestroy. The lifetime of |engine_properties| is required +// to extend only until the end of this call. +FLUTTER_EXPORT FlutterDesktopEngineRef FlutterDesktopEngineCreate( + const FlutterDesktopEngineProperties* engine_properties); + +// Shuts down and destroys the given engine instance. Returns true if the +// shutdown was successful, or if the engine was not running. +// +// |engine| is no longer valid after this call. +FLUTTER_EXPORT bool FlutterDesktopEngineDestroy(FlutterDesktopEngineRef engine); + +// Starts running the given engine instance. +// +// The entry_point parameter is deprecated but preserved for +// backward-compatibility. If desired, a custom Dart entrypoint function can be +// set in the dart_entrypoint field of the FlutterDesktopEngineProperties +// struct passed to FlutterDesktopEngineCreate. +// +// If specified, entry_point must be the name of a top-level function from the +// same Dart library that contains the app's main() function, and must be +// decorated with `@pragma(vm:entry-point)` to ensure the method is not +// tree-shaken by the Dart compiler. If conflicting non-null values are passed +// to this function and via the FlutterDesktopEngineProperties struct, the run +// will fail. +// +// Returns false if running the engine failed. +FLUTTER_EXPORT bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine, + const char* entry_point); + +// DEPRECATED: This is no longer necessary to call, Flutter will take care of +// processing engine messages transparently through DispatchMessage. +// +// Processes any pending events in the Flutter engine, and returns the +// number of nanoseconds until the next scheduled event (or max, if none). +// +// This should be called on every run of the application-level runloop, and +// a wait for native events in the runloop should never be longer than the +// last return value from this function. +FLUTTER_EXPORT uint64_t +FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine); + +FLUTTER_EXPORT void FlutterDesktopEngineReloadSystemFonts( + FlutterDesktopEngineRef engine); + +// Returns the plugin registrar handle for the plugin with the given name. +// +// The name must be unique across the application. +FLUTTER_EXPORT FlutterDesktopPluginRegistrarRef +FlutterDesktopEngineGetPluginRegistrar(FlutterDesktopEngineRef engine, + const char* plugin_name); + +// Returns the messenger associated with the engine. +// +// This does not provide an owning reference, so should *not* be balanced with a +// call to |FlutterDesktopMessengerRelease|. +// +// Callers should use |FlutterDesktopMessengerAddRef| if the returned pointer +// will potentially outlive 'engine', such as when passing it to another thread. +FLUTTER_EXPORT FlutterDesktopMessengerRef +FlutterDesktopEngineGetMessenger(FlutterDesktopEngineRef engine); + +// Returns the texture registrar associated with the engine. +FLUTTER_EXPORT FlutterDesktopTextureRegistrarRef +FlutterDesktopEngineGetTextureRegistrar(FlutterDesktopEngineRef engine); + +// Schedule a callback to be called after the next frame is drawn. +// +// This must be called from the platform thread. The callback is executed only +// once on the platform thread. +FLUTTER_EXPORT void FlutterDesktopEngineSetNextFrameCallback( + FlutterDesktopEngineRef engine, + VoidCallback callback, + void* user_data); + +// ========== View ========== + +// Returns the backing HWND for manipulation in host application. +FLUTTER_EXPORT HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view); + +// Returns the DXGI adapter used for rendering or nullptr in case of error. +FLUTTER_EXPORT IDXGIAdapter* FlutterDesktopViewGetGraphicsAdapter( + FlutterDesktopViewRef view); + +// Called to pass an external window message to the engine for lifecycle +// state updates. Non-Flutter windows must call this method in their WndProc +// in order to be included in the logic for application lifecycle state +// updates. Returns a result if the message should be consumed. +FLUTTER_EXPORT bool FlutterDesktopEngineProcessExternalWindowMessage( + FlutterDesktopEngineRef engine, + HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam, + LRESULT* result); + +// ========== Plugin Registrar (extensions) ========== +// These are Windows-specific extensions to flutter_plugin_registrar.h + +// Function pointer type for top level WindowProc delegate registration. +// +// The user data will be whatever was passed to +// FlutterDesktopRegisterTopLevelWindowProcHandler. +// +// Implementations should populate |result| and return true if the WindowProc +// was handled and further handling should stop. |result| is ignored if the +// function returns false. +typedef bool (*FlutterDesktopWindowProcCallback)(HWND /* hwnd */, + UINT /* uMsg */, + WPARAM /*wParam*/, + LPARAM /* lParam*/, + void* /* user data */, + LRESULT* result); + +// Returns the implicit view associated with this registrar's engine instance, +// or null if there is no implicit view. +// +// See: +// https://api.flutter.dev/flutter/dart-ui/PlatformDispatcher/implicitView.html +// +// DEPRECATED: Use |FlutterDesktopPluginRegistrarGetViewById| instead. +FLUTTER_EXPORT FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView( + FlutterDesktopPluginRegistrarRef registrar); + +// Returns the view associated with the registrar's engine instance, or null if +// the view does not exist. +FLUTTER_EXPORT FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetViewById( + FlutterDesktopPluginRegistrarRef registrar, + FlutterDesktopViewId view_id); + +FLUTTER_EXPORT void +FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate( + FlutterDesktopPluginRegistrarRef registrar, + FlutterDesktopWindowProcCallback delegate, + void* user_data); + +FLUTTER_EXPORT void +FlutterDesktopPluginRegistrarUnregisterTopLevelWindowProcDelegate( + FlutterDesktopPluginRegistrarRef registrar, + FlutterDesktopWindowProcCallback delegate); + +// ========== Freestanding Utilities ========== + +// Gets the DPI for a given |hwnd|, depending on the supported APIs per +// windows version and DPI awareness mode. If nullptr is passed, returns the DPI +// of the primary monitor. +// +// This uses the same logic and fallback for older Windows versions that is used +// internally by Flutter to determine the DPI to use for displaying Flutter +// content, so should be used by any code (e.g., in plugins) that translates +// between Windows and Dart sizes/offsets. +FLUTTER_EXPORT UINT FlutterDesktopGetDpiForHWND(HWND hwnd); + +// Gets the DPI for a given |monitor|. If the API is not available, a default +// DPI of 96 is returned. +// +// See FlutterDesktopGetDpiForHWND for more information. +FLUTTER_EXPORT UINT FlutterDesktopGetDpiForMonitor(HMONITOR monitor); + +// Reopens stdout and stderr and resysncs the standard library output streams. +// Should be called if output is being directed somewhere in the runner process +// (e.g., after an AllocConsole call). +FLUTTER_EXPORT void FlutterDesktopResyncOutputStreams(); + +#if defined(__cplusplus) +} // extern "C" +#endif + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_PUBLIC_FLUTTER_WINDOWS_H_ diff --git a/windows/flutter/ephemeral/generated_config.cmake b/windows/flutter/ephemeral/generated_config.cmake new file mode 100644 index 0000000..feee5b9 --- /dev/null +++ b/windows/flutter/ephemeral/generated_config.cmake @@ -0,0 +1,24 @@ +# Generated code do not commit. +file(TO_CMAKE_PATH "C:\\flutter" FLUTTER_ROOT) +file(TO_CMAKE_PATH "C:\\Users\\Jacques\\Git\\xtremflow" PROJECT_DIR) + +set(FLUTTER_VERSION "1.0.0+1" PARENT_SCOPE) +set(FLUTTER_VERSION_MAJOR 1 PARENT_SCOPE) +set(FLUTTER_VERSION_MINOR 0 PARENT_SCOPE) +set(FLUTTER_VERSION_PATCH 0 PARENT_SCOPE) +set(FLUTTER_VERSION_BUILD 1 PARENT_SCOPE) + +# Environment variables to pass to tool_backend.sh +list(APPEND FLUTTER_TOOL_ENVIRONMENT + "FLUTTER_ROOT=C:\\flutter" + "PROJECT_DIR=C:\\Users\\Jacques\\Git\\xtremflow" + "FLUTTER_ROOT=C:\\flutter" + "FLUTTER_EPHEMERAL_DIR=C:\\Users\\Jacques\\Git\\xtremflow\\windows\\flutter\\ephemeral" + "PROJECT_DIR=C:\\Users\\Jacques\\Git\\xtremflow" + "FLUTTER_TARGET=lib\\main.dart" + "DART_DEFINES=RkxVVFRFUl9WRVJTSU9OPTMuMzguNQ==,RkxVVFRFUl9DSEFOTkVMPXN0YWJsZQ==,RkxVVFRFUl9HSVRfVVJMPWh0dHBzOi8vZ2l0aHViLmNvbS9mbHV0dGVyL2ZsdXR0ZXIuZ2l0,RkxVVFRFUl9GUkFNRVdPUktfUkVWSVNJT049ZjZmZjE1MjlmZA==,RkxVVFRFUl9FTkdJTkVfUkVWSVNJT049MTUyN2FlMGVjNQ==,RkxVVFRFUl9EQVJUX1ZFUlNJT049My4xMC40" + "DART_OBFUSCATION=false" + "TRACK_WIDGET_CREATION=true" + "TREE_SHAKE_ICONS=true" + "PACKAGE_CONFIG=C:\\Users\\Jacques\\Git\\xtremflow\\.dart_tool\\package_config.json" +) diff --git a/windows/flutter/ephemeral/icudtl.dat b/windows/flutter/ephemeral/icudtl.dat new file mode 100644 index 0000000..17e5b2a Binary files /dev/null and b/windows/flutter/ephemeral/icudtl.dat differ