diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/element.rs | 6 | ||||
-rw-r--r-- | components/script/dom/htmlmediaelement.rs | 2 | ||||
-rw-r--r-- | components/script/dom/node.rs | 55 | ||||
-rw-r--r-- | components/script/dom/shadowroot.rs | 25 | ||||
-rw-r--r-- | components/script/dom/webidls/Element.webidl | 2 | ||||
-rw-r--r-- | components/script/dom/webidls/ShadowRoot.webidl | 6 |
6 files changed, 81 insertions, 15 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 75f8f4d4b20..594c63bbab6 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -507,8 +507,10 @@ impl Element { /// <https://dom.spec.whatwg.org/#dom-element-attachshadow> pub fn attach_shadow( &self, + // TODO: remove is_ua_widget argument is_ua_widget: IsUserAgentWidget, mode: ShadowRootMode, + clonable: bool, ) -> Fallible<DomRoot<ShadowRoot>> { // Step 1. if self.namespace != ns!(html) { @@ -546,7 +548,7 @@ impl Element { } // Steps 4, 5 and 6. - let shadow_root = ShadowRoot::new(self, &self.node.owner_doc(), mode); + let shadow_root = ShadowRoot::new(self, &self.node.owner_doc(), mode, clonable); self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root)); shadow_root .upcast::<Node>() @@ -3034,7 +3036,7 @@ 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)?; + let shadow_root = self.attach_shadow(IsUserAgentWidget::No, init.mode, init.clonable)?; // Step 2. Return this’s shadow root. Ok(shadow_root) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index e7b2fdbb30e..18bca9decee 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -1910,7 +1910,7 @@ impl HTMLMediaElement { return; } let shadow_root = element - .attach_shadow(IsUserAgentWidget::Yes, ShadowRootMode::Closed) + .attach_shadow(IsUserAgentWidget::Yes, ShadowRootMode::Closed, false) .unwrap(); let document = document_from_node(self); let script = HTMLScriptElement::new( diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 00501ea1718..3c7df12b633 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -98,7 +98,7 @@ use crate::dom::nodelist::NodeList; use crate::dom::processinginstruction::ProcessingInstruction; use crate::dom::range::WeakRangeVec; use crate::dom::raredata::NodeRareData; -use crate::dom::shadowroot::{LayoutShadowRootHelpers, ShadowRoot}; +use crate::dom::shadowroot::{IsUserAgentWidget, LayoutShadowRootHelpers, ShadowRoot}; use crate::dom::stylesheetlist::StyleSheetListOwner; use crate::dom::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement}; use crate::dom::text::Text; @@ -2247,13 +2247,13 @@ impl Node { clone_children: CloneChildrenFlag, can_gc: CanGc, ) -> DomRoot<Node> { - // Step 1. + // Step 1. If document is not given, let document be node’s node document. let document = match maybe_doc { Some(doc) => DomRoot::from_ref(doc), None => node.owner_doc(), }; - // Step 2. + // Step 2. / Step 3. // XXXabinader: clone() for each node as trait? let copy: DomRoot<Node> = match node.type_id() { NodeTypeId::DocumentType => { @@ -2337,14 +2337,15 @@ impl Node { }, }; - // Step 3. + // Step 4. Set copy’s node document and document to copy, if copy is a document, + // and set copy’s node document to document otherwise. let document = match copy.downcast::<Document>() { Some(doc) => DomRoot::from_ref(doc), None => DomRoot::from_ref(&*document), }; assert!(copy.owner_doc() == document); - // Step 4 (some data already copied in step 2). + // TODO: The spec tells us to do this in step 3. match node.type_id() { NodeTypeId::Document(_) => { let node_doc = node.downcast::<Document>().unwrap(); @@ -2370,10 +2371,12 @@ impl Node { _ => (), } - // Step 5: cloning steps. + // Step 5: Run any cloning steps defined for node in other applicable specifications and pass copy, + // node, document, and the clone children flag if set, as parameters. vtable_for(node).cloning_steps(©, maybe_doc, clone_children); - // Step 6. + // Step 6. If the clone children flag is set, then for each child child of node, in tree order: append the + // result of cloning child with document and the clone children flag set, to copy. if clone_children == CloneChildrenFlag::CloneChildren { for child in node.children() { let child_copy = Node::clone(&child, Some(&document), clone_children, can_gc); @@ -2381,7 +2384,43 @@ impl Node { } } - // Step 7. + // Step 7. If node is a shadow host whose shadow root’s clonable is true: + // NOTE: Only elements can be shadow hosts + if matches!(node.type_id(), NodeTypeId::Element(_)) { + let node_elem = node.downcast::<Element>().unwrap(); + let copy_elem = copy.downcast::<Element>().unwrap(); + + if let Some(shadow_root) = node_elem.shadow_root().filter(|r| r.Clonable()) { + // Step 7.1 Assert: copy is not a shadow host. + assert!(!copy_elem.is_shadow_host()); + + // Step 7.2 Run attach a shadow root with copy, node’s shadow root’s mode, true, + // node’s shadow root’s serializable, node’s shadow root’s delegates focus, + // and node’s shadow root’s slot assignment. + let copy_shadow_root = + copy_elem.attach_shadow(IsUserAgentWidget::No, shadow_root.Mode(), true) + .expect("placement of attached shadow root must be valid, as this is a copy of an existing one"); + + // TODO: Step 7.3 Set copy’s shadow root’s declarative to node’s shadow root’s declarative. + + // Step 7.4 For each child child of node’s shadow root, in tree order: append the result of + // cloning child with document and the clone children flag set, to copy’s shadow root. + for child in shadow_root.upcast::<Node>().children() { + let child_copy = Node::clone( + &child, + Some(&document), + CloneChildrenFlag::CloneChildren, + can_gc, + ); + + // TODO: Should we handle the error case here and in step 6? + let _inserted_node = + Node::pre_insert(&child_copy, copy_shadow_root.upcast::<Node>(), None); + } + } + } + + // Step 8. Return copy. copy } diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index da918ec0f51..77c4ba99b2a 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -55,11 +55,19 @@ pub struct ShadowRoot { /// <https://dom.spec.whatwg.org/#dom-shadowroot-mode> mode: ShadowRootMode, + + /// <https://dom.spec.whatwg.org/#dom-shadowroot-clonable> + clonable: bool, } impl ShadowRoot { #[allow(crown::unrooted_must_root)] - fn new_inherited(host: &Element, document: &Document, mode: ShadowRootMode) -> ShadowRoot { + fn new_inherited( + host: &Element, + document: &Document, + mode: ShadowRootMode, + clonable: bool, + ) -> ShadowRoot { let document_fragment = DocumentFragment::new_inherited(document); let node = document_fragment.upcast::<Node>(); node.set_flag(NodeFlags::IS_IN_SHADOW_TREE, true); @@ -77,12 +85,18 @@ impl ShadowRoot { stylesheet_list: MutNullableDom::new(None), window: Dom::from_ref(document.window()), mode, + clonable, } } - pub fn new(host: &Element, document: &Document, mode: ShadowRootMode) -> DomRoot<ShadowRoot> { + pub fn new( + host: &Element, + document: &Document, + mode: ShadowRootMode, + clonable: bool, + ) -> DomRoot<ShadowRoot> { reflect_dom_object( - Box::new(ShadowRoot::new_inherited(host, document, mode)), + Box::new(ShadowRoot::new_inherited(host, document, mode, clonable)), document.window(), ) } @@ -238,6 +252,11 @@ impl ShadowRootMethods<crate::DomTypeHolder> for ShadowRoot { self.mode } + /// <https://dom.spec.whatwg.org/#dom-shadowroot-clonable> + fn Clonable(&self) -> bool { + self.clonable + } + /// <https://dom.spec.whatwg.org/#dom-shadowroot-host> fn Host(&self) -> DomRoot<Element> { let host = self.host.get(); diff --git a/components/script/dom/webidls/Element.webidl b/components/script/dom/webidls/Element.webidl index 99d17117221..1a99d5ec480 100644 --- a/components/script/dom/webidls/Element.webidl +++ b/components/script/dom/webidls/Element.webidl @@ -91,7 +91,7 @@ dictionary ShadowRootInit { required ShadowRootMode mode; // boolean delegatesFocus = false; // SlotAssignmentMode slotAssignment = "named"; - // boolean clonable = false; + boolean clonable = false; // boolean serializable = false; }; diff --git a/components/script/dom/webidls/ShadowRoot.webidl b/components/script/dom/webidls/ShadowRoot.webidl index a1ecdc5c10f..40301f48517 100644 --- a/components/script/dom/webidls/ShadowRoot.webidl +++ b/components/script/dom/webidls/ShadowRoot.webidl @@ -9,9 +9,15 @@ [Exposed=Window] interface ShadowRoot : DocumentFragment { readonly attribute ShadowRootMode mode; + // readonly attribute boolean delegatesFocus; + // readonly attribute SlotAssignmentMode slotAssignment; + readonly attribute boolean clonable; + // readonly attribute boolean serializable; readonly attribute Element host; + // attribute EventHandler onslotchange; }; + enum ShadowRootMode { "open", "closed"}; // enum SlotAssignmentMode { "manual", "named" }; |