mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-10 10:09:14 +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: d9e5ae66a7
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
|
Geometry/DOMRectReadOnly.cpp
|
||||||
HTML/AbstractWorker.cpp
|
HTML/AbstractWorker.cpp
|
||||||
HTML/AnimatedBitmapDecodedImageData.cpp
|
HTML/AnimatedBitmapDecodedImageData.cpp
|
||||||
|
HTML/AnimationFrameCallbackDriver.cpp
|
||||||
HTML/AttributeNames.cpp
|
HTML/AttributeNames.cpp
|
||||||
HTML/AudioTrack.cpp
|
HTML/AudioTrack.cpp
|
||||||
HTML/AudioTrackList.cpp
|
HTML/AudioTrackList.cpp
|
||||||
|
|
|
@ -375,6 +375,7 @@ struct DOMPointInit;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Web::HTML {
|
namespace Web::HTML {
|
||||||
|
class AnimationFrameCallbackDriver;
|
||||||
class AudioTrack;
|
class AudioTrack;
|
||||||
class AudioTrackList;
|
class AudioTrackList;
|
||||||
class BroadcastChannel;
|
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) 2022, the SerenityOS developers.
|
||||||
* Copyright (c) 2024, Andreas Kling <andreas@ladybird.org>
|
* Copyright (c) 2024, Andreas Kling <andreas@ladybird.org>
|
||||||
|
* Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Function.h>
|
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
#include <LibCore/Timer.h>
|
#include <LibJS/Heap/GCPtr.h>
|
||||||
#include <LibWeb/HTML/EventLoop/EventLoop.h>
|
#include <LibJS/Heap/HeapFunction.h>
|
||||||
#include <LibWeb/WebIDL/Types.h>
|
#include <LibWeb/WebIDL/Types.h>
|
||||||
|
|
||||||
namespace Web::HTML {
|
namespace Web::HTML {
|
||||||
|
|
||||||
struct AnimationFrameCallbackDriver {
|
class AnimationFrameCallbackDriver final : public JS::Cell {
|
||||||
using Callback = Function<void(double)>;
|
JS_CELL(AnimationFrameCallbackDriver, JS::Cell);
|
||||||
|
JS_DECLARE_ALLOCATOR(AnimationFrameCallbackDriver);
|
||||||
|
|
||||||
[[nodiscard]] WebIDL::UnsignedLong add(Callback handler)
|
using Callback = JS::NonnullGCPtr<JS::HeapFunction<void(double)>>;
|
||||||
{
|
|
||||||
auto id = ++m_animation_frame_callback_identifier;
|
|
||||||
m_callbacks.set(id, move(handler));
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool remove(WebIDL::UnsignedLong id)
|
public:
|
||||||
{
|
[[nodiscard]] WebIDL::UnsignedLong add(Callback handler);
|
||||||
auto it = m_callbacks.find(id);
|
bool remove(WebIDL::UnsignedLong);
|
||||||
if (it == m_callbacks.end())
|
bool has_callbacks() const;
|
||||||
return false;
|
void run(double now);
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#animation-frame-callback-identifier
|
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#animation-frame-callback-identifier
|
||||||
WebIDL::UnsignedLong m_animation_frame_callback_identifier { 0 };
|
WebIDL::UnsignedLong m_animation_frame_callback_identifier { 0 };
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <LibWeb/DOM/EventDispatcher.h>
|
#include <LibWeb/DOM/EventDispatcher.h>
|
||||||
#include <LibWeb/DOM/HTMLCollection.h>
|
#include <LibWeb/DOM/HTMLCollection.h>
|
||||||
#include <LibWeb/DOMURL/DOMURL.h>
|
#include <LibWeb/DOMURL/DOMURL.h>
|
||||||
|
#include <LibWeb/HTML/AnimationFrameCallbackDriver.h>
|
||||||
#include <LibWeb/HTML/BrowsingContext.h>
|
#include <LibWeb/HTML/BrowsingContext.h>
|
||||||
#include <LibWeb/HTML/CloseWatcherManager.h>
|
#include <LibWeb/HTML/CloseWatcherManager.h>
|
||||||
#include <LibWeb/HTML/CustomElements/CustomElementRegistry.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_navigator);
|
||||||
visitor.visit(m_navigation);
|
visitor.visit(m_navigation);
|
||||||
visitor.visit(m_custom_element_registry);
|
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_plugin_objects);
|
||||||
visitor.visit(m_pdf_viewer_mime_type_objects);
|
visitor.visit(m_pdf_viewer_mime_type_objects);
|
||||||
visitor.visit(m_count_queuing_strategy_size_function);
|
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
|
// 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'.
|
// 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.
|
// 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));
|
auto result = WebIDL::invoke_callback(*callback, {}, JS::Value(now));
|
||||||
if (result.is_error())
|
if (result.is_error())
|
||||||
report_exception(result, realm());
|
report_exception(result, realm());
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#animationframeprovider-cancelanimationframe
|
// 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.
|
// 2. Let callbacks be this's target object's map of animation frame callbacks.
|
||||||
// 3. Remove callbacks[handle].
|
// 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
|
// https://w3c.github.io/requestidlecallback/#dom-window-requestidlecallback
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include <LibWeb/Bindings/WindowGlobalMixin.h>
|
#include <LibWeb/Bindings/WindowGlobalMixin.h>
|
||||||
#include <LibWeb/DOM/EventTarget.h>
|
#include <LibWeb/DOM/EventTarget.h>
|
||||||
#include <LibWeb/Forward.h>
|
#include <LibWeb/Forward.h>
|
||||||
#include <LibWeb/HTML/AnimationFrameCallbackDriver.h>
|
|
||||||
#include <LibWeb/HTML/CrossOrigin/CrossOriginPropertyDescriptorMap.h>
|
#include <LibWeb/HTML/CrossOrigin/CrossOriginPropertyDescriptorMap.h>
|
||||||
#include <LibWeb/HTML/GlobalEventHandlers.h>
|
#include <LibWeb/HTML/GlobalEventHandlers.h>
|
||||||
#include <LibWeb/HTML/MimeType.h>
|
#include <LibWeb/HTML/MimeType.h>
|
||||||
|
@ -110,8 +109,6 @@ public:
|
||||||
};
|
};
|
||||||
WebIDL::ExceptionOr<OpenedWindow> window_open_steps_internal(StringView url, StringView target, StringView features);
|
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* current_event() { return m_current_event.ptr(); }
|
||||||
DOM::Event const* current_event() const { return m_current_event.ptr(); }
|
DOM::Event const* current_event() const { return m_current_event.ptr(); }
|
||||||
void set_current_event(DOM::Event* event);
|
void set_current_event(DOM::Event* event);
|
||||||
|
@ -125,8 +122,6 @@ public:
|
||||||
|
|
||||||
void start_an_idle_period();
|
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
|
// https://html.spec.whatwg.org/multipage/interaction.html#sticky-activation
|
||||||
bool has_sticky_activation() const;
|
bool has_sticky_activation() const;
|
||||||
|
|
||||||
|
@ -211,7 +206,10 @@ public:
|
||||||
i32 outer_height() const;
|
i32 outer_height() const;
|
||||||
double device_pixel_ratio() 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);
|
void cancel_animation_frame(WebIDL::UnsignedLong handle);
|
||||||
|
|
||||||
u32 request_idle_callback(WebIDL::CallbackType&, RequestIdleCallback::IdleRequestOptions const&);
|
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.
|
// 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;
|
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
|
// https://w3c.github.io/requestidlecallback/#dfn-list-of-idle-request-callbacks
|
||||||
Vector<NonnullRefPtr<IdleCallback>> m_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;
|
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();
|
auto canvas_or_error = draw_bounding_box_from_the_framebuffer();
|
||||||
if (canvas_or_error.is_error()) {
|
if (canvas_or_error.is_error()) {
|
||||||
encoded_string_or_error = canvas_or_error.release_error();
|
encoded_string_or_error = canvas_or_error.release_error();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
encoded_string_or_error = encode_canvas_element(canvas_or_error.release_value());
|
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(); }));
|
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();
|
return encoded_string_or_error.release_value();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue