tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Gamepad.cpp (6782B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "Gamepad.h"
      8 
      9 #include "mozilla/StaticPrefs_dom.h"
     10 #include "mozilla/dom/GamepadBinding.h"
     11 #include "nsPIDOMWindow.h"
     12 #include "nsTArray.h"
     13 #include "nsVariant.h"
     14 
     15 namespace mozilla::dom {
     16 
     17 NS_IMPL_CYCLE_COLLECTING_ADDREF(Gamepad)
     18 NS_IMPL_CYCLE_COLLECTING_RELEASE(Gamepad)
     19 
     20 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Gamepad)
     21  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     22  NS_INTERFACE_MAP_ENTRY(nsISupports)
     23 NS_INTERFACE_MAP_END
     24 
     25 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Gamepad, mParent, mButtons, mPose,
     26                                      mHapticActuators, mLightIndicators,
     27                                      mTouchEvents)
     28 
     29 void Gamepad::UpdateTimestamp() {
     30  nsCOMPtr<nsPIDOMWindowInner> newWindow(do_QueryInterface(mParent));
     31  if (newWindow) {
     32    Performance* perf = newWindow->GetPerformance();
     33    if (perf) {
     34      mTimestamp = perf->Now();
     35    }
     36  }
     37 }
     38 
     39 Gamepad::Gamepad(nsISupports* aParent, const nsAString& aID, int32_t aIndex,
     40                 GamepadHandle aHandle, GamepadMappingType aMapping,
     41                 GamepadHand aHand, uint32_t aNumButtons, uint32_t aNumAxes,
     42                 uint32_t aNumHaptics, uint32_t aNumLightIndicator,
     43                 uint32_t aNumTouchEvents)
     44    : mParent(aParent),
     45      mID(aID),
     46      mIndex(aIndex),
     47      mHandle(aHandle),
     48      mTouchIdHashValue(0),
     49      mMapping(aMapping),
     50      mHand(aHand),
     51      mConnected(true),
     52      mButtons(aNumButtons),
     53      mAxes(aNumAxes),
     54      mTimestamp(0) {
     55  for (unsigned i = 0; i < aNumButtons; i++) {
     56    mButtons.InsertElementAt(i, new GamepadButton(mParent));
     57  }
     58  mAxes.InsertElementsAt(0, aNumAxes, 0.0f);
     59  mPose = new GamepadPose(aParent);
     60  for (uint32_t i = 0; i < aNumHaptics; ++i) {
     61    mHapticActuators.AppendElement(
     62        new GamepadHapticActuator(mParent, mHandle, i));
     63  }
     64  for (uint32_t i = 0; i < aNumLightIndicator; ++i) {
     65    mLightIndicators.AppendElement(
     66        new GamepadLightIndicator(mParent, mHandle, i));
     67  }
     68  for (uint32_t i = 0; i < aNumTouchEvents; ++i) {
     69    mTouchEvents.AppendElement(new GamepadTouch(mParent));
     70  }
     71 
     72  // Mapping touchId(0) to touchIdHash(0) by default.
     73  mTouchIdHash.InsertOrUpdate(0, mTouchIdHashValue);
     74  ++mTouchIdHashValue;
     75  UpdateTimestamp();
     76 }
     77 
     78 void Gamepad::SetIndex(int32_t aIndex) { mIndex = aIndex; }
     79 
     80 void Gamepad::SetConnected(bool aConnected) { mConnected = aConnected; }
     81 
     82 void Gamepad::SetButton(uint32_t aButton, bool aPressed, bool aTouched,
     83                        double aValue) {
     84  // Until we fix the synchronization errors in Bug 1682554, this can be
     85  // called with a stale index that might overflow. In such a case, we silently
     86  // ignore it.
     87  if (aButton >= mButtons.Length()) {
     88    return;
     89  }
     90  mButtons[aButton]->SetPressed(aPressed);
     91  mButtons[aButton]->SetTouched(aTouched);
     92  mButtons[aButton]->SetValue(aValue);
     93  UpdateTimestamp();
     94 }
     95 
     96 void Gamepad::SetAxis(uint32_t aAxis, double aValue) {
     97  // Until we fix the synchronization errors in Bug 1682554, this can be
     98  // called with a stale index that might overflow. In such a case, we silently
     99  // ignore it.
    100  if (aAxis >= mAxes.Length()) {
    101    return;
    102  }
    103 
    104  if (mAxes[aAxis] != aValue) {
    105    mAxes[aAxis] = aValue;
    106    Gamepad_Binding::ClearCachedAxesValue(this);
    107  }
    108  UpdateTimestamp();
    109 }
    110 
    111 void Gamepad::SetPose(const GamepadPoseState& aPose) {
    112  mPose->SetPoseState(aPose);
    113  UpdateTimestamp();
    114 }
    115 
    116 void Gamepad::SetLightIndicatorType(uint32_t aLightIndex,
    117                                    GamepadLightIndicatorType aType) {
    118  // Until we fix the synchronization errors in Bug 1682554, this can be
    119  // called with a stale index that might overflow. In such a case, we silently
    120  // ignore it.
    121  if (aLightIndex >= mLightIndicators.Length()) {
    122    return;
    123  }
    124 
    125  mLightIndicators[aLightIndex]->SetType(aType);
    126  UpdateTimestamp();
    127 }
    128 
    129 void Gamepad::SetTouchEvent(uint32_t aTouchIndex,
    130                            const GamepadTouchState& aTouch) {
    131  // Until we fix the synchronization errors in Bug 1682554, this can be
    132  // called with a stale index that might overflow. In such a case, we silently
    133  // ignore it.
    134  if (aTouchIndex >= mTouchEvents.Length()) {
    135    return;
    136  }
    137 
    138  // Handling cross-origin tracking.
    139  GamepadTouchState touchState(aTouch);
    140  touchState.touchId = mTouchIdHash.LookupOrInsertWith(
    141      touchState.touchId, [&] { return mTouchIdHashValue++; });
    142  mTouchEvents[aTouchIndex]->SetTouchState(touchState);
    143  UpdateTimestamp();
    144 }
    145 
    146 void Gamepad::SetHand(GamepadHand aHand) { mHand = aHand; }
    147 
    148 void Gamepad::SyncState(Gamepad* aOther) {
    149  if (mButtons.Length() != aOther->mButtons.Length() ||
    150      mAxes.Length() != aOther->mAxes.Length()) {
    151    return;
    152  }
    153 
    154  mConnected = aOther->mConnected;
    155  for (uint32_t i = 0; i < mButtons.Length(); ++i) {
    156    mButtons[i]->SetPressed(aOther->mButtons[i]->Pressed());
    157    mButtons[i]->SetTouched(aOther->mButtons[i]->Touched());
    158    mButtons[i]->SetValue(aOther->mButtons[i]->Value());
    159  }
    160 
    161  bool changed = false;
    162  for (uint32_t i = 0; i < mAxes.Length(); ++i) {
    163    changed = changed || (mAxes[i] != aOther->mAxes[i]);
    164    mAxes[i] = aOther->mAxes[i];
    165  }
    166  if (changed) {
    167    Gamepad_Binding::ClearCachedAxesValue(this);
    168  }
    169 
    170  if (StaticPrefs::dom_gamepad_extensions_enabled()) {
    171    MOZ_ASSERT(aOther->GetPose());
    172    mPose->SetPoseState(aOther->GetPose()->GetPoseState());
    173    mHand = aOther->Hand();
    174    for (uint32_t i = 0; i < mHapticActuators.Length(); ++i) {
    175      mHapticActuators[i]->Set(aOther->mHapticActuators[i]);
    176    }
    177 
    178    if (StaticPrefs::dom_gamepad_extensions_lightindicator()) {
    179      for (uint32_t i = 0; i < mLightIndicators.Length(); ++i) {
    180        mLightIndicators[i]->Set(aOther->mLightIndicators[i]);
    181      }
    182    }
    183    if (StaticPrefs::dom_gamepad_extensions_multitouch()) {
    184      for (uint32_t i = 0; i < mTouchEvents.Length(); ++i) {
    185        mTouchEvents[i]->Set(aOther->mTouchEvents[i]);
    186      }
    187    }
    188  }
    189 
    190  UpdateTimestamp();
    191 }
    192 
    193 already_AddRefed<Gamepad> Gamepad::Clone(nsISupports* aParent) {
    194  RefPtr<Gamepad> out =
    195      new Gamepad(aParent, mID, mIndex, mHandle, mMapping, mHand,
    196                  mButtons.Length(), mAxes.Length(), mHapticActuators.Length(),
    197                  mLightIndicators.Length(), mTouchEvents.Length());
    198  out->SyncState(this);
    199  return out.forget();
    200 }
    201 
    202 /* virtual */
    203 JSObject* Gamepad::WrapObject(JSContext* aCx,
    204                              JS::Handle<JSObject*> aGivenProto) {
    205  return Gamepad_Binding::Wrap(aCx, this, aGivenProto);
    206 }
    207 
    208 }  // namespace mozilla::dom