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

Code before:
    if (slottables != slot->assigned_nodes_internal())
        signal_a_slot_change(slot);

    // 4. For each slottable in slottables, set slottable’s assigned slot to slot.
    for (auto& slottable : slottables) {
        slottable.visit([&](auto& node) {
            node->set_assigned_slot(slot);
        });
    }

    // 3. Set slot’s assigned nodes to slottables.
    // NOTE: We do this step last so that we can move the slottables list.
    slot->set_assigned_nodes(move(slottables));
}

// https://dom.spec.whatwg.org/#assign-slotables-for-a-tree
void assign_slottables_for_a_tree(GC::Ref<Node> root)
{
    auto* shadow_root = as_if<ShadowRoot>(*root);
    if (!shadow_root && !root->is_html_slot_element())
        return;

    // To assign slottables for a tree, given a node root, run assign slottables for each slot of root’s inclusive
    // descendants, in tree order.
    if (shadow_root) {
        if (!shadow_root->has_registered_slots())
            return;
        shadow_root->for_each_registered_slot([](HTML::HTMLSlotElement& slot) {
            assign_slottables(slot);
        });
        return;
    }

    root->for_each_in_inclusive_subtree_of_type<HTML::HTMLSlotElement>([](auto& slot) {
        assign_slottables(slot);
        return TraversalDecision::Continue;
    });
}

// https://dom.spec.whatwg.org/#assign-a-slot
void assign_a_slot(Slottable const& slottable)
{
    // 1. Let slot be the result of finding a slot with slottable.
    auto slot = find_a_slot(slottable);

    // 2. If slot is non-null, then run assign slottables for slot.
    if (slot != nullptr)
        assign_slottables(*slot);
}

// https://dom.spec.whatwg.org/#signal-a-slot-change

Review comment (bug):
I think has_registered_slots can be removed since for_each_registered_slot will just not iterate if something is missing

BTW with that AD-HOC comment being removed, does that fix https://wpt.live/dom/nodes/moveBefore/slotchange-events.html ? If I remember correctly that test was failing due to that optimization which is incorrect in the moveBefore case

Code after:
    if (slottables != slot->assigned_nodes_internal())
        signal_a_slot_change(slot);

    // AD-HOC: Clear the assigned slot for slottables that are no longer assigned to this slot.
    //         This must happen before setting the new assigned slots to avoid stale references
    //         during style computation.
    for (auto const& old_slottable : slot->assigned_nodes_internal()) {
        old_slottable.visit([&](auto const& node) {
            node->set_assigned_slot(nullptr);
        });
    }

    // 4. For each slottable in slottables, set slottable’s assigned slot to slot.
    for (auto& slottable : slottables) {
        slottable.visit([&](auto& node) {
            node->set_assigned_slot(slot);
        });
    }

    // 3. Set slot’s assigned nodes to slottables.
    // NOTE: We do this step last so that we can move the slottables list.
    slot->set_assigned_nodes(move(slottables));
}

// https://dom.spec.whatwg.org/#assign-slotables-for-a-tree
void assign_slottables_for_a_tree(GC::Ref<Node> root)
{
    // To assign slottables for a tree, given a node root, run assign slottables for each slot of root’s inclusive
    // descendants, in tree order.

    // OPTIMIZATION: If root is not a shadow root or slot element, there are no slots to process, so return early.
    auto* shadow_root = as_if<ShadowRoot>(*root);
    if (!shadow_root && !root->is_html_slot_element())
        return;

    if (shadow_root) {
        shadow_root->for_each_registered_slot([](HTML::HTMLSlotElement& slot) {
            assign_slottables(slot);
        });
        return;
    }

    root->for_each_in_inclusive_subtree_of_type<HTML::HTMLSlotElement>([](auto& slot) {
        assign_slottables(slot);
        return TraversalDecision::Continue;
    });
}

// https://dom.spec.whatwg.org/#assign-a-slot
void assign_a_slot(Slottable const& slottable)
{