aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/bindings/trace.rs2
-rw-r--r--components/script/dom/htmlmediaelement.rs31
-rw-r--r--components/script/dom/htmlvideoelement.rs27
-rw-r--r--components/script/dom/mod.rs1
-rw-r--r--components/script/dom/webglrenderingcontext.rs11
-rw-r--r--components/script/dom/webidls/XRInputSourceEvent.webidl17
-rw-r--r--components/script/dom/webidls/XRSession.webidl6
-rw-r--r--components/script/dom/xrframe.rs12
-rw-r--r--components/script/dom/xrinputsourceevent.rs90
-rw-r--r--components/script/dom/xrsession.rs58
-rw-r--r--components/script/dom/xrspace.rs6
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!()
}