Repository: LadybirdBrowser/ladybird
File: Libraries/LibWeb/Bindings/MainThreadVM.cpp (C++)

Code before:
    return *s_main_thread_vm;
}

// https://dom.spec.whatwg.org/#queue-a-mutation-observer-compound-microtask
void queue_mutation_observer_microtask(DOM::Document const& document)
{
    auto& vm = main_thread_vm();
    auto& surrounding_agent = as<HTML::SimilarOriginWindowAgent>(*vm.agent());

    // 1. If the surrounding agent’s mutation observer microtask queued is true, then return.
    if (surrounding_agent.mutation_observer_microtask_queued)
        return;

    // 2. Set the surrounding agent’s mutation observer microtask queued to true.
    surrounding_agent.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.
    HTML::queue_a_microtask(&document, GC::create_function(vm.heap(), [&surrounding_agent, &heap = document.heap()]() {
        // https://dom.spec.whatwg.org/#notify-mutation-observers
        // 1. Set the surrounding agent’s mutation observer microtask queued to false.
        surrounding_agent.mutation_observer_microtask_queued = false;

        // 2. Let notifySet be a clone of the surrounding agent’s pending mutation observers.
        auto notify_set = move(surrounding_agent.pending_mutation_observers);

        // 3. Empty the surrounding agent’s pending mutation observers.
        // NB: We instead do this at the end of the microtask. Steps 2 and 3 are equivalent to moving
        //     surrounding_agent.pending_mutation_observers, but it's unmovable. Actually copying the MutationObservers
        //     causes issues, so for now, keep notify_set as pointers and defer this step until after we've finished
        //     using the notify_set.

        // 4. Let signalSet be a clone of the surrounding agent’s signal slots.
        // 5. Empty the surrounding agent’s signal slots.
        auto signal_set = move(surrounding_agent.signal_slots);

        // 6. 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)
                    continue;

                if (node->registered_observer_list()) {

Review comment (suggestion):
This now does both steps 2 and 3. You can remove the NB below, rearrange things a little, and also remove the `// NB: Step 3, done later.` step at the end of the function.

Code after:
    return *s_main_thread_vm;
}

// https://dom.spec.whatwg.org/#queue-a-mutation-observer-compound-microtask
void queue_mutation_observer_microtask(DOM::Document const& document)
{
    auto& vm = main_thread_vm();
    auto& surrounding_agent = as<HTML::SimilarOriginWindowAgent>(*vm.agent());

    // 1. If the surrounding agent’s mutation observer microtask queued is true, then return.
    if (surrounding_agent.mutation_observer_microtask_queued)
        return;

    // 2. Set the surrounding agent’s mutation observer microtask queued to true.
    surrounding_agent.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.
    HTML::queue_a_microtask(&document, GC::create_function(vm.heap(), [&surrounding_agent, &heap = document.heap()]() {
        // https://dom.spec.whatwg.org/#notify-mutation-observers
        // 1. Set the surrounding agent’s mutation observer microtask queued to false.
        surrounding_agent.mutation_observer_microtask_queued = false;

        // 2. Let notifySet be a clone of the surrounding agent’s pending mutation observers.
        // 3. Empty the surrounding agent’s pending mutation observers.
        auto notify_set = move(surrounding_agent.pending_mutation_observers);

        // 4. Let signalSet be a clone of the surrounding agent’s signal slots.
        // 5. Empty the surrounding agent’s signal slots.
        auto signal_set = move(surrounding_agent.signal_slots);

        // 6. 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)
                    continue;

                if (node->registered_observer_list()) {
                    node->registered_observer_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;
                    });
                }
            }