diff --git a/components/layout_thread/dom_wrapper.rs b/components/layout_thread/dom_wrapper.rs index 5d815517532a..32fccdeecdd8 100644 --- a/components/layout_thread/dom_wrapper.rs +++ b/components/layout_thread/dom_wrapper.rs @@ -189,7 +189,9 @@ impl<'lr> TShadowRoot for ServoShadowRoot<'lr> { } fn host(&self) -> ServoLayoutElement<'lr> { - ServoLayoutElement::from_layout_js(unsafe { self.shadow_root.get_host_for_layout() }) + ServoLayoutElement::from_layout_js(unsafe { + self.shadow_root.get_host_for_layout().unwrap() + }) } fn style_data<'a>(&self) -> Option<&'a CascadeData> diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 61e2ed1a3be0..a2ce8d0678c4 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -491,7 +491,7 @@ impl Element { self.ensure_rare_data().shadow_root = Some(Dom::from_ref(&*shadow_root)); shadow_root .upcast::() - .set_containing_shadow_root(&shadow_root); + .set_containing_shadow_root(Some(&shadow_root)); if self.is_connected() { self.node.owner_doc().register_shadow_root(&*shadow_root); @@ -504,6 +504,7 @@ impl Element { pub fn detach_shadow(&self) { if let Some(ref shadow_root) = self.shadow_root() { + shadow_root.detach(); self.node.owner_doc().unregister_shadow_root(shadow_root); self.ensure_rare_data().shadow_root = None; } else { diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index f20db8eb83e9..007e1c8d9547 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -1737,55 +1737,53 @@ impl HTMLMediaElement { // if we are already showing the controls. return; } - if let Ok(shadow_root) = element.attach_shadow(IsUserAgentWidget::Yes) { - let document = document_from_node(self); - let script = HTMLScriptElement::new( - local_name!("script"), - None, - &document, - ElementCreator::ScriptCreated, - ); - let mut media_controls_script = - resources::read_string(EmbedderResource::MediaControlsJS); - // This is our hacky way to temporarily workaround the lack of a privileged - // JS context. - // The media controls UI accesses the document.servoGetMediaControls(id) API - // to get an instance to the media controls ShadowRoot. - // `id` needs to match the internally generated UUID assigned to a media element. - let id = document.register_media_controls(&shadow_root); - let media_controls_script = media_controls_script.as_mut_str().replace("@@@id@@@", &id); - *self.media_controls_id.borrow_mut() = Some(id); - script - .upcast::() - .SetTextContent(Some(DOMString::from(media_controls_script))); - if let Err(e) = shadow_root - .upcast::() - .AppendChild(&*script.upcast::()) - { - warn!("Could not render media controls {:?}", e); - return; - } - - let media_controls_style = resources::read_string(EmbedderResource::MediaControlsCSS); - let style = HTMLStyleElement::new( - local_name!("script"), - None, - &document, - ElementCreator::ScriptCreated, - ); - style - .upcast::() - .SetTextContent(Some(DOMString::from(media_controls_style))); + let shadow_root = element.attach_shadow(IsUserAgentWidget::Yes).unwrap(); + let document = document_from_node(self); + let script = HTMLScriptElement::new( + local_name!("script"), + None, + &document, + ElementCreator::ScriptCreated, + ); + let mut media_controls_script = resources::read_string(EmbedderResource::MediaControlsJS); + // This is our hacky way to temporarily workaround the lack of a privileged + // JS context. + // The media controls UI accesses the document.servoGetMediaControls(id) API + // to get an instance to the media controls ShadowRoot. + // `id` needs to match the internally generated UUID assigned to a media element. + let id = document.register_media_controls(&shadow_root); + let media_controls_script = media_controls_script.as_mut_str().replace("@@@id@@@", &id); + *self.media_controls_id.borrow_mut() = Some(id); + script + .upcast::() + .SetTextContent(Some(DOMString::from(media_controls_script))); + if let Err(e) = shadow_root + .upcast::() + .AppendChild(&*script.upcast::()) + { + warn!("Could not render media controls {:?}", e); + return; + } - if let Err(e) = shadow_root - .upcast::() - .AppendChild(&*style.upcast::()) - { - warn!("Could not render media controls {:?}", e); - } + let media_controls_style = resources::read_string(EmbedderResource::MediaControlsCSS); + let style = HTMLStyleElement::new( + local_name!("script"), + None, + &document, + ElementCreator::ScriptCreated, + ); + style + .upcast::() + .SetTextContent(Some(DOMString::from(media_controls_style))); - self.upcast::().dirty(NodeDamage::OtherNodeDamage); + if let Err(e) = shadow_root + .upcast::() + .AppendChild(&*style.upcast::()) + { + warn!("Could not render media controls {:?}", e); } + + self.upcast::().dirty(NodeDamage::OtherNodeDamage); } fn remove_controls(&self) { diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index fe7f9ec29c27..9eb9210509ec 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -283,7 +283,7 @@ impl Node { for node in new_child.traverse_preorder(ShadowIncluding::No) { if parent_in_shadow_tree { if let Some(shadow_root) = self.containing_shadow_root() { - node.set_containing_shadow_root(&*shadow_root); + node.set_containing_shadow_root(Some(&*shadow_root)); } debug_assert!(node.containing_shadow_root().is_some()); } @@ -961,8 +961,8 @@ impl Node { .map(|sr| DomRoot::from_ref(&**sr)) } - pub fn set_containing_shadow_root(&self, shadow_root: &ShadowRoot) { - self.ensure_rare_data().containing_shadow_root = Some(Dom::from_ref(shadow_root)); + pub fn set_containing_shadow_root(&self, shadow_root: Option<&ShadowRoot>) { + self.ensure_rare_data().containing_shadow_root = shadow_root.map(|sr| Dom::from_ref(sr)); } pub fn is_in_html_doc(&self) -> bool { @@ -1241,7 +1241,7 @@ impl LayoutNodeHelpers for LayoutDom { let parent = (*self.unsafe_get()).parent_node.get_inner_as_layout(); if let Some(ref parent) = parent { if let Some(shadow_root) = parent.downcast::() { - return Some(shadow_root.get_host_for_layout().upcast()); + return shadow_root.get_host_for_layout().map(|h| h.upcast()); } } parent diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs index dc3977e7c561..11db6416f9fe 100644 --- a/components/script/dom/shadowroot.rs +++ b/components/script/dom/shadowroot.rs @@ -41,7 +41,7 @@ pub struct ShadowRoot { document_fragment: DocumentFragment, document_or_shadow_root: DocumentOrShadowRoot, document: Dom, - host: Dom, + host: MutNullableDom, /// List of author styles associated with nodes in this shadow tree. author_styles: DomRefCell>, stylesheet_list: MutNullableDom, @@ -62,7 +62,7 @@ impl ShadowRoot { document_fragment, document_or_shadow_root: DocumentOrShadowRoot::new(document.window()), document: Dom::from_ref(document), - host: Dom::from_ref(host), + host: MutNullableDom::new(Some(host)), author_styles: DomRefCell::new(AuthorStyles::new()), stylesheet_list: MutNullableDom::new(None), window: Dom::from_ref(document.window()), @@ -77,6 +77,16 @@ impl ShadowRoot { ) } + pub fn detach(&self) { + self.host.set(None); + let node = self.upcast::(); + node.set_containing_shadow_root(None); + node.set_flag(NodeFlags::IS_CONNECTED, false); + for child in node.traverse_preorder(ShadowIncluding::No) { + child.set_flag(NodeFlags::IS_CONNECTED, false); + } + } + pub fn get_focused_element(&self) -> Option> { //XXX get retargeted focused element None @@ -130,9 +140,9 @@ impl ShadowRoot { self.document.invalidate_shadow_roots_stylesheets(); self.author_styles.borrow_mut().stylesheets.force_dirty(); // Mark the host element dirty so a reflow will be performed. - self.host - .upcast::() - .dirty(NodeDamage::NodeStyleDamaged); + if let Some(host) = self.host.get() { + host.upcast::().dirty(NodeDamage::NodeStyleDamaged); + } } /// Remove any existing association between the provided id and any elements @@ -216,7 +226,9 @@ impl ShadowRootMethods for ShadowRoot { /// https://dom.spec.whatwg.org/#dom-shadowroot-host fn Host(&self) -> DomRoot { - DomRoot::from_ref(&self.host) + let host = self.host.get(); + debug_assert!(host.is_some()); + host.unwrap() } // https://drafts.csswg.org/cssom/#dom-document-stylesheets @@ -232,7 +244,7 @@ impl ShadowRootMethods for ShadowRoot { #[allow(unsafe_code)] pub trait LayoutShadowRootHelpers { - unsafe fn get_host_for_layout(&self) -> LayoutDom; + unsafe fn get_host_for_layout(&self) -> Option>; unsafe fn get_style_data_for_layout<'a, E: TElement>( &self, ) -> &'a AuthorStyles; @@ -247,8 +259,8 @@ pub trait LayoutShadowRootHelpers { impl LayoutShadowRootHelpers for LayoutDom { #[inline] #[allow(unsafe_code)] - unsafe fn get_host_for_layout(&self) -> LayoutDom { - (*self.unsafe_get()).host.to_layout() + unsafe fn get_host_for_layout(&self) -> Option> { + (*self.unsafe_get()).host.get_inner_as_layout() } #[inline]