diff options
-rw-r--r-- | components/script/dom/node.rs | 34 | ||||
-rw-r--r-- | components/script/dom/window.rs | 4 | ||||
-rw-r--r-- | components/script/script_thread.rs | 17 |
3 files changed, 42 insertions, 13 deletions
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index 457c1f0d55c..c1da57eae88 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -67,6 +67,7 @@ use crate::dom::window::Window; use crate::script_runtime::JSContext; use crate::script_thread::ScriptThread; use app_units::Au; +use crossbeam_channel::Sender; use devtools_traits::NodeInfo; use dom_struct::dom_struct; use euclid::default::{Point2D, Rect, Size2D, Vector2D}; @@ -209,7 +210,9 @@ impl NodeFlags { impl Drop for Node { #[allow(unsafe_code)] fn drop(&mut self) { - self.style_and_layout_data.get().map(|d| self.dispose(d)); + if let Some(data) = self.style_and_layout_data.get() { + self.dispose(data, ScriptThread::get_any_layout_chan().as_ref()); + } } } @@ -224,15 +227,16 @@ enum SuppressObserver { impl Node { /// Sends the style and layout data, if any, back to the layout thread to be destroyed. - pub fn dispose(&self, data: OpaqueStyleAndLayoutData) { + pub(crate) fn dispose( + &self, + data: OpaqueStyleAndLayoutData, + layout_chan: Option<&Sender<Msg>>, + ) { debug_assert!(thread_state::get().is_script()); - let win = window_from_node(self); self.style_and_layout_data.set(None); - if win - .layout_chan() - .send(Msg::ReapStyleAndLayoutData(data)) - .is_err() - { + if layout_chan.map_or(false, |chan| { + chan.send(Msg::ReapStyleAndLayoutData(data)).is_err() + }) { warn!("layout thread unreachable - leaking layout data"); } } @@ -315,12 +319,16 @@ impl Node { false, ); } + let window = window_from_node(root); + let layout_chan = window.layout_chan(); for node in root.traverse_preorder(ShadowIncluding::Yes) { // This needs to be in its own loop, because unbind_from_tree may // rely on the state of IS_IN_DOC of the context node's descendants, // e.g. when removing a <form>. vtable_for(&&*node).unbind_from_tree(&context); - node.style_and_layout_data.get().map(|d| node.dispose(d)); + if let Some(data) = node.style_and_layout_data.get() { + node.dispose(data, Some(layout_chan)); + } // https://dom.spec.whatwg.org/#concept-node-remove step 14 if let Some(element) = node.as_custom_element() { ScriptThread::enqueue_callback_reaction( @@ -481,10 +489,12 @@ impl<'a> Iterator for QuerySelectorIterator { impl Node { impl_rare_data!(NodeRareData); - pub fn teardown(&self) { - self.style_and_layout_data.get().map(|d| self.dispose(d)); + pub(crate) fn teardown(&self, layout_chan: &Sender<Msg>) { + if let Some(data) = self.style_and_layout_data.get() { + self.dispose(data, Some(layout_chan)); + } for kid in self.children() { - kid.teardown(); + kid.teardown(layout_chan); } } diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 358db4a06f9..77021c3df48 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1403,7 +1403,9 @@ impl Window { // We tear down the active document, which causes all the attached // nodes to dispose of their layout data. This messages the layout // thread, informing it that it can safely free the memory. - self.Document().upcast::<Node>().teardown(); + self.Document() + .upcast::<Node>() + .teardown(self.layout_chan()); // Tell the constellation to drop the sender to our message-port router, if there is any. self.upcast::<GlobalScope>().remove_message_ports_router(); diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 118b4b4f653..dd0f798fcec 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -821,6 +821,23 @@ impl ScriptThreadFactory for ScriptThread { } impl ScriptThread { + pub(crate) fn get_any_layout_chan() -> Option<Sender<Msg>> { + SCRIPT_THREAD_ROOT.with(|root| { + let script_thread = match root.get() { + Some(s) => unsafe { &*s }, + None => return None, + }; + script_thread + .documents + .borrow() + .map + .values() + .next() + .map(|d| d.window().layout_chan()) + .cloned() + }) + } + pub fn runtime_handle() -> ParentRuntime { SCRIPT_THREAD_ROOT.with(|root| { let script_thread = unsafe { &*root.get().unwrap() }; |