Quellcode durchsuchen

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.
Andreas Kling vor 2 Jahren
Ursprung
Commit
9567e211e7
28 geänderte Dateien mit 365 neuen und 42 gelöschten Zeilen
  1. 2 0
      Userland/Libraries/LibWeb/CMakeLists.txt
  2. 3 3
      Userland/Libraries/LibWeb/DOM/Document.cpp
  3. 2 2
      Userland/Libraries/LibWeb/DOM/Document.h
  4. 4 0
      Userland/Libraries/LibWeb/Forward.h
  5. 3 3
      Userland/Libraries/LibWeb/HTML/AnimationFrameCallbackDriver.h
  6. 1 1
      Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp
  7. 2 2
      Userland/Libraries/LibWeb/HTML/BrowsingContext.h
  8. 4 10
      Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp
  9. 1 1
      Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h
  10. 2 2
      Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.cpp
  11. 1 1
      Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.h
  12. 2 2
      Userland/Libraries/LibWeb/HTML/Timer.cpp
  13. 1 1
      Userland/Libraries/LibWeb/HTML/Timer.h
  14. 2 0
      Userland/Libraries/LibWeb/HTML/Window.h
  15. 2 2
      Userland/Libraries/LibWeb/Loader/ImageLoader.cpp
  16. 2 2
      Userland/Libraries/LibWeb/Loader/ImageLoader.h
  17. 2 2
      Userland/Libraries/LibWeb/Loader/Resource.cpp
  18. 6 6
      Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp
  19. 28 0
      Userland/Libraries/LibWeb/Platform/EventLoopPlugin.cpp
  20. 26 0
      Userland/Libraries/LibWeb/Platform/EventLoopPlugin.h
  21. 38 0
      Userland/Libraries/LibWeb/Platform/Timer.cpp
  22. 40 0
      Userland/Libraries/LibWeb/Platform/Timer.h
  23. 4 2
      Userland/Services/WebContent/CMakeLists.txt
  24. 34 0
      Userland/Services/WebContent/EventLoopPluginSerenity.cpp
  25. 23 0
      Userland/Services/WebContent/EventLoopPluginSerenity.h
  26. 84 0
      Userland/Services/WebContent/TimerSerenity.cpp
  27. 42 0
      Userland/Services/WebContent/TimerSerenity.h
  28. 4 0
      Userland/Services/WebContent/main.cpp

+ 2 - 0
Userland/Libraries/LibWeb/CMakeLists.txt

@@ -351,6 +351,8 @@ set(SOURCES
     Painting/ShadowPainting.cpp
     Painting/ShadowPainting.cpp
     Painting/StackingContext.cpp
     Painting/StackingContext.cpp
     Painting/TextPaintable.cpp
     Painting/TextPaintable.cpp
+    Platform/EventLoopPlugin.cpp
+    Platform/Timer.cpp
     RequestIdleCallback/IdleDeadline.cpp
     RequestIdleCallback/IdleDeadline.cpp
     ResizeObserver/ResizeObserver.cpp
     ResizeObserver/ResizeObserver.cpp
     SVG/AttributeNames.cpp
     SVG/AttributeNames.cpp

+ 3 - 3
Userland/Libraries/LibWeb/DOM/Document.cpp

@@ -10,7 +10,6 @@
 #include <AK/CharacterTypes.h>
 #include <AK/CharacterTypes.h>
 #include <AK/StringBuilder.h>
 #include <AK/StringBuilder.h>
 #include <AK/Utf8View.h>
 #include <AK/Utf8View.h>
-#include <LibCore/Timer.h>
 #include <LibJS/Interpreter.h>
 #include <LibJS/Interpreter.h>
 #include <LibJS/Parser.h>
 #include <LibJS/Parser.h>
 #include <LibJS/Runtime/FunctionObject.h>
 #include <LibJS/Runtime/FunctionObject.h>
@@ -67,6 +66,7 @@
 #include <LibWeb/Layout/TreeBuilder.h>
 #include <LibWeb/Layout/TreeBuilder.h>
 #include <LibWeb/Namespace.h>
 #include <LibWeb/Namespace.h>
 #include <LibWeb/Page/Page.h>
 #include <LibWeb/Page/Page.h>
+#include <LibWeb/Platform/Timer.h>
 #include <LibWeb/SVG/TagNames.h>
 #include <LibWeb/SVG/TagNames.h>
 #include <LibWeb/UIEvents/EventNames.h>
 #include <LibWeb/UIEvents/EventNames.h>
 #include <LibWeb/UIEvents/FocusEvent.h>
 #include <LibWeb/UIEvents/FocusEvent.h>
@@ -286,11 +286,11 @@ Document::Document(HTML::Window& window, const AK::URL& url)
 
 
     HTML::main_thread_event_loop().register_document({}, *this);
     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();
         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();
         force_layout();
     });
     });
 }
 }

+ 2 - 2
Userland/Libraries/LibWeb/DOM/Document.h

@@ -386,8 +386,8 @@ private:
     Optional<Color> m_active_link_color;
     Optional<Color> m_active_link_color;
     Optional<Color> m_visited_link_color;
     Optional<Color> m_visited_link_color;
 
 
-    RefPtr<Core::Timer> m_style_update_timer;
-    RefPtr<Core::Timer> m_layout_update_timer;
+    RefPtr<Platform::Timer> m_style_update_timer;
+    RefPtr<Platform::Timer> m_layout_update_timer;
 
 
     RefPtr<HTML::HTMLParser> m_parser;
     RefPtr<HTML::HTMLParser> m_parser;
     bool m_active_parser_was_aborted { false };
     bool m_active_parser_was_aborted { false };

+ 4 - 0
Userland/Libraries/LibWeb/Forward.h

@@ -351,6 +351,10 @@ struct BorderRadiiData;
 struct LinearGradientData;
 struct LinearGradientData;
 }
 }
 
 
+namespace Web::Platform {
+class Timer;
+}
+
 namespace Web::RequestIdleCallback {
 namespace Web::RequestIdleCallback {
 class IdleDeadline;
 class IdleDeadline;
 }
 }

+ 3 - 3
Userland/Libraries/LibWeb/HTML/AnimationFrameCallbackDriver.h

@@ -8,8 +8,8 @@
 
 
 #include <AK/Function.h>
 #include <AK/Function.h>
 #include <AK/IDAllocator.h>
 #include <AK/IDAllocator.h>
-#include <LibCore/Timer.h>
 #include <LibWeb/HTML/EventLoop/EventLoop.h>
 #include <LibWeb/HTML/EventLoop/EventLoop.h>
+#include <LibWeb/Platform/Timer.h>
 
 
 namespace Web::HTML {
 namespace Web::HTML {
 
 
@@ -18,7 +18,7 @@ struct AnimationFrameCallbackDriver {
 
 
     AnimationFrameCallbackDriver()
     AnimationFrameCallbackDriver()
     {
     {
-        m_timer = Core::Timer::create_single_shot(16, [] {
+        m_timer = Platform::Timer::create_single_shot(16, [] {
             HTML::main_thread_event_loop().schedule();
             HTML::main_thread_event_loop().schedule();
         });
         });
     }
     }
@@ -57,7 +57,7 @@ struct AnimationFrameCallbackDriver {
 private:
 private:
     HashMap<i32, Callback> m_callbacks;
     HashMap<i32, Callback> m_callbacks;
     IDAllocator m_id_allocator;
     IDAllocator m_id_allocator;
-    RefPtr<Core::Timer> m_timer;
+    RefPtr<Platform::Timer> m_timer;
 };
 };
 
 
 }
 }

+ 1 - 1
Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp

@@ -229,7 +229,7 @@ BrowsingContext::BrowsingContext(Page& page, HTML::BrowsingContextContainer* con
     , m_event_handler({}, *this)
     , m_event_handler({}, *this)
     , m_container(container)
     , 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())
         if (!is_focused_context())
             return;
             return;
         if (m_cursor_position.node() && m_cursor_position.node()->layout_node()) {
         if (m_cursor_position.node() && m_cursor_position.node()->layout_node()) {

+ 2 - 2
Userland/Libraries/LibWeb/HTML/BrowsingContext.h

@@ -10,7 +10,6 @@
 #include <AK/Noncopyable.h>
 #include <AK/Noncopyable.h>
 #include <AK/RefPtr.h>
 #include <AK/RefPtr.h>
 #include <AK/WeakPtr.h>
 #include <AK/WeakPtr.h>
-#include <LibCore/Timer.h>
 #include <LibGfx/Bitmap.h>
 #include <LibGfx/Bitmap.h>
 #include <LibGfx/Rect.h>
 #include <LibGfx/Rect.h>
 #include <LibGfx/Size.h>
 #include <LibGfx/Size.h>
@@ -20,6 +19,7 @@
 #include <LibWeb/HTML/SessionHistoryEntry.h>
 #include <LibWeb/HTML/SessionHistoryEntry.h>
 #include <LibWeb/Loader/FrameLoader.h>
 #include <LibWeb/Loader/FrameLoader.h>
 #include <LibWeb/Page/EventHandler.h>
 #include <LibWeb/Page/EventHandler.h>
+#include <LibWeb/Platform/Timer.h>
 #include <LibWeb/TreeNode.h>
 #include <LibWeb/TreeNode.h>
 
 
 namespace Web::HTML {
 namespace Web::HTML {
@@ -148,7 +148,7 @@ private:
     Gfx::IntPoint m_viewport_scroll_offset;
     Gfx::IntPoint m_viewport_scroll_offset;
 
 
     DOM::Position m_cursor_position;
     DOM::Position m_cursor_position;
-    RefPtr<Core::Timer> m_cursor_blink_timer;
+    RefPtr<Platform::Timer> m_cursor_blink_timer;
     bool m_cursor_blink_state { false };
     bool m_cursor_blink_state { false };
 
 
     HashTable<ViewportClient*> m_viewport_clients;
     HashTable<ViewportClient*> m_viewport_clients;

+ 4 - 10
Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.cpp

@@ -5,8 +5,6 @@
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
 
 
-#include <LibCore/EventLoop.h>
-#include <LibCore/Timer.h>
 #include <LibJS/Runtime/VM.h>
 #include <LibJS/Runtime/VM.h>
 #include <LibWeb/Bindings/MainThreadVM.h>
 #include <LibWeb/Bindings/MainThreadVM.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
@@ -15,6 +13,8 @@
 #include <LibWeb/HTML/Scripting/Environments.h>
 #include <LibWeb/HTML/Scripting/Environments.h>
 #include <LibWeb/HTML/Window.h>
 #include <LibWeb/HTML/Window.h>
 #include <LibWeb/HighResolutionTime/Performance.h>
 #include <LibWeb/HighResolutionTime/Performance.h>
+#include <LibWeb/Platform/EventLoopPlugin.h>
+#include <LibWeb/Platform/Timer.h>
 
 
 namespace Web::HTML {
 namespace Web::HTML {
 
 
@@ -29,7 +29,7 @@ EventLoop::~EventLoop() = default;
 void EventLoop::schedule()
 void EventLoop::schedule()
 {
 {
     if (!m_system_event_loop_timer) {
     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();
             process();
         });
         });
     }
     }
@@ -74,13 +74,7 @@ void EventLoop::spin_until(Function<bool()> goal_condition)
     //       NOTE: This is achieved by returning from the function.
     //       NOTE: This is achieved by returning from the function.
 
 
     //    1. Wait until the condition goal is met.
     //    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.
     // 7. Stop task, allowing whatever algorithm that invoked it to resume.
     // NOTE: This is achieved by returning from the function.
     // NOTE: This is achieved by returning from the function.

+ 1 - 1
Userland/Libraries/LibWeb/HTML/EventLoop/EventLoop.h

@@ -84,7 +84,7 @@ private:
 
 
     JS::VM* m_vm { nullptr };
     JS::VM* m_vm { nullptr };
 
 
-    RefPtr<Core::Timer> m_system_event_loop_timer;
+    RefPtr<Platform::Timer> m_system_event_loop_timer;
 
 
     // https://html.spec.whatwg.org/#performing-a-microtask-checkpoint
     // https://html.spec.whatwg.org/#performing-a-microtask-checkpoint
     bool m_performing_a_microtask_checkpoint { false };
     bool m_performing_a_microtask_checkpoint { false };

+ 2 - 2
Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.cpp

@@ -4,14 +4,14 @@
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
 
 
-#include <LibCore/Timer.h>
 #include <LibWeb/HTML/HTMLBlinkElement.h>
 #include <LibWeb/HTML/HTMLBlinkElement.h>
+#include <LibWeb/Platform/Timer.h>
 
 
 namespace Web::HTML {
 namespace Web::HTML {
 
 
 HTMLBlinkElement::HTMLBlinkElement(DOM::Document& document, DOM::QualifiedName qualified_name)
 HTMLBlinkElement::HTMLBlinkElement(DOM::Document& document, DOM::QualifiedName qualified_name)
     : HTMLElement(document, move(qualified_name))
     : HTMLElement(document, move(qualified_name))
-    , m_timer(Core::Timer::construct())
+    , m_timer(Platform::Timer::create())
 {
 {
     m_timer->set_interval(500);
     m_timer->set_interval(500);
     m_timer->on_timeout = [this] { blink(); };
     m_timer->on_timeout = [this] { blink(); };

+ 1 - 1
Userland/Libraries/LibWeb/HTML/HTMLBlinkElement.h

@@ -22,7 +22,7 @@ private:
 
 
     void blink();
     void blink();
 
 
-    NonnullRefPtr<Core::Timer> m_timer;
+    NonnullRefPtr<Platform::Timer> m_timer;
 };
 };
 
 
 }
 }

+ 2 - 2
Userland/Libraries/LibWeb/HTML/Timer.cpp

@@ -4,9 +4,9 @@
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
 
 
-#include <LibCore/Timer.h>
 #include <LibWeb/HTML/Timer.h>
 #include <LibWeb/HTML/Timer.h>
 #include <LibWeb/HTML/Window.h>
 #include <LibWeb/HTML/Window.h>
+#include <LibWeb/Platform/Timer.h>
 
 
 namespace Web::HTML {
 namespace Web::HTML {
 
 
@@ -20,7 +20,7 @@ Timer::Timer(Window& window, i32 milliseconds, Function<void()> callback, i32 id
     , m_callback(move(callback))
     , m_callback(move(callback))
     , m_id(id)
     , m_id(id)
 {
 {
-    m_timer = Core::Timer::create_single_shot(milliseconds, [this] {
+    m_timer = Platform::Timer::create_single_shot(milliseconds, [this] {
         m_callback();
         m_callback();
     });
     });
 }
 }

+ 1 - 1
Userland/Libraries/LibWeb/HTML/Timer.h

@@ -30,7 +30,7 @@ private:
 
 
     virtual void visit_edges(Cell::Visitor&) override;
     virtual void visit_edges(Cell::Visitor&) override;
 
 
-    RefPtr<Core::Timer> m_timer;
+    RefPtr<Platform::Timer> m_timer;
     JS::NonnullGCPtr<Window> m_window;
     JS::NonnullGCPtr<Window> m_window;
     Function<void()> m_callback;
     Function<void()> m_callback;
     i32 m_id { 0 };
     i32 m_id { 0 };

+ 2 - 0
Userland/Libraries/LibWeb/HTML/Window.h

@@ -8,7 +8,9 @@
 
 
 #include <AK/Badge.h>
 #include <AK/Badge.h>
 #include <AK/IDAllocator.h>
 #include <AK/IDAllocator.h>
+#include <AK/NonnullRefPtrVector.h>
 #include <AK/RefPtr.h>
 #include <AK/RefPtr.h>
+#include <AK/TypeCasts.h>
 #include <AK/URL.h>
 #include <AK/URL.h>
 #include <LibJS/Heap/Heap.h>
 #include <LibJS/Heap/Heap.h>
 #include <LibWeb/Bindings/CrossOriginAbstractOperations.h>
 #include <LibWeb/Bindings/CrossOriginAbstractOperations.h>

+ 2 - 2
Userland/Libraries/LibWeb/Loader/ImageLoader.cpp

@@ -5,18 +5,18 @@
  */
  */
 
 
 #include <AK/Debug.h>
 #include <AK/Debug.h>
-#include <LibCore/Timer.h>
 #include <LibGfx/Bitmap.h>
 #include <LibGfx/Bitmap.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Element.h>
 #include <LibWeb/DOM/Element.h>
 #include <LibWeb/Loader/ImageLoader.h>
 #include <LibWeb/Loader/ImageLoader.h>
 #include <LibWeb/Loader/ResourceLoader.h>
 #include <LibWeb/Loader/ResourceLoader.h>
+#include <LibWeb/Platform/Timer.h>
 
 
 namespace Web {
 namespace Web {
 
 
 ImageLoader::ImageLoader(DOM::Element& owner_element)
 ImageLoader::ImageLoader(DOM::Element& owner_element)
     : m_owner_element(owner_element)
     : m_owner_element(owner_element)
-    , m_timer(Core::Timer::construct())
+    , m_timer(Platform::Timer::create())
 {
 {
 }
 }
 
 

+ 2 - 2
Userland/Libraries/LibWeb/Loader/ImageLoader.h

@@ -7,8 +7,8 @@
 #pragma once
 #pragma once
 
 
 #include <AK/Function.h>
 #include <AK/Function.h>
-#include <LibCore/Timer.h>
 #include <LibWeb/Loader/ImageResource.h>
 #include <LibWeb/Loader/ImageResource.h>
+#include <LibWeb/Platform/Timer.h>
 
 
 namespace Web {
 namespace Web {
 
 
@@ -60,7 +60,7 @@ private:
     size_t m_current_frame_index { 0 };
     size_t m_current_frame_index { 0 };
     size_t m_loops_completed { 0 };
     size_t m_loops_completed { 0 };
     LoadingState m_loading_state { LoadingState::Loading };
     LoadingState m_loading_state { LoadingState::Loading };
-    NonnullRefPtr<Core::Timer> m_timer;
+    NonnullRefPtr<Platform::Timer> m_timer;
     size_t m_redirects_count { 0 };
     size_t m_redirects_count { 0 };
 };
 };
 
 

+ 2 - 2
Userland/Libraries/LibWeb/Loader/Resource.cpp

@@ -6,12 +6,12 @@
 
 
 #include <AK/Debug.h>
 #include <AK/Debug.h>
 #include <AK/Function.h>
 #include <AK/Function.h>
-#include <LibCore/EventLoop.h>
 #include <LibCore/MimeData.h>
 #include <LibCore/MimeData.h>
 #include <LibTextCodec/Decoder.h>
 #include <LibTextCodec/Decoder.h>
 #include <LibWeb/HTML/HTMLImageElement.h>
 #include <LibWeb/HTML/HTMLImageElement.h>
 #include <LibWeb/Loader/Resource.h>
 #include <LibWeb/Loader/Resource.h>
 #include <LibWeb/Loader/ResourceLoader.h>
 #include <LibWeb/Loader/ResourceLoader.h>
+#include <LibWeb/Platform/EventLoopPlugin.h>
 
 
 namespace Web {
 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
         // This ensures that these callbacks always happen in a consistent way, instead of being invoked
         // synchronously in some cases, and asynchronously in others.
         // synchronously in some cases, and asynchronously in others.
         if (resource->is_loaded() || resource->is_failed()) {
         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())
                 if (m_resource != strong_resource.ptr())
                     return;
                     return;
 
 

+ 6 - 6
Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp

@@ -9,14 +9,14 @@
 #include <AK/Debug.h>
 #include <AK/Debug.h>
 #include <AK/JsonObject.h>
 #include <AK/JsonObject.h>
 #include <LibCore/ElapsedTimer.h>
 #include <LibCore/ElapsedTimer.h>
-#include <LibCore/EventLoop.h>
 #include <LibCore/File.h>
 #include <LibCore/File.h>
-#include <LibCore/Timer.h>
 #include <LibWeb/Loader/ContentFilter.h>
 #include <LibWeb/Loader/ContentFilter.h>
 #include <LibWeb/Loader/LoadRequest.h>
 #include <LibWeb/Loader/LoadRequest.h>
 #include <LibWeb/Loader/ProxyMappings.h>
 #include <LibWeb/Loader/ProxyMappings.h>
 #include <LibWeb/Loader/Resource.h>
 #include <LibWeb/Loader/Resource.h>
 #include <LibWeb/Loader/ResourceLoader.h>
 #include <LibWeb/Loader/ResourceLoader.h>
+#include <LibWeb/Platform/EventLoopPlugin.h>
+#include <LibWeb/Platform/Timer.h>
 
 
 #ifdef __serenity__
 #ifdef __serenity__
 #    include <serenity.h>
 #    include <serenity.h>
@@ -179,7 +179,7 @@ void ResourceLoader::load(LoadRequest& request, Function<void(ReadonlyBytes, Has
         HashMap<String, String, CaseInsensitiveStringTraits> response_headers;
         HashMap<String, String, CaseInsensitiveStringTraits> response_headers;
         response_headers.set("Content-Type", "text/html; charset=UTF-8");
         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, {});
             success_callback(String::empty().to_byte_buffer(), response_headers, {});
         });
         });
         return;
         return;
@@ -206,7 +206,7 @@ void ResourceLoader::load(LoadRequest& request, Function<void(ReadonlyBytes, Has
         }
         }
 
 
         log_success(request);
         log_success(request);
-        deferred_invoke([data = move(data), success_callback = move(success_callback)] {
+        Platform::EventLoopPlugin::the().deferred_invoke([data = move(data), success_callback = move(success_callback)] {
             success_callback(data, {}, {});
             success_callback(data, {}, {});
         });
         });
         return;
         return;
@@ -284,7 +284,7 @@ void ResourceLoader::load(LoadRequest& request, Function<void(ReadonlyBytes, Has
         }
         }
 
 
         if (timeout.has_value() && timeout.value() > 0) {
         if (timeout.has_value() && timeout.value() > 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 {
             timer->on_timeout = [timer, protocol_request, timeout_callback = move(timeout_callback)]() mutable {
                 protocol_request->stop();
                 protocol_request->stop();
                 if (timeout_callback)
                 if (timeout_callback)
@@ -312,7 +312,7 @@ void ResourceLoader::load(LoadRequest& request, Function<void(ReadonlyBytes, Has
             }
             }
             log_success(request);
             log_success(request);
             success_callback(payload, response_headers, status_code);
             success_callback(payload, response_headers, status_code);
-            deferred_invoke([this, &protocol_request] {
+            Platform::EventLoopPlugin::the().deferred_invoke([this, &protocol_request] {
                 m_active_requests.remove(protocol_request);
                 m_active_requests.remove(protocol_request);
             });
             });
         };
         };

+ 28 - 0
Userland/Libraries/LibWeb/Platform/EventLoopPlugin.cpp

@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Function.h>
+#include <LibWeb/Platform/EventLoopPlugin.h>
+
+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;
+
+}

+ 26 - 0
Userland/Libraries/LibWeb/Platform/EventLoopPlugin.h

@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Forward.h>
+#include <LibWeb/Forward.h>
+
+namespace Web::Platform {
+
+class EventLoopPlugin {
+public:
+    static EventLoopPlugin& the();
+    static void install(EventLoopPlugin&);
+
+    virtual ~EventLoopPlugin();
+
+    virtual void spin_until(Function<bool()> goal_condition) = 0;
+    virtual void deferred_invoke(Function<void()>) = 0;
+    virtual NonnullRefPtr<Timer> create_timer() = 0;
+};
+
+}

+ 38 - 0
Userland/Libraries/LibWeb/Platform/Timer.cpp

@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/NonnullRefPtr.h>
+#include <LibWeb/Platform/EventLoopPlugin.h>
+#include <LibWeb/Platform/Timer.h>
+
+namespace Web::Platform {
+
+Timer::~Timer() = default;
+
+NonnullRefPtr<Timer> Timer::create()
+{
+    return EventLoopPlugin::the().create_timer();
+}
+
+NonnullRefPtr<Timer> Timer::create_repeating(int interval_ms, Function<void()>&& 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> Timer::create_single_shot(int interval_ms, Function<void()>&& 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;
+}
+
+}

+ 40 - 0
Userland/Libraries/LibWeb/Platform/Timer.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Function.h>
+#include <AK/RefCounted.h>
+
+namespace Web::Platform {
+
+class Timer : public RefCounted<Timer> {
+public:
+    static NonnullRefPtr<Timer> create();
+    static NonnullRefPtr<Timer> create_repeating(int interval_ms, Function<void()>&& timeout_handler);
+    static NonnullRefPtr<Timer> create_single_shot(int interval_ms, Function<void()>&& 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<void()> on_timeout;
+};
+
+}

+ 4 - 2
Userland/Services/WebContent/CMakeLists.txt

@@ -10,11 +10,13 @@ compile_ipc(WebContentClient.ipc WebContentClientEndpoint.h)
 set(SOURCES
 set(SOURCES
     ConnectionFromClient.cpp
     ConnectionFromClient.cpp
     ConsoleGlobalObject.cpp
     ConsoleGlobalObject.cpp
-    main.cpp
+    EventLoopPluginSerenity.cpp
     PageHost.cpp
     PageHost.cpp
+    TimerSerenity.cpp
+    WebContentClientEndpoint.h
     WebContentConsoleClient.cpp
     WebContentConsoleClient.cpp
     WebContentServerEndpoint.h
     WebContentServerEndpoint.h
-    WebContentClientEndpoint.h
+    main.cpp
 )
 )
 
 
 serenity_bin(WebContent)
 serenity_bin(WebContent)

+ 34 - 0
Userland/Services/WebContent/EventLoopPluginSerenity.cpp

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "EventLoopPluginSerenity.h"
+#include "TimerSerenity.h"
+#include <AK/Function.h>
+#include <AK/NonnullRefPtr.h>
+#include <LibCore/EventLoop.h>
+
+namespace WebContent {
+
+EventLoopPluginSerenity::EventLoopPluginSerenity() = default;
+EventLoopPluginSerenity::~EventLoopPluginSerenity() = default;
+
+void EventLoopPluginSerenity::spin_until(Function<bool()> goal_condition)
+{
+    Core::EventLoop::current().spin_until(move(goal_condition));
+}
+
+void EventLoopPluginSerenity::deferred_invoke(Function<void()> function)
+{
+    VERIFY(function);
+    Core::deferred_invoke(move(function));
+}
+
+NonnullRefPtr<Web::Platform::Timer> EventLoopPluginSerenity::create_timer()
+{
+    return TimerSerenity::create();
+}
+
+}

+ 23 - 0
Userland/Services/WebContent/EventLoopPluginSerenity.h

@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibWeb/Platform/EventLoopPlugin.h>
+
+namespace WebContent {
+
+class EventLoopPluginSerenity final : public Web::Platform::EventLoopPlugin {
+public:
+    EventLoopPluginSerenity();
+    virtual ~EventLoopPluginSerenity() override;
+
+    virtual void spin_until(Function<bool()> goal_condition) override;
+    virtual void deferred_invoke(Function<void()>) override;
+    virtual NonnullRefPtr<Web::Platform::Timer> create_timer() override;
+};
+
+}

+ 84 - 0
Userland/Services/WebContent/TimerSerenity.cpp

@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "TimerSerenity.h"
+#include <AK/NonnullRefPtr.h>
+#include <LibCore/Timer.h>
+
+namespace WebContent {
+
+NonnullRefPtr<TimerSerenity> 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);
+}
+
+}

+ 42 - 0
Userland/Services/WebContent/TimerSerenity.h

@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/NonnullRefPtr.h>
+#include <LibCore/Forward.h>
+#include <LibWeb/Platform/Timer.h>
+
+namespace WebContent {
+
+class TimerSerenity final : public Web::Platform::Timer {
+public:
+    static NonnullRefPtr<TimerSerenity> 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<Core::Timer> m_timer;
+};
+
+}

+ 4 - 0
Userland/Services/WebContent/main.cpp

@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  * SPDX-License-Identifier: BSD-2-Clause
  */
  */
 
 
+#include "EventLoopPluginSerenity.h"
 #include <LibCore/EventLoop.h>
 #include <LibCore/EventLoop.h>
 #include <LibCore/LocalServer.h>
 #include <LibCore/LocalServer.h>
 #include <LibCore/System.h>
 #include <LibCore/System.h>
@@ -11,6 +12,7 @@
 #include <LibMain/Main.h>
 #include <LibMain/Main.h>
 #include <LibWeb/ImageDecoding.h>
 #include <LibWeb/ImageDecoding.h>
 #include <LibWeb/Loader/ResourceLoader.h>
 #include <LibWeb/Loader/ResourceLoader.h>
+#include <LibWeb/Platform/EventLoopPlugin.h>
 #include <LibWeb/WebSockets/WebSocket.h>
 #include <LibWeb/WebSockets/WebSocket.h>
 #include <LibWebView/ImageDecoderClientAdapter.h>
 #include <LibWebView/ImageDecoderClientAdapter.h>
 #include <LibWebView/RequestServerAdapter.h>
 #include <LibWebView/RequestServerAdapter.h>
@@ -28,6 +30,8 @@ ErrorOr<int> serenity_main(Main::Arguments)
     TRY(Core::System::unveil("/tmp/user/%uid/portal/websocket", "rw"));
     TRY(Core::System::unveil("/tmp/user/%uid/portal/websocket", "rw"));
     TRY(Core::System::unveil(nullptr, nullptr));
     TRY(Core::System::unveil(nullptr, nullptr));
 
 
+    Web::Platform::EventLoopPlugin::install(*new WebContent::EventLoopPluginSerenity);
+
     Web::ImageDecoding::Decoder::initialize(WebView::ImageDecoderClientAdapter::create());
     Web::ImageDecoding::Decoder::initialize(WebView::ImageDecoderClientAdapter::create());
     Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create()));
     Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create()));
     Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create()));
     Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create()));