diff options
Diffstat (limited to 'components/script/dom')
39 files changed, 661 insertions, 76 deletions
diff --git a/components/script/dom/audiobuffer.rs b/components/script/dom/audiobuffer.rs index a021b61ac8c..cabd281dc63 100644 --- a/components/script/dom/audiobuffer.rs +++ b/components/script/dom/audiobuffer.rs @@ -42,6 +42,7 @@ type JSAudioChannel = Heap<*mut JSObject>; pub struct AudioBuffer { reflector_: Reflector, /// Float32Arrays returned by calls to GetChannelData. + #[ignore_malloc_size_of = "mozjs"] js_channels: DomRefCell<Vec<JSAudioChannel>>, /// Aggregates the data from js_channels. /// This is Some<T> iff the buffers in js_channels are detached. diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 56805e4d9fe..023917c172c 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -105,6 +105,7 @@ use servo_media::audio::panner_node::{DistanceModel, PanningModel}; use servo_media::audio::param::ParamType; use servo_media::player::Player; use servo_media::streams::registry::MediaStreamId; +use servo_media::streams::MediaStreamType; use servo_media::webrtc::WebRtcController; use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl}; use smallvec::SmallVec; @@ -138,7 +139,7 @@ use tendril::{StrTendril, TendrilSink}; use time::{Duration, Timespec}; use uuid::Uuid; use webrender_api::{DocumentId, ImageKey, RenderApiSender}; -use webvr_traits::WebVRGamepadHand; +use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState}; /// A trait to allow tracing (only) DOM objects. pub unsafe trait JSTraceable { @@ -478,7 +479,7 @@ unsafe_no_jsmanaged_fields!(WebGLVertexArrayId); unsafe_no_jsmanaged_fields!(WebGLVersion); unsafe_no_jsmanaged_fields!(WebGLSLVersion); unsafe_no_jsmanaged_fields!(MediaList); -unsafe_no_jsmanaged_fields!(WebVRGamepadHand); +unsafe_no_jsmanaged_fields!(WebVRGamepadData, WebVRGamepadState, WebVRGamepadHand); unsafe_no_jsmanaged_fields!(ScriptToConstellationChan); unsafe_no_jsmanaged_fields!(InteractiveMetrics); unsafe_no_jsmanaged_fields!(InteractiveWindow); @@ -490,7 +491,7 @@ unsafe_no_jsmanaged_fields!(NodeId); unsafe_no_jsmanaged_fields!(AnalysisEngine, DistanceModel, PanningModel, ParamType); unsafe_no_jsmanaged_fields!(dyn Player); unsafe_no_jsmanaged_fields!(WebRtcController); -unsafe_no_jsmanaged_fields!(MediaStreamId); +unsafe_no_jsmanaged_fields!(MediaStreamId, MediaStreamType); unsafe_no_jsmanaged_fields!(Mutex<MediaFrameRenderer>); unsafe_no_jsmanaged_fields!(RenderApiSender); unsafe_no_jsmanaged_fields!(ResourceFetchTiming); diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs index 3d329119f4e..39824e334a2 100644 --- a/components/script/dom/customelementregistry.rs +++ b/components/script/dom/customelementregistry.rs @@ -719,7 +719,7 @@ pub enum CustomElementReaction { Upgrade(#[ignore_malloc_size_of = "Rc"] Rc<CustomElementDefinition>), Callback( #[ignore_malloc_size_of = "Rc"] Rc<Function>, - Box<[Heap<JSVal>]>, + #[ignore_malloc_size_of = "mozjs"] Box<[Heap<JSVal>]>, ), } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index 2d12e93774d..1b918c0537b 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -3075,6 +3075,10 @@ impl<'a> SelectorsElement for DomRoot<Element> { .map_or(false, |atom| case_sensitivity.eq_atom(id, atom)) } + fn is_part(&self, _name: &Atom) -> bool { + false + } + fn has_class(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool { Element::has_class(&**self, name, case_sensitivity) } diff --git a/components/script/dom/extendablemessageevent.rs b/components/script/dom/extendablemessageevent.rs index f9c2de13a4b..7fd16aafec4 100644 --- a/components/script/dom/extendablemessageevent.rs +++ b/components/script/dom/extendablemessageevent.rs @@ -24,6 +24,7 @@ use servo_atoms::Atom; #[dom_struct] pub struct ExtendableMessageEvent { event: ExtendableEvent, + #[ignore_malloc_size_of = "mozjs"] data: Heap<JSVal>, origin: DOMString, lastEventId: DOMString, diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs index 6092dcc9935..55989078d4f 100644 --- a/components/script/dom/filereader.rs +++ b/components/script/dom/filereader.rs @@ -83,7 +83,7 @@ pub enum FileReaderReadyState { #[derive(JSTraceable, MallocSizeOf)] pub enum FileReaderResult { - ArrayBuffer(Heap<JSVal>), + ArrayBuffer(#[ignore_malloc_size_of = "mozjs"] Heap<JSVal>), String(DOMString), } diff --git a/components/script/dom/gamepad.rs b/components/script/dom/gamepad.rs index 3e65b0a11f5..fe86a3b2329 100644 --- a/components/script/dom/gamepad.rs +++ b/components/script/dom/gamepad.rs @@ -32,6 +32,7 @@ pub struct Gamepad { connected: Cell<bool>, timestamp: Cell<f64>, mapping_type: String, + #[ignore_malloc_size_of = "mozjs"] axes: Heap<*mut JSObject>, buttons: Dom<GamepadButtonList>, pose: Option<Dom<VRPose>>, diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 91112299034..33458bf2ece 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -145,6 +145,7 @@ pub struct GlobalScope { /// they're consumed before it'd be reported. /// /// <https://html.spec.whatwg.org/multipage/#about-to-be-notified-rejected-promises-list> + #[ignore_malloc_size_of = "mozjs"] uncaught_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>, /// Promises in this list have previously been reported as rejected @@ -152,6 +153,7 @@ pub struct GlobalScope { /// in the last turn of the event loop. /// /// <https://html.spec.whatwg.org/multipage/#outstanding-rejected-promises-weak-set> + #[ignore_malloc_size_of = "mozjs"] consumed_rejections: DomRefCell<Vec<Box<Heap<*mut JSObject>>>>, } diff --git a/components/script/dom/history.rs b/components/script/dom/history.rs index e468b79440c..787591af8a3 100644 --- a/components/script/dom/history.rs +++ b/components/script/dom/history.rs @@ -40,6 +40,7 @@ enum PushOrReplace { pub struct History { reflector_: Reflector, window: Dom<Window>, + #[ignore_malloc_size_of = "mozjs"] state: Heap<JSVal>, state_id: Cell<Option<HistoryStateId>>, } diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index 8d41a685b7b..9bbfb30d46c 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -62,7 +62,6 @@ use html5ever::{LocalName, Prefix}; use http::header::{self, HeaderMap, HeaderValue}; use ipc_channel::ipc; use ipc_channel::router::ROUTER; -use mime::{self, Mime}; use net_traits::image::base::Image; use net_traits::image_cache::ImageResponse; use net_traits::request::{CredentialsMode, Destination, Referrer, RequestBuilder}; @@ -73,7 +72,7 @@ use servo_config::pref; use servo_media::player::context::{GlContext, NativeDisplay, PlayerGLContext}; use servo_media::player::frame::{Frame, FrameRenderer}; use servo_media::player::{PlaybackState, Player, PlayerError, PlayerEvent, StreamType}; -use servo_media::ServoMedia; +use servo_media::{ServoMedia, SupportsMediaType}; use servo_url::ServoUrl; use std::cell::Cell; use std::collections::VecDeque; @@ -840,9 +839,13 @@ impl HTMLMediaElement { self.fetch_request(None); }, SrcObject::MediaStream(ref stream) => { - for stream in stream.get_tracks() { - if let Err(_) = - self.player.borrow().as_ref().unwrap().set_stream(&stream) + for stream in &*stream.get_tracks() { + if let Err(_) = self + .player + .borrow() + .as_ref() + .unwrap() + .set_stream(&stream.id()) { self.queue_dedicated_media_source_failure_steps(); } @@ -1674,20 +1677,10 @@ impl HTMLMediaElementMethods for HTMLMediaElement { // https://html.spec.whatwg.org/multipage/#dom-navigator-canplaytype fn CanPlayType(&self, type_: DOMString) -> CanPlayTypeResult { - match type_.parse::<Mime>() { - // XXX GStreamer is currently not very reliable playing OGG and most of - // the media related WPTs uses OGG if we report that we are able to - // play this type. So we report that we are unable to play it to force - // the usage of other types. - // https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/520 - Ok(ref mime) - if (mime.type_() == mime::APPLICATION && mime.subtype() == mime::OCTET_STREAM) || - (mime.subtype() == mime::OGG) => - { - CanPlayTypeResult::_empty - }, - Err(_) => CanPlayTypeResult::_empty, - _ => CanPlayTypeResult::Maybe, + match ServoMedia::get().unwrap().can_play_type(&type_) { + SupportsMediaType::No => CanPlayTypeResult::_empty, + SupportsMediaType::Maybe => CanPlayTypeResult::Maybe, + SupportsMediaType::Probably => CanPlayTypeResult::Probably, } } diff --git a/components/script/dom/imagedata.rs b/components/script/dom/imagedata.rs index 9566c7b0f39..29c15f665a4 100644 --- a/components/script/dom/imagedata.rs +++ b/components/script/dom/imagedata.rs @@ -25,6 +25,7 @@ pub struct ImageData { reflector_: Reflector, width: u32, height: u32, + #[ignore_malloc_size_of = "mozjs"] data: Heap<*mut JSObject>, } diff --git a/components/script/dom/mediadevices.rs b/components/script/dom/mediadevices.rs index 0a4f00e2472..bcc575a2ef6 100644 --- a/components/script/dom/mediadevices.rs +++ b/components/script/dom/mediadevices.rs @@ -14,9 +14,11 @@ use crate::dom::bindings::root::DomRoot; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::mediastream::MediaStream; +use crate::dom::mediastreamtrack::MediaStreamTrack; use crate::dom::promise::Promise; use dom_struct::dom_struct; use servo_media::streams::capture::{Constrain, ConstrainRange, MediaTrackConstraintSet}; +use servo_media::streams::MediaStreamType; use servo_media::ServoMedia; use std::rc::Rc; @@ -51,18 +53,20 @@ impl MediaDevicesMethods for MediaDevices { InCompartment::Already(&in_compartment_proof), ); let media = ServoMedia::get().unwrap(); - let mut tracks = vec![]; + let stream = MediaStream::new(&self.global()); if let Some(constraints) = convert_constraints(&constraints.audio) { if let Some(audio) = media.create_audioinput_stream(constraints) { - tracks.push(audio) + let track = MediaStreamTrack::new(&self.global(), audio, MediaStreamType::Audio); + stream.add_track(&track); } } if let Some(constraints) = convert_constraints(&constraints.video) { if let Some(video) = media.create_videoinput_stream(constraints) { - tracks.push(video) + let track = MediaStreamTrack::new(&self.global(), video, MediaStreamType::Video); + stream.add_track(&track); } } - let stream = MediaStream::new(&self.global(), tracks); + p.resolve_native(&stream); p } diff --git a/components/script/dom/mediastream.rs b/components/script/dom/mediastream.rs index 42588afc476..2ae573b290e 100644 --- a/components/script/dom/mediastream.rs +++ b/components/script/dom/mediastream.rs @@ -3,38 +3,131 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use crate::dom::bindings::cell::DomRefCell; -use crate::dom::bindings::codegen::Bindings::MediaStreamBinding; -use crate::dom::bindings::reflector::reflect_dom_object; -use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::codegen::Bindings::MediaStreamBinding::{self, MediaStreamMethods}; +use crate::dom::bindings::error::Fallible; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::str::DOMString; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; +use crate::dom::mediastreamtrack::MediaStreamTrack; +use crate::dom::window::Window; use dom_struct::dom_struct; -use servo_media::streams::registry::MediaStreamId; +use servo_media::streams::MediaStreamType; +use std::cell::Ref; #[dom_struct] pub struct MediaStream { eventtarget: EventTarget, - #[ignore_malloc_size_of = "defined in servo-media"] - tracks: DomRefCell<Vec<MediaStreamId>>, + tracks: DomRefCell<Vec<Dom<MediaStreamTrack>>>, } impl MediaStream { - pub fn new_inherited(tracks: Vec<MediaStreamId>) -> MediaStream { + pub fn new_inherited() -> MediaStream { MediaStream { eventtarget: EventTarget::new_inherited(), - tracks: DomRefCell::new(tracks), + tracks: DomRefCell::new(vec![]), } } - pub fn new(global: &GlobalScope, tracks: Vec<MediaStreamId>) -> DomRoot<MediaStream> { + pub fn new(global: &GlobalScope) -> DomRoot<MediaStream> { reflect_dom_object( - Box::new(MediaStream::new_inherited(tracks)), + Box::new(MediaStream::new_inherited()), global, MediaStreamBinding::Wrap, ) } - pub fn get_tracks(&self) -> Vec<MediaStreamId> { - self.tracks.borrow_mut().clone() + pub fn Constructor(global: &Window) -> Fallible<DomRoot<MediaStream>> { + Ok(MediaStream::new(&global.global())) + } + + pub fn Constructor_(_: &Window, stream: &MediaStream) -> Fallible<DomRoot<MediaStream>> { + Ok(stream.Clone()) + } + + pub fn Constructor__( + global: &Window, + tracks: Vec<DomRoot<MediaStreamTrack>>, + ) -> Fallible<DomRoot<MediaStream>> { + let new = MediaStream::new(&global.global()); + for track in tracks { + // this is quadratic, but shouldn't matter much + // if this becomes a problem we can use a hash map + new.AddTrack(&track) + } + Ok(new) + } + + pub fn get_tracks(&self) -> Ref<[Dom<MediaStreamTrack>]> { + Ref::map(self.tracks.borrow(), |tracks| &**tracks) + } + + pub fn add_track(&self, track: &MediaStreamTrack) { + self.tracks.borrow_mut().push(Dom::from_ref(track)) + } +} + +impl MediaStreamMethods for MediaStream { + /// https://w3c.github.io/mediacapture-main/#dom-mediastream-gettracks + fn GetTracks(&self) -> Vec<DomRoot<MediaStreamTrack>> { + self.tracks + .borrow() + .iter() + .map(|x| DomRoot::from_ref(&**x)) + .collect() + } + + /// https://w3c.github.io/mediacapture-main/#dom-mediastream-getaudiotracks + fn GetAudioTracks(&self) -> Vec<DomRoot<MediaStreamTrack>> { + self.tracks + .borrow() + .iter() + .filter(|x| x.ty() == MediaStreamType::Audio) + .map(|x| DomRoot::from_ref(&**x)) + .collect() + } + + /// https://w3c.github.io/mediacapture-main/#dom-mediastream-getvideotracks + fn GetVideoTracks(&self) -> Vec<DomRoot<MediaStreamTrack>> { + self.tracks + .borrow() + .iter() + .filter(|x| x.ty() == MediaStreamType::Video) + .map(|x| DomRoot::from_ref(&**x)) + .collect() + } + + /// https://w3c.github.io/mediacapture-main/#dom-mediastream-gettrackbyid + fn GetTrackById(&self, id: DOMString) -> Option<DomRoot<MediaStreamTrack>> { + self.tracks + .borrow() + .iter() + .find(|x| x.id().id().to_string() == &*id) + .map(|x| DomRoot::from_ref(&**x)) + } + + /// https://w3c.github.io/mediacapture-main/#dom-mediastream-addtrack + fn AddTrack(&self, track: &MediaStreamTrack) { + let existing = self.tracks.borrow().iter().find(|x| *x == &track).is_some(); + + if existing { + return; + } + self.add_track(track) + } + + /// https://w3c.github.io/mediacapture-main/#dom-mediastream-removetrack + fn RemoveTrack(&self, track: &MediaStreamTrack) { + self.tracks.borrow_mut().retain(|x| *x != track); + } + + /// https://w3c.github.io/mediacapture-main/#dom-mediastream-clone + fn Clone(&self) -> DomRoot<MediaStream> { + let new = MediaStream::new(&self.global()); + for track in &*self.tracks.borrow() { + new.add_track(&track) + } + new } } diff --git a/components/script/dom/mediastreamtrack.rs b/components/script/dom/mediastreamtrack.rs new file mode 100644 index 00000000000..2cc0bde7442 --- /dev/null +++ b/components/script/dom/mediastreamtrack.rs @@ -0,0 +1,74 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::MediaStreamTrackBinding::{ + self, MediaStreamTrackMethods, +}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; +use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::str::DOMString; +use crate::dom::eventtarget::EventTarget; +use crate::dom::globalscope::GlobalScope; +use dom_struct::dom_struct; +use servo_media::streams::registry::MediaStreamId; +use servo_media::streams::MediaStreamType; + +#[dom_struct] +pub struct MediaStreamTrack { + eventtarget: EventTarget, + #[ignore_malloc_size_of = "defined in servo-media"] + id: MediaStreamId, + #[ignore_malloc_size_of = "defined in servo-media"] + ty: MediaStreamType, +} + +impl MediaStreamTrack { + pub fn new_inherited(id: MediaStreamId, ty: MediaStreamType) -> MediaStreamTrack { + MediaStreamTrack { + eventtarget: EventTarget::new_inherited(), + id, + ty, + } + } + + pub fn new( + global: &GlobalScope, + id: MediaStreamId, + ty: MediaStreamType, + ) -> DomRoot<MediaStreamTrack> { + reflect_dom_object( + Box::new(MediaStreamTrack::new_inherited(id, ty)), + global, + MediaStreamTrackBinding::Wrap, + ) + } + + pub fn id(&self) -> MediaStreamId { + self.id + } + + pub fn ty(&self) -> MediaStreamType { + self.ty + } +} + +impl MediaStreamTrackMethods for MediaStreamTrack { + /// https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack-kind + fn Kind(&self) -> DOMString { + match self.ty { + MediaStreamType::Video => "video".into(), + MediaStreamType::Audio => "audio".into(), + } + } + + /// https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack-id + fn Id(&self) -> DOMString { + self.id.id().to_string().into() + } + + /// https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack-clone + fn Clone(&self) -> DomRoot<MediaStreamTrack> { + MediaStreamTrack::new(&self.global(), self.id, self.ty) + } +} diff --git a/components/script/dom/messageevent.rs b/components/script/dom/messageevent.rs index edde48f95e6..c02df1e8e61 100644 --- a/components/script/dom/messageevent.rs +++ b/components/script/dom/messageevent.rs @@ -25,6 +25,7 @@ use std::ptr::NonNull; #[dom_struct] pub struct MessageEvent { event: Event, + #[ignore_malloc_size_of = "mozjs"] data: Heap<JSVal>, origin: DOMString, source: Option<Dom<WindowProxy>>, diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index ff1688fb6c3..1dbc1383101 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -399,6 +399,7 @@ pub mod medialist; pub mod mediaquerylist; pub mod mediaquerylistevent; pub mod mediastream; +pub mod mediastreamtrack; pub mod messageevent; pub mod mimetype; pub mod mimetypearray; @@ -450,6 +451,7 @@ pub mod rtcicecandidate; pub mod rtcpeerconnection; pub mod rtcpeerconnectioniceevent; pub mod rtcsessiondescription; +pub mod rtctrackevent; pub mod screen; pub mod serviceworker; pub mod serviceworkercontainer; @@ -540,6 +542,7 @@ pub mod xmlhttprequestupload; pub mod xmlserializer; pub mod xr; pub mod xrframe; +pub mod xrinputsource; pub mod xrlayer; pub mod xrpose; pub mod xrreferencespace; diff --git a/components/script/dom/paintworkletglobalscope.rs b/components/script/dom/paintworkletglobalscope.rs index fe119eefbf3..89b9907c95c 100644 --- a/components/script/dom/paintworkletglobalscope.rs +++ b/components/script/dom/paintworkletglobalscope.rs @@ -76,6 +76,7 @@ pub struct PaintWorkletGlobalScope { /// <https://drafts.css-houdini.org/css-paint-api/#paint-definitions> paint_definitions: DomRefCell<HashMap<Atom, Box<PaintDefinition>>>, /// <https://drafts.css-houdini.org/css-paint-api/#paint-class-instances> + #[ignore_malloc_size_of = "mozjs"] paint_class_instances: DomRefCell<HashMap<Atom, Box<Heap<JSVal>>>>, /// The most recent name the worklet was called with cached_name: DomRefCell<Atom>, @@ -473,7 +474,9 @@ pub enum PaintWorkletTask { #[derive(JSTraceable, MallocSizeOf)] #[must_root] struct PaintDefinition { + #[ignore_malloc_size_of = "mozjs"] class_constructor: Heap<JSVal>, + #[ignore_malloc_size_of = "mozjs"] paint_function: Heap<JSVal>, constructor_valid_flag: Cell<bool>, context_alpha_flag: bool, diff --git a/components/script/dom/rtcpeerconnection.rs b/components/script/dom/rtcpeerconnection.rs index 962eb0fb02c..9ec1940bbb3 100644 --- a/components/script/dom/rtcpeerconnection.rs +++ b/components/script/dom/rtcpeerconnection.rs @@ -26,10 +26,12 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable}; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::mediastream::MediaStream; +use crate::dom::mediastreamtrack::MediaStreamTrack; use crate::dom::promise::Promise; use crate::dom::rtcicecandidate::RTCIceCandidate; use crate::dom::rtcpeerconnectioniceevent::RTCPeerConnectionIceEvent; use crate::dom::rtcsessiondescription::RTCSessionDescription; +use crate::dom::rtctrackevent::RTCTrackEvent; use crate::dom::window::Window; use crate::task::TaskCanceller; use crate::task_source::networking::NetworkingTaskSource; @@ -37,6 +39,7 @@ use crate::task_source::TaskSource; use dom_struct::dom_struct; use servo_media::streams::registry::MediaStreamId; +use servo_media::streams::MediaStreamType; use servo_media::webrtc::{ BundlePolicy, GatheringState, IceCandidate, IceConnectionState, SdpType, SessionDescription, SignalingState, WebRtcController, WebRtcSignaller, @@ -128,7 +131,17 @@ impl WebRtcSignaller for RTCSignaller { ); } - fn on_add_stream(&self, _: &MediaStreamId) {} + fn on_add_stream(&self, id: &MediaStreamId, ty: MediaStreamType) { + let this = self.trusted.clone(); + let id = *id; + let _ = self.task_source.queue_with_canceller( + task!(on_add_stream: move || { + let this = this.root(); + this.on_add_stream(id, ty); + }), + &self.canceller, + ); + } fn close(&self) { // do nothing @@ -238,6 +251,15 @@ impl RTCPeerConnection { event.upcast::<Event>().fire(self.upcast()); } + fn on_add_stream(&self, id: MediaStreamId, ty: MediaStreamType) { + if self.closed.get() { + return; + } + let track = MediaStreamTrack::new(&self.global(), id, ty); + let event = RTCTrackEvent::new(&self.global(), atom!("track"), false, false, &track); + event.upcast::<Event>().fire(self.upcast()); + } + /// https://www.w3.org/TR/webrtc/#update-ice-gathering-state fn update_gathering_state(&self, state: GatheringState) { // step 1 @@ -399,6 +421,9 @@ impl RTCPeerConnectionMethods for RTCPeerConnection { /// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-icecandidate event_handler!(icecandidate, GetOnicecandidate, SetOnicecandidate); + /// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-ontrack + event_handler!(track, GetOntrack, SetOntrack); + /// https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-iceconnectionstatechange event_handler!( iceconnectionstatechange, @@ -584,10 +609,12 @@ impl RTCPeerConnectionMethods for RTCPeerConnection { // https://w3c.github.io/webrtc-pc/#legacy-interface-extensions fn AddStream(&self, stream: &MediaStream) { - let mut tracks = stream.get_tracks(); - - for ref track in tracks.drain(..) { - self.controller.borrow().as_ref().unwrap().add_stream(track); + for track in &*stream.get_tracks() { + self.controller + .borrow() + .as_ref() + .unwrap() + .add_stream(&track.id()); } } diff --git a/components/script/dom/rtctrackevent.rs b/components/script/dom/rtctrackevent.rs new file mode 100644 index 00000000000..9c5d7bec362 --- /dev/null +++ b/components/script/dom/rtctrackevent.rs @@ -0,0 +1,78 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::EventBinding::EventBinding::EventMethods; +use crate::dom::bindings::codegen::Bindings::RTCTrackEventBinding::{self, RTCTrackEventMethods}; +use crate::dom::bindings::error::Fallible; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::str::DOMString; +use crate::dom::event::Event; +use crate::dom::globalscope::GlobalScope; +use crate::dom::mediastreamtrack::MediaStreamTrack; +use crate::dom::window::Window; +use dom_struct::dom_struct; +use servo_atoms::Atom; + +#[dom_struct] +pub struct RTCTrackEvent { + event: Event, + track: Dom<MediaStreamTrack>, +} + +impl RTCTrackEvent { + #[allow(unrooted_must_root)] + fn new_inherited(track: &MediaStreamTrack) -> RTCTrackEvent { + RTCTrackEvent { + event: Event::new_inherited(), + track: Dom::from_ref(track), + } + } + + pub fn new( + global: &GlobalScope, + type_: Atom, + bubbles: bool, + cancelable: bool, + track: &MediaStreamTrack, + ) -> DomRoot<RTCTrackEvent> { + let trackevent = reflect_dom_object( + Box::new(RTCTrackEvent::new_inherited(&track)), + global, + RTCTrackEventBinding::Wrap, + ); + { + let event = trackevent.upcast::<Event>(); + event.init_event(type_, bubbles, cancelable); + } + trackevent + } + + pub fn Constructor( + window: &Window, + type_: DOMString, + init: &RTCTrackEventBinding::RTCTrackEventInit, + ) -> Fallible<DomRoot<RTCTrackEvent>> { + Ok(RTCTrackEvent::new( + &window.global(), + Atom::from(type_), + init.parent.bubbles, + init.parent.cancelable, + &init.track, + )) + } +} + +impl RTCTrackEventMethods for RTCTrackEvent { + // https://w3c.github.io/webrtc-pc/#dom-rtctrackevent-track + fn Track(&self) -> DomRoot<MediaStreamTrack> { + DomRoot::from_ref(&*self.track) + } + + // https://dom.spec.whatwg.org/#dom-event-istrusted + fn IsTrusted(&self) -> bool { + self.event.IsTrusted() + } +} diff --git a/components/script/dom/vrdisplay.rs b/components/script/dom/vrdisplay.rs index a8cb594a2b1..77817bae2fc 100644 --- a/components/script/dom/vrdisplay.rs +++ b/components/script/dom/vrdisplay.rs @@ -22,7 +22,7 @@ use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::num::Finite; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; -use crate::dom::bindings::root::{DomRoot, MutDom, MutNullableDom}; +use crate::dom::bindings::root::{Dom, DomRoot, MutDom, MutNullableDom}; use crate::dom::bindings::str::DOMString; use crate::dom::event::Event; use crate::dom::eventtarget::EventTarget; @@ -36,6 +36,7 @@ use crate::dom::vrpose::VRPose; use crate::dom::vrstageparameters::VRStageParameters; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::xrframe::XRFrame; +use crate::dom::xrinputsource::XRInputSource; use crate::dom::xrsession::XRSession; use crate::dom::xrwebgllayer::XRWebGLLayer; use crate::script_runtime::CommonScriptMsg; @@ -47,11 +48,12 @@ use dom_struct::dom_struct; use ipc_channel::ipc::IpcSender; use profile_traits::ipc; use std::cell::Cell; +use std::collections::HashMap; use std::mem; use std::ops::Deref; use std::rc::Rc; use std::thread; -use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVRFrameData, WebVRFutureFrameData}; +use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVRFrameData, WebVRPoseInformation}; use webvr_traits::{WebVRLayer, WebVRMsg}; #[dom_struct] @@ -86,12 +88,16 @@ pub struct VRDisplay { // Compositor VRFrameData synchonization frame_data_status: Cell<VRFrameDataStatus>, #[ignore_malloc_size_of = "closures are hard"] - frame_data_receiver: DomRefCell<Option<WebGLReceiver<Result<WebVRFutureFrameData, ()>>>>, + frame_data_receiver: DomRefCell<Option<WebGLReceiver<Result<WebVRPoseInformation, ()>>>>, running_display_raf: Cell<bool>, paused: Cell<bool>, stopped_on_pause: Cell<bool>, /// Whether or not this is XR mode, and the session xr_session: MutNullableDom<XRSession>, + /// Have inputs been initialized? (i.e, has getInputSources() been called?) + /// XR only + initialized_inputs: Cell<bool>, + input_sources: DomRefCell<HashMap<u32, Dom<XRInputSource>>>, } unsafe_no_jsmanaged_fields!(WebVRDisplayData); @@ -115,6 +121,8 @@ struct VRRAFUpdate { /// Number uniquely identifying the WebGL context /// so that we may setup/tear down VR compositors as things change context_id: usize, + /// Do we need input data? + needs_inputs: bool, } type VRRAFUpdateSender = Sender<Result<VRRAFUpdate, ()>>; @@ -164,6 +172,8 @@ impl VRDisplay { // When the VR Resume event is received and the flag is set, VR presentation automatically restarts. stopped_on_pause: Cell::new(false), xr_session: MutNullableDom::default(), + initialized_inputs: Cell::new(false), + input_sources: DomRefCell::new(HashMap::new()), } } @@ -627,6 +637,7 @@ impl VRDisplay { depth_far: self.depth_far.get(), api_sender: self.api_sender(), context_id: self.context_id(), + needs_inputs: self.initialized_inputs.get(), } } @@ -690,6 +701,7 @@ impl VRDisplay { let (raf_sender, raf_receiver) = unbounded(); let (wakeup_sender, wakeup_receiver) = unbounded(); *self.raf_wakeup_sender.borrow_mut() = Some(wakeup_sender); + let mut needs_inputs = false; // The render loop at native headset frame rate is implemented using a dedicated thread. // Every loop iteration syncs pose data with the HMD, submits the pixels to the display and waits for Vsync. @@ -726,8 +738,13 @@ impl VRDisplay { .unwrap(); // Run Sync Poses in parallell on Render thread - let msg = - WebVRCommand::SyncPoses(display_id, near, far, sync_sender.clone()); + let msg = WebVRCommand::SyncPoses( + display_id, + near, + far, + needs_inputs, + sync_sender.clone(), + ); api_sender.send_vr(msg).unwrap(); } else { let _ = wakeup_receiver.recv(); @@ -752,6 +769,7 @@ impl VRDisplay { if let Ok(update) = raf_receiver.recv().unwrap() { near = update.depth_near; far = update.depth_far; + needs_inputs = update.needs_inputs; if update.context_id != context_id { if let Some(ref api_sender) = update.api_sender { api_sender @@ -808,8 +826,16 @@ impl VRDisplay { fn sync_frame_data(&self) { let status = if let Some(receiver) = self.frame_data_receiver.borrow().as_ref() { match receiver.recv().unwrap() { - Ok(future_data) => { - *self.frame_data.borrow_mut() = future_data.block(); + Ok(pose) => { + *self.frame_data.borrow_mut() = pose.frame.block(); + if self.initialized_inputs.get() { + let inputs = self.input_sources.borrow(); + for (id, state) in pose.gamepads { + if let Some(input) = inputs.get(&id) { + input.update_state(state); + } + } + } VRFrameDataStatus::Synced }, Err(()) => VRFrameDataStatus::Exit, @@ -909,6 +935,53 @@ impl VRDisplay { pair.1 = None; } } + + /// Initialize XRInputSources + fn initialize_inputs(&self) { + if self.initialized_inputs.get() { + return; + } + self.initialized_inputs.set(true); + + let (sender, receiver) = ipc::channel(self.global().time_profiler_chan().clone()).unwrap(); + let display = self.display.borrow().display_id; + self.webvr_thread() + .send(WebVRMsg::GetGamepadsForDisplay(display, sender)) + .unwrap(); + match receiver.recv().unwrap() { + Ok(gamepads) => { + let global = self.global(); + let session = self + .xr_session + .get() + .expect("initialize_inputs called on a VR session"); + let roots: Vec<_> = gamepads + .into_iter() + .map(|g| { + ( + g.1.gamepad_id, + XRInputSource::new(&global, &session, g.0, g.1), + ) + }) + .collect(); + + let mut inputs = self.input_sources.borrow_mut(); + for (id, root) in &roots { + inputs.insert(*id, Dom::from_ref(&root)); + } + }, + Err(_) => {}, + } + } + + pub fn get_input_sources(&self) -> Vec<DomRoot<XRInputSource>> { + self.initialize_inputs(); + self.input_sources + .borrow() + .iter() + .map(|(_, x)| DomRoot::from_ref(&**x)) + .collect() + } } // WebVR Spec: If the number of values in the leftBounds/rightBounds arrays diff --git a/components/script/dom/vreyeparameters.rs b/components/script/dom/vreyeparameters.rs index 2a212ab48bc..b7ea63bbd3e 100644 --- a/components/script/dom/vreyeparameters.rs +++ b/components/script/dom/vreyeparameters.rs @@ -22,6 +22,7 @@ pub struct VREyeParameters { reflector_: Reflector, #[ignore_malloc_size_of = "Defined in rust-webvr"] parameters: DomRefCell<WebVREyeParameters>, + #[ignore_malloc_size_of = "mozjs"] offset: Heap<*mut JSObject>, fov: Dom<VRFieldOfView>, } diff --git a/components/script/dom/vrframedata.rs b/components/script/dom/vrframedata.rs index 08acd74bb42..25f6af821a7 100644 --- a/components/script/dom/vrframedata.rs +++ b/components/script/dom/vrframedata.rs @@ -22,9 +22,13 @@ use webvr_traits::WebVRFrameData; #[dom_struct] pub struct VRFrameData { reflector_: Reflector, + #[ignore_malloc_size_of = "mozjs"] left_proj: Heap<*mut JSObject>, + #[ignore_malloc_size_of = "mozjs"] left_view: Heap<*mut JSObject>, + #[ignore_malloc_size_of = "mozjs"] right_proj: Heap<*mut JSObject>, + #[ignore_malloc_size_of = "mozjs"] right_view: Heap<*mut JSObject>, pose: Dom<VRPose>, timestamp: Cell<f64>, diff --git a/components/script/dom/vrpose.rs b/components/script/dom/vrpose.rs index c807ab72c91..90bca0956ee 100644 --- a/components/script/dom/vrpose.rs +++ b/components/script/dom/vrpose.rs @@ -17,11 +17,17 @@ use webvr_traits::webvr; #[dom_struct] pub struct VRPose { reflector_: Reflector, + #[ignore_malloc_size_of = "mozjs"] position: Heap<*mut JSObject>, + #[ignore_malloc_size_of = "mozjs"] orientation: Heap<*mut JSObject>, + #[ignore_malloc_size_of = "mozjs"] linear_vel: Heap<*mut JSObject>, + #[ignore_malloc_size_of = "mozjs"] angular_vel: Heap<*mut JSObject>, + #[ignore_malloc_size_of = "mozjs"] linear_acc: Heap<*mut JSObject>, + #[ignore_malloc_size_of = "mozjs"] angular_acc: Heap<*mut JSObject>, } diff --git a/components/script/dom/vrstageparameters.rs b/components/script/dom/vrstageparameters.rs index ffbe6ce0f3f..41184091232 100644 --- a/components/script/dom/vrstageparameters.rs +++ b/components/script/dom/vrstageparameters.rs @@ -21,6 +21,7 @@ pub struct VRStageParameters { reflector_: Reflector, #[ignore_malloc_size_of = "Defined in rust-webvr"] parameters: DomRefCell<WebVRStageParameters>, + #[ignore_malloc_size_of = "mozjs"] transform: Heap<*mut JSObject>, } diff --git a/components/script/dom/webidls/MediaStream.webidl b/components/script/dom/webidls/MediaStream.webidl index 0257e3c6061..b1d5664a7f7 100644 --- a/components/script/dom/webidls/MediaStream.webidl +++ b/components/script/dom/webidls/MediaStream.webidl @@ -4,20 +4,20 @@ // https://w3c.github.io/mediacapture-main/#dom-mediastream -// [Exposed=Window, -// Constructor, -// Constructor(MediaStream stream), -// Constructor(sequence<MediaStreamTrack> tracks)] -[Exposed=Window, Pref="dom.webrtc.enabled"] +[Exposed=Window, + Constructor, + Constructor(MediaStream stream), + Constructor(sequence<MediaStreamTrack> tracks), +Pref="dom.webrtc.enabled"] interface MediaStream : EventTarget { // readonly attribute DOMString id; - // sequence<MediaStreamTrack> getAudioTracks(); - // sequence<MediaStreamTrack> getVideoTracks(); - // sequence<MediaStreamTrack> getTracks(); - // MediaStreamTrack? getTrackById(DOMString trackId); - // void addTrack(MediaStreamTrack track); - // void removeTrack(MediaStreamTrack track); - // MediaStream clone(); + sequence<MediaStreamTrack> getAudioTracks(); + sequence<MediaStreamTrack> getVideoTracks(); + sequence<MediaStreamTrack> getTracks(); + MediaStreamTrack? getTrackById(DOMString trackId); + void addTrack(MediaStreamTrack track); + void removeTrack(MediaStreamTrack track); + MediaStream clone(); // readonly attribute boolean active; // attribute EventHandler onaddtrack; // attribute EventHandler onremovetrack; diff --git a/components/script/dom/webidls/MediaStreamTrack.webidl b/components/script/dom/webidls/MediaStreamTrack.webidl new file mode 100644 index 00000000000..2f8bfb0bbec --- /dev/null +++ b/components/script/dom/webidls/MediaStreamTrack.webidl @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack + +[Exposed=Window, Pref="dom.webrtc.enabled"] +interface MediaStreamTrack : EventTarget { + readonly attribute DOMString kind; + readonly attribute DOMString id; + // readonly attribute DOMString label; + // attribute boolean enabled; + // readonly attribute boolean muted; + // attribute EventHandler onmute; + // attribute EventHandler onunmute; + // readonly attribute MediaStreamTrackState readyState; + // attribute EventHandler onended; + MediaStreamTrack clone(); + // void stop(); + // MediaTrackCapabilities getCapabilities(); + // MediaTrackConstraints getConstraints(); + // MediaTrackSettings getSettings(); + // Promise<void> applyConstraints(optional MediaTrackConstraints constraints); +}; diff --git a/components/script/dom/webidls/RTCPeerConnection.webidl b/components/script/dom/webidls/RTCPeerConnection.webidl index 0f00f3b5b95..58cb7301ea3 100644 --- a/components/script/dom/webidls/RTCPeerConnection.webidl +++ b/components/script/dom/webidls/RTCPeerConnection.webidl @@ -114,3 +114,15 @@ enum RTCSignalingState { "have-remote-pranswer", "closed" }; + +partial interface RTCPeerConnection { + // sequence<RTCRtpSender> getSenders(); + // sequence<RTCRtpReceiver> getReceivers(); + // sequence<RTCRtpTransceiver> getTransceivers(); + // RTCRtpSender addTrack(MediaStreamTrack track, + // MediaStream... streams); + // void removeTrack(RTCRtpSender sender); + // RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind, + // optional RTCRtpTransceiverInit init); + attribute EventHandler ontrack; +}; diff --git a/components/script/dom/webidls/RTCTrackEvent.webidl b/components/script/dom/webidls/RTCTrackEvent.webidl new file mode 100644 index 00000000000..fa07f36b9f5 --- /dev/null +++ b/components/script/dom/webidls/RTCTrackEvent.webidl @@ -0,0 +1,23 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://w3c.github.io/webrtc-pc/#dom-rtctrackevent + +[Constructor(DOMString type, RTCTrackEventInit eventInitDict), + Exposed=Window, Pref="dom.webrtc.enabled"] +interface RTCTrackEvent : Event { + // readonly attribute RTCRtpReceiver receiver; + readonly attribute MediaStreamTrack track; + // [SameObject] + // readonly attribute FrozenArray<MediaStream> streams; + // readonly attribute RTCRtpTransceiver transceiver; +}; + +// https://www.w3.org/TR/webrtc/#dom-rtctrackeventinit +dictionary RTCTrackEventInit : EventInit { + // required RTCRtpReceiver receiver; + required MediaStreamTrack track; + // sequence<MediaStream> streams = []; + // required RTCRtpTransceiver transceiver; +}; diff --git a/components/script/dom/webidls/XRInputSource.webidl b/components/script/dom/webidls/XRInputSource.webidl new file mode 100644 index 00000000000..5ad1e48628f --- /dev/null +++ b/components/script/dom/webidls/XRInputSource.webidl @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +// https://immersive-web.github.io/webxr/#xrinputsource-interface + +enum XRHandedness { + "none", + "left", + "right" +}; + +enum XRTargetRayMode { + "gaze", + "tracked-pointer", + "screen" +}; + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRInputSource { + readonly attribute XRHandedness handedness; + // [SameObject] readonly attribute XRTargetRayMode targetRayMode; + [SameObject] readonly attribute XRSpace targetRaySpace; + // [SameObject] readonly attribute XRSpace? gripSpace; + // [SameObject] readonly attribute Gamepad? gamepad; +}; diff --git a/components/script/dom/webidls/XRSession.webidl b/components/script/dom/webidls/XRSession.webidl index f22918d469d..0399f2d0bc1 100644 --- a/components/script/dom/webidls/XRSession.webidl +++ b/components/script/dom/webidls/XRSession.webidl @@ -20,12 +20,15 @@ interface XRSession : EventTarget { readonly attribute XREnvironmentBlendMode environmentBlendMode; readonly attribute XRRenderState renderState; - readonly attribute XRSpace viewerSpace; + [SameObject] readonly attribute XRSpace viewerSpace; // // Methods Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceOptions options); + // workaround until we have FrozenArray + // see https://github.com/servo/servo/issues/10427#issuecomment-449593626 // FrozenArray<XRInputSource> getInputSources(); + sequence<XRInputSource> getInputSources(); Promise<void> updateRenderState(optional XRRenderStateInit state); long requestAnimationFrame(XRFrameRequestCallback callback); diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 0b86f0eeb1c..3b9622b3cfb 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -137,6 +137,7 @@ pub struct XMLHttpRequest { response_type: Cell<XMLHttpRequestResponseType>, response_xml: MutNullableDom<Document>, response_blob: MutNullableDom<Blob>, + #[ignore_malloc_size_of = "mozjs"] response_arraybuffer: Heap<*mut JSObject>, #[ignore_malloc_size_of = "Defined in rust-mozjs"] response_json: Heap<JSVal>, diff --git a/components/script/dom/xrinputsource.rs b/components/script/dom/xrinputsource.rs new file mode 100644 index 00000000000..2b623864d56 --- /dev/null +++ b/components/script/dom/xrinputsource.rs @@ -0,0 +1,83 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::cell::DomRefCell; +use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding; +use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{ + XRHandedness, XRInputSourceMethods, +}; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; +use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; +use crate::dom::globalscope::GlobalScope; +use crate::dom::xrsession::XRSession; +use crate::dom::xrspace::XRSpace; +use dom_struct::dom_struct; +use webvr_traits::{WebVRGamepadData, WebVRGamepadHand, WebVRGamepadState, WebVRPose}; + +#[dom_struct] +pub struct XRInputSource { + reflector: Reflector, + session: Dom<XRSession>, + #[ignore_malloc_size_of = "Defined in rust-webvr"] + data: WebVRGamepadData, + #[ignore_malloc_size_of = "Defined in rust-webvr"] + state: DomRefCell<WebVRGamepadState>, + target_ray_space: MutNullableDom<XRSpace>, +} + +impl XRInputSource { + pub fn new_inherited( + session: &XRSession, + data: WebVRGamepadData, + state: WebVRGamepadState, + ) -> XRInputSource { + XRInputSource { + reflector: Reflector::new(), + session: Dom::from_ref(session), + data, + state: DomRefCell::new(state), + target_ray_space: Default::default(), + } + } + + pub fn new( + global: &GlobalScope, + session: &XRSession, + data: WebVRGamepadData, + state: WebVRGamepadState, + ) -> DomRoot<XRInputSource> { + reflect_dom_object( + Box::new(XRInputSource::new_inherited(session, data, state)), + global, + XRInputSourceBinding::Wrap, + ) + } + + pub fn update_state(&self, state: WebVRGamepadState) { + *self.state.borrow_mut() = state; + } + + pub fn pose(&self) -> WebVRPose { + self.state.borrow().pose + } +} + +impl XRInputSourceMethods for XRInputSource { + /// https://immersive-web.github.io/webxr/#dom-xrinputsource-handedness + fn Handedness(&self) -> XRHandedness { + match self.data.hand { + WebVRGamepadHand::Unknown => XRHandedness::None, + WebVRGamepadHand::Left => XRHandedness::Left, + WebVRGamepadHand::Right => XRHandedness::Right, + } + } + + /// https://immersive-web.github.io/webxr/#dom-xrinputsource-targetrayspace + fn TargetRaySpace(&self) -> DomRoot<XRSpace> { + self.target_ray_space.or_init(|| { + let global = self.global(); + XRSpace::new_inputspace(&global, &self.session, &self) + }) + } +} diff --git a/components/script/dom/xrreferencespace.rs b/components/script/dom/xrreferencespace.rs index 664dc4f0e23..932f917b5a5 100644 --- a/components/script/dom/xrreferencespace.rs +++ b/components/script/dom/xrreferencespace.rs @@ -110,7 +110,7 @@ impl XRReferenceSpace { // non-subclassed XRReferenceSpaces exist, obtained via the "identity" // type. These are equivalent to the viewer pose and follow the headset // around - XRSpace::viewer_pose_from_frame_data(base_pose) + XRSpace::pose_to_transform(&base_pose.pose) } } } diff --git a/components/script/dom/xrrigidtransform.rs b/components/script/dom/xrrigidtransform.rs index 969ec839292..f75d3f085fb 100644 --- a/components/script/dom/xrrigidtransform.rs +++ b/components/script/dom/xrrigidtransform.rs @@ -27,6 +27,7 @@ pub struct XRRigidTransform { #[ignore_malloc_size_of = "defined in euclid"] transform: RigidTransform3D<f64>, inverse: MutNullableDom<XRRigidTransform>, + #[ignore_malloc_size_of = "defined in mozjs"] matrix: Heap<*mut JSObject>, } @@ -93,7 +94,7 @@ impl XRRigidTransformMethods for XRRigidTransform { } // https://immersive-web.github.io/webxr/#dom-xrrigidtransform-orientation fn Orientation(&self) -> DomRoot<DOMPointReadOnly> { - self.position.or_init(|| { + self.orientation.or_init(|| { let r = &self.transform.rotation; DOMPointReadOnly::new(&self.global(), r.i, r.j, r.k, r.r) }) diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 4b855cba4c8..5aab6341ca4 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -19,6 +19,7 @@ use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; use crate::dom::vrdisplay::VRDisplay; +use crate::dom::xrinputsource::XRInputSource; use crate::dom::xrlayer::XRLayer; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrrenderstate::XRRenderState; @@ -33,6 +34,7 @@ pub struct XRSession { display: Dom<VRDisplay>, base_layer: MutNullableDom<XRLayer>, blend_mode: XREnvironmentBlendMode, + viewer_space: MutNullableDom<XRSpace>, } impl XRSession { @@ -43,6 +45,7 @@ impl XRSession { base_layer: Default::default(), // we don't yet support any AR devices blend_mode: XREnvironmentBlendMode::Opaque, + viewer_space: Default::default(), } } @@ -86,7 +89,8 @@ impl XRSessionMethods for XRSession { // https://immersive-web.github.io/webxr/#dom-xrsession-viewerspace fn ViewerSpace(&self) -> DomRoot<XRSpace> { - XRSpace::new_viewerspace(&self.global(), &self) + self.viewer_space + .or_init(|| XRSpace::new_viewerspace(&self.global(), &self)) } /// https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe @@ -153,4 +157,9 @@ impl XRSessionMethods for XRSession { p } + + /// https://immersive-web.github.io/webxr/#dom-xrsession-getinputsources + fn GetInputSources(&self) -> Vec<DomRoot<XRInputSource>> { + self.display.get_input_sources() + } } diff --git a/components/script/dom/xrspace.rs b/components/script/dom/xrspace.rs index 8948ac03c8e..30f9246c354 100644 --- a/components/script/dom/xrspace.rs +++ b/components/script/dom/xrspace.rs @@ -5,20 +5,22 @@ use crate::dom::bindings::codegen::Bindings::XRSpaceBinding; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::reflect_dom_object; -use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom}; use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; +use crate::dom::xrinputsource::XRInputSource; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrsession::XRSession; use dom_struct::dom_struct; use euclid::{RigidTransform3D, Rotation3D, Vector3D}; -use webvr_traits::WebVRFrameData; +use webvr_traits::{WebVRFrameData, WebVRPose}; #[dom_struct] pub struct XRSpace { eventtarget: EventTarget, session: Dom<XRSession>, is_viewerspace: bool, + input_source: MutNullableDom<XRInputSource>, } impl XRSpace { @@ -27,6 +29,7 @@ impl XRSpace { eventtarget: EventTarget::new_inherited(), session: Dom::from_ref(session), is_viewerspace: false, + input_source: Default::default(), } } @@ -35,6 +38,7 @@ impl XRSpace { eventtarget: EventTarget::new_inherited(), session: Dom::from_ref(session), is_viewerspace: true, + input_source: Default::default(), } } @@ -45,6 +49,27 @@ impl XRSpace { XRSpaceBinding::Wrap, ) } + + fn new_inputspace_inner(session: &XRSession, input: &XRInputSource) -> XRSpace { + XRSpace { + eventtarget: EventTarget::new_inherited(), + session: Dom::from_ref(session), + is_viewerspace: false, + input_source: MutNullableDom::new(Some(input)), + } + } + + pub fn new_inputspace( + global: &GlobalScope, + session: &XRSession, + input: &XRInputSource, + ) -> DomRoot<XRSpace> { + reflect_dom_object( + Box::new(XRSpace::new_inputspace_inner(session, input)), + global, + XRSpaceBinding::Wrap, + ) + } } impl XRSpace { @@ -57,16 +82,18 @@ impl XRSpace { if let Some(reference) = self.downcast::<XRReferenceSpace>() { reference.get_pose(base_pose) } else if self.is_viewerspace { - XRSpace::viewer_pose_from_frame_data(base_pose) + XRSpace::pose_to_transform(&base_pose.pose) + } else if let Some(source) = self.input_source.get() { + XRSpace::pose_to_transform(&source.pose()) } else { unreachable!() } } - pub fn viewer_pose_from_frame_data(data: &WebVRFrameData) -> RigidTransform3D<f64> { - let pos = data.pose.position.unwrap_or([0., 0., 0.]); + pub fn pose_to_transform(pose: &WebVRPose) -> RigidTransform3D<f64> { + let pos = pose.position.unwrap_or([0., 0., 0.]); let translation = Vector3D::new(pos[0] as f64, pos[1] as f64, pos[2] as f64); - let orient = data.pose.orientation.unwrap_or([0., 0., 0., 0.]); + let orient = pose.orientation.unwrap_or([0., 0., 0., 0.]); let rotation = Rotation3D::quaternion( orient[0] as f64, orient[1] as f64, diff --git a/components/script/dom/xrstationaryreferencespace.rs b/components/script/dom/xrstationaryreferencespace.rs index a867aa0d976..65a0aebb790 100644 --- a/components/script/dom/xrstationaryreferencespace.rs +++ b/components/script/dom/xrstationaryreferencespace.rs @@ -55,7 +55,7 @@ impl XRStationaryReferenceSpace { /// /// Does not apply originOffset, use get_viewer_pose on XRReferenceSpace instead pub fn get_unoffset_viewer_pose(&self, viewer_pose: &WebVRFrameData) -> RigidTransform3D<f64> { - let viewer_pose = XRSpace::viewer_pose_from_frame_data(viewer_pose); + let viewer_pose = XRSpace::pose_to_transform(&viewer_pose.pose); // all math is in column-vector notation // we use the following equation to verify correctness here: // get_viewer_pose(space) = get_pose(space).inverse() * get_pose(viewer_space) @@ -113,7 +113,7 @@ impl XRStationaryReferenceSpace { }, XRStationaryReferenceSpaceSubtype::Position_disabled => { // This space follows the user around, but does not mirror the user's orientation - let viewer_pose = XRSpace::viewer_pose_from_frame_data(viewer_pose); + let viewer_pose = XRSpace::pose_to_transform(&viewer_pose.pose); viewer_pose.translation.into() }, } diff --git a/components/script/dom/xrview.rs b/components/script/dom/xrview.rs index a2eee03581d..c53eb8cb947 100644 --- a/components/script/dom/xrview.rs +++ b/components/script/dom/xrview.rs @@ -21,7 +21,9 @@ pub struct XRView { reflector_: Reflector, session: Dom<XRSession>, eye: XREye, + #[ignore_malloc_size_of = "mozjs"] proj: Heap<*mut JSObject>, + #[ignore_malloc_size_of = "mozjs"] view: Heap<*mut JSObject>, transform: Dom<XRRigidTransform>, } diff --git a/components/script/dom/xrviewerpose.rs b/components/script/dom/xrviewerpose.rs index 717fdcea16e..92caa7f037b 100644 --- a/components/script/dom/xrviewerpose.rs +++ b/components/script/dom/xrviewerpose.rs @@ -22,6 +22,7 @@ use webvr_traits::WebVRFrameData; #[dom_struct] pub struct XRViewerPose { pose: XRPose, + #[ignore_malloc_size_of = "mozjs"] views: Heap<JSVal>, } |