Merge m-i to m-c
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 20 Oct 2013 19:24:53 -0700
changeset 165295 7823e2985daf750ab8292c33840599f2e361acc0
parent 165283 4cec7d72e00354475935f7885d4f6690fa2f58fa (current diff)
parent 165294 48717bae9d9675ec71e6e562e2413ef524748746 (diff)
child 165297 2e3900ae8b35fee7e11d45a2eb1e4332221c4968
child 165300 858e3e2130c9dc1de3950704a85185b4189059e4
child 165335 648ebe6ac8e5d1c16df4103a1ac6c8ea6475e6ce
child 170462 81b7bc6646e13549fbc71ac06ca61304edba6670
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.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
Merge m-i to m-c
dom/interfaces/gamepad/nsIDOMGamepad.idl
--- a/CLOBBER
+++ b/CLOBBER
@@ -13,9 +13,9 @@
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-Bug 924992 - WebIDL headers changes not correctly picked up by the build system somehow
+Bug 926091 says hello to bug 924992 by touching webidl
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -799,16 +799,20 @@ var gPluginHandler = {
     let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
 
     for (let plugin of plugins) {
       plugin.QueryInterface(Ci.nsIObjectLoadingContent);
       // canActivatePlugin will return false if this isn't a known plugin type,
       // so the pluginHost.getPermissionStringForType call is protected
       if (gPluginHandler.canActivatePlugin(plugin) &&
           aPluginInfo.permissionString == pluginHost.getPermissionStringForType(plugin.actualType)) {
+        let overlay = this.getPluginUI(plugin, "main");
+        if (overlay) {
+          overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true);
+        }
         plugin.playPlugin();
       }
     }
   },
 
   _showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser, aPrimaryPlugin) {
     let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
 
--- a/browser/base/content/test/general/Makefile.in
+++ b/browser/base/content/test/general/Makefile.in
@@ -49,16 +49,17 @@ MOCHITEST_BROWSER_FILES += \
   browser_datareporting_notification.js \
   $(NULL)
 endif
 
 ifdef MOZ_CRASHREPORTER
 MOCHITEST_BROWSER_FILES += \
   browser_pluginCrashCommentAndURL.js \
   pluginCrashCommentAndURL.html \
+  browser_CTP_crashreporting.js \
   $(NULL)
 endif
 
 # browser_CTP_context_menu.js fails intermittently on Linux (bug 909342)
 ifndef MOZ_WIDGET_GTK
 MOCHITEST_BROWSER_FILES += \
   browser_CTP_context_menu.js \
   $(NULL)
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -42,16 +42,17 @@ support-files =
   head.js
   healthreport_testRemoteCommands.html
   moz.png
   offlineQuotaNotification.cacheManifest
   offlineQuotaNotification.html
   page_style_sample.html
   plugin_add_dynamically.html
   plugin_alternate_content.html
+  plugin_big.html
   plugin_both.html
   plugin_both2.html
   plugin_bug744745.html
   plugin_bug749455.html
   plugin_bug752516.html
   plugin_bug787619.html
   plugin_bug797677.html
   plugin_bug820497.html
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_CTP_crashreporting.js
@@ -0,0 +1,134 @@
+/* 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/. */
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
+const gTestRoot = getRootDirectory(gTestPath);
+var gTestBrowser = null;
+
+// Test that plugin crash submissions still work properly after
+// click-to-play activation.
+
+function test() {
+  // Crashing the plugin takes up a lot of time, so extend the test timeout.
+  requestLongerTimeout(2);
+  waitForExplicitFinish();
+  setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+
+  // The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
+  // crash reports.  This test needs them enabled.  The test also needs a mock
+  // report server, and fortunately one is already set up by toolkit/
+  // crashreporter/test/Makefile.in.  Assign its URL to MOZ_CRASHREPORTER_URL,
+  // which CrashSubmit.jsm uses as a server override.
+  let env = Cc["@mozilla.org/process/environment;1"].
+            getService(Components.interfaces.nsIEnvironment);
+  let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT");
+  let serverURL = env.get("MOZ_CRASHREPORTER_URL");
+  env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
+  env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
+
+  let tab = gBrowser.loadOneTab("about:blank", { inBackground: false });
+  gTestBrowser = gBrowser.getBrowserForTab(tab);
+  gTestBrowser.addEventListener("PluginCrashed", onCrash, false);
+  gTestBrowser.addEventListener("load", onPageLoad, true);
+  Services.obs.addObserver(onSubmitStatus, "crash-report-status", false);
+
+  registerCleanupFunction(function cleanUp() {
+    env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
+    env.set("MOZ_CRASHREPORTER_URL", serverURL);
+    gTestBrowser.removeEventListener("PluginCrashed", onCrash, false);
+    gTestBrowser.removeEventListener("load", onPageLoad, true);
+    Services.obs.removeObserver(onSubmitStatus, "crash-report-status");
+    gBrowser.removeCurrentTab();
+  });
+
+  gTestBrowser.contentWindow.location = gTestRoot + "plugin_big.html";
+}
+function onPageLoad() {
+  // Force the plugins binding to attach as layout is async.
+  let plugin = gTestBrowser.contentDocument.getElementById("test");
+  plugin.clientTop;
+  executeSoon(afterBindingAttached);
+}
+
+function afterBindingAttached() {
+  let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
+  ok(popupNotification, "Should have a click-to-play notification");
+
+  let plugin = gTestBrowser.contentDocument.getElementById("test");
+  let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(!objLoadingContent.activated, "Plugin should not be activated");
+
+  // Simulate clicking the "Allow Always" button.
+  popupNotification.reshow();
+  PopupNotifications.panel.firstChild._primaryButton.click();
+
+  let condition = function() objLoadingContent.activated;
+  waitForCondition(condition, pluginActivated, "Waited too long for plugin to activate");
+}
+
+function pluginActivated() {
+  let plugin = gTestBrowser.contentDocument.getElementById("test");
+  try {
+    plugin.crash();
+  } catch (e) {
+    // The plugin crashed in the above call, an exception is expected.
+  }
+}
+
+function onCrash() {
+  try {
+    let plugin = gBrowser.contentDocument.getElementById("test");
+    let elt = gPluginHandler.getPluginUI.bind(gPluginHandler, plugin);
+    let style =
+      gBrowser.contentWindow.getComputedStyle(elt("pleaseSubmit"));
+    is(style.display, "block", "Submission UI visibility should be correct");
+
+    elt("submitComment").value = "a test comment";
+    is(elt("submitURLOptIn").checked, true, "URL opt-in should default to true");
+    EventUtils.synthesizeMouseAtCenter(elt("submitURLOptIn"), {}, gTestBrowser.contentWindow);
+    EventUtils.synthesizeMouseAtCenter(elt("submitButton"), {}, gTestBrowser.contentWindow);
+    // And now wait for the submission status notification.
+  }
+  catch (err) {
+    failWithException(err);
+  }
+}
+
+function onSubmitStatus(subj, topic, data) {
+  try {
+    // Wait for success or failed, doesn't matter which.
+    if (data != "success" && data != "failed")
+      return;
+
+    let extra = getPropertyBagValue(subj.QueryInterface(Ci.nsIPropertyBag),
+                                    "extra");
+    ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag");
+
+    let val = getPropertyBagValue(extra, "PluginUserComment");
+    is(val, "a test comment",
+       "Comment in extra data should match comment in textbox");
+
+    val = getPropertyBagValue(extra, "PluginContentURL");
+    ok(val === undefined,
+       "URL should be absent from extra data when opt-in not checked");
+  }
+  catch (err) {
+    failWithException(err);
+  }
+  finish();
+}
+
+function getPropertyBagValue(bag, key) {
+  try {
+    var val = bag.getProperty(key);
+  }
+  catch (e if e.result == Cr.NS_ERROR_FAILURE) {}
+  return val;
+}
+
+function failWithException(err) {
+  ok(false, "Uncaught exception: " + err + "\n" + err.stack);
+}
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/plugin_big.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+<body>
+<embed id="test" style="width: 500px; height: 500px" type="application/x-test">
+</body>
+</html>
--- a/dom/gamepad/Gamepad.cpp
+++ b/dom/gamepad/Gamepad.cpp
@@ -12,33 +12,36 @@ namespace mozilla {
 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_ENTRY(nsIDOMGamepad)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(Gamepad, mParent)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(Gamepad, mParent, mButtonsVariant)
 
 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)
+    mConnected(true),
+    mButtons(aNumButtons),
+    mAxes(aNumAxes)
 {
   SetIsDOMBinding();
-  mButtons.InsertElementsAt(0, aNumButtons);
+  for (unsigned i = 0; i < aNumButtons; i++) {
+    mButtons.InsertElementAt(i, new GamepadButton(mParent));
+  }
   mAxes.InsertElementsAt(0, aNumAxes, 0.0f);
 }
 
 void
 Gamepad::SetIndex(uint32_t aIndex)
 {
   mIndex = aIndex;
 }
@@ -48,54 +51,60 @@ Gamepad::SetConnected(bool aConnected)
 {
   mConnected = aConnected;
 }
 
 void
 Gamepad::SetButton(uint32_t aButton, bool aPressed, double aValue)
 {
   MOZ_ASSERT(aButton < mButtons.Length());
-  mButtons[aButton].pressed = aPressed;
-  mButtons[aButton].value = aValue;
+  mButtons[aButton]->SetPressed(aPressed);
+  mButtons[aButton]->SetValue(aValue);
 }
 
 void
 Gamepad::SetAxis(uint32_t aAxis, double aValue)
 {
   MOZ_ASSERT(aAxis < mAxes.Length());
   mAxes[aAxis] = aValue;
 }
 
 nsresult
 Gamepad::GetButtons(nsIVariant** aButtons)
 {
+  if (mButtonsVariant) {
+    NS_ADDREF(*aButtons = mButtonsVariant);
+    return NS_OK;
+  }
+
   nsRefPtr<nsVariant> out = new nsVariant();
   NS_ENSURE_STATE(out);
 
   if (mButtons.Length() == 0) {
     nsresult rv = out->SetAsEmptyArray();
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     // Note: The resulting nsIVariant dupes both the array and its elements.
-    double* array = reinterpret_cast<double*>
-                      (NS_Alloc(mButtons.Length() * sizeof(double)));
+    GamepadButton** array = reinterpret_cast<GamepadButton**>
+                      (NS_Alloc(mButtons.Length() * sizeof(GamepadButton*)));
     NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
 
     for (uint32_t i = 0; i < mButtons.Length(); ++i) {
-      array[i] = mButtons[i].value;
+      array[i] = mButtons[i].get();
     }
 
-    nsresult rv = out->SetAsArray(nsIDataType::VTYPE_DOUBLE,
+    nsresult rv = out->SetAsArray(nsIDataType::VTYPE_INTERFACE,
                                   nullptr,
                                   mButtons.Length(),
                                   reinterpret_cast<void*>(array));
     NS_Free(array);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
+  mButtonsVariant = out;
   *aButtons = out.forget().get();
   return NS_OK;
 }
 
 nsresult
 Gamepad::GetAxes(nsIVariant** aAxes)
 {
   nsRefPtr<nsVariant> out = new nsVariant();
@@ -131,17 +140,18 @@ Gamepad::SyncState(Gamepad* aOther)
 {
   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] = aOther->mButtons[i];
+    mButtons[i]->SetPressed(aOther->mButtons[i]->Pressed());
+    mButtons[i]->SetValue(aOther->mButtons[i]->Value());
   }
   for (uint32_t i = 0; i < mAxes.Length(); ++i) {
     mAxes[i] = aOther->mAxes[i];
   }
 }
 
 already_AddRefed<Gamepad>
 Gamepad::Clone(nsISupports* aParent)
--- a/dom/gamepad/Gamepad.h
+++ b/dom/gamepad/Gamepad.h
@@ -1,45 +1,35 @@
 /* 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_Gamepad_h
 #define mozilla_dom_gamepad_Gamepad_h
 
 #include "mozilla/ErrorResult.h"
+#include "mozilla/dom/GamepadButton.h"
 #include <stdint.h>
 #include "nsCOMPtr.h"
-#include "nsIDOMGamepad.h"
 #include "nsIVariant.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 
 namespace mozilla {
 namespace dom {
 
 enum GamepadMappingType
 {
   NoMapping = 0,
   StandardMapping = 1
 };
 
-// TODO: fix the spec to expose both pressed and value:
-// https://www.w3.org/Bugs/Public/show_bug.cgi?id=21388
-struct GamepadButton
-{
-  bool pressed;
-  double value;
-
-  GamepadButton(): pressed(false), value(0.0) {}
-};
-
-class Gamepad : public nsIDOMGamepad
-              , public nsWrapperCache
+class Gamepad : public nsISupports,
+                public nsWrapperCache
 {
 public:
   Gamepad(nsISupports* aParent,
           const nsAString& aID, uint32_t aIndex,
           GamepadMappingType aMapping,
           uint32_t aNumButtons, uint32_t aNumAxes);
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Gamepad)
@@ -115,16 +105,19 @@ protected:
 
   // The mapping in use.
   GamepadMappingType mMapping;
 
   // true if this gamepad is currently connected.
   bool mConnected;
 
   // Current state of buttons, axes.
-  nsTArray<GamepadButton> mButtons;
+  nsTArray<nsRefPtr<GamepadButton>> mButtons;
   nsTArray<double> mAxes;
+
+  // Cached variant array.
+  nsCOMPtr<nsIVariant> mButtonsVariant;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_gamepad_Gamepad_h
new file mode 100644
--- /dev/null
+++ b/dom/gamepad/GamepadButton.cpp
@@ -0,0 +1,28 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/GamepadButton.h"
+#include "mozilla/dom/GamepadBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(GamepadButton)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(GamepadButton)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GamepadButton)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(GamepadButton, mParent)
+
+/* virtual */ JSObject*
+GamepadButton::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return GamepadButtonBinding::Wrap(aCx, aScope, this);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/gamepad/GamepadButton.h
@@ -0,0 +1,69 @@
+/* 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_GamepadButton_h
+#define mozilla_dom_gamepad_GamepadButton_h
+
+#include <stdint.h>
+#include "nsCOMPtr.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace dom {
+
+class GamepadButton : public nsISupports,
+                      public nsWrapperCache
+{
+public:
+  GamepadButton(nsISupports* aParent) : mParent(aParent),
+                                        mPressed(false),
+                                        mValue(0)
+  {
+    SetIsDOMBinding();
+  }
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GamepadButton)
+
+  nsISupports* GetParentObject() const
+  {
+    return mParent;
+  }
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+			       JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+  void SetPressed(bool aPressed)
+  {
+    mPressed = aPressed;
+  }
+
+  void SetValue(double aValue)
+  {
+    mValue = aValue;
+  }
+
+  bool Pressed() const
+  {
+    return mPressed;
+  }
+
+  double Value() const
+  {
+    return mValue;
+  }
+
+private:
+  virtual ~GamepadButton() {}
+
+protected:
+  nsCOMPtr<nsISupports> mParent;
+  bool mPressed;
+  double mValue;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_gamepad_GamepadButton_h
--- a/dom/gamepad/moz.build
+++ b/dom/gamepad/moz.build
@@ -1,21 +1,23 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 EXPORTS.mozilla.dom += [
     'Gamepad.h',
+    'GamepadButton.h',
     'GamepadService.h',
     ]
 
 CPP_SOURCES = [
     'Gamepad.cpp',
+    'GamepadButton.cpp',
     'GamepadService.cpp',
     ]
 
 FAIL_ON_WARNINGS = True
 
 LIBXUL_LIBRARY = True
 
 LIBRARY_NAME = 'domgamepad_s'
--- a/dom/interfaces/gamepad/moz.build
+++ b/dom/interfaces/gamepad/moz.build
@@ -2,11 +2,10 @@
 # vim: set filetype=python:
 # 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/.
 
 XPIDL_MODULE = 'dom_gamepad'
 
 XPIDL_SOURCES = [
-  'nsIDOMGamepad.idl',
   'nsIGamepadServiceTest.idl',
   ]
deleted file mode 100644
--- a/dom/interfaces/gamepad/nsIDOMGamepad.idl
+++ /dev/null
@@ -1,12 +0,0 @@
-/* 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 "nsISupports.idl"
-
-interface nsIVariant;
-
-[builtinclass, scriptable, uuid(ff13acd9-11da-4817-8f2a-4a5700dfd13e)]
-interface nsIDOMGamepad : nsISupports
-{
-};
--- a/dom/tests/mochitest/gamepad/test_gamepad_frame_state_sync.html
+++ b/dom/tests/mochitest/gamepad/test_gamepad_frame_state_sync.html
@@ -42,42 +42,42 @@ window.addEventListener("gamepadbuttondo
 var testNum = 0;
 var tests = [
   check_button_pressed,
   check_second_frame_no_button_press,
 ];
 
 function check_button_pressed() {
   // At this point the both frames should see the button as pressed.
-  is(f1.contentWindow.gamepad.buttons[0], 1, "frame 1 sees button pressed");
-  is(f2.contentWindow.gamepad.buttons[0], 1, "frame 2 sees button pressed");
+  ok(f1.contentWindow.gamepad.buttons[0].pressed, "frame 1 sees button pressed");
+  ok(f2.contentWindow.gamepad.buttons[0].pressed, "frame 2 sees button pressed");
 
   // Now release the button, then hide the second frame.
   GamepadService.newButtonEvent(index, 0, false);
   setFrameVisible(f2, false);
   SpecialPowers.executeSoon(function() {
     // Now press the button, but don't release it.
     GamepadService.newButtonEvent(index, 0, true);
   });
 }
 
 function check_second_frame_no_button_press () {
   /*
    * At this point the first frame should see the button as pressed,
    * but the second frame should not, since it's hidden.
    */
-  is(f1.contentWindow.gamepad.buttons[0], 1, "frame 1 sees button pressed");
-  is(f2.contentWindow.gamepad.buttons[0], 0, "frame 2 should not see button pressed");
+  ok(f1.contentWindow.gamepad.buttons[0].pressed, "frame 1 sees button pressed");
+  ok(!f2.contentWindow.gamepad.buttons[0].pressed, "frame 2 should not see button pressed");
 
   // Now unhide the second frame.
   setFrameVisible(f2, true);
   SpecialPowers.executeSoon(function() {
     // Now that the frame is visible again, it should see the button
     // that was pressed.
-    is(f2.contentWindow.gamepad.buttons[0], 1, "frame 2 sees button pressed");
+    ok(f2.contentWindow.gamepad.buttons[0].pressed, "frame 2 sees button pressed");
     // cleanup
     GamepadService.removeGamepad(index);
     SimpleTest.finish();
   });
 }
 
 </script>
 <iframe id="f1" src="gamepad_frame_state.html" onload="frame_loaded()"></iframe>
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -197,16 +197,17 @@ var interfaceNamesInGlobalScope =
     "FileRequest",
     {name: "FMRadio", b2g: true},
     "FocusEvent",
     "FormData",
     "GainNode",
     {name: "Gamepad", desktop: true},
     {name: "GamepadAxisMoveEvent", desktop: true},
     {name: "GamepadButtonEvent", desktop: true},
+    {name: "GamepadButton", desktop: true},
     {name: "GamepadEvent", desktop: true},
     "HashChangeEvent",
     "History",
     "HTMLAnchorElement",
     "HTMLAppletElement",
     "HTMLAreaElement",
     "HTMLAudioElement",
     "HTMLBaseElement",
--- a/dom/webidl/Gamepad.webidl
+++ b/dom/webidl/Gamepad.webidl
@@ -1,16 +1,22 @@
 /* -*- 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 nsIVariant;
 
 [Pref="dom.gamepad.enabled"]
+interface GamepadButton {
+  readonly    attribute boolean pressed;
+  readonly    attribute double  value;
+};
+
+[Pref="dom.gamepad.enabled"]
 interface Gamepad {
   /**
    * An identifier, unique per type of device.
    */
   readonly attribute DOMString id;
 
   /**
    * The game port index for the device. Unique per device
@@ -26,17 +32,17 @@ interface Gamepad {
 
   /**
    * true if this gamepad is currently connected to the system.
    */
   readonly attribute boolean connected;
 
   /**
    * The current state of all buttons on the device, an
-   * array of doubles.
+   * array of GamepadButton.
    */
   [Throws]
   readonly attribute nsIVariant buttons;
 
   /**
    * The current position of all axes on the device, an
    * array of doubles.
    */
--- a/ipc/chromium/src/chrome/common/mach_ipc_mac.mm
+++ b/ipc/chromium/src/chrome/common/mach_ipc_mac.mm
@@ -232,41 +232,37 @@ ReceivePort::~ReceivePort() {
   if (init_result_ == KERN_SUCCESS)
     mach_port_deallocate(mach_task_self(), port_);
 }
 
 //==============================================================================
 kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
                                           mach_msg_timeout_t timeout) {
   if (!out_message) {
-    printf("WaitForMessage failed because out_message was null\n");
     return KERN_INVALID_ARGUMENT;
   }
 
   // return any error condition encountered in constructor
-  if (init_result_ != KERN_SUCCESS) {
-    printf("WaitForMessage failed because init_result_ was %d\n", init_result_);
+  if (init_result_ != KERN_SUCCESS)
     return init_result_;
-  }
 
   out_message->Head()->msgh_bits = 0;
   out_message->Head()->msgh_local_port = port_;
   out_message->Head()->msgh_remote_port = MACH_PORT_NULL;
   out_message->Head()->msgh_reserved = 0;
   out_message->Head()->msgh_id = 0;
 
   kern_return_t result = mach_msg(out_message->Head(),
                                   MACH_RCV_MSG | MACH_RCV_TIMEOUT,
                                   0,
                                   out_message->MaxSize(),
                                   port_,
                                   timeout,              // timeout in ms
                                   MACH_PORT_NULL);
 
-  printf("WaitForMessage returned %d\n", result);
   return result;
 }
 
 #pragma mark -
 
 //==============================================================================
 // get a port with send rights corresponding to a named registered service
 MachPortSender::MachPortSender(const char *receive_port_name) {
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -11,16 +11,17 @@
 #include "jit/IonCode.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/ScopeObject.h"
 #include "vm/Shape.h"
 #include "vm/TypedArrayObject.h"
 
 #include "jscompartmentinlines.h"
 #include "jsinferinlines.h"
+#include "jsobjinlines.h"
 
 #ifdef JSGC_GENERATIONAL
 # include "gc/Nursery-inl.h"
 #endif
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::gc;
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -4535,18 +4535,18 @@ CodeGenerator::visitCharCodeAt(LCharCode
     Register index = ToRegister(lir->index());
     Register output = ToRegister(lir->output());
 
     OutOfLineCode *ool = oolCallVM(CharCodeAtInfo, lir, (ArgList(), str, index), StoreRegisterTo(output));
     if (!ool)
         return false;
 
     Address lengthAndFlagsAddr(str, JSString::offsetOfLengthAndFlags());
-
-    masm.branchTest32(Assembler::Zero, lengthAndFlagsAddr, Imm32(JSString::FLAGS_MASK), ool->entry());
+    masm.loadPtr(lengthAndFlagsAddr, output);
+    masm.branchTest32(Assembler::Zero, output, Imm32(JSString::FLAGS_MASK), ool->entry());
 
     // getChars
     Address charsAddr(str, JSString::offsetOfChars());
     masm.loadPtr(charsAddr, output);
     masm.load16ZeroExtend(BaseIndex(output, index, TimesTwo, 0), output);
 
     masm.bind(ool->rejoin());
     return true;
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -855,20 +855,21 @@ MacroAssembler::compareStrings(JSOp op, 
     branchPtr(Assembler::Equal, result, temp, fail);
     move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), result);
 
     bind(&done);
 }
 
 void
 MacroAssembler::checkInterruptFlagsPar(const Register &tempReg,
-                                       Label *fail)
+                                            Label *fail)
 {
     movePtr(ImmPtr(&GetIonContext()->runtime->interrupt), tempReg);
-    branch32(Assembler::NonZero, Address(tempReg, 0), Imm32(0), fail);
+    load32(Address(tempReg, 0), tempReg);
+    branchTest32(Assembler::NonZero, tempReg, tempReg, fail);
 }
 
 void
 MacroAssembler::maybeRemoveOsrFrame(Register scratch)
 {
     // Before we link an exit frame, check for an OSR frame, which is
     // indicative of working inside an existing bailout. In this case, remove
     // the OSR frame, so we don't explode the stack with repeated bailouts.
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -76,16 +76,19 @@ typedef struct nr_ice_turn_server_ nr_ic
 typedef struct nr_resolver_ nr_resolver;
 
 typedef void* NR_SOCKET;
 
 namespace mozilla {
 
 class NrIceMediaStream;
 
+const std::string kNrIceTransportUdp("udp");
+const std::string kNrIceTransportTcp("tcp");
+
 class NrIceStunServer {
  public:
   NrIceStunServer(const PRNetAddr& addr) : has_addr_(true) {
     memcpy(&addr_, &addr, sizeof(addr));
   }
 
    // The main function to use. Will take either an address or a hostname.
   static NrIceStunServer* Create(const std::string& addr, uint16_t port) {
@@ -129,17 +132,19 @@ class NrIceStunServer {
   uint16_t port_;
   PRNetAddr addr_;
 };
 
 class NrIceTurnServer : public NrIceStunServer {
  public:
   static NrIceTurnServer *Create(const std::string& addr, uint16_t port,
                                  const std::string& username,
-                                 const std::vector<unsigned char>& password) {
+                                 const std::vector<unsigned char>& password,
+                                 const std::string& transport = kNrIceTransportUdp) {
+    // TODO: Bug 906968 - Support TCP
     ScopedDeletePtr<NrIceTurnServer> server(
         new NrIceTurnServer(username, password));
 
     nsresult rv = server->Init(addr, port);
     if (NS_FAILED(rv))
       return nullptr;
 
     return server.forget();
--- a/media/webrtc/signaling/signaling.gyp
+++ b/media/webrtc/signaling/signaling.gyp
@@ -282,16 +282,17 @@
         './src/sipcc/core/gsm/h',
         './src/sipcc/plat/common',
         '../../../media/mtransport',
         '../../../dom/base',
         '../trunk/third_party/libsrtp/srtp/include',
         '../trunk/third_party/libsrtp/srtp/crypto/include',
         # Danger: this is to include config.h. This could be bad.
         '../trunk/third_party/libsrtp/config',
+        '../../../netwerk/sctp/datachannel',
       ],
 
       #
       # DEPENDENCIES
       #
       'dependencies': [
       ],
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -568,44 +568,62 @@ PeerConnectionImpl::ConvertRTCConfigurat
 {
 #ifdef MOZILLA_INTERNAL_API
   if (!aSrc.mIceServers.WasPassed()) {
     return NS_OK;
   }
   for (uint32_t i = 0; i < aSrc.mIceServers.Value().Length(); i++) {
     const RTCIceServer& server = aSrc.mIceServers.Value()[i];
     NS_ENSURE_TRUE(server.mUrl.WasPassed(), NS_ERROR_UNEXPECTED);
+
+    // Without STUN/TURN handlers, NS_NewURI returns nsSimpleURI rather than
+    // nsStandardURL. To parse STUN/TURN URI's to spec
+    // http://tools.ietf.org/html/draft-nandakumar-rtcweb-stun-uri-02#section-3
+    // http://tools.ietf.org/html/draft-petithuguenin-behave-turn-uri-03#section-3
+    // we parse out the query-string, and use ParseAuthority() on the rest
     nsRefPtr<nsIURI> url;
     nsresult rv = NS_NewURI(getter_AddRefs(url), server.mUrl.Value());
     NS_ENSURE_SUCCESS(rv, rv);
     bool isStun = false, isStuns = false, isTurn = false, isTurns = false;
     url->SchemeIs("stun", &isStun);
     url->SchemeIs("stuns", &isStuns);
     url->SchemeIs("turn", &isTurn);
     url->SchemeIs("turns", &isTurns);
     if (!(isStun || isStuns || isTurn || isTurns)) {
       return NS_ERROR_FAILURE;
     }
     nsAutoCString spec;
     rv = url->GetSpec(spec);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // TODO(jib@mozilla.com): Revisit once nsURI has STUN host+port (Bug 833509)
+    // TODO(jib@mozilla.com): Revisit once nsURI supports STUN/TURN (Bug 833509)
     int32_t port;
     nsAutoCString host;
+    nsAutoCString transport;
     {
       uint32_t hostPos;
       int32_t hostLen;
       nsAutoCString path;
       rv = url->GetPath(path);
       NS_ENSURE_SUCCESS(rv, rv);
 
-      // Tolerate '?transport=udp' by stripping it.
+      // Tolerate query-string + parse 'transport=[udp|tcp]' by hand.
       int32_t questionmark = path.FindChar('?');
       if (questionmark >= 0) {
+        const nsCString match = NS_LITERAL_CSTRING("transport=");
+
+        for (int32_t i = questionmark, endPos; i >= 0; i = endPos) {
+          endPos = path.FindCharInSet("&", i + 1);
+          const nsDependentCSubstring fieldvaluepair = Substring(path, i + 1,
+                                                                 endPos);
+          if (StringBeginsWith(fieldvaluepair, match)) {
+            transport = Substring(fieldvaluepair, match.Length());
+            ToLowerCase(transport);
+          }
+        }
         path.SetLength(questionmark);
       }
 
       rv = net_GetAuthURLParser()->ParseAuthority(path.get(), path.Length(),
                                                   nullptr,  nullptr,
                                                   nullptr,  nullptr,
                                                   &hostPos,  &hostLen, &port);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -620,17 +638,19 @@ PeerConnectionImpl::ConvertRTCConfigurat
       port = (isStuns || isTurns)? 5349 : 3478;
 
     if (isTurn || isTurns) {
       NS_ConvertUTF16toUTF8 credential(server.mCredential);
       NS_ConvertUTF16toUTF8 username(server.mUsername);
 
       if (!aDst->addTurnServer(host.get(), port,
                                username.get(),
-                               credential.get())) {
+                               credential.get(),
+                               (transport.IsEmpty() ?
+                                kNrIceTransportUdp : transport.get()))) {
         return NS_ERROR_FAILURE;
       }
     } else {
       if (!aDst->addStunServer(host.get(), port)) {
         return NS_ERROR_FAILURE;
       }
     }
   }
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -121,23 +121,25 @@ public:
     if (!server) {
       return false;
     }
     addStunServer(*server);
     return true;
   }
   bool addTurnServer(const std::string& addr, uint16_t port,
                      const std::string& username,
-                     const std::string& pwd)
+                     const std::string& pwd,
+                     const std::string& transport)
   {
     // TODO(ekr@rtfm.com): Need support for SASLprep for
     // username and password. Bug # ???
     std::vector<unsigned char> password(pwd.begin(), pwd.end());
 
-    NrIceTurnServer* server(NrIceTurnServer::Create(addr, port, username, password));
+    NrIceTurnServer* server(NrIceTurnServer::Create(addr, port, username, password,
+                                                    transport));
     if (!server) {
       return false;
     }
     addTurnServer(*server);
     return true;
   }
   void addStunServer(const NrIceStunServer& server) { mStunServers.push_back (server); }
   void addTurnServer(const NrIceTurnServer& server) { mTurnServers.push_back (server); }
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
@@ -709,17 +709,17 @@ typedef struct sdp_fmtp {
 
   /* END - All Video related FMTP parameters */
 
 } sdp_fmtp_t;
 
 /* a=sctpmap line used for Datachannels */
 typedef struct sdp_sctpmap {
     u16                       port;
-    u16                       streams;   /* Num streams per Datachannel */
+    u32                       streams;   /* Num streams per Datachannel */
     char                      protocol[SDP_MAX_STRING_LEN+1];
 } sdp_sctpmap_t;
 
 
 /* a=qos|secure|X-pc-qos|X-qos info */
 typedef struct sdp_qos {
     sdp_qos_strength_e        strength;
     sdp_qos_dir_e             direction;
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c
@@ -7,16 +7,17 @@
 
 #include "plstr.h"
 #include "sdp_os_defs.h"
 #include "sdp.h"
 #include "sdp_private.h"
 #include "sdp_base64.h"
 #include "mozilla/Assertions.h"
 #include "CSFLog.h"
+#include "DataChannelProtocol.h"
 
 static const char* logTag = "sdp_attr";
 
 /*
  * Macro for sdp_build_attr_fmtp
  * Adds name-value pair where value is char*
  */
 #define FMTP_BUILD_STRING(condition, name, value) \
@@ -2118,16 +2119,17 @@ sdp_result_e sdp_build_attr_fmtp (sdp_t 
     return SDP_SUCCESS;
 }
 
 sdp_result_e sdp_parse_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
                                     const char *ptr)
 {
     sdp_result_e result = SDP_SUCCESS;
     char tmp[SDP_MAX_STRING_LEN];
+    u32 streams;
 
     /* Find the payload type number. */
     attr_p->attr.sctpmap.port = (u16)sdp_getnextnumtok(ptr, &ptr,
                                                       " \t", &result);
     if (result != SDP_SUCCESS) {
         sdp_parse_error(sdp_p->peerconnection,
             "%s Warning: no sctpmap port number",
             sdp_p->debug_str);
@@ -2140,26 +2142,33 @@ sdp_result_e sdp_parse_attr_sctpmap(sdp_
             "%s Warning: No sctpmap protocol specified.",
             sdp_p->debug_str);
         sdp_p->conf_p->num_invalid_param++;
         return SDP_INVALID_PARAMETER;
     }
     sstrncpy(attr_p->attr.sctpmap.protocol, tmp,
         sizeof (attr_p->attr.sctpmap.protocol));
 
-    attr_p->attr.sctpmap.streams = (u16) sdp_getnextnumtok(ptr, &ptr, " \t",
-        &result);
+    streams = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
     if (result != SDP_SUCCESS) {
         sdp_parse_error(sdp_p->peerconnection,
             "%s Warning: No sctpmap streams specified.",
             sdp_p->debug_str);
         sdp_p->conf_p->num_invalid_param++;
         return SDP_INVALID_PARAMETER;
     }
 
+    /* streams value should be kept in the range 1..MAX_NUM_STREAMS */
+    if (streams < 1) {
+        streams = 1;
+    } else if (streams > MAX_NUM_STREAMS) {
+        streams = MAX_NUM_STREAMS;
+    }
+    attr_p->attr.sctpmap.streams = streams;
+
     return SDP_SUCCESS;
 }
 
 sdp_result_e sdp_build_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
                                     flex_string *fs)
 {
     MOZ_ASSERT(strlen(attr_p->attr.sctpmap.protocol) > 0);