diff options
author | Simon Wülker <simon.wuelker@arcor.de> | 2025-01-19 15:05:05 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-19 14:05:05 +0000 |
commit | dabe162d44a2b8a47b7a9dc8566e7f51ae678d05 (patch) | |
tree | 0b915202184ab6924ecb38cc961bbd4dd8ed830e /components/script/dom/element.rs | |
parent | 8bb50fa3c9d82e2575b02cefb6558467a8187439 (diff) | |
download | servo-dabe162d44a2b8a47b7a9dc8566e7f51ae678d05.tar.gz servo-dabe162d44a2b8a47b7a9dc8566e7f51ae678d05.zip |
Implement shadow dom slots (#35013)
* Implement slot-related algorithms
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Hook up slot elements to DOM creation logic
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Set a slot assignment mode for servo-internal shadow roots
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Assign slots when a slottable's slot attribute changes
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Properly compute slot name
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* ./mach test-tidy
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Update <slot> name when name attribute changes
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Implement fast path for Node::assign_slottables_for_a_tree
assign_slottables_for_a_tree traverses all descendants of the node
and is potentially very expensive. If the node is not a shadow root
then assigning slottables to it won't have any effect, so we
take a fast path out.
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Move slottable data into ElementRareData
This shrinks all element descendants back to their
original size.
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Address review comments
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Update WPT expectations
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Diffstat (limited to 'components/script/dom/element.rs')
-rw-r--r-- | components/script/dom/element.rs | 73 |
1 files changed, 70 insertions, 3 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 166b9707e31..58a4d26a6a5 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -74,7 +74,7 @@ use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function; use crate::dom::bindings::codegen::Bindings::HTMLTemplateElementBinding::HTMLTemplateElementMethods; use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; use crate::dom::bindings::codegen::Bindings::ShadowRootBinding::{ - ShadowRootMethods, ShadowRootMode, + ShadowRootMethods, ShadowRootMode, SlotAssignmentMode, }; use crate::dom::bindings::codegen::Bindings::WindowBinding::{ ScrollBehavior, ScrollToOptions, WindowMethods, @@ -105,6 +105,7 @@ use crate::dom::domrectlist::DOMRectList; use crate::dom::domtokenlist::DOMTokenList; use crate::dom::elementinternals::ElementInternals; use crate::dom::eventtarget::EventTarget; +use crate::dom::globalscope::GlobalScope; use crate::dom::htmlanchorelement::HTMLAnchorElement; use crate::dom::htmlbodyelement::{HTMLBodyElement, HTMLBodyElementLayoutHelpers}; use crate::dom::htmlbuttonelement::HTMLButtonElement; @@ -124,6 +125,7 @@ use crate::dom::htmlobjectelement::HTMLObjectElement; use crate::dom::htmloptgroupelement::HTMLOptGroupElement; use crate::dom::htmloutputelement::HTMLOutputElement; use crate::dom::htmlselectelement::HTMLSelectElement; +use crate::dom::htmlslotelement::{HTMLSlotElement, Slottable}; use crate::dom::htmlstyleelement::HTMLStyleElement; use crate::dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementLayoutHelpers}; use crate::dom::htmltableelement::{HTMLTableElement, HTMLTableElementLayoutHelpers}; @@ -510,6 +512,7 @@ impl Element { is_ua_widget: IsUserAgentWidget, mode: ShadowRootMode, clonable: bool, + slot_assignment_mode: SlotAssignmentMode, ) -> Fallible<DomRoot<ShadowRoot>> { // Step 1. // If element’s namespace is not the HTML namespace, @@ -536,7 +539,13 @@ impl Element { } // Steps 4, 5 and 6. - let shadow_root = ShadowRoot::new(self, &self.node.owner_doc(), mode, clonable); + let shadow_root = ShadowRoot::new( + self, + &self.node.owner_doc(), + mode, + slot_assignment_mode, + clonable, + ); self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root)); shadow_root .upcast::<Node>() @@ -603,6 +612,43 @@ impl Element { Some(node) => node.is::<Document>(), } } + + pub(crate) fn assigned_slot(&self) -> Option<DomRoot<HTMLSlotElement>> { + let assigned_slot = self + .rare_data + .borrow() + .as_ref()? + .slottable_data + .assigned_slot + .as_ref()? + .as_rooted(); + Some(assigned_slot) + } + + pub(crate) fn set_assigned_slot(&self, assigned_slot: DomRoot<HTMLSlotElement>) { + self.ensure_rare_data().slottable_data.assigned_slot = Some(assigned_slot.as_traced()); + } + + pub(crate) fn manual_slot_assignment(&self) -> Option<DomRoot<HTMLSlotElement>> { + let manually_assigned_slot = self + .rare_data + .borrow() + .as_ref()? + .slottable_data + .manual_slot_assignment + .as_ref()? + .as_rooted(); + Some(manually_assigned_slot) + } + + pub(crate) fn set_manual_slot_assignment( + &self, + manually_assigned_slot: Option<&HTMLSlotElement>, + ) { + self.ensure_rare_data() + .slottable_data + .manual_slot_assignment = manually_assigned_slot.map(Dom::from_ref); + } } /// <https://dom.spec.whatwg.org/#valid-shadow-host-name> @@ -3084,7 +3130,12 @@ impl ElementMethods<crate::DomTypeHolder> for Element { fn AttachShadow(&self, init: &ShadowRootInit) -> Fallible<DomRoot<ShadowRoot>> { // Step 1. Run attach a shadow root with this, init["mode"], init["clonable"], init["serializable"], // init["delegatesFocus"], and init["slotAssignment"]. - let shadow_root = self.attach_shadow(IsUserAgentWidget::No, init.mode, init.clonable)?; + let shadow_root = self.attach_shadow( + IsUserAgentWidget::No, + init.mode, + init.clonable, + init.slotAssignment, + )?; // Step 2. Return this’s shadow root. Ok(shadow_root) @@ -3460,6 +3511,16 @@ impl ElementMethods<crate::DomTypeHolder> for Element { fn SetAriaValueText(&self, value: Option<DOMString>, can_gc: CanGc) { self.set_nullable_string_attribute(&local_name!("aria-valuetext"), value, can_gc); } + + /// <https://dom.spec.whatwg.org/#dom-slotable-assignedslot> + fn GetAssignedSlot(&self) -> Option<DomRoot<HTMLSlotElement>> { + let cx = GlobalScope::get_cx(); + + // > The assignedSlot getter steps are to return the result of + // > find a slot given this and with the open flag set. + rooted!(in(*cx) let slottable = Slottable::Element(Dom::from_ref(self))); + slottable.find_a_slot(true) + } } impl VirtualMethods for Element { @@ -3600,6 +3661,12 @@ impl VirtualMethods for Element { } } }, + &local_name!("slot") => { + // Update slottable data + let cx = GlobalScope::get_cx(); + rooted!(in(*cx) let slottable = Slottable::Element(Dom::from_ref(self))); + slottable.update_slot_name(attr, mutation, CanGc::note()) + }, _ => { // FIXME(emilio): This is pretty dubious, and should be done in // the relevant super-classes. |