diff options
author | Simon Wülker <simon.wuelker@arcor.de> | 2025-03-11 00:11:20 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-10 23:11:20 +0000 |
commit | fd0e2125c60506fea5408b34a0c2021b8ca7bf00 (patch) | |
tree | 7e8dac6454c4a52857e727420fdd8b3361b2c7c2 /components/script/dom/shadowroot.rs | |
parent | 0419a7818dc051aef9f0bb9022ee89aaa4183b99 (diff) | |
download | servo-fd0e2125c60506fea5408b34a0c2021b8ca7bf00.tar.gz servo-fd0e2125c60506fea5408b34a0c2021b8ca7bf00.zip |
Keep a list of slot descendants on each shadow root (#35802)
This makes it much faster to traverse over the slot descendants of
a shadow root, which is a fairly costly part of "assign slottables to a tree".
This reduces the time it takes for the results to load on wpt.fyi from
over 3 minutes to about 5 seconds.
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Diffstat (limited to 'components/script/dom/shadowroot.rs')
-rw-r--r-- | components/script/dom/shadowroot.rs | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index 357594a0948..c1adb60f566 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -2,6 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use std::collections::HashMap; +use std::collections::hash_map::Entry; + use dom_struct::dom_struct; use servo_arc::Arc; use servo_atoms::Atom; @@ -13,6 +16,7 @@ use style::stylist::{CascadeData, Stylist}; use crate::conversions::Convert; use crate::dom::bindings::cell::DomRefCell; +use crate::dom::bindings::codegen::Bindings::HTMLSlotElementBinding::HTMLSlotElement_Binding::HTMLSlotElementMethods; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::ShadowRoot_Binding::ShadowRootMethods; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{ ShadowRootMode, SlotAssignmentMode, @@ -27,8 +31,10 @@ use crate::dom::document::Document; use crate::dom::documentfragment::DocumentFragment; use crate::dom::documentorshadowroot::{DocumentOrShadowRoot, StyleSheetInDocument}; use crate::dom::element::Element; +use crate::dom::htmlslotelement::HTMLSlotElement; use crate::dom::node::{ BindContext, Node, NodeDamage, NodeFlags, NodeTraits, ShadowIncluding, UnbindContext, + VecPreOrderInsertionHelper, }; use crate::dom::stylesheetlist::{StyleSheetList, StyleSheetListOwner}; use crate::dom::types::EventTarget; @@ -65,6 +71,8 @@ pub(crate) struct ShadowRoot { /// <https://dom.spec.whatwg.org/#dom-shadowroot-clonable> clonable: bool, + + slots: DomRefCell<HashMap<DOMString, Vec<Dom<HTMLSlotElement>>>>, } impl ShadowRoot { @@ -95,6 +103,7 @@ impl ShadowRoot { mode, slot_assignment_mode, clonable, + slots: Default::default(), } } @@ -209,6 +218,40 @@ impl ShadowRoot { root, ); } + + pub(crate) fn register_slot(&self, slot: &HTMLSlotElement) { + debug!("Registering slot with name={:?}", slot.Name().str()); + + let mut slots = self.slots.borrow_mut(); + + let slots_with_the_same_name = slots.entry(slot.Name()).or_default(); + + // Insert the slot before the first element that comes after it in tree order + slots_with_the_same_name.insert_pre_order(slot, self.upcast::<Node>()); + } + + pub(crate) fn unregister_slot(&self, name: DOMString, slot: &HTMLSlotElement) { + debug!("Unregistering slot with name={:?}", name.str()); + + let mut slots = self.slots.borrow_mut(); + let Entry::Occupied(mut entry) = slots.entry(name) else { + panic!("slot is not registered"); + }; + entry.get_mut().retain(|s| slot != &**s); + } + + /// Find the first slot with the given name among this root's descendants in tree order + pub(crate) fn slot_for_name(&self, name: &DOMString) -> Option<DomRoot<HTMLSlotElement>> { + self.slots + .borrow() + .get(name) + .and_then(|slots| slots.first()) + .map(|slot| slot.as_rooted()) + } + + pub(crate) fn has_slot_descendants(&self) -> bool { + !self.slots.borrow().is_empty() + } } impl ShadowRootMethods<crate::DomTypeHolder> for ShadowRoot { |