From 9567e211e7c0ae27a65c1f23c4fd9071e8c35e29 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 7 Sep 2022 20:30:31 +0200 Subject: LibWeb+WebContent: Add abstraction layer for event loop and timers Instead of using Core::EventLoop and Core::Timer directly, LibWeb now goes through a Web::Platform abstraction layer instead. This will allow us to plug in Qt's event loop (and QTimer) over in Ladybird, to avoid having to deal with multiple event loops. --- Userland/Libraries/LibWeb/CMakeLists.txt | 2 ++ Userland/Libraries/LibWeb/DOM/Document.cpp | 6 ++-- Userland/Libraries/LibWeb/DOM/Document.h | 4 +-- Userland/Libraries/LibWeb/Forward.h | 4 +++ .../LibWeb/HTML/AnimationFrameCallbackDriver.h | 6 ++-- Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp | 2 +- Userland/Libraries/LibWeb/HTML/BrowsingContext.h | 4 +-- .../Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp | 14 +++----- .../Libraries/LibWeb/HTML/EventLoop/EventLoop.h | 2 +- .../Libraries/LibWeb/HTML/HTMLBlinkElement.cpp | 4 +-- Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.h | 2 +- Userland/Libraries/LibWeb/HTML/Timer.cpp | 4 +-- Userland/Libraries/LibWeb/HTML/Timer.h | 2 +- Userland/Libraries/LibWeb/HTML/Window.h | 2 ++ Userland/Libraries/LibWeb/Loader/ImageLoader.cpp | 4 +-- Userland/Libraries/LibWeb/Loader/ImageLoader.h | 4 +-- Userland/Libraries/LibWeb/Loader/Resource.cpp | 4 +-- .../Libraries/LibWeb/Loader/ResourceLoader.cpp | 12 +++---- .../Libraries/LibWeb/Platform/EventLoopPlugin.cpp | 28 +++++++++++++++ .../Libraries/LibWeb/Platform/EventLoopPlugin.h | 26 ++++++++++++++ Userland/Libraries/LibWeb/Platform/Timer.cpp | 38 ++++++++++++++++++++ Userland/Libraries/LibWeb/Platform/Timer.h | 40 ++++++++++++++++++++++ 22 files changed, 174 insertions(+), 40 deletions(-) create mode 100644 Userland/Libraries/LibWeb/Platform/EventLoopPlugin.cpp create mode 100644 Userland/Libraries/LibWeb/Platform/EventLoopPlugin.h create mode 100644 Userland/Libraries/LibWeb/Platform/Timer.cpp create mode 100644 Userland/Libraries/LibWeb/Platform/Timer.h (limited to 'Userland/Libraries/LibWeb') diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 0e7dfaa0f0..079311fe98 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 43a88e19ed..5de2904b39 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 894e9011d9..6eda355046 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 1c7718b722..8b4ec2d74c 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 397ab1f3e6..510b2c449c 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 d92e1532e3..28fdb48a01 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 ddcd870ea1..1185caf3a9 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 34978bc6c3..5602e5545d 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 61685ae6d6..024666b992 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 c28d574fad..6bfa7806fd 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 39bb55d611..43097c9cad 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 b2e75fbdbc..228b514481 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 aa2edfb3f5..2f1aab762e 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 e1ce9e953b..587cc8616f 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 dc4e3f3544..ecbe258b40 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 23c5344b1f..03a00cd682 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 e5ac447050..79c54edcfa 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 98101888d8..d562506ac6 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 0000000000..de08e14fb9 --- /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 0000000000..d3de49a958 --- /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 0000000000..bde3ca3f3a --- /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; +}; + +} -- cgit v1.2.3