Skip to main content

script/dom/webxr/
xrview.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use euclid::RigidTransform3D;
9use js::context::JSContext;
10use js::typedarray::{Float32, HeapFloat32Array};
11use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
12use script_bindings::trace::RootedTraceableBox;
13use webxr_api::{ApiSpace, View};
14
15use crate::dom::bindings::buffer_source::HeapBufferSource;
16use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods};
17use crate::dom::bindings::num::Finite;
18use crate::dom::bindings::root::{Dom, DomRoot};
19use crate::dom::window::Window;
20use crate::dom::xrrigidtransform::XRRigidTransform;
21use crate::dom::xrsession::{BaseSpace, BaseTransform, XRSession, cast_transform};
22
23#[dom_struct]
24pub(crate) struct XRView {
25    reflector_: Reflector,
26    session: Dom<XRSession>,
27    eye: XREye,
28    viewport_index: usize,
29    #[ignore_malloc_size_of = "mozjs"]
30    proj: HeapBufferSource<Float32>,
31    #[no_trace]
32    view: View<ApiSpace>,
33    transform: Dom<XRRigidTransform>,
34    requested_viewport_scale: Cell<f64>,
35}
36
37impl XRView {
38    fn new_inherited(
39        session: &XRSession,
40        transform: &XRRigidTransform,
41        eye: XREye,
42        viewport_index: usize,
43        view: View<ApiSpace>,
44    ) -> XRView {
45        XRView {
46            reflector_: Reflector::new(),
47            session: Dom::from_ref(session),
48            eye,
49            viewport_index,
50            proj: HeapBufferSource::default(),
51            view,
52            transform: Dom::from_ref(transform),
53            requested_viewport_scale: Cell::new(1.0),
54        }
55    }
56
57    pub(crate) fn new<V: Copy>(
58        cx: &mut JSContext,
59        window: &Window,
60        session: &XRSession,
61        view: &View<V>,
62        eye: XREye,
63        viewport_index: usize,
64        to_base: &BaseTransform,
65    ) -> DomRoot<XRView> {
66        let transform: RigidTransform3D<f32, V, BaseSpace> = view.transform.then(to_base);
67        let transform = XRRigidTransform::new(cx, window, cast_transform(transform));
68
69        reflect_dom_object_with_cx(
70            Box::new(XRView::new_inherited(
71                session,
72                &transform,
73                eye,
74                viewport_index,
75                view.cast_unit(),
76            )),
77            window,
78            cx,
79        )
80    }
81
82    pub(crate) fn session(&self) -> &XRSession {
83        &self.session
84    }
85
86    pub(crate) fn viewport_index(&self) -> usize {
87        self.viewport_index
88    }
89}
90
91impl XRViewMethods<crate::DomTypeHolder> for XRView {
92    /// <https://immersive-web.github.io/webxr/#dom-xrview-eye>
93    fn Eye(&self) -> XREye {
94        self.eye
95    }
96
97    /// <https://immersive-web.github.io/webxr/#dom-xrview-projectionmatrix>
98    fn ProjectionMatrix(&self, cx: &mut JSContext) -> RootedTraceableBox<HeapFloat32Array> {
99        if !self.proj.is_initialized() {
100            // row_major since euclid uses row vectors
101            let proj = self.view.projection.to_array();
102            self.proj
103                .set_data(cx, &proj)
104                .expect("Failed to set projection matrix.")
105        }
106        self.proj
107            .get_typed_array()
108            .expect("Failed to get projection matrix.")
109    }
110
111    /// <https://immersive-web.github.io/webxr/#dom-xrview-transform>
112    fn Transform(&self) -> DomRoot<XRRigidTransform> {
113        DomRoot::from_ref(&self.transform)
114    }
115
116    /// <https://www.w3.org/TR/webxr/#dom-xrview-recommendedviewportscale>
117    fn GetRecommendedViewportScale(&self) -> Option<Finite<f64>> {
118        // Just return 1.0 since we currently will always use full-sized viewports
119        Finite::new(1.0)
120    }
121
122    /// <https://www.w3.org/TR/webxr/#dom-xrview-requestviewportscale>
123    fn RequestViewportScale(&self, scale: Option<Finite<f64>>) {
124        if let Some(scale) = scale &&
125            *scale > 0.0
126        {
127            let clamped_scale = scale.clamp(0.0, 1.0);
128            self.requested_viewport_scale.set(clamped_scale);
129        }
130    }
131
132    /// <https://www.w3.org/TR/webxr-ar-module-1/#dom-xrview-isfirstpersonobserver>
133    fn IsFirstPersonObserver(&self) -> bool {
134        // Servo is not currently supported anywhere that supports this, so return false
135        false
136    }
137}