diff options
Diffstat (limited to 'dom/gamepad/GamepadServiceTest.cpp')
-rw-r--r-- | dom/gamepad/GamepadServiceTest.cpp | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/dom/gamepad/GamepadServiceTest.cpp b/dom/gamepad/GamepadServiceTest.cpp new file mode 100644 index 000000000..a6fde58f0 --- /dev/null +++ b/dom/gamepad/GamepadServiceTest.cpp @@ -0,0 +1,283 @@ +/* -*- 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 "GamepadServiceTest.h" + +#include "mozilla/ErrorResult.h" +#include "mozilla/Unused.h" + +#include "mozilla/dom/GamepadManager.h" +#include "mozilla/dom/GamepadPlatformService.h" +#include "mozilla/dom/GamepadServiceTestBinding.h" +#include "mozilla/dom/GamepadTestChannelChild.h" + +#include "mozilla/ipc/BackgroundChild.h" +#include "mozilla/ipc/PBackgroundChild.h" + +#include "mozilla/Unused.h" + +#include "nsIObserver.h" +#include "nsIObserverService.h" + +namespace mozilla { +namespace dom { + +/* + * Implementation of the test service. This is just to provide a simple binding + * of the GamepadService to JavaScript via WebIDL so that we can write Mochitests + * that add and remove fake gamepads, avoiding the platform-specific backends. + */ + +NS_IMPL_CYCLE_COLLECTION_CLASS(GamepadServiceTest) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(GamepadServiceTest, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(GamepadServiceTest, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(GamepadServiceTest) + NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_ADDREF_INHERITED(GamepadServiceTest, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(GamepadServiceTest, DOMEventTargetHelper) + +// static +already_AddRefed<GamepadServiceTest> +GamepadServiceTest::CreateTestService(nsPIDOMWindowInner* aWindow) +{ + MOZ_ASSERT(aWindow); + RefPtr<GamepadServiceTest> service = new GamepadServiceTest(aWindow); + service->InitPBackgroundActor(); + return service.forget(); +} + +void +GamepadServiceTest::Shutdown() +{ + MOZ_ASSERT(!mShuttingDown); + mShuttingDown = true; + DestroyPBackgroundActor(); + mWindow = nullptr; +} + +GamepadServiceTest::GamepadServiceTest(nsPIDOMWindowInner* aWindow) + : mService(GamepadManager::GetService()), + mWindow(aWindow), + mEventNumber(0), + mShuttingDown(false), + mChild(nullptr) +{} + +GamepadServiceTest::~GamepadServiceTest() {} + +void +GamepadServiceTest::InitPBackgroundActor() +{ + MOZ_ASSERT(!mChild); + PBackgroundChild *actor = BackgroundChild::GetForCurrentThread(); + //Try to get the PBackground Child actor + if (actor) { + ActorCreated(actor); + } else { + Unused << BackgroundChild::GetOrCreateForCurrentThread(this); + } +} + +void +GamepadServiceTest::DestroyPBackgroundActor() +{ + if (mChild) { + // If mChild exists, which means that IPDL channel + // has been created, our pending operations should + // be empty. + MOZ_ASSERT(mPendingOperations.IsEmpty()); + mChild->SendShutdownChannel(); + mChild = nullptr; + } else { + // If the IPDL channel has not been created and we + // want to destroy it now, just cancel all pending + // operations. + mPendingOperations.Clear(); + } +} + +already_AddRefed<Promise> +GamepadServiceTest::AddGamepad(const nsAString& aID, + uint32_t aMapping, + uint32_t aNumButtons, + uint32_t aNumAxes, + ErrorResult& aRv) +{ + if (mShuttingDown) { + return nullptr; + } + + GamepadAdded a(nsString(aID), 0, + aMapping, + GamepadServiceType::Standard, + aNumButtons, aNumAxes); + GamepadChangeEvent e(a); + nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow); + + RefPtr<Promise> p = Promise::Create(go, aRv); + if (aRv.Failed()) { + return nullptr; + } + + uint32_t id = ++mEventNumber; + if (mChild) { + mChild->AddPromise(id, p); + mChild->SendGamepadTestEvent(id, e); + } else { + PendingOperation op(id, e, p); + mPendingOperations.AppendElement(op); + } + return p.forget(); +} + +void +GamepadServiceTest::RemoveGamepad(uint32_t aIndex) +{ + if (mShuttingDown) { + return; + } + + GamepadRemoved a(aIndex, GamepadServiceType::Standard); + GamepadChangeEvent e(a); + + uint32_t id = ++mEventNumber; + if (mChild) { + mChild->SendGamepadTestEvent(id, e); + } else { + PendingOperation op(id, e); + mPendingOperations.AppendElement(op); + } +} + +void +GamepadServiceTest::NewButtonEvent(uint32_t aIndex, + uint32_t aButton, + bool aPressed) +{ + if (mShuttingDown) { + return; + } + + GamepadButtonInformation a(aIndex, GamepadServiceType::Standard, + aButton, aPressed, aPressed ? 1.0 : 0); + GamepadChangeEvent e(a); + + uint32_t id = ++mEventNumber; + if (mChild) { + mChild->SendGamepadTestEvent(id, e); + } else { + PendingOperation op(id, e); + mPendingOperations.AppendElement(op); + } +} + +void +GamepadServiceTest::NewButtonValueEvent(uint32_t aIndex, + uint32_t aButton, + bool aPressed, + double aValue) +{ + if (mShuttingDown) { + return; + } + + GamepadButtonInformation a(aIndex, GamepadServiceType::Standard, + aButton, aPressed, aValue); + GamepadChangeEvent e(a); + + uint32_t id = ++mEventNumber; + if (mChild) { + mChild->SendGamepadTestEvent(id, e); + } else { + PendingOperation op(id, e); + mPendingOperations.AppendElement(op); + } +} + +void +GamepadServiceTest::NewAxisMoveEvent(uint32_t aIndex, + uint32_t aAxis, + double aValue) +{ + if (mShuttingDown) { + return; + } + + GamepadAxisInformation a(aIndex, GamepadServiceType::Standard, + aAxis, aValue); + GamepadChangeEvent e(a); + + uint32_t id = ++mEventNumber; + if (mChild) { + mChild->SendGamepadTestEvent(id, e); + } else { + PendingOperation op(id, e); + mPendingOperations.AppendElement(op); + } +} + +void +GamepadServiceTest::FlushPendingOperations() +{ + for (uint32_t i=0; i < mPendingOperations.Length(); ++i) { + PendingOperation op = mPendingOperations[i]; + if (op.mPromise) { + mChild->AddPromise(op.mID, op.mPromise); + } + mChild->SendGamepadTestEvent(op.mID, op.mEvent); + } + mPendingOperations.Clear(); +} + +void +GamepadServiceTest::ActorCreated(PBackgroundChild* aActor) +{ + MOZ_ASSERT(aActor); + // If we are shutting down, we don't need to create the + // IPDL child/parent pair anymore. + if (mShuttingDown) { + // mPendingOperations should be cleared in + // DestroyPBackgroundActor() + MOZ_ASSERT(mPendingOperations.IsEmpty()); + return; + } + + mChild = new GamepadTestChannelChild(); + PGamepadTestChannelChild* initedChild = + aActor->SendPGamepadTestChannelConstructor(mChild); + if (NS_WARN_IF(!initedChild)) { + ActorFailed(); + return; + } + FlushPendingOperations(); +} + +void +GamepadServiceTest::ActorFailed() +{ + MOZ_CRASH("Failed to create background child actor!"); +} + +JSObject* +GamepadServiceTest::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto) +{ + return GamepadServiceTestBinding::Wrap(aCx, this, aGivenProto); +} + +} // dom +} // mozilla |