diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 0e7dfaa0f04..079311fe989 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -351,6 +351,8 @@ set(SOURCES Painting/ShadowPainting.cpp Painting/StackingContext.cpp Painting/TextPaintable.cpp + Platform/EventLoopPlugin.cpp + Platform/Timer.cpp RequestIdleCallback/IdleDeadline.cpp ResizeObserver/ResizeObserver.cpp SVG/AttributeNames.cpp diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 43a88e19eda..5de2904b391 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -67,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -286,11 +286,11 @@ Document::Document(HTML::Window& window, const AK::URL& url) HTML::main_thread_event_loop().register_document({}, *this); - m_style_update_timer = Core::Timer::create_single_shot(0, [this] { + m_style_update_timer = Platform::Timer::create_single_shot(0, [this] { update_style(); }); - m_layout_update_timer = Core::Timer::create_single_shot(0, [this] { + m_layout_update_timer = Platform::Timer::create_single_shot(0, [this] { force_layout(); }); } diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h index 894e9011d9c..6eda3550469 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.h +++ b/Userland/Libraries/LibWeb/DOM/Document.h @@ -386,8 +386,8 @@ private: Optional m_active_link_color; Optional m_visited_link_color; - RefPtr m_style_update_timer; - RefPtr m_layout_update_timer; + RefPtr m_style_update_timer; + RefPtr m_layout_update_timer; RefPtr m_parser; bool m_active_parser_was_aborted { false }; diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 1c7718b722e..8b4ec2d74c2 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -351,6 +351,10 @@ struct BorderRadiiData; struct LinearGradientData; } +namespace Web::Platform { +class Timer; +} + namespace Web::RequestIdleCallback { class IdleDeadline; } diff --git a/Userland/Libraries/LibWeb/HTML/AnimationFrameCallbackDriver.h b/Userland/Libraries/LibWeb/HTML/AnimationFrameCallbackDriver.h index 397ab1f3e65..510b2c449c7 100644 --- a/Userland/Libraries/LibWeb/HTML/AnimationFrameCallbackDriver.h +++ b/Userland/Libraries/LibWeb/HTML/AnimationFrameCallbackDriver.h @@ -8,8 +8,8 @@ #include #include -#include #include +#include namespace Web::HTML { @@ -18,7 +18,7 @@ struct AnimationFrameCallbackDriver { AnimationFrameCallbackDriver() { - m_timer = Core::Timer::create_single_shot(16, [] { + m_timer = Platform::Timer::create_single_shot(16, [] { HTML::main_thread_event_loop().schedule(); }); } @@ -57,7 +57,7 @@ struct AnimationFrameCallbackDriver { private: HashMap m_callbacks; IDAllocator m_id_allocator; - RefPtr m_timer; + RefPtr m_timer; }; } diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp index d92e1532e36..28fdb48a01d 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp @@ -229,7 +229,7 @@ BrowsingContext::BrowsingContext(Page& page, HTML::BrowsingContextContainer* con , m_event_handler({}, *this) , m_container(container) { - m_cursor_blink_timer = Core::Timer::construct(500, [this] { + m_cursor_blink_timer = Platform::Timer::create_repeating(500, [this] { if (!is_focused_context()) return; if (m_cursor_position.node() && m_cursor_position.node()->layout_node()) { diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h index ddcd870ea19..1185caf3a95 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -20,6 +19,7 @@ #include #include #include +#include #include namespace Web::HTML { @@ -148,7 +148,7 @@ private: Gfx::IntPoint m_viewport_scroll_offset; DOM::Position m_cursor_position; - RefPtr m_cursor_blink_timer; + RefPtr m_cursor_blink_timer; bool m_cursor_blink_state { false }; HashTable m_viewport_clients; diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp index 34978bc6c33..5602e5545d7 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp @@ -5,8 +5,6 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include #include #include #include @@ -15,6 +13,8 @@ #include #include #include +#include +#include namespace Web::HTML { @@ -29,7 +29,7 @@ EventLoop::~EventLoop() = default; void EventLoop::schedule() { if (!m_system_event_loop_timer) { - m_system_event_loop_timer = Core::Timer::create_single_shot(0, [this] { + m_system_event_loop_timer = Platform::Timer::create_single_shot(0, [this] { process(); }); } @@ -74,13 +74,7 @@ void EventLoop::spin_until(Function goal_condition) // NOTE: This is achieved by returning from the function. // 1. Wait until the condition goal is met. - Core::EventLoop loop; - loop.spin_until([&]() -> bool { - if (goal_condition()) - return true; - - return goal_condition(); - }); + Platform::EventLoopPlugin::the().spin_until(move(goal_condition)); // 7. Stop task, allowing whatever algorithm that invoked it to resume. // NOTE: This is achieved by returning from the function. diff --git a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h index 61685ae6d6d..024666b9924 100644 --- a/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h +++ b/Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h @@ -84,7 +84,7 @@ private: JS::VM* m_vm { nullptr }; - RefPtr m_system_event_loop_timer; + RefPtr m_system_event_loop_timer; // https://html.spec.whatwg.org/#performing-a-microtask-checkpoint bool m_performing_a_microtask_checkpoint { false }; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.cpp index c28d574fad4..6bfa7806fd8 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.cpp @@ -4,14 +4,14 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include #include +#include namespace Web::HTML { HTMLBlinkElement::HTMLBlinkElement(DOM::Document& document, DOM::QualifiedName qualified_name) : HTMLElement(document, move(qualified_name)) - , m_timer(Core::Timer::construct()) + , m_timer(Platform::Timer::create()) { m_timer->set_interval(500); m_timer->on_timeout = [this] { blink(); }; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.h b/Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.h index 39bb55d6114..43097c9cada 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.h @@ -22,7 +22,7 @@ private: void blink(); - NonnullRefPtr m_timer; + NonnullRefPtr m_timer; }; } diff --git a/Userland/Libraries/LibWeb/HTML/Timer.cpp b/Userland/Libraries/LibWeb/HTML/Timer.cpp index b2e75fbdbcb..228b5144816 100644 --- a/Userland/Libraries/LibWeb/HTML/Timer.cpp +++ b/Userland/Libraries/LibWeb/HTML/Timer.cpp @@ -4,9 +4,9 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include #include #include +#include namespace Web::HTML { @@ -20,7 +20,7 @@ Timer::Timer(Window& window, i32 milliseconds, Function callback, i32 id , m_callback(move(callback)) , m_id(id) { - m_timer = Core::Timer::create_single_shot(milliseconds, [this] { + m_timer = Platform::Timer::create_single_shot(milliseconds, [this] { m_callback(); }); } diff --git a/Userland/Libraries/LibWeb/HTML/Timer.h b/Userland/Libraries/LibWeb/HTML/Timer.h index aa2edfb3f5e..2f1aab762e1 100644 --- a/Userland/Libraries/LibWeb/HTML/Timer.h +++ b/Userland/Libraries/LibWeb/HTML/Timer.h @@ -30,7 +30,7 @@ private: virtual void visit_edges(Cell::Visitor&) override; - RefPtr m_timer; + RefPtr m_timer; JS::NonnullGCPtr m_window; Function m_callback; i32 m_id { 0 }; diff --git a/Userland/Libraries/LibWeb/HTML/Window.h b/Userland/Libraries/LibWeb/HTML/Window.h index e1ce9e953b5..587cc8616f6 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.h +++ b/Userland/Libraries/LibWeb/HTML/Window.h @@ -8,7 +8,9 @@ #include #include +#include #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/Loader/ImageLoader.cpp b/Userland/Libraries/LibWeb/Loader/ImageLoader.cpp index dc4e3f35447..ecbe258b406 100644 --- a/Userland/Libraries/LibWeb/Loader/ImageLoader.cpp +++ b/Userland/Libraries/LibWeb/Loader/ImageLoader.cpp @@ -5,18 +5,18 @@ */ #include -#include #include #include #include #include #include +#include namespace Web { ImageLoader::ImageLoader(DOM::Element& owner_element) : m_owner_element(owner_element) - , m_timer(Core::Timer::construct()) + , m_timer(Platform::Timer::create()) { } diff --git a/Userland/Libraries/LibWeb/Loader/ImageLoader.h b/Userland/Libraries/LibWeb/Loader/ImageLoader.h index 23c5344b1f5..03a00cd6821 100644 --- a/Userland/Libraries/LibWeb/Loader/ImageLoader.h +++ b/Userland/Libraries/LibWeb/Loader/ImageLoader.h @@ -7,8 +7,8 @@ #pragma once #include -#include #include +#include namespace Web { @@ -60,7 +60,7 @@ private: size_t m_current_frame_index { 0 }; size_t m_loops_completed { 0 }; LoadingState m_loading_state { LoadingState::Loading }; - NonnullRefPtr m_timer; + NonnullRefPtr m_timer; size_t m_redirects_count { 0 }; }; diff --git a/Userland/Libraries/LibWeb/Loader/Resource.cpp b/Userland/Libraries/LibWeb/Loader/Resource.cpp index e5ac4470505..79c54edcfab 100644 --- a/Userland/Libraries/LibWeb/Loader/Resource.cpp +++ b/Userland/Libraries/LibWeb/Loader/Resource.cpp @@ -6,12 +6,12 @@ #include #include -#include #include #include #include #include #include +#include namespace Web { @@ -168,7 +168,7 @@ void ResourceClient::set_resource(Resource* resource) // This ensures that these callbacks always happen in a consistent way, instead of being invoked // synchronously in some cases, and asynchronously in others. if (resource->is_loaded() || resource->is_failed()) { - Core::deferred_invoke([this, strong_resource = NonnullRefPtr { *m_resource }] { + Platform::EventLoopPlugin::the().deferred_invoke([this, strong_resource = NonnullRefPtr { *m_resource }] { if (m_resource != strong_resource.ptr()) return; diff --git a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp index 98101888d87..d562506ac6d 100644 --- a/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp +++ b/Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp @@ -9,14 +9,14 @@ #include #include #include -#include #include -#include #include #include #include #include #include +#include +#include #ifdef __serenity__ # include @@ -179,7 +179,7 @@ void ResourceLoader::load(LoadRequest& request, Function response_headers; response_headers.set("Content-Type", "text/html; charset=UTF-8"); - deferred_invoke([success_callback = move(success_callback), response_headers = move(response_headers)] { + Platform::EventLoopPlugin::the().deferred_invoke([success_callback = move(success_callback), response_headers = move(response_headers)] { success_callback(String::empty().to_byte_buffer(), response_headers, {}); }); return; @@ -206,7 +206,7 @@ void ResourceLoader::load(LoadRequest& request, Function 0) { - auto timer = Core::Timer::create_single_shot(timeout.value(), nullptr); + auto timer = Platform::Timer::create_single_shot(timeout.value(), nullptr); timer->on_timeout = [timer, protocol_request, timeout_callback = move(timeout_callback)]() mutable { protocol_request->stop(); if (timeout_callback) @@ -312,7 +312,7 @@ void ResourceLoader::load(LoadRequest& request, Function + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Web::Platform { + +EventLoopPlugin* s_the; + +EventLoopPlugin& EventLoopPlugin::the() +{ + VERIFY(s_the); + return *s_the; +} + +void EventLoopPlugin::install(EventLoopPlugin& plugin) +{ + VERIFY(!s_the); + s_the = &plugin; +} + +EventLoopPlugin::~EventLoopPlugin() = default; + +} diff --git a/Userland/Libraries/LibWeb/Platform/EventLoopPlugin.h b/Userland/Libraries/LibWeb/Platform/EventLoopPlugin.h new file mode 100644 index 00000000000..de08e14fb9d --- /dev/null +++ b/Userland/Libraries/LibWeb/Platform/EventLoopPlugin.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::Platform { + +class EventLoopPlugin { +public: + static EventLoopPlugin& the(); + static void install(EventLoopPlugin&); + + virtual ~EventLoopPlugin(); + + virtual void spin_until(Function goal_condition) = 0; + virtual void deferred_invoke(Function) = 0; + virtual NonnullRefPtr create_timer() = 0; +}; + +} diff --git a/Userland/Libraries/LibWeb/Platform/Timer.cpp b/Userland/Libraries/LibWeb/Platform/Timer.cpp new file mode 100644 index 00000000000..d3de49a9583 --- /dev/null +++ b/Userland/Libraries/LibWeb/Platform/Timer.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Web::Platform { + +Timer::~Timer() = default; + +NonnullRefPtr Timer::create() +{ + return EventLoopPlugin::the().create_timer(); +} + +NonnullRefPtr Timer::create_repeating(int interval_ms, Function&& timeout_handler) +{ + auto timer = EventLoopPlugin::the().create_timer(); + timer->set_single_shot(false); + timer->set_interval(interval_ms); + timer->on_timeout = move(timeout_handler); + return timer; +} + +NonnullRefPtr Timer::create_single_shot(int interval_ms, Function&& timeout_handler) +{ + auto timer = EventLoopPlugin::the().create_timer(); + timer->set_single_shot(true); + timer->set_interval(interval_ms); + timer->on_timeout = move(timeout_handler); + return timer; +} + +} diff --git a/Userland/Libraries/LibWeb/Platform/Timer.h b/Userland/Libraries/LibWeb/Platform/Timer.h new file mode 100644 index 00000000000..bde3ca3f3a9 --- /dev/null +++ b/Userland/Libraries/LibWeb/Platform/Timer.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::Platform { + +class Timer : public RefCounted { +public: + static NonnullRefPtr create(); + static NonnullRefPtr create_repeating(int interval_ms, Function&& timeout_handler); + static NonnullRefPtr create_single_shot(int interval_ms, Function&& timeout_handler); + + virtual ~Timer(); + + virtual void start() = 0; + virtual void start(int interval_ms) = 0; + virtual void restart() = 0; + virtual void restart(int interval_ms) = 0; + virtual void stop() = 0; + + virtual void set_active(bool) = 0; + + virtual bool is_active() const = 0; + virtual int interval() const = 0; + virtual void set_interval(int interval_ms) = 0; + + virtual bool is_single_shot() const = 0; + virtual void set_single_shot(bool) = 0; + + Function on_timeout; +}; + +} diff --git a/Userland/Services/WebContent/CMakeLists.txt b/Userland/Services/WebContent/CMakeLists.txt index 3ec41acdb53..8327b155627 100644 --- a/Userland/Services/WebContent/CMakeLists.txt +++ b/Userland/Services/WebContent/CMakeLists.txt @@ -10,11 +10,13 @@ compile_ipc(WebContentClient.ipc WebContentClientEndpoint.h) set(SOURCES ConnectionFromClient.cpp ConsoleGlobalObject.cpp - main.cpp + EventLoopPluginSerenity.cpp PageHost.cpp + TimerSerenity.cpp + WebContentClientEndpoint.h WebContentConsoleClient.cpp WebContentServerEndpoint.h - WebContentClientEndpoint.h + main.cpp ) serenity_bin(WebContent) diff --git a/Userland/Services/WebContent/EventLoopPluginSerenity.cpp b/Userland/Services/WebContent/EventLoopPluginSerenity.cpp new file mode 100644 index 00000000000..15a6c17dd1a --- /dev/null +++ b/Userland/Services/WebContent/EventLoopPluginSerenity.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "EventLoopPluginSerenity.h" +#include "TimerSerenity.h" +#include +#include +#include + +namespace WebContent { + +EventLoopPluginSerenity::EventLoopPluginSerenity() = default; +EventLoopPluginSerenity::~EventLoopPluginSerenity() = default; + +void EventLoopPluginSerenity::spin_until(Function goal_condition) +{ + Core::EventLoop::current().spin_until(move(goal_condition)); +} + +void EventLoopPluginSerenity::deferred_invoke(Function function) +{ + VERIFY(function); + Core::deferred_invoke(move(function)); +} + +NonnullRefPtr EventLoopPluginSerenity::create_timer() +{ + return TimerSerenity::create(); +} + +} diff --git a/Userland/Services/WebContent/EventLoopPluginSerenity.h b/Userland/Services/WebContent/EventLoopPluginSerenity.h new file mode 100644 index 00000000000..0493ac7ab1d --- /dev/null +++ b/Userland/Services/WebContent/EventLoopPluginSerenity.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace WebContent { + +class EventLoopPluginSerenity final : public Web::Platform::EventLoopPlugin { +public: + EventLoopPluginSerenity(); + virtual ~EventLoopPluginSerenity() override; + + virtual void spin_until(Function goal_condition) override; + virtual void deferred_invoke(Function) override; + virtual NonnullRefPtr create_timer() override; +}; + +} diff --git a/Userland/Services/WebContent/TimerSerenity.cpp b/Userland/Services/WebContent/TimerSerenity.cpp new file mode 100644 index 00000000000..a702ba2eca7 --- /dev/null +++ b/Userland/Services/WebContent/TimerSerenity.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "TimerSerenity.h" +#include +#include + +namespace WebContent { + +NonnullRefPtr TimerSerenity::create() +{ + return adopt_ref(*new TimerSerenity); +} + +TimerSerenity::TimerSerenity() + : m_timer(Core::Timer::construct()) +{ + m_timer->on_timeout = [this] { + if (on_timeout) + on_timeout(); + }; +} + +TimerSerenity::~TimerSerenity() = default; + +void TimerSerenity::start() +{ + m_timer->start(); +} + +void TimerSerenity::start(int interval_ms) +{ + m_timer->start(interval_ms); +} + +void TimerSerenity::restart() +{ + m_timer->restart(); +} + +void TimerSerenity::restart(int interval_ms) +{ + m_timer->restart(interval_ms); +} + +void TimerSerenity::stop() +{ + m_timer->stop(); +} + +void TimerSerenity::set_active(bool active) +{ + m_timer->set_active(active); +} + +bool TimerSerenity::is_active() const +{ + return m_timer->is_active(); +} + +int TimerSerenity::interval() const +{ + return m_timer->interval(); +} + +void TimerSerenity::set_interval(int interval_ms) +{ + m_timer->set_interval(interval_ms); +} + +bool TimerSerenity::is_single_shot() const +{ + return m_timer->is_single_shot(); +} + +void TimerSerenity::set_single_shot(bool single_shot) +{ + m_timer->set_single_shot(single_shot); +} + +} diff --git a/Userland/Services/WebContent/TimerSerenity.h b/Userland/Services/WebContent/TimerSerenity.h new file mode 100644 index 00000000000..d0f92008391 --- /dev/null +++ b/Userland/Services/WebContent/TimerSerenity.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace WebContent { + +class TimerSerenity final : public Web::Platform::Timer { +public: + static NonnullRefPtr create(); + + virtual ~TimerSerenity(); + + virtual void start() override; + virtual void start(int interval_ms) override; + virtual void restart() override; + virtual void restart(int interval_ms) override; + virtual void stop() override; + + virtual void set_active(bool) override; + + virtual bool is_active() const override; + virtual int interval() const override; + virtual void set_interval(int interval_ms) override; + + virtual bool is_single_shot() const override; + virtual void set_single_shot(bool) override; + +private: + TimerSerenity(); + + NonnullRefPtr m_timer; +}; + +} diff --git a/Userland/Services/WebContent/main.cpp b/Userland/Services/WebContent/main.cpp index 9db9c3ed408..5a06e6e00c5 100644 --- a/Userland/Services/WebContent/main.cpp +++ b/Userland/Services/WebContent/main.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include "EventLoopPluginSerenity.h" #include #include #include @@ -11,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +30,8 @@ ErrorOr serenity_main(Main::Arguments) TRY(Core::System::unveil("/tmp/user/%uid/portal/websocket", "rw")); TRY(Core::System::unveil(nullptr, nullptr)); + Web::Platform::EventLoopPlugin::install(*new WebContent::EventLoopPluginSerenity); + Web::ImageDecoding::Decoder::initialize(WebView::ImageDecoderClientAdapter::create()); Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create())); Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create()));