mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
Everywhere: Transition ImageDecoder to be single-instance, owned by UI
This is the same behavior as RequestServer, with the added benefit that we know how to gracefully reconnect ImageDecoder to all WebContent processes on restart.
This commit is contained in:
parent
343a3a0d7e
commit
4b5541e1b7
Notes:
sideshowbarker
2024-07-17 00:59:43 +09:00
Author: https://github.com/ADKaster Commit: https://github.com/LadybirdBrowser/ladybird/commit/4b5541e1b7 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/284 Reviewed-by: https://github.com/kalenikaliaksandr Reviewed-by: https://github.com/trflynn89
21 changed files with 250 additions and 31 deletions
|
@ -22,6 +22,7 @@ class WebViewBridge;
|
|||
- (instancetype)init;
|
||||
|
||||
- (ErrorOr<void>)launchRequestServer:(Vector<ByteString> const&)certificates;
|
||||
- (ErrorOr<void>)launchImageDecoder;
|
||||
- (ErrorOr<NonnullRefPtr<WebView::WebContentClient>>)launchWebContent:(Ladybird::WebViewBridge&)web_view_bridge;
|
||||
- (ErrorOr<IPC::File>)launchWebWorker;
|
||||
|
||||
|
|
|
@ -41,6 +41,11 @@
|
|||
return m_application_bridge->launch_request_server(certificates);
|
||||
}
|
||||
|
||||
- (ErrorOr<void>)launchImageDecoder
|
||||
{
|
||||
return m_application_bridge->launch_image_decoder();
|
||||
}
|
||||
|
||||
- (ErrorOr<NonnullRefPtr<WebView::WebContentClient>>)launchWebContent:(Ladybird::WebViewBridge&)web_view_bridge
|
||||
{
|
||||
return m_application_bridge->launch_web_content(web_view_bridge);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <Ladybird/AppKit/UI/LadybirdWebViewBridge.h>
|
||||
#include <Ladybird/HelperProcess.h>
|
||||
#include <Ladybird/Utilities.h>
|
||||
#include <LibImageDecoderClient/Client.h>
|
||||
#include <LibProtocol/RequestClient.h>
|
||||
#include <LibWebView/WebContentClient.h>
|
||||
|
||||
|
@ -19,6 +20,7 @@ namespace Ladybird {
|
|||
// is limited to .cpp files (i.e. not .h files that an Objective-C file can include).
|
||||
struct ApplicationBridgeImpl {
|
||||
RefPtr<Protocol::RequestClient> request_server_client;
|
||||
RefPtr<ImageDecoderClient::Client> image_decoder_client;
|
||||
};
|
||||
|
||||
ApplicationBridge::ApplicationBridge()
|
||||
|
@ -37,13 +39,47 @@ ErrorOr<void> ApplicationBridge::launch_request_server(Vector<ByteString> const&
|
|||
return {};
|
||||
}
|
||||
|
||||
static ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_new_image_decoder()
|
||||
{
|
||||
auto image_decoder_paths = TRY(get_paths_for_helper_process("ImageDecoder"sv));
|
||||
return launch_image_decoder_process(image_decoder_paths);
|
||||
}
|
||||
|
||||
ErrorOr<void> ApplicationBridge::launch_image_decoder()
|
||||
{
|
||||
m_impl->image_decoder_client = TRY(launch_new_image_decoder());
|
||||
|
||||
m_impl->image_decoder_client->on_death = [this] {
|
||||
m_impl->image_decoder_client = nullptr;
|
||||
if (auto err = this->launch_image_decoder(); err.is_error()) {
|
||||
dbgln("Failed to restart image decoder: {}", err.error());
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
auto num_clients = WebView::WebContentClient::client_count();
|
||||
auto new_sockets = m_impl->image_decoder_client->send_sync_but_allow_failure<Messages::ImageDecoderServer::ConnectNewClients>(num_clients);
|
||||
if (!new_sockets || new_sockets->sockets().size() == 0) {
|
||||
dbgln("Failed to connect {} new clients to ImageDecoder", num_clients);
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
WebView::WebContentClient::for_each_client([sockets = new_sockets->take_sockets()](WebView::WebContentClient& client) mutable {
|
||||
client.async_connect_to_image_decoder(sockets.take_last());
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> ApplicationBridge::launch_web_content(WebViewBridge& web_view_bridge)
|
||||
{
|
||||
// FIXME: Fail to open the tab, rather than crashing the whole application if this fails
|
||||
auto request_server_socket = TRY(connect_new_request_server_client(*m_impl->request_server_client));
|
||||
auto image_decoder_socket = TRY(connect_new_image_decoder_client(*m_impl->image_decoder_client));
|
||||
|
||||
auto web_content_paths = TRY(get_paths_for_helper_process("WebContent"sv));
|
||||
auto web_content = TRY(launch_web_content_process(web_view_bridge, web_content_paths, web_view_bridge.web_content_options(), move(request_server_socket)));
|
||||
auto web_content = TRY(launch_web_content_process(web_view_bridge, web_content_paths, web_view_bridge.web_content_options(), move(image_decoder_socket), move(request_server_socket)));
|
||||
|
||||
return web_content;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
~ApplicationBridge();
|
||||
|
||||
ErrorOr<void> launch_request_server(Vector<ByteString> const& certificates);
|
||||
ErrorOr<void> launch_image_decoder();
|
||||
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content(WebViewBridge&);
|
||||
ErrorOr<IPC::File> launch_web_worker();
|
||||
|
||||
|
|
|
@ -136,6 +136,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
// FIXME: Create an abstraction to re-spawn the RequestServer and re-hook up its client hooks to each tab on crash
|
||||
TRY([application launchRequestServer:certificates]);
|
||||
|
||||
TRY([application launchImageDecoder]);
|
||||
|
||||
StringBuilder command_line_builder;
|
||||
command_line_builder.join(' ', arguments.strings);
|
||||
Ladybird::WebContentOptions web_content_options {
|
||||
|
|
|
@ -77,6 +77,7 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
|||
WebView::ViewImplementation& view,
|
||||
ReadonlySpan<ByteString> candidate_web_content_paths,
|
||||
Ladybird::WebContentOptions const& web_content_options,
|
||||
IPC::File image_decoder_socket,
|
||||
Optional<IPC::File> request_server_socket)
|
||||
{
|
||||
Vector<ByteString> arguments {
|
||||
|
@ -113,6 +114,9 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
|||
arguments.append(ByteString::number(request_server_socket->fd()));
|
||||
}
|
||||
|
||||
arguments.append("--image-decoder-socket"sv);
|
||||
arguments.append(ByteString::number(image_decoder_socket.fd()));
|
||||
|
||||
return launch_server_process<WebView::WebContentClient>("WebContent"sv, candidate_web_content_paths, move(arguments), RegisterWithProcessManager::No, web_content_options.enable_callgrind_profiling, view);
|
||||
}
|
||||
|
||||
|
@ -164,3 +168,19 @@ ErrorOr<IPC::File> connect_new_request_server_client(Protocol::RequestClient& cl
|
|||
|
||||
return socket;
|
||||
}
|
||||
|
||||
ErrorOr<IPC::File> connect_new_image_decoder_client(ImageDecoderClient::Client& client)
|
||||
{
|
||||
auto new_socket = client.send_sync_but_allow_failure<Messages::ImageDecoderServer::ConnectNewClients>(1);
|
||||
if (!new_socket)
|
||||
return Error::from_string_literal("Failed to connect to ImageDecoder");
|
||||
|
||||
auto sockets = new_socket->take_sockets();
|
||||
if (sockets.size() != 1)
|
||||
return Error::from_string_literal("Failed to connect to ImageDecoder");
|
||||
|
||||
auto socket = sockets.take_last();
|
||||
TRY(socket.clear_close_on_exec());
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
|||
WebView::ViewImplementation& view,
|
||||
ReadonlySpan<ByteString> candidate_web_content_paths,
|
||||
Ladybird::WebContentOptions const&,
|
||||
IPC::File image_decoder_socket,
|
||||
Optional<IPC::File> request_server_socket = {});
|
||||
|
||||
ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process(ReadonlySpan<ByteString> candidate_image_decoder_paths);
|
||||
|
@ -28,3 +29,4 @@ ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(Rea
|
|||
ErrorOr<NonnullRefPtr<Protocol::RequestClient>> launch_request_server_process(ReadonlySpan<ByteString> candidate_request_server_paths, StringView serenity_resource_root, Vector<ByteString> const& certificates);
|
||||
|
||||
ErrorOr<IPC::File> connect_new_request_server_client(Protocol::RequestClient&);
|
||||
ErrorOr<IPC::File> connect_new_image_decoder_client(ImageDecoderClient::Client&);
|
||||
|
|
|
@ -6,11 +6,6 @@
|
|||
*/
|
||||
|
||||
#include "ImageCodecPlugin.h"
|
||||
#ifdef AK_OS_ANDROID
|
||||
# include <Ladybird/Android/src/main/cpp/WebContentService.h>
|
||||
#else
|
||||
# include "HelperProcess.h"
|
||||
#endif
|
||||
#include "Utilities.h"
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/ImageFormats/ImageDecoder.h>
|
||||
|
@ -18,28 +13,37 @@
|
|||
|
||||
namespace Ladybird {
|
||||
|
||||
ImageCodecPlugin::ImageCodecPlugin(NonnullRefPtr<ImageDecoderClient::Client> client)
|
||||
: m_client(move(client))
|
||||
{
|
||||
m_client->on_death = [this] {
|
||||
m_client = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
void ImageCodecPlugin::set_client(NonnullRefPtr<ImageDecoderClient::Client> client)
|
||||
{
|
||||
m_client = move(client);
|
||||
m_client->on_death = [this] {
|
||||
m_client = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
ImageCodecPlugin::~ImageCodecPlugin() = default;
|
||||
|
||||
NonnullRefPtr<Core::Promise<Web::Platform::DecodedImage>> ImageCodecPlugin::decode_image(ReadonlyBytes bytes, Function<ErrorOr<void>(Web::Platform::DecodedImage&)> on_resolved, Function<void(Error&)> on_rejected)
|
||||
{
|
||||
if (!m_client) {
|
||||
#ifdef AK_OS_ANDROID
|
||||
m_client = MUST(bind_service<ImageDecoderClient::Client>(&bind_image_decoder_java));
|
||||
#else
|
||||
auto candidate_image_decoder_paths = get_paths_for_helper_process("ImageDecoder"sv).release_value_but_fixme_should_propagate_errors();
|
||||
m_client = launch_image_decoder_process(candidate_image_decoder_paths).release_value_but_fixme_should_propagate_errors();
|
||||
#endif
|
||||
m_client->on_death = [&] {
|
||||
m_client = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
auto promise = Core::Promise<Web::Platform::DecodedImage>::construct();
|
||||
if (on_resolved)
|
||||
promise->on_resolution = move(on_resolved);
|
||||
if (on_rejected)
|
||||
promise->on_rejection = move(on_rejected);
|
||||
|
||||
if (!m_client) {
|
||||
promise->reject(Error::from_string_literal("ImageDecoderClient is disconnected"));
|
||||
return promise;
|
||||
}
|
||||
|
||||
auto image_decoder_promise = m_client->decode_image(
|
||||
bytes,
|
||||
[promise](ImageDecoderClient::DecodedImage& result) -> ErrorOr<void> {
|
||||
|
|
|
@ -14,11 +14,13 @@ namespace Ladybird {
|
|||
|
||||
class ImageCodecPlugin final : public Web::Platform::ImageCodecPlugin {
|
||||
public:
|
||||
ImageCodecPlugin() = default;
|
||||
explicit ImageCodecPlugin(NonnullRefPtr<ImageDecoderClient::Client>);
|
||||
virtual ~ImageCodecPlugin() override;
|
||||
|
||||
virtual NonnullRefPtr<Core::Promise<Web::Platform::DecodedImage>> decode_image(ReadonlyBytes, Function<ErrorOr<void>(Web::Platform::DecodedImage&)> on_resolved, Function<void(Error&)> on_rejected) override;
|
||||
|
||||
void set_client(NonnullRefPtr<ImageDecoderClient::Client>);
|
||||
|
||||
private:
|
||||
RefPtr<ImageDecoderClient::Client> m_client;
|
||||
};
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "Application.h"
|
||||
#include "StringUtils.h"
|
||||
#include "TaskManagerWindow.h"
|
||||
#include <Ladybird/HelperProcess.h>
|
||||
#include <Ladybird/Utilities.h>
|
||||
#include <LibWebView/URL.h>
|
||||
#include <QFileOpenEvent>
|
||||
|
||||
|
@ -43,6 +45,38 @@ bool Application::event(QEvent* event)
|
|||
return QApplication::event(event);
|
||||
}
|
||||
|
||||
static ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_new_image_decoder()
|
||||
{
|
||||
auto paths = TRY(get_paths_for_helper_process("ImageDecoder"sv));
|
||||
return launch_image_decoder_process(paths);
|
||||
}
|
||||
|
||||
ErrorOr<void> Application::initialize_image_decoder()
|
||||
{
|
||||
m_image_decoder_client = TRY(launch_new_image_decoder());
|
||||
|
||||
m_image_decoder_client->on_death = [this] {
|
||||
m_image_decoder_client = nullptr;
|
||||
if (auto err = this->initialize_image_decoder(); err.is_error()) {
|
||||
dbgln("Failed to restart image decoder: {}", err.error());
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
auto num_clients = WebView::WebContentClient::client_count();
|
||||
auto new_sockets = m_image_decoder_client->send_sync_but_allow_failure<Messages::ImageDecoderServer::ConnectNewClients>(num_clients);
|
||||
if (!new_sockets || new_sockets->sockets().size() == 0) {
|
||||
dbgln("Failed to connect {} new clients to ImageDecoder", num_clients);
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
WebView::WebContentClient::for_each_client([sockets = new_sockets->take_sockets()](WebView::WebContentClient& client) mutable {
|
||||
client.async_connect_to_image_decoder(sockets.take_last());
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
};
|
||||
return {};
|
||||
}
|
||||
|
||||
void Application::show_task_manager_window()
|
||||
{
|
||||
if (!m_task_manager_window) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <AK/Function.h>
|
||||
#include <AK/HashTable.h>
|
||||
#include <Ladybird/Qt/BrowserWindow.h>
|
||||
#include <LibImageDecoderClient/Client.h>
|
||||
#include <LibProtocol/RequestClient.h>
|
||||
#include <LibURL/URL.h>
|
||||
#include <QApplication>
|
||||
|
@ -27,6 +28,9 @@ public:
|
|||
Function<void(URL::URL)> on_open_file;
|
||||
RefPtr<Protocol::RequestClient> request_server_client;
|
||||
|
||||
NonnullRefPtr<ImageDecoderClient::Client> image_decoder_client() const { return *m_image_decoder_client; }
|
||||
ErrorOr<void> initialize_image_decoder();
|
||||
|
||||
BrowserWindow& new_window(Vector<URL::URL> const& initial_urls, WebView::CookieJar&, WebContentOptions const&, StringView webdriver_content_ipc_path, bool allow_popups, Tab* parent_tab = nullptr, Optional<u64> page_index = {});
|
||||
|
||||
void show_task_manager_window();
|
||||
|
@ -38,6 +42,8 @@ public:
|
|||
private:
|
||||
TaskManagerWindow* m_task_manager_window { nullptr };
|
||||
BrowserWindow* m_active_window { nullptr };
|
||||
|
||||
RefPtr<ImageDecoderClient::Client> m_image_decoder_client;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -549,8 +549,11 @@ void WebContentView::initialize_client(WebView::ViewImplementation::CreateNewCli
|
|||
request_server_socket = AK::move(socket);
|
||||
}
|
||||
|
||||
auto image_decoder = static_cast<Ladybird::Application*>(QApplication::instance())->image_decoder_client();
|
||||
auto image_decoder_socket = connect_new_image_decoder_client(*image_decoder).release_value_but_fixme_should_propagate_errors();
|
||||
|
||||
auto candidate_web_content_paths = get_paths_for_helper_process("WebContent"sv).release_value_but_fixme_should_propagate_errors();
|
||||
auto new_client = launch_web_content_process(*this, candidate_web_content_paths, m_web_content_options, AK::move(request_server_socket)).release_value_but_fixme_should_propagate_errors();
|
||||
auto new_client = launch_web_content_process(*this, candidate_web_content_paths, m_web_content_options, AK::move(image_decoder_socket), AK::move(request_server_socket)).release_value_but_fixme_should_propagate_errors();
|
||||
|
||||
m_client_state.client = new_client;
|
||||
} else {
|
||||
|
|
|
@ -166,7 +166,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
// FIXME: Create an abstraction to re-spawn the RequestServer and re-hook up its client hooks to each tab on crash
|
||||
auto request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv));
|
||||
auto protocol_client = TRY(launch_request_server_process(request_server_paths, s_serenity_resource_root, certificates));
|
||||
app.request_server_client = protocol_client;
|
||||
app.request_server_client = move(protocol_client);
|
||||
|
||||
TRY(app.initialize_image_decoder());
|
||||
|
||||
StringBuilder command_line_builder;
|
||||
command_line_builder.join(' ', arguments.strings);
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <LibCore/LocalServer.h>
|
||||
#include <LibCore/Process.h>
|
||||
#include <LibCore/Resource.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <LibCore/SystemServerTakeover.h>
|
||||
#include <LibIPC/ConnectionFromClient.h>
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
|
@ -28,9 +27,7 @@
|
|||
#include <LibWeb/PermissionsPolicy/AutoplayAllowlist.h>
|
||||
#include <LibWeb/Platform/AudioCodecPluginAgnostic.h>
|
||||
#include <LibWeb/Platform/EventLoopPluginSerenity.h>
|
||||
#include <LibWeb/WebSockets/WebSocket.h>
|
||||
#include <LibWebView/RequestServerAdapter.h>
|
||||
#include <LibWebView/WebSocketClientAdapter.h>
|
||||
#include <WebContent/ConnectionFromClient.h>
|
||||
#include <WebContent/PageClient.h>
|
||||
#include <WebContent/WebDriverConnection.h>
|
||||
|
@ -52,6 +49,8 @@
|
|||
static ErrorOr<void> load_content_filters();
|
||||
static ErrorOr<void> load_autoplay_allowlist();
|
||||
static ErrorOr<void> initialize_lagom_networking(int request_server_socket);
|
||||
static ErrorOr<void> initialize_image_decoder(int image_decoder_socket);
|
||||
static ErrorOr<void> reinitialize_image_decoder(IPC::File const& image_decoder_socket);
|
||||
|
||||
namespace JS {
|
||||
extern bool g_log_all_js_exceptions;
|
||||
|
@ -79,7 +78,6 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
platform_init();
|
||||
|
||||
Web::Platform::EventLoopPlugin::install(*new Web::Platform::EventLoopPluginSerenity);
|
||||
Web::Platform::ImageCodecPlugin::install(*new Ladybird::ImageCodecPlugin);
|
||||
|
||||
Web::Platform::AudioCodecPlugin::install_creation_hook([](auto loader) {
|
||||
#if defined(HAVE_QT_MULTIMEDIA)
|
||||
|
@ -97,6 +95,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
StringView mach_server_name {};
|
||||
Vector<ByteString> certificates;
|
||||
int request_server_socket { -1 };
|
||||
int image_decoder_socket { -1 };
|
||||
bool is_layout_test_mode = false;
|
||||
bool expose_internals_object = false;
|
||||
bool use_lagom_networking = false;
|
||||
|
@ -111,6 +110,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
args_parser.add_option(command_line, "Chrome process command line", "command-line", 0, "command_line");
|
||||
args_parser.add_option(executable_path, "Chrome process executable path", "executable-path", 0, "executable_path");
|
||||
args_parser.add_option(request_server_socket, "File descriptor of the socket for the RequestServer connection", "request-server-socket", 'r', "request_server_socket");
|
||||
args_parser.add_option(image_decoder_socket, "File descriptor of the socket for the ImageDecoder connection", "image-decoder-socket", 'i', "image_decoder_socket");
|
||||
args_parser.add_option(is_layout_test_mode, "Is layout test mode", "layout-test-mode");
|
||||
args_parser.add_option(expose_internals_object, "Expose internals object", "expose-internals-object");
|
||||
args_parser.add_option(use_lagom_networking, "Enable Lagom servers for networking", "use-lagom-networking");
|
||||
|
@ -160,6 +160,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
#endif
|
||||
TRY(initialize_lagom_networking(request_server_socket));
|
||||
|
||||
TRY(initialize_image_decoder(image_decoder_socket));
|
||||
|
||||
Web::HTML::Window::set_internals_object_exposed(expose_internals_object);
|
||||
|
||||
Web::Platform::FontPlugin::install(*new Ladybird::FontPlugin(is_layout_test_mode));
|
||||
|
@ -185,6 +187,12 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
auto webcontent_socket = TRY(Core::take_over_socket_from_system_server("WebContent"sv));
|
||||
auto webcontent_client = TRY(WebContent::ConnectionFromClient::try_create(move(webcontent_socket)));
|
||||
|
||||
webcontent_client->on_image_decoder_connection = [&](auto& socket_file) {
|
||||
auto maybe_error = reinitialize_image_decoder(socket_file);
|
||||
if (maybe_error.is_error())
|
||||
dbgln("Failed to reinitialize image decoder: {}", maybe_error.error());
|
||||
};
|
||||
|
||||
return event_loop.exec();
|
||||
}
|
||||
|
||||
|
@ -246,3 +254,27 @@ ErrorOr<void> initialize_lagom_networking(int request_server_socket)
|
|||
Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(new_client))));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> initialize_image_decoder(int image_decoder_socket)
|
||||
{
|
||||
auto socket = TRY(Core::LocalSocket::adopt_fd(image_decoder_socket));
|
||||
TRY(socket->set_blocking(true));
|
||||
|
||||
auto new_client = TRY(try_make_ref_counted<ImageDecoderClient::Client>(move(socket)));
|
||||
|
||||
Web::Platform::ImageCodecPlugin::install(*new Ladybird::ImageCodecPlugin(move(new_client)));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> reinitialize_image_decoder(IPC::File const& image_decoder_socket)
|
||||
{
|
||||
auto socket = TRY(Core::LocalSocket::adopt_fd(image_decoder_socket.take_fd()));
|
||||
TRY(socket->set_blocking(true));
|
||||
|
||||
auto new_client = TRY(try_make_ref_counted<ImageDecoderClient::Client>(move(socket)));
|
||||
|
||||
static_cast<Ladybird::ImageCodecPlugin&>(Web::Platform::ImageCodecPlugin::the()).set_client(move(new_client));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/IDAllocator.h>
|
||||
#include <ImageDecoder/ConnectionFromClient.h>
|
||||
#include <ImageDecoder/ImageDecoderClientEndpoint.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
|
@ -13,9 +14,13 @@
|
|||
|
||||
namespace ImageDecoder {
|
||||
|
||||
static HashMap<int, RefPtr<ConnectionFromClient>> s_connections;
|
||||
static IDAllocator s_client_ids;
|
||||
|
||||
ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr<Core::LocalSocket> socket)
|
||||
: IPC::ConnectionFromClient<ImageDecoderClientEndpoint, ImageDecoderServerEndpoint>(*this, move(socket), 1)
|
||||
: IPC::ConnectionFromClient<ImageDecoderClientEndpoint, ImageDecoderServerEndpoint>(*this, move(socket), s_client_ids.allocate())
|
||||
{
|
||||
s_connections.set(client_id(), *this);
|
||||
}
|
||||
|
||||
void ConnectionFromClient::die()
|
||||
|
@ -25,8 +30,49 @@ void ConnectionFromClient::die()
|
|||
}
|
||||
m_pending_jobs.clear();
|
||||
|
||||
Threading::quit_background_thread();
|
||||
Core::EventLoop::current().quit(0);
|
||||
auto client_id = this->client_id();
|
||||
s_connections.remove(client_id);
|
||||
s_client_ids.deallocate(client_id);
|
||||
|
||||
if (s_connections.is_empty()) {
|
||||
Threading::quit_background_thread();
|
||||
Core::EventLoop::current().quit(0);
|
||||
}
|
||||
}
|
||||
|
||||
ErrorOr<IPC::File> ConnectionFromClient::connect_new_client()
|
||||
{
|
||||
int socket_fds[2] {};
|
||||
if (auto err = Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds); err.is_error())
|
||||
return err.release_error();
|
||||
|
||||
auto client_socket_or_error = Core::LocalSocket::adopt_fd(socket_fds[0]);
|
||||
if (client_socket_or_error.is_error()) {
|
||||
close(socket_fds[0]);
|
||||
close(socket_fds[1]);
|
||||
return client_socket_or_error.release_error();
|
||||
}
|
||||
|
||||
auto client_socket = client_socket_or_error.release_value();
|
||||
// Note: A ref is stored in the static s_connections map
|
||||
auto client = adopt_ref(*new ConnectionFromClient(move(client_socket)));
|
||||
|
||||
return IPC::File::adopt_fd(socket_fds[1]);
|
||||
}
|
||||
|
||||
Messages::ImageDecoderServer::ConnectNewClientsResponse ConnectionFromClient::connect_new_clients(size_t count)
|
||||
{
|
||||
Vector<IPC::File> files;
|
||||
files.ensure_capacity(count);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
auto file_or_error = connect_new_client();
|
||||
if (file_or_error.is_error()) {
|
||||
dbgln("Failed to connect new client: {}", file_or_error.error());
|
||||
return Vector<IPC::File> {};
|
||||
}
|
||||
files.unchecked_append(file_or_error.release_value());
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
static void decode_image_to_bitmaps_and_durations_with_decoder(Gfx::ImageDecoder const& decoder, Optional<Gfx::IntSize> ideal_size, Vector<Gfx::ShareableBitmap>& bitmaps, Vector<u32>& durations)
|
||||
|
|
|
@ -39,6 +39,9 @@ private:
|
|||
|
||||
virtual Messages::ImageDecoderServer::DecodeImageResponse decode_image(Core::AnonymousBuffer const&, Optional<Gfx::IntSize> const& ideal_size, Optional<ByteString> const& mime_type) override;
|
||||
virtual void cancel_decoding(i64 image_id) override;
|
||||
virtual Messages::ImageDecoderServer::ConnectNewClientsResponse connect_new_clients(size_t count) override;
|
||||
|
||||
ErrorOr<IPC::File> connect_new_client();
|
||||
|
||||
NonnullRefPtr<Job> make_decode_image_job(i64 image_id, Core::AnonymousBuffer, Optional<Gfx::IntSize> ideal_size, Optional<ByteString> mime_type);
|
||||
|
||||
|
|
|
@ -4,4 +4,6 @@ endpoint ImageDecoderServer
|
|||
{
|
||||
decode_image(Core::AnonymousBuffer data, Optional<Gfx::IntSize> ideal_size, Optional<ByteString> mime_type) => (i64 image_id)
|
||||
cancel_decoding(i64 image_id) =|
|
||||
|
||||
connect_new_clients(size_t count) => (Vector<IPC::File> sockets)
|
||||
}
|
||||
|
|
|
@ -104,6 +104,12 @@ void ConnectionFromClient::connect_to_webdriver(u64 page_id, ByteString const& w
|
|||
}
|
||||
}
|
||||
|
||||
void ConnectionFromClient::connect_to_image_decoder(IPC::File const& image_decoder_socket)
|
||||
{
|
||||
if (on_image_decoder_connection)
|
||||
on_image_decoder_connection(image_decoder_socket);
|
||||
}
|
||||
|
||||
void ConnectionFromClient::update_system_theme(u64 page_id, Core::AnonymousBuffer const& theme_buffer)
|
||||
{
|
||||
auto page = this->page(page_id);
|
||||
|
|
|
@ -45,6 +45,8 @@ public:
|
|||
PageHost& page_host() { return *m_page_host; }
|
||||
PageHost const& page_host() const { return *m_page_host; }
|
||||
|
||||
Function<void(IPC::File const&)> on_image_decoder_connection;
|
||||
|
||||
private:
|
||||
explicit ConnectionFromClient(NonnullOwnPtr<Core::LocalSocket>);
|
||||
|
||||
|
@ -54,6 +56,7 @@ private:
|
|||
virtual Messages::WebContentServer::GetWindowHandleResponse get_window_handle(u64 page_id) override;
|
||||
virtual void set_window_handle(u64 page_id, String const& handle) override;
|
||||
virtual void connect_to_webdriver(u64 page_id, ByteString const& webdriver_ipc_path) override;
|
||||
virtual void connect_to_image_decoder(IPC::File const& image_decoder_socket) override;
|
||||
virtual void update_system_theme(u64 page_id, Core::AnonymousBuffer const&) override;
|
||||
virtual void update_screen_rects(u64 page_id, Vector<Web::DevicePixelRect> const&, u32) override;
|
||||
virtual void load_url(u64 page_id, URL::URL const&) override;
|
||||
|
|
|
@ -17,6 +17,7 @@ endpoint WebContentServer
|
|||
set_window_handle(u64 page_id, String handle) =|
|
||||
|
||||
connect_to_webdriver(u64 page_id, ByteString webdriver_ipc_path) =|
|
||||
connect_to_image_decoder(IPC::File socket_fd) =|
|
||||
|
||||
update_system_theme(u64 page_id, Core::AnonymousBuffer theme_buffer) =|
|
||||
update_screen_rects(u64 page_id, Vector<Web::DevicePixelRect> rects, u32 main_screen_index) =|
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <LibGfx/StandardCursor.h>
|
||||
#include <LibGfx/SystemTheme.h>
|
||||
#include <LibIPC/File.h>
|
||||
#include <LibImageDecoderClient/Client.h>
|
||||
#include <LibProtocol/RequestClient.h>
|
||||
#include <LibURL/URL.h>
|
||||
#include <LibWeb/Cookie/Cookie.h>
|
||||
|
@ -65,14 +66,18 @@ public:
|
|||
static ErrorOr<NonnullOwnPtr<HeadlessWebContentView>> create(Core::AnonymousBuffer theme, Gfx::IntSize const& window_size, String const& command_line, StringView web_driver_ipc_path, Ladybird::IsLayoutTestMode is_layout_test_mode = Ladybird::IsLayoutTestMode::No, Vector<ByteString> const& certificates = {}, StringView resources_folder = {})
|
||||
{
|
||||
RefPtr<Protocol::RequestClient> request_client;
|
||||
RefPtr<ImageDecoderClient::Client> image_decoder_client;
|
||||
|
||||
auto request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv));
|
||||
request_client = TRY(launch_request_server_process(request_server_paths, resources_folder, certificates));
|
||||
|
||||
auto image_decoder_paths = TRY(get_paths_for_helper_process("ImageDecoder"sv));
|
||||
image_decoder_client = TRY(launch_image_decoder_process(image_decoder_paths));
|
||||
|
||||
auto database = TRY(WebView::Database::create());
|
||||
auto cookie_jar = TRY(WebView::CookieJar::create(*database));
|
||||
|
||||
auto view = TRY(adopt_nonnull_own_or_enomem(new (nothrow) HeadlessWebContentView(move(database), move(cookie_jar), request_client)));
|
||||
auto view = TRY(adopt_nonnull_own_or_enomem(new (nothrow) HeadlessWebContentView(move(database), move(cookie_jar), image_decoder_client, request_client)));
|
||||
|
||||
Ladybird::WebContentOptions web_content_options {
|
||||
.command_line = command_line,
|
||||
|
@ -81,9 +86,10 @@ public:
|
|||
};
|
||||
|
||||
auto request_server_socket = TRY(connect_new_request_server_client(*request_client));
|
||||
auto image_decoder_socket = TRY(connect_new_image_decoder_client(*image_decoder_client));
|
||||
|
||||
auto candidate_web_content_paths = TRY(get_paths_for_helper_process("WebContent"sv));
|
||||
view->m_client_state.client = TRY(launch_web_content_process(*view, candidate_web_content_paths, web_content_options, move(request_server_socket)));
|
||||
view->m_client_state.client = TRY(launch_web_content_process(*view, candidate_web_content_paths, web_content_options, move(image_decoder_socket), move(request_server_socket)));
|
||||
|
||||
view->client().async_update_system_theme(0, move(theme));
|
||||
|
||||
|
@ -145,10 +151,11 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
HeadlessWebContentView(NonnullRefPtr<WebView::Database> database, NonnullOwnPtr<WebView::CookieJar> cookie_jar, RefPtr<Protocol::RequestClient> request_client = nullptr)
|
||||
HeadlessWebContentView(NonnullRefPtr<WebView::Database> database, NonnullOwnPtr<WebView::CookieJar> cookie_jar, RefPtr<ImageDecoderClient::Client> image_decoder_client, RefPtr<Protocol::RequestClient> request_client)
|
||||
: m_database(move(database))
|
||||
, m_cookie_jar(move(cookie_jar))
|
||||
, m_request_client(move(request_client))
|
||||
, m_image_decoder_client(move(image_decoder_client))
|
||||
{
|
||||
on_get_cookie = [this](auto const& url, auto source) {
|
||||
return m_cookie_jar->get_cookie(url, source);
|
||||
|
@ -178,6 +185,7 @@ private:
|
|||
NonnullRefPtr<WebView::Database> m_database;
|
||||
NonnullOwnPtr<WebView::CookieJar> m_cookie_jar;
|
||||
RefPtr<Protocol::RequestClient> m_request_client;
|
||||
RefPtr<ImageDecoderClient::Client> m_image_decoder_client;
|
||||
};
|
||||
|
||||
static ErrorOr<NonnullRefPtr<Core::Timer>> load_page_for_screenshot_and_exit(Core::EventLoop& event_loop, HeadlessWebContentView& view, URL::URL url, int screenshot_timeout)
|
||||
|
|
Loading…
Reference in a new issue