Bug 1299932 - Part 1: Implement gamepadPose attribute in Gamepad API; r=kip,qdot
authorDaosheng Mu <daoshengmu@gmail.com>
Mon, 24 Oct 2016 18:04:41 +0800
changeset 322056 83adb3995ae671de06c79dc5fc615db62a08597a
parent 322055 1b48d4300536804a1a9abc4a80c33be35361ab01
child 322057 a8b7a04fa1508cac91516ff73ef114c4fd83fc31
push id21
push usermaklebus@msu.edu
push dateThu, 01 Dec 2016 06:22:08 +0000
reviewerskip, qdot
bugs1299932
milestone52.0a1
Bug 1299932 - Part 1: Implement gamepadPose attribute in Gamepad API; r=kip,qdot MozReview-Commit-ID: DiJadVc2TyE
dom/base/Pose.cpp
dom/base/Pose.h
dom/base/Timeout.cpp
dom/base/Timeout.h
dom/base/moz.build
dom/gamepad/Gamepad.cpp
dom/gamepad/Gamepad.h
dom/gamepad/GamepadPose.cpp
dom/gamepad/GamepadPose.h
dom/gamepad/GamepadPoseState.h
dom/gamepad/ipc/GamepadMessageUtils.h
dom/gamepad/moz.build
dom/tests/mochitest/general/test_interfaces.html
dom/vr/VRDisplay.cpp
dom/vr/VRDisplay.h
dom/webidl/Gamepad.webidl
dom/webidl/GamepadPose.webidl
dom/webidl/Pose.webidl
dom/webidl/VRDisplay.webidl
dom/webidl/moz.build
modules/libpref/init/all.js
new file mode 100644
--- /dev/null
+++ b/dom/base/Pose.cpp
@@ -0,0 +1,94 @@
+/* -*- 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/HoldDropJSObjects.h"
+#include "mozilla/dom/TypedArray.h"
+#include "mozilla/dom/PoseBinding.h"
+#include "mozilla/dom/Pose.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(Pose)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Pose)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+  tmp->mPosition = nullptr;
+  tmp->mLinearVelocity = nullptr;
+  tmp->mLinearAcceleration = nullptr;
+  tmp->mOrientation = nullptr;
+  tmp->mAngularVelocity = nullptr;
+  tmp->mAngularAcceleration = nullptr;
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Pose)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Pose)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mPosition)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLinearVelocity)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLinearAcceleration)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mOrientation)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAngularVelocity)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAngularAcceleration)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Pose, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Pose, Release)
+
+
+Pose::Pose(nsISupports* aParent)
+  : mParent(aParent),
+    mPosition(nullptr),
+    mLinearVelocity(nullptr),
+    mLinearAcceleration(nullptr),
+    mOrientation(nullptr),
+    mAngularVelocity(nullptr),
+    mAngularAcceleration(nullptr)
+{
+  mozilla::HoldJSObjects(this);
+}
+
+Pose::~Pose()
+{
+  mozilla::DropJSObjects(this);
+}
+
+nsISupports*
+Pose::GetParentObject() const
+{
+  return mParent;
+}
+
+void
+Pose::SetFloat32Array(JSContext* aJSContext, JS::MutableHandle<JSObject*> aRetVal,
+                      JS::Heap<JSObject*>& aObj, float* aVal, uint32_t sizeOfVal,
+                      bool bCreate, ErrorResult& aRv)
+{
+  if (bCreate) {
+    aObj = Float32Array::Create(aJSContext, this,
+                                 sizeOfVal, aVal);
+    if (!aObj) {
+      aRv.NoteJSContextException(aJSContext);
+      return;
+    }
+  }
+
+  aRetVal.set(aObj);
+}
+
+/* virtual */ JSObject*
+Pose::WrapObject(JSContext* aJSContext, JS::Handle<JSObject*> aGivenProto)
+{
+  return PoseBinding::Wrap(aJSContext, this, aGivenProto);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/base/Pose.h
@@ -0,0 +1,67 @@
+/* -*- 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_Pose_h
+#define mozilla_dom_Pose_h
+
+#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace dom {
+
+class Pose : public nsWrapperCache
+{
+public:
+  explicit Pose(nsISupports* aParent);
+
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Pose)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Pose)
+
+  nsISupports* GetParentObject() const;
+
+  virtual void GetPosition(JSContext* aJSContext,
+                           JS::MutableHandle<JSObject*> aRetval,
+                           ErrorResult& aRv) = 0;
+  virtual void GetLinearVelocity(JSContext* aJSContext,
+                                 JS::MutableHandle<JSObject*> aRetval,
+                                 ErrorResult& aRv) = 0;
+  virtual void GetLinearAcceleration(JSContext* aJSContext,
+                                     JS::MutableHandle<JSObject*> aRetval,
+                                     ErrorResult& aRv) = 0;
+  virtual void GetOrientation(JSContext* aJSContext,
+                              JS::MutableHandle<JSObject*> aRetval,
+                              ErrorResult& aRv) = 0;
+  virtual void GetAngularVelocity(JSContext* aJSContext,
+                                  JS::MutableHandle<JSObject*> aRetval,
+                                  ErrorResult& aRv) = 0;
+  virtual void GetAngularAcceleration(JSContext* aJSContext,
+                                      JS::MutableHandle<JSObject*> aRetval,
+                                      ErrorResult& aRv) = 0;
+
+  virtual JSObject* WrapObject(JSContext* aJSContext,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
+protected:
+  virtual ~Pose();
+
+  void SetFloat32Array(JSContext* aJSContext, JS::MutableHandle<JSObject*> aRetVal,
+                       JS::Heap<JSObject*>& aObj, float* aVal, uint32_t sizeOfVal,
+                       bool bCreate, ErrorResult& aRv);
+
+  nsCOMPtr<nsISupports> mParent;
+
+  JS::Heap<JSObject*> mPosition;
+  JS::Heap<JSObject*> mLinearVelocity;
+  JS::Heap<JSObject*> mLinearAcceleration;
+  JS::Heap<JSObject*> mOrientation;
+  JS::Heap<JSObject*> mAngularVelocity;
+  JS::Heap<JSObject*> mAngularAcceleration;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_Pose_h
--- a/dom/base/Timeout.cpp
+++ b/dom/base/Timeout.cpp
@@ -4,17 +4,16 @@
  * 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 "Timeout.h"
 
 #include "nsGlobalWindow.h"
 #include "nsITimeoutHandler.h"
 #include "nsITimer.h"
-#include "nsPIDOMWindow.h"
 
 namespace mozilla {
 namespace dom {
 
 Timeout::Timeout()
   : mCleared(false),
     mRunning(false),
     mIsInterval(false),
--- a/dom/base/Timeout.h
+++ b/dom/base/Timeout.h
@@ -6,21 +6,23 @@
 
 #ifndef mozilla_dom_timeout_h
 #define mozilla_dom_timeout_h
 
 #include "mozilla/LinkedList.h"
 #include "mozilla/TimeStamp.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsPIDOMWindow.h"
 
 class nsGlobalWindow;
 class nsIPrincipal;
 class nsITimeoutHandler;
 class nsITimer;
+class nsIEventTarget;
 
 namespace mozilla {
 namespace dom {
 
 /*
  * Timeout struct that holds information about each script
  * timeout.  Holds a strong reference to an nsITimeoutHandler, which
  * abstracts the language specific cruft.
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -196,16 +196,17 @@ EXPORTS.mozilla.dom += [
     'MutableBlobStorage.h',
     'MutableBlobStreamListener.h',
     'NameSpaceConstants.h',
     'Navigator.h',
     'NodeInfo.h',
     'NodeInfoInlines.h',
     'NodeIterator.h',
     'PartialSHistory.h',
+    'Pose.h',
     'ProcessGlobal.h',
     'ResponsiveImageSelector.h',
     'SameProcessMessageQueue.h',
     'ScreenOrientation.h',
     'ScriptSettings.h',
     'ShadowRoot.h',
     'StructuredCloneHolder.h',
     'StructuredCloneTags.h',
@@ -340,16 +341,17 @@ UNIFIED_SOURCES += [
     'nsViewportInfo.cpp',
     'nsWindowMemoryReporter.cpp',
     'nsWindowRoot.cpp',
     'nsWrapperCache.cpp',
     'nsXHTMLContentSerializer.cpp',
     'nsXMLContentSerializer.cpp',
     'nsXMLNameSpaceMap.cpp',
     'PartialSHistory.cpp',
+    'Pose.cpp',
     'PostMessageEvent.cpp',
     'ProcessGlobal.cpp',
     'ResponsiveImageSelector.cpp',
     'SameProcessMessageQueue.cpp',
     'ScreenOrientation.cpp',
     'ScriptSettings.cpp',
     'ShadowRoot.cpp',
     'StructuredCloneHolder.cpp',
--- a/dom/gamepad/Gamepad.cpp
+++ b/dom/gamepad/Gamepad.cpp
@@ -16,17 +16,17 @@ 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)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Gamepad, mParent, mButtons, mPose)
 
 void
 Gamepad::UpdateTimestamp()
 {
   nsCOMPtr<nsPIDOMWindowInner> newWindow(do_QueryInterface(mParent));
   if(newWindow) {
     Performance* perf = newWindow->GetPerformance();
     if (perf) {
@@ -47,16 +47,17 @@ Gamepad::Gamepad(nsISupports* aParent,
     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);
   UpdateTimestamp();
 }
 
 void
 Gamepad::SetIndex(uint32_t aIndex)
 {
   mIndex = aIndex;
 }
@@ -83,36 +84,51 @@ Gamepad::SetAxis(uint32_t aAxis, double 
   if (mAxes[aAxis] != aValue) {
     mAxes[aAxis] = aValue;
     GamepadBinding::ClearCachedAxesValue(this);
   }
   UpdateTimestamp();
 }
 
 void
+Gamepad::SetPose(const GamepadPoseState& aPose)
+{
+  mPose->SetPoseState(aPose);
+}
+
+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]->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());
+  }
+
   UpdateTimestamp();
 }
 
 already_AddRefed<Gamepad>
 Gamepad::Clone(nsISupports* aParent)
 {
   RefPtr<Gamepad> out =
     new Gamepad(aParent, mID, mIndex, mMapping,
--- a/dom/gamepad/Gamepad.h
+++ b/dom/gamepad/Gamepad.h
@@ -5,16 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #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/Performance.h"
 #include <stdint.h>
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 
 namespace mozilla {
@@ -44,16 +45,17 @@ public:
           uint32_t aNumButtons, uint32_t aNumAxes);
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Gamepad)
 
   void SetConnected(bool aConnected);
   void SetButton(uint32_t aButton, bool aPressed, double aValue);
   void SetAxis(uint32_t aAxis, double aValue);
   void SetIndex(uint32_t aIndex);
+  void SetPose(const GamepadPoseState& aPose);
 
   // 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);
 
@@ -94,16 +96,21 @@ public:
     aButtons = mButtons;
   }
 
   void GetAxes(nsTArray<double>& aAxes) const
   {
     aAxes = mAxes;
   }
 
+  GamepadPose* GetPose() const
+  {
+    return mPose;
+  }
+
 private:
   virtual ~Gamepad() {}
   void UpdateTimestamp();
 
 protected:
   nsCOMPtr<nsISupports> mParent;
   nsString mID;
   uint32_t mIndex;
@@ -113,14 +120,15 @@ protected:
 
   // 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;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_gamepad_Gamepad_h
new file mode 100644
--- /dev/null
+++ b/dom/gamepad/GamepadPose.cpp
@@ -0,0 +1,120 @@
+/* -*- 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 "nsWrapperCache.h"
+
+#include "mozilla/HoldDropJSObjects.h"
+#include "mozilla/dom/GamepadPoseBinding.h"
+#include "mozilla/dom/GamepadPose.h"
+
+namespace mozilla {
+namespace dom {
+
+GamepadPose::GamepadPose(nsISupports* aParent, const GamepadPoseState& aState)
+  : Pose(aParent),
+    mPoseState(aState)
+{
+  mozilla::HoldJSObjects(this);
+}
+
+GamepadPose::GamepadPose(nsISupports* aParent)
+  : Pose(aParent)
+{
+  mozilla::HoldJSObjects(this);
+  mPoseState.Clear();
+}
+
+GamepadPose::~GamepadPose()
+{
+  mozilla::DropJSObjects(this);
+}
+
+/* virtual */ JSObject*
+GamepadPose::WrapObject(JSContext* aJSContext, JS::Handle<JSObject*> aGivenProto)
+{
+  return GamepadPoseBinding::Wrap(aJSContext, this, aGivenProto);
+}
+
+bool
+GamepadPose::HasOrientation() const
+{
+  return bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Position);
+}
+
+bool
+GamepadPose::HasPosition() const
+{
+  return bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Orientation);
+}
+
+void
+GamepadPose::GetPosition(JSContext* aJSContext,
+                         JS::MutableHandle<JSObject*> aRetval,
+                         ErrorResult& aRv)
+{
+  SetFloat32Array(aJSContext, aRetval, mPosition, mPoseState.position, 3,
+    bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Position), aRv);
+}
+
+void
+GamepadPose::GetLinearVelocity(JSContext* aJSContext,
+                               JS::MutableHandle<JSObject*> aRetval,
+                               ErrorResult& aRv)
+{
+  SetFloat32Array(aJSContext, aRetval, mLinearVelocity, mPoseState.linearVelocity, 3,
+    bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Position), aRv);
+}
+
+void
+GamepadPose::GetLinearAcceleration(JSContext* aJSContext,
+                                   JS::MutableHandle<JSObject*> aRetval,
+                                   ErrorResult& aRv)
+{
+  SetFloat32Array(aJSContext, aRetval, mLinearAcceleration, mPoseState.linearAcceleration, 3,
+    bool(mPoseState.flags & GamepadCapabilityFlags::Cap_LinearAcceleration), aRv);
+}
+
+void
+GamepadPose::GetOrientation(JSContext* aJSContext,
+                            JS::MutableHandle<JSObject*> aRetval,
+                            ErrorResult& aRv)
+{
+  SetFloat32Array(aJSContext, aRetval, mOrientation, mPoseState.orientation, 4,
+    bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Orientation), aRv);
+}
+
+void
+GamepadPose::GetAngularVelocity(JSContext* aJSContext,
+                                JS::MutableHandle<JSObject*> aRetval,
+                                ErrorResult& aRv)
+{
+  SetFloat32Array(aJSContext, aRetval, mAngularVelocity, mPoseState.angularVelocity, 3,
+    bool(mPoseState.flags & GamepadCapabilityFlags::Cap_Orientation), aRv);
+}
+
+void
+GamepadPose::GetAngularAcceleration(JSContext* aJSContext,
+                                    JS::MutableHandle<JSObject*> aRetval,
+                                    ErrorResult& aRv)
+{
+  SetFloat32Array(aJSContext, aRetval, mAngularAcceleration, mPoseState.angularAcceleration, 3,
+    bool(mPoseState.flags & GamepadCapabilityFlags::Cap_AngularAcceleration), aRv);
+}
+
+void
+GamepadPose::SetPoseState(const GamepadPoseState& aPose)
+{
+  mPoseState = aPose;
+}
+
+const GamepadPoseState&
+GamepadPose::GetPoseState()
+{
+  return mPoseState;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/gamepad/GamepadPose.h
@@ -0,0 +1,58 @@
+/* -*- 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_GamepadPose_h
+#define mozilla_dom_gamepad_GamepadPose_h
+
+#include "mozilla/TypedEnumBits.h"
+#include "mozilla/dom/Pose.h"
+#include "mozilla/dom/GamepadPoseState.h"
+
+namespace mozilla {
+namespace dom {
+
+class GamepadPose final : public Pose
+{
+public:
+  GamepadPose(nsISupports* aParent, const GamepadPoseState& aState);
+  explicit GamepadPose(nsISupports* aParent);
+
+  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+  bool HasOrientation() const;
+  bool HasPosition() const;
+  virtual void GetPosition(JSContext* aJSContext,
+                           JS::MutableHandle<JSObject*> aRetval,
+                           ErrorResult& aRv) override;
+  virtual void GetLinearVelocity(JSContext* aJSContext,
+                                 JS::MutableHandle<JSObject*> aRetval,
+                                 ErrorResult& aRv) override;
+  virtual void GetLinearAcceleration(JSContext* aJSContext,
+                                     JS::MutableHandle<JSObject*> aRetval,
+                                     ErrorResult& aRv) override;
+  virtual void GetOrientation(JSContext* aJSContext,
+                              JS::MutableHandle<JSObject*> aRetval,
+                              ErrorResult& aRv) override;
+  virtual void GetAngularVelocity(JSContext* aJSContext,
+                                  JS::MutableHandle<JSObject*> aRetval,
+                                  ErrorResult& aRv) override;
+  virtual void GetAngularAcceleration(JSContext* aJSContext,
+                                      JS::MutableHandle<JSObject*> aRetval,
+                                      ErrorResult& aRv) override;
+  void SetPoseState(const GamepadPoseState& aPose);
+  const GamepadPoseState& GetPoseState();
+
+private:
+  virtual ~GamepadPose();
+
+  nsCOMPtr<nsISupports> mParent;
+  GamepadPoseState mPoseState;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_gamepad_GamepadPose_h
new file mode 100644
--- /dev/null
+++ b/dom/gamepad/GamepadPoseState.h
@@ -0,0 +1,88 @@
+
+#ifndef mozilla_dom_gamepad_GamepadPoseState_h_
+#define mozilla_dom_gamepad_GamepadPoseState_h_
+
+namespace mozilla{
+namespace dom{
+
+enum class GamepadCapabilityFlags : uint16_t {
+  Cap_None = 0,
+  /**
+   * Cap_Position is set if the Gamepad is capable of tracking its position.
+   */
+  Cap_Position = 1 << 1,
+  /**
+    * Cap_Orientation is set if the Gamepad is capable of tracking its orientation.
+    */
+  Cap_Orientation = 1 << 2,
+  /**
+   * Cap_AngularAcceleration is set if the Gamepad is capable of tracking its
+   * angular acceleration.
+   */
+  Cap_AngularAcceleration = 1 << 3,
+  /**
+   * Cap_LinearAcceleration is set if the Gamepad is capable of tracking its
+   * linear acceleration.
+   */
+  Cap_LinearAcceleration = 1 << 4,
+  /**
+   * Cap_All used for validity checking during IPC serialization
+   */
+  Cap_All = (1 << 5) - 1
+};
+
+MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(GamepadCapabilityFlags)
+
+struct GamepadPoseState
+{
+  GamepadCapabilityFlags flags;
+  float orientation[4];
+  float position[3];
+  float angularVelocity[3];
+  float angularAcceleration[3];
+  float linearVelocity[3];
+  float linearAcceleration[3];
+
+  GamepadPoseState()
+  {
+    Clear();
+  }
+
+  bool operator==(const GamepadPoseState& aPose) const
+  {
+    return flags == aPose.flags
+           && orientation[0] == aPose.orientation[0]
+           && orientation[1] == aPose.orientation[1]
+           && orientation[2] == aPose.orientation[2]
+           && orientation[3] == aPose.orientation[3]
+           && position[0] == aPose.position[0]
+           && position[1] == aPose.position[1]
+           && position[2] == aPose.position[2]
+           && angularVelocity[0] == aPose.angularVelocity[0]
+           && angularVelocity[1] == aPose.angularVelocity[1]
+           && angularVelocity[2] == aPose.angularVelocity[2]
+           && angularAcceleration[0] == aPose.angularAcceleration[0]
+           && angularAcceleration[1] == aPose.angularAcceleration[1]
+           && angularAcceleration[2] == aPose.angularAcceleration[2]
+           && linearVelocity[0] == aPose.linearVelocity[0]
+           && linearVelocity[1] == aPose.linearVelocity[1]
+           && linearVelocity[2] == aPose.linearVelocity[2]
+           && linearAcceleration[0] == aPose.linearAcceleration[0]
+           && linearAcceleration[1] == aPose.linearAcceleration[1]
+           && linearAcceleration[2] == aPose.linearAcceleration[2];
+  }
+
+  bool operator!=(const GamepadPoseState& aPose) const
+  {
+    return !(*this == aPose);
+  }
+
+  void Clear() {
+    memset(this, 0, sizeof(GamepadPoseState));
+  }
+};
+
+}// namespace dom
+}// namespace mozilla
+
+#endif // mozilla_dom_gamepad_GamepadPoseState_h_
\ No newline at end of file
--- a/dom/gamepad/ipc/GamepadMessageUtils.h
+++ b/dom/gamepad/ipc/GamepadMessageUtils.h
@@ -1,14 +1,15 @@
 
 #ifndef mozilla_dom_gamepad_GamepadMessageUtils_h
 #define mozilla_dom_gamepad_GamepadMessageUtils_h
 
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/dom/GamepadServiceType.h"
+#include "mozilla/dom/GamepadPoseState.h"
 
 namespace IPC {
 
 template<>
 struct ParamTraits<mozilla::dom::GamepadServiceType> :
   public ContiguousEnumSerializer<mozilla::dom::GamepadServiceType,
                                   mozilla::dom::GamepadServiceType(0),
                                   mozilla::dom::GamepadServiceType(
--- a/dom/gamepad/moz.build
+++ b/dom/gamepad/moz.build
@@ -6,40 +6,43 @@
 
 IPDL_SOURCES += [
     'ipc/GamepadEventTypes.ipdlh',
     'ipc/PGamepadEventChannel.ipdl',
     'ipc/PGamepadTestChannel.ipdl'
 ]
 
 EXPORTS.mozilla.dom += [
+    'GamepadPoseState.h',
     'ipc/GamepadMessageUtils.h',
     'ipc/GamepadServiceType.h'
 ]
 
 if CONFIG['MOZ_GAMEPAD']:
     EXPORTS.mozilla.dom += [
         'Gamepad.h',
         'GamepadButton.h',
         'GamepadManager.h',
         'GamepadMonitoring.h',
         'GamepadPlatformService.h',
+        'GamepadPose.h',
         'GamepadServiceTest.h',
         'ipc/GamepadEventChannelChild.h',
         'ipc/GamepadEventChannelParent.h',
         'ipc/GamepadTestChannelChild.h',
         'ipc/GamepadTestChannelParent.h'
         ]
 
     UNIFIED_SOURCES = [
         'Gamepad.cpp',
         'GamepadButton.cpp',
         'GamepadManager.cpp',
         'GamepadMonitoring.cpp',
         'GamepadPlatformService.cpp',
+        'GamepadPose.cpp',
         'GamepadServiceTest.cpp',
         'ipc/GamepadEventChannelChild.cpp',
         'ipc/GamepadEventChannelParent.cpp',
         'ipc/GamepadTestChannelChild.cpp',
         'ipc/GamepadTestChannelParent.cpp'
         ]
 
     if CONFIG['MOZ_GAMEPAD_BACKEND'] == 'stub':
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -400,16 +400,18 @@ var interfaceNamesInGlobalScope =
     "GamepadAxisMoveEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "GamepadButtonEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "GamepadButton",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "GamepadEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "GamepadPose", release: false},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "HashChangeEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Headers",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "History",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "HTMLAllCollection",
 // IMPORTANT: Do not change this list without review from a DOM peer!
@@ -770,16 +772,18 @@ var interfaceNamesInGlobalScope =
     {name: "PointerEvent", nightly: true, desktop: true, disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PopStateEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "PopupBlockedEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PopupBoxObject", xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    {name: "Pose", release: false},
+// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PresentationDeviceInfoManager",
      disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Presentation", disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PresentationAvailability", disabled: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PresentationConnection", disabled: true},
--- a/dom/vr/VRDisplay.cpp
+++ b/dom/vr/VRDisplay.cpp
@@ -251,174 +251,96 @@ NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRD
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRDisplayCapabilities, Release)
 
 JSObject*
 VRDisplayCapabilities::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return VRDisplayCapabilitiesBinding::Wrap(aCx, this, aGivenProto);
 }
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(VRPose)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(VRPose)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-  tmp->mPosition = nullptr;
-  tmp->mLinearVelocity = nullptr;
-  tmp->mLinearAcceleration = nullptr;
-  tmp->mOrientation = nullptr;
-  tmp->mAngularVelocity = nullptr;
-  tmp->mAngularAcceleration = nullptr;
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(VRPose)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(VRPose)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mPosition)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLinearVelocity)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLinearAcceleration)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mOrientation)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAngularVelocity)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAngularAcceleration)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRPose, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRPose, Release)
-
 VRPose::VRPose(nsISupports* aParent, const gfx::VRHMDSensorState& aState)
-  : mParent(aParent)
+  : Pose(aParent)
   , mVRState(aState)
-  , mPosition(nullptr)
-  , mLinearVelocity(nullptr)
-  , mLinearAcceleration(nullptr)
-  , mOrientation(nullptr)
-  , mAngularVelocity(nullptr)
-  , mAngularAcceleration(nullptr)
 {
   mFrameId = aState.inputFrameID;
   mozilla::HoldJSObjects(this);
 }
 
 VRPose::VRPose(nsISupports* aParent)
-  : mParent(aParent)
-  , mPosition(nullptr)
-  , mLinearVelocity(nullptr)
-  , mLinearAcceleration(nullptr)
-  , mOrientation(nullptr)
-  , mAngularVelocity(nullptr)
-  , mAngularAcceleration(nullptr)
+  : Pose(aParent)
 {
   mFrameId = 0;
   mVRState.Clear();
   mozilla::HoldJSObjects(this);
 }
 
 VRPose::~VRPose()
 {
   mozilla::DropJSObjects(this);
 }
 
 void
 VRPose::GetPosition(JSContext* aCx,
                     JS::MutableHandle<JSObject*> aRetval,
                     ErrorResult& aRv)
 {
-  if (!mPosition && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position) {
-    // Lazily create the Float32Array
-    mPosition = dom::Float32Array::Create(aCx, this, 3, mVRState.position);
-    if (!mPosition) {
-      aRv.NoteJSContextException(aCx);
-      return;
-    }
-  }
-  aRetval.set(mPosition);
+  SetFloat32Array(aCx, aRetval, mPosition, mVRState.position, 3,
+    !mPosition && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position),
+    aRv);
 }
 
 void
 VRPose::GetLinearVelocity(JSContext* aCx,
                           JS::MutableHandle<JSObject*> aRetval,
                           ErrorResult& aRv)
 {
-  if (!mLinearVelocity && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position) {
-    // Lazily create the Float32Array
-    mLinearVelocity = dom::Float32Array::Create(aCx, this, 3, mVRState.linearVelocity);
-    if (!mLinearVelocity) {
-      aRv.NoteJSContextException(aCx);
-      return;
-    }
-  }
-  aRetval.set(mLinearVelocity);
+  SetFloat32Array(aCx, aRetval, mLinearVelocity, mVRState.linearVelocity, 3,
+    !mLinearVelocity && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Position),
+    aRv);
 }
 
 void
 VRPose::GetLinearAcceleration(JSContext* aCx,
                               JS::MutableHandle<JSObject*> aRetval,
                               ErrorResult& aRv)
 {
-  if (!mLinearAcceleration && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_LinearAcceleration) {
-    // Lazily create the Float32Array
-    mLinearAcceleration = dom::Float32Array::Create(aCx, this, 3, mVRState.linearAcceleration);
-    if (!mLinearAcceleration) {
-      aRv.NoteJSContextException(aCx);
-      return;
-    }
-  }
-  aRetval.set(mLinearAcceleration);
+  SetFloat32Array(aCx, aRetval, mLinearAcceleration, mVRState.linearAcceleration, 3,
+    !mLinearAcceleration && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_LinearAcceleration),
+    aRv);
+
 }
 
 void
 VRPose::GetOrientation(JSContext* aCx,
                        JS::MutableHandle<JSObject*> aRetval,
                        ErrorResult& aRv)
 {
-  if (!mOrientation && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation) {
-    // Lazily create the Float32Array
-    mOrientation = dom::Float32Array::Create(aCx, this, 4, mVRState.orientation);
-    if (!mOrientation) {
-      aRv.NoteJSContextException(aCx);
-      return;
-    }
-  }
-  aRetval.set(mOrientation);
+  SetFloat32Array(aCx, aRetval, mOrientation, mVRState.orientation, 4,
+    !mOrientation && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation),
+    aRv);
 }
 
 void
 VRPose::GetAngularVelocity(JSContext* aCx,
                            JS::MutableHandle<JSObject*> aRetval,
                            ErrorResult& aRv)
 {
-  if (!mAngularVelocity && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation) {
-    // Lazily create the Float32Array
-    mAngularVelocity = dom::Float32Array::Create(aCx, this, 3, mVRState.angularVelocity);
-    if (!mAngularVelocity) {
-      aRv.NoteJSContextException(aCx);
-      return;
-    }
-  }
-  aRetval.set(mAngularVelocity);
+  SetFloat32Array(aCx, aRetval, mAngularVelocity, mVRState.angularVelocity, 3,
+    !mAngularVelocity && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_Orientation),
+    aRv);
 }
 
 void
 VRPose::GetAngularAcceleration(JSContext* aCx,
                                JS::MutableHandle<JSObject*> aRetval,
                                ErrorResult& aRv)
 {
-  if (!mAngularAcceleration && mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_AngularAcceleration) {
-    // Lazily create the Float32Array
-    mAngularAcceleration = dom::Float32Array::Create(aCx, this, 3, mVRState.angularAcceleration);
-    if (!mAngularAcceleration) {
-      aRv.NoteJSContextException(aCx);
-      return;
-    }
-  }
-  aRetval.set(mAngularAcceleration);
+  SetFloat32Array(aCx, aRetval, mAngularAcceleration, mVRState.angularAcceleration, 3,
+    !mAngularAcceleration && bool(mVRState.flags & gfx::VRDisplayCapabilityFlags::Cap_AngularAcceleration),
+    aRv);
 }
 
 JSObject*
 VRPose::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return VRPoseBinding::Wrap(aCx, this, aGivenProto);
 }
 
--- a/dom/vr/VRDisplay.h
+++ b/dom/vr/VRDisplay.h
@@ -10,21 +10,21 @@
 #include <stdint.h>
 
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/dom/VRDisplayBinding.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/DOMPoint.h"
 #include "mozilla/dom/DOMRect.h"
+#include "mozilla/dom/Pose.h"
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsTArray.h"
-#include "nsWrapperCache.h"
 
 #include "gfxVR.h"
 
 namespace mozilla {
 namespace gfx {
 class VRDisplayClient;
 class VRDisplayPresentation;
 struct VRFieldOfView;
@@ -90,64 +90,51 @@ public:
   uint32_t MaxLayers() const;
 
 protected:
   ~VRDisplayCapabilities() {}
   nsCOMPtr<nsISupports> mParent;
   gfx::VRDisplayCapabilityFlags mFlags;
 };
 
-class VRPose final : public nsWrapperCache
+class VRPose final : public Pose
 {
 
 public:
   VRPose(nsISupports* aParent, const gfx::VRHMDSensorState& aState);
   explicit VRPose(nsISupports* aParent);
 
-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(VRPose)
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(VRPose)
-
   uint32_t FrameID() const { return mFrameId; }
 
-  void GetPosition(JSContext* aCx,
-                   JS::MutableHandle<JSObject*> aRetval,
-                   ErrorResult& aRv);
-  void GetLinearVelocity(JSContext* aCx,
-                         JS::MutableHandle<JSObject*> aRetval,
-                         ErrorResult& aRv);
-  void GetLinearAcceleration(JSContext* aCx,
-                             JS::MutableHandle<JSObject*> aRetval,
-                             ErrorResult& aRv);
-  void GetOrientation(JSContext* aCx,
-                      JS::MutableHandle<JSObject*> aRetval,
-                      ErrorResult& aRv);
-  void GetAngularVelocity(JSContext* aCx,
-                          JS::MutableHandle<JSObject*> aRetval,
-                          ErrorResult& aRv);
-  void GetAngularAcceleration(JSContext* aCx,
+  virtual void GetPosition(JSContext* aCx,
+                           JS::MutableHandle<JSObject*> aRetval,
+                           ErrorResult& aRv) override;
+  virtual void GetLinearVelocity(JSContext* aCx,
+                                 JS::MutableHandle<JSObject*> aRetval,
+                                 ErrorResult& aRv) override;
+  virtual void GetLinearAcceleration(JSContext* aCx,
+                                     JS::MutableHandle<JSObject*> aRetval,
+                                     ErrorResult& aRv) override;
+  virtual void GetOrientation(JSContext* aCx,
                               JS::MutableHandle<JSObject*> aRetval,
-                              ErrorResult& aRv);
+                              ErrorResult& aRv) override;
+  virtual void GetAngularVelocity(JSContext* aCx,
+                                  JS::MutableHandle<JSObject*> aRetval,
+                                  ErrorResult& aRv) override;
+  virtual void GetAngularAcceleration(JSContext* aCx,
+                                      JS::MutableHandle<JSObject*> aRetval,
+                                      ErrorResult& aRv) override;
 
-  nsISupports* GetParentObject() const { return mParent; }
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
 protected:
   ~VRPose();
-  nsCOMPtr<nsISupports> mParent;
 
   uint32_t mFrameId;
   gfx::VRHMDSensorState mVRState;
-
-  JS::Heap<JSObject*> mPosition;
-  JS::Heap<JSObject*> mLinearVelocity;
-  JS::Heap<JSObject*> mLinearAcceleration;
-  JS::Heap<JSObject*> mOrientation;
-  JS::Heap<JSObject*> mAngularVelocity;
-  JS::Heap<JSObject*> mAngularAcceleration;
-
 };
 
 struct VRFrameInfo
 {
   VRFrameInfo();
 
   void Update(const gfx::VRDisplayInfo& aInfo,
               const gfx::VRHMDSensorState& aState,
--- a/dom/webidl/Gamepad.webidl
+++ b/dom/webidl/Gamepad.webidl
@@ -51,9 +51,15 @@ interface Gamepad {
    */
   [Pure, Cached, Frozen]
   readonly attribute sequence<double> axes;
 
   /**
    * Timestamp from when the data of this device was last updated.
    */
   readonly attribute DOMHighResTimeStamp timestamp;
+
+  /**
+   * The current pose of the device, a GamepadPose.
+   */
+  [Pref="dom.gamepad.extensions.enabled"]
+  readonly attribute GamepadPose? pose;
 };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/GamepadPose.webidl
@@ -0,0 +1,13 @@
+/* -*- 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/.
+ */
+
+[Pref="dom.gamepad.extensions.enabled",
+  HeaderFile="mozilla/dom/GamepadPose.h"]
+interface GamepadPose : Pose
+{
+  readonly attribute boolean hasOrientation;
+  readonly attribute boolean hasPosition;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/Pose.webidl
@@ -0,0 +1,23 @@
+/* -*- 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/.
+ */
+
+interface Pose
+{
+  /**
+   * position, linearVelocity, and linearAcceleration are 3-component vectors.
+   * position is relative to a sitting space. Transforming this point with
+   * VRStageParameters.sittingToStandingTransform converts this to standing space.
+   */
+  [Constant, Throws] readonly attribute Float32Array? position;
+  [Constant, Throws] readonly attribute Float32Array? linearVelocity;
+  [Constant, Throws] readonly attribute Float32Array? linearAcceleration;
+
+  /* orientation is a 4-entry array representing the components of a quaternion. */
+  [Constant, Throws] readonly attribute Float32Array? orientation;
+  /* angularVelocity and angularAcceleration are the components of 3-dimensional vectors. */
+  [Constant, Throws] readonly attribute Float32Array? angularVelocity;
+  [Constant, Throws] readonly attribute Float32Array? angularAcceleration;
+};
--- a/dom/webidl/VRDisplay.webidl
+++ b/dom/webidl/VRDisplay.webidl
@@ -111,31 +111,19 @@ interface VRStageParameters {
    * this rectangle.
    */
   readonly attribute float sizeX;
   readonly attribute float sizeZ;
 };
 
 [Pref="dom.vr.enabled",
  HeaderFile="mozilla/dom/VRDisplay.h"]
-interface VRPose {
-  /**
-   * position, linearVelocity, and linearAcceleration are 3-component vectors.
-   * position is relative to a sitting space. Transforming this point with
-   * VRStageParameters.sittingToStandingTransform converts this to standing space.
-   */
-  [Constant, Throws] readonly attribute Float32Array? position;
-  [Constant, Throws] readonly attribute Float32Array? linearVelocity;
-  [Constant, Throws] readonly attribute Float32Array? linearAcceleration;
+interface VRPose : Pose
+{
 
-  /* orientation is a 4-entry array representing the components of a quaternion. */
-  [Constant, Throws] readonly attribute Float32Array? orientation;
-  /* angularVelocity and angularAcceleration are the components of 3-dimensional vectors. */
-  [Constant, Throws] readonly attribute Float32Array? angularVelocity;
-  [Constant, Throws] readonly attribute Float32Array? angularAcceleration;
 };
 
 [Constructor,
  Pref="dom.vr.enabled",
  HeaderFile="mozilla/dom/VRDisplay.h"]
 interface VRFrameData {
   readonly attribute DOMHighResTimeStamp timestamp;
 
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -362,16 +362,17 @@ WEBIDL_FILES = [
     'PeriodicWave.webidl',
     'Permissions.webidl',
     'PermissionSettings.webidl',
     'PermissionStatus.webidl',
     'Plugin.webidl',
     'PluginArray.webidl',
     'PointerEvent.webidl',
     'PopupBoxObject.webidl',
+    'Pose.webidl',
     'Position.webidl',
     'PositionError.webidl',
     'Presentation.webidl',
     'PresentationAvailability.webidl',
     'PresentationConnection.webidl',
     'PresentationConnectionList.webidl',
     'PresentationDeviceInfoManager.webidl',
     'PresentationReceiver.webidl',
@@ -642,16 +643,17 @@ if CONFIG['MOZ_WEBSPEECH']:
         'SpeechSynthesisEvent.webidl',
         'SpeechSynthesisUtterance.webidl',
         'SpeechSynthesisVoice.webidl',
     ]
 
 if CONFIG['MOZ_GAMEPAD']:
     WEBIDL_FILES += [
         'Gamepad.webidl',
+        'GamepadPose.webidl',
         'GamepadServiceTest.webidl'
     ]
 
 WEBIDL_FILES += [
     'CloseEvent.webidl',
     'CustomEvent.webidl',
     'DeviceOrientationEvent.webidl',
     'DeviceStorageChangeEvent.webidl',
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -198,16 +198,17 @@ pref("dom.requestIdleCallback.enabled", 
 // 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", false);
 
 // Whether the KeyboardEvent.code is enabled
 pref("dom.keyboardevent.code.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", false);