Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


SSL VRManagerChild.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 "VRManagerChild.h"

#include "VRLayerChild.h"
#include "VRManagerParent.h"
#include "VRThread.h"
#include "VRDisplayClient.h"
#include "nsGlobalWindowInner.h"
#include "mozilla/ProfilerMarkers.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/layers/CompositorThread.h"  // for CompositorThread
#include "mozilla/dom/Navigator.h"
#include "mozilla/dom/VREventObserver.h"
#include "mozilla/dom/WebXRBinding.h"
#include "mozilla/dom/WindowBinding.h"  // for FrameRequestCallback
#include "mozilla/dom/XRSystem.h"
#include "mozilla/dom/XRFrame.h"
#include "mozilla/dom/ContentChild.h"
#include "nsContentUtils.h"
#include "mozilla/dom/GamepadManager.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/layers/SyncObject.h"
#include "mozilla/layers/TextureForwarder.h"

using namespace mozilla::dom;

namespace {
const nsTArray<RefPtr<mozilla::gfx::VRManagerEventObserver>>::index_type
    kNoIndex = nsTArray<RefPtr<mozilla::gfx::VRManagerEventObserver>>::NoIndex;
}  // namespace

namespace mozilla {
namespace gfx {

static StaticRefPtr<VRManagerChild> sVRManagerChildSingleton;
static StaticRefPtr<VRManagerParent> sVRManagerParentSingleton;

static TimeStamp sMostRecentFrameEnd;
static TimeDuration sAverageFrameInterval;

void ReleaseVRManagerParentSingleton() { sVRManagerParentSingleton = nullptr; }

VRManagerChild::VRManagerChild()
    : mRuntimeCapabilities(VRDisplayCapabilityFlags::Cap_None),
      mFrameRequestCallbackCounter(0),
      mWaitingForEnumeration(false),
      mBackend(layers::LayersBackend::LAYERS_NONE) {
  MOZ_ASSERT(NS_IsMainThread());

  mStartTimeStamp = TimeStamp::Now();
}

VRManagerChild::~VRManagerChild() { MOZ_ASSERT(NS_IsMainThread()); }

/*static*/
void VRManagerChild::IdentifyTextureHost(
    const TextureFactoryIdentifier& aIdentifier) {
  if (sVRManagerChildSingleton) {
    sVRManagerChildSingleton->mBackend = aIdentifier.mParentBackend;
  }
}

layers::LayersBackend VRManagerChild::GetBackendType() const {
  return mBackend;
}

/*static*/
VRManagerChild* VRManagerChild::Get() {
  MOZ_ASSERT(sVRManagerChildSingleton);
  return sVRManagerChildSingleton;
}

/* static */
bool VRManagerChild::IsCreated() { return !!sVRManagerChildSingleton; }

/* static */
bool VRManagerChild::IsPresenting() {
  if (!VRManagerChild::IsCreated()) {
    return false;
  }

  nsTArray<RefPtr<VRDisplayClient>> displays;
  sVRManagerChildSingleton->GetVRDisplays(displays);

  bool result = false;
  for (auto& display : displays) {
    result |= display->IsPresenting();
  }
  return result;
}

TimeStamp VRManagerChild::GetIdleDeadlineHint(TimeStamp aDefault) {
  MOZ_ASSERT(NS_IsMainThread());
  if (!VRManagerChild::IsCreated() || sMostRecentFrameEnd.IsNull()) {
    return aDefault;
  }

  TimeStamp idleEnd = sMostRecentFrameEnd + sAverageFrameInterval;
  return idleEnd < aDefault ? idleEnd : aDefault;
}

/* static */
bool VRManagerChild::InitForContent(Endpoint<PVRManagerChild>&& aEndpoint) {
  MOZ_ASSERT(NS_IsMainThread());

  RefPtr<VRManagerChild> child(new VRManagerChild());
  if (!aEndpoint.Bind(child)) {
    return false;
  }
  sVRManagerChildSingleton = child;
  return true;
}

/*static*/
void VRManagerChild::InitSameProcess() {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(!sVRManagerChildSingleton);

  sVRManagerChildSingleton = new VRManagerChild();
  sVRManagerParentSingleton = VRManagerParent::CreateSameProcess();
  sVRManagerChildSingleton->Open(sVRManagerParentSingleton, CompositorThread(),
                                 mozilla::ipc::ChildSide);
}

/* static */
void VRManagerChild::InitWithGPUProcess(Endpoint<PVRManagerChild>&& aEndpoint) {
  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(!sVRManagerChildSingleton);

  sVRManagerChildSingleton = new VRManagerChild();
  if (!aEndpoint.Bind(sVRManagerChildSingleton)) {
    MOZ_CRASH("Couldn't Open() Compositor channel.");
  }
}

/*static*/
void VRManagerChild::ShutDown() {
  MOZ_ASSERT(NS_IsMainThread());
  if (!sVRManagerChildSingleton) {
    return;
  }
  sVRManagerChildSingleton->Close();
  sVRManagerChildSingleton = nullptr;
}

void VRManagerChild::ActorDestroy(ActorDestroyReason aReason) {
  if (sVRManagerChildSingleton == this) {
    sVRManagerChildSingleton = nullptr;
  }
}

PVRLayerChild* VRManagerChild::AllocPVRLayerChild(const uint32_t& aDisplayID,
                                                  const uint32_t& aGroup) {
  return VRLayerChild::CreateIPDLActor();
}

bool VRManagerChild::DeallocPVRLayerChild(PVRLayerChild* actor) {
  return VRLayerChild::DestroyIPDLActor(actor);
}

void VRManagerChild::UpdateDisplayInfo(const VRDisplayInfo& aDisplayInfo) {
  nsTArray<uint32_t> disconnectedDisplays;
  nsTArray<uint32_t> connectedDisplays;

  const nsTArray<RefPtr<VRDisplayClient>> prevDisplays(mDisplays.Clone());

  // Check if any displays have been disconnected
  for (auto& display : prevDisplays) {
    bool found = false;
    if (aDisplayInfo.GetDisplayID() != 0) {
      if (display->GetDisplayInfo().GetDisplayID() ==
          aDisplayInfo.GetDisplayID()) {
        found = true;
        break;
      }
    }
    if (!found) {
      // In order to make the current VRDisplay can continue to apply for the
      // newest VRDisplayInfo, we need to exit presentionation before
      // disconnecting.
      if (display->IsPresentationGenerationCurrent()) {
        NotifyPresentationGenerationChangedInternal(
            display->GetDisplayInfo().GetDisplayID());

        RefPtr<VRManagerChild> vm = VRManagerChild::Get();
        vm->FireDOMVRDisplayPresentChangeEvent(
            display->GetDisplayInfo().GetDisplayID());
      }
      display->NotifyDisconnected();
      disconnectedDisplays.AppendElement(
          display->GetDisplayInfo().GetDisplayID());
    }
  }

  // mDisplays could be a hashed container for more scalability, but not worth
  // it now as we expect < 10 entries.
  nsTArray<RefPtr<VRDisplayClient>> displays;
  if (aDisplayInfo.GetDisplayID() != 0) {
    bool isNewDisplay = true;
    for (auto& display : prevDisplays) {
      const VRDisplayInfo& prevInfo = display->GetDisplayInfo();
      if (prevInfo.GetDisplayID() == aDisplayInfo.GetDisplayID()) {
        if (aDisplayInfo.GetIsConnected() && !prevInfo.GetIsConnected()) {
          connectedDisplays.AppendElement(aDisplayInfo.GetDisplayID());
        }
        if (!aDisplayInfo.GetIsConnected() && prevInfo.GetIsConnected()) {
          disconnectedDisplays.AppendElement(aDisplayInfo.GetDisplayID());
        }
        // MOZ_KnownLive because 'prevDisplays' is guaranteed to keep it alive.
        //
        // This can go away once
        // https://bugzilla.mozilla.org/show_bug.cgi?id=1620312 is fixed.
        MOZ_KnownLive(display)->UpdateDisplayInfo(aDisplayInfo);
        displays.AppendElement(display);
        isNewDisplay = false;
        break;
      }
    }
    if (isNewDisplay) {
      displays.AppendElement(new VRDisplayClient(aDisplayInfo));
      connectedDisplays.AppendElement(aDisplayInfo.GetDisplayID());
    }
  }

  mDisplays = std::move(displays);

  // We wish to fire the events only after mDisplays is updated
  for (uint32_t displayID : disconnectedDisplays) {
    FireDOMVRDisplayDisconnectEvent(displayID);
  }

  for (uint32_t displayID : connectedDisplays) {
    FireDOMVRDisplayConnectEvent(displayID);
  }
}

bool VRManagerChild::RuntimeSupportsVR() const {
  return bool(mRuntimeCapabilities & VRDisplayCapabilityFlags::Cap_ImmersiveVR);
}
bool VRManagerChild::RuntimeSupportsAR() const {
  return bool(mRuntimeCapabilities & VRDisplayCapabilityFlags::Cap_ImmersiveAR);
}
bool VRManagerChild::RuntimeSupportsInline() const {
  return bool(mRuntimeCapabilities & VRDisplayCapabilityFlags::Cap_Inline);
}

mozilla::ipc::IPCResult VRManagerChild::RecvUpdateRuntimeCapabilities(
    const VRDisplayCapabilityFlags& aCapabilities) {
  mRuntimeCapabilities = aCapabilities;
  nsContentUtils::AddScriptRunner(NewRunnableMethod<>(
      "gfx::VRManagerChild::NotifyRuntimeCapabilitiesUpdatedInternal"this,
      &VRManagerChild::NotifyRuntimeCapabilitiesUpdatedInternal));
  return IPC_OK();
}

void VRManagerChild::NotifyRuntimeCapabilitiesUpdatedInternal() {
  const nsTArray<RefPtr<VRManagerEventObserver>> listeners = mListeners.Clone();
  for (auto& listener : listeners) {
    listener->NotifyDetectRuntimesCompleted();
  }
}

mozilla::ipc::IPCResult VRManagerChild::RecvUpdateDisplayInfo(
    const VRDisplayInfo& aDisplayInfo) {
  UpdateDisplayInfo(aDisplayInfo);
  for (auto& windowId : mNavigatorCallbacks) {
    /** We must call NotifyVRDisplaysUpdated for every
     * window's Navigator in mNavigatorCallbacks to ensure that
     * the promise returned by Navigator.GetVRDevices
     * can resolve.  This must happen even if no changes
     * to VRDisplays have been detected here.
     */

    nsGlobalWindowInner* window =
        nsGlobalWindowInner::GetInnerWindowWithId(windowId);
    if (!window) {
      continue;
    }
    dom::Navigator* nav = window->Navigator();
    if (!nav) {
      continue;
    }
    nav->NotifyVRDisplaysUpdated();
  }
  mNavigatorCallbacks.Clear();
  if (mWaitingForEnumeration) {
    nsContentUtils::AddScriptRunner(NewRunnableMethod<>(
        "gfx::VRManagerChild::NotifyEnumerationCompletedInternal"this,
        &VRManagerChild::NotifyEnumerationCompletedInternal));
    mWaitingForEnumeration = false;
  }
  return IPC_OK();
}

mozilla::ipc::IPCResult VRManagerChild::RecvNotifyPuppetCommandBufferCompleted(
    bool aSuccess) {
  RefPtr<dom::Promise> promise = mRunPuppetPromise;
  mRunPuppetPromise = nullptr;
  if (aSuccess) {
    promise->MaybeResolve(JS::UndefinedHandleValue);
  } else {
    promise->MaybeRejectWithUndefined();
  }
  return IPC_OK();
}

mozilla::ipc::IPCResult VRManagerChild::RecvNotifyPuppetResetComplete() {
  nsTArray<RefPtr<dom::Promise>> promises;
  promises.AppendElements(mResetPuppetPromises);
  mResetPuppetPromises.Clear();
  for (const auto& promise : promises) {
    promise->MaybeResolve(JS::UndefinedHandleValue);
  }
  return IPC_OK();
}

void VRManagerChild::RunPuppet(const nsTArray<uint64_t>& aBuffer,
                               dom::Promise* aPromise, ErrorResult& aRv) {
  if (mRunPuppetPromise) {
    // We only allow one puppet script to run simultaneously.
    // The prior promise must be resolved before running a new
    // script.
    aRv.Throw(NS_ERROR_INVALID_ARG);
    return;
  }
  if (!SendRunPuppet(aBuffer)) {
    aRv.Throw(NS_ERROR_FAILURE);
    return;
  }
  mRunPuppetPromise = aPromise;
}

void VRManagerChild::ResetPuppet(dom::Promise* aPromise, ErrorResult& aRv) {
  if (!SendResetPuppet()) {
    aRv.Throw(NS_ERROR_FAILURE);
    return;
  }
  mResetPuppetPromises.AppendElement(aPromise);
}

void VRManagerChild::GetVRDisplays(
    nsTArray<RefPtr<VRDisplayClient>>& aDisplays) {
  aDisplays = mDisplays.Clone();
}

bool VRManagerChild::RefreshVRDisplaysWithCallback(uint64_t aWindowId) {
  bool success = SendRefreshDisplays();
  if (success) {
    mNavigatorCallbacks.AppendElement(aWindowId);
  }
  return success;
}

bool VRManagerChild::EnumerateVRDisplays() {
  bool success = SendRefreshDisplays();
  if (success) {
    mWaitingForEnumeration = true;
  }
  return success;
}

void VRManagerChild::DetectRuntimes() { Unused << SendDetectRuntimes(); }

PVRLayerChild* VRManagerChild::CreateVRLayer(uint32_t aDisplayID,
                                             uint32_t aGroup) {
  PVRLayerChild* vrLayerChild = AllocPVRLayerChild(aDisplayID, aGroup);
  return SendPVRLayerConstructor(vrLayerChild, aDisplayID, aGroup);
}

void VRManagerChild::XRFrameRequest::Call(
    const DOMHighResTimeStamp& aTimeStamp) {
  if (mCallback) {
    RefPtr<mozilla::dom::FrameRequestCallback> callback = mCallback;
    callback->Call(aTimeStamp);
  } else {
    RefPtr<mozilla::dom::XRFrameRequestCallback> callback = mXRCallback;
    RefPtr<mozilla::dom::XRFrame> frame = mXRFrame;
    callback->Call(aTimeStamp, *frame);
  }
}

nsresult VRManagerChild::ScheduleFrameRequestCallback(
    mozilla::dom::FrameRequestCallback& aCallback, int32_t* aHandle) {
  if (mFrameRequestCallbackCounter == INT32_MAX) {
    // Can't increment without overflowing; bail out
    return NS_ERROR_NOT_AVAILABLE;
  }
  int32_t newHandle = ++mFrameRequestCallbackCounter;

  mFrameRequestCallbacks.AppendElement(XRFrameRequest(aCallback, newHandle));

  *aHandle = newHandle;
  return NS_OK;
}

void VRManagerChild::CancelFrameRequestCallback(int32_t aHandle) {
  // mFrameRequestCallbacks is stored sorted by handle
  mFrameRequestCallbacks.RemoveElementSorted(aHandle);
}

void VRManagerChild::RunFrameRequestCallbacks() {
  AUTO_PROFILER_TRACING_MARKER("VR""RunFrameRequestCallbacks", GRAPHICS);

  TimeStamp nowTime = TimeStamp::Now();
  mozilla::TimeDuration duration = nowTime - mStartTimeStamp;
  DOMHighResTimeStamp timeStamp = duration.ToMilliseconds();

  if (!sMostRecentFrameEnd.IsNull()) {
    TimeDuration frameInterval = nowTime - sMostRecentFrameEnd;
    if (sAverageFrameInterval.IsZero()) {
      sAverageFrameInterval = frameInterval;
    } else {
      // Calculate the average interval between frame end and next frame start.
      // Apply some smoothing to make it more stable.
      const double smooth = 0.9;
      sAverageFrameInterval = sAverageFrameInterval.MultDouble(smooth) +
                              frameInterval.MultDouble(1.0 - smooth);
    }
  }

  nsTArray<XRFrameRequest> callbacks;
  callbacks.AppendElements(mFrameRequestCallbacks);
  mFrameRequestCallbacks.Clear();
  for (auto& callback : callbacks) {
    // The FrameRequest copied into the on-stack array holds a strong ref to its
    // mCallback and there's nothing that can drop that ref until we return.
    MOZ_KnownLive(callback.mCallback)->Call(timeStamp);
  }

  if (IsPresenting()) {
    sMostRecentFrameEnd = TimeStamp::Now();
  }
}

void VRManagerChild::NotifyPresentationGenerationChanged(uint32_t aDisplayID) {
  nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
      "gfx::VRManagerChild::NotifyPresentationGenerationChangedInternal"this,
      &VRManagerChild::NotifyPresentationGenerationChangedInternal,
      aDisplayID));
}

void VRManagerChild::FireDOMVRDisplayMountedEvent(uint32_t aDisplayID) {
  nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
      "gfx::VRManagerChild::FireDOMVRDisplayMountedEventInternal"this,
      &VRManagerChild::FireDOMVRDisplayMountedEventInternal, aDisplayID));
}

void VRManagerChild::FireDOMVRDisplayUnmountedEvent(uint32_t aDisplayID) {
  nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
      "gfx::VRManagerChild::FireDOMVRDisplayUnmountedEventInternal"this,
      &VRManagerChild::FireDOMVRDisplayUnmountedEventInternal, aDisplayID));
}

void VRManagerChild::FireDOMVRDisplayConnectEvent(uint32_t aDisplayID) {
  nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
      "gfx::VRManagerChild::FireDOMVRDisplayConnectEventInternal"this,
      &VRManagerChild::FireDOMVRDisplayConnectEventInternal, aDisplayID));
}

void VRManagerChild::FireDOMVRDisplayDisconnectEvent(uint32_t aDisplayID) {
  nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
      "gfx::VRManagerChild::FireDOMVRDisplayDisconnectEventInternal"this,
      &VRManagerChild::FireDOMVRDisplayDisconnectEventInternal, aDisplayID));
}

void VRManagerChild::FireDOMVRDisplayPresentChangeEvent(uint32_t aDisplayID) {
  nsContentUtils::AddScriptRunner(NewRunnableMethod<uint32_t>(
      "gfx::VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal"this,
      &VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal, aDisplayID));

  if (!IsPresenting()) {
    sMostRecentFrameEnd = TimeStamp();
    sAverageFrameInterval = 0;
  }
}

void VRManagerChild::FireDOMVRDisplayMountedEventInternal(uint32_t aDisplayID) {
  // Iterate over a copy of mListeners, as dispatched events may modify it.
  for (auto& listener : mListeners.Clone()) {
    listener->NotifyVRDisplayMounted(aDisplayID);
  }
}

void VRManagerChild::FireDOMVRDisplayUnmountedEventInternal(
    uint32_t aDisplayID) {
  // Iterate over a copy of mListeners, as dispatched events may modify it.
  for (auto& listener : mListeners.Clone()) {
    listener->NotifyVRDisplayUnmounted(aDisplayID);
  }
}

void VRManagerChild::FireDOMVRDisplayConnectEventInternal(uint32_t aDisplayID) {
  // Iterate over a copy of mListeners, as dispatched events may modify it.
  for (auto& listener : mListeners.Clone()) {
    listener->NotifyVRDisplayConnect(aDisplayID);
  }
}

void VRManagerChild::FireDOMVRDisplayDisconnectEventInternal(
    uint32_t aDisplayID) {
  // Iterate over a copy of mListeners, as dispatched events may modify it.
  for (auto& listener : mListeners.Clone()) {
    listener->NotifyVRDisplayDisconnect(aDisplayID);
  }
}

void VRManagerChild::FireDOMVRDisplayPresentChangeEventInternal(
    uint32_t aDisplayID) {
  // Iterate over a copy of mListeners, as dispatched events may modify it.
  for (auto& listener : mListeners.Clone()) {
    // MOZ_KnownLive because 'listeners' is guaranteed to keep it alive.
    //
    // This can go away once
    // https://bugzilla.mozilla.org/show_bug.cgi?id=1620312 is fixed.
    MOZ_KnownLive(listener)->NotifyVRDisplayPresentChange(aDisplayID);
  }
}

void VRManagerChild::FireDOMVRDisplayConnectEventsForLoadInternal(
    uint32_t aDisplayID, VRManagerEventObserver* aObserver) {
  aObserver->NotifyVRDisplayConnect(aDisplayID);
}

void VRManagerChild::NotifyPresentationGenerationChangedInternal(
    uint32_t aDisplayID) {
  for (auto& listener : mListeners.Clone()) {
    listener->NotifyPresentationGenerationChanged(aDisplayID);
  }
}

void VRManagerChild::NotifyEnumerationCompletedInternal() {
  for (auto& listener : mListeners.Clone()) {
    listener->NotifyEnumerationCompleted();
  }
}

void VRManagerChild::FireDOMVRDisplayConnectEventsForLoad(
    VRManagerEventObserver* aObserver) {
  // We need to fire the VRDisplayConnect event when a page is loaded
  // for each VR Display that has already been enumerated
  for (const auto& display : mDisplays.Clone()) {
    const VRDisplayInfo& info = display->GetDisplayInfo();
    if (info.GetIsConnected()) {
      nsContentUtils::AddScriptRunner(NewRunnableMethod<
                                      uint32_t, RefPtr<VRManagerEventObserver>>(
          "gfx::VRManagerChild::FireDOMVRDisplayConnectEventsForLoadInternal",
          this, &VRManagerChild::FireDOMVRDisplayConnectEventsForLoadInternal,
          info.GetDisplayID(), aObserver));
    }
  }
}

void VRManagerChild::AddListener(VRManagerEventObserver* aObserver) {
  MOZ_ASSERT(aObserver);

  if (mListeners.IndexOf(aObserver) != kNoIndex) {
    return;  // already exists
  }

  mListeners.AppendElement(aObserver);
  if (mListeners.Length() == 1) {
    Unused << SendSetHaveEventListener(true);
  }
}

void VRManagerChild::RemoveListener(VRManagerEventObserver* aObserver) {
  MOZ_ASSERT(aObserver);

  mListeners.RemoveElement(aObserver);
  if (mListeners.IsEmpty()) {
    Unused << SendSetHaveEventListener(false);
  }
}

void VRManagerChild::StartActivity() { Unused << SendStartActivity(); }

void VRManagerChild::StopActivity() {
  for (auto& listener : mListeners) {
    if (!listener->GetStopActivityStatus()) {
      // We are still showing VR in the active window.
      return;
    }
  }

  Unused << SendStopActivity();
}

void VRManagerChild::HandleFatalError(const char* aMsg) {
  dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherChildID());
}

void VRManagerChild::AddPromise(const uint32_t& aID, dom::Promise* aPromise) {
  MOZ_ASSERT(!mGamepadPromiseList.Contains(aID));
  mGamepadPromiseList.InsertOrUpdate(aID, RefPtr{aPromise});
}

gfx::VRAPIMode VRManagerChild::GetVRAPIMode(uint32_t aDisplayID) const {
  for (auto& display : mDisplays) {
    if (display->GetDisplayInfo().GetDisplayID() == aDisplayID) {
      return display->GetXRAPIMode();
    }
  }
  return VRAPIMode::WebXR;
}

mozilla::ipc::IPCResult VRManagerChild::RecvReplyGamepadVibrateHaptic(
    const uint32_t& aPromiseID) {
  // VRManagerChild could be at other processes, but GamepadManager
  // only exists at the content process or the same process
  // in non-e10s mode.
  MOZ_ASSERT(XRE_IsContentProcess() || IsSameProcess());

  RefPtr<dom::Promise> p;
  if (!mGamepadPromiseList.Get(aPromiseID, getter_AddRefs(p))) {
    MOZ_CRASH("We should always have a promise.");
  }

  p->MaybeResolve(true);
  mGamepadPromiseList.Remove(aPromiseID);
  return IPC_OK();
}

}  // namespace gfx
}  // namespace mozilla

Messung V0.5
C=94 H=95 G=94

¤ 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.0.14Bemerkung:  (vorverarbeitet)  ¤

*Bot Zugriff






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 und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge