From f02e516f323cf63d4791e8d88f74fe1de9521e8f Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 19 Dec 2019 18:10:42 -0500 Subject: [PATCH 1/5] Remove unnecessary Option. --- components/script/dom/audiocontext.rs | 4 +--- components/script/dom/document.rs | 4 ++-- components/script/dom/htmlmediaelement.rs | 4 +--- components/script/dom/mediasession.rs | 4 +--- components/script/dom/offlineaudiocontext.rs | 4 +--- components/script/dom/window.rs | 8 ++++---- 6 files changed, 10 insertions(+), 18 deletions(-) diff --git a/components/script/dom/audiocontext.rs b/components/script/dom/audiocontext.rs index d5b1c3bdb56..b81caed793b 100644 --- a/components/script/dom/audiocontext.rs +++ b/components/script/dom/audiocontext.rs @@ -75,9 +75,7 @@ impl AudioContext { #[allow(unrooted_must_root)] pub fn new(window: &Window, options: &AudioContextOptions) -> DomRoot { - let pipeline_id = window - .pipeline_id() - .expect("Cannot create AudioContext outside of a pipeline"); + let pipeline_id = window.pipeline_id(); let context = AudioContext::new_inherited(options, pipeline_id); let context = reflect_dom_object(Box::new(context), window, AudioContextBinding::Wrap); context.resume(); diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 6ee46bea95b..50566ca8d3f 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -519,7 +519,7 @@ impl Document { // Set the document's activity level, reflow if necessary, and suspend or resume timers. self.activity.set(activity); let media = ServoMedia::get().unwrap(); - let pipeline_id = self.window().pipeline_id().expect("doc with no pipeline"); + let pipeline_id = self.window().pipeline_id(); let client_context_id = ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get()); @@ -3318,7 +3318,7 @@ impl Document { let script_msg = CommonScriptMsg::Task( ScriptThreadEventCategory::EnterFullscreen, handler, - pipeline_id, + Some(pipeline_id), TaskSourceName::DOMManipulation, ); let msg = MainThreadScriptMsg::Common(script_msg); diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index d9b0f11beef..d0e73dabc74 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -1340,9 +1340,7 @@ impl HTMLMediaElement { let audio_renderer = self.audio_renderer.borrow().as_ref().map(|r| r.clone()); - let pipeline_id = window - .pipeline_id() - .expect("Cannot create player outside of a pipeline"); + let pipeline_id = window.pipeline_id(); let client_context_id = ClientContextId::build(pipeline_id.namespace_id.0, pipeline_id.index.0.get()); let player = ServoMedia::get().unwrap().create_player( diff --git a/components/script/dom/mediasession.rs b/components/script/dom/mediasession.rs index c8df282f364..54a6d2d3660 100644 --- a/components/script/dom/mediasession.rs +++ b/components/script/dom/mediasession.rs @@ -105,9 +105,7 @@ impl MediaSession { pub fn send_event(&self, event: MediaSessionEvent) { let global = self.global(); let window = global.as_window(); - let pipeline_id = window - .pipeline_id() - .expect("Cannot send media session event outside of a pipeline"); + let pipeline_id = window.pipeline_id(); window.send_to_constellation(ScriptMsg::MediaSessionEvent(pipeline_id, event)); } diff --git a/components/script/dom/offlineaudiocontext.rs b/components/script/dom/offlineaudiocontext.rs index a524595d6ea..7b8d3f52111 100644 --- a/components/script/dom/offlineaudiocontext.rs +++ b/components/script/dom/offlineaudiocontext.rs @@ -83,9 +83,7 @@ impl OfflineAudioContext { { return Err(Error::NotSupported); } - let pipeline_id = window - .pipeline_id() - .expect("Cannot create audio context outside of a pipeline"); + let pipeline_id = window.pipeline_id(); let context = OfflineAudioContext::new_inherited(channel_count, length, sample_rate, pipeline_id); Ok(reflect_dom_object( diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index ce290caabf7..358db4a06f9 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1987,7 +1987,7 @@ impl Window { .task_canceller(TaskSourceName::DOMManipulation) .wrap_task(task), ), - self.pipeline_id(), + Some(self.pipeline_id()), TaskSourceName::DOMManipulation, )); doc.set_url(load_data.url.clone()); @@ -2353,8 +2353,8 @@ impl Window { unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) } } - pub fn pipeline_id(&self) -> Option { - Some(self.upcast::().pipeline_id()) + pub fn pipeline_id(&self) -> PipelineId { + self.upcast::().pipeline_id() } } @@ -2485,7 +2485,7 @@ impl Window { .task_canceller(TaskSourceName::DOMManipulation) .wrap_task(task), ), - self.pipeline_id(), + Some(self.pipeline_id()), TaskSourceName::DOMManipulation, )); } From 2e6252f25686824a73ba267b773d9c62e5843f74 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 19 Dec 2019 18:11:32 -0500 Subject: [PATCH 2/5] Avoid fetching node global from HTMLMediaElement's destructor. --- components/script/dom/htmlmediaelement.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index d0e73dabc74..6cbb25157ff 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -74,7 +74,7 @@ use html5ever::{LocalName, Prefix}; use http::header::{self, HeaderMap, HeaderValue}; use ipc_channel::ipc; use ipc_channel::router::ROUTER; -use media::{glplayer_channel, GLPlayerMsg, GLPlayerMsgForward}; +use media::{glplayer_channel, GLPlayerMsg, GLPlayerMsgForward, WindowGLContext}; use net_traits::image::base::Image; use net_traits::image_cache::ImageResponse; use net_traits::request::{Destination, Referrer}; @@ -373,6 +373,8 @@ pub struct HTMLMediaElement { /// the access to the "privileged" document.servoGetMediaControls(id) API by /// keeping a whitelist of media controls identifiers. media_controls_id: DomRefCell>, + #[ignore_malloc_size_of = "Defined in other crates"] + player_context: WindowGLContext, } /// @@ -437,6 +439,7 @@ impl HTMLMediaElement { current_fetch_context: DomRefCell::new(None), id: Cell::new(0), media_controls_id: DomRefCell::new(None), + player_context: document.window().get_player_context(), } } @@ -1967,15 +1970,14 @@ impl HTMLMediaElement { impl Drop for HTMLMediaElement { fn drop(&mut self) { - let window = window_from_node(self); - window.get_player_context().glplayer_chan.map(|pipeline| { + if let Some(ref pipeline) = self.player_context.glplayer_chan { if let Err(err) = pipeline .channel() .send(GLPlayerMsg::UnregisterPlayer(self.id.get())) { warn!("GLPlayer disappeared!: {:?}", err); } - }); + } self.remove_controls(); } From fda0572a938b95ae50cd1e7ac479cbe928028f67 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 19 Dec 2019 18:14:05 -0500 Subject: [PATCH 3/5] Avoid accessing DOM global from VRDisplay's destructor. --- components/script/dom/vrdisplay.rs | 34 ++++++++++--------- .../script/dom/vrdisplaycapabilities.rs | 4 +-- components/script/dom/vreyeparameters.rs | 4 +-- components/script/dom/vrfieldofview.rs | 4 +-- components/script/dom/vrstageparameters.rs | 7 ++-- components/script/dom/xrsystem.rs | 2 +- 6 files changed, 27 insertions(+), 28 deletions(-) diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs index f595952b07a..4b3f7426dda 100644 --- a/components/script/dom/vrdisplay.rs +++ b/components/script/dom/vrdisplay.rs @@ -23,7 +23,6 @@ use crate::dom::bindings::root::{DomRoot, MutDom, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::event::Event; use crate::dom::eventtarget::EventTarget; -use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; use crate::dom::vrdisplaycapabilities::VRDisplayCapabilities; use crate::dom::vrdisplayevent::VRDisplayEvent; @@ -32,6 +31,7 @@ use crate::dom::vrframedata::VRFrameData; use crate::dom::vrpose::VRPose; use crate::dom::vrstageparameters::VRStageParameters; use crate::dom::webglrenderingcontext::{WebGLMessageSender, WebGLRenderingContext}; +use crate::dom::window::Window; use crate::realms::InRealm; use crate::script_runtime::CommonScriptMsg; use crate::script_runtime::ScriptThreadEventCategory::WebVREvent; @@ -40,6 +40,7 @@ use canvas_traits::webgl::{webgl_channel, WebGLReceiver, WebVRCommand}; use crossbeam_channel::{unbounded, Sender}; use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; +use msg::constellation_msg::PipelineId; use profile_traits::ipc; use std::cell::Cell; use std::mem; @@ -82,6 +83,9 @@ pub struct VRDisplay { running_display_raf: Cell, paused: Cell, stopped_on_pause: Cell, + #[ignore_malloc_size_of = "channels are hard"] + webvr_thread: IpcSender, + pipeline: PipelineId, } unsafe_no_jsmanaged_fields!(WebVRDisplayData); @@ -110,7 +114,7 @@ struct VRRAFUpdate { type VRRAFUpdateSender = Sender>; impl VRDisplay { - fn new_inherited(global: &GlobalScope, display: WebVRDisplayData) -> VRDisplay { + fn new_inherited(global: &Window, display: WebVRDisplayData) -> VRDisplay { let stage = match display.stage_parameters { Some(ref params) => Some(VRStageParameters::new(params.clone(), &global)), None => None, @@ -152,10 +156,12 @@ impl VRDisplay { // This flag is set when the Display was presenting when it received a VR Pause event. // When the VR Resume event is received and the flag is set, VR presentation automatically restarts. stopped_on_pause: Cell::new(false), + webvr_thread: global.webvr_thread().expect("webvr is disabled"), + pipeline: global.pipeline_id(), } } - pub fn new(global: &GlobalScope, display: WebVRDisplayData) -> DomRoot { + pub fn new(global: &Window, display: WebVRDisplayData) -> DomRoot { reflect_dom_object( Box::new(VRDisplay::new_inherited(&global, display)), global, @@ -229,7 +235,7 @@ impl VRDisplayMethods for VRDisplay { // If not presenting we fetch inmediante VRFrameData let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); - self.webvr_thread() + self.webvr_thread .send(WebVRMsg::GetFrameData( self.global().pipeline_id(), self.DisplayId(), @@ -258,7 +264,7 @@ impl VRDisplayMethods for VRDisplay { // https://w3c.github.io/webvr/#dom-vrdisplay-resetpose fn ResetPose(&self) { let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); - self.webvr_thread() + self.webvr_thread .send(WebVRMsg::ResetPose( self.global().pipeline_id(), self.DisplayId(), @@ -398,7 +404,7 @@ impl VRDisplayMethods for VRDisplay { // Exit present let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); - self.webvr_thread() + self.webvr_thread .send(WebVRMsg::ExitPresent( self.global().pipeline_id(), self.display.borrow().display_id, @@ -452,18 +458,14 @@ impl VRDisplayMethods for VRDisplay { } impl VRDisplay { - fn webvr_thread(&self) -> IpcSender { - self.global() - .as_window() - .webvr_thread() - .expect("Shouldn't arrive here with WebVR disabled") - } - pub fn update_display(&self, display: &WebVRDisplayData) { *self.display.borrow_mut() = display.clone(); if let Some(ref stage) = display.stage_parameters { if self.stage_params.get().is_none() { - let params = Some(VRStageParameters::new(stage.clone(), &self.global())); + let params = Some(VRStageParameters::new( + stage.clone(), + &self.global().as_window(), + )); self.stage_params.set(params.as_deref()); } else { self.stage_params.get().unwrap().update(&stage); @@ -484,7 +486,7 @@ impl VRDisplay { { // Request Present let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); - self.webvr_thread() + self.webvr_thread .send(WebVRMsg::RequestPresent( self.global().pipeline_id(), self.display.borrow().display_id, @@ -730,7 +732,7 @@ impl VRDisplay { // Only called when the JSContext is destroyed while presenting. // In this case we don't want to wait for WebVR Thread response. fn force_stop_present(&self) { - self.webvr_thread() + self.webvr_thread .send(WebVRMsg::ExitPresent( self.global().pipeline_id(), self.display.borrow().display_id, diff --git a/components/script/dom/vrdisplaycapabilities.rs b/components/script/dom/vrdisplaycapabilities.rs index 858c40978a7..214ee617e1c 100644 --- a/components/script/dom/vrdisplaycapabilities.rs +++ b/components/script/dom/vrdisplaycapabilities.rs @@ -7,7 +7,7 @@ use crate::dom::bindings::codegen::Bindings::VRDisplayCapabilitiesBinding; use crate::dom::bindings::codegen::Bindings::VRDisplayCapabilitiesBinding::VRDisplayCapabilitiesMethods; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; -use crate::dom::globalscope::GlobalScope; +use crate::dom::window::Window; use dom_struct::dom_struct; use webvr_traits::WebVRDisplayCapabilities; @@ -30,7 +30,7 @@ impl VRDisplayCapabilities { pub fn new( capabilities: WebVRDisplayCapabilities, - global: &GlobalScope, + global: &Window, ) -> DomRoot { reflect_dom_object( Box::new(VRDisplayCapabilities::new_inherited(capabilities)), diff --git a/components/script/dom/vreyeparameters.rs b/components/script/dom/vreyeparameters.rs index a7463c34a28..c908b23540d 100644 --- a/components/script/dom/vreyeparameters.rs +++ b/components/script/dom/vreyeparameters.rs @@ -7,8 +7,8 @@ use crate::dom::bindings::codegen::Bindings::VREyeParametersBinding; use crate::dom::bindings::codegen::Bindings::VREyeParametersBinding::VREyeParametersMethods; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; -use crate::dom::globalscope::GlobalScope; use crate::dom::vrfieldofview::VRFieldOfView; +use crate::dom::window::Window; use crate::script_runtime::JSContext; use dom_struct::dom_struct; use js::jsapi::{Heap, JSObject}; @@ -41,7 +41,7 @@ impl VREyeParameters { } #[allow(unsafe_code)] - pub fn new(parameters: WebVREyeParameters, global: &GlobalScope) -> DomRoot { + pub fn new(parameters: WebVREyeParameters, global: &Window) -> DomRoot { let fov = VRFieldOfView::new(&global, parameters.field_of_view.clone()); let cx = global.get_cx(); diff --git a/components/script/dom/vrfieldofview.rs b/components/script/dom/vrfieldofview.rs index 25a01daaf16..8009f6a2461 100644 --- a/components/script/dom/vrfieldofview.rs +++ b/components/script/dom/vrfieldofview.rs @@ -8,7 +8,7 @@ use crate::dom::bindings::codegen::Bindings::VRFieldOfViewBinding::VRFieldOfView use crate::dom::bindings::num::Finite; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; -use crate::dom::globalscope::GlobalScope; +use crate::dom::window::Window; use dom_struct::dom_struct; use webvr_traits::WebVRFieldOfView; @@ -29,7 +29,7 @@ impl VRFieldOfView { } } - pub fn new(global: &GlobalScope, fov: WebVRFieldOfView) -> DomRoot { + pub fn new(global: &Window, fov: WebVRFieldOfView) -> DomRoot { reflect_dom_object( Box::new(VRFieldOfView::new_inherited(fov)), global, diff --git a/components/script/dom/vrstageparameters.rs b/components/script/dom/vrstageparameters.rs index 747608763e9..e9df89364c4 100644 --- a/components/script/dom/vrstageparameters.rs +++ b/components/script/dom/vrstageparameters.rs @@ -8,7 +8,7 @@ use crate::dom::bindings::codegen::Bindings::VRStageParametersBinding::VRStagePa use crate::dom::bindings::num::Finite; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::DomRoot; -use crate::dom::globalscope::GlobalScope; +use crate::dom::window::Window; use crate::script_runtime::JSContext; use dom_struct::dom_struct; use js::jsapi::{Heap, JSObject}; @@ -38,10 +38,7 @@ impl VRStageParameters { } #[allow(unsafe_code)] - pub fn new( - parameters: WebVRStageParameters, - global: &GlobalScope, - ) -> DomRoot { + pub fn new(parameters: WebVRStageParameters, global: &Window) -> DomRoot { let cx = global.get_cx(); rooted!(in (*cx) let mut array = ptr::null_mut::()); unsafe { diff --git a/components/script/dom/xrsystem.rs b/components/script/dom/xrsystem.rs index e397a4fc0b2..ec7502fa3d4 100644 --- a/components/script/dom/xrsystem.rs +++ b/components/script/dom/xrsystem.rs @@ -364,7 +364,7 @@ impl XRSystem { existing.update_display(&display); existing } else { - let root = VRDisplay::new(&self.global(), display.clone()); + let root = VRDisplay::new(&self.global().as_window(), display.clone()); self.displays.borrow_mut().push(Dom::from_ref(&*root)); root } From 3e95efdea62266c756b04f7557cf1bd3f36f3b87 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 19 Dec 2019 18:14:49 -0500 Subject: [PATCH 4/5] Avoid accessing DOM global from XR's destructor. --- components/script/dom/navigator.rs | 3 ++- components/script/dom/xrsystem.rs | 33 +++++++++++++++++------------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/components/script/dom/navigator.rs b/components/script/dom/navigator.rs index 690eb72abd3..b297b02bc69 100644 --- a/components/script/dom/navigator.rs +++ b/components/script/dom/navigator.rs @@ -184,7 +184,8 @@ impl NavigatorMethods for Navigator { /// https://immersive-web.github.io/webxr/#dom-navigator-xr fn Xr(&self) -> DomRoot { - self.xr.or_init(|| XRSystem::new(&self.global())) + self.xr + .or_init(|| XRSystem::new(&self.global().as_window())) } /// https://w3c.github.io/mediacapture-main/#dom-navigator-mediadevices diff --git a/components/script/dom/xrsystem.rs b/components/script/dom/xrsystem.rs index ec7502fa3d4..8a8f109722b 100644 --- a/components/script/dom/xrsystem.rs +++ b/components/script/dom/xrsystem.rs @@ -18,10 +18,10 @@ use crate::dom::event::Event; use crate::dom::eventtarget::EventTarget; use crate::dom::gamepad::Gamepad; use crate::dom::gamepadevent::GamepadEventType; -use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; use crate::dom::vrdisplay::VRDisplay; use crate::dom::vrdisplayevent::VRDisplayEvent; +use crate::dom::window::Window; use crate::dom::xrsession::XRSession; use crate::dom::xrtest::XRTest; use crate::realms::InRealm; @@ -30,6 +30,7 @@ use crate::task_source::TaskSource; use dom_struct::dom_struct; use ipc_channel::ipc::{self as ipc_crate, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; +use msg::constellation_msg::PipelineId; use profile_traits::ipc; use std::cell::Cell; use std::rc::Rc; @@ -46,10 +47,13 @@ pub struct XRSystem { active_immersive_session: MutNullableDom, active_inline_sessions: DomRefCell>>, test: MutNullableDom, + pipeline: PipelineId, + #[ignore_malloc_size_of = "channels are hard"] + webvr_thread: Option>, } impl XRSystem { - fn new_inherited() -> XRSystem { + fn new_inherited(pipeline: PipelineId, webvr_thread: Option>) -> XRSystem { XRSystem { eventtarget: EventTarget::new_inherited(), displays: DomRefCell::new(Vec::new()), @@ -58,13 +62,18 @@ impl XRSystem { active_immersive_session: Default::default(), active_inline_sessions: DomRefCell::new(Vec::new()), test: Default::default(), + pipeline, + webvr_thread, } } - pub fn new(global: &GlobalScope) -> DomRoot { + pub fn new(window: &Window) -> DomRoot { let root = reflect_dom_object( - Box::new(XRSystem::new_inherited()), - global, + Box::new(XRSystem::new_inherited( + window.pipeline_id(), + window.webvr_thread(), + )), + window, XRSystemBinding::Wrap, ); root.register(); @@ -304,7 +313,7 @@ impl XRSystem { } pub fn get_displays(&self) -> Result>, ()> { - if let Some(webvr_thread) = self.webvr_thread() { + if let Some(ref webvr_thread) = self.webvr_thread { let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); webvr_thread.send(WebVRMsg::GetDisplays(sender)).unwrap(); @@ -333,10 +342,6 @@ impl XRSystem { .collect()) } - fn webvr_thread(&self) -> Option> { - self.global().as_window().webvr_thread() - } - fn find_display(&self, display_id: u32) -> Option> { self.displays .borrow() @@ -346,15 +351,15 @@ impl XRSystem { } fn register(&self) { - if let Some(webvr_thread) = self.webvr_thread() { + if let Some(ref webvr_thread) = self.webvr_thread { let msg = WebVRMsg::RegisterContext(self.global().pipeline_id()); webvr_thread.send(msg).unwrap(); } } fn unregister(&self) { - if let Some(webvr_thread) = self.webvr_thread() { - let msg = WebVRMsg::UnregisterContext(self.global().pipeline_id()); + if let Some(ref webvr_thread) = self.webvr_thread { + let msg = WebVRMsg::UnregisterContext(self.pipeline); webvr_thread.send(msg).unwrap(); } } @@ -474,7 +479,7 @@ impl XRSystem { // guarantees that the gamepads always have a valid state and can be very useful for // motion capture or drawing applications. pub fn get_gamepads(&self) -> Vec> { - if let Some(wevbr_sender) = self.webvr_thread() { + if let Some(ref wevbr_sender) = self.webvr_thread { let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); let synced_ids = self From 1449bac0e19bfafbb14a71c3bb246ad28ddbf8e8 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 19 Dec 2019 18:15:30 -0500 Subject: [PATCH 5/5] Avoid accessing node global during Node's destructor. --- components/script/dom/node.rs | 34 +++++++++++++++++++----------- components/script/dom/window.rs | 4 +++- 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>, + ) { 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
. 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) { + 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::().teardown(); + self.Document() + .upcast::() + .teardown(self.layout_chan()); // Tell the constellation to drop the sender to our message-port router, if there is any. self.upcast::().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> { + 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() };