Commit 2bad2fa2 authored by David Dorwin's avatar David Dorwin Committed by Commit Bot

Only expose "immersive-ar" when AR runtime flag(s) are enabled

Bug: 956149
Change-Id: I3ceb266f8975dc094dce48d2988d16b16a993127
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1611655Reviewed-by: default avatarBrandon Jones <bajones@chromium.org>
Commit-Queue: David Dorwin <ddorwin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#660660}
parent e275bddf
...@@ -21,8 +21,9 @@ ...@@ -21,8 +21,9 @@
#include "third_party/blink/renderer/modules/xr/xr_frame_provider.h" #include "third_party/blink/renderer/modules/xr/xr_frame_provider.h"
#include "third_party/blink/renderer/modules/xr/xr_presentation_context.h" #include "third_party/blink/renderer/modules/xr/xr_presentation_context.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h" #include "third_party/blink/renderer/modules/xr/xr_session.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink { namespace blink {
namespace { namespace {
...@@ -44,6 +45,10 @@ const char kSessionNotSupported[] = ...@@ -44,6 +45,10 @@ const char kSessionNotSupported[] =
const char kNoDevicesMessage[] = "No XR hardware found."; const char kNoDevicesMessage[] = "No XR hardware found.";
const char kImmersiveArModeNotValid[] =
"Failed to execute '%s' on 'XR': The provided value 'immersive-ar' is not "
"a valid enum value of type XRSessionMode.";
// Helper method to convert session mode into Mojo options. // Helper method to convert session mode into Mojo options.
device::mojom::blink::XRSessionOptionsPtr convertModeToMojo( device::mojom::blink::XRSessionOptionsPtr convertModeToMojo(
XRSession::SessionMode mode) { XRSession::SessionMode mode) {
...@@ -71,6 +76,11 @@ XRSession::SessionMode stringToSessionMode(const String& mode_string) { ...@@ -71,6 +76,11 @@ XRSession::SessionMode stringToSessionMode(const String& mode_string) {
return XRSession::kModeInline; return XRSession::kModeInline;
} }
bool AreArRuntimeFeaturesEnabled(const FeatureContext* context) {
return RuntimeEnabledFeatures::WebXRHitTestEnabled(context) ||
RuntimeEnabledFeatures::WebXRPlaneDetectionEnabled(context);
}
} // namespace } // namespace
XR::PendingSessionQuery::PendingSessionQuery( XR::PendingSessionQuery::PendingSessionQuery(
...@@ -152,9 +162,19 @@ ScriptPromise XR::supportsSession(ScriptState* script_state, ...@@ -152,9 +162,19 @@ ScriptPromise XR::supportsSession(ScriptState* script_state,
kNavigatorDetachedError)); kNavigatorDetachedError));
} }
if (!frame->GetDocument()->IsFeatureEnabled( Document* doc = frame->GetDocument();
mojom::FeaturePolicyFeature::kWebVr, XRSession::SessionMode session_mode = stringToSessionMode(mode);
ReportOptions::kReportOnFailure)) {
if (session_mode == XRSession::kModeImmersiveAR &&
!AreArRuntimeFeaturesEnabled(doc)) {
return ScriptPromise::Reject(
script_state, V8ThrowException::CreateTypeError(
script_state->GetIsolate(),
String::Format(kImmersiveArModeNotValid, __func__)));
}
if (!doc->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr,
ReportOptions::kReportOnFailure)) {
// Only allow the call to be made if the appropriate feature policy is in // Only allow the call to be made if the appropriate feature policy is in
// place. // place.
return ScriptPromise::RejectWithDOMException( return ScriptPromise::RejectWithDOMException(
...@@ -165,7 +185,6 @@ ScriptPromise XR::supportsSession(ScriptState* script_state, ...@@ -165,7 +185,6 @@ ScriptPromise XR::supportsSession(ScriptState* script_state,
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise(); ScriptPromise promise = resolver->Promise();
XRSession::SessionMode session_mode = stringToSessionMode(mode);
if (session_mode == XRSession::kModeInline) { if (session_mode == XRSession::kModeInline) {
// `inline` sessions are always supported if not blocked by feature policy. // `inline` sessions are always supported if not blocked by feature policy.
resolver->Resolve(); resolver->Resolve();
...@@ -218,6 +237,15 @@ ScriptPromise XR::requestSession(ScriptState* script_state, ...@@ -218,6 +237,15 @@ ScriptPromise XR::requestSession(ScriptState* script_state,
Document* doc = frame->GetDocument(); Document* doc = frame->GetDocument();
XRSession::SessionMode session_mode = stringToSessionMode(mode); XRSession::SessionMode session_mode = stringToSessionMode(mode);
if (session_mode == XRSession::kModeImmersiveAR &&
!AreArRuntimeFeaturesEnabled(doc)) {
return ScriptPromise::Reject(
script_state, V8ThrowException::CreateTypeError(
script_state->GetIsolate(),
String::Format(kImmersiveArModeNotValid, __func__)));
}
bool is_immersive = session_mode == XRSession::kModeImmersiveVR || bool is_immersive = session_mode == XRSession::kModeImmersiveVR ||
session_mode == XRSession::kModeImmersiveAR; session_mode == XRSession::kModeImmersiveAR;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "third_party/blink/renderer/modules/xr/xr_world_information.h" #include "third_party/blink/renderer/modules/xr/xr_world_information.h"
#include "third_party/blink/renderer/modules/xr/xr_world_tracking_state.h" #include "third_party/blink/renderer/modules/xr/xr_world_tracking_state.h"
#include "third_party/blink/renderer/modules/xr/xr_world_tracking_state_init.h" #include "third_party/blink/renderer/modules/xr/xr_world_tracking_state_init.h"
#include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h" #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
namespace blink { namespace blink {
......
...@@ -3,10 +3,11 @@ ...@@ -3,10 +3,11 @@
// found in the LICENSE file. // found in the LICENSE file.
// https://immersive-web.github.io/webxr/#xrsession-interface // https://immersive-web.github.io/webxr/#xrsession-interface
enum XRSessionMode { enum XRSessionMode {
"inline", "inline",
"immersive-vr", "immersive-vr",
"immersive-ar", /* [RuntimeEnabled=WebXRHitTest OR RuntimeEnabled=WebXRPlaneDetection] */ "immersive-ar",
}; };
enum XREnvironmentBlendMode { enum XREnvironmentBlendMode {
...@@ -44,10 +45,8 @@ enum XREnvironmentBlendMode { ...@@ -44,10 +45,8 @@ enum XREnvironmentBlendMode {
[RuntimeEnabled=WebXRHitTest, CallWith=ScriptState] Promise<FrozenArray<XRHitResult>> requestHitTest(XRRay ray, XRSpace space); [RuntimeEnabled=WebXRHitTest, CallWith=ScriptState] Promise<FrozenArray<XRHitResult>> requestHitTest(XRRay ray, XRSpace space);
[RuntimeEnabled=WebXRPlaneDetection] readonly attribute XRWorldTrackingState worldTrackingState;
// Configures a session with real-world understanding capabilities.
// More details can be found here:
// https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md // https://github.com/immersive-web/real-world-geometry/blob/master/plane-detection-explainer.md
[RuntimeEnabled=WebXRPlaneDetection] readonly attribute XRWorldTrackingState worldTrackingState;
[RuntimeEnabled=WebXRPlaneDetection, RaisesException] void updateWorldTrackingState(optional XRWorldTrackingStateInit state); [RuntimeEnabled=WebXRPlaneDetection, RaisesException] void updateWorldTrackingState(optional XRWorldTrackingStateInit state);
[CallWith=ScriptState] Promise<void> end(); [CallWith=ScriptState] Promise<void> end();
......
...@@ -87,4 +87,59 @@ test(t => { ...@@ -87,4 +87,59 @@ test(t => {
OriginTrialsHelper.check_interfaces_missing_unless_runtime_flag( OriginTrialsHelper.check_interfaces_missing_unless_runtime_flag(
this, planes_interfaces, 'webXRPlaneDetectionEnabled'); this, planes_interfaces, 'webXRPlaneDetectionEnabled');
}, "Plane interfaces are not available with a WebXR token."); }, "Plane interfaces are not available with a WebXR token.");
// Ensure that AR sessions are not exposed as part of the WebXR origin trial.
// The webXREnabled check is effectively checking whether experimental features
// are enabled. This works as long as at least one AR feature is experimental.
// TODO(https://crbug.com/962685): Make the supportsSession checks first after
// this issue is fixed.
promise_test(t => {
let promise = navigator.xr.requestSession('immersive-ar');
if (OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) {
return promise_rejects(t, "SecurityError", promise);
} else {
return promise_rejects(t, new TypeError(), promise);
}
}, "immersive-ar is not recognized by requestSession() with a WebXR token.");
promise_test(t => {
let promise = navigator.xr.supportsSession('immersive-ar');
if (OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) {
return promise_rejects(t, "NotSupportedError", promise);
} else {
return promise_rejects(t, new TypeError(), promise);
}
}, "immersive-ar is not recognized by supportsSession() with a WebXR token.");
// Verify the rejection reason matches that for other invalid enum values.
// It only makes sense to run these when the failure occurs.
if (!OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) {
promise_test(t => {
return navigator.xr.supportsSession('invalid').then(function() {
assert_unreached("Promise should be rejected.")
}).catch(function(invalidReason) {
return navigator.xr.supportsSession('immersive-ar').then(function() {
assert_unreached("Promise should be rejected.")
}).catch(function(arReason) {
// Replace the enum value in the expected message. That is the only
// thing that should be different.
invalidReason.message = invalidReason.message.replace('invalid', 'immersive-ar');
assert_object_equals(invalidReason, arReason);
});
});
}, "supportsSession('immersive-ar') result matches result for other invalid values.");
promise_test(t => {
return navigator.xr.requestSession('invalid').then(function() {
assert_unreached("Promise should be rejected.")
}).catch(function(invalidReason) {
return navigator.xr.requestSession('immersive-ar').then(function() {
assert_unreached("Promise should be rejected.")
}).catch(function(arReason) {
// Replace the enum value in the expected message. That is the only
// thing that should be different.
invalidReason.message = invalidReason.message.replace('invalid', 'immersive-ar');
assert_object_equals(invalidReason, arReason);
});
});
}, "requestSession('immersive-ar') result matches result for other invalid values.");
}
</script> </script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment