Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/dom/vr/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 27 kB image not shown  

Quelle  VRDisplay.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 http://mozilla.org/MPL/2.0/. */


#include "nsWrapperCache.h"

#include "mozilla/dom/Element.h"
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/UserActivation.h"
#include "mozilla/dom/VRDisplay.h"
#include "mozilla/dom/VRDisplayBinding.h"
#include "mozilla/HoldDropJSObjects.h"
#include "mozilla/Base64.h"
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "Navigator.h"
#include "gfxUtils.h"
#include "gfxVR.h"
#include "VRDisplayClient.h"
#include "VRManagerChild.h"
#include "VRDisplayPresentation.h"
#include "nsIObserverService.h"
#include "nsISupportsPrimitives.h"
#include "nsGlobalWindowInner.h"

using namespace mozilla::gfx;

namespace mozilla::dom {

VRFieldOfView::VRFieldOfView(nsISupports* aParent, double aUpDegrees,
                             double aRightDegrees, double aDownDegrees,
                             double aLeftDegrees)
    : mParent(aParent),
      mUpDegrees(aUpDegrees),
      mRightDegrees(aRightDegrees),
      mDownDegrees(aDownDegrees),
      mLeftDegrees(aLeftDegrees) {}

VRFieldOfView::VRFieldOfView(nsISupports* aParent,
                             const gfx::VRFieldOfView& aSrc)
    : mParent(aParent),
      mUpDegrees(aSrc.upDegrees),
      mRightDegrees(aSrc.rightDegrees),
      mDownDegrees(aSrc.downDegrees),
      mLeftDegrees(aSrc.leftDegrees) {}

bool VRDisplayCapabilities::HasPosition() const {
  return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_Position) ||
         bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_PositionEmulated);
}

bool VRDisplayCapabilities::HasOrientation() const {
  return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_Orientation);
}

bool VRDisplayCapabilities::HasExternalDisplay() const {
  return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_External);
}

bool VRDisplayCapabilities::CanPresent() const {
  return bool(mFlags & gfx::VRDisplayCapabilityFlags::Cap_Present);
}

uint32_t VRDisplayCapabilities::MaxLayers() const {
  return CanPresent() ? 1 : 0;
}

void VRDisplay::UpdateDisplayClient(
    already_AddRefed<gfx::VRDisplayClient> aClient) {
  mClient = std::move(aClient);
}

/*static*/
bool VRDisplay::RefreshVRDisplays(uint64_t aWindowId) {
  gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
  return vm && vm->RefreshVRDisplaysWithCallback(aWindowId);
}

/*static*/
void VRDisplay::UpdateVRDisplays(nsTArray<RefPtr<VRDisplay>>& aDisplays,
                                 nsPIDOMWindowInner* aWindow) {
  nsTArray<RefPtr<VRDisplay>> displays;

  gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
  nsTArray<RefPtr<gfx::VRDisplayClient>> updatedDisplays;
  if (vm) {
    vm->GetVRDisplays(updatedDisplays);
    for (size_t i = 0; i < updatedDisplays.Length(); i++) {
      RefPtr<gfx::VRDisplayClient> display = updatedDisplays[i];
      bool isNewDisplay = true;
      for (size_t j = 0; j < aDisplays.Length(); j++) {
        if (aDisplays[j]->GetClient()->GetDisplayInfo().GetDisplayID() ==
            display->GetDisplayInfo().GetDisplayID()) {
          displays.AppendElement(aDisplays[j]);
          isNewDisplay = false;
        } else {
          RefPtr<gfx::VRDisplayClient> ref = display;
          aDisplays[j]->UpdateDisplayClient(do_AddRef(display));
          displays.AppendElement(aDisplays[j]);
          isNewDisplay = false;
        }
      }

      if (isNewDisplay) {
        displays.AppendElement(new VRDisplay(aWindow, display));
      }
    }
  }

  aDisplays = std::move(displays);
}

NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VRFieldOfView, mParent)

JSObject* VRFieldOfView::WrapObject(JSContext* aCx,
                                    JS::Handle<JSObject*> aGivenProto) {
  return VRFieldOfView_Binding::Wrap(aCx, this, aGivenProto);
}

NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_WITH_JS_MEMBERS(VREyeParameters,
                                                      (mParent, mFOV),
                                                      (mOffset))

VREyeParameters::VREyeParameters(nsISupports* aParent,
                                 const gfx::Point3D& aEyeTranslation,
                                 const gfx::VRFieldOfView& aFOV,
                                 const gfx::IntSize& aRenderSize)
    : mParent(aParent),
      mEyeTranslation(aEyeTranslation),
      mRenderSize(aRenderSize) {
  mFOV = new VRFieldOfView(aParent, aFOV);
  mozilla::HoldJSObjects(this);
}

VREyeParameters::~VREyeParameters() { mozilla::DropJSObjects(this); }

VRFieldOfView* VREyeParameters::FieldOfView() { return mFOV; }

void VREyeParameters::GetOffset(JSContext* aCx,
                                JS::MutableHandle<JSObject*> aRetval,
                                ErrorResult& aRv) {
  if (!mOffset) {
    // Lazily create the Float32Array
    mOffset =
        dom::Float32Array::Create(aCx, this, mEyeTranslation.components, aRv);
    if (aRv.Failed()) {
      return;
    }
  }
  aRetval.set(mOffset);
}

JSObject* VREyeParameters::WrapObject(JSContext* aCx,
                                      JS::Handle<JSObject*> aGivenProto) {
  return VREyeParameters_Binding::Wrap(aCx, this, aGivenProto);
}

VRStageParameters::VRStageParameters(
    nsISupports* aParent, const gfx::Matrix4x4& aSittingToStandingTransform,
    const gfx::Size& aSize)
    : mParent(aParent),
      mSittingToStandingTransform(aSittingToStandingTransform),
      mSittingToStandingTransformArray(nullptr),
      mSize(aSize) {
  mozilla::HoldJSObjects(this);
}

VRStageParameters::~VRStageParameters() { mozilla::DropJSObjects(this); }

JSObject* VRStageParameters::WrapObject(JSContext* aCx,
                                        JS::Handle<JSObject*> aGivenProto) {
  return VRStageParameters_Binding::Wrap(aCx, this, aGivenProto);
}

NS_IMPL_CYCLE_COLLECTION_CLASS(VRStageParameters)

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(VRStageParameters)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  tmp->mSittingToStandingTransformArray = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(VRStageParameters)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(VRStageParameters)
  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(
      mSittingToStandingTransformArray)
NS_IMPL_CYCLE_COLLECTION_TRACE_END

void VRStageParameters::GetSittingToStandingTransform(
    JSContext* aCx, JS::MutableHandle<JSObject*> aRetval, ErrorResult& aRv) {
  if (!mSittingToStandingTransformArray) {
    // Lazily create the Float32Array
    mSittingToStandingTransformArray = dom::Float32Array::Create(
        aCx, this, mSittingToStandingTransform.components, aRv);
    if (aRv.Failed()) {
      return;
    }
  }
  aRetval.set(mSittingToStandingTransformArray);
}

NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VRDisplayCapabilities, mParent)

JSObject* VRDisplayCapabilities::WrapObject(JSContext* aCx,
                                            JS::Handle<JSObject*> aGivenProto) {
  return VRDisplayCapabilities_Binding::Wrap(aCx, this, aGivenProto);
}

VRPose::VRPose(nsISupports* aParent, const gfx::VRHMDSensorState& aState)
    : Pose(aParent), mVRState(aState) {
  mozilla::HoldJSObjects(this);
}

VRPose::VRPose(nsISupports* aParent) : Pose(aParent) {
  mVRState.inputFrameID = 0;
  mVRState.timestamp = 0.0;
  mVRState.flags = gfx::VRDisplayCapabilityFlags::Cap_None;
  mozilla::HoldJSObjects(this);
}

VRPose::~VRPose() { mozilla::DropJSObjects(this); }

void VRPose::GetPosition(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval,
                         ErrorResult& aRv) {
  const bool valid =
      bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position) ||
      bool(mVRState.flags &
           gfx::VRDisplayCapabilityFlags::Cap_PositionEmulated);
  SetFloat32Array(aCx, this, aRetval, mPosition,
                  valid ? mVRState.pose.position.data() : nullptr, 3, aRv);
}

void VRPose::GetLinearVelocity(JSContext* aCx,
                               JS::MutableHandle<JSObject*> aRetval,
                               ErrorResult& aRv) {
  const bool valid =
      bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position) ||
      bool(mVRState.flags &
           gfx::VRDisplayCapabilityFlags::Cap_PositionEmulated);
  SetFloat32Array(aCx, this, aRetval, mLinearVelocity,
                  valid ? mVRState.pose.linearVelocity.data() : nullptr, 3,
                  aRv);
}

void VRPose::GetLinearAcceleration(JSContext* aCx,
                                   JS::MutableHandle<JSObject*> aRetval,
                                   ErrorResult& aRv) {
  const bool valid = bool(
      mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_LinearAcceleration);
  SetFloat32Array(aCx, this, aRetval, mLinearAcceleration,
                  valid ? mVRState.pose.linearAcceleration.data() : nullptr, 3,
                  aRv);
}

void VRPose::GetOrientation(JSContext* aCx,
                            JS::MutableHandle<JSObject*> aRetval,
                            ErrorResult& aRv) {
  const bool valid =
      bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation);
  SetFloat32Array(aCx, this, aRetval, mOrientation,
                  valid ? mVRState.pose.orientation.data() : nullptr, 4, aRv);
}

void VRPose::GetAngularVelocity(JSContext* aCx,
                                JS::MutableHandle<JSObject*> aRetval,
                                ErrorResult& aRv) {
  const bool valid =
      bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation);
  SetFloat32Array(aCx, this, aRetval, mAngularVelocity,
                  valid ? mVRState.pose.angularVelocity.data() : nullptr, 3,
                  aRv);
}

void VRPose::GetAngularAcceleration(JSContext* aCx,
                                    JS::MutableHandle<JSObject*> aRetval,
                                    ErrorResult& aRv) {
  const bool valid = bool(
      mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_AngularAcceleration);
  SetFloat32Array(aCx, this, aRetval, mAngularAcceleration,
                  valid ? mVRState.pose.angularAcceleration.data() : nullptr, 3,
                  aRv);
}

void VRPose::Update(const gfx::VRHMDSensorState& aState) { mVRState = aState; }

JSObject* VRPose::WrapObject(JSContext* aCx,
                             JS::Handle<JSObject*> aGivenProto) {
  return VRPose_Binding::Wrap(aCx, this, aGivenProto);
}

/* virtual */
JSObject* VRDisplay::WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) {
  return VRDisplay_Binding::Wrap(aCx, this, aGivenProto);
}

VRDisplay::VRDisplay(nsPIDOMWindowInner* aWindow, gfx::VRDisplayClient* aClient)
    : DOMEventTargetHelper(aWindow),
      mClient(aClient),
      mDepthNear(0.01f)  // Default value from WebVR Spec
      ,
      mDepthFar(10000.0f)  // Default value from WebVR Spec
      ,
      mVRNavigationEventDepth(0),
      mShutdown(false) {
  const gfx::VRDisplayInfo& info = aClient->GetDisplayInfo();
  mCapabilities = new VRDisplayCapabilities(aWindow, info.GetCapabilities());
  if (info.GetCapabilities() &
      gfx::VRDisplayCapabilityFlags::Cap_StageParameters) {
    mStageParameters = new VRStageParameters(
        aWindow, info.GetSittingToStandingTransform(), info.GetStageSize());
  }
  mozilla::HoldJSObjects(this);
  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
  if (MOZ_LIKELY(obs)) {
    obs->AddObserver(this"inner-window-destroyed"false);
  }
}

VRDisplay::~VRDisplay() {
  MOZ_ASSERT(mShutdown);
  mozilla::DropJSObjects(this);
}

void VRDisplay::LastRelease() {
  // We don't want to wait for the CC to free up the presentation
  // for use in other documents, so we do this in LastRelease().
  Shutdown();
}

already_AddRefed<VREyeParameters> VRDisplay::GetEyeParameters(VREye aEye) {
  gfx::VRDisplayState::Eye eye = aEye == VREye::Left
                                     ? gfx::VRDisplayState::Eye_Left
                                     : gfx::VRDisplayState::Eye_Right;
  RefPtr<VREyeParameters> params = new VREyeParameters(
      GetParentObject(), mClient->GetDisplayInfo().GetEyeTranslation(eye),
      mClient->GetDisplayInfo().GetEyeFOV(eye),
      mClient->GetDisplayInfo().SuggestedEyeResolution());
  return params.forget();
}

VRDisplayCapabilities* VRDisplay::Capabilities() { return mCapabilities; }

VRStageParameters* VRDisplay::GetStageParameters() { return mStageParameters; }

uint32_t VRDisplay::DisplayId() const {
  const gfx::VRDisplayInfo& info = mClient->GetDisplayInfo();
  return info.GetDisplayID();
}

void VRDisplay::GetDisplayName(nsAString& aDisplayName) const {
  const gfx::VRDisplayInfo& info = mClient->GetDisplayInfo();
  CopyUTF8toUTF16(MakeStringSpan(info.GetDisplayName()), aDisplayName);
}

void VRDisplay::UpdateFrameInfo() {
  /**
   * The WebVR 1.1 spec Requires that VRDisplay.getPose and
   * VRDisplay.getFrameData must return the same values until the next
   * VRDisplay.submitFrame.
   *
   * mFrameInfo is marked dirty at the end of the frame or start of a new
   * composition and lazily created here in order to receive mid-frame
   * pose-prediction updates while still ensuring conformance to the WebVR spec
   * requirements.
   *
   * If we are not presenting WebVR content, the frame will never end and we
   * should return the latest frame data always.
   */

  mFrameInfo.Clear();

  if ((mFrameInfo.IsDirty() && IsPresenting()) ||
      mClient->GetDisplayInfo().GetPresentingGroups() == 0) {
    const gfx::VRHMDSensorState& state = mClient->GetSensorState();
    const gfx::VRDisplayInfo& info = mClient->GetDisplayInfo();
    mFrameInfo.Update(info, state, mDepthNear, mDepthFar);
  }
}

bool VRDisplay::GetFrameData(VRFrameData& aFrameData) {
  UpdateFrameInfo();
  if (!(mFrameInfo.mVRState.flags &
        gfx::VRDisplayCapabilityFlags::Cap_Orientation)) {
    // We must have at minimum Cap_Orientation for a valid pose.
    return false;
  }
  aFrameData.Update(mFrameInfo);
  return true;
}

already_AddRefed<VRPose> VRDisplay::GetPose() {
  UpdateFrameInfo();
  RefPtr<VRPose> obj = new VRPose(GetParentObject(), mFrameInfo.mVRState);

  return obj.forget();
}

void VRDisplay::ResetPose() {
  // ResetPose is deprecated and unimplemented
  // We must keep this stub function around as its referenced by
  // VRDisplay.webidl. Not asserting here, as that could break existing web
  // content.
}

void VRDisplay::StartVRNavigation() { mClient->StartVRNavigation(); }

void VRDisplay::StartHandlingVRNavigationEvent() {
  mHandlingVRNavigationEventStart = TimeStamp::Now();
  ++mVRNavigationEventDepth;
  TimeDuration timeout =
      TimeDuration::FromMilliseconds(StaticPrefs::dom_vr_navigation_timeout());
  // A 0 or negative TimeDuration indicates that content may take
  // as long as it wishes to respond to the event, as long as
  // it happens before the event exits.
  if (timeout.ToMilliseconds() > 0) {
    mClient->StopVRNavigation(timeout);
  }
}

void VRDisplay::StopHandlingVRNavigationEvent() {
  MOZ_ASSERT(mVRNavigationEventDepth > 0);
  --mVRNavigationEventDepth;
  if (mVRNavigationEventDepth == 0) {
    mClient->StopVRNavigation(TimeDuration::FromMilliseconds(0));
  }
}

bool VRDisplay::IsHandlingVRNavigationEvent() {
  if (mVRNavigationEventDepth == 0) {
    return false;
  }
  if (mHandlingVRNavigationEventStart.IsNull()) {
    return false;
  }
  TimeDuration timeout =
      TimeDuration::FromMilliseconds(StaticPrefs::dom_vr_navigation_timeout());
  return timeout.ToMilliseconds() <= 0 ||
         (TimeStamp::Now() - mHandlingVRNavigationEventStart) <= timeout;
}

void VRDisplay::OnPresentationGenerationChanged() { ExitPresentInternal(); }

already_AddRefed<Promise> VRDisplay::RequestPresent(
    const nsTArray<VRLayer>& aLayers, CallerType aCallerType,
    ErrorResult& aRv) {
  nsCOMPtr<nsIGlobalObject> global = GetParentObject();
  if (!global) {
    aRv.Throw(NS_ERROR_FAILURE);
    return nullptr;
  }

  RefPtr<Promise> promise = Promise::Create(global, aRv);
  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);

  bool isChromePresentation = aCallerType == CallerType::System;
  uint32_t presentationGroup =
      isChromePresentation ? gfx::kVRGroupChrome : gfx::kVRGroupContent;

  mClient->SetXRAPIMode(gfx::VRAPIMode::WebVR);
  if (!UserActivation::IsHandlingUserInput() && !isChromePresentation &&
      !IsHandlingVRNavigationEvent() && StaticPrefs::dom_vr_require_gesture() &&
      !IsPresenting()) {
    // The WebVR API states that if called outside of a user gesture, the
    // promise must be rejected.  We allow VR presentations to start within
    // trusted events such as vrdisplayactivate, which triggers in response to
    // HMD proximity sensors and when navigating within a VR presentation.
    // This user gesture requirement is not enforced for chrome/system code.
    promise->MaybeRejectWithUndefined();
  } else if (!IsPresenting() && IsAnyPresenting(presentationGroup)) {
    // Only one presentation allowed per VRDisplay on a
    // first-come-first-serve basis.
    // If this Javascript context is presenting, then we can replace our
    // presentation with a new one containing new layers but we should never
    // replace the presentation of another context.
    // Simultaneous presentations in other groups are allowed in separate
    // Javascript contexts to enable browser UI from chrome/system contexts.
    // Eventually, this restriction will be loosened to enable multitasking
    // use cases.
    promise->MaybeRejectWithUndefined();
  } else {
    if (mPresentation) {
      mPresentation->UpdateLayers(aLayers);
    } else {
      mPresentation = mClient->BeginPresentation(aLayers, presentationGroup);
    }
    mFrameInfo.Clear();
    promise->MaybeResolve(JS::UndefinedHandleValue);
  }
  return promise.forget();
}

NS_IMETHODIMP
VRDisplay::Observe(nsISupports* aSubject, const char* aTopic,
                   const char16_t* aData) {
  MOZ_ASSERT(NS_IsMainThread());

  if (strcmp(aTopic, "inner-window-destroyed") == 0) {
    nsCOMPtr<nsISupportsPRUint64> wrapper = do_QueryInterface(aSubject);
    NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);

    uint64_t innerID;
    nsresult rv = wrapper->GetData(&innerID);
    NS_ENSURE_SUCCESS(rv, rv);

    if (!GetOwnerWindow() || GetOwnerWindow()->WindowID() == innerID) {
      Shutdown();
    }

    return NS_OK;
  }

  // This should not happen.
  return NS_ERROR_FAILURE;
}

already_AddRefed<Promise> VRDisplay::ExitPresent(ErrorResult& aRv) {
  nsCOMPtr<nsIGlobalObject> global = GetParentObject();
  if (!global) {
    aRv.Throw(NS_ERROR_FAILURE);
    return nullptr;
  }

  RefPtr<Promise> promise = Promise::Create(global, aRv);
  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);

  if (!IsPresenting()) {
    // We can not exit a presentation outside of the context that
    // started the presentation.
    promise->MaybeRejectWithUndefined();
  } else {
    promise->MaybeResolve(JS::UndefinedHandleValue);
    ExitPresentInternal();
  }

  return promise.forget();
}

void VRDisplay::ExitPresentInternal() { mPresentation = nullptr; }

void VRDisplay::Shutdown() {
  mShutdown = true;
  ExitPresentInternal();
  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
  if (MOZ_LIKELY(obs)) {
    obs->RemoveObserver(this"inner-window-destroyed");
  }
}

void VRDisplay::GetLayers(nsTArray<VRLayer>& result) {
  if (mPresentation) {
    mPresentation->GetDOMLayers(result);
  } else {
    result = nsTArray<VRLayer>();
  }
}

void VRDisplay::SubmitFrame() {
  AUTO_PROFILER_TRACING_MARKER("VR""SubmitFrameAtVRDisplay", OTHER);

  if (mClient && !mClient->IsPresentationGenerationCurrent()) {
    mPresentation = nullptr;
    mClient->MakePresentationGenerationCurrent();
  }

  if (mPresentation) {
    mPresentation->SubmitFrame();
  }
  mFrameInfo.Clear();
}

int32_t VRDisplay::RequestAnimationFrame(FrameRequestCallback& aCallback,
                                         ErrorResult& aError) {
  if (mShutdown) {
    return 0;
  }

  gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();

  int32_t handle;
  aError = vm->ScheduleFrameRequestCallback(aCallback, &handle);
  return handle;
}

void VRDisplay::CancelAnimationFrame(int32_t aHandle, ErrorResult& aError) {
  gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
  vm->CancelFrameRequestCallback(aHandle);
}

bool VRDisplay::IsPresenting() const {
  // IsPresenting returns true only if this Javascript context is presenting
  // and will return false if another context is presenting.
  return mPresentation != nullptr;
}

bool VRDisplay::IsAnyPresenting(uint32_t aGroupMask) const {
  // IsAnyPresenting returns true if either this VRDisplay object or any other
  // from anther Javascript context is presenting with a group matching
  // aGroupMask.
  if (mPresentation && (mPresentation->GetGroup() & aGroupMask)) {
    return true;
  }
  if (mClient->GetDisplayInfo().GetPresentingGroups() & aGroupMask) {
    return true;
  }
  return false;
}

bool VRDisplay::IsConnected() const { return mClient->GetIsConnected(); }

uint32_t VRDisplay::PresentingGroups() const {
  return mClient->GetDisplayInfo().GetPresentingGroups();
}

uint32_t VRDisplay::GroupMask() const {
  return mClient->GetDisplayInfo().GetGroupMask();
}

void VRDisplay::SetGroupMask(const uint32_t& aGroupMask) {
  mClient->SetGroupMask(aGroupMask);
}

NS_IMPL_CYCLE_COLLECTION_INHERITED(VRDisplay, DOMEventTargetHelper,
                                   mCapabilities, mStageParameters)

NS_IMPL_ADDREF_INHERITED(VRDisplay, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(VRDisplay, DOMEventTargetHelper)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(VRDisplay)
  NS_INTERFACE_MAP_ENTRY(nsIObserver)
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)

NS_IMPL_CYCLE_COLLECTION_CLASS(VRFrameData)

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(VRFrameData)
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent, mPose)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  tmp->mLeftProjectionMatrix = nullptr;
  tmp->mLeftViewMatrix = nullptr;
  tmp->mRightProjectionMatrix = nullptr;
  tmp->mRightViewMatrix = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END

NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(VRFrameData)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent, mPose)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(VRFrameData)
  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLeftProjectionMatrix)
  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLeftViewMatrix)
  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRightProjectionMatrix)
  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mRightViewMatrix)
NS_IMPL_CYCLE_COLLECTION_TRACE_END

VRFrameData::VRFrameData(nsISupports* aParent)
    : mParent(aParent),
      mLeftProjectionMatrix(nullptr),
      mLeftViewMatrix(nullptr),
      mRightProjectionMatrix(nullptr),
      mRightViewMatrix(nullptr) {
  mozilla::HoldJSObjects(this);
  mPose = new VRPose(aParent);
}

VRFrameData::~VRFrameData() { mozilla::DropJSObjects(this); }

/* static */
already_AddRefed<VRFrameData> VRFrameData::Constructor(
    const GlobalObject& aGlobal) {
  RefPtr<VRFrameData> obj = new VRFrameData(aGlobal.GetAsSupports());
  return obj.forget();
}

JSObject* VRFrameData::WrapObject(JSContext* aCx,
                                  JS::Handle<JSObject*> aGivenProto) {
  return VRFrameData_Binding::Wrap(aCx, this, aGivenProto);
}

VRPose* VRFrameData::Pose() { return mPose; }

double VRFrameData::Timestamp() const {
  // Converting from seconds to milliseconds
  return mFrameInfo.mVRState.timestamp * 1000.0f;
}

void VRFrameData::GetLeftProjectionMatrix(JSContext* aCx,
                                          JS::MutableHandle<JSObject*> aRetval,
                                          ErrorResult& aRv) {
  Pose::SetFloat32Array(aCx, this, aRetval, mLeftProjectionMatrix,
                        mFrameInfo.mLeftProjection.components, 16, aRv);
}

void VRFrameData::GetLeftViewMatrix(JSContext* aCx,
                                    JS::MutableHandle<JSObject*> aRetval,
                                    ErrorResult& aRv) {
  Pose::SetFloat32Array(aCx, this, aRetval, mLeftViewMatrix,
                        mFrameInfo.mLeftView.components, 16, aRv);
}

void VRFrameData::GetRightProjectionMatrix(JSContext* aCx,
                                           JS::MutableHandle<JSObject*> aRetval,
                                           ErrorResult& aRv) {
  Pose::SetFloat32Array(aCx, this, aRetval, mRightProjectionMatrix,
                        mFrameInfo.mRightProjection.components, 16, aRv);
}

void VRFrameData::GetRightViewMatrix(JSContext* aCx,
                                     JS::MutableHandle<JSObject*> aRetval,
                                     ErrorResult& aRv) {
  Pose::SetFloat32Array(aCx, this, aRetval, mRightViewMatrix,
                        mFrameInfo.mRightView.components, 16, aRv);
}

void VRFrameData::Update(const VRFrameInfo& aFrameInfo) {
  mFrameInfo = aFrameInfo;
  mPose->Update(mFrameInfo.mVRState);
}

void VRFrameInfo::Update(const gfx::VRDisplayInfo& aInfo,
                         const gfx::VRHMDSensorState& aState, float aDepthNear,
                         float aDepthFar) {
  mVRState = aState;
  if (mTimeStampOffset == 0.0f) {
    /**
     * A mTimeStampOffset value of 0.0f indicates that this is the first
     * iteration and an offset has not yet been set.
     *
     * Generate a value for mTimeStampOffset such that if aState.timestamp is
     * monotonically increasing, aState.timestamp + mTimeStampOffset will never
     * be a negative number and will start at a pseudo-random offset
     * between 1000.0f and 11000.0f seconds.
     *
     * We use a pseudo random offset rather than 0.0f just to discourage users
     * from making the assumption that the timestamp returned in the WebVR API
     * has a base of 0, which is not necessarily true in all UA's.
     */

    mTimeStampOffset =
        float(rand()) / float(RAND_MAX) * 10000.0f + 1000.0f - aState.timestamp;
  }
  mVRState.timestamp = aState.timestamp + mTimeStampOffset;

  // Avoid division by zero within ConstructProjectionMatrix
  const float kEpsilon = 0.00001f;
  if (fabs(aDepthFar - aDepthNear) < kEpsilon) {
    aDepthFar = aDepthNear + kEpsilon;
  }

  const gfx::VRFieldOfView leftFOV =
      aInfo.mDisplayState.eyeFOV[gfx::VRDisplayState::Eye_Left];
  mLeftProjection =
      leftFOV.ConstructProjectionMatrix(aDepthNear, aDepthFar, true);
  const gfx::VRFieldOfView rightFOV =
      aInfo.mDisplayState.eyeFOV[gfx::VRDisplayState::Eye_Right];
  mRightProjection =
      rightFOV.ConstructProjectionMatrix(aDepthNear, aDepthFar, true);
  memcpy(mLeftView.components, aState.leftViewMatrix.data(),
         sizeof(aState.leftViewMatrix));
  memcpy(mRightView.components, aState.rightViewMatrix.data(),
         sizeof(aState.rightViewMatrix));
}

VRFrameInfo::VRFrameInfo() : mTimeStampOffset(0.0f) {
  mVRState.inputFrameID = 0;
  mVRState.timestamp = 0.0;
  mVRState.flags = gfx::VRDisplayCapabilityFlags::Cap_None;
}

bool VRFrameInfo::IsDirty() { return mVRState.timestamp == 0; }

void VRFrameInfo::Clear() { mVRState.Clear(); }

}  // namespace mozilla::dom

99%


¤ Dauer der Verarbeitung: 0.35 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.