Files
webview_cef/windows/webview_cef_plugin.cpp
2024-01-11 19:41:20 +08:00

253 lines
9.5 KiB
C++

#include "webview_cef_plugin.h"
// This must be included before many other Windows headers.
#include <windows.h>
// For getPlatformVersion; remove unless needed for your plugin implementation.
#include <VersionHelpers.h>
#include <flutter/method_channel.h>
#include <flutter/plugin_registrar_windows.h>
#include <flutter/standard_method_codec.h>
#include <memory>
#include <thread>
#include <iostream>
#include <mutex>
namespace webview_cef {
int64_t texture_id;
FlutterDesktopTextureRegistrarRef texture_registrar;
std::shared_ptr<FlutterDesktopPixelBuffer> pixel_buffer;
std::unique_ptr<uint8_t> backing_pixel_buffer;
std::mutex buffer_mutex_;
std::unique_ptr<flutter::TextureVariant> m_texture = std::make_unique<flutter::TextureVariant>(flutter::PixelBufferTexture([](size_t width, size_t height) -> const FlutterDesktopPixelBuffer* {
buffer_mutex_.lock();
auto buffer = pixel_buffer.get();
// Only lock the mutex if the buffer is not null
// (to ensure the release callback gets called)
if (!buffer) {
buffer_mutex_.unlock();
}
return buffer;
}));
std::unique_ptr<
flutter::MethodChannel<flutter::EncodableValue>,
std::default_delete<flutter::MethodChannel<flutter::EncodableValue>>>
channel = nullptr;
static flutter::EncodableValue encode_wvalue_to_flvalue(WValue* args) {
WValueType type = webview_value_get_type(args);
switch(type){
case Webview_Value_Type_Bool:
return flutter::EncodableValue(webview_value_get_bool(args));
case Webview_Value_Type_Int:
return flutter::EncodableValue(webview_value_get_int(args));
case Webview_Value_Type_Float:
return flutter::EncodableValue(webview_value_get_float(args));
case Webview_Value_Type_Double:
return flutter::EncodableValue(webview_value_get_double(args));
case Webview_Value_Type_String:
return flutter::EncodableValue(webview_value_get_string(args));
case Webview_Value_Type_Uint8_List:
return flutter::EncodableValue(webview_value_get_uint8_list(args));
case Webview_Value_Type_Int32_List:
return flutter::EncodableValue(webview_value_get_int32_list(args));
case Webview_Value_Type_Int64_List:
return flutter::EncodableValue(webview_value_get_int64_list(args));
case Webview_Value_Type_Float_List:
return flutter::EncodableValue(webview_value_get_float_list(args));
case Webview_Value_Type_Double_List:
return flutter::EncodableValue(webview_value_get_double_list(args));
case Webview_Value_Type_List:
{
flutter::EncodableList ret;
size_t len = webview_value_get_len(args);
for (size_t i = 0; i < len; i++) {
ret.push_back(encode_wvalue_to_flvalue(webview_value_get_list_value(args, i)));
}
return ret;
}
case Webview_Value_Type_Map:
{
flutter::EncodableMap ret;
size_t len = webview_value_get_len(args);
for (size_t i = 0; i < len; i++) {
ret[encode_wvalue_to_flvalue(webview_value_get_key(args, i))] = encode_wvalue_to_flvalue(webview_value_get_value(args, i));
}
return ret;
}
default:
return flutter::EncodableValue(nullptr);
}
}
static WValue *encode_flvalue_to_wvalue(flutter::EncodableValue* args) {
size_t index = args->index();
if (index == 1) {
return webview_value_new_bool(*std::get_if<bool>(args));
}
else if (index == 2 || index == 3) {
return webview_value_new_int(*std::get_if<int32_t>(args));
}
else if (index == 4) {
return webview_value_new_double(*std::get_if<double>(args));
}
else if (index == 5) {
return webview_value_new_string((*std::get_if<std::string>(args)).c_str());
}
else if (index == 6) {
auto list = *std::get_if<std::vector<uint8_t>>(args);
return webview_value_new_uint8_list(list.data(), list.size());
}
else if (index == 7) {
auto list = *std::get_if<std::vector<int32_t>>(args);
return webview_value_new_int32_list(list.data(), list.size());
}
else if (index == 8) {
auto list = *std::get_if<std::vector<int64_t>>(args);
return webview_value_new_int64_list(list.data(), list.size());
}
else if (index == 9) {
auto list = *std::get_if<std::vector<double>>(args);
return webview_value_new_double_list(list.data(), list.size());
}
else if (index == 10) {
WValue * ret = webview_value_new_list();
flutter::EncodableList list = *std::get_if<flutter::EncodableList>(args);
for (size_t i = 0; i < list.size(); i++) {
WValue *value = encode_flvalue_to_wvalue(&list[i]);
webview_value_append(ret, value);
webview_value_unref(value);
}
return ret;
}
else if (index == 11) {
WValue * ret = webview_value_new_map();
flutter::EncodableMap map = *std::get_if<flutter::EncodableMap>(args);
for (flutter::EncodableMap::iterator it = map.begin(); it != map.end(); it++)
{
WValue *key = encode_flvalue_to_wvalue(const_cast<flutter::EncodableValue *>(&it->first));
WValue *value = encode_flvalue_to_wvalue(const_cast<flutter::EncodableValue*>(&it->second));
webview_value_set(ret, key, value);
webview_value_unref(key);
webview_value_unref(value);
}
return ret;
}
else if (index == 12) {
return nullptr;
}
else if (index == 13) {
auto list = *std::get_if<std::vector<float>>(args);
return webview_value_new_float_list(list.data(), list.size());
}
return nullptr;
}
// static
void WebviewCefPlugin::RegisterWithRegistrar(FlutterDesktopPluginRegistrarRef registrar) {
texture_registrar = FlutterDesktopRegistrarGetTextureRegistrar(registrar);
flutter::PluginRegistrarWindows* window_registrar = flutter::PluginRegistrarManager::GetInstance()
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar);
channel =
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
window_registrar->messenger(), "webview_cef",
&flutter::StandardMethodCodec::GetInstance());
auto plugin = std::make_unique<WebviewCefPlugin>();
channel->SetMethodCallHandler(
[plugin_pointer = plugin.get()](const auto& call, auto result) {
plugin_pointer->HandleMethodCall(call, std::move(result));
});
DWORD threadId = GetCurrentThreadId();
auto invoke = [=](std::string method, WValue* arguments) {
flutter::EncodableValue *methodValue = new flutter::EncodableValue(method);
flutter::EncodableValue *args = new flutter::EncodableValue(encode_wvalue_to_flvalue(arguments));
PostThreadMessage(threadId, WM_USER + 1, WPARAM(methodValue), LPARAM(args));
};
webview_cef::setInvokeMethodFunc(invoke);
window_registrar->AddPlugin(std::move(plugin));
}
WebviewCefPlugin::WebviewCefPlugin() {}
WebviewCefPlugin::~WebviewCefPlugin() {}
void WebviewCefPlugin::HandleMethodCall(
const flutter::MethodCall<flutter::EncodableValue>& method_call,
std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
if (method_call.method_name().compare("init") == 0) {
FlutterDesktopTextureInfo info = {};
info.type = kFlutterDesktopPixelBufferTexture;
info.pixel_buffer_config.user_data = std::get_if<flutter::PixelBufferTexture>(m_texture.get());
info.pixel_buffer_config.callback = [](size_t width, size_t height, void* user_data) -> const FlutterDesktopPixelBuffer* {
auto texture = static_cast<flutter::PixelBufferTexture*>(user_data);
return texture->CopyPixelBuffer(width, height);
};
texture_id = FlutterDesktopTextureRegistrarRegisterExternalTexture(texture_registrar, &info);
auto callback = [=](const void* buffer, int32_t width, int32_t height) {
const std::lock_guard<std::mutex> lock(buffer_mutex_);
if (!pixel_buffer.get() || pixel_buffer.get()->width != width || pixel_buffer.get()->height != height) {
if (!pixel_buffer.get()) {
pixel_buffer = std::make_unique<FlutterDesktopPixelBuffer>();
pixel_buffer->release_context = &buffer_mutex_;
// Gets invoked after the FlutterDesktopPixelBuffer's
// backing buffer has been uploaded.
pixel_buffer->release_callback = [](void* opaque) {
auto mutex = reinterpret_cast<std::mutex*>(opaque);
// Gets locked just before |CopyPixelBuffer| returns.
mutex->unlock();
};
}
pixel_buffer->width = width;
pixel_buffer->height = height;
const auto size = width * height * 4;
backing_pixel_buffer.reset(new uint8_t[size]);
pixel_buffer->buffer = backing_pixel_buffer.get();
}
webview_cef::SwapBufferFromBgraToRgba((void*)pixel_buffer->buffer, buffer, width, height);
FlutterDesktopTextureRegistrarMarkExternalTextureFrameAvailable(texture_registrar, texture_id);
};
webview_cef::setPaintCallBack(callback);
result->Success(flutter::EncodableValue(texture_id));
}
else{
WValue *encodeArgs = encode_flvalue_to_wvalue(const_cast<flutter::EncodableValue *>(method_call.arguments()));
webview_cef::HandleMethodCall(method_call.method_name(), encodeArgs, [=](int ret, WValue* args){
if (ret > 0){
result->Success(encode_wvalue_to_flvalue(args));
}
else if (ret < 0){
result->Error("error", "error", encode_wvalue_to_flvalue(args));
}
else{
result->NotImplemented();
}
});
webview_value_unref(encodeArgs);
}
}
void WebviewCefPlugin::handleMessageProc(UINT message, WPARAM wparam, LPARAM lparam) {
switch (message) {
case WM_USER + 1:
{
flutter::EncodableValue *method = (flutter::EncodableValue *)wparam;
flutter::EncodableValue *args = (flutter::EncodableValue *)lparam;
channel->InvokeMethod(*std::get_if<std::string>(method), std::make_unique<flutter::EncodableValue>(*args));
break;
}
case WM_QUIT:
webview_cef::HandleMethodCall("dispose", nullptr, nullptr);
}
}
} // namespace webview_cef