diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/element.rs | 6 | ||||
-rw-r--r-- | components/script/dom/node.rs | 40 |
2 files changed, 34 insertions, 12 deletions
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 006d99eb2f1..ca7effd3e09 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -3665,7 +3665,11 @@ impl VirtualMethods for Element { } if let Some(ref value) = *self.id_attribute.borrow() { if let Some(ref shadow_root) = self.containing_shadow_root() { - shadow_root.unregister_element_id(self, value.clone()); + // Only unregister the element id if the node was disconnected from it's shadow root + // (as opposed to the whole shadow tree being disconnected as a whole) + if !self.upcast::<Node>().is_in_shadow_tree() { + shadow_root.unregister_element_id(self, value.clone()); + } } else { doc.unregister_element_id(self, value.clone()); } diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 09684c5d9e9..aaa25abc3a6 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -316,17 +316,28 @@ impl Node { /// Clean up flags and unbind from tree. pub fn complete_remove_subtree(root: &Node, context: &UnbindContext) { - for node in root.traverse_preorder(ShadowIncluding::Yes) { - // Out-of-document elements never have the descendants flag set. - node.set_flag( - NodeFlags::IS_IN_DOC | - NodeFlags::IS_CONNECTED | - NodeFlags::HAS_DIRTY_DESCENDANTS | - NodeFlags::HAS_SNAPSHOT | - NodeFlags::HANDLED_SNAPSHOT, - false, - ); + // Flags that reset when a node is disconnected + const RESET_FLAGS: NodeFlags = NodeFlags::IS_IN_DOC + .union(NodeFlags::IS_CONNECTED) + .union(NodeFlags::HAS_DIRTY_DESCENDANTS) + .union(NodeFlags::HAS_SNAPSHOT) + .union(NodeFlags::HANDLED_SNAPSHOT); + + for node in root.traverse_preorder(ShadowIncluding::No) { + node.set_flag(RESET_FLAGS | NodeFlags::IS_IN_SHADOW_TREE, false); + + // If the element has a shadow root attached to it then we traverse that as well, + // but without touching the IS_IN_SHADOW_TREE flags of the children + if let Some(shadow_root) = node.downcast::<Element>().and_then(Element::shadow_root) { + for node in shadow_root + .upcast::<Node>() + .traverse_preorder(ShadowIncluding::Yes) + { + node.set_flag(RESET_FLAGS, false); + } + } } + for node in root.traverse_preorder(ShadowIncluding::Yes) { node.clean_up_style_and_layout_data(); @@ -608,6 +619,11 @@ impl Node { self.flags.get().contains(NodeFlags::IS_CONNECTED) } + /// Return true iff the node's root is a Document or a ShadowRoot + pub fn is_connected_to_tree(&self) -> bool { + self.is_connected() || self.is_in_shadow_tree() + } + /// Returns the type ID of this node. pub fn type_id(&self) -> NodeTypeId { match *self.eventtarget.type_id() { @@ -3559,6 +3575,8 @@ pub struct UnbindContext<'a> { /// The next sibling of the inclusive ancestor that was removed. pub next_sibling: Option<&'a Node>, /// Whether the tree is connected. + /// + /// A tree is connected iff it's root is a Document or a ShadowRoot. pub tree_connected: bool, /// Whether the tree is in doc. pub tree_in_doc: bool, @@ -3577,7 +3595,7 @@ impl<'a> UnbindContext<'a> { parent, prev_sibling, next_sibling, - tree_connected: parent.is_connected(), + tree_connected: parent.is_connected_to_tree(), tree_in_doc: parent.is_in_doc(), } } |