Repository: LadybirdBrowser/ladybird
File: Libraries/LibWeb/DOM/Node.cpp (C++)

Code before:
    // 13. Remove node from oldParent’s children.
    old_parent->remove_child_impl(*this);

    // 14. If node is assigned, then run assign slottables for node’s assigned slot.
    if (auto assigned_slot = assigned_slot_for_node(*this))
        assign_slottables(*assigned_slot);

    // 15. If oldParent’s root is a shadow root, and oldParent is a slot whose assigned nodes is empty, then run signal a slot change for oldParent.
    auto& old_parent_root = old_parent->root();
    if (auto* old_parent_slot_element = as_if<HTML::HTMLSlotElement>(*old_parent); old_parent_slot_element && old_parent_root.is_shadow_root()) {
        if (old_parent_slot_element->assigned_nodes_internal().is_empty())
            signal_a_slot_change(*old_parent_slot_element);
    }

    // 16. If node has an inclusive descendant that is a slot:
    auto has_descendent_slot = false;

    for_each_in_inclusive_subtree_of_type<HTML::HTMLSlotElement>([&](auto const&) {
        has_descendent_slot = true;
        return TraversalDecision::Break;
    });

    if (has_descendent_slot) {
        // AD-HOC: Unregister any slot elements in the removed subtree from the shadow root's slot registry
        //         before running assign_slottables_for_a_tree, so the registry is up-to-date.
        if (auto* shadow_root = as_if<ShadowRoot>(old_parent_root)) {
            for_each_in_inclusive_subtree_of_type<HTML::HTMLSlotElement>([&](auto& slot) {
                shadow_root->unregister_slot(slot);
                return TraversalDecision::Continue;
            });
        }

        // 1. Run assign slottables for a tree with oldParent’s root.
        assign_slottables_for_a_tree(old_parent_root);

        // 2. Run assign slottables for a tree with node.
        assign_slottables_for_a_tree(*this);
    }

    // 17. If child is non-null:
    if (child) {
        // 1. For each live range whose start node is newParent and start offset is greater than child’s index:
        //    increase its start offset by 1.
        for (auto& range : Range::live_ranges()) {
            if (range->start_container() == &new_parent && range->start_offset() > child->index())
                range->increase_start_offset(1);
        }

        // 2. For each live range whose end node is newParent and end offset is greater than child’s index:
        //    increase its end offset by 1.
        for (auto& range : Range::live_ranges()) {

Review comment (suggestion):
For this and `Node::remove()`, I think we can combine into the loop above so we only do a single pass

Code after:
    if (auto assigned_slot = assigned_slot_for_node(*this))
        assign_slottables(*assigned_slot);

    // 15. If oldParent’s root is a shadow root, and oldParent is a slot whose assigned nodes is empty, then run signal a slot change for oldParent.
    auto& old_parent_root = old_parent->root();
    if (auto* old_parent_slot_element = as_if<HTML::HTMLSlotElement>(*old_parent); old_parent_slot_element && old_parent_root.is_shadow_root()) {
        if (old_parent_slot_element->assigned_nodes_internal().is_empty())
            signal_a_slot_change(*old_parent_slot_element);
    }

    // 16. If node has an inclusive descendant that is a slot:
    auto has_descendent_slot = false;
    auto* shadow_root = as_if<ShadowRoot>(old_parent_root);

    for_each_in_inclusive_subtree_of_type<HTML::HTMLSlotElement>([&](auto& slot) {
        has_descendent_slot = true;
        if (!shadow_root)
            return TraversalDecision::Break;
        // AD-HOC: Unregister slot from the shadow root's registry before assign_slottables_for_a_tree.
        shadow_root->unregister_slot(slot);
        return TraversalDecision::Continue;
    });

    if (has_descendent_slot) {
        // 1. Run assign slottables for a tree with oldParent’s root.
        assign_slottables_for_a_tree(old_parent_root);

        // 2. Run assign slottables for a tree with node.
        assign_slottables_for_a_tree(*this);
    }

    // 17. If child is non-null:
    if (child) {
        // 1. For each live range whose start node is newParent and start offset is greater than child’s index:
        //    increase its start offset by 1.
        for (auto& range : Range::live_ranges()) {
            if (range->start_container() == &new_parent && range->start_offset() > child->index())
                range->increase_start_offset(1);
        }

        // 2. For each live range whose end node is newParent and end offset is greater than child’s index:
        //    increase its end offset by 1.
        for (auto& range : Range::live_ranges()) {
            if (range->end_container() == &new_parent && range->end_offset() > child->index())
                range->increase_end_offset(1);
        }
    }

    // 18. Let newPreviousSibling be child’s previous sibling if child is non-null, and newParent’s last child otherwise.
    auto* new_previous_sibling = child ? child->previous_sibling() : new_parent.last_child();