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 364879 83adb3995ae671de06c79dc5fc615db62a08597a
parent 364878 1b48d4300536804a1a9abc4a80c33be35361ab01
child 364880 a8b7a04fa1508cac91516ff73ef114c4fd83fc31
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-beta@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskip, qdot
bugs1299932
milestone52.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 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);