diff options
Diffstat (limited to 'Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp')
-rw-r--r-- | Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp b/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp index 9329b77ea6..e8432f0d5e 100644 --- a/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp +++ b/Userland/Libraries/LibWeb/Bindings/MainThreadVM.cpp @@ -6,11 +6,15 @@ */ #include <LibJS/Module.h> +#include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/Environment.h> #include <LibJS/Runtime/FinalizationRegistry.h> #include <LibJS/Runtime/NativeFunction.h> #include <LibJS/Runtime/VM.h> +#include <LibWeb/Bindings/IDLAbstractOperations.h> #include <LibWeb/Bindings/MainThreadVM.h> +#include <LibWeb/Bindings/MutationObserverWrapper.h> +#include <LibWeb/Bindings/MutationRecordWrapper.h> #include <LibWeb/DOM/Document.h> #include <LibWeb/HTML/PromiseRejectionEvent.h> #include <LibWeb/HTML/Scripting/ClassicScript.h> @@ -286,4 +290,74 @@ JS::VM& main_thread_vm() return *vm; } +// https://dom.spec.whatwg.org/#queue-a-mutation-observer-compound-microtask +void queue_mutation_observer_microtask(DOM::Document& document) +{ + // FIXME: Is this the correct VM? + auto& vm = main_thread_vm(); + auto& custom_data = verify_cast<WebEngineCustomData>(*vm.custom_data()); + + // 1. If the surrounding agent’s mutation observer microtask queued is true, then return. + if (custom_data.mutation_observer_microtask_queued) + return; + + // 2. Set the surrounding agent’s mutation observer microtask queued to true. + custom_data.mutation_observer_microtask_queued = true; + + // 3. Queue a microtask to notify mutation observers. + // NOTE: This uses the implied document concept. In the case of mutation observers, it is always done in a node context, so document should be that node's document. + // FIXME: Is it safe to pass custom_data through? + HTML::queue_a_microtask(&document, [&custom_data]() { + // 1. Set the surrounding agent’s mutation observer microtask queued to false. + custom_data.mutation_observer_microtask_queued = false; + + // 2. Let notifySet be a clone of the surrounding agent’s mutation observers. + auto notify_set = custom_data.mutation_observers; + + // FIXME: 3. Let signalSet be a clone of the surrounding agent’s signal slots. + + // FIXME: 4. Empty the surrounding agent’s signal slots. + + // 5. For each mo of notifySet: + for (auto& mutation_observer : notify_set) { + // 1. Let records be a clone of mo’s record queue. + // 2. Empty mo’s record queue. + auto records = mutation_observer.take_records(); + + // 3. For each node of mo’s node list, remove all transient registered observers whose observer is mo from node’s registered observer list. + for (auto& node : mutation_observer.node_list()) { + // FIXME: Is this correct? + if (node.is_null()) + continue; + + node->registered_observers_list().remove_all_matching([&mutation_observer](DOM::RegisteredObserver& registered_observer) { + return is<DOM::TransientRegisteredObserver>(registered_observer) && static_cast<DOM::TransientRegisteredObserver&>(registered_observer).observer.ptr() == &mutation_observer; + }); + } + + // 4. If records is not empty, then invoke mo’s callback with « records, mo », and mo. If this throws an exception, catch it, and report the exception. + if (!records.is_empty()) { + auto& callback = mutation_observer.callback(); + auto& global_object = callback.callback_context.global_object(); + + auto* wrapped_records = MUST(JS::Array::create(global_object, 0)); + for (size_t i = 0; i < records.size(); ++i) { + auto& record = records.at(i); + auto* wrapped_record = Bindings::wrap(global_object, record); + auto property_index = JS::PropertyKey { i }; + MUST(wrapped_records->create_data_property(property_index, wrapped_record)); + } + + auto* wrapped_mutation_observer = Bindings::wrap(global_object, mutation_observer); + + auto result = IDL::invoke_callback(callback, wrapped_mutation_observer, wrapped_records, wrapped_mutation_observer); + if (result.is_abrupt()) + HTML::report_exception(result); + } + } + + // FIXME: 6. For each slot of signalSet, fire an event named slotchange, with its bubbles attribute set to true, at slot. + }); +} + } |