dom/gamepad/Gamepad.cpp
author moz-wptsync-bot <wptsync@mozilla.com>
Mon, 16 Apr 2018 18:38:41 +0000
changeset 1486024 3a644abd5eaa108f67471c0aae4fb4a424ea41bf
parent 1189488 7e194151d3691e523b1ba9d7a02e71915f06b1f9
child 1252009 ac9e0a05c85d7c5a5902b82ba74cd3f71e625f73
child 1336492 46ef8bf6c68664b27953e4680747da7a985c30b2
child 1343097 98e2b4ee9775a2a2b5cc1bb8a390bfe901814f38
child 1398386 80ed235cff6a319ed3171c949f352a5d6e41726e
child 1547991 2e3d3bb50080527d56ca81397960dfd520270f45
permissions -rw-r--r--
Bug 1454380 [wpt PR 8508] - Update wpt metadata, a=testonly wpt-pr: 8508 wpt-type: metadata

/* -*- 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 "Gamepad.h"
#include "nsPIDOMWindow.h"
#include "nsTArray.h"
#include "nsVariant.h"
#include "mozilla/dom/GamepadBinding.h"

namespace mozilla {
namespace dom {

NS_IMPL_CYCLE_COLLECTING_ADDREF(Gamepad)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Gamepad)

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Gamepad)
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Gamepad, mParent, mButtons, mPose,
                                      mHapticActuators)

void
Gamepad::UpdateTimestamp()
{
  nsCOMPtr<nsPIDOMWindowInner> newWindow(do_QueryInterface(mParent));
  if(newWindow) {
    Performance* perf = newWindow->GetPerformance();
    if (perf) {
      mTimestamp = perf->Now();
    }
  }
}

Gamepad::Gamepad(nsISupports* aParent,
                 const nsAString& aID, uint32_t aIndex,
                 uint32_t aHashKey,
                 GamepadMappingType aMapping,
                 GamepadHand aHand,
                 uint32_t aDisplayID, uint32_t aNumButtons,
                 uint32_t aNumAxes, uint32_t aNumHaptics)
  : mParent(aParent),
    mID(aID),
    mIndex(aIndex),
    mHashKey(aHashKey),
    mDisplayId(aDisplayID),
    mMapping(aMapping),
    mHand(aHand),
    mConnected(true),
    mButtons(aNumButtons),
    mAxes(aNumAxes),
    mTimestamp(0)
{
  for (unsigned i = 0; i < aNumButtons; i++) {
    mButtons.InsertElementAt(i, new GamepadButton(mParent));
  }
  mAxes.InsertElementsAt(0, aNumAxes, 0.0f);
  mPose = new GamepadPose(aParent);
  for (uint32_t i = 0; i < aNumHaptics; ++i) {
    mHapticActuators.AppendElement(new GamepadHapticActuator(mParent, mHashKey, i));
  }
  UpdateTimestamp();
}

void
Gamepad::SetIndex(uint32_t aIndex)
{
  mIndex = aIndex;
}

void
Gamepad::SetConnected(bool aConnected)
{
  mConnected = aConnected;
}

void
Gamepad::SetButton(uint32_t aButton, bool aPressed,
                   bool aTouched, double aValue)
{
  MOZ_ASSERT(aButton < mButtons.Length());
  mButtons[aButton]->SetPressed(aPressed);
  mButtons[aButton]->SetTouched(aTouched);
  mButtons[aButton]->SetValue(aValue);
  UpdateTimestamp();
}

void
Gamepad::SetAxis(uint32_t aAxis, double aValue)
{
  MOZ_ASSERT(aAxis < mAxes.Length());
  if (mAxes[aAxis] != aValue) {
    mAxes[aAxis] = aValue;
    GamepadBinding::ClearCachedAxesValue(this);
  }
  UpdateTimestamp();
}

void
Gamepad::SetPose(const GamepadPoseState& aPose)
{
  mPose->SetPoseState(aPose);
  UpdateTimestamp();
}

void
Gamepad::SetHand(GamepadHand aHand)
{
  mHand = aHand;
}

void
Gamepad::SyncState(Gamepad* aOther)
{
  const char* kGamepadExtEnabledPref = "dom.gamepad.extensions.enabled";

  if (mButtons.Length() != aOther->mButtons.Length() ||
      mAxes.Length() != aOther->mAxes.Length()) {
    return;
  }

  mConnected = aOther->mConnected;
  for (uint32_t i = 0; i < mButtons.Length(); ++i) {
    mButtons[i]->SetPressed(aOther->mButtons[i]->Pressed());
    mButtons[i]->SetTouched(aOther->mButtons[i]->Touched());
    mButtons[i]->SetValue(aOther->mButtons[i]->Value());
  }

  bool changed = false;
  for (uint32_t i = 0; i < mAxes.Length(); ++i) {
    changed = changed || (mAxes[i] != aOther->mAxes[i]);
    mAxes[i] = aOther->mAxes[i];
  }
  if (changed) {
    GamepadBinding::ClearCachedAxesValue(this);
  }

  if (Preferences::GetBool(kGamepadExtEnabledPref)) {
    MOZ_ASSERT(aOther->GetPose());
    mPose->SetPoseState(aOther->GetPose()->GetPoseState());
    mHand = aOther->Hand();
    for (uint32_t i = 0; i < mHapticActuators.Length(); ++i) {
      mHapticActuators[i]->Set(aOther->mHapticActuators[i]);
    }
  }

  UpdateTimestamp();
}

already_AddRefed<Gamepad>
Gamepad::Clone(nsISupports* aParent)
{
  RefPtr<Gamepad> out =
    new Gamepad(aParent, mID, mIndex, mHashKey, mMapping,
                mHand, mDisplayId, mButtons.Length(), mAxes.Length(),
                mHapticActuators.Length());
  out->SyncState(this);
  return out.forget();
}

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

} // namespace dom
} // namespace mozilla