Bug 1523351 - Part 1: GamepadTouch and GamepadLightIndicator WebAPI implementation. r=baku
☠☠ backed out by 4c4c08d01af4 ☠ ☠
authorDaosheng Mu <daoshengmu@gmail.com>
Thu, 23 May 2019 05:36:31 +0000
changeset 476117 cac2a77abd09be11842b55ab042e3662e5fa43df
parent 476116 b860b13c8eae8d8eeb363c21f2aa3c1430e0301b
child 476118 053540f0b00a5fa9cd4edd24b11b522e847e9725
push id36086
push usershindli@mozilla.com
push dateThu, 30 May 2019 03:47:55 +0000
treeherdermozilla-central@73c98da145a7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1523351
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1523351 - Part 1: GamepadTouch and GamepadLightIndicator WebAPI implementation. r=baku Differential Revision: https://phabricator.services.mozilla.com/D20744
dom/gamepad/Gamepad.cpp
dom/gamepad/Gamepad.h
dom/gamepad/GamepadLightIndicator.cpp
dom/gamepad/GamepadLightIndicator.h
dom/gamepad/GamepadTouch.cpp
dom/gamepad/GamepadTouch.h
dom/gamepad/GamepadTouchState.h
dom/gamepad/moz.build
dom/tests/mochitest/general/test_interfaces.js
dom/webidl/Gamepad.webidl
dom/webidl/GamepadLightIndicator.webidl
dom/webidl/GamepadTouch.webidl
dom/webidl/moz.build
modules/libpref/init/StaticPrefList.h
modules/libpref/init/all.js
--- a/dom/gamepad/Gamepad.cpp
+++ b/dom/gamepad/Gamepad.cpp
@@ -17,52 +17,63 @@ 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)
+                                      mHapticActuators, mLightIndicators,
+                                      mTouchEvents)
 
 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)
+                 uint32_t aNumAxes, uint32_t aNumHaptics,
+                 uint32_t aNumLightIndicator, uint32_t aNumTouchEvents)
     : mParent(aParent),
       mID(aID),
       mIndex(aIndex),
       mHashKey(aHashKey),
       mDisplayId(aDisplayID),
+      mTouchIdHashValue(0),
       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));
   }
+  for (uint32_t i = 0; i < aNumLightIndicator; ++i) {
+    mLightIndicators.AppendElement(
+        new GamepadLightIndicator(mParent, mHashKey, i));
+  }
+  for (uint32_t i = 0; i < aNumTouchEvents; ++i) {
+    mTouchEvents.AppendElement(new GamepadTouch(mParent));
+  }
+
   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,
@@ -83,21 +94,45 @@ void Gamepad::SetAxis(uint32_t aAxis, do
   UpdateTimestamp();
 }
 
 void Gamepad::SetPose(const GamepadPoseState& aPose) {
   mPose->SetPoseState(aPose);
   UpdateTimestamp();
 }
 
+void Gamepad::SetLightIndicatorType(uint32_t aLightIndex,
+                                    GamepadLightIndicatorType aType) {
+  mLightIndicators[aLightIndex]->SetType(aType);
+  UpdateTimestamp();
+}
+
+void Gamepad::SetTouchEvent(uint32_t aTouchIndex,
+                            const GamepadTouchState& aTouch) {
+  if (aTouchIndex >= mTouchEvents.Length()) {
+    MOZ_CRASH("Touch index exceeds the event array.");
+    return;
+  }
+
+  // Handling cross-origin tracking.
+  GamepadTouchState touchState(aTouch);
+  if (auto hashValue = mTouchIdHash.GetValue(touchState.touchId)) {
+    touchState.touchId = *hashValue;
+  } else {
+    touchState.touchId = mTouchIdHashValue;
+    mTouchIdHash.Put(aTouch.touchId, mTouchIdHashValue);
+    ++mTouchIdHashValue;
+  }
+  mTouchEvents[aTouchIndex]->SetTouchState(touchState);
+  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());
@@ -109,32 +144,44 @@ void Gamepad::SyncState(Gamepad* aOther)
   for (uint32_t i = 0; i < mAxes.Length(); ++i) {
     changed = changed || (mAxes[i] != aOther->mAxes[i]);
     mAxes[i] = aOther->mAxes[i];
   }
   if (changed) {
     Gamepad_Binding::ClearCachedAxesValue(this);
   }
 
-  if (Preferences::GetBool(kGamepadExtEnabledPref)) {
+  if (StaticPrefs::dom_gamepad_extensions_enabled()) {
     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]);
     }
+
+    if (StaticPrefs::dom_gamepad_extensions_lightindicator()) {
+      for (uint32_t i = 0; i < mLightIndicators.Length(); ++i) {
+        mLightIndicators[i]->Set(aOther->mLightIndicators[i]);
+      }
+    }
+    if (StaticPrefs::dom_gamepad_extensions_multitouch()) {
+      for (uint32_t i = 0; i < mTouchEvents.Length(); ++i) {
+        mTouchEvents[i]->Set(aOther->mTouchEvents[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());
+                  mButtons.Length(), mAxes.Length(), mHapticActuators.Length(),
+                  mLightIndicators.Length(), mTouchEvents.Length());
   out->SyncState(this);
   return out.forget();
 }
 
 /* virtual */
 JSObject* Gamepad::WrapObject(JSContext* aCx,
                               JS::Handle<JSObject*> aGivenProto) {
   return Gamepad_Binding::Wrap(aCx, this, aGivenProto);
--- a/dom/gamepad/Gamepad.h
+++ b/dom/gamepad/Gamepad.h
@@ -7,16 +7,18 @@
 #ifndef mozilla_dom_gamepad_Gamepad_h
 #define mozilla_dom_gamepad_Gamepad_h
 
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/GamepadBinding.h"
 #include "mozilla/dom/GamepadButton.h"
 #include "mozilla/dom/GamepadPose.h"
 #include "mozilla/dom/GamepadHapticActuator.h"
+#include "mozilla/dom/GamepadLightIndicator.h"
+#include "mozilla/dom/GamepadTouch.h"
 #include "mozilla/dom/Performance.h"
 #include <stdint.h>
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 
 namespace mozilla {
@@ -35,26 +37,30 @@ const int kLeftStickYAxis = 1;
 const int kRightStickXAxis = 2;
 const int kRightStickYAxis = 3;
 
 class Gamepad final : public nsISupports, public nsWrapperCache {
  public:
   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);
+          uint32_t aNumHaptics, uint32_t aNumLightIndicator,
+          uint32_t aNumTouchEvents);
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Gamepad)
 
   void SetConnected(bool aConnected);
   void SetButton(uint32_t aButton, bool aPressed, bool aTouched, double aValue);
   void SetAxis(uint32_t aAxis, double aValue);
   void SetIndex(uint32_t aIndex);
   void SetPose(const GamepadPoseState& aPose);
+  void SetLightIndicatorType(uint32_t aLightIndex,
+                             GamepadLightIndicatorType aType);
+  void SetTouchEvent(uint32_t aTouchIndex, const GamepadTouchState& aTouch);
   void SetHand(GamepadHand aHand);
 
   // Make the state of this gamepad equivalent to other.
   void SyncState(Gamepad* aOther);
 
   // Return a new Gamepad containing the same data as this object,
   // parented to aParent.
   already_AddRefed<Gamepad> Clone(nsISupports* aParent);
@@ -88,38 +94,51 @@ class Gamepad final : public nsISupports
 
   GamepadPose* GetPose() const { return mPose; }
 
   void GetHapticActuators(
       nsTArray<RefPtr<GamepadHapticActuator>>& aHapticActuators) const {
     aHapticActuators = mHapticActuators;
   }
 
+  void GetLightIndicators(
+      nsTArray<RefPtr<GamepadLightIndicator>>& aLightIndicators) const {
+    aLightIndicators = mLightIndicators;
+  }
+
+  void GetTouchEvents(nsTArray<RefPtr<GamepadTouch>>& aTouchEvents) const {
+    aTouchEvents = mTouchEvents;
+  }
+
  private:
   virtual ~Gamepad() {}
   void UpdateTimestamp();
 
  protected:
   nsCOMPtr<nsISupports> mParent;
   nsString mID;
   uint32_t mIndex;
   // the gamepad hash key in GamepadManager
   uint32_t mHashKey;
   uint32_t mDisplayId;
+  uint32_t mTouchIdHashValue;
   // The mapping in use.
   GamepadMappingType mMapping;
   GamepadHand mHand;
 
   // true if this gamepad is currently connected.
   bool mConnected;
 
   // Current state of buttons, axes.
   nsTArray<RefPtr<GamepadButton>> mButtons;
   nsTArray<double> mAxes;
   DOMHighResTimeStamp mTimestamp;
   RefPtr<GamepadPose> mPose;
   nsTArray<RefPtr<GamepadHapticActuator>> mHapticActuators;
+  nsTArray<RefPtr<GamepadLightIndicator>> mLightIndicators;
+  nsTArray<RefPtr<GamepadTouch>> mTouchEvents;
+  nsDataHashtable<nsUint32HashKey, uint32_t> mTouchIdHash;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
 #endif  // mozilla_dom_gamepad_Gamepad_h
new file mode 100644
--- /dev/null
+++ b/dom/gamepad/GamepadLightIndicator.cpp
@@ -0,0 +1,69 @@
+/* -*- 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/GamepadLightIndicator.h"
+#include "mozilla/dom/GamepadManager.h"
+#include "mozilla/dom/Promise.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(GamepadLightIndicator)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(GamepadLightIndicator)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GamepadLightIndicator)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GamepadLightIndicator, mParent)
+
+GamepadLightIndicator::GamepadLightIndicator(nsISupports* aParent,
+                                             uint32_t aGamepadId,
+                                             uint32_t aIndex)
+    : mParent(aParent),
+      mType(DefaultType()),
+      mGamepadId(aGamepadId),
+      mIndex(aIndex) {}
+
+GamepadLightIndicator::~GamepadLightIndicator() {
+  mozilla::DropJSObjects(this);
+}
+
+/* virtual */ JSObject* GamepadLightIndicator::WrapObject(
+    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
+  return GamepadLightIndicator_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+nsISupports* GamepadLightIndicator::GetParentObject() const { return mParent; }
+
+already_AddRefed<Promise> GamepadLightIndicator::SetColor(
+    const GamepadLightColor& color, ErrorResult& aRv) {
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
+  MOZ_ASSERT(global);
+
+  RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
+  MOZ_ASSERT(gamepadManager);
+
+  RefPtr<Promise> promise = gamepadManager->SetLightIndicatorColor(
+      mGamepadId, mIndex, color.mRed, color.mGreen, color.mBlue, global, aRv);
+  if (!promise) {
+    return nullptr;
+  }
+  return promise.forget();
+}
+
+GamepadLightIndicatorType GamepadLightIndicator::Type() const { return mType; }
+
+void GamepadLightIndicator::Set(const GamepadLightIndicator* aOther) {
+  MOZ_ASSERT(aOther);
+  mGamepadId = aOther->mGamepadId;
+  mType = aOther->mType;
+  mIndex = aOther->mIndex;
+}
+
+}  // namespace dom
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/gamepad/GamepadLightIndicator.h
@@ -0,0 +1,53 @@
+/* -*- 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/. */
+
+#ifndef mozilla_dom_gamepad_GamepadLightIndicator_h
+#define mozilla_dom_gamepad_GamepadLightIndicator_h
+
+#include "mozilla/dom/GamepadLightIndicatorBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+class GamepadLightIndicator final : public nsISupports, public nsWrapperCache {
+ public:
+  GamepadLightIndicator(nsISupports* aParent, uint32_t aGamepadId,
+                        uint32_t aIndex);
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GamepadLightIndicator)
+
+  static GamepadLightIndicatorType DefaultType() {
+    return GamepadLightIndicatorType::Rgb;
+  }
+
+  nsISupports* GetParentObject() const;
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
+  already_AddRefed<Promise> SetColor(const GamepadLightColor& color,
+                                     ErrorResult& aRv);
+
+  void SetType(GamepadLightIndicatorType aType) { mType = aType; }
+
+  GamepadLightIndicatorType Type() const;
+
+  void Set(const GamepadLightIndicator* aOther);
+
+ private:
+  virtual ~GamepadLightIndicator();
+
+  nsCOMPtr<nsISupports> mParent;
+  GamepadLightIndicatorType mType;
+  uint32_t mGamepadId;
+  uint32_t mIndex;
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif  // mozilla_dom_gamepad_GamepadLightIndicator_h
new file mode 100644
--- /dev/null
+++ b/dom/gamepad/GamepadTouch.cpp
@@ -0,0 +1,87 @@
+/* -*- 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/GamepadTouch.h"
+#include "mozilla/dom/GamepadManager.h"
+#include "mozilla/dom/Promise.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(GamepadTouch)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(GamepadTouch)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+  tmp->mPosition = nullptr;
+  tmp->mSurfaceDimensions = nullptr;
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(GamepadTouch)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(GamepadTouch)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mPosition)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mSurfaceDimensions)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(GamepadTouch, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(GamepadTouch, Release)
+
+GamepadTouch::GamepadTouch(nsISupports* aParent)
+    : mParent(aParent), mPosition(nullptr), mSurfaceDimensions(nullptr) {
+  mozilla::HoldJSObjects(this);
+  mTouchState = GamepadTouchState();
+}
+
+GamepadTouch::~GamepadTouch() { mozilla::DropJSObjects(this); }
+
+/* virtual */ JSObject* GamepadTouch::WrapObject(
+    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
+  return GamepadTouch_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+void GamepadTouch::GetPosition(JSContext* aCx,
+                               JS::MutableHandle<JSObject*> aRetval,
+                               ErrorResult& aRv) {
+  mPosition = Float32Array::Create(aCx, this, 2, mTouchState.position);
+  if (!mPosition) {
+    aRv.NoteJSContextException(aCx);
+    return;
+  }
+
+  aRetval.set(mPosition);
+}
+
+void GamepadTouch::GetSurfaceDimensions(JSContext* aCx,
+                                        JS::MutableHandle<JSObject*> aRetval,
+                                        ErrorResult& aRv) {
+  mSurfaceDimensions = Uint32Array::Create(aCx, this, 2,
+                                           mTouchState.isSurfaceDimensionsValid
+                                               ? mTouchState.surfaceDimensions
+                                               : nullptr);
+
+  if (!mSurfaceDimensions) {
+    aRv.NoteJSContextException(aCx);
+    return;
+  }
+
+  aRetval.set(mSurfaceDimensions);
+}
+
+void GamepadTouch::SetTouchState(const GamepadTouchState& aTouch) {
+  mTouchState = aTouch;
+}
+
+void GamepadTouch::Set(const GamepadTouch* aOther) {
+  MOZ_ASSERT(aOther);
+  mTouchState = aOther->mTouchState;
+}
+
+}  // namespace dom
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/gamepad/GamepadTouch.h
@@ -0,0 +1,48 @@
+/* -*- 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/. */
+
+#ifndef mozilla_dom_gamepad_GamepadTouch_h
+#define mozilla_dom_gamepad_GamepadTouch_h
+
+#include "mozilla/dom/GamepadTouchBinding.h"
+#include "mozilla/dom/GamepadTouchState.h"
+
+namespace mozilla {
+namespace dom {
+
+class GamepadTouch final : public nsWrapperCache {
+ public:
+  explicit GamepadTouch(nsISupports* aParent);
+
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(GamepadTouch)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(GamepadTouch)
+
+  nsISupports* GetParentObject() const { return mParent; }
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+  uint32_t TouchId() const { return mTouchState.touchId; }
+  uint32_t SurfaceId() const { return mTouchState.surfaceId; }
+  void GetPosition(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval,
+                   ErrorResult& aRv);
+  void GetSurfaceDimensions(JSContext* aCx,
+                            JS::MutableHandle<JSObject*> aRetval,
+                            ErrorResult& aRv);
+  void SetTouchState(const GamepadTouchState& aTouch);
+  void Set(const GamepadTouch* aOther);
+
+ private:
+  virtual ~GamepadTouch();
+
+  nsCOMPtr<nsISupports> mParent;
+  JS::Heap<JSObject*> mPosition;
+  JS::Heap<JSObject*> mSurfaceDimensions;
+  GamepadTouchState mTouchState;
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif  // mozilla_dom_gamepad_GamepadTouch_h
new file mode 100644
--- /dev/null
+++ b/dom/gamepad/GamepadTouchState.h
@@ -0,0 +1,44 @@
+/* -*- 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/. */
+
+#ifndef mozilla_dom_gamepad_GamepadTouchState_h_
+#define mozilla_dom_gamepad_GamepadTouchState_h_
+
+namespace mozilla {
+namespace dom {
+
+struct GamepadTouchState {
+  uint32_t touchId;
+  uint32_t surfaceId;
+  float position[2];
+  uint32_t surfaceDimensions[2];
+  bool isSurfaceDimensionsValid;
+
+  GamepadTouchState()
+      : touchId(0),
+        surfaceId(0),
+        position{0, 0},
+        surfaceDimensions{0, 0},
+        isSurfaceDimensionsValid(false) {}
+
+  bool operator==(const GamepadTouchState& aTouch) const {
+    return touchId == aTouch.touchId && touchId == aTouch.touchId &&
+           surfaceId == aTouch.surfaceId && position[0] == aTouch.position[0] &&
+           position[1] == aTouch.position[1] &&
+           surfaceDimensions[0] == aTouch.surfaceDimensions[0] &&
+           surfaceDimensions[1] == aTouch.surfaceDimensions[1] &&
+           isSurfaceDimensionsValid == aTouch.isSurfaceDimensionsValid;
+  }
+
+  bool operator!=(const GamepadTouchState& aTouch) const {
+    return !(*this == aTouch);
+  }
+};
+
+}  // namespace dom
+}  // namespace mozilla
+
+#endif  // mozilla_dom_gamepad_GamepadTouchState_h_
--- a/dom/gamepad/moz.build
+++ b/dom/gamepad/moz.build
@@ -12,41 +12,46 @@ IPDL_SOURCES += [
     'ipc/PGamepadEventChannel.ipdl',
     'ipc/PGamepadTestChannel.ipdl'
 ]
 
 EXPORTS.mozilla.dom += [
     'Gamepad.h',
     'GamepadButton.h',
     'GamepadHapticActuator.h',
+    'GamepadLightIndicator.h',
     'GamepadManager.h',
     'GamepadMonitoring.h',
     'GamepadPlatformService.h',
     'GamepadPose.h',
     'GamepadPoseState.h',
     'GamepadRemapping.h',
     'GamepadServiceTest.h',
+    'GamepadTouch.h',
+    'GamepadTouchState.h',
     'ipc/GamepadEventChannelChild.h',
     'ipc/GamepadEventChannelParent.h',
     'ipc/GamepadMessageUtils.h',
     'ipc/GamepadServiceType.h',
     'ipc/GamepadTestChannelChild.h',
     'ipc/GamepadTestChannelParent.h'
 ]
 
 UNIFIED_SOURCES = [
     'Gamepad.cpp',
     'GamepadButton.cpp',
     'GamepadHapticActuator.cpp',
+    'GamepadLightIndicator.cpp',
     'GamepadManager.cpp',
     'GamepadMonitoring.cpp',
     'GamepadPlatformService.cpp',
     'GamepadPose.cpp',
     'GamepadRemapping.cpp',
     'GamepadServiceTest.cpp',
+    'GamepadTouch.cpp',
     'ipc/GamepadEventChannelChild.cpp',
     'ipc/GamepadEventChannelParent.cpp',
     'ipc/GamepadTestChannelChild.cpp',
     'ipc/GamepadTestChannelParent.cpp'
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     UNIFIED_SOURCES += [
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -387,18 +387,22 @@ var interfaceNamesInGlobalScope =
     {name: "GamepadButtonEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "GamepadButton", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "GamepadEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "GamepadHapticActuator", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "GamepadLightIndicator", insecureContext: false, disabled: true},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "GamepadPose", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "GamepadTouch", insecureContext: false, disabled: true},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "HashChangeEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Headers", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "History", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "HTMLAllCollection", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/Gamepad.webidl
+++ b/dom/webidl/Gamepad.webidl
@@ -91,9 +91,15 @@ interface Gamepad {
   readonly attribute GamepadPose? pose;
 
   /**
    * The current haptic actuator of the device, an array of
    * GamepadHapticActuator.
    */
   [Constant, Cached, Frozen, Pref="dom.gamepad.extensions.enabled"]
   readonly attribute sequence<GamepadHapticActuator> hapticActuators;
+
+  [Constant, Cached, Frozen, Pref="dom.gamepad.extensions.enabled", Pref="dom.gamepad.extensions.lightindicator"]
+  readonly attribute sequence<GamepadLightIndicator> lightIndicators;
+
+  [Constant, Cached, Frozen, Pref="dom.gamepad.extensions.enabled", Pref="dom.gamepad.extensions.multitouch"]
+  readonly attribute sequence<GamepadTouch> touchEvents;
 };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/GamepadLightIndicator.webidl
@@ -0,0 +1,27 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * The origin of this IDL file is
+ * https://github.com/knyg/gamepad/blob/lightindicator/extensions.html
+ */
+
+enum GamepadLightIndicatorType {
+  "on-off",
+  "rgb"
+};
+
+dictionary GamepadLightColor {
+  required octet red;
+  required octet green;
+  required octet blue;
+};
+
+[SecureContext, Pref="dom.gamepad.extensions.lightindicator"]
+interface GamepadLightIndicator
+{
+  readonly attribute GamepadLightIndicatorType type;
+  [Throws, NewObject]
+  Promise<boolean> setColor(GamepadLightColor color);
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/GamepadTouch.webidl
@@ -0,0 +1,16 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ *
+ * The origin of this IDL file is
+ * https://github.com/knyg/gamepad/blob/multitouch/extensions.html
+ */
+
+[SecureContext, Pref="dom.gamepad.extensions.multitouch"]
+interface GamepadTouch {
+  readonly attribute unsigned long touchId;
+  readonly attribute octet surfaceId;
+  [Constant, Throws] readonly attribute Float32Array position;
+  [Constant, Throws] readonly attribute Uint32Array? surfaceDimensions;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -514,18 +514,20 @@ WEBIDL_FILES = [
     'FontFaceSet.webidl',
     'FontFaceSource.webidl',
     'FormData.webidl',
     'FrameLoader.webidl',
     'Function.webidl',
     'GainNode.webidl',
     'Gamepad.webidl',
     'GamepadHapticActuator.webidl',
+    'GamepadLightIndicator.webidl',
     'GamepadPose.webidl',
     'GamepadServiceTest.webidl',
+    'GamepadTouch.webidl',
     'Geolocation.webidl',
     'GeometryUtils.webidl',
     'GetUserMediaRequest.webidl',
     'Grid.webidl',
     'Headers.webidl',
     'History.webidl',
     'HTMLAllCollection.webidl',
     'HTMLAnchorElement.webidl',
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -1211,16 +1211,44 @@ VARCACHE_PREF(
 
 VARCACHE_PREF(
   Live,
   "dom.ipc.plugins.asyncdrawing.enabled",
   PluginAsyncDrawingEnabled,
   RelaxedAtomicBool, false
 )
 
+// Is Gamepad Extension API enabled?
+VARCACHE_PREF(
+  "dom.gamepad.extensions.enabled",
+   dom_gamepad_extensions_enabled,
+   bool, true
+)
+
+// Is LightIndcator API enabled in Gamepad Extension API?
+VARCACHE_PREF(
+  "dom.gamepad.extensions.lightindicator",
+   dom_gamepad_extensions_lightindicator,
+   bool, false
+)
+
+// Is MultiTouch API enabled in Gamepad Extension API?
+VARCACHE_PREF(
+  "dom.gamepad.extensions.multitouch",
+   dom_gamepad_extensions_multitouch,
+   bool, false
+)
+
+// Is Gamepad vibrate haptic feedback function enabled?
+VARCACHE_PREF(
+  "dom.gamepad.haptic_feedback.enabled",
+   dom_gamepad_haptic_feedback_enabled,
+   bool, true
+)
+
 // How long a content process can take before closing its IPC channel
 // after shutdown is initiated.  If the process exceeds the timeout,
 // we fear the worst and kill it.
 #if !defined(DEBUG) && !defined(MOZ_ASAN) && !defined(MOZ_VALGRIND) && \
     !defined(MOZ_TSAN)
 # define PREF_VALUE 5
 #else
 # define PREF_VALUE 0
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -178,18 +178,16 @@ pref("dom.pointer-lock.enabled", true);
 // Whether the Gamepad API is enabled
 pref("dom.gamepad.enabled", true);
 pref("dom.gamepad.test.enabled", false);
 #ifdef RELEASE_OR_BETA
 pref("dom.gamepad.non_standard_events.enabled", false);
 #else
 pref("dom.gamepad.non_standard_events.enabled", true);
 #endif
-pref("dom.gamepad.extensions.enabled", true);
-pref("dom.gamepad.haptic_feedback.enabled", true);
 
 // If this is true, TextEventDispatcher dispatches keydown and keyup events
 // even during composition (keypress events are never fired during composition
 // even if this is true).
 pref("dom.keyboardevent.dispatch_during_composition", true);
 
 // If this is true, TextEventDispatcher dispatches keypress event with setting
 // WidgetEvent::mFlags::mOnlySystemGroupDispatchInContent to true if it won't