blob: 2210764a51908efefd5a4cd32bf05cb538243b27 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/xr/XRDevice.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "core/dom/DOMException.h"
#include "core/frame/Frame.h"
#include "core/frame/LocalFrame.h"
#include "modules/EventTargetModules.h"
#include "modules/xr/XR.h"
#include "modules/xr/XRFrameProvider.h"
#include "modules/xr/XRSession.h"
namespace blink {
namespace {
const char kActiveExclusiveSession[] =
"XRDevice already has an active, exclusive session";
const char kExclusiveNotSupported[] =
"XRDevice does not support the creation of exclusive sessions.";
const char kNoOutputContext[] =
"Non-exclusive sessions must be created with an outputContext.";
const char kRequestNotInUserGesture[] =
"Exclusive sessions can only be requested during a user gesture.";
} // namespace
XRDevice::XRDevice(
XR* xr,
device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider,
device::mojom::blink::VRDisplayHostPtr display,
device::mojom::blink::VRDisplayClientRequest client_request,
device::mojom::blink::VRDisplayInfoPtr display_info)
: xr_(xr),
magic_window_provider_(std::move(magic_window_provider)),
display_(std::move(display)),
display_client_binding_(this, std::move(client_request)) {
SetXRDisplayInfo(std::move(display_info));
}
ExecutionContext* XRDevice::GetExecutionContext() const {
return xr_->GetExecutionContext();
}
const AtomicString& XRDevice::InterfaceName() const {
return EventTargetNames::XRDevice;
}
const char* XRDevice::checkSessionSupport(
const XRSessionCreationOptions& options) const {
if (options.exclusive()) {
// Validation for exclusive sessions.
if (!supports_exclusive_) {
return kExclusiveNotSupported;
}
} else {
// Validation for non-exclusive sessions.
if (!options.hasOutputContext()) {
return kNoOutputContext;
}
}
return nullptr;
}
ScriptPromise XRDevice::supportsSession(
ScriptState* script_state,
const XRSessionCreationOptions& options) const {
// Check to see if the device is capable of supporting the requested session
// options. Note that reporting support here does not guarantee that creating
// a session with those options will succeed, as other external and
// time-sensitve factors (focus state, existance of another exclusive session,
// etc.) may prevent the creation of a session as well.
const char* reject_reason = checkSessionSupport(options);
if (reject_reason) {
return ScriptPromise::RejectWithDOMException(
script_state, DOMException::Create(kNotSupportedError, reject_reason));
}
// If the above checks pass, resolve without a value. Future API iterations
// may specify a value to be returned here.
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
resolver->Resolve();
return promise;
}
ScriptPromise XRDevice::requestSession(
ScriptState* script_state,
const XRSessionCreationOptions& options) {
// Check first to see if the device is capable of supporting the requested
// options.
const char* reject_reason = checkSessionSupport(options);
if (reject_reason) {
return ScriptPromise::RejectWithDOMException(
script_state, DOMException::Create(kNotSupportedError, reject_reason));
}
// Check if the current page state prevents the requested session from being
// created.
if (options.exclusive()) {
if (frameProvider()->exclusive_session()) {
return ScriptPromise::RejectWithDOMException(
script_state,
DOMException::Create(kInvalidStateError, kActiveExclusiveSession));
}
Document* doc = ToDocumentOrNull(ExecutionContext::From(script_state));
if (!Frame::HasTransientUserActivation(doc ? doc->GetFrame() : nullptr)) {
return ScriptPromise::RejectWithDOMException(
script_state,
DOMException::Create(kInvalidStateError, kRequestNotInUserGesture));
}
}
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
XRPresentationContext* output_context = nullptr;
if (options.hasOutputContext()) {
output_context = options.outputContext();
}
XRSession* session = new XRSession(this, options.exclusive(), output_context);
if (options.exclusive()) {
frameProvider()->BeginExclusiveSession(session, resolver);
} else {
resolver->Resolve(session);
}
return promise;
}
// TODO: Forward these calls on to the sessions once they've been implemented.
void XRDevice::OnChanged(device::mojom::blink::VRDisplayInfoPtr display_info) {
SetXRDisplayInfo(std::move(display_info));
}
void XRDevice::OnExitPresent() {}
void XRDevice::OnBlur() {}
void XRDevice::OnFocus() {}
void XRDevice::OnActivate(device::mojom::blink::VRDisplayEventReason,
OnActivateCallback on_handled) {}
void XRDevice::OnDeactivate(device::mojom::blink::VRDisplayEventReason) {}
XRFrameProvider* XRDevice::frameProvider() {
if (!frame_provider_)
frame_provider_ = new XRFrameProvider(this);
return frame_provider_;
}
void XRDevice::Dispose() {
display_client_binding_.Close();
if (frame_provider_)
frame_provider_->Dispose();
}
void XRDevice::SetXRDisplayInfo(
device::mojom::blink::VRDisplayInfoPtr display_info) {
display_info_ = std::move(display_info);
is_external_ = display_info_->capabilities->hasExternalDisplay;
supports_exclusive_ = (display_info_->capabilities->canPresent);
}
void XRDevice::Trace(blink::Visitor* visitor) {
visitor->Trace(xr_);
visitor->Trace(frame_provider_);
EventTargetWithInlineData::Trace(visitor);
}
} // namespace blink