diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/error.rs | 3 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 11 | ||||
-rw-r--r-- | components/script/dom/domexception.rs | 5 | ||||
-rw-r--r-- | components/script/dom/fakexrdevice.rs | 12 | ||||
-rw-r--r-- | components/script/dom/webidls/DOMException.webidl | 3 | ||||
-rw-r--r-- | components/script/dom/webidls/XRWebGLLayer.webidl | 6 | ||||
-rw-r--r-- | components/script/dom/xrsession.rs | 2 | ||||
-rw-r--r-- | components/script/dom/xrviewport.rs | 32 | ||||
-rw-r--r-- | components/script/dom/xrwebgllayer.rs | 126 |
9 files changed, 156 insertions, 44 deletions
diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index 5953a013d6d..40d690ff8d0 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -84,6 +84,8 @@ pub enum Error { InvalidModification, /// NotReadableError DOMException NotReadable, + /// OperationError DOMException + Operation, /// TypeError JavaScript Error Type(String), @@ -136,6 +138,7 @@ pub unsafe fn throw_dom_exception(cx: *mut JSContext, global: &GlobalScope, resu Error::TypeMismatch => DOMErrorName::TypeMismatchError, Error::InvalidModification => DOMErrorName::InvalidModificationError, Error::NotReadable => DOMErrorName::NotReadableError, + Error::Operation => DOMErrorName::OperationError, Error::Type(message) => { assert!(!JS_IsExceptionPending(cx)); throw_type_error(cx, &message); diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index a0307413719..7f4fad813e5 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -57,8 +57,8 @@ use devtools_traits::{CSSError, TimelineMarkerType, WorkerId}; use encoding_rs::{Decoder, Encoding}; use euclid::Length as EuclidLength; use euclid::{ - Point2D, Rect, RigidTransform3D, Rotation3D, Transform2D, Transform3D, TypedRigidTransform3D, - TypedScale, TypedSize2D, Vector2D, + Point2D, Rect, RigidTransform3D, Rotation3D, Transform2D, Transform3D, TypedRect, + TypedRigidTransform3D, TypedScale, TypedSize2D, Vector2D, }; use html5ever::buffer_queue::BufferQueue; use html5ever::{LocalName, Namespace, Prefix, QualName}; @@ -647,6 +647,13 @@ unsafe impl<U> JSTraceable for TypedSize2D<u32, U> { } } +unsafe impl<U> JSTraceable for TypedRect<i32, U> { + #[inline] + unsafe fn trace(&self, _trc: *mut JSTracer) { + // Do nothing + } +} + unsafe impl JSTraceable for StyleLocked<FontFaceRule> { unsafe fn trace(&self, _trc: *mut JSTracer) { // Do nothing. diff --git a/components/script/dom/domexception.rs b/components/script/dom/domexception.rs index b5b0ca5a8c4..0df528edb87 100644 --- a/components/script/dom/domexception.rs +++ b/components/script/dom/domexception.rs @@ -37,6 +37,7 @@ pub enum DOMErrorName { InvalidNodeTypeError = DOMExceptionConstants::INVALID_NODE_TYPE_ERR, DataCloneError = DOMExceptionConstants::DATA_CLONE_ERR, NotReadableError = DOMExceptionConstants::NOT_READABLE_ERR, + OperationError = DOMExceptionConstants::OPERATION_ERR, } impl DOMErrorName { @@ -64,6 +65,7 @@ impl DOMErrorName { "InvalidNodeTypeError" => Some(DOMErrorName::InvalidNodeTypeError), "DataCloneError" => Some(DOMErrorName::DataCloneError), "NotReadableError" => Some(DOMErrorName::NotReadableError), + "OperationError" => Some(DOMErrorName::OperationError), _ => None, } } @@ -107,6 +109,9 @@ impl DOMException { }, DOMErrorName::DataCloneError => "The object can not be cloned.", DOMErrorName::NotReadableError => "The I/O read operation failed.", + DOMErrorName::OperationError => { + "The operation failed for an operation-specific reason." + }, }; ( diff --git a/components/script/dom/fakexrdevice.rs b/components/script/dom/fakexrdevice.rs index e8aa3e26dff..c1268d743d9 100644 --- a/components/script/dom/fakexrdevice.rs +++ b/components/script/dom/fakexrdevice.rs @@ -11,6 +11,7 @@ use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::globalscope::GlobalScope; use dom_struct::dom_struct; +use euclid::{TypedPoint2D, TypedRect, TypedSize2D}; use euclid::{TypedRigidTransform3D, TypedRotation3D, TypedTransform3D, TypedVector3D}; use ipc_channel::ipc::IpcSender; use webxr_api::{MockDeviceMsg, View, Views}; @@ -71,13 +72,24 @@ pub fn get_views(views: &[FakeXRViewInit]) -> Fallible<Views> { let offset_l = get_origin(&left.viewOffset)?.inverse(); let offset_r = get_origin(&right.viewOffset)?.inverse(); + let size_l = TypedSize2D::new(views[0].resolution.width, views[0].resolution.height); + let size_r = TypedSize2D::new(views[1].resolution.width, views[1].resolution.height); + + let origin_l = TypedPoint2D::new(0, 0); + let origin_r = TypedPoint2D::new(size_l.width, 0); + + let viewport_l = TypedRect::new(origin_l, size_l); + let viewport_r = TypedRect::new(origin_r, size_r); + let left = View { projection: proj_l, transform: offset_l, + viewport: viewport_l, }; let right = View { projection: proj_r, transform: offset_r, + viewport: viewport_r, }; Ok(Views::Stereo(left, right)) } diff --git a/components/script/dom/webidls/DOMException.webidl b/components/script/dom/webidls/DOMException.webidl index a686e5b7023..80bf319fdd5 100644 --- a/components/script/dom/webidls/DOMException.webidl +++ b/components/script/dom/webidls/DOMException.webidl @@ -38,7 +38,10 @@ interface DOMException { const unsigned short TIMEOUT_ERR = 23; const unsigned short INVALID_NODE_TYPE_ERR = 24; const unsigned short DATA_CLONE_ERR = 25; + // Only the first 25 errors are given codes in + // https://heycam.github.io/webidl/#idl-DOMException const unsigned short NOT_READABLE_ERR = 26; + const unsigned short OPERATION_ERR = 27; // Error code as u16 readonly attribute unsigned short code; diff --git a/components/script/dom/webidls/XRWebGLLayer.webidl b/components/script/dom/webidls/XRWebGLLayer.webidl index f551096fc05..f83e1e4c35a 100644 --- a/components/script/dom/webidls/XRWebGLLayer.webidl +++ b/components/script/dom/webidls/XRWebGLLayer.webidl @@ -30,9 +30,9 @@ interface XRWebGLLayer : XRLayer { readonly attribute boolean stencil; readonly attribute boolean alpha; - // readonly attribute WebGLFramebuffer framebuffer; - // readonly attribute unsigned long framebufferWidth; - // readonly attribute unsigned long framebufferHeight; + readonly attribute WebGLFramebuffer framebuffer; + readonly attribute unsigned long framebufferWidth; + readonly attribute unsigned long framebufferHeight; // // Methods XRViewport? getViewport(XRView view); diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index 1c29978e2ae..50e89a773dc 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -103,7 +103,7 @@ impl XRSession { ret } - pub fn with_session<F: FnOnce(&Session)>(&self, with: F) { + pub fn with_session<R, F: FnOnce(&Session) -> R>(&self, with: F) -> R { let session = self.session.borrow(); with(&session) } diff --git a/components/script/dom/xrviewport.rs b/components/script/dom/xrviewport.rs index e3065a51d43..f0b013a317e 100644 --- a/components/script/dom/xrviewport.rs +++ b/components/script/dom/xrviewport.rs @@ -8,36 +8,26 @@ use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::globalscope::GlobalScope; use dom_struct::dom_struct; +use euclid::TypedRect; +use webxr_api::Viewport; #[dom_struct] pub struct XRViewport { reflector_: Reflector, - x: u32, - y: u32, - width: u32, - height: u32, + viewport: TypedRect<i32, Viewport>, } impl XRViewport { - fn new_inherited(x: u32, y: u32, width: u32, height: u32) -> XRViewport { + fn new_inherited(viewport: TypedRect<i32, Viewport>) -> XRViewport { XRViewport { reflector_: Reflector::new(), - x, - y, - width, - height, + viewport, } } - pub fn new( - global: &GlobalScope, - x: u32, - y: u32, - width: u32, - height: u32, - ) -> DomRoot<XRViewport> { + pub fn new(global: &GlobalScope, viewport: TypedRect<i32, Viewport>) -> DomRoot<XRViewport> { reflect_dom_object( - Box::new(XRViewport::new_inherited(x, y, width, height)), + Box::new(XRViewport::new_inherited(viewport)), global, XRViewportBinding::Wrap, ) @@ -47,21 +37,21 @@ impl XRViewport { impl XRViewportMethods for XRViewport { /// https://immersive-web.github.io/webxr/#dom-xrviewport-x fn X(&self) -> i32 { - self.x as i32 + self.viewport.origin.x } /// https://immersive-web.github.io/webxr/#dom-xrviewport-y fn Y(&self) -> i32 { - self.y as i32 + self.viewport.origin.y } /// https://immersive-web.github.io/webxr/#dom-xrviewport-width fn Width(&self) -> i32 { - self.width as i32 + self.viewport.size.width } /// https://immersive-web.github.io/webxr/#dom-xrviewport-height fn Height(&self) -> i32 { - self.height as i32 + self.viewport.size.height } } diff --git a/components/script/dom/xrwebgllayer.rs b/components/script/dom/xrwebgllayer.rs index 16653383a0b..a2a7c93f37c 100644 --- a/components/script/dom/xrwebgllayer.rs +++ b/components/script/dom/xrwebgllayer.rs @@ -6,10 +6,15 @@ use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethod use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerInit; use crate::dom::bindings::codegen::Bindings::XRWebGLLayerBinding::XRWebGLLayerMethods; +use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextBinding::WebGLRenderingContextMethods; +use crate::dom::bindings::codegen::Bindings::WebGLRenderingContextBinding::WebGLRenderingContextConstants as constants; +use crate::dom::bindings::error::Error; 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::globalscope::GlobalScope; +use crate::dom::webgl_validations::types::TexImageTarget; +use crate::dom::webglframebuffer::WebGLFramebuffer; use crate::dom::webglrenderingcontext::WebGLRenderingContext; use crate::dom::window::Window; use crate::dom::xrlayer::XRLayer; @@ -17,6 +22,9 @@ use crate::dom::xrsession::XRSession; use crate::dom::xrview::XRView; use crate::dom::xrviewport::XRViewport; use dom_struct::dom_struct; +use js::rust::CustomAutoRooter; +use std::convert::TryInto; +use webxr_api::Views; #[dom_struct] pub struct XRWebGLLayer { @@ -27,6 +35,7 @@ pub struct XRWebGLLayer { alpha: bool, context: Dom<WebGLRenderingContext>, session: Dom<XRSession>, + framebuffer: Dom<WebGLFramebuffer>, } impl XRWebGLLayer { @@ -34,6 +43,7 @@ impl XRWebGLLayer { session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, + framebuffer: &WebGLFramebuffer, ) -> XRWebGLLayer { XRWebGLLayer { xrlayer: XRLayer::new_inherited(), @@ -43,6 +53,7 @@ impl XRWebGLLayer { alpha: init.alpha, context: Dom::from_ref(context), session: Dom::from_ref(session), + framebuffer: Dom::from_ref(framebuffer), } } @@ -51,21 +62,82 @@ impl XRWebGLLayer { session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, + framebuffer: &WebGLFramebuffer, ) -> DomRoot<XRWebGLLayer> { reflect_dom_object( - Box::new(XRWebGLLayer::new_inherited(session, context, init)), + Box::new(XRWebGLLayer::new_inherited( + session, + context, + init, + framebuffer, + )), global, XRWebGLLayerBinding::Wrap, ) } + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-xrwebgllayer pub fn Constructor( global: &Window, session: &XRSession, context: &WebGLRenderingContext, init: &XRWebGLLayerInit, ) -> Fallible<DomRoot<Self>> { - Ok(XRWebGLLayer::new(&global.global(), session, context, init)) + let cx = global.get_cx(); + let old_fbo = context.bound_framebuffer(); + let old_texture = context + .textures() + .active_texture_for_image_target(TexImageTarget::Texture2D); + + // Step 8.2. "Initialize layer’s framebuffer to a new opaque framebuffer created with context." + let framebuffer = context.CreateFramebuffer().ok_or(Error::Operation)?; + + // Step 8.3. "Allocate and initialize resources compatible with session’s XR device, + // including GPU accessible memory buffers, as required to support the compositing of layer." + + // Create a new texture with size given by the session's recommended resolution + let texture = context.CreateTexture().ok_or(Error::Operation)?; + let resolution = session.with_session(|s| s.recommended_framebuffer_resolution()); + let mut pixels = CustomAutoRooter::new(None); + context.BindTexture(constants::TEXTURE_2D, Some(&texture)); + let sc = context.TexImage2D( + constants::TEXTURE_2D, + 0, + constants::RGBA, + resolution.width, + resolution.height, + 0, + constants::RGBA, + constants::UNSIGNED_BYTE, + pixels.root(cx), + ); + + // Bind the new texture to the framebuffer + context.BindFramebuffer(constants::FRAMEBUFFER, Some(&framebuffer)); + context.FramebufferTexture2D( + constants::FRAMEBUFFER, + constants::COLOR_ATTACHMENT0, + constants::TEXTURE_2D, + Some(&texture), + 0, + ); + + // Restore the WebGL state while complaining about global mutable state + context.BindTexture(constants::TEXTURE_2D, old_texture.as_ref().map(|t| &**t)); + context.BindFramebuffer(constants::FRAMEBUFFER, old_fbo.as_ref().map(|f| &**f)); + + // Step 8.4: "If layer’s resources were unable to be created for any reason, + // throw an OperationError and abort these steps." + sc.or(Err(Error::Operation))?; + + // Step 9. "Return layer." + Ok(XRWebGLLayer::new( + &global.global(), + session, + context, + init, + &framebuffer, + )) } } @@ -95,28 +167,48 @@ impl XRWebGLLayerMethods for XRWebGLLayer { DomRoot::from_ref(&self.context) } + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebuffer + fn Framebuffer(&self) -> DomRoot<WebGLFramebuffer> { + DomRoot::from_ref(&self.framebuffer) + } + + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferwidth + fn FramebufferWidth(&self) -> u32 { + self.framebuffer + .size() + .unwrap_or((0, 0)) + .0 + .try_into() + .unwrap_or(0) + } + + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-framebufferheight + fn FramebufferHeight(&self) -> u32 { + self.framebuffer + .size() + .unwrap_or((0, 0)) + .1 + .try_into() + .unwrap_or(0) + } + /// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport fn GetViewport(&self, view: &XRView) -> Option<DomRoot<XRViewport>> { if self.session != view.session() { return None; } - let size = self.context.size(); + let views = self.session.with_session(|s| s.views().clone()); - let x = if view.Eye() == XREye::Left { - 0 - } else { - size.width / 2 + let viewport = match (view.Eye(), views) { + (XREye::None, Views::Mono(view)) => view.viewport, + (XREye::Left, Views::Stereo(view, _)) => view.viewport, + (XREye::Right, Views::Stereo(_, view)) => view.viewport, + // The spec doesn't really say what to do in this case + // https://github.com/immersive-web/webxr/issues/769 + _ => return None, }; - // XXXManishearth this assumes the WebVR default of canvases being cut in half - // which need not be generally true for all devices, and will not work in - // inline VR mode - Some(XRViewport::new( - &self.global(), - x, - 0, - size.width / 2, - size.height, - )) + + Some(XRViewport::new(&self.global(), viewport)) } } |