diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs index e6c38aa1fb3..3e245ccdd35 100644 --- a/components/script/layout_wrapper.rs +++ b/components/script/layout_wrapper.rs @@ -199,6 +199,10 @@ impl<'ln> TNode for ServoLayoutNode<'ln> { self.node.parent_node_ref().map(|node| self.new_with_this_lifetime(&node)) } } + + fn is_in_doc(&self) -> bool { + unsafe { (*self.node.unsafe_get()).is_in_doc() } + } } pub struct ServoChildrenIterator<'a> { diff --git a/components/style/dom.rs b/components/style/dom.rs index e9095ec0c9f..6f117259689 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -99,6 +99,8 @@ pub trait TNode : Sized + Copy + Clone + Debug + NodeInfo { unsafe fn set_can_be_fragmented(&self, value: bool); fn parent_node(&self) -> Option; + + fn is_in_doc(&self) -> bool; } /// Wrapper to output the ElementData along with the node when formatting for diff --git a/components/style/gecko/wrapper.rs b/components/style/gecko/wrapper.rs index dfdbf749875..a3fe48ccc89 100644 --- a/components/style/gecko/wrapper.rs +++ b/components/style/gecko/wrapper.rs @@ -157,6 +157,10 @@ impl<'ln> TNode for GeckoNode<'ln> { unsafe { bindings::Gecko_GetParentNode(self.0).map(GeckoNode) } } + fn is_in_doc(&self) -> bool { + unsafe { bindings::Gecko_IsInDocument(self.0) } + } + fn needs_dirty_on_viewport_size_changed(&self) -> bool { // Gecko's node doesn't have the DIRTY_ON_VIEWPORT_SIZE_CHANGE flag, // so we force them to be dirtied on viewport size change, regardless if diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 721880679a5..c8c4bdf686f 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -267,6 +267,9 @@ extern "C" { extern "C" { pub fn Gecko_NodeIsElement(node: RawGeckoNodeBorrowed) -> bool; } +extern "C" { + pub fn Gecko_IsInDocument(node: RawGeckoNodeBorrowed) -> bool; +} extern "C" { pub fn Gecko_GetParentNode(node: RawGeckoNodeBorrowed) -> RawGeckoNodeBorrowedOrNull; diff --git a/components/style/traversal.rs b/components/style/traversal.rs index 8a7ae7b241a..1053db613c6 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -324,16 +324,23 @@ pub fn resolve_style(context: &StyleContext, element: E, // on the Element. callback(element.borrow_data().unwrap().styles()); - // Clear any styles in display:none subtrees to leave the tree in a valid state. - if let Some(root) = display_none_root { + // Clear any styles in display:none subtrees or subtrees not in the document, + // to leave the tree in a valid state. For display:none subtrees, we leave + // the styles on the display:none root, but for subtrees not in the document, + // we clear styles all the way up to the root of the disconnected subtree. + let in_doc = element.as_node().is_in_doc(); + if !in_doc || display_none_root.is_some() { let mut curr = element; loop { unsafe { curr.unset_dirty_descendants(); } - if curr == root { + if in_doc && curr == display_none_root.unwrap() { break; } clear_data(curr); - curr = curr.parent_element().unwrap(); + curr = match curr.parent_element() { + Some(parent) => parent, + None => break, + }; } } }