Compositor+LibWebView+WebContent: Scaffold opt-in Compositor process

The compositor is moving into a dedicated helper process. That requires
a process to launch, channels for Browser and WebContent to talk to it
over, and client proxies on each side. Land all of that as an inert
scaffold first, gated behind --enable-compositor-process, so the default
rendering path is unchanged and later commits can fill in the protocol,
the service-side state, and the runtime switch against a stable target.
This commit is contained in:
Aliaksandr Kalenik 2026-05-22 16:02:42 +02:00 committed by Alexander Kalenik
parent 4a34a60d93
commit bfc9bf80d9
33 changed files with 489 additions and 1 deletions

View file

@ -21,6 +21,7 @@
#include <LibWeb/CSS/PropertyID.h>
#include <LibWeb/Loader/UserAgent.h>
#include <LibWebView/Application.h>
#include <LibWebView/CompositorClient.h>
#include <LibWebView/CookieJar.h>
#include <LibWebView/HeadlessWebView.h>
#include <LibWebView/HelperProcess.h>
@ -97,6 +98,8 @@ Application::~Application()
// Explicitly delete the observers first, as the observer destructors will refer to Application::the().
m_settings_observer.clear();
m_bookmark_store_observer.clear();
if (m_compositor_client)
m_compositor_client->on_death = nullptr;
s_the = nullptr;
}
@ -164,6 +167,7 @@ ErrorOr<void> Application::initialize(Main::Arguments const& arguments)
bool disable_http_memory_cache = false;
bool disable_http_disk_cache = false;
bool disable_content_blocker = false;
bool enable_compositor_process = false;
Vector<StringView> content_blocker_list_paths;
Optional<StringView> resource_substitution_map_path;
bool enable_autoplay = false;
@ -238,6 +242,7 @@ ErrorOr<void> Application::initialize(Main::Arguments const& arguments)
args_parser.add_option(disable_http_memory_cache, "Disable HTTP memory cache", "disable-http-memory-cache");
args_parser.add_option(disable_http_disk_cache, "Disable HTTP disk cache", "disable-http-disk-cache");
args_parser.add_option(disable_content_blocker, "Disable content blocker", "disable-content-blocker");
args_parser.add_option(enable_compositor_process, "Enable the out-of-process compositor", "enable-compositor-process");
args_parser.add_option(Core::ArgsParser::Option {
.argument_mode = Core::ArgsParser::OptionArgumentMode::Required,
.help_string = "Path to a content blocker list. May be specified multiple times.",
@ -353,6 +358,7 @@ ErrorOr<void> Application::initialize(Main::Arguments const& arguments)
: OptionalNone()),
.devtools_port = devtools_port,
.enable_content_blocker = disable_content_blocker ? EnableContentBlocker::No : EnableContentBlocker::Yes,
.enable_compositor_process = enable_compositor_process ? EnableCompositorProcess::Yes : EnableCompositorProcess::No,
.content_blocker_list_paths = move(content_blocker_list_paths_as_byte_strings),
};
@ -481,10 +487,26 @@ static ErrorOr<NonnullRefPtr<WebContentClient>> create_web_content_client(Option
client->async_connect_to_request_server(move(request_server_handle));
client->async_connect_to_image_decoder(move(image_decoder_handle));
TRY(Application::the().connect_web_content_to_compositor(*client));
return client;
}
ErrorOr<void> Application::connect_web_content_to_compositor(WebContentClient& web_content_client)
{
if (m_browser_options.enable_compositor_process == EnableCompositorProcess::No)
return {};
if (web_content_client.compositor_connection_id({}).has_value())
return {};
VERIFY(m_compositor_client);
auto response = m_compositor_client->connect_web_content();
web_content_client.set_compositor_connection_id({}, response.web_content_connection_id());
web_content_client.async_connect_to_compositor_process(response.take_handle());
return {};
}
ErrorOr<NonnullRefPtr<WebContentClient>> Application::launch_web_content_process(ViewImplementation& view)
{
if (m_spare_web_content_process) {
@ -582,6 +604,8 @@ ErrorOr<void> Application::launch_services()
TRY(launch_request_server());
TRY(launch_image_decoder_server());
if (m_browser_options.enable_compositor_process == EnableCompositorProcess::Yes)
TRY(launch_compositor_process());
if (m_browser_options.devtools_port.has_value())
TRY(launch_devtools_server());
@ -589,6 +613,23 @@ ErrorOr<void> Application::launch_services()
return {};
}
ErrorOr<void> Application::launch_compositor_process()
{
VERIFY(!m_compositor_client);
m_compositor_client = TRY(WebView::launch_compositor_process());
m_compositor_client->on_death = [this]() {
m_compositor_client = nullptr;
if (Core::EventLoop::current().was_exit_requested())
return;
dbgln("Compositor process died");
VERIFY_NOT_REACHED();
};
return {};
}
ErrorOr<void> Application::launch_request_server()
{
m_request_server_client = TRY(launch_request_server_process());
@ -806,6 +847,12 @@ void Application::process_did_exit(Process&& process, Optional<int> exit_status)
dbgln_if(WEBVIEW_PROCESS_DEBUG, "Process {} died, type: {}", process.pid(), process_name_from_type(process.type()));
switch (process.type()) {
case ProcessType::Compositor:
if (auto client = process.client<CompositorClient>(); client.has_value()) {
if (auto on_death = move(client->on_death))
on_death();
}
break;
case ProcessType::ImageDecoder:
if (auto client = process.client<ImageDecoderClient::Client>(); client.has_value()) {
dbgln_if(WEBVIEW_PROCESS_DEBUG, "Restart ImageDecoder process");

View file

@ -82,6 +82,7 @@ public:
#endif
ErrorOr<NonnullRefPtr<WebContentClient>> launch_web_content_process(ViewImplementation&);
ErrorOr<void> connect_web_content_to_compositor(WebContentClient&);
virtual Optional<ViewImplementation&> active_web_view() const { return {}; }
virtual Optional<ViewImplementation&> open_blank_new_tab(Web::HTML::ActivateTab) const { return {}; }
@ -207,6 +208,7 @@ protected:
private:
ErrorOr<void> launch_services();
void launch_spare_web_content_process();
ErrorOr<void> launch_compositor_process();
ErrorOr<void> launch_request_server();
ErrorOr<void> launch_image_decoder_server();
ErrorOr<void> launch_devtools_server();
@ -277,6 +279,7 @@ private:
RefPtr<Requests::RequestClient> m_request_server_client;
RefPtr<ImageDecoderClient::Client> m_image_decoder_client;
RefPtr<CompositorClient> m_compositor_client;
RefPtr<WebContentClient> m_spare_web_content_process;
bool m_has_queued_task_to_launch_spare_web_content_process { false };

View file

@ -33,6 +33,7 @@ set(SOURCES
WebUI/ProcessesUI.cpp
WebUI/SettingsUI.cpp
WebUI/VersionUI.cpp
CompositorClient.cpp
)
set(GENERATED_SOURCES ${CURRENT_LIB_GENERATED})
@ -48,12 +49,18 @@ embed_as_string(
compile_ipc(UIProcessServer.ipc UIProcessServerEndpoint.h)
compile_ipc(UIProcessClient.ipc UIProcessClientEndpoint.h)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Services/Compositor)
if (NOT APPLE AND NOT CMAKE_INSTALL_LIBEXECDIR STREQUAL "libexec")
set_source_files_properties(Utilities.cpp PROPERTIES COMPILE_DEFINITIONS LADYBIRD_LIBEXECDIR="${CMAKE_INSTALL_LIBEXECDIR}")
endif()
set(GENERATED_SOURCES
${GENERATED_SOURCES}
../../Services/Compositor/CompositorControlClientEndpoint.h
../../Services/Compositor/CompositorControlServerEndpoint.h
../../Services/Compositor/CompositorWebContentClientEndpoint.h
../../Services/Compositor/CompositorWebContentServerEndpoint.h
../../Services/RequestServer/RequestClientEndpoint.h
../../Services/RequestServer/RequestServerEndpoint.h
../../Services/WebContent/CompositorClientEndpoint.h
@ -71,6 +78,10 @@ set(GENERATED_SOURCES
UIProcessServerEndpoint.h
)
compile_ipc(${LADYBIRD_SOURCE_DIR}/Services/Compositor/CompositorControlClient.ipc ${CMAKE_BINARY_DIR}/Services/Compositor/CompositorControlClientEndpoint.h)
compile_ipc(${LADYBIRD_SOURCE_DIR}/Services/Compositor/CompositorControlServer.ipc ${CMAKE_BINARY_DIR}/Services/Compositor/CompositorControlServerEndpoint.h)
compile_ipc(${LADYBIRD_SOURCE_DIR}/Services/Compositor/CompositorWebContentClient.ipc ${CMAKE_BINARY_DIR}/Services/Compositor/CompositorWebContentClientEndpoint.h)
compile_ipc(${LADYBIRD_SOURCE_DIR}/Services/Compositor/CompositorWebContentServer.ipc ${CMAKE_BINARY_DIR}/Services/Compositor/CompositorWebContentServerEndpoint.h)
compile_ipc(${LADYBIRD_SOURCE_DIR}/Services/WebContent/CompositorClient.ipc ${CMAKE_BINARY_DIR}/Services/WebContent/CompositorClientEndpoint.h)
compile_ipc(${LADYBIRD_SOURCE_DIR}/Services/WebContent/CompositorServer.ipc ${CMAKE_BINARY_DIR}/Services/WebContent/CompositorServerEndpoint.h)
compile_ipc(${LADYBIRD_SOURCE_DIR}/Services/WebContent/WebContentClient.ipc ${CMAKE_BINARY_DIR}/Services/WebContent/WebContentClientEndpoint.h)

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWebView/CompositorClient.h>
#include <LibCore/EventLoop.h>
namespace WebView {
CompositorClient::CompositorClient(NonnullOwnPtr<IPC::Transport> transport)
: IPC::ConnectionToServer<CompositorControlClientEndpoint, CompositorControlServerEndpoint>(*this, move(transport))
{
}
void CompositorClient::die()
{
if (auto callback = move(on_death)) {
Core::deferred_invoke([callback = move(callback)]() mutable {
callback();
});
}
}
void CompositorClient::did_connect_web_content(i32)
{
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Function.h>
#include <Compositor/CompositorControlClientEndpoint.h>
#include <Compositor/CompositorControlServerEndpoint.h>
#include <LibIPC/ConnectionToServer.h>
#include <LibWebView/Forward.h>
namespace WebView {
class WEBVIEW_API CompositorClient final
: public IPC::ConnectionToServer<CompositorControlClientEndpoint, CompositorControlServerEndpoint>
, public CompositorControlClientEndpoint {
C_OBJECT_ABSTRACT(CompositorClient)
public:
using InitTransport = Messages::CompositorControlServer::InitTransport;
explicit CompositorClient(NonnullOwnPtr<IPC::Transport>);
Function<void()> on_death;
private:
virtual void die() override;
virtual void did_connect_web_content(i32 web_content_connection_id) override;
};
}

View file

@ -16,6 +16,7 @@ class Action;
class Application;
class Autocomplete;
class BookmarkStore;
class CompositorClient;
class CookieJar;
class HistoryStore;
class Menu;

View file

@ -8,6 +8,7 @@
#include <LibCore/Process.h>
#include <LibCore/System.h>
#include <LibWebView/Application.h>
#include <LibWebView/CompositorClient.h>
#include <LibWebView/HelperProcess.h>
#include <LibWebView/Utilities.h>
@ -165,6 +166,25 @@ ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process(
return launch_server_process<ImageDecoderClient::Client>("ImageDecoder"sv, arguments);
}
ErrorOr<NonnullRefPtr<WebView::CompositorClient>> launch_compositor_process()
{
auto const& web_content_options = WebView::Application::web_content_options();
Vector<ByteString> arguments;
if (web_content_options.force_cpu_painting == WebView::ForceCPUPainting::Yes)
arguments.append("--force-cpu-painting"sv);
if (web_content_options.force_fontconfig == WebView::ForceFontconfig::Yes)
arguments.append("--force-fontconfig"sv);
if (web_content_options.enable_async_scrolling == EnableAsyncScrolling::No)
arguments.append("--disable-async-scrolling"sv);
if (auto server = mach_server_name(); server.has_value()) {
arguments.append("--mach-server-name"sv);
arguments.append(server.value());
}
return launch_server_process<WebView::CompositorClient>("Compositor"sv, move(arguments));
}
ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(Web::Bindings::AgentType type)
{
auto const& web_content_options = WebView::Application::web_content_options();

View file

@ -24,6 +24,7 @@ WEBVIEW_API ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content
WEBVIEW_API ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_spare_web_content_process();
WEBVIEW_API ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process();
WEBVIEW_API ErrorOr<NonnullRefPtr<WebView::CompositorClient>> launch_compositor_process();
WEBVIEW_API ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(Web::Bindings::AgentType);
WEBVIEW_API ErrorOr<NonnullRefPtr<Requests::RequestClient>> launch_request_server_process();

View file

@ -74,6 +74,11 @@ enum class EnableContentBlocker {
Yes,
};
enum class EnableCompositorProcess {
No,
Yes,
};
struct BrowserOptions {
Vector<URL::URL> urls;
Vector<ByteString> raw_urls;
@ -92,6 +97,7 @@ struct BrowserOptions {
Optional<DNSSettings> dns_settings {};
Optional<u16> devtools_port;
EnableContentBlocker enable_content_blocker { EnableContentBlocker::Yes };
EnableCompositorProcess enable_compositor_process { EnableCompositorProcess::No };
Vector<ByteString> content_blocker_list_paths {};
};

View file

@ -17,6 +17,8 @@ ProcessType process_type_from_name(StringView name)
{
if (name == "Browser"sv)
return ProcessType::Browser;
if (name == "Compositor"sv)
return ProcessType::Compositor;
if (name == "WebContent"sv)
return ProcessType::WebContent;
if (name == "WebWorker"sv)
@ -35,6 +37,8 @@ StringView process_name_from_type(ProcessType type)
switch (type) {
case ProcessType::Browser:
return "Browser"sv;
case ProcessType::Compositor:
return "Compositor"sv;
case ProcessType::WebContent:
return "WebContent"sv;
case ProcessType::WebWorker:

View file

@ -12,6 +12,7 @@ namespace WebView {
enum class ProcessType : u8 {
Browser,
Compositor,
WebContent,
WebWorker,
RequestServer,

View file

@ -128,6 +128,11 @@ void WebContentClient::assign_view(Badge<Application>, ViewImplementation& view)
m_views.set(0, view);
}
void WebContentClient::set_compositor_connection_id(Badge<Application>, i32 compositor_connection_id)
{
m_compositor_connection_id = compositor_connection_id;
}
void WebContentClient::register_view(u64 page_id, ViewImplementation& view)
{
VERIFY(page_id > 0);

View file

@ -54,6 +54,8 @@ public:
~WebContentClient();
void assign_view(Badge<Application>, ViewImplementation&);
void set_compositor_connection_id(Badge<Application>, i32);
Optional<i32> compositor_connection_id(Badge<Application>) const { return m_compositor_connection_id; }
void register_view(u64 page_id, ViewImplementation&);
void unregister_view(u64 page_id);
@ -168,6 +170,7 @@ private:
HashMap<u64, NonnullRawPtr<ViewImplementation>> m_views;
HashMap<u64, String> m_history_recorded_urls_for_current_load;
Optional<i32> m_compositor_connection_id;
ProcessHandle m_process_handle;

View file

@ -1,3 +1,4 @@
add_subdirectory(Compositor)
add_subdirectory(ImageDecoder)
add_subdirectory(RequestServer)
add_subdirectory(WebContent)

View file

@ -0,0 +1,28 @@
set(SOURCES
ConnectionFromClient.cpp
ConnectionFromWebContent.cpp
)
set(GENERATED_SOURCES
CompositorControlClientEndpoint.h
CompositorControlServerEndpoint.h
CompositorWebContentClientEndpoint.h
CompositorWebContentServerEndpoint.h
)
add_library(compositorservice STATIC ${SOURCES} ${GENERATED_SOURCES})
ladybird_generated_sources(compositorservice)
add_executable(Compositor main.cpp)
target_include_directories(compositorservice PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../..)
target_include_directories(compositorservice PRIVATE ${LADYBIRD_SOURCE_DIR}/Services/)
target_link_libraries(Compositor PRIVATE compositorservice LibCore LibGfx LibIPC LibMain LibWebView)
target_link_libraries(compositorservice PRIVATE LibCore LibIPC)
if (WIN32)
target_include_directories(Compositor PRIVATE $<BUILD_INTERFACE:${PTHREAD_INCLUDE_DIR}>)
target_include_directories(compositorservice PRIVATE $<BUILD_INTERFACE:${PTHREAD_INCLUDE_DIR}>)
ladybird_windows_bin(Compositor CONSOLE)
endif()

View file

@ -0,0 +1,4 @@
endpoint CompositorControlClient
{
did_connect_web_content(i32 web_content_connection_id) =|
}

View file

@ -0,0 +1,8 @@
#include <LibIPC/TransportHandle.h>
endpoint CompositorControlServer
{
init_transport(int peer_pid) => (int peer_pid)
connect_web_content() => (IPC::TransportHandle handle, i32 web_content_connection_id)
}

View file

@ -0,0 +1,4 @@
endpoint CompositorWebContentClient
{
did_connect() =|
}

View file

@ -0,0 +1,4 @@
endpoint CompositorWebContentServer
{
ping() =|
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Compositor/ConnectionFromClient.h>
#include <Compositor/ConnectionFromWebContent.h>
#include <LibCore/EventLoop.h>
#include <LibCore/System.h>
#include <LibIPC/Transport.h>
namespace Compositor {
ConnectionFromClient::ConnectionFromClient(NonnullOwnPtr<IPC::Transport> transport)
: IPC::ConnectionFromClient<CompositorControlClientEndpoint, CompositorControlServerEndpoint>(*this, move(transport), 1)
{
}
void ConnectionFromClient::die()
{
Core::EventLoop::current().quit(0);
}
Messages::CompositorControlServer::InitTransportResponse ConnectionFromClient::init_transport([[maybe_unused]] int peer_pid)
{
#ifdef AK_OS_WINDOWS
m_transport->set_peer_pid(peer_pid);
return Core::System::getpid();
#endif
VERIFY_NOT_REACHED();
}
Messages::CompositorControlServer::ConnectWebContentResponse ConnectionFromClient::connect_web_content()
{
auto paired_transport = MUST(IPC::Transport::create_paired());
auto web_content_connection_id = m_next_web_content_connection_id++;
auto connection = ConnectionFromWebContent::construct(move(paired_transport.local), web_content_connection_id);
connection->on_death = [this](auto& dead) {
m_web_content_connections.remove(dead.client_id());
};
m_web_content_connections.set(web_content_connection_id, move(connection));
async_did_connect_web_content(web_content_connection_id);
return { move(paired_transport.remote_handle), web_content_connection_id };
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/HashMap.h>
#include <AK/NonnullRefPtr.h>
#include <Compositor/CompositorControlClientEndpoint.h>
#include <Compositor/CompositorControlServerEndpoint.h>
#include <Compositor/Forward.h>
#include <LibIPC/ConnectionFromClient.h>
namespace Compositor {
class ConnectionFromClient final
: public IPC::ConnectionFromClient<CompositorControlClientEndpoint, CompositorControlServerEndpoint> {
C_OBJECT(ConnectionFromClient)
public:
virtual void die() override;
private:
explicit ConnectionFromClient(NonnullOwnPtr<IPC::Transport>);
virtual Messages::CompositorControlServer::InitTransportResponse init_transport(int peer_pid) override;
virtual Messages::CompositorControlServer::ConnectWebContentResponse connect_web_content() override;
i32 m_next_web_content_connection_id { 1 };
HashMap<i32, NonnullRefPtr<ConnectionFromWebContent>> m_web_content_connections;
};
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Compositor/ConnectionFromWebContent.h>
namespace Compositor {
ConnectionFromWebContent::ConnectionFromWebContent(NonnullOwnPtr<IPC::Transport> transport, int client_id)
: IPC::ConnectionFromClient<CompositorWebContentClientEndpoint, CompositorWebContentServerEndpoint>(*this, move(transport), client_id)
{
}
void ConnectionFromWebContent::die()
{
if (on_death)
on_death(*this);
}
void ConnectionFromWebContent::ping()
{
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Function.h>
#include <Compositor/CompositorWebContentClientEndpoint.h>
#include <Compositor/CompositorWebContentServerEndpoint.h>
#include <LibIPC/ConnectionFromClient.h>
namespace Compositor {
class ConnectionFromWebContent final
: public IPC::ConnectionFromClient<CompositorWebContentClientEndpoint, CompositorWebContentServerEndpoint> {
C_OBJECT(ConnectionFromWebContent)
public:
virtual void die() override;
Function<void(ConnectionFromWebContent&)> on_death;
private:
explicit ConnectionFromWebContent(NonnullOwnPtr<IPC::Transport>, int client_id);
virtual void ping() override;
};
}

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
namespace Compositor {
class ConnectionFromClient;
class ConnectionFromWebContent;
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Compositor/ConnectionFromClient.h>
#include <LibCore/ArgsParser.h>
#include <LibCore/EventLoop.h>
#include <LibCore/Process.h>
#include <LibGfx/Font/FontDatabase.h>
#include <LibGfx/Font/PathFontProvider.h>
#include <LibGfx/SkiaBackendContext.h>
#include <LibIPC/SingleServer.h>
#include <LibMain/Main.h>
#include <LibWebView/Utilities.h>
ErrorOr<int> ladybird_main(Main::Arguments arguments)
{
AK::set_rich_debug_enabled(true);
StringView mach_server_name;
bool wait_for_debugger = false;
bool force_cpu_painting = false;
bool force_fontconfig = false;
bool disable_async_scrolling = false;
Core::ArgsParser args_parser;
args_parser.add_option(mach_server_name, "Mach server name", "mach-server-name", 0, "mach_server_name");
args_parser.add_option(wait_for_debugger, "Wait for debugger", "wait-for-debugger");
args_parser.add_option(force_cpu_painting, "Force CPU painting", "force-cpu-painting");
args_parser.add_option(force_fontconfig, "Force using fontconfig for font loading", "force-fontconfig");
args_parser.add_option(disable_async_scrolling, "Disable async scrolling", "disable-async-scrolling");
args_parser.parse(arguments);
if (wait_for_debugger)
Core::Process::wait_for_debugger_and_break();
WebView::platform_init();
auto& font_provider = static_cast<Gfx::PathFontProvider&>(Gfx::FontDatabase::the().install_system_font_provider(make<Gfx::PathFontProvider>()));
if (force_fontconfig)
font_provider.set_name_but_fixme_should_create_custom_system_font_provider("FontConfig"_string);
if (!force_cpu_painting)
Gfx::SkiaBackendContext::initialize_gpu_backend();
Core::EventLoop event_loop;
auto client = TRY(IPC::take_over_accepted_client_from_system_server<Compositor::ConnectionFromClient>(mach_server_name));
(void)client;
(void)disable_async_scrolling;
return event_loop.exec();
}

View file

@ -1,6 +1,7 @@
include(audio)
set(SOURCES
CompositorConnection.cpp
ConnectionFromClient.cpp
ConsoleGlobalEnvironmentExtensions.cpp
DevToolsConsoleClient.cpp

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <WebContent/CompositorConnection.h>
namespace WebContent {
CompositorConnection::CompositorConnection(NonnullOwnPtr<IPC::Transport> transport)
: IPC::ConnectionToServer<CompositorWebContentClientEndpoint, CompositorWebContentServerEndpoint>(*this, move(transport))
{
}
void CompositorConnection::die()
{
}
void CompositorConnection::did_connect()
{
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2026, the Ladybird developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <Compositor/CompositorWebContentClientEndpoint.h>
#include <Compositor/CompositorWebContentServerEndpoint.h>
#include <LibIPC/ConnectionToServer.h>
namespace WebContent {
class CompositorConnection final
: public IPC::ConnectionToServer<CompositorWebContentClientEndpoint, CompositorWebContentServerEndpoint>
, public CompositorWebContentClientEndpoint {
C_OBJECT_ABSTRACT(CompositorConnection)
public:
explicit CompositorConnection(NonnullOwnPtr<IPC::Transport>);
private:
virtual void die() override;
virtual void did_connect() override;
};
}

View file

@ -61,6 +61,7 @@
#include <LibWeb/Worker/WebWorkerClient.h>
#include <LibWebView/Attribute.h>
#include <LibWebView/ViewImplementation.h>
#include <WebContent/CompositorConnection.h>
#include <WebContent/ConnectionFromClient.h>
#include <WebContent/PageClient.h>
#include <WebContent/PageHost.h>
@ -155,6 +156,11 @@ void ConnectionFromClient::connect_to_compositor(IPC::TransportHandle handle)
m_page_host->attach_compositor_ui_client(move(handle));
}
void ConnectionFromClient::connect_to_compositor_process(IPC::TransportHandle handle)
{
(void)handle;
}
void ConnectionFromClient::connect_to_request_server(IPC::TransportHandle handle)
{
if (on_request_server_connection)

View file

@ -10,6 +10,7 @@
#include <AK/HashMap.h>
#include <AK/Queue.h>
#include <AK/RefPtr.h>
#include <AK/SourceLocation.h>
#include <LibCore/AnonymousBuffer.h>
#include <LibGC/Root.h>
@ -68,6 +69,7 @@ private:
virtual void connect_to_request_server(IPC::TransportHandle handle) override;
virtual void connect_to_image_decoder(IPC::TransportHandle handle) override;
virtual void connect_to_compositor(IPC::TransportHandle handle) override;
virtual void connect_to_compositor_process(IPC::TransportHandle handle) override;
virtual void update_system_theme(u64 page_id, Core::AnonymousBuffer) override;
virtual void update_screen_rects(u64 page_id, Vector<Web::DevicePixelRect>, u32) override;
virtual void load_url(u64 page_id, URL::URL) override;
@ -185,6 +187,7 @@ private:
void enqueue_input_event(Web::QueuedInputEvent);
Queue<Web::QueuedInputEvent> m_input_event_queue;
RefPtr<CompositorConnection> m_compositor_connection;
};
}

View file

@ -8,6 +8,7 @@
namespace WebContent {
class CompositorConnection;
class ConnectionFromClient;
class ConsoleGlobalEnvironmentExtensions;
class DevToolsConsoleClient;

View file

@ -35,6 +35,7 @@ endpoint WebContentServer
connect_to_request_server(IPC::TransportHandle handle) =|
connect_to_image_decoder(IPC::TransportHandle handle) =|
connect_to_compositor(IPC::TransportHandle handle) =|
connect_to_compositor_process(IPC::TransportHandle handle) =|
update_system_theme(u64 page_id, Core::AnonymousBuffer theme_buffer) =|
update_screen_rects(u64 page_id, Vector<Web::DevicePixelRect> rects, u32 main_screen_index) =|

View file

@ -99,7 +99,7 @@ else()
)
endif()
set(ladybird_helper_processes ImageDecoder RequestServer WebContent WebWorker)
set(ladybird_helper_processes Compositor ImageDecoder RequestServer WebContent WebWorker)
add_dependencies(ladybird ${ladybird_helper_processes})
# FIXME: Increase support for building targets on Windows