diff options
Diffstat (limited to 'dom/vr/XRInputSourceArray.cpp')
-rw-r--r-- | dom/vr/XRInputSourceArray.cpp | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/dom/vr/XRInputSourceArray.cpp b/dom/vr/XRInputSourceArray.cpp new file mode 100644 index 0000000000..2cc2c4537a --- /dev/null +++ b/dom/vr/XRInputSourceArray.cpp @@ -0,0 +1,167 @@ +/* -*- 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 "mozilla/dom/XRInputSourceArray.h" +#include "mozilla/dom/XRSession.h" +#include "mozilla/dom/XRInputSourcesChangeEvent.h" +#include "VRDisplayClient.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(XRInputSourceArray, mParent, + mInputSources) +NS_IMPL_CYCLE_COLLECTING_ADDREF(XRInputSourceArray) +NS_IMPL_CYCLE_COLLECTING_RELEASE(XRInputSourceArray) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XRInputSourceArray) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +XRInputSourceArray::XRInputSourceArray(nsISupports* aParent) + : mParent(aParent) {} + +JSObject* XRInputSourceArray::WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) { + return XRInputSourceArray_Binding::Wrap(aCx, this, aGivenProto); +} + +void XRInputSourceArray::Update(XRSession* aSession) { + MOZ_ASSERT(aSession); + + gfx::VRDisplayClient* displayClient = aSession->GetDisplayClient(); + if (!displayClient) { + return; + } + + XRInputSourcesChangeEventInit addInit; + nsTArray<RefPtr<XRInputSource>> removedInputs; + if (NS_WARN_IF(!addInit.mAdded.SetCapacity(gfx::kVRControllerMaxCount, + mozilla::fallible))) { + MOZ_ASSERT(false, + "'add' sequence in XRInputSourcesChangeEventInit SetCapacity() " + "failed."); + return; + } + + for (int32_t i = 0; i < gfx::kVRControllerMaxCount; ++i) { + const gfx::VRControllerState& controllerState = + displayClient->GetDisplayInfo().mControllerState[i]; + if (controllerState.controllerName[0] == '\0') { + // Checking if exising controllers need to be removed. + for (auto& input : mInputSources) { + if (input->GetIndex() == i) { + removedInputs.AppendElement(input); + break; + } + } + continue; + } + + bool found = false; + RefPtr<XRInputSource> inputSource = nullptr; + for (auto& input : mInputSources) { + if (input->GetIndex() == i) { + found = true; + inputSource = input; + break; + } + } + // Checking if it is added before. + if (!found && + (controllerState.numButtons > 0 || controllerState.numAxes > 0)) { + inputSource = new XRInputSource(mParent); + inputSource->Setup(aSession, i); + mInputSources.AppendElement(inputSource); + + addInit.mBubbles = false; + addInit.mCancelable = false; + addInit.mSession = aSession; + if (!addInit.mAdded.AppendElement(*inputSource, mozilla::fallible)) { + MOZ_ASSERT(false, + "'add' sequence in XRInputSourcesChangeEventInit " + "AppendElement() failed, it might be due to the" + "wrong size when SetCapacity()."); + } + } + // If added, updating the current controller states. + if (inputSource) { + inputSource->Update(aSession); + } + } + + // Send `inputsourceschange` for new controllers. + if (addInit.mAdded.Length()) { + RefPtr<XRInputSourcesChangeEvent> event = + XRInputSourcesChangeEvent::Constructor( + aSession, u"inputsourceschange"_ns, addInit); + + event->SetTrusted(true); + aSession->DispatchEvent(*event); + } + + // If there's a controller is removed, dispatch `inputsourceschange`. + if (removedInputs.Length()) { + DispatchInputSourceRemovedEvent(removedInputs, aSession); + } + for (auto& input : removedInputs) { + mInputSources.RemoveElement(input); + } +} + +void XRInputSourceArray::DispatchInputSourceRemovedEvent( + const nsTArray<RefPtr<XRInputSource>>& aInputs, XRSession* aSession) { + if (!aSession) { + return; + } + + XRInputSourcesChangeEventInit init; + if (NS_WARN_IF( + !init.mRemoved.SetCapacity(aInputs.Length(), mozilla::fallible))) { + MOZ_ASSERT(false, + "'removed' sequence in XRInputSourcesChangeEventInit " + "SetCapacity() failed."); + return; + } + for (const auto& input : aInputs) { + input->SetGamepadIsConnected(false, aSession); + init.mBubbles = false; + init.mCancelable = false; + init.mSession = aSession; + if (!init.mRemoved.AppendElement(*input, mozilla::fallible)) { + MOZ_ASSERT(false, + "'removed' sequence in XRInputSourcesChangeEventInit " + "AppendElement() failed, it might be due to the" + "wrong size when SetCapacity()."); + } + } + + if (init.mRemoved.Length()) { + RefPtr<XRInputSourcesChangeEvent> event = + XRInputSourcesChangeEvent::Constructor(aSession, + u"inputsourceschange"_ns, init); + + event->SetTrusted(true); + aSession->DispatchEvent(*event); + } +} + +void XRInputSourceArray::Clear(XRSession* aSession) { + DispatchInputSourceRemovedEvent(mInputSources, aSession); + mInputSources.Clear(); +} + +uint32_t XRInputSourceArray::Length() { return mInputSources.Length(); } + +XRInputSource* XRInputSourceArray::IndexedGetter(uint32_t aIndex, + bool& aFound) { + aFound = aIndex < mInputSources.Length(); + if (!aFound) { + return nullptr; + } + return mInputSources[aIndex]; +} + +} // namespace mozilla::dom |