mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 00:50:22 +00:00
LibWeb: Allocate AnimationFrameCallbackDriver on the JS heap
This avoids needing to creating root handles for each heap-allocated object captured in the animation callback. An upcoming commit would add several of these.
This commit is contained in:
parent
144907f5bd
commit
d9e5ae66a7
Notes:
github-actions[bot]
2024-10-31 02:40:42 +00:00
Author: https://github.com/trflynn89 Commit: https://github.com/LadybirdBrowser/ladybird/commit/d9e5ae66a77 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2071 Reviewed-by: https://github.com/tcl3 ✅
7 changed files with 88 additions and 44 deletions
|
@ -269,6 +269,7 @@ set(SOURCES
|
|||
Geometry/DOMRectReadOnly.cpp
|
||||
HTML/AbstractWorker.cpp
|
||||
HTML/AnimatedBitmapDecodedImageData.cpp
|
||||
HTML/AnimationFrameCallbackDriver.cpp
|
||||
HTML/AttributeNames.cpp
|
||||
HTML/AudioTrack.cpp
|
||||
HTML/AudioTrackList.cpp
|
||||
|
|
|
@ -375,6 +375,7 @@ struct DOMPointInit;
|
|||
}
|
||||
|
||||
namespace Web::HTML {
|
||||
class AnimationFrameCallbackDriver;
|
||||
class AudioTrack;
|
||||
class AudioTrackList;
|
||||
class BroadcastChannel;
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2022, the SerenityOS developers.
|
||||
* Copyright (c) 2024, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/HTML/AnimationFrameCallbackDriver.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
JS_DEFINE_ALLOCATOR(AnimationFrameCallbackDriver);
|
||||
|
||||
void AnimationFrameCallbackDriver::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_callbacks);
|
||||
}
|
||||
|
||||
WebIDL::UnsignedLong AnimationFrameCallbackDriver::add(Callback handler)
|
||||
{
|
||||
auto id = ++m_animation_frame_callback_identifier;
|
||||
m_callbacks.set(id, handler);
|
||||
return id;
|
||||
}
|
||||
|
||||
bool AnimationFrameCallbackDriver::remove(WebIDL::UnsignedLong id)
|
||||
{
|
||||
return m_callbacks.remove(id);
|
||||
}
|
||||
|
||||
bool AnimationFrameCallbackDriver::has_callbacks() const
|
||||
{
|
||||
return !m_callbacks.is_empty();
|
||||
}
|
||||
|
||||
void AnimationFrameCallbackDriver::run(double now)
|
||||
{
|
||||
auto taken_callbacks = move(m_callbacks);
|
||||
for (auto& [id, callback] : taken_callbacks)
|
||||
callback->function()(now);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,52 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2022, the SerenityOS developers.
|
||||
* Copyright (c) 2024, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <LibCore/Timer.h>
|
||||
#include <LibWeb/HTML/EventLoop/EventLoop.h>
|
||||
#include <LibJS/Heap/GCPtr.h>
|
||||
#include <LibJS/Heap/HeapFunction.h>
|
||||
#include <LibWeb/WebIDL/Types.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
struct AnimationFrameCallbackDriver {
|
||||
using Callback = Function<void(double)>;
|
||||
class AnimationFrameCallbackDriver final : public JS::Cell {
|
||||
JS_CELL(AnimationFrameCallbackDriver, JS::Cell);
|
||||
JS_DECLARE_ALLOCATOR(AnimationFrameCallbackDriver);
|
||||
|
||||
[[nodiscard]] WebIDL::UnsignedLong add(Callback handler)
|
||||
{
|
||||
auto id = ++m_animation_frame_callback_identifier;
|
||||
m_callbacks.set(id, move(handler));
|
||||
return id;
|
||||
}
|
||||
using Callback = JS::NonnullGCPtr<JS::HeapFunction<void(double)>>;
|
||||
|
||||
bool remove(WebIDL::UnsignedLong id)
|
||||
{
|
||||
auto it = m_callbacks.find(id);
|
||||
if (it == m_callbacks.end())
|
||||
return false;
|
||||
m_callbacks.remove(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
void run(double now)
|
||||
{
|
||||
auto taken_callbacks = move(m_callbacks);
|
||||
for (auto& [id, callback] : taken_callbacks)
|
||||
callback(now);
|
||||
}
|
||||
|
||||
bool has_callbacks() const
|
||||
{
|
||||
return !m_callbacks.is_empty();
|
||||
}
|
||||
public:
|
||||
[[nodiscard]] WebIDL::UnsignedLong add(Callback handler);
|
||||
bool remove(WebIDL::UnsignedLong);
|
||||
bool has_callbacks() const;
|
||||
void run(double now);
|
||||
|
||||
private:
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#animation-frame-callback-identifier
|
||||
WebIDL::UnsignedLong m_animation_frame_callback_identifier { 0 };
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <LibWeb/DOM/EventDispatcher.h>
|
||||
#include <LibWeb/DOM/HTMLCollection.h>
|
||||
#include <LibWeb/DOMURL/DOMURL.h>
|
||||
#include <LibWeb/HTML/AnimationFrameCallbackDriver.h>
|
||||
#include <LibWeb/HTML/BrowsingContext.h>
|
||||
#include <LibWeb/HTML/CloseWatcherManager.h>
|
||||
#include <LibWeb/HTML/CustomElements/CustomElementRegistry.h>
|
||||
|
@ -123,6 +124,7 @@ void Window::visit_edges(JS::Cell::Visitor& visitor)
|
|||
visitor.visit(m_navigator);
|
||||
visitor.visit(m_navigation);
|
||||
visitor.visit(m_custom_element_registry);
|
||||
visitor.visit(m_animation_frame_callback_driver);
|
||||
visitor.visit(m_pdf_viewer_plugin_objects);
|
||||
visitor.visit(m_pdf_viewer_mime_type_objects);
|
||||
visitor.visit(m_count_queuing_strategy_size_function);
|
||||
|
@ -1541,15 +1543,15 @@ double Window::device_pixel_ratio() const
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#dom-animationframeprovider-requestanimationframe
|
||||
WebIDL::UnsignedLong Window::request_animation_frame(WebIDL::CallbackType& callback)
|
||||
WebIDL::UnsignedLong Window::request_animation_frame(JS::NonnullGCPtr<WebIDL::CallbackType> callback)
|
||||
{
|
||||
// FIXME: Make this fully spec compliant. Currently implements a mix of 'requestAnimationFrame()' and 'run the animation frame callbacks'.
|
||||
return m_animation_frame_callback_driver.add([this, callback = JS::make_handle(callback)](double now) {
|
||||
return animation_frame_callback_driver().add(JS::create_heap_function(heap(), [this, callback](double now) {
|
||||
// 3. Invoke callback, passing now as the only argument, and if an exception is thrown, report the exception.
|
||||
auto result = WebIDL::invoke_callback(*callback, {}, JS::Value(now));
|
||||
if (result.is_error())
|
||||
report_exception(result, realm());
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#animationframeprovider-cancelanimationframe
|
||||
|
@ -1560,7 +1562,21 @@ void Window::cancel_animation_frame(WebIDL::UnsignedLong handle)
|
|||
|
||||
// 2. Let callbacks be this's target object's map of animation frame callbacks.
|
||||
// 3. Remove callbacks[handle].
|
||||
(void)m_animation_frame_callback_driver.remove(handle);
|
||||
(void)animation_frame_callback_driver().remove(handle);
|
||||
}
|
||||
|
||||
AnimationFrameCallbackDriver& Window::animation_frame_callback_driver()
|
||||
{
|
||||
if (!m_animation_frame_callback_driver)
|
||||
m_animation_frame_callback_driver = heap().allocate<AnimationFrameCallbackDriver>(realm());
|
||||
return *m_animation_frame_callback_driver;
|
||||
}
|
||||
|
||||
bool Window::has_animation_frame_callbacks()
|
||||
{
|
||||
if (!m_animation_frame_callback_driver)
|
||||
return false;
|
||||
return m_animation_frame_callback_driver->has_callbacks();
|
||||
}
|
||||
|
||||
// https://w3c.github.io/requestidlecallback/#dom-window-requestidlecallback
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <LibWeb/Bindings/WindowGlobalMixin.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/HTML/AnimationFrameCallbackDriver.h>
|
||||
#include <LibWeb/HTML/CrossOrigin/CrossOriginPropertyDescriptorMap.h>
|
||||
#include <LibWeb/HTML/GlobalEventHandlers.h>
|
||||
#include <LibWeb/HTML/MimeType.h>
|
||||
|
@ -110,8 +109,6 @@ public:
|
|||
};
|
||||
WebIDL::ExceptionOr<OpenedWindow> window_open_steps_internal(StringView url, StringView target, StringView features);
|
||||
|
||||
bool has_animation_frame_callbacks() const { return m_animation_frame_callback_driver.has_callbacks(); }
|
||||
|
||||
DOM::Event* current_event() { return m_current_event.ptr(); }
|
||||
DOM::Event const* current_event() const { return m_current_event.ptr(); }
|
||||
void set_current_event(DOM::Event* event);
|
||||
|
@ -125,8 +122,6 @@ public:
|
|||
|
||||
void start_an_idle_period();
|
||||
|
||||
AnimationFrameCallbackDriver& animation_frame_callback_driver() { return m_animation_frame_callback_driver; }
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/interaction.html#sticky-activation
|
||||
bool has_sticky_activation() const;
|
||||
|
||||
|
@ -211,7 +206,10 @@ public:
|
|||
i32 outer_height() const;
|
||||
double device_pixel_ratio() const;
|
||||
|
||||
WebIDL::UnsignedLong request_animation_frame(WebIDL::CallbackType&);
|
||||
AnimationFrameCallbackDriver& animation_frame_callback_driver();
|
||||
bool has_animation_frame_callbacks();
|
||||
|
||||
WebIDL::UnsignedLong request_animation_frame(JS::NonnullGCPtr<WebIDL::CallbackType>);
|
||||
void cancel_animation_frame(WebIDL::UnsignedLong handle);
|
||||
|
||||
u32 request_idle_callback(WebIDL::CallbackType&, RequestIdleCallback::IdleRequestOptions const&);
|
||||
|
@ -289,7 +287,7 @@ private:
|
|||
// Each Window object is associated with a unique instance of a CustomElementRegistry object, allocated when the Window object is created.
|
||||
JS::GCPtr<CustomElementRegistry> m_custom_element_registry;
|
||||
|
||||
AnimationFrameCallbackDriver m_animation_frame_callback_driver;
|
||||
JS::GCPtr<AnimationFrameCallbackDriver> m_animation_frame_callback_driver;
|
||||
|
||||
// https://w3c.github.io/requestidlecallback/#dfn-list-of-idle-request-callbacks
|
||||
Vector<NonnullRefPtr<IdleCallback>> m_idle_request_callbacks;
|
||||
|
|
|
@ -93,14 +93,14 @@ Response capture_element_screenshot(Painter const& painter, Page& page, DOM::Ele
|
|||
return canvas;
|
||||
};
|
||||
|
||||
(void)element.document().window()->animation_frame_callback_driver().add([&](auto) {
|
||||
(void)element.document().window()->animation_frame_callback_driver().add(JS::create_heap_function(element.heap(), [&](double) {
|
||||
auto canvas_or_error = draw_bounding_box_from_the_framebuffer();
|
||||
if (canvas_or_error.is_error()) {
|
||||
encoded_string_or_error = canvas_or_error.release_error();
|
||||
return;
|
||||
}
|
||||
encoded_string_or_error = encode_canvas_element(canvas_or_error.release_value());
|
||||
});
|
||||
}));
|
||||
|
||||
Platform::EventLoopPlugin::the().spin_until(JS::create_heap_function(element.document().heap(), [&]() { return encoded_string_or_error.has_value(); }));
|
||||
return encoded_string_or_error.release_value();
|
||||
|
|
Loading…
Reference in a new issue