mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Auto merge of #25504 - Manishearth:features, r=asajeffrey
Support features in webxr Based on https://github.com/servo/webxr/pull/119 Todo: - [x] gate reference space creation on feature presence - [x] Fix the `features_deviceSupport` test to correctly use simulateUserActivation Fixes #24196, #24270 r? @jdm @asajeffrey
This commit is contained in:
commit
ee3fb92e53
26 changed files with 222 additions and 93 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -6729,7 +6729,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "webxr"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/servo/webxr#ed1ec1afadce730247401e60994b7f6ff226639d"
|
||||
source = "git+https://github.com/servo/webxr#33072cbbb67ff14b5938e886ee11a13f4cf2bafc"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"euclid",
|
||||
|
@ -6750,7 +6750,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "webxr-api"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/servo/webxr#ed1ec1afadce730247401e60994b7f6ff226639d"
|
||||
source = "git+https://github.com/servo/webxr#33072cbbb67ff14b5938e886ee11a13f4cf2bafc"
|
||||
dependencies = [
|
||||
"euclid",
|
||||
"ipc-channel",
|
||||
|
|
|
@ -205,13 +205,16 @@ impl FakeXRDeviceMethods for FakeXRDevice {
|
|||
None
|
||||
};
|
||||
|
||||
// XXXManishearth deal with profiles, supportedButtons, selection*
|
||||
let profiles = init.profiles.iter().cloned().map(String::from).collect();
|
||||
|
||||
// XXXManishearth deal with supportedButtons and selection*
|
||||
|
||||
let source = InputSource {
|
||||
handedness,
|
||||
target_ray_mode,
|
||||
id,
|
||||
supports_grip: true,
|
||||
profiles,
|
||||
};
|
||||
|
||||
let init = MockInputInit {
|
||||
|
|
|
@ -6,14 +6,20 @@ use crate::dom::bindings::codegen::Bindings::FakeXRDeviceBinding::FakeXRRigidTra
|
|||
use crate::dom::bindings::codegen::Bindings::FakeXRInputControllerBinding::{
|
||||
self, FakeXRInputControllerMethods,
|
||||
};
|
||||
use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{
|
||||
XRHandedness, XRTargetRayMode,
|
||||
};
|
||||
use crate::dom::bindings::error::Fallible;
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::fakexrdevice::get_origin;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use dom_struct::dom_struct;
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use webxr_api::{InputId, MockDeviceMsg, MockInputMsg, SelectEvent, SelectKind};
|
||||
use webxr_api::{
|
||||
Handedness, InputId, MockDeviceMsg, MockInputMsg, SelectEvent, SelectKind, TargetRayMode,
|
||||
};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct FakeXRInputController {
|
||||
|
@ -103,4 +109,30 @@ impl FakeXRInputControllerMethods for FakeXRInputController {
|
|||
SelectEvent::Select,
|
||||
))
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-sethandedness
|
||||
fn SetHandedness(&self, handedness: XRHandedness) {
|
||||
let h = match handedness {
|
||||
XRHandedness::None => Handedness::None,
|
||||
XRHandedness::Left => Handedness::Left,
|
||||
XRHandedness::Right => Handedness::Right,
|
||||
};
|
||||
let _ = self.send_message(MockInputMsg::SetHandedness(h));
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-settargetraymode
|
||||
fn SetTargetRayMode(&self, target_ray_mode: XRTargetRayMode) {
|
||||
let t = match target_ray_mode {
|
||||
XRTargetRayMode::Gaze => TargetRayMode::Gaze,
|
||||
XRTargetRayMode::Tracked_pointer => TargetRayMode::TrackedPointer,
|
||||
XRTargetRayMode::Screen => TargetRayMode::Screen,
|
||||
};
|
||||
let _ = self.send_message(MockInputMsg::SetTargetRayMode(t));
|
||||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr-test-api/#dom-fakexrinputcontroller-setprofiles
|
||||
fn SetProfiles(&self, profiles: Vec<DOMString>) {
|
||||
let t = profiles.into_iter().map(String::from).collect();
|
||||
let _ = self.send_message(MockInputMsg::SetProfiles(t));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
|
||||
[Exposed=Window, Pref="dom.webxr.test"]
|
||||
interface FakeXRInputController {
|
||||
// void setHandedness(XRHandedness handedness);
|
||||
// void setTargetRayMode(XRTargetRayMode targetRayMode);
|
||||
// void setProfiles(sequence<DOMString> profiles);
|
||||
void setHandedness(XRHandedness handedness);
|
||||
void setTargetRayMode(XRTargetRayMode targetRayMode);
|
||||
void setProfiles(sequence<DOMString> profiles);
|
||||
[Throws] void setGripOrigin(FakeXRRigidTransformInit gripOrigin, optional boolean emulatedPosition = false);
|
||||
void clearGripOrigin();
|
||||
[Throws] void setPointerOrigin(FakeXRRigidTransformInit pointerOrigin, optional boolean emulatedPosition = false);
|
||||
|
|
|
@ -25,8 +25,8 @@ enum XRSessionMode {
|
|||
};
|
||||
|
||||
dictionary XRSessionInit {
|
||||
sequence<DOMString> requiredFeatures;
|
||||
sequence<DOMString> optionalFeatures;
|
||||
sequence<any> requiredFeatures;
|
||||
sequence<any> optionalFeatures;
|
||||
};
|
||||
|
||||
partial interface XR {
|
||||
|
|
|
@ -23,4 +23,5 @@ interface XRInputSource {
|
|||
[SameObject] readonly attribute XRSpace targetRaySpace;
|
||||
[SameObject] readonly attribute XRSpace? gripSpace;
|
||||
// [SameObject] readonly attribute Gamepad? gamepad;
|
||||
/* [SameObject] */ readonly attribute /* FrozenArray<DOMString> */ any profiles;
|
||||
};
|
||||
|
|
|
@ -23,6 +23,9 @@ dictionary FakeXRDeviceInit {
|
|||
required boolean supportsImmersive;
|
||||
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;
|
||||
|
|
|
@ -8,11 +8,13 @@ use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods;
|
|||
use crate::dom::bindings::codegen::Bindings::XRBinding;
|
||||
use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionInit;
|
||||
use crate::dom::bindings::codegen::Bindings::XRBinding::{XRMethods, XRSessionMode};
|
||||
use crate::dom::bindings::conversions::{ConversionResult, FromJSValConvertible};
|
||||
use crate::dom::bindings::error::Error;
|
||||
use crate::dom::bindings::inheritance::Castable;
|
||||
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
|
||||
use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
|
||||
use crate::dom::bindings::trace::RootedTraceableBox;
|
||||
use crate::dom::event::Event;
|
||||
use crate::dom::eventtarget::EventTarget;
|
||||
use crate::dom::gamepad::Gamepad;
|
||||
|
@ -33,7 +35,7 @@ use std::cell::Cell;
|
|||
use std::rc::Rc;
|
||||
use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVREvent, WebVRMsg};
|
||||
use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState};
|
||||
use webxr_api::{Error as XRError, Frame, Session, SessionMode};
|
||||
use webxr_api::{Error as XRError, Frame, Session, SessionInit, SessionMode};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct XR {
|
||||
|
@ -154,13 +156,16 @@ impl XRMethods for XR {
|
|||
}
|
||||
|
||||
/// https://immersive-web.github.io/webxr/#dom-xr-requestsession
|
||||
#[allow(unsafe_code)]
|
||||
fn RequestSession(
|
||||
&self,
|
||||
mode: XRSessionMode,
|
||||
_: &XRSessionInit,
|
||||
init: RootedTraceableBox<XRSessionInit>,
|
||||
comp: InCompartment,
|
||||
) -> Rc<Promise> {
|
||||
let promise = Promise::new_in_current_compartment(&self.global(), comp);
|
||||
let global = self.global();
|
||||
let window = global.as_window();
|
||||
let promise = Promise::new_in_current_compartment(&global, comp);
|
||||
|
||||
if mode != XRSessionMode::Inline {
|
||||
if !ScriptThread::is_user_interacting() {
|
||||
|
@ -176,11 +181,52 @@ impl XRMethods for XR {
|
|||
self.set_pending();
|
||||
}
|
||||
|
||||
let promise = Promise::new_in_current_compartment(&self.global(), comp);
|
||||
let mut required_features = vec![];
|
||||
let mut optional_features = vec![];
|
||||
let cx = global.get_cx();
|
||||
|
||||
// We are supposed to include "viewer" and on immersive devices "local"
|
||||
// by default here, but this is handled directly in requestReferenceSpace()
|
||||
if let Some(ref r) = init.requiredFeatures {
|
||||
for feature in r {
|
||||
unsafe {
|
||||
if let Ok(ConversionResult::Success(s)) =
|
||||
String::from_jsval(*cx, feature.handle(), ())
|
||||
{
|
||||
required_features.push(s)
|
||||
} else {
|
||||
warn!("Unable to convert required feature to string");
|
||||
if mode != XRSessionMode::Inline {
|
||||
self.pending_immersive_session.set(false);
|
||||
}
|
||||
promise.reject_error(Error::NotSupported);
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ref o) = init.optionalFeatures {
|
||||
for feature in o {
|
||||
unsafe {
|
||||
if let Ok(ConversionResult::Success(s)) =
|
||||
String::from_jsval(*cx, feature.handle(), ())
|
||||
{
|
||||
optional_features.push(s)
|
||||
} else {
|
||||
warn!("Unable to convert optional feature to string");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let init = SessionInit {
|
||||
required_features,
|
||||
optional_features,
|
||||
};
|
||||
|
||||
let mut trusted = Some(TrustedPromise::new(promise.clone()));
|
||||
let this = Trusted::new(self);
|
||||
let global = self.global();
|
||||
let window = global.as_window();
|
||||
let (task_source, canceller) = window
|
||||
.task_manager()
|
||||
.dom_manipulation_task_source_with_canceller();
|
||||
|
@ -210,8 +256,7 @@ impl XRMethods for XR {
|
|||
);
|
||||
window
|
||||
.webxr_registry()
|
||||
.request_session(mode.into(), sender, frame_sender);
|
||||
|
||||
.request_session(mode.into(), init, sender, frame_sender);
|
||||
promise
|
||||
}
|
||||
|
||||
|
@ -232,7 +277,10 @@ impl XR {
|
|||
let session = match response {
|
||||
Ok(session) => session,
|
||||
Err(_) => {
|
||||
promise.reject_native(&());
|
||||
if mode != XRSessionMode::Inline {
|
||||
self.pending_immersive_session.set(false);
|
||||
}
|
||||
promise.reject_error(Error::NotSupported);
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* 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::compartments::enter_realm;
|
||||
use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding;
|
||||
use crate::dom::bindings::codegen::Bindings::XRInputSourceBinding::{
|
||||
XRHandedness, XRInputSourceMethods, XRTargetRayMode,
|
||||
|
@ -11,7 +12,11 @@ use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
|
|||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::xrsession::XRSession;
|
||||
use crate::dom::xrspace::XRSpace;
|
||||
use crate::script_runtime::JSContext;
|
||||
use dom_struct::dom_struct;
|
||||
use js::conversions::ToJSValConvertible;
|
||||
use js::jsapi::Heap;
|
||||
use js::jsval::{JSVal, UndefinedValue};
|
||||
use webxr_api::{Handedness, InputId, InputSource, TargetRayMode};
|
||||
|
||||
#[dom_struct]
|
||||
|
@ -24,6 +29,8 @@ pub struct XRInputSource {
|
|||
target_ray_space: MutNullableDom<XRSpace>,
|
||||
#[ignore_malloc_size_of = "Defined in rust-webxr"]
|
||||
grip_space: MutNullableDom<XRSpace>,
|
||||
#[ignore_malloc_size_of = "mozjs"]
|
||||
profiles: Heap<JSVal>,
|
||||
}
|
||||
|
||||
impl XRInputSource {
|
||||
|
@ -34,19 +41,30 @@ impl XRInputSource {
|
|||
info,
|
||||
target_ray_space: Default::default(),
|
||||
grip_space: Default::default(),
|
||||
profiles: Heap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
pub fn new(
|
||||
global: &GlobalScope,
|
||||
session: &XRSession,
|
||||
info: InputSource,
|
||||
) -> DomRoot<XRInputSource> {
|
||||
reflect_dom_object(
|
||||
let source = reflect_dom_object(
|
||||
Box::new(XRInputSource::new_inherited(session, info)),
|
||||
global,
|
||||
XRInputSourceBinding::Wrap,
|
||||
)
|
||||
);
|
||||
|
||||
let _ac = enter_realm(&*global);
|
||||
let cx = global.get_cx();
|
||||
unsafe {
|
||||
rooted!(in(*cx) let mut profiles = UndefinedValue());
|
||||
source.info.profiles.to_jsval(*cx, profiles.handle_mut());
|
||||
source.profiles.set(profiles.get());
|
||||
}
|
||||
source
|
||||
}
|
||||
|
||||
pub fn id(&self) -> InputId {
|
||||
|
@ -92,4 +110,8 @@ impl XRInputSourceMethods for XRInputSource {
|
|||
None
|
||||
}
|
||||
}
|
||||
// https://immersive-web.github.io/webxr/#dom-xrinputsource-profiles
|
||||
fn Profiles(&self, _cx: JSContext) -> JSVal {
|
||||
self.profiles.get()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ impl XRInputSourceArray {
|
|||
for info in sess.initial_inputs() {
|
||||
// XXXManishearth we should be able to listen for updates
|
||||
// to the input sources
|
||||
let input = XRInputSource::new(&global, &session, *info);
|
||||
let input = XRInputSource::new(&global, &session, info.clone());
|
||||
input_sources.push(Dom::from_ref(&input));
|
||||
}
|
||||
});
|
||||
|
@ -54,11 +54,11 @@ impl XRInputSourceArray {
|
|||
pub fn add_input_source(&self, session: &XRSession, info: InputSource) {
|
||||
let mut input_sources = self.input_sources.borrow_mut();
|
||||
let global = self.global();
|
||||
let input = XRInputSource::new(&global, &session, info);
|
||||
debug_assert!(
|
||||
input_sources.iter().find(|i| i.id() == info.id).is_none(),
|
||||
"Should never add a duplicate input id!"
|
||||
);
|
||||
let input = XRInputSource::new(&global, &session, info);
|
||||
input_sources.push(Dom::from_ref(&input));
|
||||
|
||||
let added = [input];
|
||||
|
@ -101,6 +101,37 @@ impl XRInputSourceArray {
|
|||
event.upcast::<Event>().fire(session.upcast());
|
||||
}
|
||||
|
||||
pub fn add_remove_input_source(&self, session: &XRSession, id: InputId, info: InputSource) {
|
||||
let mut input_sources = self.input_sources.borrow_mut();
|
||||
let global = self.global();
|
||||
let root;
|
||||
let removed = if let Some(i) = input_sources.iter().find(|i| i.id() == id) {
|
||||
root = [DomRoot::from_ref(&**i)];
|
||||
&root as &[_]
|
||||
} else {
|
||||
warn!("Could not find removed input source with id {:?}", id);
|
||||
&[]
|
||||
};
|
||||
input_sources.retain(|i| i.id() != id);
|
||||
let input = XRInputSource::new(&global, &session, info);
|
||||
input_sources.push(Dom::from_ref(&input));
|
||||
|
||||
let added = [input];
|
||||
|
||||
let event = XRInputSourcesChangeEvent::new(
|
||||
&global,
|
||||
atom!("inputsourceschange"),
|
||||
false,
|
||||
true,
|
||||
session,
|
||||
&added,
|
||||
removed,
|
||||
);
|
||||
// release the refcell guard
|
||||
drop(input_sources);
|
||||
event.upcast::<Event>().fire(session.upcast());
|
||||
}
|
||||
|
||||
pub fn find(&self, id: InputId) -> Option<DomRoot<XRInputSource>> {
|
||||
self.input_sources
|
||||
.borrow()
|
||||
|
|
|
@ -71,7 +71,7 @@ impl XRInputSourcesChangeEvent {
|
|||
changeevent.added.set(added_val.get());
|
||||
rooted!(in(*cx) let mut removed_val = UndefinedValue());
|
||||
removed.to_jsval(*cx, removed_val.handle_mut());
|
||||
changeevent.added.set(removed_val.get());
|
||||
changeevent.removed.set(removed_val.get());
|
||||
}
|
||||
|
||||
changeevent
|
||||
|
|
|
@ -295,6 +295,9 @@ impl XRSession {
|
|||
XREvent::RemoveInput(id) => {
|
||||
self.input_sources.remove_input_source(self, id);
|
||||
},
|
||||
XREvent::UpdateInput(id, source) => {
|
||||
self.input_sources.add_remove_input_source(self, id, source);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -556,10 +559,25 @@ impl XRSessionMethods for XRSession {
|
|||
p.reject_error(Error::NotSupported)
|
||||
},
|
||||
ty => {
|
||||
if ty != XRReferenceSpaceType::Viewer &&
|
||||
(!self.is_immersive() || ty != XRReferenceSpaceType::Local)
|
||||
{
|
||||
let s = ty.as_str();
|
||||
if self
|
||||
.session
|
||||
.borrow()
|
||||
.granted_features()
|
||||
.iter()
|
||||
.find(|f| &**f == s)
|
||||
.is_none()
|
||||
{
|
||||
p.reject_error(Error::NotSupported);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
p.resolve_native(&XRReferenceSpace::new(&self.global(), self, ty));
|
||||
},
|
||||
}
|
||||
|
||||
p
|
||||
}
|
||||
|
||||
|
|
|
@ -69,8 +69,10 @@ impl XRTest {
|
|||
|
||||
impl XRTestMethods for XRTest {
|
||||
/// https://github.com/immersive-web/webxr-test-api/blob/master/explainer.md
|
||||
#[allow(unsafe_code)]
|
||||
fn SimulateDeviceConnection(&self, init: &FakeXRDeviceInit) -> Rc<Promise> {
|
||||
let p = Promise::new(&self.global());
|
||||
let global = self.global();
|
||||
let p = Promise::new(&global);
|
||||
|
||||
let origin = if let Some(ref o) = init.viewerOrigin {
|
||||
match get_origin(&o) {
|
||||
|
@ -104,12 +106,19 @@ impl XRTestMethods for XRTest {
|
|||
},
|
||||
};
|
||||
|
||||
let supported_features = if let Some(ref s) = init.supportedFeatures {
|
||||
s.iter().cloned().map(String::from).collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let init = MockDeviceInit {
|
||||
viewer_origin: origin,
|
||||
views,
|
||||
supports_immersive: init.supportsImmersive,
|
||||
supports_unbounded: init.supportsUnbounded,
|
||||
floor_origin,
|
||||
supported_features,
|
||||
};
|
||||
|
||||
let global = self.global();
|
||||
|
|
|
@ -735150,7 +735150,7 @@
|
|||
"support"
|
||||
],
|
||||
"webxr/resources/webxr_util.js": [
|
||||
"5f66dc9573d37630d588265f20e5b57a8175766f",
|
||||
"dbe1585929f50089bb3e26a981b9c12b30e9fa1f",
|
||||
"support"
|
||||
],
|
||||
"webxr/webGLCanvasContext_create_xrcompatible.https.html": [
|
||||
|
@ -735302,7 +735302,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"webxr/xrSession_features_deviceSupport.https.html": [
|
||||
"d8858bd4be689bf8e4f3a3795e13fad2a2057019",
|
||||
"1ee63bae047bd196233f5e4253baec94b6a576a9",
|
||||
"testharness"
|
||||
],
|
||||
"webxr/xrSession_input_events_end.https.html": [
|
||||
|
@ -735342,7 +735342,7 @@
|
|||
"testharness"
|
||||
],
|
||||
"webxr/xrSession_viewer_availability.https.html": [
|
||||
"c509e5f1a2a992b9329fd55e591e37fcea2b6e91",
|
||||
"f28a07ad8bd0f8529b791048840bf60495186a7e",
|
||||
"testharness"
|
||||
],
|
||||
"webxr/xrSession_viewer_referenceSpace.https.html": [
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[events_input_source_recreation.https.html]
|
||||
expected: ERROR
|
||||
[Input sources are re-created when handedness or target ray mode changes]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[getInputPose_handedness.https.html]
|
||||
expected: ERROR
|
||||
[XRInputSources properly communicate their handedness]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -95,9 +95,6 @@
|
|||
[XRReferenceSpaceEvent interface: existence and properties of interface prototype object's "constructor" property]
|
||||
expected: FAIL
|
||||
|
||||
[XRInputSource interface: attribute profiles]
|
||||
expected: FAIL
|
||||
|
||||
[XR interface: operation requestSession(XRSessionMode, XRSessionInit)]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[xrDevice_requestSession_immersive_unsupported.https.html]
|
||||
[Requesting an immersive session when unsupported rejects]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[xrInputSource_profiles.https.html]
|
||||
[WebXR InputSource's profiles list can be set]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[xrSession_features_deviceSupport.https.html]
|
||||
[Immersive XRSession requests with no supported device should reject]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
[xrSession_input_events_end.https.html]
|
||||
expected: TIMEOUT
|
||||
[Calling end during an input callback stops processing at the right time]
|
||||
expected: TIMEOUT
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
[xrSession_requestReferenceSpace_features.https.html]
|
||||
[Immersive session rejects local-floor space if not requested]
|
||||
expected: FAIL
|
||||
|
||||
[Non-immersive session rejects local space if not requested]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[xrSession_sameObject.https.html]
|
||||
expected: ERROR
|
||||
[XRSession attributes meet [SameObject\] requirement]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -101,6 +101,18 @@ function xr_session_promise_test(
|
|||
properties);
|
||||
}
|
||||
|
||||
|
||||
// This function wraps the provided function in a
|
||||
// simulateUserActivation() call, and resolves the promise with the
|
||||
// result of func(), or an error if one is thrown
|
||||
function promise_simulate_user_activation(func) {
|
||||
return new Promise((resolve, reject) => {
|
||||
navigator.xr.test.simulateUserActivation(() => {
|
||||
try { let a = func(); resolve(a); } catch(e) { reject(e); }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// This functions calls a callback with each API object as specified
|
||||
// by https://immersive-web.github.io/webxr/spec/latest/, allowing
|
||||
// checks to be made on all ojects.
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"local-floor"]
|
||||
};
|
||||
|
||||
|
||||
xr_promise_test(testName,
|
||||
(t) => {
|
||||
function session_resolves(sessionMode, sessionInit) {
|
||||
|
@ -31,34 +32,28 @@
|
|||
}
|
||||
|
||||
return navigator.xr.test.simulateDeviceConnection(fakeDeviceInitParams)
|
||||
.then((controller) => new Promise((resolve, reject) => {
|
||||
navigator.xr.test.simulateUserActivation(() => {
|
||||
.then((controller) =>
|
||||
promise_simulate_user_activation(() => {
|
||||
// Attempting to request required features that aren't supported by
|
||||
// the device should reject.
|
||||
promise_rejects(t, "NotSupportedError",
|
||||
|
||||
return promise_rejects(t, "NotSupportedError",
|
||||
navigator.xr.requestSession("immersive-vr", {
|
||||
requiredFeatures: ['bounded-floor']
|
||||
}))
|
||||
.then(() => {
|
||||
}).then(() => promise_simulate_user_activation(() => {
|
||||
// Attempting to request with an unsupported feature as optional
|
||||
// should succeed
|
||||
return session_resolves("immersive-vr", {
|
||||
optionalFeatures: ['bounded-floor']
|
||||
});
|
||||
})).then(() => promise_simulate_user_activation(() => {
|
||||
// Attempting to request with supported features only should succeed.
|
||||
return session_resolves("immersive-vr", {
|
||||
requiredFeatures: ['local', 'local-floor']
|
||||
})
|
||||
.then(() => {
|
||||
// Attempting to request with supported features only should succeed.
|
||||
return session_resolves("immersive-vr", {
|
||||
requiredFeatures: ['local', 'local-floor']
|
||||
})
|
||||
.then(() => {
|
||||
resolve();
|
||||
}).catch((err) => {
|
||||
reject(err);
|
||||
});;
|
||||
});
|
||||
});
|
||||
}));
|
||||
}))
|
||||
);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
@ -24,14 +24,6 @@
|
|||
.then(session => session.end()));
|
||||
}
|
||||
|
||||
function simulate_user_activation(func) {
|
||||
return new Promise((resolve, reject) => {
|
||||
navigator.xr.test.simulateUserActivation(() => {
|
||||
try { resolve(func()); } catch(e) { reject(e); }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return session_resolves('inline', {
|
||||
// RequestSession with 'viewer' as a required featre should succeed, even
|
||||
// without user activation.
|
||||
|
@ -62,14 +54,14 @@
|
|||
optionalFeatures: ['local']
|
||||
});
|
||||
})
|
||||
.then(() => simulate_user_activation(() => {
|
||||
.then(() => promise_simulate_user_activation(() => {
|
||||
// RequestSession with unsupported optional features should succeed.
|
||||
return session_resolves('inline', {
|
||||
requiredFeatures: ['viewer'],
|
||||
optionalFeatures: ['local']
|
||||
})
|
||||
}))
|
||||
.then(() => simulate_user_activation(() => {
|
||||
.then(() => promise_simulate_user_activation(() => {
|
||||
// Request with unsupported required features should reject.
|
||||
return session_rejects("NotSupportedError", 'inline', {
|
||||
requiredFeatures: ['local']
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue