diff --git a/Libraries/LibWeb/DOM/ShadowRoot.h b/Libraries/LibWeb/DOM/ShadowRoot.h index ef18117b56a9..86d7bb0cb784 100644 --- a/Libraries/LibWeb/DOM/ShadowRoot.h +++ b/Libraries/LibWeb/DOM/ShadowRoot.h @@ -64,6 +64,20 @@ class ShadowRoot final : public DocumentFragment { virtual void finalize() override; + void increment_slot_count() { ++m_slot_count; } + void decrement_slot_count() { --m_slot_count; } + [[nodiscard]] size_t slot_count() const { return m_slot_count; } + + template + void for_each_slot(Callback callback) + { + if (m_slot_count == 0) + return; + for_each_in_subtree_of_type([&](HTML::HTMLSlotElement& slot) { + return callback(slot); + }); + } + protected: virtual void visit_edges(Cell::Visitor&) override; @@ -92,6 +106,9 @@ class ShadowRoot final : public DocumentFragment { GC::Ptr m_style_sheets; mutable GC::Ptr m_adopted_style_sheets; + + // AD-HOC: Number of HTMLSlotElement nodes that are descendants of this ShadowRoot. + size_t m_slot_count { 0 }; }; template<> diff --git a/Libraries/LibWeb/DOM/Slottable.cpp b/Libraries/LibWeb/DOM/Slottable.cpp index 41d70c78b01b..c6be2b413bc9 100644 --- a/Libraries/LibWeb/DOM/Slottable.cpp +++ b/Libraries/LibWeb/DOM/Slottable.cpp @@ -74,32 +74,32 @@ GC::Ptr find_a_slot(Slottable const& slottable, OpenFlag // 5. If shadow’s slot assignment is "manual", then return the slot in shadow’s descendants whose manually assigned // nodes contains slottable, if any; otherwise null. if (shadow->slot_assignment() == Bindings::SlotAssignmentMode::Manual) { - GC::Ptr slot; + GC::Ptr found_slot; - shadow->for_each_in_subtree_of_type([&](auto& child) { - if (!child.manually_assigned_nodes().contains_slow(slottable)) + shadow->for_each_slot([&](auto& slot) { + if (!slot.manually_assigned_nodes().contains_slow(slottable)) return TraversalDecision::Continue; - slot = child; + found_slot = slot; return TraversalDecision::Break; }); - return slot; + return found_slot; } // 6. Return the first slot in tree order in shadow’s descendants whose name is slottable’s name, if any; otherwise null. auto const& slottable_name = slottable.visit([](auto const& node) { return node->slottable_name(); }); - GC::Ptr slot; + GC::Ptr found_slot; - shadow->for_each_in_subtree_of_type([&](auto& child) { - if (child.slot_name() != slottable_name) + shadow->for_each_slot([&](auto& slot) { + if (slot.slot_name() != slottable_name) return TraversalDecision::Continue; - slot = child; + found_slot = slot; return TraversalDecision::Break; }); - return slot; + return found_slot; } // https://dom.spec.whatwg.org/#find-slotables @@ -186,7 +186,7 @@ void assign_slottables_for_a_tree(GC::Ref root) // To assign slottables for a tree, given a node root, run assign slottables for each slot slot in root’s inclusive // descendants, in tree order. - root->for_each_in_inclusive_subtree_of_type([](auto& slot) { + static_cast(*root).for_each_slot([](auto& slot) { assign_slottables(slot); return TraversalDecision::Continue; }); diff --git a/Libraries/LibWeb/HTML/HTMLSlotElement.cpp b/Libraries/LibWeb/HTML/HTMLSlotElement.cpp index 162259031266..8aa67285779e 100644 --- a/Libraries/LibWeb/HTML/HTMLSlotElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLSlotElement.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -147,4 +148,24 @@ void HTMLSlotElement::attribute_changed(FlyString const& local_name, Optionalroot(); + if (!root.is_shadow_root()) + return; + static_cast(root).increment_slot_count(); +} + +void HTMLSlotElement::removed_from(Node* old_parent) +{ + Base::removed_from(old_parent); + if (!old_parent) + return; + auto& root = old_parent->root(); + if (!root.is_shadow_root()) + return; + static_cast(root).decrement_slot_count(); +} + } diff --git a/Libraries/LibWeb/HTML/HTMLSlotElement.h b/Libraries/LibWeb/HTML/HTMLSlotElement.h index a39d17ebc879..9a1fbb6e5026 100644 --- a/Libraries/LibWeb/HTML/HTMLSlotElement.h +++ b/Libraries/LibWeb/HTML/HTMLSlotElement.h @@ -45,6 +45,9 @@ class HTMLSlotElement final virtual void initialize(JS::Realm&) override; virtual void visit_edges(JS::Cell::Visitor&) override; + virtual void inserted() override; + virtual void removed_from(Node*) override; + virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value, Optional const& namespace_) override; // https://html.spec.whatwg.org/multipage/scripting.html#manually-assigned-nodes