diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/bindings/trace.rs | 2 | ||||
-rw-r--r-- | components/script/dom/htmlmediaelement.rs | 31 | ||||
-rw-r--r-- | components/script/dom/htmlvideoelement.rs | 27 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 1 | ||||
-rw-r--r-- | components/script/dom/webglrenderingcontext.rs | 11 | ||||
-rw-r--r-- | components/script/dom/webidls/XRInputSourceEvent.webidl | 17 | ||||
-rw-r--r-- | components/script/dom/webidls/XRSession.webidl | 6 | ||||
-rw-r--r-- | components/script/dom/xrframe.rs | 12 | ||||
-rw-r--r-- | components/script/dom/xrinputsourceevent.rs | 90 | ||||
-rw-r--r-- | components/script/dom/xrsession.rs | 58 | ||||
-rw-r--r-- | components/script/dom/xrspace.rs | 6 |
11 files changed, 241 insertions, 20 deletions
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 95bad8b4c4e..bf65eb1e87d 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -103,6 +103,7 @@ use servo_media::audio::context::AudioContext; use servo_media::audio::graph::NodeId; use servo_media::audio::panner_node::{DistanceModel, PanningModel}; use servo_media::audio::param::ParamType; +use servo_media::player::frame::Frame; use servo_media::player::Player; use servo_media::streams::registry::MediaStreamId; use servo_media::streams::MediaStreamType; @@ -516,6 +517,7 @@ unsafe_no_jsmanaged_fields!(Point2D<f32>, Rect<Au>); unsafe_no_jsmanaged_fields!(Rect<f32>); unsafe_no_jsmanaged_fields!(CascadeData); unsafe_no_jsmanaged_fields!(WindowGLContext); +unsafe_no_jsmanaged_fields!(Frame); unsafe impl<'a> JSTraceable for &'a str { #[inline] diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index e3cb0dfb5b2..398a3ad40f1 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -136,6 +136,10 @@ impl FrameHolder { unreachable!(); } } + + fn get_frame(&self) -> Frame { + self.1.clone() + } } pub struct MediaFrameRenderer { @@ -193,12 +197,12 @@ impl FrameRenderer for MediaFrameRenderer { ImageData::Raw(frame.get_data()), &webrender_api::DirtyRect::All, ); - } else if self.player_id.is_some() { - self.current_frame_holder - .get_or_insert_with(|| FrameHolder::new(frame.clone())) - .set(frame); } + self.current_frame_holder + .get_or_insert_with(|| FrameHolder::new(frame.clone())) + .set(frame); + if let Some(old_image_key) = self.old_frame.take() { txn.delete_image(old_image_key); } @@ -220,9 +224,6 @@ impl FrameRenderer for MediaFrameRenderer { TextureTarget::Default }; - self.current_frame_holder - .get_or_insert_with(|| FrameHolder::new(frame.clone())) - .set(frame); ImageData::External(ExternalImageData { id: ExternalImageId(self.player_id.unwrap()), channel_index: 0, @@ -231,6 +232,11 @@ impl FrameRenderer for MediaFrameRenderer { } else { ImageData::Raw(frame.get_data()) }; + + self.current_frame_holder + .get_or_insert_with(|| FrameHolder::new(frame.clone())) + .set(frame); + txn.add_image(new_image_key, descriptor, image_data, None); }, None => { @@ -244,7 +250,6 @@ impl FrameRenderer for MediaFrameRenderer { TextureTarget::Default }; - self.current_frame_holder = Some(FrameHolder::new(frame)); ImageData::External(ExternalImageData { id: ExternalImageId(self.player_id.unwrap()), channel_index: 0, @@ -253,6 +258,9 @@ impl FrameRenderer for MediaFrameRenderer { } else { ImageData::Raw(frame.get_data()) }; + + self.current_frame_holder = Some(FrameHolder::new(frame)); + txn.add_image(image_key, descriptor, image_data, None); }, } @@ -1853,6 +1861,13 @@ impl HTMLMediaElement { document_from_node(self).unregister_media_controls(&id); } } + + pub fn get_current_frame(&self) -> Option<Frame> { + match self.frame_renderer.lock().unwrap().current_frame_holder { + Some(ref holder) => Some(holder.get_frame()), + None => return None, + } + } } // XXX Placeholder for [https://github.com/servo/servo/issues/22293] diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs index e95a2ca8ccd..bca18c35a2b 100644 --- a/components/script/dom/htmlvideoelement.rs +++ b/components/script/dom/htmlvideoelement.rs @@ -23,6 +23,7 @@ use crate::fetch::FetchCanceller; use crate::image_listener::{add_cache_listener_for_element, ImageCacheListener}; use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener}; use dom_struct::dom_struct; +use euclid::default::Size2D; use html5ever::{LocalName, Prefix}; use ipc_channel::ipc; use ipc_channel::router::ROUTER; @@ -34,6 +35,7 @@ use net_traits::{ CoreResourceMsg, FetchChannels, FetchMetadata, FetchResponseListener, FetchResponseMsg, }; use net_traits::{NetworkError, ResourceFetchTiming, ResourceTimingType}; +use servo_media::player::frame::Frame; use servo_url::ServoUrl; use std::cell::Cell; use std::sync::{Arc, Mutex}; @@ -55,6 +57,9 @@ pub struct HTMLVideoElement { /// Load event blocker. Will block the load event while the poster frame /// is being fetched. load_blocker: DomRefCell<Option<LoadBlocker>>, + /// A copy of the last frame + #[ignore_malloc_size_of = "Frame"] + last_frame: DomRefCell<Option<Frame>>, } impl HTMLVideoElement { @@ -70,6 +75,7 @@ impl HTMLVideoElement { generation_id: Cell::new(0), poster_frame_canceller: DomRefCell::new(Default::default()), load_blocker: Default::default(), + last_frame: Default::default(), } } @@ -108,6 +114,27 @@ impl HTMLVideoElement { LoadBlocker::terminate(&mut *self.load_blocker.borrow_mut()); } + pub fn get_current_frame_data(&self) -> Option<(Option<ipc::IpcSharedMemory>, Size2D<u32>)> { + let frame = self.htmlmediaelement.get_current_frame(); + if frame.is_some() { + *self.last_frame.borrow_mut() = frame; + } + + match self.last_frame.borrow().as_ref() { + Some(frame) => { + let size = Size2D::new(frame.get_width() as u32, frame.get_height() as u32); + if !frame.is_gl_texture() { + let data = Some(ipc::IpcSharedMemory::from_bytes(&frame.get_data())); + Some((data, size)) + } else { + // XXX(victor): here we only have the GL texture ID. + Some((None, size)) + } + }, + None => None, + } + } + /// https://html.spec.whatwg.org/multipage/#poster-frame fn fetch_poster_frame(&self, poster_url: &str) { // Step 1. diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index d6a6c30b823..598832403e0 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -549,6 +549,7 @@ pub mod xmlserializer; pub mod xr; pub mod xrframe; pub mod xrinputsource; +pub mod xrinputsourceevent; pub mod xrpose; pub mod xrreferencespace; pub mod xrrenderstate; diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs index 46b9c72c6ca..f8350759dd8 100644 --- a/components/script/dom/webglrenderingcontext.rs +++ b/components/script/dom/webglrenderingcontext.rs @@ -604,9 +604,14 @@ impl WebGLRenderingContext { return Ok(None); } }, - TexImageSource::HTMLVideoElement(_) => { - // TODO: https://github.com/servo/servo/issues/6711 - return Ok(None); + TexImageSource::HTMLVideoElement(video) => match video.get_current_frame_data() { + Some((data, size)) => { + let data = data.unwrap_or_else(|| { + IpcSharedMemory::from_bytes(&vec![0; size.area() as usize * 4]) + }); + TexPixels::new(data, size, PixelFormat::BGRA8, false) + }, + None => return Ok(None), }, })) } diff --git a/components/script/dom/webidls/XRInputSourceEvent.webidl b/components/script/dom/webidls/XRInputSourceEvent.webidl new file mode 100644 index 00000000000..f1ffbf2a799 --- /dev/null +++ b/components/script/dom/webidls/XRInputSourceEvent.webidl @@ -0,0 +1,17 @@ +/* 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/#xrinputsourceevent-interface + +[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"] +interface XRInputSourceEvent : Event { + [Throws] constructor(DOMString type, XRInputSourceEventInit eventInitDict); + [SameObject] readonly attribute XRFrame frame; + [SameObject] readonly attribute XRInputSource inputSource; +}; + +dictionary XRInputSourceEventInit : EventInit { + required XRFrame frame; + required XRInputSource inputSource; +}; diff --git a/components/script/dom/webidls/XRSession.webidl b/components/script/dom/webidls/XRSession.webidl index 6d946ccef55..820ef11dc70 100644 --- a/components/script/dom/webidls/XRSession.webidl +++ b/components/script/dom/webidls/XRSession.webidl @@ -39,8 +39,8 @@ interface XRSession : EventTarget { // attribute EventHandler onblur; // attribute EventHandler onfocus; attribute EventHandler onend; - // attribute EventHandler onselect; + attribute EventHandler onselect; // attribute EventHandler oninputsourceschange; - // attribute EventHandler onselectstart; - // attribute EventHandler onselectend; + attribute EventHandler onselectstart; + attribute EventHandler onselectend; }; diff --git a/components/script/dom/xrframe.rs b/components/script/dom/xrframe.rs index 29572c02300..6c67d896f81 100644 --- a/components/script/dom/xrframe.rs +++ b/components/script/dom/xrframe.rs @@ -93,8 +93,16 @@ impl XRFrameMethods for XRFrame { if !self.active.get() { return Err(Error::InvalidState); } - let space = space.get_pose(&self.data); - let relative_to = relative_to.get_pose(&self.data); + let space = if let Some(space) = space.get_pose(&self.data) { + space + } else { + return Ok(None); + }; + let relative_to = if let Some(r) = relative_to.get_pose(&self.data) { + r + } else { + return Ok(None); + }; let pose = relative_to.inverse().pre_transform(&space); Ok(Some(XRPose::new(&self.global(), pose))) } diff --git a/components/script/dom/xrinputsourceevent.rs b/components/script/dom/xrinputsourceevent.rs new file mode 100644 index 00000000000..aa177f1df9a --- /dev/null +++ b/components/script/dom/xrinputsourceevent.rs @@ -0,0 +1,90 @@ +/* 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::XRInputSourceEventBinding::{ + self, XRInputSourceEventMethods, +}; +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::window::Window; +use crate::dom::xrframe::XRFrame; +use crate::dom::xrinputsource::XRInputSource; +use dom_struct::dom_struct; +use servo_atoms::Atom; + +#[dom_struct] +pub struct XRInputSourceEvent { + event: Event, + frame: Dom<XRFrame>, + source: Dom<XRInputSource>, +} + +impl XRInputSourceEvent { + #[allow(unrooted_must_root)] + fn new_inherited(frame: &XRFrame, source: &XRInputSource) -> XRInputSourceEvent { + XRInputSourceEvent { + event: Event::new_inherited(), + frame: Dom::from_ref(frame), + source: Dom::from_ref(source), + } + } + + pub fn new( + global: &GlobalScope, + type_: Atom, + bubbles: bool, + cancelable: bool, + frame: &XRFrame, + source: &XRInputSource, + ) -> DomRoot<XRInputSourceEvent> { + let trackevent = reflect_dom_object( + Box::new(XRInputSourceEvent::new_inherited(frame, source)), + global, + XRInputSourceEventBinding::Wrap, + ); + { + let event = trackevent.upcast::<Event>(); + event.init_event(type_, bubbles, cancelable); + } + trackevent + } + + pub fn Constructor( + window: &Window, + type_: DOMString, + init: &XRInputSourceEventBinding::XRInputSourceEventInit, + ) -> Fallible<DomRoot<XRInputSourceEvent>> { + Ok(XRInputSourceEvent::new( + &window.global(), + Atom::from(type_), + init.parent.bubbles, + init.parent.cancelable, + &init.frame, + &init.inputSource, + )) + } +} + +impl XRInputSourceEventMethods for XRInputSourceEvent { + // https://immersive-web.github.io/webxr/#dom-xrinputsourceeventinit-frame + fn Frame(&self) -> DomRoot<XRFrame> { + DomRoot::from_ref(&*self.frame) + } + + // https://immersive-web.github.io/webxr/#dom-xrinputsourceeventinit-inputsource + fn InputSource(&self) -> DomRoot<XRInputSource> { + DomRoot::from_ref(&*self.source) + } + + // https://dom.spec.whatwg.org/#dom-event-istrusted + fn IsTrusted(&self) -> bool { + self.event.IsTrusted() + } +} diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index dacfc373540..e7a3fab4677 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -33,6 +33,7 @@ use crate::dom::promise::Promise; use crate::dom::webglframebuffer::WebGLFramebufferAttachmentRoot; use crate::dom::xrframe::XRFrame; use crate::dom::xrinputsource::XRInputSource; +use crate::dom::xrinputsourceevent::XRInputSourceEvent; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrrenderstate::XRRenderState; use crate::dom::xrsessionevent::XRSessionEvent; @@ -48,7 +49,7 @@ use profile_traits::ipc; use std::cell::Cell; use std::mem; use std::rc::Rc; -use webxr_api::{self, Event as XREvent, Frame, Session}; +use webxr_api::{self, Event as XREvent, Frame, SelectEvent, Session}; #[dom_struct] pub struct XRSession { @@ -170,6 +171,52 @@ impl XRSession { let event = XRSessionEvent::new(&self.global(), atom!("end"), false, false, self); event.upcast::<Event>().fire(self.upcast()); }, + XREvent::Select(input, kind, frame) => { + // https://immersive-web.github.io/webxr/#primary-action + let source = self + .input_sources + .borrow_mut() + .iter() + .find(|s| s.id() == input) + .map(|x| DomRoot::from_ref(&**x)); + if let Some(source) = source { + let frame = XRFrame::new(&self.global(), self, frame); + frame.set_active(true); + if kind == SelectEvent::Start { + let event = XRInputSourceEvent::new( + &self.global(), + atom!("selectstart"), + false, + false, + &frame, + &source, + ); + event.upcast::<Event>().fire(self.upcast()); + } else { + if kind == SelectEvent::Select { + let event = XRInputSourceEvent::new( + &self.global(), + atom!("select"), + false, + false, + &frame, + &source, + ); + event.upcast::<Event>().fire(self.upcast()); + } + let event = XRInputSourceEvent::new( + &self.global(), + atom!("selectend"), + false, + false, + &frame, + &source, + ); + event.upcast::<Event>().fire(self.upcast()); + } + frame.set_active(false); + } + }, _ => (), // XXXManishearth TBD } } @@ -244,6 +291,15 @@ impl XRSessionMethods for XRSession { /// https://immersive-web.github.io/webxr/#eventdef-xrsession-end event_handler!(end, GetOnend, SetOnend); + /// https://immersive-web.github.io/webxr/#eventdef-xrsession-select + event_handler!(select, GetOnselect, SetOnselect); + + /// https://immersive-web.github.io/webxr/#eventdef-xrsession-selectstart + event_handler!(selectstart, GetOnselectstart, SetOnselectstart); + + /// https://immersive-web.github.io/webxr/#eventdef-xrsession-selectend + event_handler!(selectend, GetOnselectend, SetOnselectend); + /// https://immersive-web.github.io/webxr/#dom-xrsession-mode fn Mode(&self) -> XRSessionMode { XRSessionMode::Immersive_vr diff --git a/components/script/dom/xrspace.rs b/components/script/dom/xrspace.rs index 6fa00d1cffe..ce68e786927 100644 --- a/components/script/dom/xrspace.rs +++ b/components/script/dom/xrspace.rs @@ -57,9 +57,9 @@ impl XRSpace { /// The reference origin used is common between all /// get_pose calls for spaces from the same device, so this can be used to compare /// with other spaces - pub fn get_pose(&self, base_pose: &Frame) -> ApiPose { + pub fn get_pose(&self, base_pose: &Frame) -> Option<ApiPose> { if let Some(reference) = self.downcast::<XRReferenceSpace>() { - reference.get_pose(base_pose) + Some(reference.get_pose(base_pose)) } else if let Some(source) = self.input_source.get() { // XXXManishearth we should be able to request frame information // for inputs when necessary instead of always loading it @@ -72,7 +72,7 @@ impl XRSpace { .iter() .find(|i| i.id == id) .expect("no input found"); - cast_transform(frame.target_ray_origin) + frame.target_ray_origin.map(cast_transform) } else { unreachable!() } |