mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Auto merge of #25345 - jdm:drop-cleanup, r=asajeffrey
Avoid accessing global objects from DOM destructors This removes all instances that I could find of DOM objects accessing `self.global()` in code that runs as part of a Drop method. This is unsafe because the GC could destroy objects in any order when doing a big sweep. Instead, these types should store the data they need as members so they can run in isolation without accessing the rest of the GC graph as part of their destructors. --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #25258 and fix #23986 - [x] There are tests for these changes
This commit is contained in:
commit
0884884796
15 changed files with 106 additions and 78 deletions
|
@ -75,9 +75,7 @@ impl AudioContext {
|
|||
|
||||
#[allow(unrooted_must_root)]
|
||||
pub fn new(window: &Window, options: &AudioContextOptions) -> DomRoot<AudioContext> {
|
||||
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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<Option<String>>,
|
||||
#[ignore_malloc_size_of = "Defined in other crates"]
|
||||
player_context: WindowGLContext,
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#dom-media-networkstate>
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1340,9 +1343,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(
|
||||
|
@ -1969,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();
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -184,7 +184,8 @@ impl NavigatorMethods for Navigator {
|
|||
|
||||
/// https://immersive-web.github.io/webxr/#dom-navigator-xr
|
||||
fn Xr(&self) -> DomRoot<XRSystem> {
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<bool>,
|
||||
paused: Cell<bool>,
|
||||
stopped_on_pause: Cell<bool>,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
webvr_thread: IpcSender<WebVRMsg>,
|
||||
pipeline: PipelineId,
|
||||
}
|
||||
|
||||
unsafe_no_jsmanaged_fields!(WebVRDisplayData);
|
||||
|
@ -110,7 +114,7 @@ struct VRRAFUpdate {
|
|||
type VRRAFUpdateSender = Sender<Result<VRRAFUpdate, ()>>;
|
||||
|
||||
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<VRDisplay> {
|
||||
pub fn new(global: &Window, display: WebVRDisplayData) -> DomRoot<VRDisplay> {
|
||||
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<WebVRMsg> {
|
||||
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,
|
||||
|
|
|
@ -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<VRDisplayCapabilities> {
|
||||
reflect_dom_object(
|
||||
Box::new(VRDisplayCapabilities::new_inherited(capabilities)),
|
||||
|
|
|
@ -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<VREyeParameters> {
|
||||
pub fn new(parameters: WebVREyeParameters, global: &Window) -> DomRoot<VREyeParameters> {
|
||||
let fov = VRFieldOfView::new(&global, parameters.field_of_view.clone());
|
||||
|
||||
let cx = global.get_cx();
|
||||
|
|
|
@ -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<VRFieldOfView> {
|
||||
pub fn new(global: &Window, fov: WebVRFieldOfView) -> DomRoot<VRFieldOfView> {
|
||||
reflect_dom_object(
|
||||
Box::new(VRFieldOfView::new_inherited(fov)),
|
||||
global,
|
||||
|
|
|
@ -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<VRStageParameters> {
|
||||
pub fn new(parameters: WebVRStageParameters, global: &Window) -> DomRoot<VRStageParameters> {
|
||||
let cx = global.get_cx();
|
||||
rooted!(in (*cx) let mut array = ptr::null_mut::<JSObject>());
|
||||
unsafe {
|
||||
|
|
|
@ -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();
|
||||
|
@ -1987,7 +1989,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 +2355,8 @@ impl Window {
|
|||
unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) }
|
||||
}
|
||||
|
||||
pub fn pipeline_id(&self) -> Option<PipelineId> {
|
||||
Some(self.upcast::<GlobalScope>().pipeline_id())
|
||||
pub fn pipeline_id(&self) -> PipelineId {
|
||||
self.upcast::<GlobalScope>().pipeline_id()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2485,7 +2487,7 @@ impl Window {
|
|||
.task_canceller(TaskSourceName::DOMManipulation)
|
||||
.wrap_task(task),
|
||||
),
|
||||
self.pipeline_id(),
|
||||
Some(self.pipeline_id()),
|
||||
TaskSourceName::DOMManipulation,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -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<XRSession>,
|
||||
active_inline_sessions: DomRefCell<Vec<Dom<XRSession>>>,
|
||||
test: MutNullableDom<XRTest>,
|
||||
pipeline: PipelineId,
|
||||
#[ignore_malloc_size_of = "channels are hard"]
|
||||
webvr_thread: Option<IpcSender<WebVRMsg>>,
|
||||
}
|
||||
|
||||
impl XRSystem {
|
||||
fn new_inherited() -> XRSystem {
|
||||
fn new_inherited(pipeline: PipelineId, webvr_thread: Option<IpcSender<WebVRMsg>>) -> 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<XRSystem> {
|
||||
pub fn new(window: &Window) -> DomRoot<XRSystem> {
|
||||
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<Vec<DomRoot<VRDisplay>>, ()> {
|
||||
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<IpcSender<WebVRMsg>> {
|
||||
self.global().as_window().webvr_thread()
|
||||
}
|
||||
|
||||
fn find_display(&self, display_id: u32) -> Option<DomRoot<VRDisplay>> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -364,7 +369,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
|
||||
}
|
||||
|
@ -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<DomRoot<Gamepad>> {
|
||||
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
|
||||
|
|
|
@ -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() };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue