blob: cb7d7da89baa02af49cddd0409e800c17fee1ade [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 "third_party/blink/renderer/modules/xr/xr_frame.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/modules/xr/xr_hit_test_source.h"
#include "third_party/blink/renderer/modules/xr/xr_input_source.h"
#include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
#include "third_party/blink/renderer/modules/xr/xr_session.h"
#include "third_party/blink/renderer/modules/xr/xr_transient_input_hit_test_source.h"
#include "third_party/blink/renderer/modules/xr/xr_view.h"
#include "third_party/blink/renderer/modules/xr/xr_viewer_pose.h"
#include "third_party/blink/renderer/modules/xr/xr_world_information.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
namespace {
const char kInactiveFrame[] =
"XRFrame access outside the callback that produced it is invalid.";
const char kNonAnimationFrame[] =
"getViewerPose can only be called on XRFrame objects passed to "
"XRSession.requestAnimationFrame callbacks.";
const char kSessionMismatch[] = "XRSpace and XRFrame sessions do not match.";
const char kCannotReportPoses[] =
"Poses cannot be given out for the current state.";
const char kHitTestSourceUnavailable[] =
"Unable to obtain hit test results for specified hit test source. Ensure "
"that it was not already canceled.";
} // namespace
XRFrame::XRFrame(XRSession* session, XRWorldInformation* world_information)
: world_information_(world_information), session_(session) {}
XRViewerPose* XRFrame::getViewerPose(XRReferenceSpace* reference_space,
ExceptionState& exception_state) const {
if (!is_active_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kInactiveFrame);
return nullptr;
}
if (!is_animation_frame_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kNonAnimationFrame);
return nullptr;
}
if (!reference_space) {
return nullptr;
}
// Must use a reference space created from the same session.
if (reference_space->session() != session_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kSessionMismatch);
return nullptr;
}
if (!session_->CanReportPoses()) {
exception_state.ThrowSecurityError(kCannotReportPoses);
return nullptr;
}
session_->LogGetPose();
std::unique_ptr<TransformationMatrix> offset_space_from_viewer =
reference_space->OffsetFromViewer();
// Can only update an XRViewerPose's views with an invertible matrix.
if (!(offset_space_from_viewer && offset_space_from_viewer->IsInvertible())) {
return nullptr;
}
return MakeGarbageCollected<XRViewerPose>(session(),
*offset_space_from_viewer);
}
XRAnchorSet* XRFrame::trackedAnchors() const {
return session_->trackedAnchors();
}
// Return an XRPose that has a transform of basespace_from_space, while
// accounting for the base pose matrix of this frame. If computing a transform
// isn't possible, return nullptr.
XRPose* XRFrame::getPose(XRSpace* space,
XRSpace* basespace,
ExceptionState& exception_state) {
if (!is_active_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kInactiveFrame);
return nullptr;
}
if (!space || !basespace) {
DVLOG(2) << __func__ << " : space or basespace is null, space =" << space
<< ", basespace = " << basespace;
return nullptr;
}
if (space->session() != session_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kSessionMismatch);
return nullptr;
}
if (basespace->session() != session_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kSessionMismatch);
return nullptr;
}
if (!session_->CanReportPoses()) {
exception_state.ThrowSecurityError(kCannotReportPoses);
return nullptr;
}
return space->getPose(basespace);
}
void XRFrame::Deactivate() {
is_active_ = false;
is_animation_frame_ = false;
}
HeapVector<Member<XRHitTestResult>> XRFrame::getHitTestResults(
XRHitTestSource* hit_test_source,
ExceptionState& exception_state) {
if (!hit_test_source ||
!session_->ValidateHitTestSourceExists(hit_test_source)) {
// This should only happen when hit test source was already canceled.
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kHitTestSourceUnavailable);
return {};
}
return hit_test_source->Results();
}
HeapVector<Member<XRTransientInputHitTestResult>>
XRFrame::getHitTestResultsForTransientInput(
XRTransientInputHitTestSource* hit_test_source,
ExceptionState& exception_state) {
if (!hit_test_source ||
!session_->ValidateHitTestSourceExists(hit_test_source)) {
// This should only happen when hit test source was already canceled.
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
kHitTestSourceUnavailable);
return {};
}
return hit_test_source->Results();
}
void XRFrame::Trace(blink::Visitor* visitor) {
visitor->Trace(session_);
visitor->Trace(world_information_);
ScriptWrappable::Trace(visitor);
}
} // namespace blink