1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:17:44 +00:00

LibWeb: Make MutationObserver GC-allocated

This commit is contained in:
Andreas Kling 2022-09-01 17:59:48 +02:00
parent 43ec0f734f
commit 905eb8cb4d
8 changed files with 134 additions and 68 deletions

View file

@ -5,23 +5,42 @@
*/
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/Bindings/MutationObserverPrototype.h>
#include <LibWeb/DOM/MutationObserver.h>
#include <LibWeb/DOM/Node.h>
#include <LibWeb/HTML/Window.h>
namespace Web::DOM {
// https://dom.spec.whatwg.org/#dom-mutationobserver-mutationobserver
MutationObserver::MutationObserver(HTML::Window& window_object, JS::Handle<Bindings::CallbackType> callback)
: m_callback(move(callback))
JS::NonnullGCPtr<MutationObserver> MutationObserver::create_with_global_object(HTML::Window& window, JS::GCPtr<Bindings::CallbackType> callback)
{
return *window.heap().allocate<MutationObserver>(window.realm(), window, callback);
}
// https://dom.spec.whatwg.org/#dom-mutationobserver-mutationobserver
MutationObserver::MutationObserver(HTML::Window& window, JS::GCPtr<Bindings::CallbackType> callback)
: PlatformObject(window.realm())
, m_callback(move(callback))
{
set_prototype(&window.ensure_web_prototype<Bindings::MutationObserverPrototype>("MutationObserver"));
// 1. Set thiss callback to callback.
// 2. Append this to thiss relevant agents mutation observers.
auto* agent_custom_data = verify_cast<Bindings::WebEngineCustomData>(window_object.vm().custom_data());
auto* agent_custom_data = verify_cast<Bindings::WebEngineCustomData>(window.vm().custom_data());
agent_custom_data->mutation_observers.append(*this);
}
MutationObserver::~MutationObserver() = default;
void MutationObserver::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_callback.ptr());
for (auto& record : m_record_queue)
visitor.visit(record.ptr());
}
// https://dom.spec.whatwg.org/#dom-mutationobserver-observe
ExceptionOr<void> MutationObserver::observe(Node& target, MutationObserverInit options)
{
@ -55,7 +74,7 @@ ExceptionOr<void> MutationObserver::observe(Node& target, MutationObserverInit o
// 7. For each registered of targets registered observer list, if registereds observer is this:
bool updated_existing_observer = false;
for (auto& registered_observer : target.registered_observers_list()) {
if (registered_observer.observer.ptr() != this)
if (registered_observer.observer().ptr() != this)
continue;
updated_existing_observer = true;
@ -67,12 +86,12 @@ ExceptionOr<void> MutationObserver::observe(Node& target, MutationObserverInit o
continue;
node->registered_observers_list().remove_all_matching([&registered_observer](RegisteredObserver& observer) {
return is<TransientRegisteredObserver>(observer) && verify_cast<TransientRegisteredObserver>(observer).source.ptr() == &registered_observer;
return is<TransientRegisteredObserver>(observer) && verify_cast<TransientRegisteredObserver>(observer).source().ptr() == &registered_observer;
});
}
// 2. Set registereds options to options.
registered_observer.options = options;
registered_observer.set_options(options);
break;
}
@ -99,7 +118,7 @@ void MutationObserver::disconnect()
continue;
node->registered_observers_list().remove_all_matching([this](RegisteredObserver& registered_observer) {
return registered_observer.observer.ptr() == this;
return registered_observer.observer().ptr() == this;
});
}
@ -111,7 +130,9 @@ void MutationObserver::disconnect()
Vector<JS::Handle<MutationRecord>> MutationObserver::take_records()
{
// 1. Let records be a clone of thiss record queue.
auto records = m_record_queue;
Vector<JS::Handle<MutationRecord>> records;
for (auto& record : m_record_queue)
records.append(*record);
// 2. Empty thiss record queue.
m_record_queue.clear();
@ -120,4 +141,42 @@ Vector<JS::Handle<MutationRecord>> MutationObserver::take_records()
return records;
}
JS::NonnullGCPtr<RegisteredObserver> RegisteredObserver::create(MutationObserver& observer, MutationObserverInit const& options)
{
return *observer.heap().allocate_without_realm<RegisteredObserver>(observer, options);
}
RegisteredObserver::RegisteredObserver(MutationObserver& observer, MutationObserverInit const& options)
: m_observer(observer)
, m_options(options)
{
}
RegisteredObserver::~RegisteredObserver() = default;
void RegisteredObserver::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_observer.ptr());
}
JS::NonnullGCPtr<TransientRegisteredObserver> TransientRegisteredObserver::create(MutationObserver& observer, MutationObserverInit const& options, RegisteredObserver& source)
{
return *observer.heap().allocate_without_realm<TransientRegisteredObserver>(observer, options, source);
}
TransientRegisteredObserver::TransientRegisteredObserver(MutationObserver& observer, MutationObserverInit const& options, RegisteredObserver& source)
: RegisteredObserver(observer, options)
, m_source(source)
{
}
TransientRegisteredObserver::~TransientRegisteredObserver() = default;
void TransientRegisteredObserver::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_source.ptr());
}
}