mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Auto merge of #26171 - Manishearth:hittest, r=asajeffrey
Implement hit testing API Depends on https://github.com/servo/webxr/pull/149 , https://github.com/servo/servo/pull/26170 This implements non-transient hit tests. The tests that do not pass are due to https://github.com/web-platform-tests/wpt/issues/22898 , https://github.com/web-platform-tests/wpt/issues/22900, https://github.com/web-platform-tests/wpt/issues/22901 , and https://github.com/immersive-web/hit-test/issues/86
This commit is contained in:
commit
99cd30eaad
34 changed files with 650 additions and 77 deletions
36
Cargo.lock
generated
36
Cargo.lock
generated
|
@ -183,9 +183,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.7"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "background_hang_monitor"
|
||||
|
@ -971,14 +971,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.8.0"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
|
||||
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"maybe-uninit",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
@ -995,9 +996,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.0"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
|
@ -1473,9 +1474,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "euclid"
|
||||
version = "0.20.5"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8813df82772c5ef4c2e9cd4a986773c125ffeafdc08204c9d5c2f06e0abdc17"
|
||||
checksum = "0c6a5b0c779cd0b744c73a1d2083faf181080d696903cdad99a3b03d015d7030"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"serde",
|
||||
|
@ -3846,9 +3847,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.4"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28"
|
||||
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
|
@ -3926,9 +3930,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
|||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.53"
|
||||
version = "0.9.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "465d16ae7fc0e313318f7de5cecf57b2fbe7511fd213978b457e1c96ff46736f"
|
||||
checksum = "7717097d810a0f2e2323f9e5d11e71608355e24828410b55b9d4f18aa5f9a5d8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
|
@ -6270,9 +6274,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.2"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
|
||||
checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
|
@ -6566,7 +6570,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "webxr"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/servo/webxr#0d9c83f333920b98d95adf9666b0a365258990a3"
|
||||
source = "git+https://github.com/servo/webxr#805811544cafbc8dcebc3cd02c38dd329226088d"
|
||||
dependencies = [
|
||||
"android_injected_glue",
|
||||
"bindgen",
|
||||
|
@ -6590,7 +6594,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "webxr-api"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/servo/webxr#0d9c83f333920b98d95adf9666b0a365258990a3"
|
||||
source = "git+https://github.com/servo/webxr#805811544cafbc8dcebc3cd02c38dd329226088d"
|
||||
dependencies = [
|
||||
"euclid",
|
||||
"ipc-channel",
|
||||
|
|
|
@ -157,6 +157,7 @@ use webgpu::{
|
|||
WebGPUPipelineLayout, WebGPUQueue, WebGPUShaderModule,
|
||||
};
|
||||
use webrender_api::{DocumentId, ImageKey};
|
||||
use webxr_api::Ray;
|
||||
use webxr_api::SwapChainId as WebXRSwapChainId;
|
||||
|
||||
unsafe_no_jsmanaged_fields!(Tm);
|
||||
|
@ -552,7 +553,9 @@ unsafe_no_jsmanaged_fields!(
|
|||
webxr_api::Session,
|
||||
webxr_api::Frame,
|
||||
webxr_api::InputSource,
|
||||
webxr_api::InputId
|
||||
webxr_api::InputId,
|
||||
webxr_api::HitTestId,
|
||||
webxr_api::HitTestResult
|
||||
);
|
||||
unsafe_no_jsmanaged_fields!(ScriptToConstellationChan);
|
||||
unsafe_no_jsmanaged_fields!(InteractiveMetrics);
|
||||
|
@ -750,6 +753,13 @@ unsafe impl<U> JSTraceable for euclid::Rect<i32, U> {
|
|||
}
|
||||
}
|
||||
|
||||
unsafe impl<Space> JSTraceable for Ray<Space> {
|
||||
#[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.
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
* 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::DOMPointBinding::DOMPointInit;
|
||||
use crate::dom::bindings::codegen::Bindings::FakeXRDeviceBinding::{
|
||||
FakeXRDeviceMethods, FakeXRRigidTransformInit, FakeXRViewInit,
|
||||
FakeXRDeviceMethods, FakeXRRegionType, FakeXRRigidTransformInit, FakeXRViewInit,
|
||||
FakeXRWorldInit,
|
||||
};
|
||||
use crate::dom::bindings::codegen::Bindings::FakeXRInputControllerBinding::FakeXRInputSourceInit;
|
||||
use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{
|
||||
|
@ -21,15 +23,15 @@ use crate::dom::promise::Promise;
|
|||
use crate::task_source::TaskSource;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::{Point2D, Rect, Size2D};
|
||||
use euclid::{RigidTransform3D, Rotation3D, Transform3D, Vector3D};
|
||||
use euclid::{Point3D, RigidTransform3D, Rotation3D, Transform3D, Vector3D};
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use profile_traits::ipc;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use webxr_api::{
|
||||
Handedness, InputId, InputSource, MockDeviceMsg, MockInputInit, MockViewInit, MockViewsInit,
|
||||
TargetRayMode, Visibility,
|
||||
EntityType, Handedness, InputId, InputSource, MockDeviceMsg, MockInputInit, MockRegion,
|
||||
MockViewInit, MockViewsInit, MockWorld, TargetRayMode, Triangle, Visibility,
|
||||
};
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -97,6 +99,7 @@ pub fn view<Eye>(view: &FakeXRViewInit) -> Fallible<MockViewInit<Eye>> {
|
|||
fov,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_views(views: &[FakeXRViewInit]) -> Fallible<MockViewsInit> {
|
||||
match views.len() {
|
||||
1 => Ok(MockViewsInit::Mono(view(&views[0])?)),
|
||||
|
@ -133,6 +136,50 @@ pub fn get_origin<T, U>(
|
|||
Ok(RigidTransform3D::new(o, p))
|
||||
}
|
||||
|
||||
pub fn get_point<T>(pt: &DOMPointInit) -> Point3D<f32, T> {
|
||||
Point3D::new(pt.x / pt.w, pt.y / pt.w, pt.z / pt.w).cast()
|
||||
}
|
||||
|
||||
pub fn get_world(world: &FakeXRWorldInit) -> Fallible<MockWorld> {
|
||||
let regions = world
|
||||
.hitTestRegions
|
||||
.iter()
|
||||
.map(|region| {
|
||||
let ty = region.type_.into();
|
||||
let faces = region
|
||||
.faces
|
||||
.iter()
|
||||
.map(|face| {
|
||||
if face.vertices.len() != 3 {
|
||||
return Err(Error::Type(
|
||||
"Incorrectly sized array for triangle list".into(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Triangle {
|
||||
first: get_point(&face.vertices[0]),
|
||||
second: get_point(&face.vertices[1]),
|
||||
third: get_point(&face.vertices[2]),
|
||||
})
|
||||
})
|
||||
.collect::<Fallible<Vec<_>>>()?;
|
||||
Ok(MockRegion { faces, ty })
|
||||
})
|
||||
.collect::<Fallible<Vec<_>>>()?;
|
||||
|
||||
Ok(MockWorld { regions })
|
||||
}
|
||||
|
||||
impl From<FakeXRRegionType> for EntityType {
|
||||
fn from(x: FakeXRRegionType) -> Self {
|
||||
match x {
|
||||
FakeXRRegionType::Point => EntityType::Point,
|
||||
FakeXRRegionType::Plane => EntityType::Plane,
|
||||
FakeXRRegionType::Mesh => EntityType::Mesh,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FakeXRDeviceMethods for FakeXRDevice {
|
||||
/// https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md
|
||||
fn SetViews(&self, views: Vec<FakeXRViewInit>) -> Fallible<()> {
|
||||
|
@ -172,6 +219,17 @@ impl FakeXRDeviceMethods for FakeXRDevice {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr-test-api/#dom-fakexrdevice-clearworld
|
||||
fn ClearWorld(&self) {
|
||||
let _ = self.sender.send(MockDeviceMsg::ClearWorld);
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr-test-api/#dom-fakexrdevice-setworld
|
||||
fn SetWorld(&self, world: &FakeXRWorldInit) -> Fallible<()> {
|
||||
let _ = self.sender.send(MockDeviceMsg::SetWorld(get_world(world)?));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr-test-api/#dom-fakexrdevice-simulatevisibilitychange
|
||||
fn SimulateVisibilityChange(&self, v: XRVisibilityState) {
|
||||
let v = match v {
|
||||
|
|
|
@ -572,6 +572,8 @@ pub mod xmlhttprequesteventtarget;
|
|||
pub mod xmlhttprequestupload;
|
||||
pub mod xmlserializer;
|
||||
pub mod xrframe;
|
||||
pub mod xrhittestresult;
|
||||
pub mod xrhittestsource;
|
||||
pub mod xrinputsource;
|
||||
pub mod xrinputsourcearray;
|
||||
pub mod xrinputsourceevent;
|
||||
|
@ -579,6 +581,7 @@ pub mod xrinputsourceschangeevent;
|
|||
pub mod xrlayer;
|
||||
pub mod xrmediabinding;
|
||||
pub mod xrpose;
|
||||
pub mod xrray;
|
||||
pub mod xrreferencespace;
|
||||
pub mod xrrenderstate;
|
||||
pub mod xrrigidtransform;
|
||||
|
|
|
@ -25,6 +25,10 @@ interface FakeXRDevice {
|
|||
|
||||
// behaves as if device was disconnected
|
||||
Promise<void> disconnect();
|
||||
|
||||
// Hit test extensions:
|
||||
[Throws] void setWorld(FakeXRWorldInit world);
|
||||
void clearWorld();
|
||||
};
|
||||
|
||||
// https://immersive-web.github.io/webxr/#dom-xrwebgllayer-getviewport
|
||||
|
@ -61,3 +65,26 @@ dictionary FakeXRFieldOfViewInit {
|
|||
required float leftDegrees;
|
||||
required float rightDegrees;
|
||||
};
|
||||
|
||||
// hit testing
|
||||
dictionary FakeXRWorldInit {
|
||||
required sequence<FakeXRRegionInit> hitTestRegions;
|
||||
};
|
||||
|
||||
|
||||
dictionary FakeXRRegionInit {
|
||||
required sequence<FakeXRTriangleInit> faces;
|
||||
required FakeXRRegionType type;
|
||||
};
|
||||
|
||||
|
||||
dictionary FakeXRTriangleInit {
|
||||
required sequence<DOMPointInit> vertices; // size = 3
|
||||
};
|
||||
|
||||
|
||||
enum FakeXRRegionType {
|
||||
"point",
|
||||
"plane",
|
||||
"mesh"
|
||||
};
|
||||
|
|
|
@ -10,5 +10,5 @@ interface XRFrame {
|
|||
|
||||
[Throws] XRViewerPose? getViewerPose(XRReferenceSpace referenceSpace);
|
||||
[Throws] XRPose? getPose(XRSpace space, XRSpace relativeTo);
|
||||
// XRInputPose? getInputPose(XRInputSource inputSource, optional XRReferenceSpace referenceSpace);
|
||||
sequence<XRHitTestResult> getHitTestResults(XRHitTestSource hitTestSource);
|
||||
};
|
||||
|
|
10
components/script/dom/webidls/XRHitTestResult.webidl
Normal file
10
components/script/dom/webidls/XRHitTestResult.webidl
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* 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/hit-test/#xrhittestresult-interface
|
||||
|
||||
[SecureContext, Exposed=Window]
|
||||
interface XRHitTestResult {
|
||||
XRPose? getPose(XRSpace baseSpace);
|
||||
};
|
22
components/script/dom/webidls/XRHitTestSource.webidl
Normal file
22
components/script/dom/webidls/XRHitTestSource.webidl
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* 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/hit-test/#xrhittestsource-interface
|
||||
|
||||
enum XRHitTestTrackableType {
|
||||
"point",
|
||||
"plane",
|
||||
"mesh"
|
||||
};
|
||||
|
||||
dictionary XRHitTestOptionsInit {
|
||||
required XRSpace space;
|
||||
sequence<XRHitTestTrackableType> entityTypes;
|
||||
XRRay offsetRay;
|
||||
};
|
||||
|
||||
[SecureContext, Exposed=Window]
|
||||
interface XRHitTestSource {
|
||||
void cancel();
|
||||
};
|
21
components/script/dom/webidls/XRRay.webidl
Normal file
21
components/script/dom/webidls/XRRay.webidl
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* 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/hit-test/#xrray-interface
|
||||
|
||||
dictionary XRRayDirectionInit {
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
double z = -1;
|
||||
double w = 0;
|
||||
};
|
||||
|
||||
[SecureContext, Exposed=Window, Pref="dom.webxr.enabled"]
|
||||
interface XRRay {
|
||||
[Throws] constructor(optional DOMPointInit origin = {}, optional XRRayDirectionInit direction = {});
|
||||
[Throws] constructor(XRRigidTransform transform);
|
||||
[SameObject] readonly attribute DOMPointReadOnly origin;
|
||||
[SameObject] readonly attribute DOMPointReadOnly direction;
|
||||
[SameObject] readonly attribute Float32Array matrix;
|
||||
};
|
|
@ -36,6 +36,9 @@ interface XRSession : EventTarget {
|
|||
|
||||
Promise<void> end();
|
||||
|
||||
// hit test module
|
||||
Promise<XRHitTestSource> requestHitTestSource(XRHitTestOptionsInit options);
|
||||
|
||||
// // Events
|
||||
attribute EventHandler onend;
|
||||
attribute EventHandler onselect;
|
||||
|
|
|
@ -20,13 +20,14 @@ interface XRTest {
|
|||
};
|
||||
|
||||
dictionary FakeXRDeviceInit {
|
||||
required boolean supportsImmersive;
|
||||
boolean supportsImmersive = false;
|
||||
sequence<XRSessionMode> supportedModes;
|
||||
|
||||
required sequence<FakeXRViewInit> views;
|
||||
|
||||
// this is actually sequence<any>, but we don't support
|
||||
// non-string features anyway
|
||||
sequence<DOMString> supportedFeatures;
|
||||
boolean supportsUnbounded = false;
|
||||
// Whether the space supports tracking in inline sessions
|
||||
boolean supportsTrackingInInline = true;
|
||||
// The bounds coordinates. If null, bounded reference spaces are not supported.
|
||||
|
@ -34,5 +35,8 @@ dictionary FakeXRDeviceInit {
|
|||
// Eye level used for calculating floor-level spaces
|
||||
FakeXRRigidTransformInit floorOrigin;
|
||||
FakeXRRigidTransformInit viewerOrigin;
|
||||
|
||||
// Hit test extensions:
|
||||
FakeXRWorldInit world;
|
||||
};
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@ use crate::dom::bindings::inheritance::Castable;
|
|||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::xrhittestresult::XRHitTestResult;
|
||||
use crate::dom::xrhittestsource::XRHitTestSource;
|
||||
use crate::dom::xrpose::XRPose;
|
||||
use crate::dom::xrreferencespace::XRReferenceSpace;
|
||||
use crate::dom::xrsession::XRSession;
|
||||
use crate::dom::xrsession::{ApiPose, XRSession};
|
||||
use crate::dom::xrspace::XRSpace;
|
||||
use crate::dom::xrviewerpose::XRViewerPose;
|
||||
use dom_struct::dom_struct;
|
||||
|
@ -51,6 +53,10 @@ impl XRFrame {
|
|||
pub fn set_animation_frame(&self, animation_frame: bool) {
|
||||
self.animation_frame.set(animation_frame);
|
||||
}
|
||||
|
||||
pub fn get_pose(&self, space: &XRSpace) -> Option<ApiPose> {
|
||||
space.get_pose(&self.data)
|
||||
}
|
||||
}
|
||||
|
||||
impl XRFrameMethods for XRFrame {
|
||||
|
@ -92,12 +98,12 @@ impl XRFrameMethods for XRFrame {
|
|||
if !self.active.get() {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
let space = if let Some(space) = space.get_pose(&self.data) {
|
||||
let space = if let Some(space) = self.get_pose(space) {
|
||||
space
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
let relative_to = if let Some(r) = relative_to.get_pose(&self.data) {
|
||||
let relative_to = if let Some(r) = self.get_pose(relative_to) {
|
||||
r
|
||||
} else {
|
||||
return Ok(None);
|
||||
|
@ -105,4 +111,14 @@ impl XRFrameMethods for XRFrame {
|
|||
let pose = relative_to.inverse().pre_transform(&space);
|
||||
Ok(Some(XRPose::new(&self.global(), pose)))
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/hit-test/#dom-xrframe-gethittestresults
|
||||
fn GetHitTestResults(&self, source: &XRHitTestSource) -> Vec<DomRoot<XRHitTestResult>> {
|
||||
self.data
|
||||
.hit_test_results
|
||||
.iter()
|
||||
.filter(|r| r.id == source.id())
|
||||
.map(|r| XRHitTestResult::new(&self.global(), *r, self))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
|
51
components/script/dom/xrhittestresult.rs
Normal file
51
components/script/dom/xrhittestresult.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* 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::XRHitTestResultBinding::XRHitTestResultMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::xrframe::XRFrame;
|
||||
use crate::dom::xrpose::XRPose;
|
||||
use crate::dom::xrspace::XRSpace;
|
||||
use dom_struct::dom_struct;
|
||||
use webxr_api::HitTestResult;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XRHitTestResult {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webxr"]
|
||||
result: HitTestResult,
|
||||
frame: Dom<XRFrame>,
|
||||
}
|
||||
|
||||
impl XRHitTestResult {
|
||||
fn new_inherited(result: HitTestResult, frame: &XRFrame) -> XRHitTestResult {
|
||||
XRHitTestResult {
|
||||
reflector_: Reflector::new(),
|
||||
result,
|
||||
frame: Dom::from_ref(frame),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
result: HitTestResult,
|
||||
frame: &XRFrame,
|
||||
) -> DomRoot<XRHitTestResult> {
|
||||
reflect_dom_object(
|
||||
Box::new(XRHitTestResult::new_inherited(result, frame)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl XRHitTestResultMethods for XRHitTestResult {
|
||||
// https://immersive-web.github.io/hit-test/#dom-xrhittestresult-getpose
|
||||
fn GetPose(&self, base: &XRSpace) -> Option<DomRoot<XRPose>> {
|
||||
let base = self.frame.get_pose(base)?;
|
||||
let pose = base.inverse().pre_transform(&self.result.space);
|
||||
Some(XRPose::new(&self.global(), pose.cast_unit()))
|
||||
}
|
||||
}
|
51
components/script/dom/xrhittestsource.rs
Normal file
51
components/script/dom/xrhittestsource.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* 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::XRHitTestSourceBinding::XRHitTestSourceMethods;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::xrsession::XRSession;
|
||||
use dom_struct::dom_struct;
|
||||
use webxr_api::HitTestId;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XRHitTestSource {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webxr"]
|
||||
id: HitTestId,
|
||||
session: Dom<XRSession>,
|
||||
}
|
||||
|
||||
impl XRHitTestSource {
|
||||
fn new_inherited(id: HitTestId, session: &XRSession) -> XRHitTestSource {
|
||||
XRHitTestSource {
|
||||
reflector_: Reflector::new(),
|
||||
id,
|
||||
session: Dom::from_ref(session),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
id: HitTestId,
|
||||
session: &XRSession,
|
||||
) -> DomRoot<XRHitTestSource> {
|
||||
reflect_dom_object(
|
||||
Box::new(XRHitTestSource::new_inherited(id, session)),
|
||||
global,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn id(&self) -> HitTestId {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl XRHitTestSourceMethods for XRHitTestSource {
|
||||
// https://immersive-web.github.io/hit-test/#dom-xrhittestsource-cancel
|
||||
fn Cancel(&self) {
|
||||
self.session.with_session(|s| s.cancel_hit_test(self.id));
|
||||
}
|
||||
}
|
147
components/script/dom/xrray.rs
Normal file
147
components/script/dom/xrray.rs
Normal file
|
@ -0,0 +1,147 @@
|
|||
/* 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::DOMPointBinding::DOMPointInit;
|
||||
use crate::dom::bindings::codegen::Bindings::XRRayBinding::{XRRayDirectionInit, XRRayMethods};
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::utils::create_typed_array;
|
||||
use crate::dom::dompointreadonly::DOMPointReadOnly;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::window::Window;
|
||||
use crate::dom::xrrigidtransform::XRRigidTransform;
|
||||
use crate::script_runtime::JSContext;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::{Angle, RigidTransform3D, Rotation3D, Vector3D};
|
||||
use js::jsapi::{Heap, JSObject};
|
||||
use std::ptr::NonNull;
|
||||
use webxr_api::{ApiSpace, Ray};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XRRay {
|
||||
reflector_: Reflector,
|
||||
#[ignore_malloc_size_of = "defined in webxr"]
|
||||
ray: Ray<ApiSpace>,
|
||||
#[ignore_malloc_size_of = "defined in mozjs"]
|
||||
matrix: Heap<*mut JSObject>,
|
||||
}
|
||||
|
||||
impl XRRay {
|
||||
fn new_inherited(ray: Ray<ApiSpace>) -> XRRay {
|
||||
XRRay {
|
||||
reflector_: Reflector::new(),
|
||||
ray,
|
||||
matrix: Heap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: &GlobalScope, ray: Ray<ApiSpace>) -> DomRoot<XRRay> {
|
||||
reflect_dom_object(Box::new(XRRay::new_inherited(ray)), global)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
/// https://immersive-web.github.io/hit-test/#dom-xrray-xrray
|
||||
pub fn Constructor(
|
||||
window: &Window,
|
||||
origin: &DOMPointInit,
|
||||
direction: &XRRayDirectionInit,
|
||||
) -> Fallible<DomRoot<Self>> {
|
||||
if origin.w != 1.0 {
|
||||
return Err(Error::Type("Origin w coordinate must be 1".into()));
|
||||
}
|
||||
if *direction.w != 0.0 {
|
||||
return Err(Error::Type("Direction w coordinate must be 0".into()));
|
||||
}
|
||||
if *direction.x == 0.0 && *direction.y == 0.0 && *direction.z == 0.0 {
|
||||
return Err(Error::Type(
|
||||
"Direction vector cannot have zero length".into(),
|
||||
));
|
||||
}
|
||||
|
||||
let origin = Vector3D::new(origin.x as f32, origin.y as f32, origin.z as f32);
|
||||
let direction = Vector3D::new(
|
||||
*direction.x as f32,
|
||||
*direction.y as f32,
|
||||
*direction.z as f32,
|
||||
)
|
||||
.normalize();
|
||||
|
||||
Ok(Self::new(&window.global(), Ray { origin, direction }))
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
/// https://immersive-web.github.io/hit-test/#dom-xrray-xrray-transform
|
||||
pub fn Constructor_(window: &Window, transform: &XRRigidTransform) -> Fallible<DomRoot<Self>> {
|
||||
let transform = transform.transform();
|
||||
let origin = transform.translation;
|
||||
let direction = transform
|
||||
.rotation
|
||||
.transform_vector3d(Vector3D::new(0., 0., -1.));
|
||||
|
||||
Ok(Self::new(&window.global(), Ray { origin, direction }))
|
||||
}
|
||||
|
||||
pub fn ray(&self) -> Ray<ApiSpace> {
|
||||
self.ray
|
||||
}
|
||||
}
|
||||
|
||||
impl XRRayMethods for XRRay {
|
||||
/// https://immersive-web.github.io/hit-test/#dom-xrray-origin
|
||||
fn Origin(&self) -> DomRoot<DOMPointReadOnly> {
|
||||
DOMPointReadOnly::new(
|
||||
&self.global(),
|
||||
self.ray.origin.x as f64,
|
||||
self.ray.origin.y as f64,
|
||||
self.ray.origin.z as f64,
|
||||
1.,
|
||||
)
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/hit-test/#dom-xrray-direction
|
||||
fn Direction(&self) -> DomRoot<DOMPointReadOnly> {
|
||||
DOMPointReadOnly::new(
|
||||
&self.global(),
|
||||
self.ray.direction.x as f64,
|
||||
self.ray.direction.y as f64,
|
||||
self.ray.direction.z as f64,
|
||||
0.,
|
||||
)
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/hit-test/#dom-xrray-matrix
|
||||
fn Matrix(&self, _cx: JSContext) -> NonNull<JSObject> {
|
||||
// https://immersive-web.github.io/hit-test/#xrray-obtain-the-matrix
|
||||
// Step 1
|
||||
if self.matrix.get().is_null() {
|
||||
let cx = self.global().get_cx();
|
||||
// Step 2
|
||||
let z = Vector3D::new(0., 0., -1.);
|
||||
// Step 3
|
||||
let axis = z.cross(self.ray.direction);
|
||||
// Step 4
|
||||
let cos_angle = z.dot(self.ray.direction);
|
||||
// Step 5
|
||||
let rotation = if cos_angle > -1. && cos_angle < 1. {
|
||||
Rotation3D::around_axis(axis, Angle::radians(cos_angle.acos()))
|
||||
} else if cos_angle == -1. {
|
||||
let axis = Vector3D::new(1., 0., 0.);
|
||||
Rotation3D::around_axis(axis, Angle::radians(cos_angle.acos()))
|
||||
} else {
|
||||
Rotation3D::identity()
|
||||
};
|
||||
// Step 6
|
||||
let translation = self.ray.origin;
|
||||
// Step 7
|
||||
// According to the spec all matrices are column-major,
|
||||
// however euclid uses row vectors so we use .to_row_major_array()
|
||||
let arr = RigidTransform3D::new(rotation, translation)
|
||||
.to_transform()
|
||||
.to_row_major_array();
|
||||
create_typed_array(cx, &arr, &self.matrix);
|
||||
}
|
||||
NonNull::new(self.matrix.get()).unwrap()
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ use crate::dom::xrsession::{cast_transform, ApiPose, ApiViewerPose, XRSession};
|
|||
use crate::dom::xrspace::XRSpace;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::RigidTransform3D;
|
||||
use webxr_api::Frame;
|
||||
use webxr_api::{BaseSpace, Frame, Space};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XRReferenceSpace {
|
||||
|
@ -57,6 +57,17 @@ impl XRReferenceSpace {
|
|||
global,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn space(&self) -> Space {
|
||||
let base = match self.ty {
|
||||
XRReferenceSpaceType::Local => BaseSpace::Local,
|
||||
XRReferenceSpaceType::Viewer => BaseSpace::Viewer,
|
||||
XRReferenceSpaceType::Local_floor => BaseSpace::Floor,
|
||||
_ => panic!("unsupported reference space found"),
|
||||
};
|
||||
let offset = self.offset.transform();
|
||||
Space { base, offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl XRReferenceSpaceMethods for XRReferenceSpace {
|
||||
|
|
|
@ -6,6 +6,8 @@ use crate::dom::bindings::callback::ExceptionHandling;
|
|||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::NavigatorBinding::NavigatorBinding::NavigatorMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowBinding::WindowMethods;
|
||||
use crate::dom::bindings::codegen::Bindings::XRHitTestSourceBinding::XRHitTestOptionsInit;
|
||||
use crate::dom::bindings::codegen::Bindings::XRHitTestSourceBinding::XRHitTestTrackableType;
|
||||
use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType;
|
||||
use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateInit;
|
||||
use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateMethods;
|
||||
|
@ -28,6 +30,7 @@ use crate::dom::globalscope::GlobalScope;
|
|||
use crate::dom::performance::reduce_timing_resolution;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::dom::xrframe::XRFrame;
|
||||
use crate::dom::xrhittestsource::XRHitTestSource;
|
||||
use crate::dom::xrinputsourcearray::XRInputSourceArray;
|
||||
use crate::dom::xrinputsourceevent::XRInputSourceEvent;
|
||||
use crate::dom::xrreferencespace::XRReferenceSpace;
|
||||
|
@ -37,18 +40,20 @@ use crate::dom::xrspace::XRSpace;
|
|||
use crate::realms::InRealm;
|
||||
use crate::task_source::TaskSource;
|
||||
use dom_struct::dom_struct;
|
||||
use euclid::{Rect, RigidTransform3D, Transform3D};
|
||||
use euclid::{Rect, RigidTransform3D, Transform3D, Vector3D};
|
||||
use ipc_channel::ipc::IpcReceiver;
|
||||
use ipc_channel::router::ROUTER;
|
||||
use metrics::ToMs;
|
||||
use profile_traits::ipc;
|
||||
use std::cell::Cell;
|
||||
use std::collections::HashMap;
|
||||
use std::f64::consts::{FRAC_PI_2, PI};
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
use webxr_api::{
|
||||
self, util, Display, EnvironmentBlendMode, Event as XREvent, Frame, SelectEvent, SelectKind,
|
||||
Session, SessionId, View, Viewer, Visibility,
|
||||
self, util, ApiSpace, Display, EntityTypes, EnvironmentBlendMode, Event as XREvent, Frame,
|
||||
FrameUpdateEvent, HitTestId, HitTestSource, Ray, SelectEvent, SelectKind, Session, SessionId,
|
||||
View, Viewer, Visibility,
|
||||
};
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -75,6 +80,10 @@ pub struct XRSession {
|
|||
end_promises: DomRefCell<Vec<Rc<Promise>>>,
|
||||
/// https://immersive-web.github.io/webxr/#ended
|
||||
ended: Cell<bool>,
|
||||
#[ignore_malloc_size_of = "defined in webxr"]
|
||||
next_hit_test_id: Cell<HitTestId>,
|
||||
#[ignore_malloc_size_of = "defined in webxr"]
|
||||
pending_hit_test_promises: DomRefCell<HashMap<HitTestId, Rc<Promise>>>,
|
||||
/// Opaque framebuffers need to know the session is "outside of a requestAnimationFrame"
|
||||
/// https://immersive-web.github.io/webxr/#opaque-framebuffer
|
||||
outside_raf: Cell<bool>,
|
||||
|
@ -104,6 +113,8 @@ impl XRSession {
|
|||
input_sources: Dom::from_ref(input_sources),
|
||||
end_promises: DomRefCell::new(vec![]),
|
||||
ended: Cell::new(false),
|
||||
next_hit_test_id: Cell::new(HitTestId(0)),
|
||||
pending_hit_test_promises: DomRefCell::new(HashMap::new()),
|
||||
outside_raf: Cell::new(true),
|
||||
}
|
||||
}
|
||||
|
@ -373,7 +384,7 @@ impl XRSession {
|
|||
}
|
||||
|
||||
for event in frame.events.drain(..) {
|
||||
self.session.borrow_mut().apply_event(event)
|
||||
self.handle_frame_update(event);
|
||||
}
|
||||
|
||||
// Step 2
|
||||
|
@ -480,6 +491,22 @@ impl XRSession {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_frame_update(&self, event: FrameUpdateEvent) {
|
||||
match event {
|
||||
FrameUpdateEvent::HitTestSourceAdded(id) => {
|
||||
if let Some(promise) = self.pending_hit_test_promises.borrow_mut().remove(&id) {
|
||||
promise.resolve_native(&XRHitTestSource::new(&self.global(), id, &self));
|
||||
} else {
|
||||
warn!(
|
||||
"received hit test add request for unknown hit test {:?}",
|
||||
id
|
||||
)
|
||||
}
|
||||
},
|
||||
_ => self.session.borrow_mut().apply_event(event),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl XRSessionMethods for XRSession {
|
||||
|
@ -709,10 +736,66 @@ impl XRSessionMethods for XRSession {
|
|||
self.session.borrow_mut().end_session();
|
||||
p
|
||||
}
|
||||
|
||||
// https://immersive-web.github.io/hit-test/#dom-xrsession-requesthittestsource
|
||||
fn RequestHitTestSource(&self, options: &XRHitTestOptionsInit) -> Rc<Promise> {
|
||||
let p = Promise::new(&self.global());
|
||||
|
||||
if self
|
||||
.session
|
||||
.borrow()
|
||||
.granted_features()
|
||||
.iter()
|
||||
.find(|f| &**f == "hit-test")
|
||||
.is_none()
|
||||
{
|
||||
p.reject_error(Error::NotSupported);
|
||||
return p;
|
||||
}
|
||||
|
||||
let id = self.next_hit_test_id.get();
|
||||
self.next_hit_test_id.set(HitTestId(id.0 + 1));
|
||||
|
||||
let space = options.space.space();
|
||||
let ray = if let Some(ref ray) = options.offsetRay {
|
||||
ray.ray()
|
||||
} else {
|
||||
Ray {
|
||||
origin: Vector3D::new(0., 0., 0.),
|
||||
direction: Vector3D::new(0., 0., -1.),
|
||||
}
|
||||
};
|
||||
|
||||
let mut types = EntityTypes::default();
|
||||
|
||||
if let Some(ref tys) = options.entityTypes {
|
||||
for ty in tys {
|
||||
match ty {
|
||||
XRHitTestTrackableType::Point => types.point = true,
|
||||
XRHitTestTrackableType::Plane => types.plane = true,
|
||||
XRHitTestTrackableType::Mesh => types.mesh = true,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
types.plane = true;
|
||||
}
|
||||
|
||||
let source = HitTestSource {
|
||||
id,
|
||||
space,
|
||||
ray,
|
||||
types,
|
||||
};
|
||||
self.pending_hit_test_promises
|
||||
.borrow_mut()
|
||||
.insert(id, p.clone());
|
||||
|
||||
self.session.borrow().request_hit_test(source);
|
||||
|
||||
p
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ApiSpace;
|
||||
// The pose of an object in native-space. Should never be exposed.
|
||||
pub type ApiPose = RigidTransform3D<f32, ApiSpace, webxr_api::Native>;
|
||||
// The pose of the viewer in some api-space.
|
||||
|
|
|
@ -11,7 +11,8 @@ use crate::dom::xrinputsource::XRInputSource;
|
|||
use crate::dom::xrreferencespace::XRReferenceSpace;
|
||||
use crate::dom::xrsession::{cast_transform, ApiPose, XRSession};
|
||||
use dom_struct::dom_struct;
|
||||
use webxr_api::Frame;
|
||||
use euclid::RigidTransform3D;
|
||||
use webxr_api::{BaseSpace, Frame, Space};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XRSpace {
|
||||
|
@ -56,6 +57,24 @@ impl XRSpace {
|
|||
global,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn space(&self) -> Space {
|
||||
if let Some(rs) = self.downcast::<XRReferenceSpace>() {
|
||||
rs.space()
|
||||
} else if let Some(source) = self.input_source.get() {
|
||||
let base = if self.is_grip_space {
|
||||
BaseSpace::Grip(source.id())
|
||||
} else {
|
||||
BaseSpace::TargetRay(source.id())
|
||||
};
|
||||
Space {
|
||||
base,
|
||||
offset: RigidTransform3D::identity(),
|
||||
}
|
||||
} else {
|
||||
panic!("invalid space found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl XRSpace {
|
||||
|
|
|
@ -9,11 +9,12 @@
|
|||
use crate::dom::bindings::callback::ExceptionHandling;
|
||||
use crate::dom::bindings::cell::DomRefCell;
|
||||
use crate::dom::bindings::codegen::Bindings::FunctionBinding::Function;
|
||||
use crate::dom::bindings::codegen::Bindings::XRSystemBinding::XRSessionMode;
|
||||
use crate::dom::bindings::codegen::Bindings::XRTestBinding::{FakeXRDeviceInit, XRTestMethods};
|
||||
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot};
|
||||
use crate::dom::fakexrdevice::{get_origin, get_views, FakeXRDevice};
|
||||
use crate::dom::fakexrdevice::{get_origin, get_views, get_world, FakeXRDevice};
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::promise::Promise;
|
||||
use crate::script_thread::ScriptThread;
|
||||
|
@ -106,13 +107,40 @@ impl XRTestMethods for XRTest {
|
|||
vec![]
|
||||
};
|
||||
|
||||
let world = if let Some(ref w) = init.world {
|
||||
let w = match get_world(w) {
|
||||
Ok(w) => w,
|
||||
Err(e) => {
|
||||
p.reject_error(e);
|
||||
return p;
|
||||
},
|
||||
};
|
||||
Some(w)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (mut supports_inline, mut supports_vr, mut supports_ar) = (false, false, false);
|
||||
|
||||
if let Some(ref modes) = init.supportedModes {
|
||||
for mode in modes {
|
||||
match mode {
|
||||
XRSessionMode::Immersive_vr => supports_vr = true,
|
||||
XRSessionMode::Immersive_ar => supports_ar = true,
|
||||
XRSessionMode::Inline => supports_inline = true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let init = MockDeviceInit {
|
||||
viewer_origin: origin,
|
||||
views,
|
||||
supports_immersive: init.supportsImmersive,
|
||||
supports_unbounded: init.supportsUnbounded,
|
||||
supports_inline,
|
||||
supports_vr,
|
||||
supports_ar,
|
||||
floor_origin,
|
||||
supported_features,
|
||||
world,
|
||||
};
|
||||
|
||||
let global = self.global();
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[xrDevice_isSessionSupported_immersive-ar.https.html]
|
||||
[isSessionSupported resolves to false for immersive-ar on an unsupported device]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[xrDevice_requestSession_immersive-ar.https.html]
|
||||
[Tests requestSession rejects immersive-ar mode when unsupported]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
[ar_dom_overlay.https.html]
|
||||
expected: ERROR
|
||||
[Ensures DOM Overlay element selection works]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -6,7 +7,7 @@
|
|||
expected: FAIL
|
||||
|
||||
[Ensures DOM Overlay input deduplication works]
|
||||
expected: FAIL
|
||||
expected: TIMEOUT
|
||||
|
||||
[Ensures DOM Overlay feature works for immersive-ar, body element]
|
||||
expected: FAIL
|
||||
|
@ -15,11 +16,11 @@
|
|||
expected: FAIL
|
||||
|
||||
[Ensures DOM Overlay Fullscreen API doesn't change DOM overlay]
|
||||
expected: FAIL
|
||||
expected: NOTRUN
|
||||
|
||||
[Ensures DOM Overlay feature works for immersive-ar, div element]
|
||||
expected: FAIL
|
||||
|
||||
[Ensures DOM Overlay interactions on cross origin iframe are ignored]
|
||||
expected: FAIL
|
||||
expected: NOTRUN
|
||||
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
[ar_dom_overlay_hit_test.https.html]
|
||||
expected: ERROR
|
||||
[Ensures DOM Overlay interactions on cross origin iframe do not cause hit test results to come up]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,2 +1,10 @@
|
|||
[ar_hittest_subscription_inputSources.https.html]
|
||||
expected: ERROR
|
||||
[Ensures subscription to hit test works with an XRSpace from input source - after move - no results]
|
||||
expected: FAIL
|
||||
|
||||
[Ensures subscription to hit test works with an XRSpace from input source - after move - 1 result]
|
||||
expected: FAIL
|
||||
|
||||
[Ensures subscription to hit test works with an XRSpace from input source - no move]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,2 +1,10 @@
|
|||
[ar_hittest_subscription_refSpaces.https.html]
|
||||
expected: ERROR
|
||||
[Ensures subscription to hit test works with viewer space - straight ahead - plane]
|
||||
expected: FAIL
|
||||
|
||||
[Ensures subscription to hit test works with local space]
|
||||
expected: FAIL
|
||||
|
||||
[Ensures subscription to hit test works with local-floor space]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
[ar_hittest_subscription_states_regular.https.html]
|
||||
[Hit test subscription succeeds if the feature was requested]
|
||||
expected: FAIL
|
||||
|
||||
[Hit test subscription fails if the feature was not requested]
|
||||
expected: FAIL
|
||||
|
||||
[Hit test subscription fails if the feature was requested but the session already ended]
|
||||
expected: FAIL
|
||||
|
|
@ -1,2 +1,11 @@
|
|||
[ar_hittest_subscription_transientInputSources.https.html]
|
||||
expected: ERROR
|
||||
[Ensures subscription to transient hit test works with an XRSpace from input source - after move - 1 result]
|
||||
expected: NOTRUN
|
||||
|
||||
[Ensures subscription to transient hit test works with an XRSpace from input source - after move - no results]
|
||||
expected: NOTRUN
|
||||
|
||||
[Ensures subscription to transient hit test works with an XRSpace from input source - no move]
|
||||
expected: TIMEOUT
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[xrRay_constructor.https.html]
|
||||
[XRRay constructors work]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[xrRay_matrix.https.html]
|
||||
[XRRay matrix works]
|
||||
expected: FAIL
|
||||
|
|
@ -13870,7 +13870,7 @@
|
|||
]
|
||||
],
|
||||
"interfaces.html": [
|
||||
"dc9a1f5f378bc50487bfb7dc3db6d121d2f325ca",
|
||||
"1a579837cc22d31a7792566615d9e321b3d7fe39",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
|
@ -14609,21 +14609,21 @@
|
|||
},
|
||||
"webxr": {
|
||||
"create_session.html": [
|
||||
"af76c5a812d7d05a0158194560933def3fbdb9f9",
|
||||
"5b5d485b372bfffb22204bc162c9e182306395cb",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"layers.html": [
|
||||
"31f4b6bd51cfcca47666331857bd2bbdf84d2f5e",
|
||||
"49821d7661f92bc9cf22232d3fcb391c2cdc7295",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
]
|
||||
],
|
||||
"obtain_frame.html": [
|
||||
"74fda5bad43e8ea95552e65380e83952680e8469",
|
||||
"d9ff25729f9cdfd348e7c9914ce2dacd231e13a0",
|
||||
[
|
||||
null,
|
||||
{}
|
||||
|
|
|
@ -266,11 +266,14 @@ test_interfaces([
|
|||
"XMLHttpRequestUpload",
|
||||
"XMLSerializer",
|
||||
"XRFrame",
|
||||
"XRHitTestResult",
|
||||
"XRHitTestSource",
|
||||
"XRInputSource",
|
||||
"XRInputSourceArray",
|
||||
"XRInputSourceEvent",
|
||||
"XRPose",
|
||||
"XRReferenceSpace",
|
||||
"XRRay",
|
||||
"XRRenderState",
|
||||
"XRRigidTransform",
|
||||
"XRSession",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<script>
|
||||
async_test(function(t) {
|
||||
navigator.xr.test.simulateDeviceConnection({
|
||||
supportsImmersive: true,
|
||||
supportedModes: ["immersive-vr"],
|
||||
views: TEST_VIEWS,
|
||||
viewerOrigin: {position: [0.5, 0.1, 0.1], orientation: [1, 0, 0, 1] }
|
||||
}).then((m) => {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
let gl = canvas.getContext('webgl');
|
||||
promise_test(async function() {
|
||||
let mock = await navigator.xr.test.simulateDeviceConnection({
|
||||
supportsImmersive: true,
|
||||
supportedModes: ["immersive-vr"],
|
||||
views: TEST_VIEWS,
|
||||
viewerOrigin: {position: [0.5, 0.1, 0.1], orientation: [1, 0, 0, 1] }
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
let gl = canvas.getContext('webgl');
|
||||
promise_test(async function() {
|
||||
let mock = await navigator.xr.test.simulateDeviceConnection({
|
||||
supportsImmersive: true,
|
||||
supportedModes: ["immersive-vr"],
|
||||
views: TEST_VIEWS,
|
||||
viewerOrigin: {position: [0.5, 0.1, 0.1], orientation: [1, 0, 0, 1] }
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue