Bug 852257 - implement Gamepad.timestamp property; r=ted, r=smaug
authorSnigdha Agarwal <snigdhaagarwal93@gmail.com>
Wed, 07 Jan 2015 14:17:04 -0500
changeset 249201 8e8ce6c0d19aca731410e3ef8b3810e2bfb2b799
parent 249200 fff1eae2346fce938e64f070280a1528330a769c
child 249202 b2aff7ebf9b45444997a83d8aeccc3339897cb41
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted, smaug
bugs852257
milestone37.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 852257 - implement Gamepad.timestamp property; r=ted, r=smaug
dom/gamepad/Gamepad.cpp
dom/gamepad/Gamepad.h
dom/tests/mochitest/gamepad/mochitest.ini
dom/tests/mochitest/gamepad/test_check_timestamp.html
dom/tests/mochitest/gamepad/test_gamepad.html
dom/webidl/Gamepad.webidl
--- a/dom/gamepad/Gamepad.cpp
+++ b/dom/gamepad/Gamepad.cpp
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Gamepad.h"
 #include "nsAutoPtr.h"
+#include "nsPIDOMWindow.h"
 #include "nsTArray.h"
 #include "nsVariant.h"
 #include "mozilla/dom/GamepadBinding.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(Gamepad)
@@ -16,32 +17,45 @@ 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)
 
+void
+Gamepad::UpdateTimestamp()
+{
+  nsCOMPtr<nsPIDOMWindow> newWindow(do_QueryInterface(mParent));
+  if(newWindow) {
+    nsPerformance* perf = newWindow->GetPerformance();
+    if (perf) {
+      mTimestamp =  perf->GetDOMTiming()->TimeStampToDOMHighRes(TimeStamp::Now());
+    }
+  }
+}
+
 Gamepad::Gamepad(nsISupports* aParent,
                  const nsAString& aID, uint32_t aIndex,
                  GamepadMappingType aMapping,
                  uint32_t aNumButtons, uint32_t aNumAxes)
   : mParent(aParent),
     mID(aID),
     mIndex(aIndex),
     mMapping(aMapping),
     mConnected(true),
     mButtons(aNumButtons),
     mAxes(aNumAxes)
 {
   for (unsigned i = 0; i < aNumButtons; i++) {
     mButtons.InsertElementAt(i, new GamepadButton(mParent));
   }
   mAxes.InsertElementsAt(0, aNumAxes, 0.0f);
+  UpdateTimestamp();
 }
 
 void
 Gamepad::SetIndex(uint32_t aIndex)
 {
   mIndex = aIndex;
 }
 
@@ -52,26 +66,28 @@ Gamepad::SetConnected(bool aConnected)
 }
 
 void
 Gamepad::SetButton(uint32_t aButton, bool aPressed, double aValue)
 {
   MOZ_ASSERT(aButton < mButtons.Length());
   mButtons[aButton]->SetPressed(aPressed);
   mButtons[aButton]->SetValue(aValue);
+  UpdateTimestamp();
 }
 
 void
 Gamepad::SetAxis(uint32_t aAxis, double aValue)
 {
   MOZ_ASSERT(aAxis < mAxes.Length());
   if (mAxes[aAxis] != aValue) {
     mAxes[aAxis] = aValue;
     GamepadBinding::ClearCachedAxesValue(this);
   }
+  UpdateTimestamp();
 }
 
 void
 Gamepad::SyncState(Gamepad* aOther)
 {
   if (mButtons.Length() != aOther->mButtons.Length() ||
       mAxes.Length() != aOther->mAxes.Length()) {
     return;
@@ -85,16 +101,17 @@ Gamepad::SyncState(Gamepad* aOther)
   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);
   }
+  UpdateTimestamp();
 }
 
 already_AddRefed<Gamepad>
 Gamepad::Clone(nsISupports* aParent)
 {
   nsRefPtr<Gamepad> out =
     new Gamepad(aParent, mID, mIndex, mMapping,
                 mButtons.Length(), mAxes.Length());
--- a/dom/gamepad/Gamepad.h
+++ b/dom/gamepad/Gamepad.h
@@ -8,16 +8,17 @@
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/GamepadBinding.h"
 #include "mozilla/dom/GamepadButton.h"
 #include <stdint.h>
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
+#include "nsPerformance.h"
 
 namespace mozilla {
 namespace dom {
 
 // Per spec:
 // https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#remapping
 const int kStandardGamepadButtons = 17;
 const int kStandardGamepadAxes = 4;
@@ -60,16 +61,21 @@ public:
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   void GetId(nsAString& aID) const
   {
     aID = mID;
   }
 
+  DOMHighResTimeStamp Timestamp() const
+  {
+     return mTimestamp;
+  }
+
   GamepadMappingType Mapping()
   {
     return mMapping;
   }
 
   bool Connected() const
   {
     return mConnected;
@@ -87,29 +93,31 @@ public:
 
   void GetAxes(nsTArray<double>& aAxes) const
   {
     aAxes = mAxes;
   }
 
 private:
   virtual ~Gamepad() {}
+  void UpdateTimestamp();
 
 protected:
   nsCOMPtr<nsISupports> mParent;
   nsString mID;
   uint32_t mIndex;
 
   // The mapping in use.
   GamepadMappingType mMapping;
 
   // true if this gamepad is currently connected.
   bool mConnected;
 
   // Current state of buttons, axes.
   nsTArray<nsRefPtr<GamepadButton>> mButtons;
   nsTArray<double> mAxes;
+  DOMHighResTimeStamp mTimestamp;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_gamepad_Gamepad_h
--- a/dom/tests/mochitest/gamepad/mochitest.ini
+++ b/dom/tests/mochitest/gamepad/mochitest.ini
@@ -1,15 +1,16 @@
 [DEFAULT]
 skip-if = e10s
 support-files =
   gamepad_frame.html
   gamepad_frame_state.html
   mock_gamepad.js
 
+[test_check_timestamp.html]
 [test_gamepad.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_gamepad_connect_events.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_gamepad_frame_state_sync.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_gamepad_hidden_frame.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/gamepad/test_check_timestamp.html
@@ -0,0 +1,51 @@
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test Gamepad.timestamp</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<script type="text/javascript" src="mock_gamepad.js"></script>
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+var index = GamepadService.addGamepad("test gamepad", // id
+                                      SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
+                                      4, // buttons
+                                      2);// axes
+
+var timea=0;
+window.addEventListener("gamepadbuttondown", buttonpresshandler);
+
+var firstPress = true;
+GamepadService.newButtonEvent(index, 0, true);
+GamepadService.newButtonEvent(index, 0, true);
+
+function cleanup(){
+  SpecialPowers.executeSoon(function() {
+    GamepadService.removeGamepad(index);
+    SimpleTest.finish();
+  });
+}
+
+function buttonpresshandler(e) {
+  if(timea == 0){
+    timea = e.gamepad.timestamp;
+  }
+  else{
+    ok(timea <= e.gamepad.timestamp);
+  }
+  GamepadService.newButtonEvent(index, 0, false);
+  if (!firstPress) {
+    SpecialPowers.executeSoon(cleanup);
+  }
+  else {
+    firstPress = false;
+  }
+}
+
+</script>
+</body>
+</html>
--- a/dom/tests/mochitest/gamepad/test_gamepad.html
+++ b/dom/tests/mochitest/gamepad/test_gamepad.html
@@ -15,16 +15,17 @@ window.addEventListener("gamepadconnecte
 // Add a gamepad
 var index = GamepadService.addGamepad("test gamepad", // id
                                       SpecialPowers.Ci.nsIGamepadServiceTest.STANDARD_MAPPING,
                                       4, // buttons
                                       2);// axes
 // Press a button
 GamepadService.newButtonEvent(index, 0, true);
 function connecthandler(e) {
+  ok(e.gamepad.timestamp <= performance.now());
   is(e.gamepad.id, "test gamepad", "correct gamepad name");
   is(e.gamepad.mapping, "standard", "standard mapping");
   is(e.gamepad.buttons.length, 4, "correct number of buttons");
   is(e.gamepad.axes.length, 2, "correct number of axes");
   SimpleTest.executeSoon(function() {
     GamepadService.removeGamepad(index);
     SimpleTest.finish();
   });
--- a/dom/webidl/Gamepad.webidl
+++ b/dom/webidl/Gamepad.webidl
@@ -46,9 +46,14 @@ interface Gamepad {
   readonly attribute sequence<GamepadButton> buttons;
 
   /**
    * The current position of all axes on the device, an
    * array of doubles.
    */
   [Pure, Cached, Frozen]
   readonly attribute sequence<double> axes;
+
+  /**
+   * Timestamp from when the data of this device was last updated.
+   */
+  readonly attribute DOMHighResTimeStamp timestamp;
 };