Merge m-c to birch.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 02 May 2013 21:54:16 -0400
changeset 141706 82c443653988c0132c72481cb5958d685d200d4d
parent 141705 a12273aa858b6b51b6131929f5ecadf8f2ffda07 (current diff)
parent 141620 cdd14d9b3aae1142cc37c0be1b4e74c139bb5a37 (diff)
child 141707 4e3ac5fbf0740de3648c8b9568a87580e8ee80fa
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone23.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-c to birch.
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -3,16 +3,17 @@ dnl Local autoconf macros used with mozi
 dnl The contents of this file are under the Public Domain.
 dnl
 
 builtin(include, build/autoconf/acwinpaths.m4)dnl
 builtin(include, build/autoconf/hooks.m4)dnl
 builtin(include, build/autoconf/config.status.m4)dnl
 builtin(include, build/autoconf/toolchain.m4)dnl
 builtin(include, build/autoconf/ccache.m4)dnl
+builtin(include, build/autoconf/wrapper.m4)dnl
 builtin(include, build/autoconf/nspr.m4)dnl
 builtin(include, build/autoconf/nss.m4)dnl
 builtin(include, build/autoconf/pkg.m4)dnl
 builtin(include, build/autoconf/codeset.m4)dnl
 builtin(include, build/autoconf/altoptions.m4)dnl
 builtin(include, build/autoconf/mozprog.m4)dnl
 builtin(include, build/autoconf/mozheader.m4)dnl
 builtin(include, build/autoconf/mozcommonheader.m4)dnl
--- a/browser/metro/base/content/helperui/MenuUI.js
+++ b/browser/metro/base/content/helperui/MenuUI.js
@@ -383,16 +383,18 @@ MenuPopup.prototype = {
     window.removeEventListener("mousedown", this, true);
     Elements.stack.removeEventListener("PopupChanged", this, false);
 
     let self = this;
     this._panel.addEventListener("transitionend", function () {
       self._panel.removeEventListener("transitionend", arguments.callee);
       self._panel.removeAttribute("hiding");
       self._panel.hidden = true;
+      self._popup.style.maxWidth = "none";
+      self._popup.style.maxHeight = "none";
 
       let event = document.createEvent("Events");
       event.initEvent("popuphidden", true, false);
       document.dispatchEvent(event);
     });
 
     this._panel.setAttribute("hiding", "true");
     setTimeout(()=>this._panel.removeAttribute("showing"), 0);
@@ -427,39 +429,47 @@ MenuPopup.prototype = {
       aX -= width;
 
     if (aPositionOptions.bottomAligned)
       aY -= height;
 
     if (aPositionOptions.centerHorizontally)
       aX -= halfWidth;
 
-    if (aX < 0) {
-      aX = 0;
+    // Always leave some padding.
+    if (aX < kPositionPadding) {
+      aX = kPositionPadding;
     } else if (aX + width + kPositionPadding > screenWidth){
-      aX = screenWidth - width - kPositionPadding;
+      // Don't let the popup overflow to the right.
+      aX = Math.max(screenWidth - width - kPositionPadding, kPositionPadding);
     }
 
-    if (aY < 0 && aPositionOptions.moveBelowToFit) {
+    if (aY < kPositionPadding  && aPositionOptions.moveBelowToFit) {
       // show context menu below when it doesn't fit.
       aY = aPositionOptions.yPos;
-    } else if (aY < 0) {
-      aY = 0;
+    }
+
+    if (aY < kPositionPadding) {
+      aY = kPositionPadding;
+    } else if (aY + height + kPositionPadding > screenHeight){
+      aY = Math.max(screenHeight - height - kPositionPadding, kPositionPadding);
     }
 
     this._panel.left = aX;
     this._panel.top = aY;
 
-    if (!aPositionOptions.maxWidth) {
-      let excessY = (aY + height + kPositionPadding - screenHeight);
-      this._popup.style.maxHeight = (excessY > 0) ? (height - excessY) + "px" : "none";
+    if (!aPositionOptions.maxHeight) {
+      // Make sure it fits in the window.
+      let popupHeight = Math.min(aY + height + kPositionPadding, screenHeight - aY - kPositionPadding);
+      this._popup.style.maxHeight = popupHeight + "px";
     }
-    if (!aPositionOptions.maxHeight) {
-      let excessX = (aX + width + kPositionPadding - screenWidth);
-      this._popup.style.maxWidth = (excessX > 0) ? (width - excessX) + "px" : "none";
+
+    if (!aPositionOptions.maxWidth) {
+      let popupWidth = Math.min(aX + width + kPositionPadding, screenWidth - aX - kPositionPadding);
+      this._popup.style.maxWidth = popupWidth + "px";
     }
   },
 
   handleEvent: function handleEvent(aEvent) {
     switch (aEvent.type) {
       case "keypress":
         if (!this._wantTypeBehind) {
           // Hide the context menu so you can't type behind it.
--- a/browser/metro/base/tests/mochitest/browser_context_menu_tests.js
+++ b/browser/metro/base/tests/mochitest/browser_context_menu_tests.js
@@ -292,17 +292,17 @@ gTests.push({
     yield promise;
 
     // should *not* be visible
     ok(!ContextMenuUI._menuPopup._visible, "is visible");
 
     // the test above will invoke the app bar
     yield hideContextUI();
 
-    Browser.closeTab(Browser.selectedTab);
+    Browser.closeTab(Browser.selectedTab, { forceClose: true });
     purgeEventQueue();
   }
 });
 
 gTests.push({
   desc: "checks for context menu positioning when browser shifts",
   run: function test() {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
@@ -340,17 +340,17 @@ gTests.push({
     let notificationHeight = notification.boxObject.height;
 
     checkContextMenuPositionRange(ContextMenuUI._panel, 65, 80, notificationHeight +  155, notificationHeight + 180);
 
     promise = waitForEvent(document, "popuphidden");
     ContextMenuUI.hide();
     yield promise;
 
-    Browser.closeTab(Browser.selectedTab);
+    Browser.closeTab(Browser.selectedTab, { forceClose: true });
   }
 });
 
 // Image context menu tests
 gTests.push({
   desc: "image context menu",
   run: function test() {
     netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
@@ -487,18 +487,17 @@ gTests.push({
     yield popupPromise;
     let event = yield tabPromise;
 
     purgeEventQueue();
 
     let imagetab = Browser.getTabFromChrome(event.originalTarget);
     ok(imagetab != null, "tab created");
 
-    Browser.closeTab(imagetab);
-    yield waitForEvent(imagetab.chromeTab.parentNode, "TabRemove");
+    Browser.closeTab(imagetab, { forceClose: true });
   }
 });
 
 gTests.push({
   desc: "tests for subframe positioning",
   run: function test() {
     info(chromeRoot + "browser_context_menu_tests_03.html");
     yield addTab(chromeRoot + "browser_context_menu_tests_03.html");
--- a/browser/metro/base/tests/mochitest/browser_context_ui.js
+++ b/browser/metro/base/tests/mochitest/browser_context_ui.js
@@ -77,17 +77,17 @@ gTests.push({
     is(ContextUI.isExpanded, false, "Tab bar is not visible");
 
     let edit = document.getElementById("urlbar-edit");
     is(edit.value, "about:", "Location field contains the page URL");
     ok(document.commandDispatcher.focusedElement, edit.inputField, "Location field is focused");
     is(edit.selectionStart, 0, "Location field is selected");
     is(edit.selectionEnd, edit.value.length, "Location field is selected");
 
-    Browser.closeTab(tab);
+    Browser.closeTab(tab, { forceClose: true });
   }
 });
 
 function doEdgeUIGesture() {
   let event = document.createEvent("Events");
   event.initEvent("MozEdgeUIGesture", true, false);
   window.dispatchEvent(event);
 }
--- a/browser/metro/base/tests/mochitest/browser_history.js
+++ b/browser/metro/base/tests/mochitest/browser_history.js
@@ -230,16 +230,18 @@ gTests.push({
     // --------- delete item 2 for realz
 
     let item = gStartView._set.getItemsByUrl(uriFromIndex(2))[0];
 
     let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
     sendContextMenuClickToElement(window, item, 10, 10);
     yield promise;
 
+    yield waitForCondition(() => !deleteButton.hidden);
+
     ok(!deleteButton.hidden, "Delete button is visible.");
 
     let promise = waitForCondition(() => !restoreButton.hidden);
     EventUtils.synthesizeMouse(deleteButton, 10, 10, {}, window);
     yield promise;
 
     item = gStartView._set.getItemsByUrl(uriFromIndex(2))[0];
 
@@ -312,16 +314,18 @@ gTests.push({
     let item3 = gStartView._set.getItemsByUrl(uriFromIndex(12))[0];
 
     let promise = waitForEvent(Elements.appbar, "transitionend", null, Elements.appbar);
     sendContextMenuClickToElement(window, item1, 10, 10);
     sendContextMenuClickToElement(window, item2, 10, 10);
     sendContextMenuClickToElement(window, item3, 10, 10);
     yield promise;
 
+    yield waitForCondition(() => !deleteButton.hidden);
+
     ok(!deleteButton.hidden, "Delete button is visible.");
 
     let promise = waitForCondition(() => !restoreButton.hidden);
     EventUtils.synthesizeMouse(deleteButton, 10, 10, {}, window);
     yield promise;
 
     item1 = gStartView._set.getItemsByUrl(uriFromIndex(0))[0];
     item2 = gStartView._set.getItemsByUrl(uriFromIndex(5))[0];
--- a/browser/metro/base/tests/mochitest/head.js
+++ b/browser/metro/base/tests/mochitest/head.js
@@ -152,20 +152,20 @@ function clearSelection(aTarget) {
 /*=============================================================================
   Asynchronous Metro ui helpers
 =============================================================================*/
 
 function hideContextUI()
 {
   purgeEventQueue();
   if (ContextUI.isVisible) {
-    info("is visible, waiting...");
     let promise = waitForEvent(Elements.tray, "transitionend", null, Elements.tray);
     if (ContextUI.dismiss())
     {
+      info("ContextUI dismissed, waiting...");
       return promise;
     }
     return true;
   }
 }
 
 function showNavBar()
 {
@@ -184,16 +184,18 @@ function fireAppBarDisplayEvent()
   gWindow.dispatchEvent(event);
   purgeEventQueue();
   return promise;
 }
 
 /*=============================================================================
   Asynchronous test helpers
 =============================================================================*/
+let gOpenedTabs = [];
+
 /**
  *  Loads a URL in a new tab asynchronously.
  *
  * Usage:
  *    Task.spawn(function() {
  *      let tab = yield addTab("http://example.com/");
  *      ok(Browser.selectedTab == tab, "the new tab is selected");
  *    });
@@ -203,22 +205,37 @@ function fireAppBarDisplayEvent()
  */
 function addTab(aUrl) {
   return Task.spawn(function() {
     info("Opening "+aUrl+" in a new tab");
     let tab = Browser.addTab(aUrl, true);
     yield tab.pageShowPromise;
 
     is(tab.browser.currentURI.spec, aUrl, aUrl + " is loaded");
-    registerCleanupFunction(function() Browser.closeTab(tab));
+
+    yield hideContextUI();
+
+    gOpenedTabs.push(tab);
+
     throw new Task.Result(tab);
   });
 }
 
 /**
+ * Cleans up tabs left open by addTab().
+ * This is being called at runTests() after the test loop.
+ */
+function cleanUpOpenedTabs() {
+  let tab;
+  while(tab = gOpenedTabs.shift()) {
+    Browser.closeTab(Browser.getTabFromChrome(tab.chromeTab), { forceClose: true })
+  }
+}
+
+/**
  * Waits a specified number of miliseconds for a specified event to be
  * fired on a specified element.
  *
  * Usage:
  *    let receivedEvent = waitForEvent(element, "eventName");
  *    // Do some processing here that will cause the event to be fired
  *    // ...
  *    // Now yield until the Promise is fulfilled
@@ -645,16 +662,17 @@ function purgeEventQueue() {
 /*=============================================================================
   Test-running helpers
 =============================================================================*/
 let gCurrentTest = null;
 let gTests = [];
 
 function runTests() {
   waitForExplicitFinish();
+
   Task.spawn(function() {
     while((gCurrentTest = gTests.shift())){
       try {
         if ('function' == typeof gCurrentTest.setUp) {
           info("SETUP " + gCurrentTest.desc);
           yield Task.spawn(gCurrentTest.setUp.bind(gCurrentTest));
         }
         try {
@@ -667,16 +685,36 @@ function runTests() {
           }
         }
       } catch (ex) {
         ok(false, "runTests: Task failed - " + ex + ' at ' + ex.stack);
       } finally {
         info("END " + gCurrentTest.desc);
       }
     }
+
+    try {
+      cleanUpOpenedTabs();
+
+      let badTabs = [];
+      Browser.tabs.forEach(function(item, index, array) {
+        let location = item.browser.currentURI.spec;
+        if (index == 0 && location == "about:blank")
+          return;
+        ok(false, "Left over tab after test: '" + location + "'");
+        badTabs.push(item);
+      });
+
+      badTabs.forEach(function(item, index, array) {
+        Browser.closeTab(item, { forceClose: true });
+      });
+    } catch (ex) {
+      ok(false, "Cleanup tabs failed - " + ex);
+    }
+
     finish();
   });
 }
 
 function stubMethod(aObj, aMethod) {
   let origFunc = aObj[aMethod];
   let func = function() {
     func.calledWith = Array.slice(arguments);
--- a/browser/metro/base/tests/mochitest/res/textblock01.html
+++ b/browser/metro/base/tests/mochitest/res/textblock01.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8" />
 </head>
 <body>
-<div id="content">
+<div id="content" style="font-size: 105%">
     <p>(start of paragraph)
     Alice was beginning to get very (break)<br>
     tired of sitting by her sister on the bank, and of having nothing to do: once or twice she (span)
     <span>(start of span) had peeped into the book her sister was reading (end of span)</span>,
     but it had no pictures or conversations in it, `and what is the use of a book,' thought Alice
     `without pictures or conversation?' (break)<br> 
     (end of paragraph)</p>
     (in between paragraphs)
new file mode 100644
--- /dev/null
+++ b/build/autoconf/wrapper.m4
@@ -0,0 +1,22 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+dnl =======================================================================
+dnl = Enable compiling with various compiler wrappers (distcc, ccache, etc)
+dnl =======================================================================
+AC_DEFUN([MOZ_CHECK_COMPILER_WRAPPER],
+[
+MOZ_ARG_WITH_STRING(compiler_wrapper,
+[  --with-compiler-wrapper[=path/to/wrapper]
+    Enable compiling with wrappers such as distcc and ccache],
+    COMPILER_WRAPPER=$withval, COMPILER_WRAPPER="no")
+
+if test "$COMPILER_WRAPPER" != "no"; then
+    CC="$COMPILER_WRAPPER $CC"
+    CXX="$COMPILER_WRAPPER $CXX"
+    MOZ_USING_COMPILER_WRAPPER=1
+fi
+
+AC_SUBST(MOZ_USING_COMPILER_WRAPPER)
+])
--- a/configure.in
+++ b/configure.in
@@ -7389,16 +7389,17 @@ MOZ_ARG_ENABLE_BOOL(js-diagnostics,
                           Enable JS diagnostic assertions and breakpad data],
     JS_CRASH_DIAGNOSTICS=1,
     JS_CRASH_DIAGNOSTICS= )
 if test -n "$JS_CRASH_DIAGNOSTICS"; then
     AC_DEFINE(JS_CRASH_DIAGNOSTICS)
 fi
 
 MOZ_CHECK_CCACHE
+MOZ_CHECK_COMPILER_WRAPPER
 
 dnl ========================================================
 dnl = Enable static checking using gcc-dehydra
 dnl ========================================================
 
 MOZ_ARG_WITH_STRING(static-checking,
 [  --with-static-checking=path/to/gcc_dehydra.so
                           Enable static checking of code using GCC-dehydra],
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1678,40 +1678,40 @@ public:
 
   /**
    * The method checks whether the caller can access native anonymous content.
    * If there is no JS in the stack or privileged JS is running, this
    * method returns true, otherwise false.
    */
   static bool CanAccessNativeAnon();
 
-  static nsresult WrapNative(JSContext *cx, JSObject *scope,
+  static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
                              nsISupports *native, const nsIID* aIID,
                              JS::Value *vp,
                              // If non-null aHolder will keep the Value alive
                              // while there's a ref to it
                              nsIXPConnectJSObjectHolder** aHolder = nullptr,
                              bool aAllowWrapping = false)
   {
     return WrapNative(cx, scope, native, nullptr, aIID, vp, aHolder,
                       aAllowWrapping);
   }
 
   // Same as the WrapNative above, but use this one if aIID is nsISupports' IID.
-  static nsresult WrapNative(JSContext *cx, JSObject *scope,
+  static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
                              nsISupports *native, JS::Value *vp,
                              // If non-null aHolder will keep the Value alive
                              // while there's a ref to it
                              nsIXPConnectJSObjectHolder** aHolder = nullptr,
                              bool aAllowWrapping = false)
   {
     return WrapNative(cx, scope, native, nullptr, nullptr, vp, aHolder,
                       aAllowWrapping);
   }
-  static nsresult WrapNative(JSContext *cx, JSObject *scope,
+  static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
                              nsISupports *native, nsWrapperCache *cache,
                              JS::Value *vp,
                              // If non-null aHolder will keep the Value alive
                              // while there's a ref to it
                              nsIXPConnectJSObjectHolder** aHolder = nullptr,
                              bool aAllowWrapping = false)
   {
     return WrapNative(cx, scope, native, cache, nullptr, vp, aHolder,
@@ -2141,22 +2141,22 @@ public:
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
-  static nsresult WrapNative(JSContext *cx, JSObject *scope,
+  static nsresult WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
                              nsISupports *native, nsWrapperCache *cache,
                              const nsIID* aIID, JS::Value *vp,
                              nsIXPConnectJSObjectHolder** aHolder,
                              bool aAllowWrapping);
-                            
+
   static nsresult DispatchEvent(nsIDocument* aDoc,
                                 nsISupports* aTarget,
                                 const nsAString& aEventName,
                                 bool aCanBubble,
                                 bool aCancelable,
                                 bool aTrusted,
                                 bool *aDefaultAction = nullptr);
 
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -2137,17 +2137,17 @@ protected:
 
   nsCString GetContentTypeInternal() const
   {
     return mContentType;
   }
 
   // All document WrapNode implementations MUST call this method.  A
   // false return value means an exception was thrown.
-  bool PostCreateWrapper(JSContext* aCx, JSObject *aNewObject);
+  bool PostCreateWrapper(JSContext* aCx, JS::Handle<JSObject*> aNewObject);
 
   nsCString mReferrer;
   nsString mLastModified;
 
   nsCOMPtr<nsIURI> mDocumentURI;
   nsCOMPtr<nsIURI> mOriginalURI;
   nsCOMPtr<nsIURI> mDocumentBaseURI;
 
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -527,17 +527,17 @@ nsContentList::Item(uint32_t aIndex, boo
 
   return mElements.SafeElementAt(aIndex);
 }
 
 nsIContent *
 nsContentList::NamedItem(const nsAString& aName, bool aDoFlush)
 {
   BringSelfUpToDate(aDoFlush);
-    
+
   uint32_t i, count = mElements.Length();
 
   // Typically IDs and names are atomized
   nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
   NS_ENSURE_TRUE(name, nullptr);
 
   for (i = 0; i < count; i++) {
     nsIContent *content = mElements[i];
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5834,18 +5834,19 @@ nsContentUtils::DispatchXULCommand(nsICo
   nsCOMPtr<EventTarget> target = do_QueryInterface(aTarget);
   NS_ENSURE_STATE(target);
   bool dummy;
   return target->DispatchEvent(event, &dummy);
 }
 
 // static
 nsresult
-nsContentUtils::WrapNative(JSContext *cx, JSObject *scope, nsISupports *native,
-                           nsWrapperCache *cache, const nsIID* aIID, JS::Value *vp,
+nsContentUtils::WrapNative(JSContext *cx, JS::Handle<JSObject*> scope,
+                           nsISupports *native, nsWrapperCache *cache,
+                           const nsIID* aIID, JS::Value *vp,
                            nsIXPConnectJSObjectHolder **aHolder,
                            bool aAllowWrapping)
 {
   if (!native) {
     NS_ASSERTION(!aHolder || !*aHolder, "*aHolder should be null!");
 
     *vp = JSVAL_NULL;
 
@@ -5924,17 +5925,17 @@ nsContentUtils::CreateBlobBuffer(JSConte
   void* blobData = moz_malloc(blobLen);
   nsCOMPtr<nsIDOMBlob> blob;
   if (blobData) {
     memcpy(blobData, aData.BeginReading(), blobLen);
     blob = new nsDOMMemoryFile(blobData, blobLen, EmptyString());
   } else {
     return NS_ERROR_OUT_OF_MEMORY;
   }
-  JSObject* scope = JS_GetGlobalForScopeChain(aCx);
+  JS::Rooted<JSObject*> scope(aCx, JS_GetGlobalForScopeChain(aCx));
   return nsContentUtils::WrapNative(aCx, scope, blob, &aBlob, nullptr, true);
 }
 
 void
 nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr)
 {
   // In common cases where we don't have nulls in the
   // string we can simple simply bypass the checking code.
@@ -6375,21 +6376,21 @@ nsContentUtils::IsPatternMatching(nsAStr
   JSObject* re = JS_NewUCRegExpObjectNoStatics(cx, static_cast<jschar*>
                                                  (aPattern.BeginWriting()),
                                                aPattern.Length(), 0);
   if (!re) {
     JS_ClearPendingException(cx);
     return true;
   }
 
-  JS::Value rval = JS::NullValue();
+  JS::Rooted<JS::Value> rval(cx, JS::NullValue());
   size_t idx = 0;
   if (!JS_ExecuteRegExpNoStatics(cx, re,
                                  static_cast<jschar*>(aValue.BeginWriting()),
-                                 aValue.Length(), &idx, true, &rval)) {
+                                 aValue.Length(), &idx, true, rval.address())) {
     JS_ClearPendingException(cx);
     return true;
   }
 
   return !rval.isNull();
 }
 
 // static
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -204,53 +204,53 @@ nsDOMMultipartFile::InitBlob(JSContext* 
     }
   }
 
   if (aArgc > 0) {
     if (!aArgv[0].isObject()) {
       return NS_ERROR_TYPE_ERR; // We're not interested
     }
 
-    JSObject& obj = aArgv[0].toObject();
-    if (!JS_IsArrayObject(aCx, &obj)) {
+    JS::Rooted<JSObject*> obj(aCx, &aArgv[0].toObject());
+    if (!JS_IsArrayObject(aCx, obj)) {
       return NS_ERROR_TYPE_ERR; // We're not interested
     }
 
     BlobSet blobSet;
 
     uint32_t length;
-    JS_ALWAYS_TRUE(JS_GetArrayLength(aCx, &obj, &length));
+    JS_ALWAYS_TRUE(JS_GetArrayLength(aCx, obj, &length));
     for (uint32_t i = 0; i < length; ++i) {
-      JS::Value element;
-      if (!JS_GetElement(aCx, &obj, i, &element))
+      JS::Rooted<JS::Value> element(aCx);
+      if (!JS_GetElement(aCx, obj, i, element.address()))
         return NS_ERROR_TYPE_ERR;
 
       if (element.isObject()) {
-        JSObject& obj = element.toObject();
-        nsCOMPtr<nsIDOMBlob> blob = aUnwrapFunc(aCx, &obj);
+        JS::Rooted<JSObject*> obj(aCx, &element.toObject());
+        nsCOMPtr<nsIDOMBlob> blob = aUnwrapFunc(aCx, obj);
         if (blob) {
           // Flatten so that multipart blobs will never nest
           nsDOMFileBase* file = static_cast<nsDOMFileBase*>(
               static_cast<nsIDOMBlob*>(blob));
           const nsTArray<nsCOMPtr<nsIDOMBlob> >*
               subBlobs = file->GetSubBlobs();
           if (subBlobs) {
             blobSet.AppendBlobs(*subBlobs);
           } else {
             blobSet.AppendBlob(blob);
           }
           continue;
         }
-        if (JS_IsArrayBufferViewObject(&obj)) {
-          blobSet.AppendVoidPtr(JS_GetArrayBufferViewData(&obj),
-                                JS_GetArrayBufferViewByteLength(&obj));
+        if (JS_IsArrayBufferViewObject(obj)) {
+          blobSet.AppendVoidPtr(JS_GetArrayBufferViewData(obj),
+                                JS_GetArrayBufferViewByteLength(obj));
           continue;
         }
-        if (JS_IsArrayBufferObject(&obj)) {
-          blobSet.AppendArrayBuffer(&obj);
+        if (JS_IsArrayBufferObject(obj)) {
+          blobSet.AppendArrayBuffer(obj);
           continue;
         }
         // neither Blob nor ArrayBuffer(View)
       } else if (element.isString()) {
         blobSet.AppendString(element.toString(), nativeEOL, aCx);
         continue;
       }
       // coerce it to a string
--- a/content/base/src/nsDOMFileReader.cpp
+++ b/content/base/src/nsDOMFileReader.cpp
@@ -179,18 +179,18 @@ nsDOMFileReader::GetReadyState(uint16_t 
 {
   *aReadyState = ReadyState();
   return NS_OK;
 }
 
 JS::Value
 nsDOMFileReader::GetResult(JSContext* aCx, ErrorResult& aRv)
 {
-  JS::Value result = JS::UndefinedValue();
-  aRv = GetResult(aCx, &result);
+  JS::Rooted<JS::Value> result(aCx, JS::UndefinedValue());
+  aRv = GetResult(aCx, result.address());
   return result;
 }
 
 NS_IMETHODIMP
 nsDOMFileReader::GetResult(JSContext* aCx, JS::Value* aResult)
 {
   if (mDataFormat == FILE_AS_ARRAYBUFFER) {
     if (mReadyState == nsIDOMFileReader::DONE && mResultArrayBuffer) {
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -4961,39 +4961,40 @@ nsIDocument::CreateAttributeNS(const nsA
   nsRefPtr<Attr> attribute = new Attr(nullptr, nodeInfo.forget(),
                                       EmptyString(), true);
   return attribute.forget();
 }
 
 static JSBool
 CustomElementConstructor(JSContext *aCx, unsigned aArgc, JS::Value* aVp)
 {
-  JS::Value calleeVal = JS_CALLEE(aCx, aVp);
-
-  JSObject* global = JS_GetGlobalForObject(aCx, &calleeVal.toObject());
+  JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
+
+  JS::Rooted<JSObject*> global(aCx,
+    JS_GetGlobalForObject(aCx, &args.callee()));
   nsCOMPtr<nsPIDOMWindow> window = do_QueryWrapper(aCx, global);
   MOZ_ASSERT(window, "Should have a non-null window");
 
   nsIDocument* document = window->GetDoc();
 
   // Function name is the type of the custom element.
-  JSString* jsFunName = JS_GetFunctionId(JS_ValueToFunction(aCx, calleeVal));
+  JSString* jsFunName =
+    JS_GetFunctionId(JS_ValueToFunction(aCx, args.calleev()));
   nsDependentJSString elemName;
   if (!elemName.init(aCx, jsFunName)) {
     return false;
   }
 
   nsCOMPtr<nsIContent> newElement;
   nsresult rv = document->CreateElem(elemName, nullptr, kNameSpaceID_XHTML,
                                      getter_AddRefs(newElement));
-  JS::Value v;
-  rv = nsContentUtils::WrapNative(aCx, global, newElement, newElement, &v);
+  rv = nsContentUtils::WrapNative(aCx, global, newElement, newElement,
+                                  args.rval().address());
   NS_ENSURE_SUCCESS(rv, false);
 
-  JS_SET_RVAL(aCx, aVp, v);
   return true;
 }
 
 bool
 nsDocument::RegisterEnabled()
 {
   static bool sPrefValue =
     Preferences::GetBool("dom.webcomponents.enabled", false);
@@ -5045,49 +5046,50 @@ nsDocument::Register(JSContext* aCx, con
   if (!sgo) {
     rv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
   JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject());
 
   JSAutoCompartment ac(aCx, global);
 
-  JSObject* htmlProto = HTMLElementBinding::GetProtoObject(aCx, global);
+  JS::Handle<JSObject*> htmlProto(
+    HTMLElementBinding::GetProtoObject(aCx, global));
   if (!htmlProto) {
     rv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return nullptr;
   }
 
-  JSObject* protoObject;
+  JS::Rooted<JSObject*> protoObject(aCx);
   if (!aOptions.mPrototype) {
     protoObject = JS_NewObject(aCx, nullptr, htmlProto, nullptr);
     if (!protoObject) {
       rv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
   } else {
     // If a prototype is provided, we must check to ensure that it inherits
     // from HTMLElement.
     protoObject = aOptions.mPrototype;
-    if (!JS_WrapObject(aCx, &protoObject)) {
+    if (!JS_WrapObject(aCx, protoObject.address())) {
       rv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
 
     // Check the proto chain for HTMLElement prototype.
-    JSObject* protoProto;
-    if (!JS_GetPrototype(aCx, protoObject, &protoProto)) {
+    JS::Rooted<JSObject*> protoProto(aCx);
+    if (!JS_GetPrototype(aCx, protoObject, protoProto.address())) {
       rv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
     while (protoProto) {
       if (protoProto == htmlProto) {
         break;
       }
-      if (!JS_GetPrototype(aCx, protoProto, &protoProto)) {
+      if (!JS_GetPrototype(aCx, protoProto, protoProto.address())) {
         rv.Throw(NS_ERROR_UNEXPECTED);
         return nullptr;
       }
     }
 
     if (!protoProto) {
       rv.Throw(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
       return nullptr;
@@ -6569,29 +6571,29 @@ nsIDocument::AdoptNode(nsINode& aAdopted
       return nullptr;
     }
   }
 
   nsCOMPtr<nsIDocument> oldDocument = adoptedNode->OwnerDoc();
   bool sameDocument = oldDocument == this;
 
   AutoJSContext cx;
-  JSObject *newScope = nullptr;
+  JS::Rooted<JSObject*> newScope(cx, nullptr);
   if (!sameDocument) {
     newScope = GetWrapper();
     if (!newScope && GetScopeObject() && GetScopeObject()->GetGlobalJSObject()) {
       // We need to pass some sort of scope object to WrapNative. It's kind of
       // irrelevant, given that we're passing aAllowWrapping = false, and
       // documents should always insist on being wrapped in an canonical
       // scope. But we try to pass something sane anyway.
-      JSObject *global = GetScopeObject()->GetGlobalJSObject();
-
-      JS::Value v;
-      rv = nsContentUtils::WrapNative(cx, global, this, this, &v, nullptr,
-                                      /* aAllowWrapping = */ false);
+      JS::Rooted<JSObject*> global(cx, GetScopeObject()->GetGlobalJSObject());
+
+      JS::Rooted<JS::Value> v(cx);
+      rv = nsContentUtils::WrapNative(cx, global, this, this, v.address(),
+                                      nullptr, /* aAllowWrapping = */ false);
       if (rv.Failed())
         return nullptr;
       newScope = &v.toObject();
     }
   }
 
   nsCOMArray<nsINode> nodesWithProperties;
   rv = nsNodeUtils::Adopt(adoptedNode, sameDocument ? nullptr : mNodeInfoManager,
@@ -11195,38 +11197,39 @@ nsIDocument::Evaluate(const nsAString& a
   rv = evaluator->Evaluate(aExpression, contextNode, aResolver, aType,
                            aResult, getter_AddRefs(res));
   return res.forget();
 }
 
 // This is just a hack around the fact that window.document is not
 // [Unforgeable] yet.
 bool
-nsIDocument::PostCreateWrapper(JSContext* aCx, JSObject *aNewObject)
+nsIDocument::PostCreateWrapper(JSContext* aCx, JS::Handle<JSObject*> aNewObject)
 {
   MOZ_ASSERT(IsDOMBinding());
 
   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(GetScriptGlobalObject());
   if (!win) {
     // No window, nothing else to do here
     return true;
   }
 
   if (this != win->GetExtantDoc()) {
     // We're not the current document; we're also done here
     return true;
   }
 
   JSAutoCompartment ac(aCx, aNewObject);
 
-  jsval winVal;
+  JS::Rooted<JS::Value> winVal(aCx);
   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
   nsresult rv = nsContentUtils::WrapNative(aCx, aNewObject, win,
                                            &NS_GET_IID(nsIDOMWindow),
-                                           &winVal, getter_AddRefs(holder),
+                                           winVal.address(),
+                                           getter_AddRefs(holder),
                                            false);
   if (NS_FAILED(rv)) {
     return Throw<true>(aCx, rv);
   }
 
   NS_NAMED_LITERAL_STRING(doc_str, "document");
 
   return JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(winVal),
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -651,23 +651,24 @@ nsFrameMessageManager::ReceiveMessage(ns
         }
         nsCxPusher pusher;
         pusher.Push(ctx);
 
         JSAutoRequest ar(ctx);
         JSAutoCompartment ac(ctx, object);
 
         // The parameter for the listener function.
-        JSObject* param = JS_NewObject(ctx, nullptr, nullptr, nullptr);
+        JS::Rooted<JSObject*> param(ctx,
+          JS_NewObject(ctx, nullptr, nullptr, nullptr));
         NS_ENSURE_TRUE(param, NS_ERROR_OUT_OF_MEMORY);
 
-        JS::Value targetv;
-        nsContentUtils::WrapNative(ctx,
-                                   JS_GetGlobalForObject(ctx, object),
-                                   aTarget, &targetv, nullptr, true);
+        JS::Rooted<JS::Value> targetv(ctx);
+        JS::Rooted<JSObject*> global(ctx, JS_GetGlobalForObject(ctx, object));
+        nsContentUtils::WrapNative(ctx, global, aTarget, targetv.address(),
+                                   nullptr, true);
 
         // To keep compatibility with e10s message manager,
         // define empty objects array.
         if (!aObjectsArray) {
           // Because we want JS messages to have always the same properties,
           // create array even if len == 0.
           aObjectsArray = JS_NewArrayObject(ctx, 0, nullptr);
           if (!aObjectsArray) {
@@ -694,50 +695,51 @@ nsFrameMessageManager::ReceiveMessage(ns
         JS_DefineProperty(ctx, param, "name",
                           STRING_TO_JSVAL(jsMessage), nullptr, nullptr, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "sync",
                           BOOLEAN_TO_JSVAL(aSync), nullptr, nullptr, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "json", json, nullptr, nullptr, JSPROP_ENUMERATE); // deprecated
         JS_DefineProperty(ctx, param, "data", json, nullptr, nullptr, JSPROP_ENUMERATE);
         JS_DefineProperty(ctx, param, "objects", objectsv, nullptr, nullptr, JSPROP_ENUMERATE);
 
-        JS::Value thisValue = JSVAL_VOID;
+        JS::Rooted<JS::Value> thisValue(ctx, JS::UndefinedValue());
 
-        JS::Value funval;
+        JS::Rooted<JS::Value> funval(ctx);
         if (JS_ObjectIsCallable(ctx, object)) {
           // If the listener is a JS function:
           funval.setObject(*object);
 
           // A small hack to get 'this' value right on content side where
           // messageManager is wrapped in TabChildGlobal.
           nsCOMPtr<nsISupports> defaultThisValue;
           if (mChrome) {
             defaultThisValue = do_QueryObject(this);
           } else {
             defaultThisValue = aTarget;
           }
-          nsContentUtils::WrapNative(ctx,
-                                     JS_GetGlobalForObject(ctx, object),
-                                     defaultThisValue, &thisValue, nullptr, true);
+          JS::Rooted<JSObject*> global(ctx, JS_GetGlobalForObject(ctx, object));
+          nsContentUtils::WrapNative(ctx, global, defaultThisValue,
+                                     thisValue.address(), nullptr, true);
         } else {
           // If the listener is a JS object which has receiveMessage function:
-          if (!JS_GetProperty(ctx, object, "receiveMessage", &funval) ||
+          if (!JS_GetProperty(ctx, object, "receiveMessage",
+                              funval.address()) ||
               !funval.isObject())
             return NS_ERROR_UNEXPECTED;
 
           // Check if the object is even callable.
           NS_ENSURE_STATE(JS_ObjectIsCallable(ctx, &funval.toObject()));
           thisValue.setObject(*object);
         }
 
         JS::Rooted<JS::Value> rval(ctx, JSVAL_VOID);
         JS::Rooted<JS::Value> argv(ctx, JS::ObjectValue(*param));
 
         {
-          JSObject* thisObject = JSVAL_TO_OBJECT(thisValue);
+          JS::Rooted<JSObject*> thisObject(ctx, thisValue.toObjectOrNull());
 
           JSAutoCompartment tac(ctx, thisObject);
           if (!JS_WrapValue(ctx, argv.address()))
             return NS_ERROR_UNEXPECTED;
 
           JS_CallFunctionValue(ctx, thisObject,
                                funval, 1, argv.address(), rval.address());
           if (aJSONRetVal) {
@@ -1068,18 +1070,19 @@ nsFrameScriptExecutor::TryCacheLoadAndCo
       mGlobal->GetJSObject(&global);
       if (global) {
         JSAutoCompartment ac(mCx, global);
         JS::CompileOptions options(mCx);
         options.setNoScriptRval(true)
                .setFileAndLine(url.get(), 1)
                .setPrincipals(nsJSPrincipals::get(mPrincipal));
         JS::RootedObject empty(mCx, nullptr);
-        JSScript* script = JS::Compile(mCx, empty, options,
-                                       dataString.get(), dataString.Length());
+        JS::Rooted<JSScript*> script(mCx,
+          JS::Compile(mCx, empty, options, dataString.get(),
+                      dataString.Length()));
 
         if (script) {
           nsAutoCString scheme;
           uri->GetScheme(scheme);
           // We don't cache data: scripts!
           if (!scheme.EqualsLiteral("data")) {
             nsFrameJSScriptExecutorHolder* holder =
               new nsFrameJSScriptExecutorHolder(script);
@@ -1095,18 +1098,18 @@ nsFrameScriptExecutor::TryCacheLoadAndCo
     }
   }
 }
 
 bool
 nsFrameScriptExecutor::InitTabChildGlobalInternal(nsISupports* aScope,
                                                   const nsACString& aID)
 {
-  
-  nsCOMPtr<nsIJSRuntimeService> runtimeSvc = 
+
+  nsCOMPtr<nsIJSRuntimeService> runtimeSvc =
     do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
   NS_ENSURE_TRUE(runtimeSvc, false);
 
   JSRuntime* rt = nullptr;
   runtimeSvc->GetRuntime(&rt);
   NS_ENSURE_TRUE(rt, false);
 
   JSContext* cx = JS_NewContext(rt, 8192);
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1976,16 +1976,17 @@ GK_ATOM(CriticalDisplayPort, "_critical_
 // Names for system metrics
 GK_ATOM(scrollbar_start_backward, "scrollbar-start-backward")
 GK_ATOM(scrollbar_start_forward, "scrollbar-start-forward")
 GK_ATOM(scrollbar_end_backward, "scrollbar-end-backward")
 GK_ATOM(scrollbar_end_forward, "scrollbar-end-forward")
 GK_ATOM(scrollbar_thumb_proportional, "scrollbar-thumb-proportional")
 GK_ATOM(images_in_menus, "images-in-menus")
 GK_ATOM(images_in_buttons, "images-in-buttons")
+GK_ATOM(overlay_scrollbars, "overlay-scrollbars")
 GK_ATOM(windows_default_theme, "windows-default-theme")
 GK_ATOM(mac_graphite_theme, "mac-graphite-theme")
 GK_ATOM(mac_lion_theme, "mac-lion-theme")
 GK_ATOM(windows_compositor, "windows-compositor")
 GK_ATOM(windows_glass, "windows-glass")
 GK_ATOM(touch_enabled, "touch-enabled")
 GK_ATOM(maemo_classic, "maemo-classic")
 GK_ATOM(menubar_drag, "menubar-drag")
@@ -2004,16 +2005,17 @@ GK_ATOM(windows_theme_generic, "windows-
 // And the same again, as media query keywords.
 GK_ATOM(_moz_scrollbar_start_backward, "-moz-scrollbar-start-backward")
 GK_ATOM(_moz_scrollbar_start_forward, "-moz-scrollbar-start-forward")
 GK_ATOM(_moz_scrollbar_end_backward, "-moz-scrollbar-end-backward")
 GK_ATOM(_moz_scrollbar_end_forward, "-moz-scrollbar-end-forward")
 GK_ATOM(_moz_scrollbar_thumb_proportional, "-moz-scrollbar-thumb-proportional")
 GK_ATOM(_moz_images_in_menus, "-moz-images-in-menus")
 GK_ATOM(_moz_images_in_buttons, "-moz-images-in-buttons")
+GK_ATOM(_moz_overlay_scrollbars, "-moz-overlay-scrollbars")
 GK_ATOM(_moz_windows_default_theme, "-moz-windows-default-theme")
 GK_ATOM(_moz_mac_graphite_theme, "-moz-mac-graphite-theme")
 GK_ATOM(_moz_mac_lion_theme, "-moz-mac-lion-theme")
 GK_ATOM(_moz_windows_compositor, "-moz-windows-compositor")
 GK_ATOM(_moz_windows_classic, "-moz-windows-classic")
 GK_ATOM(_moz_windows_glass, "-moz-windows-glass")
 GK_ATOM(_moz_windows_theme, "-moz-windows-theme")
 GK_ATOM(_moz_touch_enabled, "-moz-touch-enabled")
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -2646,17 +2646,17 @@ nsObjectLoadingContent::NotifyContentObj
   nsIScriptContext *scx = sgo->GetContext();
   if (!scx)
     return;
 
   JSContext *cx = scx->GetNativeContext();
   nsCxPusher pusher;
   pusher.Push(cx);
 
-  JSObject *obj = thisContent->GetWrapper();
+  JS::Rooted<JSObject*> obj(cx, thisContent->GetWrapper());
   if (!obj) {
     // Nothing to do here if there's no wrapper for mContent. The proto
     // chain will be fixed appropriately when the wrapper is created.
     return;
   }
 
   SetupProtoChain(cx, obj);
 }
@@ -2844,24 +2844,24 @@ nsObjectLoadingContent::GetContentDocume
 JS::Value
 nsObjectLoadingContent::LegacyCall(JSContext* aCx,
                                    JS::Value aThisVal,
                                    const Sequence<JS::Value>& aArguments,
                                    ErrorResult& aRv)
 {
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
-  JSObject* obj = thisContent->GetWrapper();
+  JS::Rooted<JSObject*> obj(aCx, thisContent->GetWrapper());
   MOZ_ASSERT(obj, "How did we get called?");
 
   // Make sure we're not dealing with an Xray.  Our DoCall code can't handle
   // random cross-compartment wrappers, so we're going to have to wrap
   // everything up into our compartment, but that means we need to check that
   // this is not an Xray situation by hand.
-  if (!JS_WrapObject(aCx, &obj)) {
+  if (!JS_WrapObject(aCx, obj.address())) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return JS::UndefinedValue();
   }
 
   if (nsDOMClassInfo::ObjectIsNativeWrapper(aCx, obj)) {
     aRv.Throw(NS_ERROR_NOT_AVAILABLE);
     return JS::UndefinedValue();
   }
@@ -2919,17 +2919,18 @@ nsObjectLoadingContent::LegacyCall(JSCon
     return JS::UndefinedValue();
   }
 
   Telemetry::Accumulate(Telemetry::PLUGIN_CALLED_DIRECTLY, true);
   return retval;
 }
 
 void
-nsObjectLoadingContent::SetupProtoChain(JSContext* aCx, JSObject* aObject)
+nsObjectLoadingContent::SetupProtoChain(JSContext* aCx,
+                                        JS::Handle<JSObject*> aObject)
 {
   MOZ_ASSERT(nsCOMPtr<nsIContent>(do_QueryInterface(
     static_cast<nsIObjectLoadingContent*>(this)))->IsDOMBinding());
 
   if (mType != eType_Plugin) {
     return;
   }
 
@@ -3081,38 +3082,38 @@ void
 nsObjectLoadingContent::TeardownProtoChain()
 {
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
   // Use the safe JSContext here as we're not always able to find the
   // JSContext associated with the NPP any more.
   JSContext *cx = nsContentUtils::GetSafeJSContext();
-  JSObject *obj = thisContent->GetWrapper();
+  JS::Rooted<JSObject*> obj(cx, thisContent->GetWrapper());
   NS_ENSURE_TRUE(obj, /* void */);
 
-  JSObject *proto;
+  JS::Rooted<JSObject*> proto(cx);
   JSAutoRequest ar(cx);
   JSAutoCompartment ac(cx, obj);
 
   // Loop over the DOM element's JS object prototype chain and remove
   // all JS objects of the class sNPObjectJSWrapperClass
   bool removed = false;
   while (obj) {
-    if (!::JS_GetPrototype(cx, obj, &proto)) {
+    if (!::JS_GetPrototype(cx, obj, proto.address())) {
       return;
     }
     if (!proto) {
       break;
     }
     // Unwrap while checking the jsclass - if the prototype is a wrapper for
     // an NP object, that counts too.
     if (JS_GetClass(js::UncheckedUnwrap(proto)) == &sNPObjectJSWrapperClass) {
       // We found an NPObject on the proto chain, get its prototype...
-      if (!::JS_GetPrototype(cx, proto, &proto)) {
+      if (!::JS_GetPrototype(cx, proto, proto.address())) {
         return;
       }
 
       MOZ_ASSERT(!removed, "more than one NPObject in prototype chain");
       removed = true;
 
       // ... and pull it out of the chain.
       ::JS_SetPrototype(cx, obj, proto);
@@ -3153,17 +3154,17 @@ nsObjectLoadingContent::SetupProtoChainR
   // like we could just always use the safe context....
   nsCxPusher pusher;
   JSContext* cx = mContext ? mContext->GetNativeContext()
                            : nsContentUtils::GetSafeJSContext();
   pusher.Push(cx);
 
   nsCOMPtr<nsIContent> content;
   CallQueryInterface(mContent.get(), getter_AddRefs(content));
-  JSObject* obj = content->GetWrapper();
+  JS::Rooted<JSObject*> obj(cx, content->GetWrapper());
   if (!obj) {
     // No need to set up our proto chain if we don't even have an object
     return NS_OK;
   }
   nsObjectLoadingContent* objectLoadingContent =
     static_cast<nsObjectLoadingContent*>(mContent.get());
   objectLoadingContent->SetupProtoChain(cx, obj);
   return NS_OK;
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -139,17 +139,17 @@ class nsObjectLoadingContent : public ns
      * SetupProtoChain handles actually inserting the plug-in
      * scriptable object into the proto chain if needed.
      *
      * DoNewResolve is a hook that allows us to find out when the web
      * page is looking up a property name on our object and make sure
      * that our plug-in, if any, is instantiated.
      */
     // Helper for WebIDL node wrapping
-    void SetupProtoChain(JSContext* aCx, JSObject* aObject);
+    void SetupProtoChain(JSContext* aCx, JS::Handle<JSObject*> aObject);
 
     // Remove plugin from protochain
     void TeardownProtoChain();
 
     // Helper for WebIDL newResolve
     bool DoNewResolve(JSContext* aCx, JSHandleObject aObject, JSHandleId aId,
                       unsigned aFlags, JS::MutableHandle<JSObject*> aObjp);
 
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -997,28 +997,28 @@ nsXMLHttpRequest::GetResponse(JSContext*
       }
     }
 
     if (!mResponseBlob) {
       return JSVAL_NULL;
     }
 
     JS::Value result = JSVAL_NULL;
-    JSObject* scope = JS_GetGlobalForScopeChain(aCx);
+    JS::Rooted<JSObject*> scope(aCx, JS_GetGlobalForScopeChain(aCx));
     aRv = nsContentUtils::WrapNative(aCx, scope, mResponseBlob, &result,
                                      nullptr, true);
     return result;
   }
   case XML_HTTP_RESPONSE_TYPE_DOCUMENT:
   {
     if (!(mState & XML_HTTP_REQUEST_DONE) || !mResponseXML) {
       return JSVAL_NULL;
     }
 
-    JSObject* scope = JS_GetGlobalForScopeChain(aCx);
+    JS::Rooted<JSObject*> scope(aCx, JS_GetGlobalForScopeChain(aCx));
     JS::Value result = JSVAL_NULL;
     aRv = nsContentUtils::WrapNative(aCx, scope, mResponseXML, &result,
                                      nullptr, true);
     return result;
   }
   case XML_HTTP_RESPONSE_TYPE_JSON:
   {
     if (!(mState & XML_HTTP_REQUEST_DONE)) {
@@ -3625,24 +3625,24 @@ nsXMLHttpRequest::GetInterface(const nsI
   return QueryInterface(aIID, aResult);
 }
 
 JS::Value
 nsXMLHttpRequest::GetInterface(JSContext* aCx, nsIJSID* aIID, ErrorResult& aRv)
 {
   const nsID* iid = aIID->GetID();
   nsCOMPtr<nsISupports> result;
-  JS::Value v = JSVAL_NULL;
+  JS::Rooted<JS::Value> v(aCx, JSVAL_NULL);
   aRv = GetInterface(*iid, getter_AddRefs(result));
   NS_ENSURE_FALSE(aRv.Failed(), JSVAL_NULL);
 
-  JSObject* wrapper = GetWrapper();
+  JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
   JSAutoCompartment ac(aCx, wrapper);
-  JSObject* global = JS_GetGlobalForObject(aCx, wrapper);
-  aRv = nsContentUtils::WrapNative(aCx, global, result, iid, &v);
+  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, wrapper));
+  aRv = nsContentUtils::WrapNative(aCx, global, result, iid, v.address());
   return aRv.Failed() ? JSVAL_NULL : v;
 }
 
 nsXMLHttpRequestUpload*
 nsXMLHttpRequest::Upload()
 {
   if (!mUpload) {
     mUpload = new nsXMLHttpRequestUpload(this);
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -2806,19 +2806,17 @@ CanvasRenderingContext2D::SetMozDash(JSC
       state.dashOffset = 0;
     }
   }
 }
 
 JS::Value
 CanvasRenderingContext2D::GetMozDash(JSContext* cx, ErrorResult& error)
 {
-  JS::Value mozDash;
-  error = DashArrayToJSVal(CurrentState().dash, cx, &mozDash);
-  return mozDash;
+  return DashArrayToJSVal(CurrentState().dash, cx, error);
 }
 
 void
 CanvasRenderingContext2D::SetMozDashOffset(double mozDashOffset)
 {
   ContextState& state = CurrentState();
   if (!state.dash.IsEmpty()) {
     state.dashOffset = mozDashOffset;
@@ -3419,17 +3417,17 @@ CanvasRenderingContext2D::GetImageDataAr
     if (snapshot) {
       readback = snapshot->GetDataSurface();
     }
     if (!readback || !readback->GetData()) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
-  JSObject* darray = JS_NewUint8ClampedArray(aCx, len.value());
+  JS::Rooted<JSObject*> darray(aCx, JS_NewUint8ClampedArray(aCx, len.value()));
   if (!darray) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (mZero) {
     *aRetval = darray;
     return NS_OK;
   }
--- a/content/canvas/src/CanvasUtils.h
+++ b/content/canvas/src/CanvasUtils.h
@@ -86,31 +86,31 @@ inline bool FloatValidate (double f1, do
 #undef VALIDATE
 
 template<typename T>
 nsresult
 JSValToDashArray(JSContext* cx, const JS::Value& val,
                  FallibleTArray<T>& dashArray);
 
 template<typename T>
-nsresult
+JS::Value
 DashArrayToJSVal(FallibleTArray<T>& dashArray,
-                 JSContext* cx, JS::Value* val);
+                 JSContext* cx, mozilla::ErrorResult& rv);
 
 template<typename T>
 nsresult
 JSValToDashArray(JSContext* cx, const JS::Value& patternArray,
                  FallibleTArray<T>& dashes)
 {
     // The cap is pretty arbitrary.  16k should be enough for
     // anybody...
     static const uint32_t MAX_NUM_DASHES = 1 << 14;
 
     if (!JSVAL_IS_PRIMITIVE(patternArray)) {
-        JSObject* obj = JSVAL_TO_OBJECT(patternArray);
+        JS::Rooted<JSObject*> obj(cx, JSVAL_TO_OBJECT(patternArray));
         uint32_t length;
         if (!JS_GetArrayLength(cx, obj, &length)) {
             // Not an array-like thing
             return NS_ERROR_INVALID_ARG;
         } else if (length > MAX_NUM_DASHES) {
             // Too many dashes in the pattern
             return NS_ERROR_ILLEGAL_VALUE;
         }
@@ -144,35 +144,36 @@ JSValToDashArray(JSContext* cx, const JS
         // random garbage is a type error.
         return NS_ERROR_INVALID_ARG;
     }
 
     return NS_OK;
 }
 
 template<typename T>
-nsresult
+JS::Value
 DashArrayToJSVal(FallibleTArray<T>& dashes,
-                 JSContext* cx, JS::Value* val)
+                 JSContext* cx, mozilla::ErrorResult& rv)
 {
     if (dashes.IsEmpty()) {
-        *val = JSVAL_NULL;
-    } else {
-        JSObject* obj = JS_NewArrayObject(cx, dashes.Length(), nullptr);
-        if (!obj) {
-            return NS_ERROR_OUT_OF_MEMORY;
+        return JSVAL_NULL;
+    }
+    JS::Rooted<JSObject*> obj(cx,
+        JS_NewArrayObject(cx, dashes.Length(), nullptr));
+    if (!obj) {
+        rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+        return JSVAL_NULL;
+    }
+    for (uint32_t i = 0; i < dashes.Length(); ++i) {
+        double d = dashes[i];
+        JS::Value elt = DOUBLE_TO_JSVAL(d);
+        if (!JS_DefineElement(cx, obj, i, elt, nullptr, nullptr, 0)) {
+            rv.Throw(NS_ERROR_FAILURE);
+            return JSVAL_NULL;
         }
-        for (uint32_t i = 0; i < dashes.Length(); ++i) {
-            double d = dashes[i];
-            JS::Value elt = DOUBLE_TO_JSVAL(d);
-            if (!JS_SetElement(cx, obj, i, &elt)) {
-                return NS_ERROR_FAILURE;
-            }
-        }
-        *val = OBJECT_TO_JSVAL(obj);
     }
-    return NS_OK;
+    return OBJECT_TO_JSVAL(obj);
 }
 
 }
 }
 
 #endif /* _CANVASUTILS_H_ */
--- a/content/events/src/nsDOMMessageEvent.cpp
+++ b/content/events/src/nsDOMMessageEvent.cpp
@@ -3,16 +3,19 @@
  * 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 "nsDOMMessageEvent.h"
 #include "nsContentUtils.h"
 #include "jsapi.h"
 #include "nsDOMClassInfoID.h"
 
+using namespace mozilla;
+using namespace mozilla::dom;
+
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
   tmp->mData = JSVAL_VOID;
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSource)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDOMMessageEvent, nsDOMEvent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -44,20 +47,29 @@ nsDOMMessageEvent::~nsDOMMessageEvent()
 {
   mData = JSVAL_VOID;
   NS_DROP_JS_OBJECTS(this, nsDOMMessageEvent);
 }
 
 NS_IMETHODIMP
 nsDOMMessageEvent::GetData(JSContext* aCx, JS::Value* aData)
 {
-  *aData = mData;
-  if (!JS_WrapValue(aCx, aData))
-    return NS_ERROR_FAILURE;
-  return NS_OK;
+  ErrorResult rv;
+  *aData = GetData(aCx, rv);
+  return rv.ErrorCode();
+}
+
+JS::Value
+nsDOMMessageEvent::GetData(JSContext* aCx, ErrorResult& aRv)
+{
+  JS::Rooted<JS::Value> data(aCx, mData);
+  if (!JS_WrapValue(aCx, data.address())) {
+    aRv.Throw(NS_ERROR_FAILURE);
+  }
+  return data;
 }
 
 NS_IMETHODIMP
 nsDOMMessageEvent::GetOrigin(nsAString& aOrigin)
 {
   aOrigin = mOrigin;
   return NS_OK;
 }
--- a/content/events/src/nsDOMMessageEvent.h
+++ b/content/events/src/nsDOMMessageEvent.h
@@ -21,38 +21,33 @@
  */
 class nsDOMMessageEvent : public nsDOMEvent,
                           public nsIDOMMessageEvent
 {
 public:
   nsDOMMessageEvent(mozilla::dom::EventTarget* aOwner,
                     nsPresContext* aPresContext, nsEvent* aEvent);
   ~nsDOMMessageEvent();
-                     
+
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsDOMMessageEvent,
                                                          nsDOMEvent)
 
   NS_DECL_NSIDOMMESSAGEEVENT
 
   // Forward to base class
   NS_FORWARD_TO_NSDOMEVENT
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
   {
     return mozilla::dom::MessageEventBinding::Wrap(aCx, aScope, this);
   }
 
-  JS::Value GetData(JSContext* aCx, mozilla::ErrorResult& aRv)
-  {
-    JS::Value data;
-    aRv = GetData(aCx, &data);
-    return data;
-  }
+  JS::Value GetData(JSContext* aCx, mozilla::ErrorResult& aRv);
 
   already_AddRefed<nsIDOMWindow> GetSource()
   {
     nsCOMPtr<nsIDOMWindow> ret = mSource;
     return ret.forget();
   }
 
   void InitMessageEvent(JSContext* aCx,
--- a/content/events/src/nsDOMNotifyAudioAvailableEvent.cpp
+++ b/content/events/src/nsDOMNotifyAudioAvailableEvent.cpp
@@ -5,17 +5,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsError.h"
 #include "nsDOMNotifyAudioAvailableEvent.h"
 #include "nsDOMClassInfoID.h" // DOMCI_DATA, NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO
 #include "nsContentUtils.h" // NS_DROP_JS_OBJECTS
 #include "jsfriendapi.h"
 
-nsDOMNotifyAudioAvailableEvent::nsDOMNotifyAudioAvailableEvent(mozilla::dom::EventTarget* aOwner,
+using namespace mozilla;
+using namespace mozilla::dom;
+
+nsDOMNotifyAudioAvailableEvent::nsDOMNotifyAudioAvailableEvent(EventTarget* aOwner,
                                                                nsPresContext* aPresContext,
                                                                nsEvent* aEvent,
                                                                uint32_t aEventType,
                                                                float* aFrameBuffer,
                                                                uint32_t aFrameBufferLength,
                                                                float aTime)
   : nsDOMEvent(aOwner, aPresContext, aEvent),
     mFrameBuffer(aFrameBuffer),
@@ -23,16 +26,17 @@ nsDOMNotifyAudioAvailableEvent::nsDOMNot
     mTime(aTime),
     mCachedArray(nullptr),
     mAllowAudioData(false)
 {
   MOZ_COUNT_CTOR(nsDOMNotifyAudioAvailableEvent);
   if (mEvent) {
     mEvent->message = aEventType;
   }
+  SetIsDOMBinding();
 }
 
 DOMCI_DATA(NotifyAudioAvailableEvent, nsDOMNotifyAudioAvailableEvent)
 
 NS_IMPL_ADDREF_INHERITED(nsDOMNotifyAudioAvailableEvent, nsDOMEvent)
 NS_IMPL_RELEASE_INHERITED(nsDOMNotifyAudioAvailableEvent, nsDOMEvent)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDOMNotifyAudioAvailableEvent, nsDOMEvent)
@@ -88,17 +92,17 @@ nsDOMNotifyAudioAvailableEvent::GetFrame
 
   *aResult = OBJECT_TO_JSVAL(mCachedArray);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMNotifyAudioAvailableEvent::GetTime(float *aRetVal)
 {
-  *aRetVal = mTime;
+  *aRetVal = Time();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMNotifyAudioAvailableEvent::InitAudioAvailableEvent(const nsAString& aType,
                                                         bool aCanBubble,
                                                         bool aCancelable,
                                                         float* aFrameBuffer,
@@ -112,21 +116,52 @@ nsDOMNotifyAudioAvailableEvent::InitAudi
   nsAutoArrayPtr<float> frameBuffer(aFrameBuffer);
   nsresult rv = nsDOMEvent::InitEvent(aType, aCanBubble, aCancelable);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mFrameBuffer = frameBuffer.forget();
   mFrameBufferLength = aFrameBufferLength;
   mTime = aTime;
   mAllowAudioData = aAllowAudioData;
+  mCachedArray = nullptr;
   return NS_OK;
 }
 
+void
+nsDOMNotifyAudioAvailableEvent::InitAudioAvailableEvent(const nsAString& aType,
+                                                        bool aCanBubble,
+                                                        bool aCancelable,
+                                                        const Nullable<Sequence<float> >& aFrameBuffer,
+                                                        uint32_t aFrameBufferLength,
+                                                        float aTime,
+                                                        bool aAllowAudioData,
+                                                        ErrorResult& aRv)
+{
+  if ((aFrameBuffer.IsNull() && aFrameBufferLength > 0) ||
+      (!aFrameBuffer.IsNull() &&
+       aFrameBuffer.Value().Length() < aFrameBufferLength)) {
+    aRv = NS_ERROR_UNEXPECTED;
+    return;
+  }
+
+  nsAutoArrayPtr<float> buffer;
+  if (!aFrameBuffer.IsNull()) {
+    buffer = new float[aFrameBufferLength];
+    memcpy(buffer.get(), aFrameBuffer.Value().Elements(),
+           aFrameBufferLength * sizeof(float));
+  }
+
+  aRv = InitAudioAvailableEvent(aType, aCanBubble, aCancelable,
+                                buffer.forget(),
+                                aFrameBufferLength,
+                                aTime, aAllowAudioData);
+}
+
 nsresult NS_NewDOMAudioAvailableEvent(nsIDOMEvent** aInstancePtrResult,
-                                      mozilla::dom::EventTarget* aOwner,
+                                      EventTarget* aOwner,
                                       nsPresContext* aPresContext,
                                       nsEvent *aEvent,
                                       uint32_t aEventType,
                                       float* aFrameBuffer,
                                       uint32_t aFrameBufferLength,
                                       float aTime)
 {
   nsDOMNotifyAudioAvailableEvent* it =
--- a/content/events/src/nsDOMNotifyAudioAvailableEvent.h
+++ b/content/events/src/nsDOMNotifyAudioAvailableEvent.h
@@ -6,16 +6,17 @@
 
 #ifndef nsDOMNotifyAudioAvailableEvent_h_
 #define nsDOMNotifyAudioAvailableEvent_h_
 
 #include "nsIDOMNotifyAudioAvailableEvent.h"
 #include "nsDOMEvent.h"
 #include "nsPresContext.h"
 #include "nsCycleCollectionParticipant.h"
+#include "mozilla/dom/NotifyAudioAvailableEventBinding.h"
 
 class nsDOMNotifyAudioAvailableEvent : public nsDOMEvent,
                                        public nsIDOMNotifyAudioAvailableEvent
 {
 public:
   nsDOMNotifyAudioAvailableEvent(mozilla::dom::EventTarget* aOwner,
                                  nsPresContext* aPresContext, nsEvent* aEvent,
                                  uint32_t aEventType, float * aFrameBuffer,
@@ -34,16 +35,42 @@ public:
                                         nsEvent *aEvent,
                                         uint32_t aEventType,
                                         float * aFrameBuffer,
                                         uint32_t aFrameBufferLength,
                                         float aTime);
 
   ~nsDOMNotifyAudioAvailableEvent();
 
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aScope) MOZ_OVERRIDE
+  {
+    return mozilla::dom::NotifyAudioAvailableEventBinding::Wrap(aCx, aScope, this);
+  }
+
+  JSObject* GetFrameBuffer(JSContext* aCx, mozilla::ErrorResult& aRv)
+  {
+    JS::Value dummy;
+    aRv = GetFrameBuffer(aCx, &dummy);
+    return mCachedArray;
+  }
+
+  float Time()
+  {
+    return mTime;
+  }
+
+  void InitAudioAvailableEvent(const nsAString& aType,
+                               bool aCanBubble,
+                               bool aCancelable,
+                               const mozilla::dom::Nullable<mozilla::dom::Sequence<float> >& aFrameBuffer,
+                               uint32_t aFrameBufferLength,
+                               float aTime,
+                               bool aAllowAudioData,
+                               mozilla::ErrorResult& aRv);
 private:
   nsAutoArrayPtr<float> mFrameBuffer;
   uint32_t mFrameBufferLength;
   float mTime;
   JSObject* mCachedArray;
   bool mAllowAudioData;
 };
 
--- a/content/events/src/nsEventListenerService.cpp
+++ b/content/events/src/nsEventListenerService.cpp
@@ -79,18 +79,18 @@ NS_IMPL_ISUPPORTS1(nsEventListenerServic
 bool
 nsEventListenerInfo::GetJSVal(JSContext* aCx,
                               mozilla::Maybe<JSAutoCompartment>& aAc,
                               JS::Value* aJSVal)
 {
   *aJSVal = JSVAL_NULL;
   nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(mListener);
   if (wrappedJS) {
-    JSObject* object = nullptr;
-    if (NS_FAILED(wrappedJS->GetJSObject(&object))) {
+    JS::Rooted<JSObject*> object(aCx, nullptr);
+    if (NS_FAILED(wrappedJS->GetJSObject(object.address()))) {
       return false;
     }
     aAc.construct(aCx, object);
     *aJSVal = OBJECT_TO_JSVAL(object);
     return true;
   }
 
   nsCOMPtr<nsIJSEventListener> jsl = do_QueryInterface(mListener);
@@ -110,18 +110,18 @@ nsEventListenerInfo::ToSource(nsAString&
 {
   aResult.SetIsVoid(true);
 
   SafeAutoJSContext cx;
   {
     // Extra block to finish the auto request before calling pop
     JSAutoRequest ar(cx);
     mozilla::Maybe<JSAutoCompartment> ac;
-    JS::Value v = JSVAL_NULL;
-    if (GetJSVal(cx, ac, &v)) {
+    JS::Rooted<JS::Value> v(cx, JSVAL_NULL);
+    if (GetJSVal(cx, ac, v.address())) {
       JSString* str = JS_ValueToSource(cx, v);
       if (str) {
         nsDependentJSString depStr;
         if (depStr.init(cx, str)) {
           aResult.Assign(depStr);
         }
       }
     }
@@ -134,28 +134,28 @@ nsEventListenerInfo::GetDebugObject(nsIS
 {
   *aRetVal = nullptr;
 
 #ifdef MOZ_JSDEBUGGER
   nsresult rv = NS_OK;
   nsCOMPtr<jsdIDebuggerService> jsd =
     do_GetService("@mozilla.org/js/jsd/debugger-service;1", &rv);
   NS_ENSURE_SUCCESS(rv, NS_OK);
-  
+
   bool isOn = false;
   jsd->GetIsOn(&isOn);
   NS_ENSURE_TRUE(isOn, NS_OK);
 
   SafeAutoJSContext cx;
   {
     // Extra block to finish the auto request before calling pop
     JSAutoRequest ar(cx);
     mozilla::Maybe<JSAutoCompartment> ac;
-    JS::Value v = JSVAL_NULL;
-    if (GetJSVal(cx, ac, &v)) {
+    JS::Rooted<JS::Value> v(cx, JSVAL_NULL);
+    if (GetJSVal(cx, ac, v.address())) {
       nsCOMPtr<jsdIValue> jsdValue;
       rv = jsd->WrapValue(v, getter_AddRefs(jsdValue));
       NS_ENSURE_SUCCESS(rv, rv);
       jsdValue.forget(aRetVal);
     }
   }
 #endif
 
--- a/content/events/test/Makefile.in
+++ b/content/events/test/Makefile.in
@@ -97,16 +97,17 @@ MOCHITEST_FILES = \
 		window_wheel_default_action.html \
 		test_bug603008.html \
 		test_bug716822.html \
 		test_bug742376.html \
 		test_dragstart.html \
 		test_bug812744.html \
 		test_addEventListenerExtraArg.html \
 		test_focus_disabled.html \
+		test_bug847597.html \
 		$(NULL)
 
 MOCHITEST_CHROME_FILES = \
 		test_bug336682_2.xul \
 		test_bug336682.js \
 		test_bug586961.xul \
 		test_bug415498.xul \
 		bug415498-doc1.html \
new file mode 100644
--- /dev/null
+++ b/content/events/test/test_bug847597.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=847597
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 847597</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 847597 **/
+
+
+  var e = document.createEvent("mozaudioavailableevent");
+  e.initAudioAvailableEvent("foo", true, true, [1], 1, 123456, false);
+  is(e.type, "foo");
+  is(e.bubbles, true);
+  is(e.cancelable, true);
+  is(e.time, 123456);
+
+  try {
+    e.frameBuffer;
+    ok(false, "Should not be possible to access frameBuffer in unsafe context when the last parameter to init is false.");
+  } catch(ex) {
+    ok(true);
+  }
+
+  try {
+    e.initAudioAvailableEvent("foo", true, true, [1, 2, 3], 4, 123456, false);
+    ok(false, "Should have thrown an exception because too short array");
+  } catch(ex) {
+    ok(true);
+  }
+
+  try {
+    e.initAudioAvailableEvent("foo", true, true, [], 1, 123456, false);
+    ok(false, "Should have thrown an exception because too short array");
+  } catch(ex) {
+    ok(true);
+  }
+
+  try {
+    e.initAudioAvailableEvent("foo", true, true, null, 1, 123456, false);
+    ok(false, "Should have thrown an exception because too short array");
+  } catch(ex) {
+    ok(true);
+  }
+
+  e.initAudioAvailableEvent("foo", true, true, null, 0, 123456, false);
+  e.initAudioAvailableEvent("foo", true, true, [], 0, 123456, false);
+  e.initAudioAvailableEvent("foo", true, true, [1], 0, 123456, false);
+
+  e.initAudioAvailableEvent("foo", true, true, [0, 1, 2], 0, 123456, true);
+  is(e.frameBuffer.length, 0);
+  e.initAudioAvailableEvent("foo", true, true, [0, 1, 2], 1, 123456, true);
+  is(e.frameBuffer.length, 1);
+  is(e.frameBuffer[0], 0);
+  e.initAudioAvailableEvent("foo", true, true, [0, 1, 2], 2, 123456, true);
+  is(e.frameBuffer.length, 2);
+  is(e.frameBuffer[0], 0);
+  is(e.frameBuffer[1], 1);
+  e.initAudioAvailableEvent("foo", true, true, [0, 1, 2], 3, 123456, true);
+  is(e.frameBuffer.length, 3);
+  is(e.frameBuffer[0], 0);
+  is(e.frameBuffer[1], 1);
+  is(e.frameBuffer[2], 2);
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=847597">Mozilla Bug 847597</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -757,23 +757,23 @@ HTMLCanvasElement::GetContext(const nsAS
     // than objects, e.g. plain strings, then we'll need to expand
     // this to know how to create nsISupportsStrings etc.
 
     nsCOMPtr<nsIWritablePropertyBag2> contextProps;
     if (aContextOptions.isObject()) {
       MOZ_ASSERT(aCx);
       contextProps = do_CreateInstance("@mozilla.org/hash-property-bag;1");
 
-      JSObject& opts = aContextOptions.toObject();
-      JS::AutoIdArray props(aCx, JS_Enumerate(aCx, &opts));
+      JS::Rooted<JSObject*> opts(aCx, &aContextOptions.toObject());
+      JS::AutoIdArray props(aCx, JS_Enumerate(aCx, opts));
       for (size_t i = 0; !!props && i < props.length(); ++i) {
         jsid propid = props[i];
-        JS::Value propname, propval;
-        if (!JS_IdToValue(aCx, propid, &propname) ||
-            !JS_GetPropertyById(aCx, &opts, propid, &propval)) {
+        JS::Rooted<JS::Value> propname(aCx), propval(aCx);
+        if (!JS_IdToValue(aCx, propid, propname.address()) ||
+            !JS_GetPropertyById(aCx, opts, propid, propval.address())) {
           return NS_ERROR_FAILURE;
         }
 
         JSString *propnameString = JS_ValueToString(aCx, propname);
         nsDependentJSString pstr;
         if (!propnameString || !pstr.init(aCx, propnameString)) {
           mCurrentContext = nullptr;
           return NS_ERROR_FAILURE;
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -92,17 +92,16 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/MathAlgorithms.h"
 
 #include "nsIIDNService.h"
 
 #include <limits>
 
 // input type=date
-#include "jsapi.h"
 #include "js/Date.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Input)
 
 // XXX align=left, hspace, vspace, border? other nav4 attrs
 
 static NS_DEFINE_CID(kXULControllersCID,  NS_XULCONTROLLERS_CID);
 
@@ -1395,122 +1394,68 @@ HTMLInputElement::ConvertNumberToString(
         return true;
       }
     default:
       MOZ_ASSERT(false, "Unrecognized input type");
       return false;
   }
 }
 
-JS::Value
-HTMLInputElement::GetValueAsDate(JSContext* aCx, ErrorResult& aRv)
+
+Nullable<Date>
+HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
 {
   if (mType != NS_FORM_INPUT_DATE && mType != NS_FORM_INPUT_TIME) {
-    return JS::NullValue();
+    return Nullable<Date>();
   }
 
   switch (mType) {
     case NS_FORM_INPUT_DATE:
     {
       uint32_t year, month, day;
       nsAutoString value;
       GetValueInternal(value);
       if (!GetValueAsDate(value, &year, &month, &day)) {
-        return JS::NullValue();
-      }
-
-      JSObject* date = JS_NewDateObjectMsec(aCx, 0);
-      if (!date) {
-        JS_ClearPendingException(aCx);
-        return JS::NullValue();
+        return Nullable<Date>();
       }
 
-      JS::Value rval;
-      JS::Value fullYear[3];
-      fullYear[0].setInt32(year);
-      fullYear[1].setInt32(month - 1);
-      fullYear[2].setInt32(day);
-      if (!JS::Call(aCx, date, "setUTCFullYear", 3, fullYear, &rval)) {
-        JS_ClearPendingException(aCx);
-        return JS::NullValue();
-      }
-
-      return JS::ObjectOrNullValue(date);
+      return Nullable<Date>(Date(JS::MakeDate(year, month - 1, day)));
     }
     case NS_FORM_INPUT_TIME:
     {
       uint32_t millisecond;
       nsAutoString value;
       GetValueInternal(value);
       if (!ParseTime(value, &millisecond)) {
-        return JS::NullValue();
+        return Nullable<Date>();
       }
 
-      JSObject* date = JS_NewDateObjectMsec(aCx, millisecond);
-      if (!date) {
-        JS_ClearPendingException(aCx);
-        return JS::NullValue();
-      }
-
-      return JS::ObjectValue(*date);
+      return Nullable<Date>(Date(millisecond));
     }
   }
 
   MOZ_ASSERT(false, "Unrecognized input type");
   aRv.Throw(NS_ERROR_UNEXPECTED);
-  return JS::NullValue();
-}
-
-NS_IMETHODIMP
-HTMLInputElement::GetValueAsDate(JSContext* aCx, JS::Value* aDate)
-{
-  ErrorResult rv;
-  *aDate = GetValueAsDate(aCx, rv);
-  return rv.ErrorCode();
+  return Nullable<Date>();
 }
 
 void
-HTMLInputElement::SetValueAsDate(JSContext* aCx, JS::Value aDate, ErrorResult& aRv)
+HTMLInputElement::SetValueAsDate(Nullable<Date> aDate, ErrorResult& aRv)
 {
   if (mType != NS_FORM_INPUT_DATE && mType != NS_FORM_INPUT_TIME) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
-  if (aDate.isNullOrUndefined()) {
+  if (aDate.IsNull() || aDate.Value().IsUndefined()) {
     aRv = SetValue(EmptyString());
     return;
   }
 
-  // TODO: return TypeError when HTMLInputElement is converted to WebIDL, see
-  // bug 826302.
-  if (!aDate.isObject() || !JS_ObjectIsDate(aCx, &aDate.toObject())) {
-    SetValue(EmptyString());
-    aRv.Throw(NS_ERROR_INVALID_ARG);
-    return;
-  }
-
-  JSObject& date = aDate.toObject();
-  JS::Value timestamp;
-  if (!JS::Call(aCx, &date, "getTime", 0, nullptr, &timestamp) ||
-      !timestamp.isNumber() || MOZ_DOUBLE_IS_NaN(timestamp.toNumber())) {
-    JS_ClearPendingException(aCx);
-    SetValue(EmptyString());
-    return;
-  }
-
-  SetValue(timestamp.toNumber());
-}
-
-NS_IMETHODIMP
-HTMLInputElement::SetValueAsDate(JSContext* aCx, const JS::Value& aDate)
-{
-  ErrorResult rv;
-  SetValueAsDate(aCx, aDate, rv);
-  return rv.ErrorCode();
+  SetValue(aDate.Value().TimeStamp());
 }
 
 NS_IMETHODIMP
 HTMLInputElement::GetValueAsNumber(double* aValueAsNumber)
 {
   *aValueAsNumber = ValueAsNumber();
   return NS_OK;
 }
--- a/content/html/content/src/HTMLInputElement.h
+++ b/content/html/content/src/HTMLInputElement.h
@@ -568,19 +568,19 @@ public:
   void SetDefaultValue(const nsAString& aValue, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::value, aValue, aRv);
   }
 
   // XPCOM GetValue() is OK
   void SetValue(const nsAString& aValue, ErrorResult& aRv);
 
-  JS::Value GetValueAsDate(JSContext* aCx, ErrorResult& aRv);
+  Nullable<Date> GetValueAsDate(ErrorResult& aRv);
 
-  void SetValueAsDate(JSContext* aCx, JS::Value aValue, ErrorResult& aRv);
+  void SetValueAsDate(Nullable<Date>, ErrorResult& aRv);
 
   double ValueAsNumber() const
   {
     return DoesValueAsNumberApply() ? GetValueAsDouble()
                                     : MOZ_DOUBLE_NaN();
   }
 
   void SetValueAsNumber(double aValue, ErrorResult& aRv);
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -1594,17 +1594,17 @@ HTMLMediaElement::BuildObjectFromTags(ns
 JSObject*
 HTMLMediaElement::MozGetMetadata(JSContext* cx, ErrorResult& aRv)
 {
   if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
-  JSObject* tags = JS_NewObject(cx, nullptr, nullptr, nullptr);
+  JS::Rooted<JSObject*> tags(cx, JS_NewObject(cx, nullptr, nullptr, nullptr));
   if (!tags) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   if (mTags) {
     MetadataIterCx iter = {cx, tags, false};
     mTags->EnumerateRead(BuildObjectFromTags, static_cast<void*>(&iter));
     if (iter.error) {
--- a/content/html/content/src/HTMLObjectElement.cpp
+++ b/content/html/content/src/HTMLObjectElement.cpp
@@ -450,17 +450,18 @@ HTMLObjectElement::CopyInnerTo(Element* 
   }
 
   return rv;
 }
 
 JSObject*
 HTMLObjectElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
-  JSObject* obj = HTMLObjectElementBinding::Wrap(aCx, aScope, this);
+  JS::Rooted<JSObject*> obj(aCx,
+    HTMLObjectElementBinding::Wrap(aCx, aScope, this));
   if (!obj) {
     return nullptr;
   }
   SetupProtoChain(aCx, obj);
   return obj;
 }
 
 } // namespace dom
--- a/content/html/content/src/HTMLOptionsCollection.cpp
+++ b/content/html/content/src/HTMLOptionsCollection.cpp
@@ -286,18 +286,19 @@ HTMLOptionsCollection::NamedItem(JSConte
                                  ErrorResult& error)
 {
   nsINode* item = GetNamedItemHelper(mElements, name);
   if (!item) {
     return nullptr;
   }
   JS::Rooted<JSObject*> wrapper(cx, nsWrapperCache::GetWrapper());
   JSAutoCompartment ac(cx, wrapper);
-  JS::Value v;
-  if (!mozilla::dom::WrapObject(cx, wrapper, item, item, nullptr, &v)) {
+  JS::Rooted<JS::Value> v(cx);
+  if (!mozilla::dom::WrapObject(cx, wrapper, item, item, nullptr,
+                                v.address())) {
     error.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   return &v.toObject();
 }
 
 void
 HTMLOptionsCollection::GetSupportedNames(nsTArray<nsString>& aNames)
--- a/content/html/content/src/HTMLSharedObjectElement.cpp
+++ b/content/html/content/src/HTMLSharedObjectElement.cpp
@@ -357,14 +357,15 @@ HTMLSharedObjectElement::WrapNode(JSCont
     obj = HTMLAppletElementBinding::Wrap(aCx, aScope, this);
   } else {
     MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::embed));
     obj = HTMLEmbedElementBinding::Wrap(aCx, aScope, this);
   }
   if (!obj) {
     return nullptr;
   }
-  SetupProtoChain(aCx, obj);
-  return obj;
+  JS::Rooted<JSObject*> rootedObj(aCx, obj);
+  SetupProtoChain(aCx, rootedObj);
+  return rootedObj;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/html/content/src/HTMLTableElement.cpp
+++ b/content/html/content/src/HTMLTableElement.cpp
@@ -229,18 +229,18 @@ TableRowsCollection::NamedItem(JSContext
       nsCOMPtr<nsIDOMNode> item;
       error = collection->NamedItem(name, getter_AddRefs(item));
       if (error.Failed()) {
         return nullptr;
       }
       if (item) {
         JS::Rooted<JSObject*> wrapper(cx, nsWrapperCache::GetWrapper());
         JSAutoCompartment ac(cx, wrapper);
-        JS::Value v;
-        if (!mozilla::dom::WrapObject(cx, wrapper, item, &v)) {
+        JS::Rooted<JS::Value> v(cx);
+        if (!mozilla::dom::WrapObject(cx, wrapper, item, v.address())) {
           error.Throw(NS_ERROR_FAILURE);
           return nullptr;
         }
         return &v.toObject();
       }
     }
   );
   return nullptr;
--- a/content/html/content/src/HTMLUnknownElement.cpp
+++ b/content/html/content/src/HTMLUnknownElement.cpp
@@ -13,25 +13,26 @@ namespace mozilla {
 namespace dom {
 
 NS_IMPL_ADDREF_INHERITED(HTMLUnknownElement, Element)
 NS_IMPL_RELEASE_INHERITED(HTMLUnknownElement, Element)
 
 JSObject*
 HTMLUnknownElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
-  JSObject* obj =
-    HTMLUnknownElementBinding::Wrap(aCx, aScope, this);
+  JS::Rooted<JSObject*> obj(aCx,
+    HTMLUnknownElementBinding::Wrap(aCx, aScope, this));
   if (obj && Substring(NodeName(), 0, 2).LowerCaseEqualsLiteral("x-")) {
     // If we have a registered x-tag then we fix the prototype.
     JSAutoCompartment ac(aCx, obj);
     nsDocument* document = static_cast<nsDocument*>(OwnerDoc());
-    JSObject* prototype = document->GetCustomPrototype(LocalName());
+    JS::Rooted<JSObject*> prototype(aCx,
+      document->GetCustomPrototype(LocalName()));
     if (prototype) {
-      NS_ENSURE_TRUE(JS_WrapObject(aCx, &prototype), nullptr);
+      NS_ENSURE_TRUE(JS_WrapObject(aCx, prototype.address()), nullptr);
       NS_ENSURE_TRUE(JS_SetPrototype(aCx, obj, prototype), nullptr);
     }
   }
   return obj;
 }
 
 // QueryInterface implementation for HTMLUnknownElement
 NS_INTERFACE_TABLE_HEAD(HTMLUnknownElement)
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -2252,17 +2252,17 @@ NS_IMETHODIMP
 nsFormControlList::NamedItem(const nsAString& aName,
                              nsIDOMNode** aReturn)
 {
   FlushPendingNotifications();
 
   *aReturn = nullptr;
 
   nsCOMPtr<nsISupports> supports;
-  
+
   if (!mNameLookupTable.Get(aName, getter_AddRefs(supports))) {
     // key not found
     return NS_OK;
   }
 
   if (!supports) {
     return NS_OK;
   }
@@ -2548,18 +2548,18 @@ nsFormControlList::NamedItem(JSContext* 
                              mozilla::ErrorResult& error)
 {
   nsISupports *item = NamedItemInternal(name, true);
   if (!item) {
     return nullptr;
   }
   JS::Rooted<JSObject*> wrapper(cx, nsWrapperCache::GetWrapper());
   JSAutoCompartment ac(cx, wrapper);
-  JS::Value v;
-  if (!mozilla::dom::WrapObject(cx, wrapper, item, &v)) {
+  JS::Rooted<JS::Value> v(cx);
+  if (!mozilla::dom::WrapObject(cx, wrapper, item, v.address())) {
     error.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
   return &v.toObject();
 }
 
 static PLDHashOperator
 CollectNames(const nsAString& aName,
--- a/content/html/content/test/forms/test_valueasdate_attribute.html
+++ b/content/html/content/test/forms/test_valueasdate_attribute.html
@@ -345,31 +345,31 @@ function checkWithBustedPrototype()
     Date.prototype.getUTCFullYear = function() { return {}; };
     Date.prototype.getUTCMonth = function() { return {}; };
     Date.prototype.getUTCDate = function() { return {}; };
     Date.prototype.getTime = function() { return {}; };
     Date.prototype.setUTCFullYear = function(y,m,d) { };
 
     element.valueAsDate = new Date();
 
-    todo_isnot(element.valueAsDate, null, ".valueAsDate should not return null");
+    isnot(element.valueAsDate, null, ".valueAsDate should not return null");
     // TODO: check the Date object value (UTCFullYear, UTCMonth and UTCDate)
     // when .valueAsDate will stop returning null.
 
     // Same test as above but using NaN instead of {}.
 
     Date.prototype.getUTCFullYear = function() { return NaN; };
     Date.prototype.getUTCMonth = function() { return NaN; };
     Date.prototype.getUTCDate = function() { return NaN; };
     Date.prototype.getTime = function() { return NaN; };
     Date.prototype.setUTCFullYear = function(y,m,d) { };
 
     element.valueAsDate = new Date();
 
-    todo_isnot(element.valueAsDate, null, ".valueAsDate should not return null");
+    isnot(element.valueAsDate, null, ".valueAsDate should not return null");
     // TODO: check the Date object value (UTCFullYear, UTCMonth and UTCDate)
     // when .valueAsDate will stop returning null.
 
     Date.prototype.getUTCFullYear = backupPrototype.getUTCFullYear;
     Date.prototype.getUTCMonth = backupPrototype.getUTCMonth;
     Date.prototype.getUTCDate = backupPrototype.getUTCDate;
     Date.prototype.getTime = backupPrototype.getTime;
     Date.prototype.setUTCFullYear = backupPrototype.setUTCFullYear;
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -2362,23 +2362,23 @@ nsHTMLDocument::NamedGetter(JSContext* c
     aFound = false;
     if (GetCompatibilityMode() == eCompatibility_NavQuirks &&
         aName.EqualsLiteral("all")) {
       rv = nsHTMLDocumentSH::TryResolveAll(cx, this, GetWrapper());
     }
     return nullptr;
   }
 
-  JS::Value val;
+  JS::Rooted<JS::Value> val(cx);
   { // Scope for auto-compartment
     JS::Rooted<JSObject*> wrapper(cx, GetWrapper());
     JSAutoCompartment ac(cx, wrapper);
     // XXXbz Should we call the (slightly misnamed, really) WrapNativeParent
     // here?
-    if (!dom::WrapObject(cx, wrapper, supp, cache, nullptr, &val)) {
+    if (!dom::WrapObject(cx, wrapper, supp, cache, nullptr, val.address())) {
       rv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return nullptr;
     }
   }
   aFound = true;
   return &val.toObject();
 }
 
--- a/content/media/test/crashtests/crashtests.list
+++ b/content/media/test/crashtests/crashtests.list
@@ -1,9 +1,9 @@
-load 459439-1.html
+skip-if(Android) load 459439-1.html
 load 466607-1.html
 load 466945-1.html
 load 468763-1.html
 load 474744-1.html
 HTTP load 481136-1.html # needs to be HTTP to recognize the ogg as an audio file?
 load 493915-1.html
 skip-if(Android) load 495794-1.html
 load 492286-1.xhtml
--- a/content/media/test/test_constants.html
+++ b/content/media/test/test_constants.html
@@ -34,38 +34,38 @@ is(HTMLMediaElement.HAVE_NOTHING, 0);
 is(HTMLMediaElement.HAVE_METADATA, 1);
 is(HTMLMediaElement.HAVE_CURRENT_DATA, 2);
 is(HTMLMediaElement.HAVE_FUTURE_DATA, 3);
 is(HTMLMediaElement.HAVE_ENOUGH_DATA, 4);
 is(HTMLMediaElement.MEDIA_ERR_ABORTED, undefined);
 is(HTMLMediaElement.MEDIA_ERR_NETWORK, undefined);
 is(HTMLMediaElement.MEDIA_ERR_DECODE, undefined);
 is(HTMLMediaElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
-is(HTMLVideoElement.NETWORK_EMPTY, undefined);
-is(HTMLVideoElement.NETWORK_IDLE, undefined);
-is(HTMLVideoElement.NETWORK_LOADING, undefined);
-is(HTMLVideoElement.NETWORK_NO_SOURCE, undefined);
-is(HTMLVideoElement.HAVE_NOTHING, undefined);
-is(HTMLVideoElement.HAVE_METADATA, undefined);
-is(HTMLVideoElement.HAVE_CURRENT_DATA, undefined);
-is(HTMLVideoElement.HAVE_FUTURE_DATA, undefined);
-is(HTMLVideoElement.HAVE_ENOUGH_DATA, undefined);
+is(HTMLVideoElement.NETWORK_EMPTY, 0);
+is(HTMLVideoElement.NETWORK_IDLE, 1);
+is(HTMLVideoElement.NETWORK_LOADING, 2);
+is(HTMLVideoElement.NETWORK_NO_SOURCE, 3);
+is(HTMLVideoElement.HAVE_NOTHING, 0);
+is(HTMLVideoElement.HAVE_METADATA, 1);
+is(HTMLVideoElement.HAVE_CURRENT_DATA, 2);
+is(HTMLVideoElement.HAVE_FUTURE_DATA, 3);
+is(HTMLVideoElement.HAVE_ENOUGH_DATA, 4);
 is(HTMLVideoElement.MEDIA_ERR_ABORTED, undefined);
 is(HTMLVideoElement.MEDIA_ERR_NETWORK, undefined);
 is(HTMLVideoElement.MEDIA_ERR_DECODE, undefined);
 is(HTMLVideoElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
-is(HTMLAudioElement.NETWORK_EMPTY, undefined);
-is(HTMLAudioElement.NETWORK_IDLE, undefined);
-is(HTMLAudioElement.NETWORK_LOADING, undefined);
-is(HTMLAudioElement.NETWORK_NO_SOURCE, undefined);
-is(HTMLAudioElement.HAVE_NOTHING, undefined);
-is(HTMLAudioElement.HAVE_METADATA, undefined);
-is(HTMLAudioElement.HAVE_CURRENT_DATA, undefined);
-is(HTMLAudioElement.HAVE_FUTURE_DATA, undefined);
-is(HTMLAudioElement.HAVE_ENOUGH_DATA, undefined);
+is(HTMLAudioElement.NETWORK_EMPTY, 0);
+is(HTMLAudioElement.NETWORK_IDLE, 1);
+is(HTMLAudioElement.NETWORK_LOADING, 2);
+is(HTMLAudioElement.NETWORK_NO_SOURCE, 3);
+is(HTMLAudioElement.HAVE_NOTHING, 0);
+is(HTMLAudioElement.HAVE_METADATA, 1);
+is(HTMLAudioElement.HAVE_CURRENT_DATA, 2);
+is(HTMLAudioElement.HAVE_FUTURE_DATA, 3);
+is(HTMLAudioElement.HAVE_ENOUGH_DATA, 4);
 is(HTMLAudioElement.MEDIA_ERR_ABORTED, undefined);
 is(HTMLAudioElement.MEDIA_ERR_NETWORK, undefined);
 is(HTMLAudioElement.MEDIA_ERR_DECODE, undefined);
 is(HTMLAudioElement.MEDIA_ERR_SRC_NOT_SUPPORTED, undefined);
 is(HTMLSourceElement.NETWORK_EMPTY, undefined);
 is(HTMLSourceElement.NETWORK_IDLE, undefined);
 is(HTMLSourceElement.NETWORK_LOADING, undefined);
 is(HTMLSourceElement.NETWORK_NO_SOURCE, undefined);
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -299,32 +299,34 @@ public:
 
   bool ShouldResample() const
   {
     return !(mPlaybackRate == 1.0 &&
              mDopplerShift == 1.0 &&
              mSampleRate == IdealAudioRate());
   }
 
-  void UpdateSampleRateIfNeeded(AudioNodeStream* aStream)
+  void UpdateSampleRateIfNeeded(AudioNodeStream* aStream, uint32_t aChannels)
   {
     if (mPlaybackRateTimeline.HasSimpleValue()) {
       mPlaybackRate = mPlaybackRateTimeline.GetValue();
     } else {
       mPlaybackRate = mPlaybackRateTimeline.GetValueAtTime<TrackTicks>(aStream->GetCurrentPosition());
     }
 
-    // Make sure the playback rate if something our resampler can work with.
-    if (mPlaybackRate <= 0.0 || mPlaybackRate >= 1024) {
+    // Make sure the playback rate and the doppler shift are something
+    // our resampler can work with.
+    if (ComputeFinalOutSampleRate() == 0) {
       mPlaybackRate = 1.0;
+      mDopplerShift = 1.0;
     }
 
     uint32_t currentOutSampleRate, currentInSampleRate;
     if (ShouldResample()) {
-      SpeexResamplerState* resampler = Resampler(mChannels);
+      SpeexResamplerState* resampler = Resampler(aChannels);
       speex_resampler_get_rate(resampler, &currentInSampleRate, &currentOutSampleRate);
       uint32_t finalSampleRate = ComputeFinalOutSampleRate();
       if (currentOutSampleRate != finalSampleRate) {
         speex_resampler_set_rate(resampler, currentInSampleRate, finalSampleRate);
       }
     }
   }
 
@@ -340,17 +342,17 @@ public:
     if (!channels) {
       aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
       return;
     }
 
     // WebKit treats the playbackRate as a k-rate parameter in their code,
     // despite the spec saying that it should be an a-rate parameter. We treat
     // it as k-rate. Spec bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=21592
-    UpdateSampleRateIfNeeded(aStream);
+    UpdateSampleRateIfNeeded(aStream, channels);
 
     uint32_t written = 0;
     TrackTicks currentPosition = GetPosition(aStream);
     while (written < WEBAUDIO_BLOCK_SIZE) {
       if (mStop != TRACK_TICKS_MAX &&
           currentPosition >= mStop) {
         FillWithZeroes(aOutput, channels, &written, &currentPosition, TRACK_TICKS_MAX);
         continue;
--- a/content/media/webaudio/blink/DenormalDisabler.h
+++ b/content/media/webaudio/blink/DenormalDisabler.h
@@ -28,18 +28,18 @@
 #define _USE_MATH_DEFINES
 #include <cmath>
 
 namespace WebCore {
 
 // Deal with denormals. They can very seriously impact performance on x86.
 
 // Define HAVE_DENORMAL if we support flushing denormals to zero.
+#include <float.h>
 #if defined(XP_WIN) && defined(_MSC_VER)
-#include <float.h>
 #define HAVE_DENORMAL
 #endif
 
 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 #define HAVE_DENORMAL
 #endif
 
 #ifdef HAVE_DENORMAL
--- a/content/media/webaudio/test/Makefile.in
+++ b/content/media/webaudio/test/Makefile.in
@@ -20,42 +20,51 @@ MOCHITEST_FILES := \
   test_bug866570.html \
   test_bug866737.html \
   test_bug867089.html \
   test_analyserNode.html \
   test_AudioBuffer.html \
   test_AudioContext.html \
   test_AudioListener.html \
   test_AudioParam.html \
+  test_audioParamExponentialRamp.html \
+  test_audioParamLinearRamp.html \
   test_audioBufferSourceNode.html \
   test_audioBufferSourceNodeLazyLoopParam.html \
   test_audioBufferSourceNodeLoop.html \
   test_audioBufferSourceNodeLoopStartEnd.html \
   test_audioBufferSourceNodeLoopStartEndSame.html \
   test_audioBufferSourceNodeNullBuffer.html \
   test_badConnect.html \
   test_biquadFilterNode.html \
-  test_currentTime.html \
-  test_delayNode.html \
-  test_delayNodeWithGain.html \
   test_decodeAudioData.html \
   test_dynamicsCompressorNode.html \
-  test_gainNode.html \
-  test_mixingRules.html \
   test_pannerNode.html \
-  test_scriptProcessorNode.html \
   test_scriptProcessorNodeChannelCount.html \
   test_singleSourceDest.html \
   ting.ogg \
   ting-expected.wav \
   ting-dualchannel44.1.ogg \
   ting-dualchannel44.1-expected.wav \
   ting-dualchannel48.ogg \
   ting-dualchannel48-expected.wav \
   small-shot.ogg \
   small-shot-expected.wav \
   invalid.txt \
   noaudio.webm \
   audio.ogv \
   audio-expected.wav \
   $(NULL)
 
+# Disable these tests on Android due to frequent timeouts
+ifneq ($(OS_TARGET),Android)
+MOCHITEST_FILES += \
+  test_bug867174.html \
+  test_currentTime.html \
+  test_delayNode.html \
+  test_delayNodeWithGain.html \
+  test_gainNode.html \
+  test_mixingRules.html \
+  test_scriptProcessorNode.html \
+  $(NULL)
+endif
+
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_audioParamExponentialRamp.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test AudioParam.exponentialRampToValue</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context = new AudioContext();
+
+  var V0 = 0.1;
+  var V1 = 0.9;
+  var T0 = 0;
+  var T1 = 2048 / context.sampleRate;
+
+  var sourceBuffer = context.createBuffer(1, 2048, context.sampleRate);
+  for (var i = 0; i < 2048; ++i) {
+    sourceBuffer.getChannelData(0)[i] = 1;
+  }
+  var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
+  for (var i = 0; i < 2048; ++i) {
+    var t = i / context.sampleRate;
+    expectedBuffer.getChannelData(0)[i] = V0 * Math.pow(V1 / V0, (t - T0) / (T1 - T0));
+  }
+
+  var destination = context.destination;
+
+  var source = context.createBufferSource();
+  source.buffer = sourceBuffer;
+
+  var gain = context.createGain();
+  gain.gain.setValueAtTime(V0, 0);
+  gain.gain.exponentialRampToValueAtTime(V1, 2048/context.sampleRate);
+
+  var sp = context.createScriptProcessor(2048, 1);
+  source.connect(gain);
+  gain.connect(sp);
+  sp.connect(destination);
+
+  source.start(0);
+  sp.onaudioprocess = function(e) {
+    is(e.inputBuffer.numberOfChannels, 1, "Correct input channel count");
+    compareBuffers(e.inputBuffer.getChannelData(0), expectedBuffer.getChannelData(0));
+
+    sp.onaudioprocess = null;
+
+    SpecialPowers.clearUserPref("media.webaudio.enabled");
+    SimpleTest.finish();
+  };
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_audioParamLinearRamp.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test AudioParam.linearRampToValue</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+
+  var context = new AudioContext();
+
+  var V0 = 0.1;
+  var V1 = 0.9;
+  var T0 = 0;
+  var T1 = 2048 / context.sampleRate;
+
+  var sourceBuffer = context.createBuffer(1, 2048, context.sampleRate);
+  for (var i = 0; i < 2048; ++i) {
+    sourceBuffer.getChannelData(0)[i] = 1;
+  }
+  var expectedBuffer = context.createBuffer(1, 2048, context.sampleRate);
+  for (var i = 0; i < 2048; ++i) {
+    var t = i / context.sampleRate;
+    expectedBuffer.getChannelData(0)[i] = V0 + (V1 - V0) * ((t - T0) / (T1 - T0));
+  }
+
+  var destination = context.destination;
+
+  var source = context.createBufferSource();
+  source.buffer = sourceBuffer;
+
+  var gain = context.createGain();
+  gain.gain.setValueAtTime(V0, 0);
+  gain.gain.linearRampToValueAtTime(V1, 2048/context.sampleRate);
+
+  var sp = context.createScriptProcessor(2048, 1);
+  source.connect(gain);
+  gain.connect(sp);
+  sp.connect(destination);
+
+  source.start(0);
+  sp.onaudioprocess = function(e) {
+    is(e.inputBuffer.numberOfChannels, 1, "Correct input channel count");
+    compareBuffers(e.inputBuffer.getChannelData(0), expectedBuffer.getChannelData(0));
+
+    sp.onaudioprocess = null;
+
+    SpecialPowers.clearUserPref("media.webaudio.enabled");
+    SimpleTest.finish();
+  };
+});
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_bug867174.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Crashtest for bug 867174</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SpecialPowers.setBoolPref("media.webaudio.enabled", true);
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  var ctx = new AudioContext();
+
+  var source = ctx.createBufferSource();
+  var buffer = ctx.createBuffer(2, 2048, 8000);
+  source.playbackRate.setTargetValueAtTime(0, 2, 3);
+  var sp = ctx.createScriptProcessor();
+  source.connect(sp);
+  sp.connect(ctx.destination);
+  source.start(0);
+
+  sp.onaudioprocess = function(e) {
+    // Now set the buffer
+    source.buffer = buffer;
+
+    ok(true, "We did not crash.");
+    sp.onaudioprocess = null;
+    SpecialPowers.clearUserPref("media.webaudio.enabled");
+    SimpleTest.finish();
+  };
+});
+
+
+</script>
+</pre>
+</body>
+</html>
--- a/content/media/webaudio/test/webaudio.js
+++ b/content/media/webaudio/test/webaudio.js
@@ -19,17 +19,17 @@ function expectTypeError(func) {
   } catch (ex) {
     threw = true;
     ok(ex instanceof TypeError, "Expect a TypeError");
   }
   ok(threw, "The exception was thrown");
 }
 
 function fuzzyCompare(a, b) {
-  return Math.abs(a - b) < 5e-5;
+  return Math.abs(a - b) < 9e-3;
 }
 
 function compareBuffers(buf1, buf2,
                         /*optional*/ offset,
                         /*optional*/ length,
                         /*optional*/ sourceOffset,
                         /*optional*/ destOffset) {
   is(buf1.length, buf2.length, "Buffers must have the same length");
--- a/content/svg/document/src/SVGDocument.cpp
+++ b/content/svg/document/src/SVGDocument.cpp
@@ -99,17 +99,17 @@ SVGDocument::Clone(nsINodeInfo *aNodeInf
   NS_ENSURE_SUCCESS(rv, rv);
 
   return CallQueryInterface(clone.get(), aResult);
 }
 
 JSObject*
 SVGDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
-  JSObject* obj = SVGDocumentBinding::Wrap(aCx, aScope, this);
+  JS::Rooted<JSObject*> obj(aCx, SVGDocumentBinding::Wrap(aCx, aScope, this));
   if (obj && !PostCreateWrapper(aCx, obj)) {
     return nullptr;
   }
   return obj;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/xbl/src/nsXBLProtoImpl.cpp
+++ b/content/xbl/src/nsXBLProtoImpl.cpp
@@ -95,26 +95,27 @@ nsXBLProtoImpl::InstallImplementation(ns
   for (nsXBLProtoImplMember* curr = mMembers;
        curr;
        curr = curr->GetNext())
     curr->InstallMember(cx, targetClassObject);
 
   // If we're using a separate XBL scope, make a safe copy of the target class
   // object in the XBL scope that we can use for Xray lookups. We don't need
   // the field accessors, so do this before installing them.
-  JSObject* globalObject = JS_GetGlobalForObject(cx, targetClassObject);
-  JSObject* scopeObject = xpc::GetXBLScope(cx, globalObject);
+  JS::Rooted<JSObject*> globalObject(cx,
+    JS_GetGlobalForObject(cx, targetClassObject));
+  JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScope(cx, globalObject));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
   if (scopeObject != globalObject) {
     JSAutoCompartment ac2(cx, scopeObject);
 
     // Create the object. This is just a property holder, so it doesn't need
     // any special JSClass.
-    JSObject *shadowProto = JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
-                                                       scopeObject);
+    JS::Rooted<JSObject*> shadowProto(cx,
+      JS_NewObjectWithGivenProto(cx, nullptr, nullptr, scopeObject));
     NS_ENSURE_TRUE(shadowProto, NS_ERROR_OUT_OF_MEMORY);
 
     // Define it as a property on the scopeObject, using the same name used on
     // the content side.
     bool ok = JS_DefineProperty(cx, scopeObject,
                                 js::GetObjectClass(targetClassObject)->name,
                                 JS::ObjectValue(*shadowProto), JS_PropertyStub,
                                 JS_StrictPropertyStub,
--- a/content/xml/document/src/XMLDocument.cpp
+++ b/content/xml/document/src/XMLDocument.cpp
@@ -624,17 +624,17 @@ XMLDocument::Clone(nsINodeInfo *aNodeInf
   clone->mAsync = mAsync;
 
   return CallQueryInterface(clone.get(), aResult);
 }
 
 JSObject*
 XMLDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
-  JSObject* obj = XMLDocumentBinding::Wrap(aCx, aScope, this);
+  JS::Rooted<JSObject*> obj(aCx, XMLDocumentBinding::Wrap(aCx, aScope, this));
   if (obj && !PostCreateWrapper(aCx, obj)) {
     return nullptr;
   }
   return obj;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/xul/document/src/XULDocument.cpp
+++ b/content/xul/document/src/XULDocument.cpp
@@ -4757,17 +4757,17 @@ XULDocument::GetBoxObjectFor(nsIDOMEleme
     nsCOMPtr<Element> el = do_QueryInterface(aElement);
     *aResult = GetBoxObjectFor(el, rv).get();
     return rv.ErrorCode();
 }
 
 JSObject*
 XULDocument::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
-  JSObject* obj = XULDocumentBinding::Wrap(aCx, aScope, this);
+  JS::Rooted<JSObject*> obj(aCx, XULDocumentBinding::Wrap(aCx, aScope, this));
   if (obj && !PostCreateWrapper(aCx, obj)) {
     return nullptr;
   }
   return obj;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -758,19 +758,19 @@ nsXULPDGlobalObject::EnsureScriptEnviron
 
   // We have to setup a special global object.  We do this then
   // attach it as the global for this context.  Then, we
   // will re-fetch the global and set it up in our language globals array.
   {
     AutoPushJSContext cx(ctxNew->GetNativeContext());
     JSAutoRequest ar(cx);
 
-    JSObject *newGlob = JS_NewGlobalObject(cx, &gSharedGlobalClass,
-                                           nsJSPrincipals::get(GetPrincipal()),
-                                           JS::SystemZone);
+    JS::Rooted<JSObject*> newGlob(cx,
+      JS_NewGlobalObject(cx, &gSharedGlobalClass,
+                         nsJSPrincipals::get(GetPrincipal()), JS::SystemZone));
     if (!newGlob)
         return NS_OK;
 
     ::JS_SetGlobalObject(cx, newGlob);
 
     // Add an owning reference from JS back to us. This'll be
     // released when the JSObject is finalized.
     ::JS_SetPrivate(newGlob, this);
--- a/content/xul/templates/src/nsXULTemplateBuilder.cpp
+++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp
@@ -1369,36 +1369,36 @@ nsXULTemplateBuilder::InitHTMLTemplateRo
     NS_ASSERTION(doc, "no document");
     if (! doc)
         return NS_ERROR_UNEXPECTED;
 
     nsIScriptGlobalObject *global = doc->GetScriptGlobalObject();
     if (! global)
         return NS_ERROR_UNEXPECTED;
 
-    JSObject *scope = global->GetGlobalJSObject();
-
     nsIScriptContext *context = global->GetContext();
     if (! context)
         return NS_ERROR_UNEXPECTED;
 
     AutoPushJSContext jscontext(context->GetNativeContext());
     NS_ASSERTION(context != nullptr, "no jscontext");
     if (! jscontext)
         return NS_ERROR_UNEXPECTED;
 
+    JS::Rooted<JSObject*> scope(jscontext, global->GetGlobalJSObject());
+
     JSAutoRequest ar(jscontext);
 
-    JS::Value v;
+    JS::Rooted<JS::Value> v(jscontext);
     nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
-    rv = nsContentUtils::WrapNative(jscontext, scope, mRoot, mRoot, &v,
+    rv = nsContentUtils::WrapNative(jscontext, scope, mRoot, mRoot, v.address(),
                                     getter_AddRefs(wrapper));
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JSObject* jselement = JSVAL_TO_OBJECT(v);
+    JS::Rooted<JSObject*> jselement(jscontext, JSVAL_TO_OBJECT(v));
 
     if (mDB) {
         // database
         JS::Value jsdatabase;
         rv = nsContentUtils::WrapNative(jscontext, scope, mDB,
                                         &NS_GET_IID(nsIRDFCompositeDataSource),
                                         &jsdatabase, getter_AddRefs(wrapper));
         NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -947,18 +947,18 @@ nsChromeOuterWindowProxy::className(JSCo
 
 nsChromeOuterWindowProxy
 nsChromeOuterWindowProxy::singleton;
 
 static JSObject*
 NewOuterWindowProxy(JSContext *cx, JSObject *parent, bool isChrome)
 {
   JSAutoCompartment ac(cx, parent);
-  JSObject *proto;
-  if (!js::GetObjectProto(cx, parent, &proto))
+  JS::Rooted<JSObject*> proto(cx);
+  if (!js::GetObjectProto(cx, parent, proto.address()))
     return nullptr;
 
   JSObject *obj = js::Wrapper::New(cx, parent, proto, parent,
                                    isChrome ? &nsChromeOuterWindowProxy::singleton
                                             : &nsOuterWindowProxy::singleton);
 
   NS_ASSERTION(js::GetObjectClass(obj)->ext.innerObject, "bad class");
   return obj;
@@ -2031,18 +2031,18 @@ nsresult
 nsGlobalWindow::SetOuterObject(JSContext* aCx, JSObject* aOuterObject)
 {
   // Force our context's global object to be the outer.
   // NB: JS_SetGlobalObject sets aCx->compartment.
   JS_SetGlobalObject(aCx, aOuterObject);
 
   // Set up the prototype for the outer object.
   JSObject* inner = JS_GetParent(aOuterObject);
-  JSObject* proto;
-  if (!JS_GetPrototype(aCx, inner, &proto)) {
+  JS::Rooted<JSObject*> proto(aCx);
+  if (!JS_GetPrototype(aCx, inner, proto.address())) {
     return NS_ERROR_FAILURE;
   }
   JS_SetPrototype(aCx, aOuterObject, proto);
 
   return NS_OK;
 }
 
 // We need certain special behavior for remote XUL whitelisted domains, but we
@@ -6457,43 +6457,43 @@ JSObject* nsGlobalWindow::CallerGlobal()
   // If somebody does sameOriginIframeWindow.postMessage(...), they probably
   // expect the .source attribute of the resulting message event to be |window|
   // rather than |sameOriginIframeWindow|, even though the transparent wrapper
   // semantics of same-origin access will cause us to be in the iframe's cx at
   // the time of the call. So we do some nasty poking in the JS engine and
   // retrieve the global corresponding to the innermost scripted frame. Then,
   // we verify that its principal is subsumed by the subject principal. If it
   // isn't, something is screwy, and we want to clamp to the cx global.
-  JSObject *scriptedGlobal = JS_GetScriptedGlobal(cx);
-  JSObject *cxGlobal = JS_GetGlobalForScopeChain(cx);
+  JS::Rooted<JSObject*> scriptedGlobal(cx, JS_GetScriptedGlobal(cx));
+  JS::Rooted<JSObject*> cxGlobal(cx, JS_GetGlobalForScopeChain(cx));
   if (!xpc::AccessCheck::subsumes(cxGlobal, scriptedGlobal)) {
     NS_WARNING("Something nasty is happening! Applying countermeasures...");
     return cxGlobal;
   }
   return scriptedGlobal;
 }
 
 
 nsGlobalWindow*
 nsGlobalWindow::CallerInnerWindow()
 {
   JSContext *cx = nsContentUtils::GetCurrentJSContext();
   NS_ENSURE_TRUE(cx, nullptr);
-  JSObject *scope = CallerGlobal();
+  JS::Rooted<JSObject*> scope(cx, CallerGlobal());
 
   // When Jetpack runs content scripts inside a sandbox, it uses
   // sandboxPrototype to make them appear as though they're running in the
   // scope of the page. So when a content script invokes postMessage, it expects
   // the |source| of the received message to be the window set as the
   // sandboxPrototype. This used to work incidentally for unrelated reasons, but
   // now we need to do some special handling to support it.
   {
     JSAutoCompartment ac(cx, scope);
-    JSObject *scopeProto;
-    bool ok = JS_GetPrototype(cx, scope, &scopeProto);
+    JS::Rooted<JSObject*> scopeProto(cx);
+    bool ok = JS_GetPrototype(cx, scope, scopeProto.address());
     NS_ENSURE_TRUE(ok, nullptr);
     if (scopeProto && xpc::IsSandboxPrototypeProxy(scopeProto) &&
         (scopeProto = js::CheckedUnwrap(scopeProto, /* stopAtOuter = */ false)))
     {
       scope = scopeProto;
     }
   }
   JSAutoCompartment ac(cx, scope);
@@ -6583,22 +6583,22 @@ PostMessageReadStructuredClone(JSContext
 {
   NS_ASSERTION(closure, "Must have closure!");
 
   if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
     NS_ASSERTION(!data, "Data should be empty");
 
     nsISupports* supports;
     if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
-      JSObject* global = JS_GetGlobalForScopeChain(cx);
+      JS::Rooted<JSObject*> global(cx, JS_GetGlobalForScopeChain(cx));
       if (global) {
-        JS::Value val;
+        JS::Rooted<JS::Value> val(cx);
         nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
         if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, global, supports,
-                                                    &val,
+                                                    val.address(),
                                                     getter_AddRefs(wrapper)))) {
           return JSVAL_TO_OBJECT(val);
         }
       }
     }
   }
 
   const JSStructuredCloneCallbacks* runtimeCallbacks =
@@ -6723,24 +6723,26 @@ PostMessageEvent::Run()
     nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
     nsresult rv =
       ssm->CheckSameOriginURI(mProvidedOrigin, targetURI, true);
     if (NS_FAILED(rv))
       return NS_OK;
   }
 
   // Deserialize the structured clone data
-  JS::Value messageData;
+  JS::Rooted<JS::Value> messageData(cx);
   {
     JSAutoRequest ar(cx);
     StructuredCloneInfo scInfo;
     scInfo.event = this;
 
-    if (!buffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo))
+    if (!buffer.read(cx, messageData.address(), &kPostMessageCallbacks,
+                     &scInfo)) {
       return NS_ERROR_DOM_DATA_CLONE_ERR;
+    }
   }
 
   // Create the event
   nsIDocument* doc = targetWindow->mDoc;
   if (!doc)
     return NS_OK;
 
   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
@@ -7361,17 +7363,17 @@ public:
       NS_ENSURE_TRUE(currentInner, NS_OK);
 
       JSObject* obj = currentInner->FastGetGlobalJSObject();
       // We only want to nuke wrappers for the chrome->content case
       if (obj && !js::IsSystemCompartment(js::GetObjectCompartment(obj))) {
         JSContext* cx = nsContentUtils::GetSafeJSContext();
 
         JSAutoRequest ar(cx);
-        js::NukeCrossCompartmentWrappers(cx, 
+        js::NukeCrossCompartmentWrappers(cx,
                                          js::ChromeCompartmentsOnly(),
                                          js::SingleCompartment(js::GetObjectCompartment(obj)),
                                          window->IsInnerWindow() ? js::DontNukeWindowReferences :
                                                                    js::NukeWindowReferences);
       }
     }
 
     return NS_OK;
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -751,19 +751,19 @@ nsJSContext::DOMOperationCallback(JSCont
 
   // If we get here we're most likely executing an infinite loop in JS,
   // we'll tell the user about this and we'll give the user the option
   // of stopping the execution of the script.
   nsCOMPtr<nsIPrompt> prompt = GetPromptFromContext(ctx);
   NS_ENSURE_TRUE(prompt, JS_FALSE);
 
   // Check if we should offer the option to debug
-  JSScript *script;
+  JS::RootedScript script(cx);
   unsigned lineno;
-  JSBool hasFrame = ::JS_DescribeScriptedCaller(cx, &script, &lineno);
+  JSBool hasFrame = ::JS_DescribeScriptedCaller(cx, script.address(), &lineno);
 
   bool debugPossible = hasFrame && js::CanCallContextDebugHandler(cx);
 #ifdef MOZ_JSDEBUGGER
   // Get the debugger service if necessary.
   if (debugPossible) {
     bool jsds_IsOn = false;
     const char jsdServiceCtrID[] = "@mozilla.org/js/jsd/debugger-service;1";
     nsCOMPtr<jsdIExecutionHook> jsdHook;
@@ -1349,17 +1349,17 @@ nsJSContext::CompileScript(const PRUnich
                            JS::MutableHandle<JSScript*> aScriptObject,
                            bool aSaveSource /* = false */)
 {
   PROFILER_LABEL_PRINTF("JS", "Compile Script", "%s", aURL ? aURL : "");
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
   NS_ENSURE_ARG_POINTER(aPrincipal);
 
-  JSObject* scopeObject = ::JS_GetGlobalObject(mContext);
+  JS::Rooted<JSObject*> scopeObject(mContext, ::JS_GetGlobalObject(mContext));
   xpc_UnmarkGrayObject(scopeObject);
 
   bool ok = false;
 
   nsresult rv = sSecurityManager->CanExecuteScripts(mContext, aPrincipal, &ok);
   if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
   }
@@ -1466,29 +1466,32 @@ AtomIsEventHandlerName(nsIAtom *aName)
 
   return true;
 }
 #endif
 
 // Helper function to find the JSObject associated with a (presumably DOM)
 // interface.
 nsresult
-nsJSContext::JSObjectFromInterface(nsISupports* aTarget, JSObject* aScope, JSObject** aRet)
+nsJSContext::JSObjectFromInterface(nsISupports* aTarget,
+                                   JS::Handle<JSObject*> aScope,
+                                   JSObject** aRet)
 {
   // It is legal to specify a null target.
   if (!aTarget) {
     *aRet = nullptr;
     return NS_OK;
   }
 
   // Get the jsobject associated with this target
   // We don't wrap here because we trust the JS engine to wrap the target
   // later.
-  JS::Value v;
-  nsresult rv = nsContentUtils::WrapNative(mContext, aScope, aTarget, &v);
+  JS::Rooted<JS::Value> v(mContext);
+  nsresult rv = nsContentUtils::WrapNative(mContext, aScope, aTarget,
+                                           v.address());
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
   nsCOMPtr<nsISupports> targetSupp = do_QueryInterface(aTarget);
   nsCOMPtr<nsISupports> native =
     nsContentUtils::XPConnect()->GetNativeOfWrapper(mContext,
                                                     JSVAL_TO_OBJECT(v));
   NS_ASSERTION(native == targetSupp, "Native should be the target!");
@@ -1510,18 +1513,19 @@ nsJSContext::BindCompiledEventHandler(ns
   NS_PRECONDITION(!aBoundHandler, "Shouldn't already have a bound handler!");
 
   xpc_UnmarkGrayObject(aScope);
   xpc_UnmarkGrayObject(aHandler);
 
   XPCAutoRequest ar(mContext);
 
   // Get the jsobject associated with this target
-  JSObject *target = nullptr;
-  nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
+  JS::Rooted<JSObject*> target(mContext);
+  JS::Rooted<JSObject*> scope(mContext, aScope);
+  nsresult rv = JSObjectFromInterface(aTarget, scope, target.address());
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
   {
     JSAutoCompartment ac(mContext, aHandler);
     NS_ASSERTION(JS_TypeOfValue(mContext,
                                 OBJECT_TO_JSVAL(aHandler)) == JSTYPE_FUNCTION,
                  "Event handler object not a function");
@@ -1556,28 +1560,29 @@ nsJSContext::Serialize(nsIObjectOutputSt
   return nsContentUtils::XPConnect()->WriteScript(aStream, mContext,
                                                   xpc_UnmarkGrayScript(aScriptObject));
 }
 
 nsresult
 nsJSContext::Deserialize(nsIObjectInputStream* aStream,
                          JS::MutableHandle<JSScript*> aResult)
 {
-  JSScript *script;
-  nsresult rv = nsContentUtils::XPConnect()->ReadScript(aStream, mContext, &script);
+  JS::Rooted<JSScript*> script(mContext);
+  nsresult rv = nsContentUtils::XPConnect()->ReadScript(aStream, mContext,
+                                                        script.address());
   if (NS_FAILED(rv)) return rv;
 
   aResult.set(script);
   return NS_OK;
 }
 
 nsIScriptGlobalObject *
 nsJSContext::GetGlobalObject()
 {
-  JSObject *global = ::JS_GetGlobalObject(mContext);
+  JS::Rooted<JSObject*> global(mContext, ::JS_GetGlobalObject(mContext));
 
   if (!global) {
     return nullptr;
   }
 
   if (mGlobalObjectRef)
     return mGlobalObjectRef;
 
@@ -1667,18 +1672,19 @@ nsJSContext::SetProperty(JSObject* aTarg
   JS::Value *argv = nullptr;
 
   nsCxPusher pusher;
   pusher.Push(mContext);
   XPCAutoRequest ar(mContext);
 
   Maybe<nsRootedJSValueArray> tempStorage;
 
+  JS::Rooted<JSObject*> global(mContext, GetNativeGlobal());
   nsresult rv =
-    ConvertSupportsTojsvals(aArgs, GetNativeGlobal(), &argc, &argv, tempStorage);
+    ConvertSupportsTojsvals(aArgs, global, &argc, &argv, tempStorage);
   NS_ENSURE_SUCCESS(rv, rv);
 
   JS::Value vargs;
 
   // got the arguments, now attach them.
 
   // window.dialogArguments is supposed to be an array if a JS array
   // was passed to showModalDialog(), deal with that here.
@@ -1699,17 +1705,17 @@ nsJSContext::SetProperty(JSObject* aTarg
   // readonly XPConnect properties here as well (read dialogArguments).
   return JS_DefineProperty(mContext, aTarget, aPropName, vargs, NULL, NULL, 0)
     ? NS_OK
     : NS_ERROR_FAILURE;
 }
 
 nsresult
 nsJSContext::ConvertSupportsTojsvals(nsISupports *aArgs,
-                                     JSObject *aScope,
+                                     JS::Handle<JSObject*> aScope,
                                      uint32_t *aArgc,
                                      JS::Value **aArgv,
                                      Maybe<nsRootedJSValueArray> &aTempStorage)
 {
   nsresult rv = NS_OK;
 
   // If the array implements nsIJSArgArray, just grab the values directly.
   nsCOMPtr<nsIJSArgArray> fastArray = do_QueryInterface(aArgs);
@@ -1771,18 +1777,18 @@ nsJSContext::ConvertSupportsTojsvals(nsI
 #ifdef DEBUG
           // but first, check its not another nsISupportsPrimitive, as
           // these are now deprecated for use with script contexts.
           nsCOMPtr<nsISupportsPrimitive> prim(do_QueryInterface(arg));
           NS_ASSERTION(prim == nullptr,
                        "Don't pass nsISupportsPrimitives - use nsIVariant!");
 #endif
           nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
-          JS::Value v;
-          rv = nsContentUtils::WrapNative(mContext, aScope, arg, &v,
+          JS::Rooted<JS::Value> v(mContext);
+          rv = nsContentUtils::WrapNative(mContext, aScope, arg, v.address(),
                                           getter_AddRefs(wrapper));
           if (NS_SUCCEEDED(rv)) {
             *thisval = v;
           }
         }
       }
     }
   } else {
@@ -1971,20 +1977,21 @@ nsJSContext::AddSupportsPrimitiveTojsval
 
       p->GetData(getter_AddRefs(data));
       p->GetDataIID(&iid);
       NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
 
       AutoFree iidGuard(iid); // Free iid upon destruction.
 
       nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
-      JSObject *global = xpc_UnmarkGrayObject(::JS_GetGlobalObject(cx));
-      JS::Value v;
+      JS::Rooted<JSObject*> global(cx,
+        xpc_UnmarkGrayObject(::JS_GetGlobalObject(cx)));
+      JS::Rooted<JS::Value> v(cx);
       nsresult rv = nsContentUtils::WrapNative(cx, global,
-                                               data, iid, &v,
+                                               data, iid, v.address(),
                                                getter_AddRefs(wrapper));
       NS_ENSURE_SUCCESS(rv, rv);
 
       *aArgv = v;
 
       break;
     }
     case nsISupportsPrimitive::TYPE_ID :
@@ -3386,19 +3393,19 @@ NS_DOMReadStructuredClone(JSContext* cx,
                           JSStructuredCloneReader* reader,
                           uint32_t tag,
                           uint32_t data,
                           void* closure)
 {
   if (tag == SCTAG_DOM_IMAGEDATA) {
     // Read the information out of the stream.
     uint32_t width, height;
-    JS::Value dataArray;
+    JS::Rooted<JS::Value> dataArray(cx);
     if (!JS_ReadUint32Pair(reader, &width, &height) ||
-        !JS_ReadTypedArray(reader, &dataArray)) {
+        !JS_ReadTypedArray(reader, dataArray.address())) {
       return nullptr;
     }
     MOZ_ASSERT(dataArray.isObject());
 
     // Construct the ImageData.
     nsRefPtr<ImageData> imageData = new ImageData(width, height,
                                                   dataArray.toObject());
     // Wrap it in a JS::Value.
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -158,26 +158,27 @@ public:
     JSObject* global = JS_GetGlobalObject(mContext);
     return global ? mGlobalObjectRef.get() : nullptr;
   }
 protected:
   nsresult InitializeExternalClasses();
 
   // Helper to convert xpcom datatypes to jsvals.
   nsresult ConvertSupportsTojsvals(nsISupports *aArgs,
-                                   JSObject *aScope,
+                                   JS::Handle<JSObject*> aScope,
                                    uint32_t *aArgc,
                                    JS::Value **aArgv,
                                    mozilla::Maybe<nsRootedJSValueArray> &aPoolRelease);
 
   nsresult AddSupportsPrimitiveTojsvals(nsISupports *aArg, JS::Value *aArgv);
 
   // given an nsISupports object (presumably an event target or some other
   // DOM object), get (or create) the JSObject wrapping it.
-  nsresult JSObjectFromInterface(nsISupports *aSup, JSObject *aScript,
+  nsresult JSObjectFromInterface(nsISupports *aSup,
+                                 JS::Handle<JSObject*> aScript,
                                  JSObject **aRet);
 
   // Report the pending exception on our mContext, if any.  This
   // function will set aside the frame chain on mContext before
   // reporting.
   void ReportPendingException();
 private:
   void DestroyJSContext();
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -439,12 +439,40 @@ struct ParentObject {
     mObject(aObject),
     mWrapperCache(aCache)
   {}
 
   nsISupports* const mObject;
   nsWrapperCache* const mWrapperCache;
 };
 
+// Representation for dates
+class Date {
+public:
+  // Not inlining much here to avoid the extra includes we'd need
+  Date();
+  Date(double aMilliseconds) :
+    mMsecSinceEpoch(aMilliseconds)
+  {}
+
+  bool IsUndefined() const;
+  double TimeStamp() const
+  {
+    return mMsecSinceEpoch;
+  }
+  void SetTimeStamp(double aMilliseconds)
+  {
+    mMsecSinceEpoch = aMilliseconds;
+  }
+  // Can return false if CheckedUnwrap fails.  This will NOT throw;
+  // callers should do it as needed.
+  bool SetTimeStamp(JSContext* cx, JSObject* obj);
+
+  bool ToDateObject(JSContext* cx, JS::Value* vp) const;
+
+private:
+  double mMsecSinceEpoch;
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_BindingDeclarations_h__
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -3,26 +3,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 <algorithm>
 #include <stdarg.h>
 
 #include "mozilla/DebugOnly.h"
+#include "mozilla/FloatingPoint.h"
 
 #include "BindingUtils.h"
 
 #include "AccessCheck.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "XPCQuickStubs.h"
 #include "XrayWrapper.h"
+#include "jsfriendapi.h"
 
 #include "mozilla/dom/HTMLObjectElement.h"
 #include "mozilla/dom/HTMLObjectElementBinding.h"
 #include "mozilla/dom/HTMLSharedObjectElement.h"
 #include "mozilla/dom/HTMLEmbedElementBinding.h"
 #include "mozilla/dom/HTMLAppletElementBinding.h"
 
 namespace mozilla {
@@ -304,47 +306,40 @@ DefineConstructor(JSContext* cx, JS::Han
   // This is Enumerable: False per spec.
   return alreadyDefined ||
          JS_DefineProperty(cx, global, name, OBJECT_TO_JSVAL(constructor),
                            nullptr, nullptr, 0);
 }
 
 static JSObject*
 CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
+                      JS::Handle<JSObject*> constructorProto,
                       JSClass* constructorClass,
                       const JSNativeHolder* constructorNative,
                       unsigned ctorNargs, const NamedConstructor* namedConstructors,
                       JS::Handle<JSObject*> proto,
                       const NativeProperties* properties,
                       const NativeProperties* chromeOnlyProperties,
                       const char* name)
 {
   JS::Rooted<JSObject*> constructor(cx);
-  bool isCallbackInterface = constructorClass == js::Jsvalify(&js::ObjectClass);
   if (constructorClass) {
-    JSObject* constructorProto;
-    if (isCallbackInterface) {
-      constructorProto = JS_GetObjectPrototype(cx, global);
-    } else {
-      constructorProto = JS_GetFunctionPrototype(cx, global);
-    }
-    if (!constructorProto) {
-      return NULL;
-    }
+    MOZ_ASSERT(constructorProto);
     constructor = JS_NewObject(cx, constructorClass, constructorProto, global);
   } else {
     MOZ_ASSERT(constructorNative);
+    MOZ_ASSERT(constructorProto == JS_GetFunctionPrototype(cx, global));
     constructor = CreateConstructor(cx, global, name, constructorNative,
                                     ctorNargs);
   }
   if (!constructor) {
     return NULL;
   }
 
-  if (constructorClass && !isCallbackInterface) {
+  if (constructorClass) {
     // Have to shadow Function.prototype.toString, since that throws
     // on things that are not js::FunctionClass.
     JS::Rooted<JSFunction*> toString(cx,
       js::DefineFunctionWithReserved(cx, constructor,
                                      "toString",
                                      InterfaceObjectToString,
                                      0, 0));
     if (!toString) {
@@ -501,16 +496,17 @@ CreateInterfacePrototypeObject(JSContext
 
   return ourProto;
 }
 
 void
 CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
                        JS::Handle<JSObject*> protoProto,
                        JSClass* protoClass, JSObject** protoCache,
+                       JS::Handle<JSObject*> constructorProto,
                        JSClass* constructorClass, const JSNativeHolder* constructor,
                        unsigned ctorNargs, const NamedConstructor* namedConstructors,
                        JSObject** constructorCache, const DOMClass* domClass,
                        const NativeProperties* properties,
                        const NativeProperties* chromeOnlyProperties,
                        const char* name)
 {
   MOZ_ASSERT(protoClass || constructorClass || constructor,
@@ -553,17 +549,18 @@ CreateInterfaceObjects(JSContext* cx, JS
     *protoCache = proto;
   }
   else {
     MOZ_ASSERT(!proto);
   }
 
   JSObject* interface;
   if (constructorClass || constructor) {
-    interface = CreateInterfaceObject(cx, global, constructorClass, constructor,
+    interface = CreateInterfaceObject(cx, global, constructorProto,
+                                      constructorClass, constructor,
                                       ctorNargs, namedConstructors, proto,
                                       properties, chromeOnlyProperties, name);
     if (!interface) {
       if (protoCache) {
         // If we fail we need to make sure to clear the value of protoCache we
         // set above.
         *protoCache = nullptr;
       }
@@ -1712,10 +1709,48 @@ ReportLenientThisUnwrappingFailure(JSCon
 {
   GlobalObject global(cx, obj);
   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.Get());
   if (window && window->GetDoc()) {
     window->GetDoc()->WarnOnceAbout(nsIDocument::eLenientThis);
   }
 }
 
+// Date implementation methods
+Date::Date() :
+  mMsecSinceEpoch(MOZ_DOUBLE_NaN())
+{
+}
+
+bool
+Date::IsUndefined() const
+{
+  return MOZ_DOUBLE_IS_NaN(mMsecSinceEpoch);
+}
+
+bool
+Date::SetTimeStamp(JSContext* cx, JSObject* objArg)
+{
+  JS::Rooted<JSObject*> obj(cx, objArg);
+  MOZ_ASSERT(JS_ObjectIsDate(cx, obj));
+
+  obj = js::CheckedUnwrap(obj);
+  // This really sucks: even if JS_ObjectIsDate, CheckedUnwrap can _still_ fail
+  if (!obj) {
+    return false;
+  }
+  mMsecSinceEpoch = js_DateGetMsecSinceEpoch(obj);
+  return true;
+}
+
+bool
+Date::ToDateObject(JSContext* cx, JS::Value* vp) const
+{
+  JSObject* obj = JS_NewDateObjectMsec(cx, mMsecSinceEpoch);
+  if (!obj) {
+    return false;
+  }
+  *vp = JS::ObjectValue(*obj);
+  return true;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -294,16 +294,17 @@ struct NamedConstructor
 
 /*
  * Create a DOM interface object (if constructorClass is non-null) and/or a
  * DOM interface prototype object (if protoClass is non-null).
  *
  * global is used as the parent of the interface object and the interface
  *        prototype object
  * protoProto is the prototype to use for the interface prototype object.
+ * interfaceProto is the prototype to use for the interface object.
  * protoClass is the JSClass to use for the interface prototype object.
  *            This is null if we should not create an interface prototype
  *            object.
  * protoCache a pointer to a JSObject pointer where we should cache the
  *            interface prototype object. This must be null if protoClass is and
  *            vice versa.
  * constructorClass is the JSClass to use for the interface object.
  *                  This is null if we should not create an interface object or
@@ -329,16 +330,17 @@ struct NamedConstructor
  * non-null. If constructorClass or constructor are non-null, the resulting
  * interface object will be defined on the given global with property name
  * |name|, which must also be non-null.
  */
 void
 CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
                        JS::Handle<JSObject*> protoProto,
                        JSClass* protoClass, JSObject** protoCache,
+                       JS::Handle<JSObject*> interfaceProto,
                        JSClass* constructorClass, const JSNativeHolder* constructor,
                        unsigned ctorNargs, const NamedConstructor* namedConstructors,
                        JSObject** constructorCache, const DOMClass* domClass,
                        const NativeProperties* regularProperties,
                        const NativeProperties* chromeOnlyProperties,
                        const char* name);
 
 /*
@@ -1171,28 +1173,28 @@ JSObject* GetJSObjectFromCallback(void* 
 
 template<typename T>
 static inline JSObject*
 WrapCallThisObject(JSContext* cx, JS::Handle<JSObject*> scope, const T& p)
 {
   // Callbacks are nsISupports, so WrapNativeParent will just happily wrap them
   // up as an nsISupports XPCWrappedNative... which is not at all what we want.
   // So we need to special-case them.
-  JSObject* obj = GetJSObjectFromCallback(p);
+  JS::Rooted<JSObject*> obj(cx, GetJSObjectFromCallback(p));
   if (!obj) {
     // WrapNativeParent is a bit of a Swiss army knife that will
     // wrap anything for us.
     obj = WrapNativeParent(cx, scope, p);
     if (!obj) {
       return nullptr;
     }
   }
 
   // But all that won't necessarily put things in the compartment of cx.
-  if (!JS_WrapObject(cx, &obj)) {
+  if (!JS_WrapObject(cx, obj.address())) {
     return nullptr;
   }
 
   return obj;
 }
 
 // Helper for calling WrapNewBindingObject with smart pointers
 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -660,16 +660,20 @@ DOMInterfaces = {
     'nativeType': 'nsINodeList',
     'resultNotAddRefed': [ 'item' ]
 },
 
 'NotifyPaintEvent': {
     'nativeType': 'nsDOMNotifyPaintEvent',
 },
 
+'NotifyAudioAvailableEvent': {
+    'nativeType': 'nsDOMNotifyAudioAvailableEvent',
+},
+
 'PaintRequest': {
     'nativeType': 'nsPaintRequest',
 },
 
 'PaintRequestList': {
     'nativeType': 'nsPaintRequestList',
     'headerFile': 'nsPaintRequest.h',
     'resultNotAddRefed': [ 'item' ]
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -238,17 +238,17 @@ def CallOnUnforgeableHolder(descriptor, 
     global = js::GetGlobalForObjectCrossCompartment(proxy);
   }"""
     else:
         pre = """// Scope for 'global' and 'unforgeableHolder'
 {
   JSObject* global = js::GetGlobalForObjectCrossCompartment(proxy);"""
 
     return (pre + """
-  JSObject* unforgeableHolder = GetUnforgeableHolder(global, prototypes::id::%s);
+  JS::Rooted<JSObject*> unforgeableHolder(cx, GetUnforgeableHolder(global, prototypes::id::%s));
 """ + CGIndenter(CGGeneric(code)).define() + """
 }
 """) % descriptor.name
 
 class CGPrototypeJSClass(CGThing):
     def __init__(self, descriptor, properties):
         CGThing.__init__(self)
         self.descriptor = descriptor
@@ -1199,17 +1199,17 @@ class CGClassHasInstanceHook(CGAbstractS
     def generate_code(self):
         assert self.descriptor.nativeOwnership == 'nsisupports'
         header = """
   if (!vp.isObject()) {
     *bp = false;
     return true;
   }
 
-  JSObject* instance = &vp.toObject();
+  JS::Rooted<JSObject*> instance(cx, &vp.toObject());
   """
         if self.descriptor.interface.hasInterfacePrototypeObject():
             return header + """
   bool ok = InterfaceHasInstance(cx, obj, instance, bp);
   if (!ok || *bp) {
     return ok;
   }
 
@@ -1683,16 +1683,31 @@ class CGCreateInterfaceObjectsMethod(CGA
             getParentProto = "aCx, JS_GetObjectPrototype(aCx, aGlobal)"
             parentProtoType = "Rooted"
         else:
             parentProtoName = self.descriptor.prototypeChain[-2]
             getParentProto = ("%s::GetProtoObject(aCx, aGlobal)" %
                               toBindingNamespace(parentProtoName))
             parentProtoType = "Handle"
 
+        parentWithInterfaceObject = self.descriptor.interface.parent
+        while (parentWithInterfaceObject and
+               not parentWithInterfaceObject.hasInterfaceObject()):
+            parentWithInterfaceObject = parentWithInterfaceObject.parent
+        if parentWithInterfaceObject:
+            parentIfaceName = parentWithInterfaceObject.identifier.name
+            if self.descriptor.workers:
+                parentIfaceName += "_workers"
+            getConstructorProto = ("%s::GetConstructorObject(aCx, aGlobal)" %
+                                   toBindingNamespace(parentIfaceName))
+            constructorProtoType = "Handle"
+        else:
+            getConstructorProto = "aCx, JS_GetFunctionPrototype(aCx, aGlobal)"
+            constructorProtoType = "Rooted"
+
         needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
         needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject()
 
         # if we don't need to create anything, why are we generating this?
         assert needInterfaceObject or needInterfacePrototypeObject
 
         idsToInit = []
         # There is no need to init any IDs in workers, because worker bindings
@@ -1752,17 +1767,22 @@ if (!unforgeableHolder) {
                                               defineUnforgeables],
                                              "\n")
         else:
             createUnforgeableHolder = None
 
         getParentProto = ("JS::%s<JSObject*> parentProto(%s);\n" +
                           "if (!parentProto) {\n" +
                           "  return;\n" +
-                          "}\n") % (parentProtoType, getParentProto)
+                          "}") % (parentProtoType, getParentProto)
+
+        getConstructorProto = ("JS::%s<JSObject*> constructorProto(%s);\n"
+                               "if (!constructorProto) {\n"
+                               "  return;\n"
+                               "}" % (constructorProtoType, getConstructorProto))
 
         if (needInterfaceObject and
             self.descriptor.needsConstructHookHolder()):
             constructHookHolder = "&" + CONSTRUCT_HOOK_NAME + "_holder"
         else:
             constructHookHolder = "nullptr"
         if self.descriptor.interface.ctor():
             constructArgs = methodLength(self.descriptor.interface.ctor())
@@ -1802,17 +1822,17 @@ if (!unforgeableHolder) {
             properties = "nullptr"
         if self.properties.hasChromeOnly():
             accessCheck = GetAccessCheck(self.descriptor, "aGlobal")
             chromeProperties = accessCheck + " ? &sChromeOnlyNativeProperties : nullptr"
         else:
             chromeProperties = "nullptr"
         call = ("dom::CreateInterfaceObjects(aCx, aGlobal, parentProto,\n"
                 "                            %s, %s,\n"
-                "                            %s, %s, %d, %s,\n"
+                "                            constructorProto, %s, %s, %d, %s,\n"
                 "                            %s,\n"
                 "                            %s,\n"
                 "                            %s,\n"
                 "                            %s,\n"
                 "                            %s);" % (
             protoClass, protoCache,
             interfaceClass, constructHookHolder, constructArgs,
             namedConstructors,
@@ -1827,18 +1847,18 @@ if (!unforgeableHolder) {
                 "JSObject* proto = protoAndIfaceArray[prototypes::id::%s];\n"
                 "if (proto) {\n"
                 "  js::SetReservedSlot(proto, DOM_INTERFACE_PROTO_SLOTS_BASE,\n"
                 "                      JS::ObjectValue(*unforgeableHolder));\n"
                 "}" % self.descriptor.name)
         else:
             setUnforgeableHolder = None
         functionBody = CGList(
-            [CGGeneric(getParentProto), initIds, prefCache,
-             createUnforgeableHolder, CGGeneric(call), setUnforgeableHolder],
+            [CGGeneric(getParentProto), CGGeneric(getConstructorProto), initIds,
+             prefCache, createUnforgeableHolder, CGGeneric(call), setUnforgeableHolder],
             "\n\n")
         return CGIndenter(functionBody).define()
 
 class CGGetPerInterfaceObject(CGAbstractMethod):
     """
     A method for getting a per-interface object (a prototype object or interface
     constructor object).
     """
@@ -2487,17 +2507,17 @@ def getJSToNativeConversionTemplate(type
         return handleDefault(template, codeToSetNull)
 
     # A helper function for wrapping up the template body for
     # possibly-nullable objecty stuff
     def wrapObjectTemplate(templateBody, type, codeToSetNull, failureCode=None):
         if isNullOrUndefined:
             assert type.nullable()
             # Just ignore templateBody and set ourselves to null.
-            # Note that wedon't have to worry about default values
+            # Note that we don't have to worry about default values
             # here either, since we already examined this value.
             return "%s;" % codeToSetNull
 
         if not isDefinitelyObject:
             # Handle the non-object cases by wrapping up the whole
             # thing in an if cascade.
             templateBody = (
                 "if (${val}.isObject()) {\n" +
@@ -2572,17 +2592,17 @@ def getJSToNativeConversionTemplate(type
         sequenceType = typeName.define()
         if nullable:
             typeName = CGTemplatedType("Nullable", typeName)
             arrayRef = "${declName}.SetValue()"
         else:
             arrayRef = "${declName}"
 
         # NOTE: Keep this in sync with variadic conversions as needed
-        templateBody = ("""JSObject* seq = &${val}.toObject();\n
+        templateBody = ("""JS::Rooted<JSObject*> seq(cx, &${val}.toObject());\n
 if (!IsArrayLike(cx, seq)) {
 %s
 }
 uint32_t length;
 // JS_GetArrayLength actually works on all objects
 if (!JS_GetArrayLength(cx, seq, &length)) {
 %s
 }
@@ -2911,19 +2931,19 @@ for (uint32_t i = 0; i < length; ++i) {
             # it'll put a non-null pointer in there.
             if forceOwningType:
                 # Don't return a holderType in this case; our declName
                 # will just own stuff.
                 templateBody += "nsRefPtr<" + typeName + "> ${holderName};\n"
             else:
                 holderType = "nsRefPtr<" + typeName + ">"
             templateBody += (
-                "jsval tmpVal = ${val};\n" +
+                "JS::Rooted<JS::Value> tmpVal(cx, ${val});\n" +
                 typePtr + " tmp;\n"
-                "if (NS_FAILED(xpc_qsUnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n")
+                "if (NS_FAILED(xpc_qsUnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), tmpVal.address()))) {\n")
             templateBody += CGIndenter(onFailureBadType(failureCode,
                                                         descriptor.interface.identifier.name)).define()
             templateBody += ("}\n"
                 "MOZ_ASSERT(tmp);\n")
 
             if not isDefinitelyObject and not forceOwningType:
                 # Our tmpVal will go out of scope, so we can't rely on it
                 # for rooting
@@ -3279,16 +3299,43 @@ for (uint32_t i = 0; i < length; ++i) {
         return (template, declType, None, False)
 
     if type.isVoid():
         assert not isOptional
         # This one only happens for return values, and its easy: Just
         # ignore the jsval.
         return ("", None, None, False)
 
+    if type.isDate():
+        assert not isEnforceRange and not isClamp
+
+        declType = CGGeneric("Date")
+        if type.nullable():
+            declType = CGTemplatedType("Nullable", declType)
+            dateVal = "${declName}.SetValue()"
+        else:
+            dateVal = "${declName}"
+
+        if failureCode is None:
+            notDate = ("ThrowErrorMessage(cx, MSG_NOT_DATE);\n"
+                       "%s" % exceptionCode)
+        else:
+            notDate = failureCode
+
+        conversion = (
+            "if (!JS_ObjectIsDate(cx, &${val}.toObject()) ||\n"
+            "    !%s.SetTimeStamp(cx, &${val}.toObject())) {\n"
+            "%s\n"
+            "}" %
+            (dateVal, CGIndenter(CGGeneric(notDate)).define()))
+
+        conversion = wrapObjectTemplate(conversion, type,
+                                        "${declName}.SetNull()")
+        return (conversion, declType, None, isOptional)
+
     if not type.isPrimitive():
         raise TypeError("Need conversion for argument type '%s'" % str(type))
 
     typeName = builtinNames[type.tag()]
 
     conversionBehavior = "eDefault"
     if isEnforceRange:
         assert type.isInteger()
@@ -3757,17 +3804,17 @@ if (!returnArray) {
                 "if (%(result)s) {\n" +
                 CGIndenter(CGGeneric(wrapCode)).define() + "\n"
                 "} else {\n" +
                 CGIndenter(CGGeneric(setValue("JS::NullValue()"))).define() + "\n"
                 "}")
         wrapCode = wrapCode % { "result": result }
         return wrapCode, False
 
-    if type.tag() == IDLType.Tags.any:
+    if type.isAny():
         # See comments in WrapNewBindingObject explaining why we need
         # to wrap here.
         # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
         return (setValue(result, True), False)
 
     if type.isObject() or type.isSpiderMonkeyInterface():
         # See comments in WrapNewBindingObject explaining why we need
         # to wrap here.
@@ -3784,31 +3831,34 @@ if (!returnArray) {
     if type.isUnion():
         if type.nullable():
             prefix = "%s->"
         else:
             prefix = "%s."
         return (wrapAndSetPtr((prefix % result) +
                               "ToJSVal(cx, ${obj}, ${jsvalPtr})"), False)
 
-    if not (type.isPrimitive() or type.isDictionary()):
+    if not (type.isPrimitive() or type.isDictionary() or type.isDate()):
         raise TypeError("Need to learn to wrap %s" % type)
 
     if type.nullable():
         (recTemplate, recInfal) = getWrapTemplateForType(type.inner, descriptorProvider,
                                                          "%s.Value()" % result, successCode,
                                                          isCreator, exceptionCode)
         return ("if (%s.IsNull()) {\n" % result +
                 CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
                 "}\n" + recTemplate, recInfal)
 
     if type.isDictionary():
         return (wrapAndSetPtr("%s.ToObject(cx, ${obj}, ${jsvalPtr})" % result),
                 False)
 
+    if type.isDate():
+        return (wrapAndSetPtr("%s.ToDateObject(cx, ${jsvalPtr})" % result),
+                False)
 
     tag = type.tag()
 
     if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
                IDLType.Tags.uint16, IDLType.Tags.int32]:
         return (setValue("INT_TO_JSVAL(int32_t(%s))" % result), True)
 
     elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
@@ -3965,16 +4015,21 @@ def getRetvalDeclarationForType(returnTy
             CGDictionary.makeDictionaryName(returnType.unroll().inner,
                                             descriptorProvider.workers) +
             "Initializer")
         if nullable:
             result = CGTemplatedType("Nullable", result)
         return result, True
     if returnType.isUnion():
         raise TypeError("Need to sort out ownership model for union retvals");
+    if returnType.isDate():
+        result = CGGeneric("Date")
+        if returnType.nullable():
+            result = CGTemplatedType("Nullable", result)
+        return result, False
     raise TypeError("Don't know how to declare return value for %s" %
                     returnType)
 
 def isResultAlreadyAddRefed(descriptor, extendedAttributes):
     # Default to already_AddRefed on the main thread, raw pointer in workers
     return not descriptor.workers and not 'resultNotAddRefed' in extendedAttributes
 
 def needCx(returnType, arguments, extendedAttributes, descriptorProvider):
@@ -5208,16 +5263,18 @@ class CGMemberJITInfo(CGThing):
             u = t.unroll();
             if u.hasNullableType:
                 # Might be null or not
                 return "JSVAL_TYPE_UNKNOWN"
             return reduce(CGMemberJITInfo.getSingleReturnType,
                           u.flatMemberTypes, "")
         if t.isDictionary():
             return "JSVAL_TYPE_OBJECT"
+        if t.isDate():
+            return "JSVAL_TYPE_OBJECT"
         if not t.isPrimitive():
             raise TypeError("No idea what type " + str(t) + " is.")
         tag = t.tag()
         if tag in [IDLType.Tags.int8, IDLType.Tags.uint8,
                    IDLType.Tags.int16, IDLType.Tags.uint16,
                    IDLType.Tags.int32, IDLType.Tags.bool]:
             return "JSVAL_TYPE_INT32"
         if tag in [IDLType.Tags.int64, IDLType.Tags.uint64,
@@ -6777,17 +6834,17 @@ class CGDOMJSProxyHandler_hasOwn(ClassMe
                      "\n")
         else:
             named = ""
 
         return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
           "Should not have a XrayWrapper here");
 
 """ + indexed + unforgeable + """
-JSObject* expando = GetExpandoObject(proxy);
+JS::Rooted<JSObject*> expando(cx, GetExpandoObject(proxy));
 if (expando) {
   JSBool b = true;
   JSBool ok = JS_HasPropertyById(cx, expando, id, &b);
   *bp = !!b;
   if (!ok || *bp) {
     return ok;
   }
 }
@@ -6813,17 +6870,17 @@ class CGDOMJSProxyHandler_get(ClassMetho
                  "}\n"
                  "if (hasUnforgeable) {\n"
                  "  return JS_ForwardGetPropertyTo(cx, ${holder}, id, proxy, vp.address());\n"
                  "}")
             getUnforgeableOrExpando = CallOnUnforgeableHolder(self.descriptor,
                                                               hasUnforgeable)
         else:
             getUnforgeableOrExpando = ""
-        getUnforgeableOrExpando += """JSObject* expando = DOMProxyHandler::GetExpandoObject(proxy);
+        getUnforgeableOrExpando += """JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy));
 if (expando) {
   JSBool hasProp;
   if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
     return false;
   }
 
   if (hasProp) {
     return JS_GetPropertyById(cx, expando, id, vp.address());
@@ -8016,16 +8073,22 @@ class CGNativeMember(ClassMethod):
                 returnCode = ("if (${declName}.IsNull()) {\n"
                               "  retval.SetNull();\n"
                               "} else {\n"
                               "  retval.SetValue().SwapElements(${declName}.Value());\n"
                               "}")
             else:
                 returnCode = "retval.SwapElements(${declName});"
             return "void", "", returnCode
+        if type.isDate():
+            result = CGGeneric("Date")
+            if type.nullable():
+                result = CGTemplatedType("Nullable", result)
+            return (result.define(), "%s()" % result.define(),
+                    "return ${declName};")
         raise TypeError("Don't know how to declare return value for %s" %
                         type)
 
     def getArgs(self, returnType, argList):
         args = [self.getArg(arg) for arg in argList]
         # Now the outparams
         if returnType.isString():
             args.append(Argument("nsString&", "retval"))
@@ -8161,16 +8224,19 @@ class CGNativeMember(ClassMethod):
                 declType = "%s&"
             return (declType % "JSObject"), False, False
 
         if type.isDictionary():
             typeName = CGDictionary.makeDictionaryName(type.inner,
                                                        self.descriptor.workers)
             return typeName, True, True
 
+        if type.isDate():
+            return "Date", False, True
+
         assert type.isPrimitive()
 
         return builtinNames[type.tag()], False, True
 
     def getArgType(self, type, optional, variadic, isMember):
         """
         Get the type of an argument declaration.  Returns the type CGThing, and
         whether this should be a const ref.
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -32,8 +32,9 @@ MSG_DEF(MSG_ENFORCE_RANGE_OUT_OF_RANGE, 
 MSG_DEF(MSG_NOT_SEQUENCE, 0, "object can not be converted to a sequence")
 MSG_DEF(MSG_NOT_DICTIONARY, 0, "value can not be converted to a dictionary")
 MSG_DEF(MSG_INVALID_ARG, 2, "argument {0} is not valid for any of the {1}-argument overloads")
 MSG_DEF(MSG_GLOBAL_NOT_NATIVE, 0, "global is not a native object")
 MSG_DEF(MSG_ENCODING_NOT_SUPPORTED, 1, "The given encoding '{0}' is not supported.")
 MSG_DEF(MSG_DOM_ENCODING_NOT_UTF, 0, "The encoding must be utf-8, utf-16, or utf-16be.")
 MSG_DEF(MSG_NOT_FINITE, 0, "Floating-point value is not finite.")
 MSG_DEF(MSG_INVALID_VERSION, 0, "0 (Zero) is not a valid database version.")
+MSG_DEF(MSG_NOT_DATE, 0, "Value is not a date.")
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1206,17 +1206,19 @@ class IDLType(IDLObject):
         'object',
         'date',
         'void',
         # Funny stuff
         'interface',
         'dictionary',
         'enum',
         'callback',
-        'union'
+        'union',
+        'sequence',
+        'array'
         )
 
     def __init__(self, location, name):
         IDLObject.__init__(self, location)
         self.name = name
         self.builtin = False
 
     def __eq__(self, other):
@@ -1281,17 +1283,17 @@ class IDLType(IDLObject):
 
     def isDictionary(self):
         return False
 
     def isInterface(self):
         return False
 
     def isAny(self):
-        return self.tag() == IDLType.Tags.any and not self.isSequence()
+        return self.tag() == IDLType.Tags.any
 
     def isDate(self):
         return self.tag() == IDLType.Tags.date
 
     def isObject(self):
         return self.tag() == IDLType.Tags.object
 
     def isComplete(self):
@@ -1514,18 +1516,17 @@ class IDLSequenceType(IDLType):
 
     def isEnum(self):
         return False
 
     def includesRestrictedFloat(self):
         return self.inner.includesRestrictedFloat()
 
     def tag(self):
-        # XXXkhuey this is probably wrong.
-        return self.inner.tag()
+        return IDLType.Tags.sequence
 
     def resolveType(self, parentScope):
         assert isinstance(parentScope, IDLScope)
         self.inner.resolveType(parentScope)
 
     def isComplete(self):
         return self.inner.isComplete()
 
@@ -1698,18 +1699,17 @@ class IDLArrayType(IDLType):
 
     def isInterface(self):
         return False
 
     def isEnum(self):
         return False
 
     def tag(self):
-        # XXXkhuey this is probably wrong.
-        return self.inner.tag()
+        return IDLType.Tags.array
 
     def resolveType(self, parentScope):
         assert isinstance(parentScope, IDLScope)
         self.inner.resolveType(parentScope)
 
     def isComplete(self):
         return self.inner.isComplete()
 
@@ -4259,18 +4259,18 @@ class Parser(Tokenizer):
 
         type = IDLUnresolvedType(self.getLocation(p, 1), p[1])
         p[0] = self.handleModifiers(type, p[2])
 
     def p_NonAnyTypeDate(self, p):
         """
             NonAnyType : DATE TypeSuffix
         """
-        assert False
-        pass
+        p[0] = self.handleModifiers(BuiltinTypes[IDLBuiltinType.Types.date],
+                                    p[2])
 
     def p_ConstType(self, p):
         """
             ConstType : PrimitiveOrStringType Null
         """
         type = BuiltinTypes[p[1]]
         if p[2]:
             type = IDLNullableType(self.getLocation(p, 1), type)
new file mode 100644
--- /dev/null
+++ b/dom/bindings/parser/tests/test_date.py
@@ -0,0 +1,15 @@
+def WebIDLTest(parser, harness):
+    parser.parse("""
+        interface WithDates {
+          attribute Date foo;
+          void bar(Date arg);
+          void baz(sequence<Date> arg);
+        };
+    """)
+
+    results = parser.finish()
+    harness.ok(results[0].members[0].type.isDate(), "Should have Date")
+    harness.ok(results[0].members[1].signatures()[0][1][0].type.isDate(),
+               "Should have Date argument")
+    harness.ok(not results[0].members[2].signatures()[0][1][0].type.isDate(),
+               "Should have non-Date argument")
--- a/dom/bindings/parser/tests/test_distinguishability.py
+++ b/dom/bindings/parser/tests/test_distinguishability.py
@@ -152,32 +152,33 @@ def WebIDLTest(parser, harness):
     # Now let's test our whole distinguishability table
     argTypes = [ "long", "short", "long?", "short?", "DOMString", "Enum",
                  "Enum2", "Interface", "Interface?",
                  "AncestorInterface", "UnrelatedInterface",
                  "ImplementedInterface", "CallbackInterface",
                  "CallbackInterface?", "CallbackInterface2",
                  "object", "Callback", "Callback2", "optional Dict",
                  "optional Dict2", "sequence<long>", "sequence<short>",
-                 "long[]", "short[]" ]
+                 "long[]", "short[]", "Date", "Date?" ]
     # When we can parse Date and RegExp, we need to add them here.
 
     # Try to categorize things a bit to keep list lengths down
     def allBut(list1, list2):
         return [a for a in list1 if a not in list2]
     primitives = [ "long", "short", "long?", "short?", "DOMString",
                    "Enum", "Enum2" ]
     nonPrimitives = allBut(argTypes, primitives)
     interfaces = [ "Interface", "Interface?", "AncestorInterface",
                    "UnrelatedInterface", "ImplementedInterface" ]
     nullables = ["long?", "short?", "Interface?", "CallbackInterface?",
-                 "optional Dict", "optional Dict2"]
-    nonUserObjects = primitives + interfaces
+                 "optional Dict", "optional Dict2", "Date?"]
+    dates = [ "Date", "Date?" ]
+    nonUserObjects = primitives + interfaces + dates
     otherObjects = allBut(argTypes, nonUserObjects + ["object"])
-    notRelatedInterfaces = primitives + ["UnrelatedInterface"] + otherObjects
+    notRelatedInterfaces = primitives + ["UnrelatedInterface"] + otherObjects + dates
 
     # Build a representation of the distinguishability table as a dict
     # of dicts, holding True values where needed, holes elsewhere.
     data = dict();
     for type in argTypes:
         data[type] = dict()
     def setDistinguishable(type, types):
         for other in types:
@@ -203,16 +204,18 @@ def WebIDLTest(parser, harness):
     setDistinguishable("Callback", nonUserObjects)
     setDistinguishable("Callback2", nonUserObjects)
     setDistinguishable("optional Dict", allBut(nonUserObjects, nullables))
     setDistinguishable("optional Dict2", allBut(nonUserObjects, nullables))
     setDistinguishable("sequence<long>", nonUserObjects)
     setDistinguishable("sequence<short>", nonUserObjects)
     setDistinguishable("long[]", nonUserObjects)
     setDistinguishable("short[]", nonUserObjects)
+    setDistinguishable("Date", allBut(argTypes, dates + ["object"]))
+    setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"]))
 
     def areDistinguishable(type1, type2):
         return data[type1].get(type2, False)
 
     def checkDistinguishability(parser, type1, type2):
         idlTemplate = """
           enum Enum { "a", "b" };
           enum Enum2 { "c", "d" };
--- a/dom/bindings/test/Makefile.in
+++ b/dom/bindings/test/Makefile.in
@@ -68,16 +68,17 @@ MOCHITEST_FILES := \
   test_bug788369.html \
   test_bug742191.html \
   test_namedNoIndexed.html \
   test_bug759621.html \
   test_queryInterface.html \
   test_exceptionThrowing.html \
   test_bug852846.html \
   test_bug862092.html \
+  test_bug560072.html \
   $(NULL)
 
 MOCHITEST_CHROME_FILES = \
   test_bug775543.html \
   $(NULL)
 
 ifdef GNU_CC
 CXXFLAGS += -Wno-uninitialized
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -464,16 +464,27 @@ public:
   //void PassUnionWithInterfaces(const TestInterfaceOrTestExternalInterface& arg);
   //void PassUnionWithInterfacesAndNullable(const TestInterfaceOrNullOrTestExternalInterface& arg);
   void PassUnionWithArrayBuffer(const ArrayBufferOrLong&);
   void PassUnionWithString(JSContext*, const StringOrObject&);
   //void PassUnionWithEnum(JSContext*, const TestEnumOrObject&);
   //void PassUnionWithCallback(JSContext*, const TestCallbackOrLong&);
   void PassUnionWithObject(JSContext*, const ObjectOrLong&);
 
+  // Date types
+  void PassDate(Date);
+  void PassNullableDate(const Nullable<Date>&);
+  void PassOptionalDate(const Optional<Date>&);
+  void PassOptionalNullableDate(const Optional<Nullable<Date> >&);
+  void PassOptionalNullableDateWithDefaultValue(const Nullable<Date>&);
+  void PassDateSequence(const Sequence<Date>&);
+  void PassNullableDateSequence(const Sequence<Nullable<Date> >&);
+  Date ReceiveDate();
+  Nullable<Date> ReceiveNullableDate();
+
   // binaryNames tests
   void MethodRenamedTo();
   void MethodRenamedTo(int8_t);
   int8_t AttributeGetterRenamedTo();
   int8_t AttributeRenamedTo();
   void SetAttributeRenamedTo(int8_t);
 
   // Dictionary tests
@@ -500,16 +511,17 @@ public:
   static void SetStaticAttribute(const GlobalObject&, bool);
 
   // Overload resolution tests
   bool Overload1(TestInterface&);
   TestInterface* Overload1(const nsAString&, TestInterface&);
   void Overload2(TestInterface&);
   void Overload2(JSContext*, const Dict&);
   void Overload2(const nsAString&);
+  void Overload2(Date);
   void Overload3(TestInterface&);
   void Overload3(const TestCallback&);
   void Overload3(const nsAString&);
   void Overload4(TestInterface&);
   void Overload4(TestCallbackInterface&);
   void Overload4(const nsAString&);
 
   // Variadic handling
@@ -712,16 +724,24 @@ private:
 
   // Make sure unions are always const
   void PassUnion(JSContext*, ObjectOrLong& arg) MOZ_DELETE;
   void PassUnionWithNullable(JSContext*, ObjectOrNullOrLong& arg) MOZ_DELETE;
   void PassNullableUnion(JSContext*, Nullable<ObjectOrLong>&) MOZ_DELETE;
   void PassOptionalUnion(JSContext*, Optional<ObjectOrLong>&) MOZ_DELETE;
   void PassOptionalNullableUnion(JSContext*, Optional<Nullable<ObjectOrLong> >&) MOZ_DELETE;
   void PassOptionalNullableUnionWithDefaultValue(JSContext*, Nullable<ObjectOrLong>&) MOZ_DELETE;
+
+  // Make sure various date stuff is const as needed
+  void PassNullableDate(Nullable<Date>&) MOZ_DELETE;
+  void PassOptionalDate(Optional<Date>&) MOZ_DELETE;
+  void PassOptionalNullableDate(Optional<Nullable<Date> >&) MOZ_DELETE;
+  void PassOptionalNullableDateWithDefaultValue(Nullable<Date>&) MOZ_DELETE;
+  void PassDateSequence(Sequence<Date>&) MOZ_DELETE;
+  void PassNullableDateSequence(Sequence<Nullable<Date> >&) MOZ_DELETE;
 };
 
 class TestIndexedGetterInterface : public nsISupports,
                                    public nsWrapperCache
 {
 public:
   NS_DECL_ISUPPORTS
 
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -423,16 +423,27 @@ interface TestInterface {
   void passUnionWithString((DOMString or object) arg);
   //void passUnionWithEnum((TestEnum or object) arg);
   // Trying to use a callback in a union won't include the test
   // headers, unfortunately, so won't compile.
   //void passUnionWithCallback((TestCallback or long) arg);
   void passUnionWithObject((object or long) arg);
   //void passUnionWithDict((Dict or long) arg);
 
+  // Date types
+  void passDate(Date arg);
+  void passNullableDate(Date? arg);
+  void passOptionalDate(optional Date arg);
+  void passOptionalNullableDate(optional Date? arg);
+  void passOptionalNullableDateWithDefaultValue(optional Date? arg = null);
+  void passDateSequence(sequence<Date> arg);
+  void passNullableDateSequence(sequence<Date?> arg);
+  Date receiveDate();
+  Date? receiveNullableDate();
+
   // binaryNames tests
   void methodRenamedFrom();
   void methodRenamedFrom(byte argument);
   readonly attribute byte attributeGetterRenamedFrom;
   attribute byte attributeRenamedFrom;
 
   void passDictionary(optional Dict x);
   Dict receiveDictionary();
@@ -463,16 +474,17 @@ interface TestInterface {
 
   // Overload resolution tests
   //void overload1(DOMString... strs);
   boolean overload1(TestInterface arg);
   TestInterface overload1(DOMString strs, TestInterface arg);
   void overload2(TestInterface arg);
   void overload2(optional Dict arg);
   void overload2(DOMString arg);
+  void overload2(Date arg);
   void overload3(TestInterface arg);
   void overload3(TestCallback arg);
   void overload3(DOMString arg);
   void overload4(TestInterface arg);
   void overload4(TestCallbackInterface arg);
   void overload4(DOMString arg);
 
   // Variadic handling
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -317,16 +317,27 @@ interface TestExampleInterface {
   void passUnionWithString((DOMString or object) arg);
   //void passUnionWithEnum((TestEnum or object) arg);
   // Trying to use a callback in a union won't include the test
   // headers, unfortunately, so won't compile.
   //  void passUnionWithCallback((TestCallback or long) arg);
   void passUnionWithObject((object or long) arg);
   //void passUnionWithDict((Dict or long) arg);
 
+  // Date types
+  void passDate(Date arg);
+  void passNullableDate(Date? arg);
+  void passOptionalDate(optional Date arg);
+  void passOptionalNullableDate(optional Date? arg);
+  void passOptionalNullableDateWithDefaultValue(optional Date? arg = null);
+  void passDateSequence(sequence<Date> arg);
+  void passNullableDateSequence(sequence<Date?> arg);
+  Date receiveDate();
+  Date? receiveNullableDate();
+
   // binaryNames tests
   void methodRenamedFrom();
   void methodRenamedFrom(byte argument);
   readonly attribute byte attributeGetterRenamedFrom;
   attribute byte attributeRenamedFrom;
 
   void passDictionary(optional Dict x);
   //UNSUPPORTED  Dict receiveDictionary();
@@ -357,16 +368,17 @@ interface TestExampleInterface {
 
   // Overload resolution tests
   //void overload1(DOMString... strs);
   boolean overload1(TestInterface arg);
   TestInterface overload1(DOMString strs, TestInterface arg);
   void overload2(TestInterface arg);
   void overload2(optional Dict arg);
   void overload2(DOMString arg);
+  void overload2(Date arg);
   void overload3(TestInterface arg);
   void overload3(TestCallback arg);
   void overload3(DOMString arg);
   void overload4(TestInterface arg);
   void overload4(TestCallbackInterface arg);
   void overload4(DOMString arg);
 
   // Variadic handling
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -340,16 +340,27 @@ interface TestJSImplInterface {
   void passUnionWithString((DOMString or object) arg);
   //void passUnionWithEnum((MyTestEnum or object) arg);
   // Trying to use a callback in a union won't include the test
   // headers, unfortunately, so won't compile.
   //  void passUnionWithCallback((MyTestCallback or long) arg);
   void passUnionWithObject((object or long) arg);
   //void passUnionWithDict((Dict or long) arg);
 
+  // Date types
+  void passDate(Date arg);
+  void passNullableDate(Date? arg);
+  void passOptionalDate(optional Date arg);
+  void passOptionalNullableDate(optional Date? arg);
+  void passOptionalNullableDateWithDefaultValue(optional Date? arg = null);
+  void passDateSequence(sequence<Date> arg);
+  void passNullableDateSequence(sequence<Date?> arg);
+  Date receiveDate();
+  Date? receiveNullableDate();
+
   // binaryNames tests
   void methodRenamedFrom();
   void methodRenamedFrom(byte argument);
   readonly attribute byte attributeGetterRenamedFrom;
   attribute byte attributeRenamedFrom;
 
   void passDictionary(optional Dict x);
   // FIXME: Bug 863949 no dictionary return values
@@ -385,16 +396,17 @@ interface TestJSImplInterface {
 
   // Overload resolution tests
   //void overload1(DOMString... strs);
   boolean overload1(TestJSImplInterface arg);
   TestJSImplInterface overload1(DOMString strs, TestJSImplInterface arg);
   void overload2(TestJSImplInterface arg);
   void overload2(optional Dict arg);
   void overload2(DOMString arg);
+  void overload2(Date arg);
   void overload3(TestJSImplInterface arg);
   void overload3(MyTestCallback arg);
   void overload3(DOMString arg);
   void overload4(TestJSImplInterface arg);
   void overload4(TestCallbackInterface arg);
   void overload4(DOMString arg);
 
   // Variadic handling
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_bug560072.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=560072
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 560072</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=560072">Mozilla Bug 560072</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 560072 **/
+is(document.body,
+   Object.getOwnPropertyDescriptor(HTMLDocument.prototype, "body").get.call(document),
+   "Should get body out of property descriptor");
+
+is(document.body,
+   Object.getOwnPropertyDescriptor(Object.getPrototypeOf(document), "body").get.call(document),
+   "Should get body out of property descriptor this way too");
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -63,20 +63,19 @@ public:
     nsresult rv;
     nsIScriptContext* sc = mManagerPtr->GetContextForEventHandlers(&rv);
     if (!sc) {
       NS_WARNING("Cannot create script context!");
       SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
       return false;
     }
 
-    rv = nsContentUtils::WrapNative(sc->GetNativeContext(),
-                                    sc->GetNativeGlobal(),
-                                    adapter,
-                                    aValue);
+    JSContext* cx = sc->GetNativeContext();
+    JS::Rooted<JSObject*> global(cx, sc->GetNativeGlobal());
+    rv = nsContentUtils::WrapNative(cx, global, adapter, aValue);
     if (NS_FAILED(rv)) {
       NS_WARNING("Cannot create native object!");
       SetError(NS_LITERAL_STRING("BluetoothNativeObjectError"));
       return false;
     }
 
     return true;
   }
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -1063,22 +1063,23 @@ InterfaceToJsval(nsPIDOMWindow* aWindow,
     return JSVAL_NULL;
   }
 
   AutoPushJSContext cx(scriptContext->GetNativeContext());
   if (!cx) {
     return JSVAL_NULL;
   }
 
-  JS::Value someJsVal;
+  JS::Rooted<JS::Value> someJsVal(cx);
+  JS::Rooted<JSObject*> global(cx, JS_GetGlobalObject(cx));
   nsresult rv = nsContentUtils::WrapNative(cx,
-                                           JS_GetGlobalObject(cx),
+                                           global,
                                            aObject,
                                            aIID,
-                                           &someJsVal);
+                                           someJsVal.address());
   if (NS_FAILED(rv)) {
     return JSVAL_NULL;
   }
 
   return someJsVal;
 }
 
 JS::Value
--- a/dom/file/ArchiveRequest.cpp
+++ b/dom/file/ArchiveRequest.cpp
@@ -218,20 +218,19 @@ ArchiveRequest::GetFileResult(JSContext*
   for (uint32_t i = 0; i < aFileList.Length(); ++i) {
     nsCOMPtr<nsIDOMFile> file = aFileList[i];
 
     nsString filename;
     nsresult rv = file->GetName(filename);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (filename == mFilename) {
-      nsresult rv = nsContentUtils::WrapNative(
-                      aCx, JS_GetGlobalForScopeChain(aCx),
-                      file, &NS_GET_IID(nsIDOMFile), aValue);
-      return rv;
+      JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
+      return nsContentUtils::WrapNative(aCx, global, file,
+                                        &NS_GET_IID(nsIDOMFile), aValue);
     }
   }
 
   return NS_ERROR_FAILURE;
 }
 
 nsresult
 ArchiveRequest::GetFilesResult(JSContext* aCx,
@@ -241,20 +240,22 @@ ArchiveRequest::GetFilesResult(JSContext
   JSObject* array = JS_NewArrayObject(aCx, aFileList.Length(), nullptr);
   if (!array) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   for (uint32_t i = 0; i < aFileList.Length(); ++i) {
     nsCOMPtr<nsIDOMFile> file = aFileList[i];
 
-    JS::Value value;
-    nsresult rv = nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx),
-                                             file, &NS_GET_IID(nsIDOMFile), &value);
-    if (NS_FAILED(rv) || !JS_SetElement(aCx, array, i, &value)) {
+    JS::Rooted<JS::Value> value(aCx);
+    JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
+    nsresult rv = nsContentUtils::WrapNative(aCx, global, file,
+                                             &NS_GET_IID(nsIDOMFile),
+                                             value.address());
+    if (NS_FAILED(rv) || !JS_SetElement(aCx, array, i, value.address())) {
       return NS_ERROR_FAILURE;
     }
   }
 
   aValue->setObject(*array);
   return NS_OK;
 }
 
--- a/dom/file/FileHandle.cpp
+++ b/dom/file/FileHandle.cpp
@@ -186,18 +186,19 @@ FileHandle::GetFileInfo()
 }
 
 nsresult
 GetFileHelper::GetSuccessResult(JSContext* aCx, JS::Value* aVal)
 {
   nsCOMPtr<nsIDOMFile> domFile =
     mFileHandle->CreateFileObject(mLockedFile, mParams->Size());
 
+  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
   nsresult rv =
-    nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domFile,
+    nsContentUtils::WrapNative(aCx, global, domFile,
                                &NS_GET_IID(nsIDOMFile), aVal);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 /* virtual */
 JSObject*
--- a/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
+++ b/dom/imptests/failures/webapps/DOMCore/tests/approved/test_interfaces.html.json
@@ -134,11 +134,23 @@
   "CharacterData interface: document.createComment(\"abc\") must inherit property \"previousElementSibling\" with the proper type (7)": true,
   "CharacterData interface: document.createComment(\"abc\") must inherit property \"nextElementSibling\" with the proper type (8)": true,
   "CharacterData interface: document.createComment(\"abc\") must inherit property \"before\" with the proper type (9)": true,
   "CharacterData interface: calling before(union) on document.createComment(\"abc\") with too few arguments must throw TypeError": true,
   "CharacterData interface: document.createComment(\"abc\") must inherit property \"after\" with the proper type (10)": true,
   "CharacterData interface: calling after(union) on document.createComment(\"abc\") with too few arguments must throw TypeError": true,
   "CharacterData interface: document.createComment(\"abc\") must inherit property \"replace\" with the proper type (11)": true,
   "CharacterData interface: calling replace(union) on document.createComment(\"abc\") with too few arguments must throw TypeError": true,
+  "Node interface: existence and properties of interface object": true,
+  "Document interface: existence and properties of interface object": true,
+  "XMLDocument interface: existence and properties of interface object": true,
+  "DocumentFragment interface: existence and properties of interface object": true,
+  "DocumentType interface: existence and properties of interface object": true,
+  "Element interface: existence and properties of interface object": true,
+  "Attr interface: existence and properties of interface object": true,
+  "CharacterData interface: existence and properties of interface object": true,
+  "Text interface: existence and properties of interface object": true,
+  "ProcessingInstruction interface: existence and properties of interface object": true,
+  "Comment interface: existence and properties of interface object": true,
+  "DOMSettableTokenList interface: existence and properties of interface object": true,
   "NodeFilter interface: existence and properties of interface object": true,
   "NodeList interface: existence and properties of interface prototype object": true
 }
new file mode 100644
--- /dev/null
+++ b/dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/Makefile.in
@@ -0,0 +1,16 @@
+# THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT
+
+DEPTH := @DEPTH@
+
+topsrcdir := @top_srcdir@
+srcdir := @srcdir@
+VPATH := @srcdir@
+relativesrcdir := @relativesrcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MOCHITEST_FILES := \
+  test_interfaces.html.json \
+  $(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# THIS FILE IS AUTOGENERATED BY parseFailures.py - DO NOT EDIT
+
+DIRS += [
+]
new file mode 100644
--- /dev/null
+++ b/dom/imptests/failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger/test_interfaces.html.json
@@ -0,0 +1,4 @@
+{
+  "XMLHttpRequestUpload interface: existence and properties of interface object": true,
+  "XMLHttpRequest interface: existence and properties of interface object": true
+}
--- a/dom/imptests/moz.build
+++ b/dom/imptests/moz.build
@@ -21,13 +21,14 @@ DIRS += [
     'failures/html/js/builtins',
     'failures/html/old-tests/submission/Opera/microdata',
     'failures/html/typedarrays',
     'failures/webapps/DOMCore/tests/approved',
     'failures/webapps/DOMCore/tests/submissions/Ms2ger',
     'failures/webapps/DOMCore/tests/submissions/Opera',
     'failures/webapps/WebStorage/tests/submissions/Infraware',
     'failures/webapps/WebStorage/tests/submissions/Ms2ger',
+    'failures/webapps/XMLHttpRequest/tests/submissions/Ms2ger'
 ]
 
 include('editing.mozbuild')
 include('html.mozbuild')
 include('webapps.mozbuild')
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -51,39 +51,39 @@ private:
 // something fails.
 inline
 nsresult
 ConvertCloneReadInfosToArrayInternal(
                                 JSContext* aCx,
                                 nsTArray<StructuredCloneReadInfo>& aReadInfos,
                                 jsval* aResult)
 {
-  JSObject* array = JS_NewArrayObject(aCx, 0, nullptr);
+  JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0, nullptr));
   if (!array) {
     NS_WARNING("Failed to make array!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (!aReadInfos.IsEmpty()) {
     if (!JS_SetArrayLength(aCx, array, uint32_t(aReadInfos.Length()))) {
       NS_WARNING("Failed to set array length!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (uint32_t index = 0, count = aReadInfos.Length(); index < count;
          index++) {
       StructuredCloneReadInfo& readInfo = aReadInfos[index];
 
-      jsval val;
-      if (!IDBObjectStore::DeserializeValue(aCx, readInfo, &val)) {
+      JS::Rooted<JS::Value> val(aCx);
+      if (!IDBObjectStore::DeserializeValue(aCx, readInfo, val.address())) {
         NS_WARNING("Failed to decode!");
         return NS_ERROR_DOM_DATA_CLONE_ERR;
       }
 
-      if (!JS_SetElement(aCx, array, index, &val)) {
+      if (!JS_SetElement(aCx, array, index, val.address())) {
         NS_WARNING("Failed to set array element!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
   }
 
   *aResult = OBJECT_TO_JSVAL(array);
   return NS_OK;
@@ -114,17 +114,17 @@ HelperBase::WrapNative(JSContext* aCx,
                        nsISupports* aNative,
                        jsval* aResult)
 {
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aNative, "Null pointer!");
   NS_ASSERTION(aResult, "Null pointer!");
   NS_ASSERTION(mRequest, "Null request!");
 
-  JSObject* global = mRequest->GetParentObject();
+  JS::Rooted<JSObject*> global(aCx, mRequest->GetParentObject());
   NS_ASSERTION(global, "This should never be null!");
 
   nsresult rv =
     nsContentUtils::WrapNative(aCx, global, aNative, aResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
--- a/dom/indexedDB/IDBCursor.cpp
+++ b/dom/indexedDB/IDBCursor.cpp
@@ -603,18 +603,18 @@ IDBCursor::GetValue(JSContext* aCx,
   }
 
   if (!mHaveCachedValue) {
     if (!mRooted) {
       NS_HOLD_JS_OBJECTS(this, IDBCursor);
       mRooted = true;
     }
 
-    jsval val;
-    if (!IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, &val)) {
+    JS::Rooted<JS::Value> val(aCx);
+    if (!IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, val.address())) {
       return NS_ERROR_DOM_DATA_CLONE_ERR;
     }
 
     mCloneReadInfo.mCloneBuffer.clear();
 
     mCachedValue = val;
     mHaveCachedValue = true;
   }
@@ -735,18 +735,18 @@ IDBCursor::Update(const jsval& aValue,
     }
 
     rv = mObjectStore->Put(aValue, JSVAL_VOID, aCx, 0, getter_AddRefs(request));
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
   else {
-    jsval keyVal;
-    rv = objectKey.ToJSVal(aCx, &keyVal);
+    JS::Rooted<JS::Value> keyVal(aCx);
+    rv = objectKey.ToJSVal(aCx, keyVal.address());
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = mObjectStore->Put(aValue, keyVal, aCx, 1, getter_AddRefs(request));
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
@@ -806,18 +806,18 @@ IDBCursor::Delete(JSContext* aCx,
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   NS_ASSERTION(mObjectStore, "This cannot be null!");
   NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
 
   Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
 
-  jsval key;
-  nsresult rv = objectKey.ToJSVal(aCx, &key);
+  JS::Rooted<JS::Value> key(aCx);
+  nsresult rv = objectKey.ToJSVal(aCx, key.address());
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIIDBRequest> request;
   rv = mObjectStore->Delete(key, aCx, getter_AddRefs(request));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -653,36 +653,36 @@ IDBDatabase::Transaction(const jsval& aS
       return NS_ERROR_TYPE_ERR;
     }
   }
 
   nsresult rv;
   nsTArray<nsString> storesToOpen;
 
   if (!JSVAL_IS_PRIMITIVE(aStoreNames)) {
-    JSObject* obj = JSVAL_TO_OBJECT(aStoreNames);
+    JS::Rooted<JSObject*> obj(aCx, JSVAL_TO_OBJECT(aStoreNames));
 
     // See if this is a JS array.
     if (JS_IsArrayObject(aCx, obj)) {
       uint32_t length;
       if (!JS_GetArrayLength(aCx, obj, &length)) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       if (!length) {
         return NS_ERROR_DOM_INVALID_ACCESS_ERR;
       }
 
       storesToOpen.SetCapacity(length);
 
       for (uint32_t index = 0; index < length; index++) {
-        jsval val;
+        JS::Rooted<JS::Value> val(aCx);
         JSString* jsstr;
         nsDependentJSString str;
-        if (!JS_GetElement(aCx, obj, index, &val) ||
+        if (!JS_GetElement(aCx, obj, index, val.address()) ||
             !(jsstr = JS_ValueToString(aCx, val)) ||
             !str.init(aCx, jsstr)) {
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
 
         storesToOpen.AppendElement(str);
       }
 
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -213,18 +213,18 @@ IDBFactory::Create(ContentParent* aConte
 
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
   NS_ASSERTION(xpc, "This should never be null!");
 
   nsCOMPtr<nsIXPConnectJSObjectHolder> globalHolder;
   nsresult rv = xpc->CreateSandbox(cx, principal, getter_AddRefs(globalHolder));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  JSObject* global;
-  rv = globalHolder->GetJSObject(&global);
+  JS::Rooted<JSObject*> global(cx);
+  rv = globalHolder->GetJSObject(global.address());
   NS_ENSURE_SUCCESS(rv, rv);
 
   // The CreateSandbox call returns a proxy to the actual sandbox object. We
   // don't need a proxy here.
   global = js::UncheckedUnwrap(global);
 
   JSAutoCompartment ac(cx, global);
 
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -1488,40 +1488,40 @@ GetAllKeysHelper::GetSuccessResult(JSCon
 {
   NS_ASSERTION(mKeys.Length() <= mLimit, "Too many results!");
 
   nsTArray<Key> keys;
   mKeys.SwapElements(keys);
 
   JSAutoRequest ar(aCx);
 
-  JSObject* array = JS_NewArrayObject(aCx, 0, NULL);
+  JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0, NULL));
   if (!array) {
     NS_WARNING("Failed to make array!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   if (!keys.IsEmpty()) {
     if (!JS_SetArrayLength(aCx, array, uint32_t(keys.Length()))) {
       NS_WARNING("Failed to set array length!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (uint32_t index = 0, count = keys.Length(); index < count; index++) {
       const Key& key = keys[index];
       NS_ASSERTION(!key.IsUnset(), "Bad key!");
 
-      jsval value;
-      nsresult rv = key.ToJSVal(aCx, &value);
+      JS::Rooted<JS::Value> value(aCx);
+      nsresult rv = key.ToJSVal(aCx, value.address());
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to get jsval for key!");
         return rv;
       }
 
-      if (!JS_SetElement(aCx, array, index, &value)) {
+      if (!JS_SetElement(aCx, array, index, value.address())) {
         NS_WARNING("Failed to set array element!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
   }
 
   *aVal = OBJECT_TO_JSVAL(array);
   return NS_OK;
--- a/dom/indexedDB/IDBKeyRange.cpp
+++ b/dom/indexedDB/IDBKeyRange.cpp
@@ -47,18 +47,18 @@ ReturnKeyRange(JSContext* aCx,
   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
   if (NS_FAILED(xpc->WrapNative(aCx, global, aKeyRange,
                                 NS_GET_IID(nsIIDBKeyRange),
                                 getter_AddRefs(holder)))) {
     JS_ReportError(aCx, "Couldn't wrap IDBKeyRange object.");
     return false;
   }
 
-  JSObject* result;
-  if (NS_FAILED(holder->GetJSObject(&result))) {
+  JS::Rooted<JSObject*> result(aCx);
+  if (NS_FAILED(holder->GetJSObject(result.address()))) {
     JS_ReportError(aCx, "Couldn't get JSObject from wrapper.");
     return false;
   }
 
   JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(result));
   return true;
 }
 
@@ -108,18 +108,18 @@ GetKeyFromJSValOrThrow(JSContext* aCx,
 
 JSBool
 MakeOnlyKeyRange(JSContext* aCx,
                  unsigned aArgc,
                  jsval* aVp)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  jsval val;
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &val)) {
+  JS::Rooted<JS::Value> val(aCx);
+  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", val.address())) {
     return false;
   }
 
   nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(false, false, true);
 
   if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Lower())) {
     return false;
   }
@@ -129,19 +129,20 @@ MakeOnlyKeyRange(JSContext* aCx,
 
 JSBool
 MakeLowerBoundKeyRange(JSContext* aCx,
                        unsigned aArgc,
                        jsval* aVp)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  jsval val;
+  JS::Rooted<JS::Value> val(aCx);
   JSBool open = false;
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/b", &val, &open)) {
+  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/b", val.address(),
+                           &open)) {
     return false;
   }
 
   nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(open, true, false);
 
   if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Lower())) {
     return false;
   }
@@ -151,19 +152,20 @@ MakeLowerBoundKeyRange(JSContext* aCx,
 
 JSBool
 MakeUpperBoundKeyRange(JSContext* aCx,
                        unsigned aArgc,
                        jsval* aVp)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  jsval val;
+  JS::Rooted<JS::Value> val(aCx);
   JSBool open = false;
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/b", &val, &open)) {
+  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/b", val.address(),
+                           &open)) {
     return false;
   }
 
   nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(true, open, false);
 
   if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Upper())) {
     return false;
   }
@@ -173,20 +175,21 @@ MakeUpperBoundKeyRange(JSContext* aCx,
 
 JSBool
 MakeBoundKeyRange(JSContext* aCx,
                   unsigned aArgc,
                   jsval* aVp)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  jsval lowerVal, upperVal;
+  JS::Rooted<JS::Value> lowerVal(aCx), upperVal(aCx);
   JSBool lowerOpen = false, upperOpen = false;
-  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "vv/bb", &lowerVal,
-                           &upperVal, &lowerOpen, &upperOpen)) {
+  if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "vv/bb",
+                           lowerVal.address(), upperVal.address(),
+                           &lowerOpen, &upperOpen)) {
     return false;
   }
 
   nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(lowerOpen, upperOpen, false);
 
   if (!GetKeyFromJSValOrThrow(aCx, lowerVal, keyRange->Lower()) ||
       !GetKeyFromJSValOrThrow(aCx, upperVal, keyRange->Upper())) {
     return false;
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -660,22 +660,23 @@ public:
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     nsRefPtr<FileInfo>& fileInfo = aFile.mFileInfo;
 
     nsRefPtr<IDBFileHandle> fileHandle = IDBFileHandle::Create(aDatabase,
       aData.name, aData.type, fileInfo.forget());
 
-    jsval wrappedFileHandle;
+    JS::Rooted<JS::Value> wrappedFileHandle(aCx);
+    JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
     nsresult rv =
-      nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx),
+      nsContentUtils::WrapNative(aCx, global,
                                  static_cast<nsIDOMFileHandle*>(fileHandle),
                                  &NS_GET_IID(nsIDOMFileHandle),
-                                 &wrappedFileHandle);
+                                 wrappedFileHandle.address());
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to wrap native!");
       return nullptr;
     }
 
     return JSVAL_TO_OBJECT(wrappedFileHandle);
   }
 
@@ -720,20 +721,21 @@ public:
         }
         domBlob = aFile.mFile;
       }
       else {
         domBlob = new nsDOMFileFile(aData.type, aData.size, nativeFile,
                                     fileInfo);
       }
 
-      jsval wrappedBlob;
-       rv =
-        nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domBlob,
-                                   &NS_GET_IID(nsIDOMBlob), &wrappedBlob);
+      JS::Rooted<JS::Value> wrappedBlob(aCx);
+      JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
+      rv = nsContentUtils::WrapNative(aCx, global, domBlob,
+                                      &NS_GET_IID(nsIDOMBlob),
+                                      wrappedBlob.address());
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to wrap native!");
         return nullptr;
       }
 
       return JSVAL_TO_OBJECT(wrappedBlob);
     }
 
@@ -746,20 +748,21 @@ public:
       domFile = do_QueryInterface(aFile.mFile);
       NS_ASSERTION(domFile, "This should never fail!");
     }
     else {
       domFile = new nsDOMFileFile(aData.name, aData.type, aData.size,
                                   nativeFile, fileInfo);
     }
 
-    jsval wrappedFile;
-    rv =
-      nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), domFile,
-                                 &NS_GET_IID(nsIDOMFile), &wrappedFile);
+    JS::Rooted<JS::Value> wrappedFile(aCx);
+    JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
+    rv = nsContentUtils::WrapNative(aCx, global, domFile,
+                                    &NS_GET_IID(nsIDOMFile),
+                                    wrappedFile.address());
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to wrap native!");
       return nullptr;
     }
 
     return JSVAL_TO_OBJECT(wrappedFile);
   }
 };
@@ -787,27 +790,28 @@ public:
                aData.tag == SCTAG_DOM_BLOB);
 
     // The following properties are available for use in index creation
     //   Blob.size
     //   Blob.type
     //   File.name
     //   File.lastModifiedDate
 
-    JSObject* obj = JS_NewObject(aCx, nullptr, nullptr, nullptr);
+    JS::Rooted<JSObject*> obj(aCx,
+      JS_NewObject(aCx, nullptr, nullptr, nullptr));
     if (!obj) {
       NS_WARNING("Failed to create object!");
       return nullptr;
     }
 
     // Technically these props go on the proto, but this detail won't change
     // the results of index creation.
 
-    JSString* type =
-      JS_NewUCStringCopyN(aCx, aData.type.get(), aData.type.Length());
+    JS::Rooted<JSString*> type(aCx,
+      JS_NewUCStringCopyN(aCx, aData.type.get(), aData.type.Length()));
     if (!type ||
         !JS_DefineProperty(aCx, obj, "size",
                            JS_NumberValue((double)aData.size),
                            nullptr, nullptr, 0) ||
         !JS_DefineProperty(aCx, obj, "type", STRING_TO_JSVAL(type),
                            nullptr, nullptr, 0)) {
       return nullptr;
     }
@@ -922,25 +926,25 @@ IDBObjectStore::AppendIndexUpdateInfo(
 
   JS::Value val;
   if (NS_FAILED(aKeyPath.ExtractKeyAsJSVal(aCx, aVal, &val))) {
     return NS_OK;
   }
 
   if (!JSVAL_IS_PRIMITIVE(val) &&
       JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(val))) {
-    JSObject* array = JSVAL_TO_OBJECT(val);
+    JS::Rooted<JSObject*> array(aCx, JSVAL_TO_OBJECT(val));
     uint32_t arrayLength;
     if (!JS_GetArrayLength(aCx, array, &arrayLength)) {
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
-      jsval arrayItem;
-      if (!JS_GetElement(aCx, array, arrayIndex, &arrayItem)) {
+      JS::Rooted<JS::Value> arrayItem(aCx);
+      if (!JS_GetElement(aCx, array, arrayIndex, arrayItem.address())) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       Key value;
       if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
           value.IsUnset()) {
         // Not a value we can do anything with, ignore it.
         continue;
@@ -1810,17 +1814,18 @@ IDBObjectStore::AddOrPut(const jsval& aV
   if (!mTransaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
   if (!IsWriteAllowed()) {
     return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
   }
 
-  jsval keyval = (aOptionalArgCount >= 1) ? aKey : JSVAL_VOID;
+  JS::Rooted<JS::Value> keyval(aCx,
+    (aOptionalArgCount >= 1) ? aKey : JSVAL_VOID);
 
   StructuredCloneWriteInfo cloneWriteInfo;
   Key key;
   nsTArray<IndexUpdateInfo> updateInfo;
 
   nsresult rv = GetAddInfo(aCx, aValue, keyval, cloneWriteInfo, key,
                            updateInfo);
   if (NS_FAILED(rv)) {
@@ -4020,18 +4025,18 @@ CreateIndexHelper::InsertDataFromObjectS
     JSAutoStructuredCloneBuffer& buffer = cloneReadInfo.mCloneBuffer;
 
     JSStructuredCloneCallbacks callbacks = {
       IDBObjectStore::StructuredCloneReadCallback<CreateIndexDeserializationTraits>,
       nullptr,
       nullptr
     };
 
-    jsval clone;
-    if (!buffer.read(cx, &clone, &callbacks, &cloneReadInfo)) {
+    JS::Rooted<JS::Value> clone(cx);
+    if (!buffer.read(cx, clone.address(), &callbacks, &cloneReadInfo)) {
       NS_WARNING("Failed to deserialize structured clone data!");
       return NS_ERROR_DOM_DATA_CLONE_ERR;
     }
 
     nsTArray<IndexUpdateInfo> updateInfo;
     rv = IDBObjectStore::AppendIndexUpdateInfo(mIndex->Id(),
                                                mIndex->GetKeyPath(),
                                                mIndex->IsUnique(),
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -109,17 +109,17 @@ IDBRequest::NotifyHelperCompleted(Helper
   AutoPushJSContext cx(GetJSContext());
   if (!cx) {
     NS_WARNING("Failed to get safe JSContext!");
     rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     SetError(rv);
     return rv;
   }
 
-  JSObject* global = GetParentObject();
+  JS::Rooted<JSObject*> global(cx, GetParentObject());
   NS_ASSERTION(global, "This should never be null!");
 
   JSAutoRequest ar(cx);
   JSAutoCompartment ac(cx, global);
   AssertIsRooted();
 
   rv = aHelper->GetSuccessResult(cx, &mResultVal);
   if (NS_FAILED(rv)) {
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -397,53 +397,54 @@ NS_IMPL_RELEASE_WITH_DESTROY(IndexedData
 NS_IMPL_QUERY_INTERFACE1(IndexedDatabaseManager, nsIIndexedDatabaseManager)
 
 NS_IMETHODIMP
 IndexedDatabaseManager::InitWindowless(const jsval& aObj, JSContext* aCx)
 {
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
   NS_ENSURE_ARG(!JSVAL_IS_PRIMITIVE(aObj));
 
-  JSObject* obj = JSVAL_TO_OBJECT(aObj);
+  JS::Rooted<JSObject*> obj(aCx, JSVAL_TO_OBJECT(aObj));
 
   JSBool hasIndexedDB;
   if (!JS_HasProperty(aCx, obj, "indexedDB", &hasIndexedDB)) {
     return NS_ERROR_FAILURE;
   }
 
   if (hasIndexedDB) {
     NS_WARNING("Passed object already has an 'indexedDB' property!");
     return NS_ERROR_FAILURE;
   }
 
   // Instantiating this class will register exception providers so even 
   // in xpcshell we will get typed (dom) exceptions, instead of general
   // exceptions.
   nsCOMPtr<nsIDOMScriptObjectFactory> sof(do_GetService(kDOMSOF_CID));
 
-  JSObject* global = JS_GetGlobalForObject(aCx, obj);
+  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
   NS_ASSERTION(global, "What?! No global!");
 
   nsRefPtr<IDBFactory> factory;
   nsresult rv =
     IDBFactory::Create(aCx, global, nullptr, getter_AddRefs(factory));
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   NS_ASSERTION(factory, "This should never fail for chrome!");
 
-  jsval indexedDBVal;
-  rv = nsContentUtils::WrapNative(aCx, obj, factory, &indexedDBVal);
+  JS::Rooted<JS::Value> indexedDBVal(aCx);
+  rv = nsContentUtils::WrapNative(aCx, obj, factory, indexedDBVal.address());
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!JS_DefineProperty(aCx, obj, "indexedDB", indexedDBVal, nullptr,
                          nullptr, JSPROP_ENUMERATE)) {
     return NS_ERROR_FAILURE;
   }
 
-  JSObject* keyrangeObj = JS_NewObject(aCx, nullptr, nullptr, nullptr);
+  JS::Rooted<JSObject*> keyrangeObj(aCx,
+    JS_NewObject(aCx, nullptr, nullptr, nullptr));
   NS_ENSURE_TRUE(keyrangeObj, NS_ERROR_OUT_OF_MEMORY);
 
   if (!IDBKeyRange::DefineConstructors(aCx, keyrangeObj)) {
     return NS_ERROR_FAILURE;
   }
 
   if (!JS_DefineProperty(aCx, obj, "IDBKeyRange", OBJECT_TO_JSVAL(keyrangeObj),
                          nullptr, nullptr, JSPROP_ENUMERATE)) {
--- a/dom/indexedDB/Key.cpp
+++ b/dom/indexedDB/Key.cpp
@@ -128,17 +128,17 @@ Key::EncodeJSValInternal(JSContext* aCx,
     if (MOZ_DOUBLE_IS_NaN(d)) {
       return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     }
     EncodeNumber(d, eFloat + aTypeOffset);
     return NS_OK;
   }
 
   if (!JSVAL_IS_PRIMITIVE(aVal)) {
-    JSObject* obj = JSVAL_TO_OBJECT(aVal);
+    JS::Rooted<JSObject*> obj(aCx, JSVAL_TO_OBJECT(aVal));
     if (JS_IsArrayObject(aCx, obj)) {
       aTypeOffset += eMaxType;
 
       if (aTypeOffset == eMaxType * MaxArrayCollapse) {
         mBuffer.Append(aTypeOffset);
         aTypeOffset = 0;
       }
       NS_ASSERTION((aTypeOffset % eMaxType) == 0 &&
@@ -146,18 +146,18 @@ Key::EncodeJSValInternal(JSContext* aCx,
                    "Wrong typeoffset");
 
       uint32_t length;
       if (!JS_GetArrayLength(aCx, obj, &length)) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
       for (uint32_t index = 0; index < length; index++) {
-        jsval val;
-        if (!JS_GetElement(aCx, obj, index, &val)) {
+        JS::Rooted<JS::Value> val(aCx);
+        if (!JS_GetElement(aCx, obj, index, val.address())) {
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
 
         nsresult rv = EncodeJSValInternal(aCx, val, aTypeOffset,
                                           aRecursionDepth + 1);
         if (NS_FAILED(rv)) {
           return rv;
         }
@@ -186,39 +186,39 @@ Key::EncodeJSValInternal(JSContext* aCx,
 nsresult
 Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd,
                          JSContext* aCx, uint8_t aTypeOffset, jsval* aVal,
                          uint16_t aRecursionDepth)
 {
   NS_ENSURE_TRUE(aRecursionDepth < MaxRecursionDepth, NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
 
   if (*aPos - aTypeOffset >= eArray) {
-    JSObject* array = JS_NewArrayObject(aCx, 0, nullptr);
+    JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0, nullptr));
     if (!array) {
       NS_WARNING("Failed to make array!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     aTypeOffset += eMaxType;
 
     if (aTypeOffset == eMaxType * MaxArrayCollapse) {
       ++aPos;
       aTypeOffset = 0;
     }
 
     uint32_t index = 0;
     while (aPos < aEnd && *aPos - aTypeOffset != eTerminator) {
-      jsval val;
+      JS::Rooted<JS::Value> val(aCx);
       nsresult rv = DecodeJSValInternal(aPos, aEnd, aCx, aTypeOffset,
-                                        &val, aRecursionDepth + 1);
+                                        val.address(), aRecursionDepth + 1);
       NS_ENSURE_SUCCESS(rv, rv);
 
       aTypeOffset = 0;
 
-      if (!JS_SetElement(aCx, array, index++, &val)) {
+      if (!JS_SetElement(aCx, array, index++, val.address())) {
         NS_WARNING("Failed to set array element!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
     NS_ASSERTION(aPos >= aEnd || (*aPos % eMaxType) == eTerminator,
                  "Should have found end-of-array marker");
     ++aPos;
--- a/dom/indexedDB/KeyPath.cpp
+++ b/dom/indexedDB/KeyPath.cpp
@@ -86,19 +86,19 @@ GetJSValFromKeyPathString(JSContext* aCx
                "If properties are created, there must be a callback!");
 
   nsresult rv = NS_OK;
   *aKeyJSVal = aValue;
 
   KeyPathTokenizer tokenizer(aKeyPathString, '.');
 
   nsString targetObjectPropName;
-  JSObject* targetObject = nullptr;
-  JSObject* obj = JSVAL_IS_PRIMITIVE(aValue) ? nullptr : 
-                                               JSVAL_TO_OBJECT(aValue);
+  JS::Rooted<JSObject*> targetObject(aCx, nullptr);
+  JS::Rooted<JSObject*> obj(aCx,
+    JSVAL_IS_PRIMITIVE(aValue) ? nullptr : JSVAL_TO_OBJECT(aValue));
 
   while (tokenizer.hasMoreTokens()) {
     const nsDependentSubstring& token = tokenizer.nextToken();
 
     NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath");
 
     const jschar* keyPathChars = token.BeginReading();
     const size_t keyPathLen = token.Length();
@@ -111,19 +111,19 @@ GetJSValFromKeyPathString(JSContext* aCx
       }
 
       JSBool ok = JS_HasUCProperty(aCx, obj, keyPathChars, keyPathLen,
                                    &hasProp);
       NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       if (hasProp) {
         // Get if the property exists...
-        jsval intermediate;
+        JS::Rooted<JS::Value> intermediate(aCx);
         JSBool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen,
-                                     &intermediate);
+                                     intermediate.address());
         NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
         // Treat explicitly undefined as an error.
         if (intermediate == JSVAL_VOID) {
           return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
         }
         if (tokenizer.hasMoreTokens()) {
           // ...and walk to it if there are more steps...
@@ -198,20 +198,21 @@ GetJSValFromKeyPathString(JSContext* aCx
   // deletion code below even if we should not be running the callback.
   if (NS_SUCCEEDED(rv) && aCallback) {
     rv = (*aCallback)(aCx, aClosure);
   }
 
   if (targetObject) {
     // If this fails, we lose, and the web page sees a magical property
     // appear on the object :-(
-    jsval succeeded;
+    JS::Rooted<JS::Value> succeeded(aCx);
     if (!JS_DeleteUCProperty2(aCx, targetObject,
                               targetObjectPropName.get(),
-                              targetObjectPropName.Length(), &succeeded)) {
+                              targetObjectPropName.Length(),
+                              succeeded.address())) {
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
     NS_ASSERTION(JSVAL_IS_BOOLEAN(succeeded), "Wtf?");
     NS_ENSURE_TRUE(JSVAL_TO_BOOLEAN(succeeded),
                    NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
@@ -227,34 +228,34 @@ KeyPath::Parse(JSContext* aCx, const JS:
   KeyPath keyPath(0);
 
   aKeyPath->SetType(NONEXISTENT);
 
   // See if this is a JS array.
   if (!JSVAL_IS_PRIMITIVE(aValue) &&
       JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(aValue))) {
 
-    JSObject* obj = JSVAL_TO_OBJECT(aValue);
+    JS::Rooted<JSObject*> obj(aCx, JSVAL_TO_OBJECT(aValue));
 
     uint32_t length;
     if (!JS_GetArrayLength(aCx, obj, &length)) {
       return NS_ERROR_FAILURE;
     }
 
     if (!length) {
       return NS_ERROR_FAILURE;
     }
 
     keyPath.SetType(ARRAY);
 
     for (uint32_t index = 0; index < length; index++) {
-      jsval val;
+      JS::Rooted<JS::Value> val(aCx);
       JSString* jsstr;
       nsDependentJSString str;
-      if (!JS_GetElement(aCx, obj, index, &val) ||
+      if (!JS_GetElement(aCx, obj, index, val.address()) ||
           !(jsstr = JS_ValueToString(aCx, val)) ||
           !str.init(aCx, jsstr)) {
         return NS_ERROR_FAILURE;
       }
 
       if (!keyPath.AppendStringWithValidation(aCx, str)) {
         return NS_ERROR_FAILURE;
       }
@@ -308,22 +309,23 @@ KeyPath::AppendStringWithValidation(JSCo
   NS_NOTREACHED("What?!");
   return false;
 }
 
 nsresult
 KeyPath::ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const
 {
   uint32_t len = mStrings.Length();
-  JS::Value value;
+  JS::Rooted<JS::Value> value(aCx);
 
   aKey.Unset();
 
   for (uint32_t i = 0; i < len; ++i) {
-    nsresult rv = GetJSValFromKeyPathString(aCx, aValue, mStrings[i], &value,
+    nsresult rv = GetJSValFromKeyPathString(aCx, aValue, mStrings[i],
+                                            value.address(),
                                             DoNotCreateProperties, nullptr,
                                             nullptr);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     if (NS_FAILED(aKey.AppendItem(aCx, IsArray() && i == 0, value))) {
       NS_ASSERTION(aKey.IsUnset(), "Encoding error should unset");
@@ -341,53 +343,55 @@ KeyPath::ExtractKeyAsJSVal(JSContext* aC
                            JS::Value* aOutVal) const
 {
   NS_ASSERTION(IsValid(), "This doesn't make sense!");
 
   if (IsString()) {
     return GetJSValFromKeyPathString(aCx, aValue, mStrings[0], aOutVal,
                                      DoNotCreateProperties, nullptr, nullptr);
   }
- 
+
   const uint32_t len = mStrings.Length();
   JS::RootedObject arrayObj(aCx, JS_NewArrayObject(aCx, len, nullptr));
   if (!arrayObj) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  JS::Value value;
+  JS::Rooted<JS::Value> value(aCx);
   for (uint32_t i = 0; i < len; ++i) {
-    nsresult rv = GetJSValFromKeyPathString(aCx, aValue, mStrings[i], &value,
+    nsresult rv = GetJSValFromKeyPathString(aCx, aValue, mStrings[i],
+                                            value.address(),
                                             DoNotCreateProperties, nullptr,
                                             nullptr);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
-    if (!JS_SetElement(aCx, arrayObj, i, &value)) {
+    if (!JS_SetElement(aCx, arrayObj, i, value.address())) {
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
 
   *aOutVal = OBJECT_TO_JSVAL(arrayObj);
   return NS_OK;
 }
 
 nsresult
 KeyPath::ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue,
                             Key& aKey, ExtractOrCreateKeyCallback aCallback,
                             void* aClosure) const
 {
   NS_ASSERTION(IsString(), "This doesn't make sense!");
 
-  JS::Value value;
+  JS::Rooted<JS::Value> value(aCx);
 
   aKey.Unset();
 
-  nsresult rv = GetJSValFromKeyPathString(aCx, aValue, mStrings[0], &value,
+  nsresult rv = GetJSValFromKeyPathString(aCx, aValue, mStrings[0],
+                                          value.address(),
                                           CreateProperties, aCallback,
                                           aClosure);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   if (NS_FAILED(aKey.AppendItem(aCx, false, value))) {
     NS_ASSERTION(aKey.IsUnset(), "Should be unset");
@@ -452,30 +456,30 @@ KeyPath::DeserializeFromString(const nsA
   return keyPath;
 }
 
 nsresult
 KeyPath::ToJSVal(JSContext* aCx, JS::Value* aValue) const
 {
   if (IsArray()) {
     uint32_t len = mStrings.Length();
-    JSObject* array = JS_NewArrayObject(aCx, len, nullptr);
+    JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, len, nullptr));
     if (!array) {
       NS_WARNING("Failed to make array!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     for (uint32_t i = 0; i < len; ++i) {
-      jsval val;
+      JS::Rooted<JS::Value> val(aCx);
       nsString tmp(mStrings[i]);
-      if (!xpc::StringToJsval(aCx, tmp, &val)) {
+      if (!xpc::StringToJsval(aCx, tmp, val.address())) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
-      if (!JS_SetElement(aCx, array, i, &val)) {
+      if (!JS_SetElement(aCx, array, i, val.address())) {
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
     }
 
     *aValue = OBJECT_TO_JSVAL(array);
     return NS_OK;
   }
 
--- a/dom/indexedDB/ipc/IndexedDBParent.cpp
+++ b/dom/indexedDB/ipc/IndexedDBParent.cpp
@@ -379,27 +379,27 @@ IndexedDBDatabaseParent::HandleRequestEv
 
     if (!SendBlocked(oldVersion)) {
       return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
   }
 
-  jsval result;
-  rv = mOpenRequest->GetResult(&result);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  MOZ_ASSERT(!JSVAL_IS_PRIMITIVE(result));
-
   nsIXPConnect* xpc = nsContentUtils::XPConnect();
   MOZ_ASSERT(xpc);
 
   SafeAutoJSContext cx;
 
+  JS::Rooted<JS::Value> result(cx);
+  rv = mOpenRequest->GetResult(result.address());
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  MOZ_ASSERT(!JSVAL_IS_PRIMITIVE(result));
+
   nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
   rv = xpc->GetWrappedNativeOfJSObject(cx, JSVAL_TO_OBJECT(result),
                                        getter_AddRefs(wrapper));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIIDBDatabase> database;
   if (!wrapper || !(database = do_QueryInterface(wrapper->Native()))) {
     NS_WARNING("Didn't get the object we expected!");
@@ -531,18 +531,18 @@ IndexedDBDatabaseParent::HandleDatabaseE
 
     nsCOMPtr<nsIIDBVersionChangeEvent> changeEvent = do_QueryInterface(aEvent);
     NS_ENSURE_TRUE(changeEvent, NS_ERROR_FAILURE);
 
     uint64_t oldVersion;
     rv = changeEvent->GetOldVersion(&oldVersion);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JS::Value newVersionVal;
-    rv = changeEvent->GetNewVersion(cx, &newVersionVal);
+    JS::Rooted<JS::Value> newVersionVal(cx);
+    rv = changeEvent->GetNewVersion(cx, newVersionVal.address());
     NS_ENSURE_SUCCESS(rv, rv);
 
     uint64_t newVersion;
     if (newVersionVal.isNull()) {
       newVersion = 0;
     }
     else {
       MOZ_ASSERT(newVersionVal.isNumber());
--- a/dom/interfaces/html/nsIDOMHTMLInputElement.idl
+++ b/dom/interfaces/html/nsIDOMHTMLInputElement.idl
@@ -15,17 +15,17 @@ interface nsIDOMValidityState;
   *
   * This interface is trying to follow the DOM Level 2 HTML specification:
   * http://www.w3.org/TR/DOM-Level-2-HTML/
   *
   * with changes from the work-in-progress WHATWG HTML specification:
   * http://www.whatwg.org/specs/web-apps/current-work/
   */
 
-[scriptable, uuid(79474f55-a561-44d6-a80f-8e57dba634dd)]
+[scriptable, uuid(d57537ed-39d0-46ea-8516-0ce0a5bfb805)]
 interface nsIDOMHTMLInputElement : nsIDOMHTMLElement
 {
            attribute DOMString             accept;
            attribute DOMString             alt;
 
            attribute DOMString             autocomplete;
            attribute boolean               autofocus;
            attribute boolean               defaultChecked;
@@ -64,17 +64,19 @@ interface nsIDOMHTMLInputElement : nsIDO
            attribute unsigned long         size;
            attribute unsigned long width;
            attribute DOMString             src;
 
            attribute DOMString             type;
            attribute DOMString             defaultValue;
            attribute DOMString             value;
            attribute double                valueAsNumber;
-  [implicit_jscontext] attribute jsval     valueAsDate;
+          // valustAsDate is only supported via WebIDL, because it's intimately
+          // tied to JS Date objects and xpidl support for that sort of thing is
+          // terrible.
 
   [optional_argc] void stepDown([optional] in long n);
   [optional_argc] void stepUp([optional] in long n);
 
   // The following lines are part of the constraint validation API, see:
   // http://www.whatwg.org/specs/web-apps/current-work/#the-constraint-validation-api
   readonly attribute boolean             willValidate;
   readonly attribute nsIDOMValidityState validity;
--- a/dom/ipc/StructuredCloneUtils.cpp
+++ b/dom/ipc/StructuredCloneUtils.cpp
@@ -52,20 +52,21 @@ Read(JSContext* aCx, JSStructuredCloneRe
         MOZ_NOT_REACHED("GetMutable failed!");
       }
       else {
         MOZ_ASSERT(!isMutable);
       }
     }
 #endif
 
-    JS::Value wrappedFile;
-    nsresult rv =
-      nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), file,
-                                  &NS_GET_IID(nsIDOMFile), &wrappedFile);
+    JS::Rooted<JS::Value> wrappedFile(aCx);
+    JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
+    nsresult rv = nsContentUtils::WrapNative(aCx, global, file,
+                                             &NS_GET_IID(nsIDOMFile),
+                                             wrappedFile.address());
     if (NS_FAILED(rv)) {
       Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR);
       return nullptr;
     }
 
     return &wrappedFile.toObject();
   }
 
@@ -84,20 +85,21 @@ Read(JSContext* aCx, JSStructuredCloneRe
         MOZ_NOT_REACHED("GetMutable failed!");
       }
       else {
         MOZ_ASSERT(!isMutable);
       }
     }
 #endif
 
-    JS::Value wrappedBlob;
-    nsresult rv =
-      nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), blob,
-                                  &NS_GET_IID(nsIDOMBlob), &wrappedBlob);
+    JS::Rooted<JS::Value> wrappedBlob(aCx);
+    JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
+    nsresult rv = nsContentUtils::WrapNative(aCx, global, blob,
+                                             &NS_GET_IID(nsIDOMBlob),
+                                             wrappedBlob.address());
     if (NS_FAILED(rv)) {
       Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR);
       return nullptr;
     }
 
     return &wrappedBlob.toObject();
   }
 
--- a/dom/mobilemessage/src/MmsMessage.cpp
+++ b/dom/mobilemessage/src/MmsMessage.cpp
@@ -484,18 +484,19 @@ MmsMessage::GetAttachments(JSContext* aC
 
     tmpJsVal.setString(tmpJsStr);
     if (!JS_DefineProperty(aCx, attachmentObj, "location", tmpJsVal,
                            NULL, NULL, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
     // Get |attachment.mContent|.
+    JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
     nsresult rv = nsContentUtils::WrapNative(aCx,
-                                             JS_GetGlobalForScopeChain(aCx),
+                                             global,
                                              attachment.content,
                                              &NS_GET_IID(nsIDOMBlob),
                                              &tmpJsVal);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!JS_DefineProperty(aCx, attachmentObj, "content", tmpJsVal,
                            NULL, NULL, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
--- a/dom/mobilemessage/src/MobileMessageCallback.cpp
+++ b/dom/mobilemessage/src/MobileMessageCallback.cpp
@@ -49,24 +49,25 @@ MobileMessageCallback::NotifySuccess(nsI
   nsresult rv;
   nsIScriptContext* scriptContext = mDOMRequest->GetContextForEventHandlers(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(scriptContext, NS_ERROR_FAILURE);
 
   AutoPushJSContext cx(scriptContext->GetNativeContext());
   NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
 
-  JSObject* global = scriptContext->GetNativeGlobal();
+  JS::Rooted<JSObject*> global(cx, scriptContext->GetNativeGlobal());
   NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
 
   JSAutoRequest ar(cx);
   JSAutoCompartment ac(cx, global);
 
-  JS::Value wrappedMessage;
-  rv = nsContentUtils::WrapNative(cx, global, aMessage, &wrappedMessage);
+  JS::Rooted<JS::Value> wrappedMessage(cx);
+  rv = nsContentUtils::WrapNative(cx, global, aMessage,
+                                  wrappedMessage.address());
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NotifySuccess(wrappedMessage);
 }
 
 nsresult
 MobileMessageCallback::NotifyError(int32_t aError)
 {
--- a/dom/mobilemessage/src/MobileMessageCursorCallback.cpp
+++ b/dom/mobilemessage/src/MobileMessageCursorCallback.cpp
@@ -62,24 +62,24 @@ MobileMessageCursorCallback::NotifyCurso
   nsresult rv;
   nsIScriptContext* scriptContext = mDOMCursor->GetContextForEventHandlers(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(scriptContext, NS_ERROR_FAILURE);
 
   AutoPushJSContext cx(scriptContext->GetNativeContext());
   NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE);
 
-  JSObject* global = scriptContext->GetNativeGlobal();
+  JS::Rooted<JSObject*> global(cx, scriptContext->GetNativeGlobal());
   NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
 
   JSAutoRequest ar(cx);
   JSAutoCompartment ac(cx, global);
 
-  JS::Value wrappedResult;
-  rv = nsContentUtils::WrapNative(cx, global, aResult, &wrappedResult);
+  JS::Rooted<JS::Value> wrappedResult(cx);
+  rv = nsContentUtils::WrapNative(cx, global, aResult, wrappedResult.address());
   NS_ENSURE_SUCCESS(rv, rv);
 
   mDOMCursor->FireSuccess(wrappedResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MobileMessageCursorCallback::NotifyCursorDone()
--- a/dom/mobilemessage/src/MobileMessageManager.cpp
+++ b/dom/mobilemessage/src/MobileMessageManager.cpp
@@ -116,17 +116,18 @@ MobileMessageManager::Send(JSContext* aC
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsCOMPtr<nsIMobileMessageCallback> msgCallback =
     new MobileMessageCallback(request);
 
   nsresult rv = smsService->Send(number, aMessage, msgCallback);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = nsContentUtils::WrapNative(aCx, aGlobal,
+  JS::Rooted<JSObject*> global(aCx, aGlobal);
+  rv = nsContentUtils::WrapNative(aCx, global,
                                   static_cast<nsIDOMDOMRequest*>(request.get()),
                                   aRequest);
   if (NS_FAILED(rv)) {
     NS_ERROR("Failed to create the js value!");
     return rv;
   }
 
   return NS_OK;
--- a/dom/mobilemessage/src/SmsManager.cpp
+++ b/dom/mobilemessage/src/SmsManager.cpp
@@ -152,17 +152,18 @@ SmsManager::Send(JSContext* aCx, JSObjec
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsCOMPtr<nsIMobileMessageCallback> msgCallback =
     new MobileMessageCallback(request);
 
   nsresult rv = smsService->Send(number, aMessage, msgCallback);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = nsContentUtils::WrapNative(aCx, aGlobal,
+  JS::Rooted<JSObject*> global(aCx, aGlobal);
+  rv = nsContentUtils::WrapNative(aCx, global,
                                   static_cast<nsIDOMDOMRequest*>(request.get()),
                                   aRequest);
   if (NS_FAILED(rv)) {
     NS_ERROR("Failed to create the js value!");
     return rv;
   }
 
   return NS_OK;
--- a/dom/mobilemessage/src/ipc/SmsParent.cpp
+++ b/dom/mobilemessage/src/ipc/SmsParent.cpp
@@ -51,18 +51,19 @@ MmsAttachmentDataToJSObject(JSContext* a
   NS_ENSURE_TRUE(locStr, nullptr);
   if (!JS_DefineProperty(aContext, obj, "location", JS::StringValue(locStr),
                          nullptr, nullptr, 0)) {
     return nullptr;
   }
 
   nsCOMPtr<nsIDOMBlob> blob = static_cast<BlobParent*>(aAttachment.contentParent())->GetBlob();
   JS::Value content;
+  JS::Rooted<JSObject*> global (aContext, JS_GetGlobalForScopeChain(aContext));
   nsresult rv = nsContentUtils::WrapNative(aContext,
-                                           JS_GetGlobalForScopeChain(aContext),
+                                           global,
                                            blob,
                                            &NS_GET_IID(nsIDOMBlob),
                                            &content);
   NS_ENSURE_SUCCESS(rv, nullptr);
   if (!JS_DefineProperty(aContext, obj, "content", content,
                          nullptr, nullptr, 0)) {
     return nullptr;
   }
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -291,24 +291,24 @@ Telephony::GetActive(JS::Value* aActive)
   if (!mActiveCall) {
     aActive->setNull();
     return NS_OK;
   }
 
   nsresult rv;
   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
-  AutoPushJSContext cx(sc ? sc->GetNativeContext() : nullptr);
-  if (sc) {
-    rv =
-      nsContentUtils::WrapNative(cx, sc->GetNativeGlobal(),
-                                 mActiveCall->ToISupports(), aActive);
-    NS_ENSURE_SUCCESS(rv, rv);
+  if (!sc) {
+    return NS_OK;
   }
-  return NS_OK;
+
+  AutoPushJSContext cx(sc->GetNativeContext());
+  JS::Rooted<JSObject*> global(cx, sc->GetNativeGlobal());
+  return nsContentUtils::WrapNative(cx, global, mActiveCall->ToISupports(),
+                                    aActive);
 }
 
 NS_IMETHODIMP
 Telephony::GetCalls(JS::Value* aCalls)
 {
   JSObject* calls = mCallsArray;
   if (!calls) {
     nsresult rv;
--- a/dom/tests/mochitest/general/test_offsets.xul
+++ b/dom/tests/mochitest/general/test_offsets.xul
@@ -22,17 +22,17 @@
           maxwidth="66" maxheight="56">
       <label value="One" style="margin: 0"/>
       <label id="scrollchild" value="Two"/>
       <label value="Three"/>
       <label id="lastline" value="This fourth label is much longer than the others"
              style="margin: 0; padding: 0; border: 0;"/>
     </vbox>
     <vbox id="scrollbox-test">
-       <scrollbar orient="vertical" style="margin: 0; border: 0; padding: 0;"/>
+       <scrollbar orient="vertical" style="border: 0; padding: 0;"/>
     </vbox>
   </hbox>
 </vbox>
 
 <svg:svg id="svgbase" width="45" height="20" xmlns:svg="http://www.w3.org/2000/svg">
   <svg:rect id="svgrect" x="3" y="5" width="45" height="20" fill="red"/>
 </svg:svg>
 
--- a/dom/webidl/HTMLInputElement.webidl
+++ b/dom/webidl/HTMLInputElement.webidl
@@ -76,19 +76,18 @@ interface HTMLInputElement : HTMLElement
   [Pure, SetterThrows]
            attribute DOMString step;
   [Pure, SetterThrows]
            attribute DOMString type;
   [Pure, SetterThrows]
            attribute DOMString defaultValue;
   [Pure, TreatNullAs=EmptyString, SetterThrows]
            attribute DOMString value;
-           // Bug 742206 - any to Date?
   [Throws]
-           attribute any valueAsDate;
+           attribute Date? valueAsDate;
   [Pure, SetterThrows]
            attribute unrestricted double valueAsNumber;
            attribute unsigned long width;
 
   [Throws]
   void stepUp(optional long n = 1);
   [Throws]
   void stepDown(optional long n = 1);
new file mode 100644
--- /dev/null
+++ b/dom/webidl/NotifyAudioAvailableEvent.webidl
@@ -0,0 +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 NotifyAudioAvailableEvent : Event
+{
+  [Throws]
+  readonly attribute Float32Array frameBuffer;
+
+  readonly attribute float  time;
+
+  [Throws]
+  void initAudioAvailableEvent(DOMString type,
+                               boolean canBubble,
+                               boolean cancelable,
+                               sequence<float>? frameBuffer,
+                               unsigned long frameBufferLength,
+                               float time,
+                               boolean allowAudioData);
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -167,16 +167,17 @@ webidl_files = \
   MutationEvent.webidl \
   MutationObserver.webidl \
   NetDashboard.webidl \
   Node.webidl \
   NodeFilter.webidl \
   NodeIterator.webidl \
   NodeList.webidl \
   Notification.webidl \
+  NotifyAudioAvailableEvent.webidl \
   NotifyPaintEvent.webidl \
   PaintRequest.webidl \
   PaintRequestList.webidl \
   PannerNode.webidl \
   Performance.webidl \
   PerformanceNavigation.webidl \
   PerformanceTiming.webidl \
   Position.webidl \
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -303,20 +303,21 @@ struct MainThreadWorkerStructuredCloneCa
           NS_ASSERTION(NS_SUCCEEDED(mutableFile->GetMutable(&isMutable)) &&
                        !isMutable,
                        "Only immutable file should be passed to worker");
         }
 #endif
 
         // nsIDOMFiles should be threadsafe, thus we will use the same instance
         // on the main thread.
-        JS::Value wrappedFile;
-        nsresult rv =
-          nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), file,
-                                     &NS_GET_IID(nsIDOMFile), &wrappedFile);
+        JS::Rooted<JS::Value> wrappedFile(aCx);
+        JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
+        nsresult rv = nsContentUtils::WrapNative(aCx, global, file,
+                                                 &NS_GET_IID(nsIDOMFile),
+                                                 wrappedFile.address());
         if (NS_FAILED(rv)) {
           Error(aCx, DATA_CLONE_ERR);
           return nullptr;
         }
 
         return &wrappedFile.toObject();
       }
     }
@@ -336,20 +337,21 @@ struct MainThreadWorkerStructuredCloneCa
           NS_ASSERTION(NS_SUCCEEDED(mutableBlob->GetMutable(&isMutable)) &&
                        !isMutable,
                        "Only immutable blob should be passed to worker");
         }
 #endif
 
         // nsIDOMBlobs should be threadsafe, thus we will use the same instance
         // on the main thread.
-        JS::Value wrappedBlob;
-        nsresult rv =
-          nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx), blob,
-                                     &NS_GET_IID(nsIDOMBlob), &wrappedBlob);
+        JS::Rooted<JS::Value> wrappedBlob(aCx);
+        JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
+        nsresult rv = nsContentUtils::WrapNative(aCx, global, blob,
+                                                 &NS_GET_IID(nsIDOMBlob),
+                                                 wrappedBlob.address());
         if (NS_FAILED(rv)) {
           Error(aCx, DATA_CLONE_ERR);
           return nullptr;
         }
 
         return &wrappedBlob.toObject();
       }
     }
--- a/gfx/layers/ipc/Axis.cpp
+++ b/gfx/layers/ipc/Axis.cpp
@@ -216,17 +216,17 @@ float Axis::GetExcess() {
   case OVERSCROLL_MINUS: return GetOrigin() - GetPageStart();
   case OVERSCROLL_PLUS: return GetCompositionEnd() - GetPageEnd();
   case OVERSCROLL_BOTH: return (GetCompositionEnd() - GetPageEnd()) +
                                (GetPageStart() - GetOrigin());
   default: return 0;
   }
 }
 
-Axis::Overscroll Axis::DisplacementWillOverscroll(int32_t aDisplacement) {
+Axis::Overscroll Axis::DisplacementWillOverscroll(float aDisplacement) {
   // If the current pan plus a displacement takes the window to the left of or
   // above the current page rect.
   bool minus = GetOrigin() + aDisplacement < GetPageStart();
   // If the current pan plus a displacement takes the window to the right of or
   // below the current page rect.
   bool plus = GetCompositionEnd() + aDisplacement > GetPageEnd();
   if (minus && plus) {
     return OVERSCROLL_BOTH;
@@ -235,17 +235,17 @@ Axis::Overscroll Axis::DisplacementWillO
     return OVERSCROLL_MINUS;
   }
   if (plus) {
     return OVERSCROLL_PLUS;
   }
   return OVERSCROLL_NONE;
 }
 
-float Axis::DisplacementWillOverscrollAmount(int32_t aDisplacement) {
+float Axis::DisplacementWillOverscrollAmount(float aDisplacement) {
   switch (DisplacementWillOverscroll(aDisplacement)) {
   case OVERSCROLL_MINUS: return (GetOrigin() + aDisplacement) - GetPageStart();
   case OVERSCROLL_PLUS: return (GetCompositionEnd() + aDisplacement) - GetPageEnd();
   // Don't handle overscrolled in both directions; a displacement can't cause
   // this, it must have already been zoomed out too far.
   default: return 0;
   }
 }
--- a/gfx/layers/ipc/Axis.h
+++ b/gfx/layers/ipc/Axis.h
@@ -120,23 +120,23 @@ public:
    */
   float GetVelocity();
 
   /**
    * Gets the overscroll state of the axis given an additional displacement.
    * That is to say, if the given displacement is applied, this will tell you
    * whether or not it will overscroll, and in what direction.
    */
-  Overscroll DisplacementWillOverscroll(int32_t aDisplacement);
+  Overscroll DisplacementWillOverscroll(float aDisplacement);
 
   /**
    * If a displacement will overscroll the axis, this returns the amount and in
    * what direction. Similar to getExcess() but takes a displacement to apply.
    */
-  float DisplacementWillOverscrollAmount(int32_t aDisplacement);
+  float DisplacementWillOverscrollAmount(float aDisplacement);
 
   /**
    * Gets the overscroll state of the axis given a scaling of the page. That is
    * to say, if the given scale is applied, this will tell you whether or not
    * it will overscroll, and in what direction.
    *
    * |aFocus| is the point at which the scale is focused at. We will offset the
    * scroll offset in such a way that it remains in the same place on the page
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/d3dkmtQueryStatistics.h
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * 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/. */
+/* This file is based on a header file that was briefly seen in the
+ * Windows 8 RC SDK. The work for this file itself was based on the one in ProcessHacker at
+ * http://processhacker.svn.sourceforge.net/viewvc/processhacker/2.x/trunk/plugins/ExtendedTools/d3dkmt.h?revision=4758&view=markup
+ * For more details see Mozilla Bug 689870.
+ */
+
+typedef struct _D3DKMTQS_COUNTER
+{
+    ULONG Count;
+    ULONGLONG Bytes;
+} D3DKMTQS_COUNTER;
+
+typedef struct _D3DKMTQS_ADAPTER_INFO
+{
+    ULONG NbSegments;
+
+    ULONG Filler[4];
+    ULONGLONG Filler2[2]; // Assumed sizeof(LONGLONG) = sizeof(ULONGLONG)
+    struct {
+        ULONG Filler[14];
+    } Filler_RDMAB;
+    struct {
+        ULONG Filler[9];
+    } Filler_R;
+    struct {
+        ULONG Filler[4];
+        D3DKMTQS_COUNTER Filler2;
+    } Filler_P;
+    struct {
+        D3DKMTQS_COUNTER Filler[16];
+        ULONG Filler2[2];
+    } Filler_PF;
+    struct {
+        ULONGLONG Filler[8];
+    } Filler_PT;
+    struct {
+        ULONG Filler[2];
+    } Filler_SR;
+    struct {
+        ULONG Filler[7];
+    } Filler_L;
+    struct {
+        D3DKMTQS_COUNTER Filler[7];
+    } Filler_A;
+    struct {
+        D3DKMTQS_COUNTER Filler[4];
+    } Filler_T;
+    ULONG64 Reserved[8];
+} D3DKMTQS_ADAPTER_INFO;
+
+typedef struct _D3DKMTQS_SEGMENT_INFO_WIN7
+{
+    ULONG Filler[3];
+    struct {
+        ULONGLONG Filler;
+        ULONG Filler2[2];
+    } Filler_M;
+
+    ULONG Aperture;
+
+    ULONGLONG Filler3[5];
+    ULONG64 Filler4[8];
+} D3DKMTQS_SEGMENT_INFO_WIN7;
+
+typedef struct _D3DKMTQS_SEGMENT_INFO_WIN8
+{
+    ULONGLONG Filler[3];
+    struct {
+        ULONGLONG Filler;
+        ULONG Filler2[2];
+    } Filler_M;
+
+    ULONG Aperture;
+
+    ULONGLONG Filler3[5];
+    ULONG64 Filler4[8];
+} D3DKMTQS_SEGMENT_INFO_WIN8;
+
+typedef struct _D3DKMTQS_SYSTEM_MEMORY
+{
+    ULONGLONG BytesAllocated;
+    ULONG Filler[2];
+    ULONGLONG Filler2[7];
+} D3DKMTQS_SYSTEM_MEMORY;
+
+typedef struct _D3DKMTQS_PROCESS_INFO
+{
+    ULONG Filler[2];
+    struct {
+        ULONGLONG BytesAllocated;
+
+        ULONG Filler[2];
+        ULONGLONG Filler2[7];
+    } SystemMemory;
+    ULONG64 Reserved[8];
+} D3DKMTQS_PROCESS_INFO;
+
+typedef struct _D3DKMTQS_PROCESS_SEGMENT_INFO
+{
+    ULONGLONG BytesCommitted;
+
+    ULONGLONG Filler[2];
+    ULONG Filler2;
+    struct {
+        ULONG Filler;
+        D3DKMTQS_COUNTER Filler2[6];
+        ULONGLONG Filler3;
+    } Filler3;
+    struct {
+        ULONGLONG Filler;
+    } Filler4;
+    ULONG64 Reserved[8];
+} D3DKMTQS_PROCESS_SEGMENT_INFO;
+
+typedef enum _D3DKMTQS_TYPE
+{
+    D3DKMTQS_ADAPTER = 0,
+    D3DKMTQS_PROCESS = 1,
+    D3DKMTQS_SEGMENT = 3,
+    D3DKMTQS_PROCESS_SEGMENT = 4,
+} D3DKMTQS_TYPE;
+
+typedef union _D3DKMTQS_RESULT
+{
+    D3DKMTQS_ADAPTER_INFO AdapterInfo;
+    D3DKMTQS_SEGMENT_INFO_WIN7 SegmentInfoWin7;
+    D3DKMTQS_SEGMENT_INFO_WIN8 SegmentInfoWin8;
+    D3DKMTQS_PROCESS_INFO ProcessInfo;
+    D3DKMTQS_PROCESS_SEGMENT_INFO ProcessSegmentInfo;
+} D3DKMTQS_RESULT;
+
+typedef struct _D3DKMTQS_QUERY_SEGMENT
+{
+    ULONG SegmentId;
+} D3DKMTQS_QUERY_SEGMENT;
+
+typedef struct _D3DKMTQS
+{
+    __in D3DKMTQS_TYPE Type;
+    __in LUID AdapterLuid;
+    __in_opt HANDLE hProcess;
+    __out D3DKMTQS_RESULT QueryResult;
+
+    union
+    {
+        __in D3DKMTQS_QUERY_SEGMENT QuerySegment;
+        __in D3DKMTQS_QUERY_SEGMENT QueryProcessSegment;
+    };
+} D3DKMTQS;
+
+extern "C" {
+typedef __checkReturn NTSTATUS (APIENTRY *PFND3DKMTQS)(__in const D3DKMTQS *);
+}
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -48,44 +48,19 @@ using namespace mozilla::gfx;
 
 #include <d3d10_1.h>
 
 #include "mozilla/gfx/2D.h"
 
 #include "nsMemory.h"
 #endif
 
-/*
- * Required headers are not available in the current consumer preview Win8
- * dev kit, disabling for now.
- */
-#undef MOZ_WINSDK_TARGETVER
-
-/**
- * XXX below should be >= MOZ_NTDDI_WIN8 or such which is not defined yet
- */
-#if MOZ_WINSDK_TARGETVER > MOZ_NTDDI_WIN7
-#define ENABLE_GPU_MEM_REPORTER
-#endif
-
-#if defined CAIRO_HAS_D2D_SURFACE || defined ENABLE_GPU_MEM_REPORTER
 #include "nsIMemoryReporter.h"
-#endif
-
-#ifdef ENABLE_GPU_MEM_REPORTER
 #include <winternl.h>
-
-/**
- * XXX need to check that extern C is really needed with Win8 SDK.
- *     It was required for files I had available at push time.
- */
-extern "C" {
-#include <d3dkmthk.h>
-}
-#endif
+#include "d3dkmtQueryStatistics.h"
 
 using namespace mozilla;
 
 #ifdef CAIRO_HAS_D2D_SURFACE
 
 static const char *kFeatureLevelPref =
   "gfx.direct3d.last_used_feature_level_idx";
 static const int kSupportedFeatureLevels[] =
@@ -185,17 +160,16 @@ typedef HRESULT (WINAPI*D3D10CreateDevic
 );
 
 typedef HRESULT(WINAPI*CreateDXGIFactory1Func)(
   REFIID riid,
   void **ppFactory
 );
 #endif
 
-#ifdef ENABLE_GPU_MEM_REPORTER
 class GPUAdapterMultiReporter : public nsIMemoryMultiReporter {
 
     // Callers must Release the DXGIAdapter after use or risk mem-leak
     static bool GetDXGIAdapter(__out IDXGIAdapter **DXGIAdapter)
     {
         ID3D10Device1 *D2D10Device;
         IDXGIDevice *DXGIDevice;
         bool result = false;
@@ -207,94 +181,102 @@ class GPUAdapterMultiReporter : public n
             }
         }
         
         return result;
     }
     
 public:
     NS_DECL_ISUPPORTS
+
+    // nsIMemoryMultiReporter abstract method implementation
+    NS_IMETHOD
+    GetName(nsACString &aName)
+    {
+        aName.AssignLiteral("gpuadapter");
+        return NS_OK;
+    }
     
     // nsIMemoryMultiReporter abstract method implementation
     NS_IMETHOD
     CollectReports(nsIMemoryMultiReporterCallback* aCb,
                    nsISupports* aClosure)
     {
         int32_t winVers, buildNum;
         HANDLE ProcessHandle = GetCurrentProcess();
         
         int64_t dedicatedBytesUsed = 0;
         int64_t sharedBytesUsed = 0;
         int64_t committedBytesUsed = 0;
         IDXGIAdapter *DXGIAdapter;
         
         HMODULE gdi32Handle;
-        PFND3DKMT_QUERYSTATISTICS queryD3DKMTStatistics;
+        PFND3DKMTQS queryD3DKMTStatistics;
         
         winVers = gfxWindowsPlatform::WindowsOSVersion(&buildNum);
         
         // GPU memory reporting is not available before Windows 7
         if (winVers < gfxWindowsPlatform::kWindows7) 
             return NS_OK;
         
         if (gdi32Handle = LoadLibrary(TEXT("gdi32.dll")))
-            queryD3DKMTStatistics = (PFND3DKMT_QUERYSTATISTICS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics");
+            queryD3DKMTStatistics = (PFND3DKMTQS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics");
         
         if (queryD3DKMTStatistics && GetDXGIAdapter(&DXGIAdapter)) {
             // Most of this block is understood thanks to wj32's work on Process Hacker
             
             DXGI_ADAPTER_DESC adapterDesc;
-            D3DKMT_QUERYSTATISTICS queryStatistics;
+            D3DKMTQS queryStatistics;
             
             DXGIAdapter->GetDesc(&adapterDesc);
             DXGIAdapter->Release();
             
-            memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
-            queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS;
+            memset(&queryStatistics, 0, sizeof(D3DKMTQS));
+            queryStatistics.Type = D3DKMTQS_PROCESS;
             queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
             queryStatistics.hProcess = ProcessHandle;
             if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
-                committedBytesUsed = queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesAllocated;
+                committedBytesUsed = queryStatistics.QueryResult.ProcessInfo.SystemMemory.BytesAllocated;
             }
             
-            memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
-            queryStatistics.Type = D3DKMT_QUERYSTATISTICS_ADAPTER;
+            memset(&queryStatistics, 0, sizeof(D3DKMTQS));
+            queryStatistics.Type = D3DKMTQS_ADAPTER;
             queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
             if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
                 ULONG i;
-                ULONG segmentCount = queryStatistics.QueryResult.AdapterInformation.NbSegments;
+                ULONG segmentCount = queryStatistics.QueryResult.AdapterInfo.NbSegments;
                 
                 for (i = 0; i < segmentCount; i++) {
-                    memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
-                    queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT;
+                    memset(&queryStatistics, 0, sizeof(D3DKMTQS));
+                    queryStatistics.Type = D3DKMTQS_SEGMENT;
                     queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
                     queryStatistics.QuerySegment.SegmentId = i;
                     
                     if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
                         bool aperture;
                         
                         // SegmentInformation has a different definition in Win7 than later versions
-                        if (winVers > gfxWindowsPlatform::kWindows7)
-                            aperture = queryStatistics.QueryResult.SegmentInformation.Aperture;
+                        if (winVers < gfxWindowsPlatform::kWindows8)
+                            aperture = queryStatistics.QueryResult.SegmentInfoWin7.Aperture;
                         else
-                            aperture = queryStatistics.QueryResult.SegmentInformationV1.Aperture;
+                            aperture = queryStatistics.QueryResult.SegmentInfoWin8.Aperture;
                         
-                        memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
-                        queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT;
+                        memset(&queryStatistics, 0, sizeof(D3DKMTQS));
+                        queryStatistics.Type = D3DKMTQS_PROCESS_SEGMENT;
                         queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
                         queryStatistics.hProcess = ProcessHandle;
                         queryStatistics.QueryProcessSegment.SegmentId = i;
                         if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
                             if (aperture)
                                 sharedBytesUsed += queryStatistics.QueryResult
-                                                                  .ProcessSegmentInformation
+                                                                  .ProcessSegmentInfo
                                                                   .BytesCommitted;
                             else
                                 dedicatedBytesUsed += queryStatistics.QueryResult
-                                                                     .ProcessSegmentInformation
+                                                                     .ProcessSegmentInfo
                                                                      .BytesCommitted;
                         }
                     }
                 }
             }
         }
         
         FreeLibrary(gdi32Handle);
@@ -320,17 +302,16 @@ public:
                "In-process memory that is shared with the GPU.");
         
 #undef REPORT
 
         return NS_OK;
     }
 };
 NS_IMPL_ISUPPORTS1(GPUAdapterMultiReporter, nsIMemoryMultiReporter)
-#endif // ENABLE_GPU_MEM_REPORTER
 
 static __inline void
 BuildKeyNameFromFontName(nsAString &aName)
 {
     if (aName.Length() >= LF_FACESIZE)
         aName.Truncate(LF_FACESIZE - 1);
     ToLowerCase(aName);
 }
@@ -356,27 +337,23 @@ gfxWindowsPlatform::gfxWindowsPlatform()
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(D2DVram));
     mD2DDevice = nullptr;
 #endif
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(D2DVRAMDT));
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(D2DVRAMSS));
 
     UpdateRenderMode();
 
-#ifdef ENABLE_GPU_MEM_REPORTER
     mGPUAdapterMultiReporter = new GPUAdapterMultiReporter();
     NS_RegisterMemoryMultiReporter(mGPUAdapterMultiReporter);
-#endif
 }
 
 gfxWindowsPlatform::~gfxWindowsPlatform()
 {
-#ifdef ENABLE_GPU_MEM_REPORTER
     NS_UnregisterMemoryMultiReporter(mGPUAdapterMultiReporter);
-#endif
     
     ::ReleaseDC(NULL, mScreenDC);
     // not calling FT_Done_FreeType because cairo may still hold references to
     // these FT_Faces.  See bug 458169.
 #ifdef CAIRO_HAS_D2D_SURFACE
     if (mD2DDevice) {
         cairo_release_device(mD2DDevice);
     }
--- a/js/src/aclocal.m4
+++ b/js/src/aclocal.m4
@@ -3,16 +3,17 @@ dnl Local autoconf macros used with mozi
 dnl The contents of this file are under the Public Domain.
 dnl
 
 builtin(include, build/autoconf/acwinpaths.m4)dnl
 builtin(include, build/autoconf/hooks.m4)dnl
 builtin(include, build/autoconf/config.status.m4)dnl
 builtin(include, build/autoconf/toolchain.m4)dnl
 builtin(include, build/autoconf/ccache.m4)dnl
+builtin(include, build/autoconf/wrapper.m4)dnl
 builtin(include, build/autoconf/pkg.m4)dnl
 builtin(include, build/autoconf/nspr.m4)dnl
 builtin(include, build/autoconf/altoptions.m4)dnl
 builtin(include, build/autoconf/moznbytetype.m4)dnl
 builtin(include, build/autoconf/mozprog.m4)dnl
 builtin(include, build/autoconf/mozheader.m4)dnl
 builtin(include, build/autoconf/mozcommonheader.m4)dnl
 builtin(include, build/autoconf/lto.m4)dnl
new file mode 100644
--- /dev/null
+++ b/js/src/build/autoconf/wrapper.m4
@@ -0,0 +1,22 @@
+dnl This Source Code Form is subject to the terms of the Mozilla Public
+dnl License, v. 2.0. If a copy of the MPL was not distributed with this
+dnl file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+dnl =======================================================================
+dnl = Enable compiling with various compiler wrappers (distcc, ccache, etc)
+dnl =======================================================================
+AC_DEFUN([MOZ_CHECK_COMPILER_WRAPPER],
+[
+MOZ_ARG_WITH_STRING(compiler_wrapper,
+[  --with-compiler-wrapper[=path/to/wrapper]
+    Enable compiling with wrappers such as distcc and ccache],
+    COMPILER_WRAPPER=$withval, COMPILER_WRAPPER="no")
+
+if test "$COMPILER_WRAPPER" != "no"; then
+    CC="$COMPILER_WRAPPER $CC"
+    CXX="$COMPILER_WRAPPER $CXX"
+    MOZ_USING_COMPILER_WRAPPER=1
+fi
+
+AC_SUBST(MOZ_USING_COMPILER_WRAPPER)
+])
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -3762,16 +3762,17 @@ MOZ_ARG_ENABLE_BOOL(oom-backtrace,
                           Enable output of backtraces on artificial OOMs (-A)],
     JS_OOM_DO_BACKTRACES=1,
     JS_OOM_DO_BACKTRACES= )
 if test -n "$JS_OOM_DO_BACKTRACES"; then
     AC_DEFINE(JS_OOM_DO_BACKTRACES)
 fi
 
 MOZ_CHECK_CCACHE
+MOZ_CHECK_COMPILER_WRAPPER
 
 dnl ========================================================
 dnl = Enable static checking using gcc-dehydra
 dnl ========================================================
 
 MOZ_ARG_WITH_STRING(static-checking,
 [  --with-static-checking=path/to/gcc_dehydra.so
                           Enable static checking of code using GCC-dehydra],
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -1,24 +1,23 @@
 /* -*- Mode: Javascript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
 "use strict";
 
+// Ignore calls made through these function pointers
 var ignoreIndirectCalls = {
     "mallocSizeOf" : true,
     "aMallocSizeOf" : true,
     "_malloc_message" : true,
     "__conv" : true,
     "__convf" : true,
     "prerrortable.c:callback_newtable" : true,
     "mozalloc_oom.cpp:void (* gAbortHandler)(size_t)" : true,
-    "JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoAssertNoGC instead
 };
 
-
 function indirectCallCannotGC(caller, name)
 {
     if (name in ignoreIndirectCalls)
         return true;
 
     if (name == "mapper" && caller == "ptio.c:pt_MapError")
         return true;
 
@@ -27,28 +26,30 @@ function indirectCallCannotGC(caller, na
 
     // hook called during script finalization which cannot GC.
     if (/CallDestroyScriptHook/.test(caller))
         return true;
 
     return false;
 }
 
-// classes to ignore indirect calls on.
+// Ignore calls through functions pointers with these types
 var ignoreClasses = {
     "JSTracer" : true,
     "JSStringFinalizer" : true,
     "SprintfStateStr" : true,
     "JSLocaleCallbacks" : true,
     "JSC::ExecutableAllocator" : true,
     "PRIOMethods": true,
     "XPCOMFunctions" : true, // I'm a little unsure of this one
     "_MD_IOVector" : true,
 };
 
+// Ignore calls through TYPE.FIELD, where TYPE is the class or struct name containing
+// a function pointer field named FIELD.
 var ignoreCallees = {
     "js::Class.trace" : true,
     "js::Class.finalize" : true,
     "JSRuntime.destroyPrincipals" : true,
     "nsISupports.AddRef" : true,
     "nsISupports.Release" : true, // makes me a bit nervous; this is a bug but can happen
     "nsAXPCNativeCallContext.GetJSContext" : true,
     "js::ion::MDefinition.op" : true, // macro generated virtuals just return a constant
@@ -91,21 +92,23 @@ function ignoreEdgeUse(edge, variable)
             if (/~DebugOnly/.test(name))
                 return true;
         }
     }
 
     return false;
 }
 
+// Ignore calls of these functions (so ignore any stack containing these)
 var ignoreFunctions = {
     "ptio.c:pt_MapError" : true,
     "PR_ExplodeTime" : true,
     "PR_ErrorInstallTable" : true,
-    "PR_SetThreadPrivate" : true
+    "PR_SetThreadPrivate" : true,
+    "JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoAssertNoGC instead
 };
 
 function ignoreGCFunction(fun)
 {
     if (fun in ignoreFunctions)
         return true;
 
     // Templatized function
--- a/js/src/vm/ParallelDo.cpp
+++ b/js/src/vm/ParallelDo.cpp
@@ -399,18 +399,18 @@ class ParallelIonInvoke
         // Find JIT code pointer.
         IonScript *ion = callee->nonLazyScript()->parallelIonScript();
         IonCode *code = ion->method();
         jitcode_ = code->raw();
         enter_ = cx->compartment->ionCompartment()->enterJIT();
         calleeToken_ = CalleeToParallelToken(callee);
     }
 
-    bool invoke(JSContext *cx) {
-        RootedValue result(cx);
+    bool invoke() {
+        RootedValue result(TlsPerThreadData.get());
         enter_(jitcode_, argc_ + 1, argv_ + 1, NULL, calleeToken_, NULL, 0, result.address());
         return !result.isMagic();
     }
 };
 #endif // JS_ION
 
 class ParallelDo : public ForkJoinOp
 {
@@ -482,27 +482,27 @@ class ParallelDo : public ForkJoinOp
         return SpewEndOp(disqualifyFromParallelExecution());
     }
 
     MethodStatus compileForParallelExecution() {
         // The kernel should be a self-hosted function.
         if (!fun_->isFunction())
             return Method_Skipped;
 
-        RootedFunction callee(cx_, fun_->toFunction());
+        RootedFunction callee(TlsPerThreadData.get(), fun_->toFunction());
 
         if (!callee->isInterpreted() || !callee->isSelfHostedBuiltin())
             return Method_Skipped;
 
         if (callee->isInterpretedLazy() && !callee->initializeLazyScript(cx_))
             return Method_Error;
 
         // If this function has not been run enough to enable parallel
         // execution, perform a warmup.
-        RootedScript script(cx_, callee->nonLazyScript());
+        RootedScript script(TlsPerThreadData.get(), callee->nonLazyScript());
         if (script->getUseCount() < js_IonOptions.usesBeforeCompileParallel) {
             if (!warmupForParallelExecution())
                 return Method_Error;
         }
 
         if (script->hasParallelIonScript() &&
             !script->parallelIonScript()->hasInvalidatedCallTarget())
         {
@@ -532,17 +532,17 @@ class ParallelDo : public ForkJoinOp
 
     ExecutionStatus disqualifyFromParallelExecution() {
         if (!executeSequentially())
             return ExecutionFatal;
         return ExecutionSequential;
     }
 
     bool invalidateBailedOutScripts() {
-        RootedScript script(cx_, fun_->toFunction()->nonLazyScript());
+        RootedScript script(TlsPerThreadData.get(), fun_->toFunction()->nonLazyScript());
 
         // Sometimes the script is collected or invalidated already,
         // for example when a full GC runs at an inconvenient time.
         if (!script->hasParallelIonScript()) {
             JS_ASSERT(hasNoPendingInvalidations());
             return true;
         }
 
@@ -563,17 +563,17 @@ class ParallelDo : public ForkJoinOp
     bool warmupForParallelExecution() {
         AutoEnterWarmup warmup(cx_->runtime);
         return executeSequentially();
     }
 #endif // JS_ION
 
     bool executeSequentially() {
         uint32_t numSlices = ForkJoinSlices(cx_);
-        RootedValue funVal(cx_, ObjectValue(*fun_));
+        RootedValue funVal(TlsPerThreadData.get(), ObjectValue(*fun_));
         FastInvokeGuard fig(cx_, funVal);
         for (uint32_t i = 0; i < numSlices; i++) {
             InvokeArgsGuard &args = fig.args();
             if (!args.pushed() && !cx_->stack.pushInvokeArgs(cx_, 3, &args))
                 return false;
             args.setCallee(funVal);
             args.setThis(UndefinedValue());
             args[0].setInt32(i);
@@ -594,33 +594,33 @@ class ParallelDo : public ForkJoinOp
 
         // Make a new IonContext for the slice, which is needed if we need to
         // re-enter the VM.
         IonContext icx(cx_, NULL);
 
         JS_ASSERT(pendingInvalidations[slice.sliceId] == NULL);
 
         JS_ASSERT(fun_->isFunction());
-        RootedFunction callee(cx_, fun_->toFunction());
+        RootedFunction callee(TlsPerThreadData.get(), fun_->toFunction());
         if (!callee->nonLazyScript()->hasParallelIonScript()) {
             // Sometimes, particularly with GCZeal, the parallel ion
             // script can be collected between starting the parallel
             // op and reaching this point.  In that case, we just fail
             // and fallback.
             Spew(SpewOps, "Down (Script no longer present)");
             return false;
         }
 
         ParallelIonInvoke<3> fii(cx_, callee, 3);
 
         fii.args[0] = Int32Value(slice.sliceId);
         fii.args[1] = Int32Value(slice.numSlices);
         fii.args[2] = BooleanValue(false);
 
-        bool ok = fii.invoke(cx_);
+        bool ok = fii.invoke();
         JS_ASSERT(ok == !slice.abortedScript);
         if (!ok) {
             JSScript *script = slice.abortedScript;
             Spew(SpewBailouts, "Aborted script: %p (hasParallelIonScript? %d)",
                  script, script->hasParallelIonScript());
             JS_ASSERT(script->hasParallelIonScript());
             pendingInvalidations[slice.sliceId] = script;
         }
@@ -649,24 +649,24 @@ class ParallelDo : public ForkJoinOp
 };
 
 bool
 js::parallel::Do(JSContext *cx, CallArgs &args)
 {
     JS_ASSERT(args[0].isObject());
     JS_ASSERT(args[0].toObject().isFunction());
 
-    RootedObject fun(cx, &args[0].toObject());
+    RootedObject fun(TlsPerThreadData.get(), &args[0].toObject());
     ParallelDo op(cx, fun);
     ExecutionStatus status = op.apply();
     if (status == ExecutionFatal)
         return false;
 
     if (args[1].isObject()) {
-        RootedObject feedback(cx, &args[1].toObject());
+        RootedObject feedback(TlsPerThreadData.get(), &args[1].toObject());
         if (feedback && feedback->isFunction()) {
             InvokeArgsGuard feedbackArgs;
             if (!cx->stack.pushInvokeArgs(cx, 1, &feedbackArgs))
                 return false;
             feedbackArgs.setCallee(ObjectValue(*feedback));
             feedbackArgs.setThis(UndefinedValue());
             if (status == ExecutionParallel)
                 feedbackArgs[0].setInt32(op.bailouts);
--- a/js/xpconnect/public/nsTArrayHelpers.h
+++ b/js/xpconnect/public/nsTArrayHelpers.h
@@ -14,17 +14,17 @@ nsTArrayToJSArray(JSContext* aCx, const 
   JSAutoRequest ar(aCx);
 
   JSObject* arrayObj = JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr);
   if (!arrayObj) {
     NS_WARNING("JS_NewArrayObject failed!");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  JSObject* global = JS_GetGlobalForScopeChain(aCx);
+  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
   MOZ_ASSERT(global);
 
   for (uint32_t index = 0; index < aSourceArray.Length(); index++) {
     nsCOMPtr<nsISupports> obj;
     nsresult rv = aSourceArray[index]->QueryInterface(NS_GET_IID(nsISupports), getter_AddRefs(obj));
     NS_ENSURE_SUCCESS(rv, rv);
 
     jsval wrappedVal;
--- a/js/xpconnect/src/XPCJSWeakReference.cpp
+++ b/js/xpconnect/src/XPCJSWeakReference.cpp
@@ -67,17 +67,18 @@ xpcJSWeakReference::Get(JSContext* aCx, 
     if (!supports) {
         return NS_OK;
     }
 
     nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(supports);
     if (!wrappedObj) {
         // We have a generic XPCOM object that supports weak references here.
         // Wrap it and pass it out.
-        return nsContentUtils::WrapNative(aCx, JS_GetGlobalForScopeChain(aCx),
+        JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForScopeChain(aCx));
+        return nsContentUtils::WrapNative(aCx, global,
                                           supports, &NS_GET_IID(nsISupports),
                                           aRetval);
     }
 
     JS::RootedObject obj(aCx);
     wrappedObj->GetJSObject(obj.address());
     if (!obj) {
         return NS_OK;
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -95,20 +95,16 @@ members = [
     # layout/xul/base/public
     'nsIBoxObject.x',
     'nsIBoxObject.y',
     'nsIBoxObject.screenX',
     'nsIBoxObject.screenY',
     'nsIBoxObject.width',
     'nsIBoxObject.height',
 
-    # Audio
-    'nsIDOMNotifyAudioAvailableEvent.frameBuffer',
-    'nsIDOMNotifyAudioAvailableEvent.time',
-
     # dom/indexedDB
     'nsIIDBCursor.*',
     'nsIIDBCursorWithValue.*',
     'nsIIDBDatabase.*',
     'nsIIDBFileHandle.*',
     'nsIIDBIndex.*',
     'nsIIDBKeyRange.*',
     'nsIIDBObjectStore.*',
--- a/layout/generic/ScrollbarActivity.cpp
+++ b/layout/generic/ScrollbarActivity.cpp
@@ -1,43 +1,268 @@
 /* -*- Mode: C++; 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/. */
 
 #include "ScrollbarActivity.h"
-#include "nsContentUtils.h"
+#include "nsIScrollbarOwner.h"
+#include "nsIDOMEvent.h"
+#include "nsIDOMNSEvent.h"
+#include "nsIDOMElementCSSInlineStyle.h"
+#include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIFrame.h"
-#include "nsIScrollableFrame.h"
+#include "nsContentUtils.h"
+#include "nsAString.h"
+#include "nsQueryFrame.h"
 #include "nsComponentManagerUtils.h"
 
 namespace mozilla {
+namespace layout {
 
-ScrollbarActivity::~ScrollbarActivity()
+NS_IMPL_ISUPPORTS1(ScrollbarActivity, nsIDOMEventListener)
+
+void
+ScrollbarActivity::Destroy()
 {
-  CancelActivityFinishedTimer();
+  StopListeningForEvents();
+  UnregisterFromRefreshDriver();
+  CancelFadeBeginTimer();
 }
 
 void
 ScrollbarActivity::ActivityOccurred()
 {
-  CancelActivityFinishedTimer();
-  StartActivityFinishedTimer();
+  ActivityStarted();
+  ActivityStopped();
+}
+
+void
+ScrollbarActivity::ActivityStarted()
+{
+  mNestedActivityCounter++;
+  CancelFadeBeginTimer();
+  SetIsFading(false);
+  UnregisterFromRefreshDriver();
+  StartListeningForEvents();
+  SetIsActive(true);
+
+  NS_ASSERTION(mIsActive, "need to be active during activity");
+  NS_ASSERTION(!mIsFading, "must not be fading during activity");
+  NS_ASSERTION(!mFadeBeginTimer, "fade begin timer shouldn't be running");
+}
+
+void
+ScrollbarActivity::ActivityStopped()
+{
+  NS_ASSERTION(IsActivityOngoing(), "activity stopped while none was going on");
+  NS_ASSERTION(mIsActive, "need to be active during activity");
+  NS_ASSERTION(!mIsFading, "must not be fading during ongoing activity");
+  NS_ASSERTION(!mFadeBeginTimer, "must not be waiting for fade during ongoing activity");
+
+  mNestedActivityCounter--;
+
+  if (!IsActivityOngoing()) {
+    StartFadeBeginTimer();
+
+    NS_ASSERTION(mIsActive, "need to be active right after activity");
+    NS_ASSERTION(!mIsFading, "must not be fading right after activity");
+    NS_ASSERTION(mFadeBeginTimer, "fade begin timer should be running");
+  }
+}
 
-  SetIsActive(true);
-  NS_ASSERTION(mIsActive, "need to be active during activity");
+NS_IMETHODIMP
+ScrollbarActivity::HandleEvent(nsIDOMEvent* aEvent)
+{
+  if (!mIsActive)
+    return NS_OK;
+
+  nsAutoString type;
+  aEvent->GetType(type);
+
+  if (type.EqualsLiteral("mousemove")) {
+    // Mouse motions anywhere in the scrollable frame should keep the
+    // scrollbars visible.
+    ActivityOccurred();
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDOMEventTarget> target;
+  aEvent->GetOriginalTarget(getter_AddRefs(target));
+  nsCOMPtr<nsIContent> targetContent = do_QueryInterface(target);
+
+  HandleEventForScrollbar(type, targetContent, GetHorizontalScrollbar(),
+                          &mHScrollbarHovered);
+  HandleEventForScrollbar(type, targetContent, GetVerticalScrollbar(),
+                          &mVScrollbarHovered);
+
+  return NS_OK;
+}
+
+void
+ScrollbarActivity::WillRefresh(TimeStamp aTime)
+{
+  NS_ASSERTION(mIsActive, "should only fade while scrollbars are visible");
+  NS_ASSERTION(!IsActivityOngoing(), "why weren't we unregistered from the refresh driver when scrollbar activity started?");
+  NS_ASSERTION(mIsFading, "should only animate fading during fade");
+
+  UpdateOpacity(aTime);
+
+  if (!IsStillFading(aTime)) {
+    EndFade();
+  }
+}
+
+bool
+ScrollbarActivity::IsStillFading(TimeStamp aTime)
+{
+  return !mFadeBeginTime.IsNull() && (aTime - mFadeBeginTime < FadeDuration());
 }
 
 void
-ScrollbarActivity::ActivityFinished()
+ScrollbarActivity::HandleEventForScrollbar(const nsAString& aType,
+                                           nsIContent* aTarget,
+                                           nsIContent* aScrollbar,
+                                           bool* aStoredHoverState)
 {
-  SetIsActive(false);
-  NS_ASSERTION(!mIsActive, "need to be unactive once activity is finished");
+  if (!aTarget || !aScrollbar ||
+      !nsContentUtils::ContentIsDescendantOf(aTarget, aScrollbar))
+    return;
+
+  if (aType.EqualsLiteral("mousedown")) {
+    ActivityStarted();
+  } else if (aType.EqualsLiteral("mouseup")) {
+    ActivityStopped();
+  } else if (aType.EqualsLiteral("mouseover") ||
+             aType.EqualsLiteral("mouseout")) {
+    bool newHoveredState = aType.EqualsLiteral("mouseover");
+    if (newHoveredState && !*aStoredHoverState) {
+      ActivityStarted();
+      HoveredScrollbar(aScrollbar);
+    } else if (*aStoredHoverState && !newHoveredState) {
+      ActivityStopped();
+      // Don't call HoveredScrollbar(nullptr) here because we want the hover
+      // attribute to stick until the scrollbars are hidden.
+    }
+    *aStoredHoverState = newHoveredState;
+  }
+}
+
+void
+ScrollbarActivity::StartListeningForEvents()
+{
+  if (mListeningForEvents)
+    return;
+
+  nsIFrame* scrollArea = do_QueryFrame(mScrollableFrame);
+  nsCOMPtr<nsIDOMEventTarget> scrollAreaTarget = do_QueryInterface(
+                                                   scrollArea->GetContent());
+  mHorizontalScrollbar = do_QueryInterface(GetHorizontalScrollbar());
+  mVerticalScrollbar = do_QueryInterface(GetVerticalScrollbar());
+
+  if (scrollAreaTarget) {
+    scrollAreaTarget->AddEventListener(NS_LITERAL_STRING("mousemove"), this,
+                                       true);
+  }
+  StartListeningForEventsOnScrollbar(mHorizontalScrollbar);
+  StartListeningForEventsOnScrollbar(mVerticalScrollbar);
+  mListeningForEvents = true;
+}
+
+void
+ScrollbarActivity::StartListeningForEventsOnScrollbar(nsIDOMEventTarget* aScrollbar)
+{
+  if (aScrollbar) {
+    aScrollbar->AddEventListener(NS_LITERAL_STRING("mousedown"), this, true);
+    aScrollbar->AddEventListener(NS_LITERAL_STRING("mouseup"), this, true);
+    aScrollbar->AddEventListener(NS_LITERAL_STRING("mouseover"), this, true);
+    aScrollbar->AddEventListener(NS_LITERAL_STRING("mouseout"), this, true);
+  }
 }
 
+void
+ScrollbarActivity::StopListeningForEvents()
+{
+  if (!mListeningForEvents)
+    return;
+
+  nsIFrame* scrollArea = do_QueryFrame(mScrollableFrame);
+  nsCOMPtr<nsIDOMEventTarget> scrollAreaTarget = do_QueryInterface(scrollArea->GetContent());
+
+  if (scrollAreaTarget) {
+    scrollAreaTarget->RemoveEventListener(NS_LITERAL_STRING("mousemove"), this, true);
+  }
+  StopListeningForEventsOnScrollbar(mHorizontalScrollbar);
+  StopListeningForEventsOnScrollbar(mVerticalScrollbar);
+
+  mHorizontalScrollbar = nullptr;
+  mVerticalScrollbar = nullptr;
+  mListeningForEvents = false;
+}
+
+void
+ScrollbarActivity::StopListeningForEventsOnScrollbar(nsIDOMEventTarget* aScrollbar)
+{
+  if (aScrollbar) {
+    aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, true);
+    aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mouseup"), this, true);
+    aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mouseover"), this, true);
+    aScrollbar->RemoveEventListener(NS_LITERAL_STRING("mouseout"), this, true);
+  }
+}
+
+void
+ScrollbarActivity::BeginFade()
+{
+  NS_ASSERTION(mIsActive, "can't begin fade when we're already inactive");
+  NS_ASSERTION(!IsActivityOngoing(), "why wasn't the fade begin timer cancelled when scrollbar activity started?");
+  NS_ASSERTION(!mIsFading, "shouldn't be fading just yet");
+
+  CancelFadeBeginTimer();
+  mFadeBeginTime = TimeStamp::Now();
+  SetIsFading(true);
+  RegisterWithRefreshDriver();
+
+  NS_ASSERTION(mIsActive, "only fade while scrollbars are visible");
+  NS_ASSERTION(mIsFading, "should be fading now");
+}
+
+void
+ScrollbarActivity::EndFade()
+{
+  NS_ASSERTION(mIsActive, "still need to be active at this point");
+  NS_ASSERTION(!IsActivityOngoing(), "why wasn't the fade end timer cancelled when scrollbar activity started?");
+
+  SetIsFading(false);
+  SetIsActive(false);
+  UnregisterFromRefreshDriver();
+  StopListeningForEvents();
+
+  NS_ASSERTION(!mIsActive, "should have gone inactive after fade end");
+  NS_ASSERTION(!mIsFading, "shouldn't be fading anymore");
+  NS_ASSERTION(!mFadeBeginTimer, "fade begin timer shouldn't be running");
+}
+
+void
+ScrollbarActivity::RegisterWithRefreshDriver()
+{
+  nsRefreshDriver* refreshDriver = GetRefreshDriver();
+  if (refreshDriver) {
+    refreshDriver->AddRefreshObserver(this, Flush_Style);
+  }
+}
+
+void
+ScrollbarActivity::UnregisterFromRefreshDriver()
+{
+  nsRefreshDriver* refreshDriver = GetRefreshDriver();
+  if (refreshDriver) {
+    refreshDriver->RemoveRefreshObserver(this, Flush_Style);
+  }
+}
 
 static void
 SetBooleanAttribute(nsIContent* aContent, nsIAtom* aAttribute, bool aValue)
 {
   if (aContent) {
     if (aValue) {
       aContent->SetAttr(kNameSpaceID_None, aAttribute,
                         NS_LITERAL_STRING("true"), true);
@@ -47,43 +272,119 @@ SetBooleanAttribute(nsIContent* aContent
   }
 }
 
 void
 ScrollbarActivity::SetIsActive(bool aNewActive)
 {
   if (mIsActive == aNewActive)
     return;
+
   mIsActive = aNewActive;
+  if (!mIsActive) {
+    // Clear sticky scrollbar hover status.
+    HoveredScrollbar(nullptr);
+  }
 
   SetBooleanAttribute(GetHorizontalScrollbar(), nsGkAtoms::active, mIsActive);
   SetBooleanAttribute(GetVerticalScrollbar(), nsGkAtoms::active, mIsActive);
 }
 
+static void
+SetOpacityOnElement(nsIContent* aContent, double aOpacity)
+{
+  nsCOMPtr<nsIDOMElementCSSInlineStyle> inlineStyleContent =
+    do_QueryInterface(aContent);
+  if (inlineStyleContent) {
+    nsCOMPtr<nsIDOMCSSStyleDeclaration> decl;
+    inlineStyleContent->GetStyle(getter_AddRefs(decl));
+    if (decl) {
+      nsAutoString str;
+      str.AppendFloat(aOpacity);
+      decl->SetProperty(NS_LITERAL_STRING("opacity"), str, EmptyString());
+    }
+  }
+}
+
 void
-ScrollbarActivity::StartActivityFinishedTimer()
+ScrollbarActivity::UpdateOpacity(TimeStamp aTime)
 {
-  NS_ASSERTION(!mActivityFinishedTimer, "timer already alive!");
-  mActivityFinishedTimer = do_CreateInstance("@mozilla.org/timer;1");
-  mActivityFinishedTimer->InitWithFuncCallback(ActivityFinishedTimerFired, this,
-                                            kScrollbarActivityFinishedDelay,
-                                            nsITimer::TYPE_ONE_SHOT);
+  double progress = (aTime - mFadeBeginTime) / FadeDuration();
+  double opacity = 1.0 - std::max(0.0, std::min(1.0, progress));
+  SetOpacityOnElement(GetHorizontalScrollbar(), opacity);
+  SetOpacityOnElement(GetVerticalScrollbar(), opacity);
+}
+
+static void
+UnsetOpacityOnElement(nsIContent* aContent)
+{
+  nsCOMPtr<nsIDOMElementCSSInlineStyle> inlineStyleContent =
+    do_QueryInterface(aContent);
+  if (inlineStyleContent) {
+    nsCOMPtr<nsIDOMCSSStyleDeclaration> decl;
+    inlineStyleContent->GetStyle(getter_AddRefs(decl));
+    if (decl) {
+      nsAutoString dummy;
+      decl->RemoveProperty(NS_LITERAL_STRING("opacity"), dummy);
+    }
+  }
 }
 
 void
-ScrollbarActivity::CancelActivityFinishedTimer()
+ScrollbarActivity::SetIsFading(bool aNewFading)
+{
+  if (mIsFading == aNewFading)
+    return;
+
+  mIsFading = aNewFading;
+  if (!mIsFading) {
+    mFadeBeginTime = TimeStamp();
+    UnsetOpacityOnElement(GetHorizontalScrollbar());
+    UnsetOpacityOnElement(GetVerticalScrollbar());
+  }
+}
+
+void
+ScrollbarActivity::StartFadeBeginTimer()
 {
-  if (mActivityFinishedTimer) {
-    mActivityFinishedTimer->Cancel();
-    mActivityFinishedTimer = nullptr;
+  NS_ASSERTION(!mFadeBeginTimer, "timer already alive!");
+  mFadeBeginTimer = do_CreateInstance("@mozilla.org/timer;1");
+  mFadeBeginTimer->InitWithFuncCallback(FadeBeginTimerFired, this,
+                                        kScrollbarFadeBeginDelay,
+                                        nsITimer::TYPE_ONE_SHOT);
+}
+
+void
+ScrollbarActivity::CancelFadeBeginTimer()
+{
+  if (mFadeBeginTimer) {
+    mFadeBeginTimer->Cancel();
+    mFadeBeginTimer = nullptr;
   }
 }
 
+void
+ScrollbarActivity::HoveredScrollbar(nsIContent* aScrollbar)
+{
+  SetBooleanAttribute(GetHorizontalScrollbar(), nsGkAtoms::hover, false);
+  SetBooleanAttribute(GetVerticalScrollbar(), nsGkAtoms::hover, false);
+  SetBooleanAttribute(aScrollbar, nsGkAtoms::hover, true);
+}
+
+nsRefreshDriver*
+ScrollbarActivity::GetRefreshDriver()
+{
+  nsIFrame* box = mScrollableFrame->GetScrollbarBox(false);
+  if (!box) {
+    box = mScrollableFrame->GetScrollbarBox(true);
+  }
+  return box ? box->PresContext()->RefreshDriver() : nullptr;
+}
+
 nsIContent*
 ScrollbarActivity::GetScrollbarContent(bool aVertical)
 {
   nsIFrame* box = mScrollableFrame->GetScrollbarBox(aVertical);
   return box ? box->GetContent() : nullptr;
-
-  return nullptr;
 }
 
+} // namespace layout
 } // namespace mozilla
--- a/layout/generic/ScrollbarActivity.h
+++ b/layout/generic/ScrollbarActivity.h
@@ -2,87 +2,143 @@
 /* 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 ScrollbarActivity_h___
 #define ScrollbarActivity_h___
 
 #include "nsCOMPtr.h"
+#include "nsIDOMEventListener.h"
 #include "mozilla/TimeStamp.h"
+#include "nsRefreshDriver.h"
 
 class nsIContent;
+class nsIScrollbarOwner;
 class nsITimer;
 class nsIAtom;
-class nsIScrollableFrame;
 
 namespace mozilla {
+namespace layout {
 
 /**
  * ScrollbarActivity
  *
- * This class manages scrollbar active state. When some activity occured
- * the 'active' attribute of the both the horizontal scrollbar and vertical
- * scrollbar is set.
- * After a small amount of time of inactivity this attribute is unset from
- * both scrollbars.
- * Some css specific rules can affect the scrollbar, like showing/hiding it
- * with a fade transition.
+ * This class manages scrollbar behavior that imitates the native Mac OS X
+ * Lion overlay scrollbar behavior: Scrollbars are only shown while "scrollbar
+ * activity" occurs, and they're hidden with a fade animation after a short
+ * delay.
  *
- * Initial scrollbar activity needs to be reported by the scrollbar frame that
+ * Scrollbar activity has these states:
+ *  - inactive:
+ *      Scrollbars are hidden.
+ *  - ongoing activity:
+ *      Scrollbars are visible and being operated on in some way, for example
+ *      because they're hovered or pressed.
+ *  - active, but waiting for fade out
+ *      Scrollbars are still completely visible but are about to fade away.
+ *  - fading out
+ *      Scrollbars are subject to a fade-out animation.
+ *
+ * Initial scrollbar activity needs to be reported by the scrollbar holder that
  * owns the ScrollbarActivity instance. This needs to happen via a call to
  * ActivityOccurred(), for example when the current scroll position or the size
  * of the scroll area changes.
  *
- * ScrollbarActivity then wait until a timeout has expired or a new call to
- * ActivityOccured() has been made. When the timeout expires ActivityFinished()
- * is call and reset the active state.
+ * As soon as scrollbars are visible, the ScrollbarActivity class manages the
+ * rest of the activity behavior: It ensures that mouse motions inside the
+ * scroll area keep the scrollbars visible, and that scrollbars don't fade away
+ * while they're being hovered / dragged. It also sets a sticky hover attribute
+ * on the most recently hovered scrollbar.
+ *
+ * ScrollbarActivity falls into hibernation after the scrollbars have faded
+ * out. It only starts acting after the next call to ActivityOccurred() /
+ * ActivityStarted().
  */
 
-class ScrollbarActivity {
+class ScrollbarActivity : public nsIDOMEventListener,
+                          public nsARefreshObserver {
 public:
-  ScrollbarActivity(nsIScrollableFrame* aScrollableFrame)
-   : mIsActive(false)
-   , mScrollableFrame(aScrollableFrame)
+  ScrollbarActivity(nsIScrollbarOwner* aScrollableFrame)
+   : mScrollableFrame(aScrollableFrame)
+   , mNestedActivityCounter(0)
+   , mIsActive(false)
+   , mIsFading(false)
+   , mListeningForEvents(false)
+   , mHScrollbarHovered(false)
+   , mVScrollbarHovered(false)
   {}
 
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOMEVENTLISTENER
+
+  virtual ~ScrollbarActivity() {}
+
+  void Destroy();
+
   void ActivityOccurred();
-  void ActivityFinished();
-  ~ScrollbarActivity();
+  void ActivityStarted();
+  void ActivityStopped();
+
+  virtual void WillRefresh(TimeStamp aTime);
+
+  static void FadeBeginTimerFired(nsITimer* aTimer, void* aSelf) {
+    reinterpret_cast<ScrollbarActivity*>(aSelf)->BeginFade();
+  }
+
+  static const uint32_t kScrollbarFadeBeginDelay = 450; // milliseconds
+  static const uint32_t kScrollbarFadeDuration = 200; // milliseconds
 
 protected:
-  /*
-   * mIsActive is true once any type of activity occurent on the scrollable
-   * frame and until kScrollbarActivityFinishedDelay has expired.
-   * This does not reflect the value of the 'active' attributes on scrollbars.
-   */
-  bool mIsActive;
+
+  bool IsActivityOngoing()
+  { return mNestedActivityCounter > 0; }
+  bool IsStillFading(TimeStamp aTime);
 
-  /*
-   * Hold a reference to the scrollable frame in order to retrieve the
-   * horizontal and vertical scrollbar boxes where to set the 'active'
-   * attribute.
-   */
-  nsIScrollableFrame* mScrollableFrame;
-
-  nsCOMPtr<nsITimer> mActivityFinishedTimer;
+  void HandleEventForScrollbar(const nsAString& aType,
+                               nsIContent* aTarget,
+                               nsIContent* aScrollbar,
+                               bool* aStoredHoverState);
 
   void SetIsActive(bool aNewActive);
+  void SetIsFading(bool aNewFading);
 
-  enum { kScrollbarActivityFinishedDelay = 450 }; // milliseconds
-  static void ActivityFinishedTimerFired(nsITimer* aTimer, void* aSelf) {
-    reinterpret_cast<ScrollbarActivity*>(aSelf)->ActivityFinished();
-  }
-  void StartActivityFinishedTimer();
-  void CancelActivityFinishedTimer();
+  void BeginFade();
+  void EndFade();
+
+  void StartFadeBeginTimer();
+  void CancelFadeBeginTimer();
+  void StartListeningForEvents();
+  void StartListeningForEventsOnScrollbar(nsIDOMEventTarget* aScrollbar);
+  void StopListeningForEvents();
+  void StopListeningForEventsOnScrollbar(nsIDOMEventTarget* aScrollbar);
+  void RegisterWithRefreshDriver();
+  void UnregisterFromRefreshDriver();
+
+  void UpdateOpacity(TimeStamp aTime);
+  void HoveredScrollbar(nsIContent* aScrollbar);
 
+  nsRefreshDriver* GetRefreshDriver();
   nsIContent* GetScrollbarContent(bool aVertical);
-  nsIContent* GetHorizontalScrollbar() {
-    return GetScrollbarContent(false);
+  nsIContent* GetHorizontalScrollbar() { return GetScrollbarContent(false); }
+  nsIContent* GetVerticalScrollbar() { return GetScrollbarContent(true); }
+
+  static const TimeDuration FadeDuration() {
+    return TimeDuration::FromMilliseconds(kScrollbarFadeDuration);
   }
-  nsIContent* GetVerticalScrollbar() {
-    return GetScrollbarContent(true);
-  }
+
+  nsIScrollbarOwner* mScrollableFrame;
+  TimeStamp mFadeBeginTime;
+  nsCOMPtr<nsITimer> mFadeBeginTimer;
+  nsCOMPtr<nsIDOMEventTarget> mHorizontalScrollbar; // null while inactive
+  nsCOMPtr<nsIDOMEventTarget> mVerticalScrollbar;   // null while inactive
+  int mNestedActivityCounter;
+  bool mIsActive;
+  bool mIsFading;
+  bool mListeningForEvents;
+  bool mHScrollbarHovered;
+  bool mVScrollbarHovered;
 };
 
+} // namespace layout
 } // namespace mozilla
 
 #endif /* ScrollbarActivity_h___ */
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -20,16 +20,17 @@ EXPORTS += [
     'nsHTMLReflowState.h',
     'nsIAnonymousContentCreator.h',
     'nsIFrame.h',
     'nsIFrameUtil.h',
     'nsILineIterator.h',
     'nsIObjectFrame.h',
     'nsIPageSequenceFrame.h',
     'nsIScrollableFrame.h',
+    'nsIScrollbarOwner.h',
     'nsIStatefulFrame.h',
     'nsObjectFrame.h',
     'nsQueryFrame.h',
     'nsSubDocumentFrame.h',
 ]
 
 EXPORTS.mozilla += [
     'Selection.h',
--- a/layout/generic/nsFrameIdList.h
+++ b/layout/generic/nsFrameIdList.h
@@ -50,16 +50,17 @@ FRAME_ID(nsIPageSequenceFrame)
 FRAME_ID(nsIPercentHeightObserver)
 FRAME_ID(nsIRootBox)
 FRAME_ID(nsISVGChildFrame)
 FRAME_ID(nsISVGGlyphFragmentLeaf)
 FRAME_ID(nsISVGGlyphFragmentNode)
 FRAME_ID(nsISVGSVGFrame)
 FRAME_ID(nsIScrollableFrame)
 FRAME_ID(nsIScrollbarMediator)
+FRAME_ID(nsIScrollbarOwner)
 FRAME_ID(nsISelectControlFrame)
 FRAME_ID(nsIStatefulFrame)
 FRAME_ID(nsITableCellLayout)
 FRAME_ID(nsITableLayout)
 FRAME_ID(nsITextControlFrame)
 FRAME_ID(nsITreeBoxObject)
 FRAME_ID(nsImageBoxFrame)
 FRAME_ID(nsImageControlFrame)
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -55,16 +55,17 @@
 #include "nsRefreshDriver.h"
 #include "nsContentList.h"
 #include <algorithm>
 #include <cstdlib> // for std::abs(int/long)
 #include <cmath> // for std::abs(float/double)
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::layout;
 
 //----------------------------------------------------------------------
 
 //----------nsHTMLScrollFrame-------------------------------------------
 
 nsIFrame*
 NS_NewHTMLScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot)
 {
@@ -220,21 +221,33 @@ GetScrollbarMetrics(nsBoxLayoutState& aS
 {
   NS_ASSERTION(aState.GetRenderingContext(),
                "Must have rendering context in layout state for size "
                "computations");
 
   if (aMin) {
     *aMin = aBox->GetMinSize(aState);
     nsBox::AddMargin(aBox, *aMin);
+    if (aMin->width < 0) {
+      aMin->width = 0;
+    }
+    if (aMin->height < 0) {
+      aMin->height = 0;
+    }
   }
 
   if (aPref) {
     *aPref = aBox->GetPrefSize(aState);
     nsBox::AddMargin(aBox, *aPref);
+    if (aPref->width < 0) {
+      aPref->width = 0;
+    }
+    if (aPref->height < 0) {
+      aPref->height = 0;
+    }
   }
 }
 
 /**
  * Assuming that we know the metrics for our wrapped frame and
  * whether the horizontal and/or vertical scrollbars are present,
  * compute the resulting layout and return true if the layout is
  * consistent. If the layout is consistent then we fill in the
@@ -863,16 +876,17 @@ nsHTMLScrollFrame::AccessibleType()
   }
 
   return a11y::eHyperTextType;
 }
 #endif
 
 NS_QUERYFRAME_HEAD(nsHTMLScrollFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
+  NS_QUERYFRAME_ENTRY(nsIScrollbarOwner)
   NS_QUERYFRAME_ENTRY(nsIScrollableFrame)
   NS_QUERYFRAME_ENTRY(nsIStatefulFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 //----------nsXULScrollFrame-------------------------------------------
 
 nsIFrame*
 NS_NewXULScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot)
@@ -1110,16 +1124,17 @@ nsXULScrollFrame::DoLayout(nsBoxLayoutSt
   aState.SetLayoutFlags(flags);
 
   nsBox::DoLayout(aState);
   return rv;
 }
 
 NS_QUERYFRAME_HEAD(nsXULScrollFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
+  NS_QUERYFRAME_ENTRY(nsIScrollbarOwner)
   NS_QUERYFRAME_ENTRY(nsIScrollableFrame)
   NS_QUERYFRAME_ENTRY(nsIStatefulFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
 
 //-------------------- Inner ----------------------
 
 #define SMOOTH_SCROLL_PREF_NAME "general.smoothScroll"
 
@@ -1462,17 +1477,17 @@ nsGfxScrollFrameInner::nsGfxScrollFrameI
   , mMayHaveDirtyFixedChildren(false)
   , mUpdateScrollbarAttributes(false)
   , mCollapsedResizer(false)
   , mShouldBuildLayer(false)
   , mHasBeenScrolled(false)
 {
   mScrollingActive = IsAlwaysActive();
 
-  if (LookAndFeel::GetInt(LookAndFeel::eIntID_ShowHideScrollbars) != 0) {
+  if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
     mScrollbarActivity = new ScrollbarActivity(do_QueryFrame(aOuter));
   }
 }
 
 nsGfxScrollFrameInner::~nsGfxScrollFrameInner()
 {
   if (mActivityExpirationState.IsTracked()) {
     gScrollFrameActivityTracker->RemoveObject(this);
@@ -2816,16 +2831,17 @@ nsGfxScrollFrameInner::AppendAnonymousCo
   aElements.MaybeAppendElement(mScrollCornerContent);
   aElements.MaybeAppendElement(mResizerContent);
 }
 
 void
 nsGfxScrollFrameInner::Destroy()
 {
   if (mScrollbarActivity) {
+    mScrollbarActivity->Destroy();
     mScrollbarActivity = nullptr;
   }
 
   // Unbind any content created in CreateAnonymousContent from the tree
   nsContentUtils::DestroyAnonymousContent(&mHScrollbarContent);
   nsContentUtils::DestroyAnonymousContent(&mVScrollbarContent);
   nsContentUtils::DestroyAnonymousContent(&mScrollCornerContent);
   nsContentUtils::DestroyAnonymousContent(&mResizerContent);
@@ -3597,16 +3613,36 @@ nsGfxScrollFrameInner::AdjustScrollbarRe
     return;
 
   if (aVertical)
     aRect.height = std::max(0, resizerRect.y - aRect.y);
   else
     aRect.width = std::max(0, resizerRect.x - aRect.x);
 }
 
+static void
+AdjustOverlappingScrollbars(nsRect& aVRect, nsRect& aHRect)
+{
+  if (aVRect.IsEmpty() || aHRect.IsEmpty())
+    return;
+
+  const nsRect oldVRect = aVRect;
+  const nsRect oldHRect = aHRect;
+  if (oldVRect.Contains(oldHRect.BottomRight() - nsPoint(1, 1))) {
+    aHRect.width = std::max(0, oldVRect.x - oldHRect.x);
+  } else if (oldVRect.Contains(oldHRect.BottomLeft() - nsPoint(0, 1))) {
+    nscoord overlap = std::min(oldHRect.width, oldVRect.XMost() - oldHRect.x);
+    aHRect.x += overlap;
+    aHRect.width -= overlap;
+  }
+  if (oldHRect.Contains(oldVRect.BottomRight() - nsPoint(1, 1))) {
+    aVRect.height = std::max(0, oldHRect.y - oldVRect.y);
+  }
+}
+
 void
 nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState,
                                         const nsRect& aContentArea,
                                         const nsRect& aOldScrollArea)
 {
   NS_ASSERTION(!mSupppressScrollbarUpdate,
                "This should have been suppressed");
 
@@ -3639,68 +3675,75 @@ nsGfxScrollFrameInner::LayoutScrollbars(
     }
 
     if (mScrollCornerBox) {
       nsBoxFrame::LayoutChildAt(aState, mScrollCornerBox, r);
     }
 
     if (hasResizer) {
       // if a resizer is present, get its size. Assume a default size of 15 pixels.
-      nsSize resizerSize;
       nscoord defaultSize = nsPresContext::CSSPixelsToAppUnits(15);
-      resizerSize.width = mVScrollbarBox ?
+      nsSize resizerMinSize = mResizerBox->GetMinSize(aState);
+
+      nscoord vScrollbarWidth = mVScrollbarBox ?
         mVScrollbarBox->GetPrefSize(aState).width : defaultSize;
-      if (resizerSize.width > r.width) {
-        r.width = resizerSize.width;
-        if (aContentArea.x == mScrollPort.x && !scrollbarOnLeft)
-          r.x = aContentArea.XMost() - r.width;
+      r.width = std::max(std::max(r.width, vScrollbarWidth), resizerMinSize.width);
+      if (aContentArea.x == mScrollPort.x && !scrollbarOnLeft) {
+        r.x = aContentArea.XMost() - r.width;
       }
 
-      resizerSize.height = mHScrollbarBox ?
+      nscoord hScrollbarHeight = mHScrollbarBox ?
         mHScrollbarBox->GetPrefSize(aState).height : defaultSize;
-      if (resizerSize.height > r.height) {
-        r.height = resizerSize.height;
-        if (aContentArea.y == mScrollPort.y)
-          r.y = aContentArea.YMost() - r.height;
+      r.height = std::max(std::max(r.height, hScrollbarHeight), resizerMinSize.height);
+      if (aContentArea.y == mScrollPort.y) {
+        r.y = aContentArea.YMost() - r.height;
       }
 
       nsBoxFrame::LayoutChildAt(aState, mResizerBox, r);
     }
     else if (mResizerBox) {
       // otherwise lay out the resizer with an empty rectangle
       nsBoxFrame::LayoutChildAt(aState, mResizerBox, nsRect());
     }
   }
 
   nsPresContext* presContext = mScrolledFrame->PresContext();
+  nsRect vRect;
   if (mVScrollbarBox) {
     NS_PRECONDITION(mVScrollbarBox->IsBoxFrame(), "Must be a box frame!");
-    nsRect vRect(mScrollPort);
+    vRect = mScrollPort;
     vRect.width = aContentArea.width - mScrollPort.width;
     vRect.x = scrollbarOnLeft ? aContentArea.x : mScrollPort.XMost();
     if (mHasVerticalScrollbar) {
       nsMargin margin;
       mVScrollbarBox->GetMargin(margin);
       vRect.Deflate(margin);
     }
     AdjustScrollbarRectForResizer(mOuter, presContext, vRect, hasResizer, true);
-    nsBoxFrame::LayoutChildAt(aState, mVScrollbarBox, vRect);
   }
 
+  nsRect hRect;
   if (mHScrollbarBox) {
     NS_PRECONDITION(mHScrollbarBox->IsBoxFrame(), "Must be a box frame!");
-    nsRect hRect(mScrollPort);
+    hRect = mScrollPort;
     hRect.height = aContentArea.height - mScrollPort.height;
     hRect.y = true ? mScrollPort.YMost() : aContentArea.y;
     if (mHasHorizontalScrollbar) {
       nsMargin margin;
       mHScrollbarBox->GetMargin(margin);
       hRect.Deflate(margin);
     }
     AdjustScrollbarRectForResizer(mOuter, presContext, hRect, hasResizer, false);
+  }
+
+  AdjustOverlappingScrollbars(vRect, hRect);
+  if (mVScrollbarBox) {
+    nsBoxFrame::LayoutChildAt(aState, mVScrollbarBox, vRect);
+  }
+  if (mHScrollbarBox) {
     nsBoxFrame::LayoutChildAt(aState, mHScrollbarBox, hRect);
   }
 
   // may need to update fixed position children of the viewport,
   // if the client area changed size because of an incremental
   // reflow of a descendant.  (If the outer frame is dirty, the fixed
   // children will be re-laid out anyway)
   if (aOldScrollArea.Size() != mScrollPort.Size() &&
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -29,28 +29,31 @@ class nsIPresShell;
 class nsIContent;
 class nsIAtom;
 class nsIDocument;
 class nsIScrollFrameInternal;
 class nsPresState;
 struct ScrollReflowState;
 
 namespace mozilla {
+namespace layout {
 class ScrollbarActivity;
 }
+}
 
 // When set, the next scroll operation on the scrollframe will invalidate its
 // entire contents. Useful for text-overflow.
 // This bit is cleared after each time the scrollframe is scrolled. Whoever
 // needs to set it should set it again on each paint.
 #define NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL NS_FRAME_STATE_BIT(20)
 
 class nsGfxScrollFrameInner : public nsIReflowCallback {
 public:
   typedef mozilla::gfx::Point Point;
+  typedef mozilla::layout::ScrollbarActivity ScrollbarActivity;
 
   class AsyncScroll;
 
   nsGfxScrollFrameInner(nsContainerFrame* aOuter, bool aIsRoot);
   ~nsGfxScrollFrameInner();
 
   typedef nsIScrollableFrame::ScrollbarStyles ScrollbarStyles;
   ScrollbarStyles GetScrollbarStylesFromFrame() const;
@@ -276,17 +279,17 @@ public:
   nsRevocableEventPtr<ScrolledAreaEvent> mScrolledAreaEvent;
   nsIFrame* mHScrollbarBox;
   nsIFrame* mVScrollbarBox;
   nsIFrame* mScrolledFrame;
   nsIFrame* mScrollCornerBox;
   nsIFrame* mResizerBox;
   nsContainerFrame* mOuter;
   nsRefPtr<AsyncScroll> mAsyncScroll;
-  nsAutoPtr<mozilla::ScrollbarActivity> mScrollbarActivity;
+  nsCOMPtr<ScrollbarActivity> mScrollbarActivity;
   nsTArray<nsIScrollPositionListener*> mListeners;
   nsRect mScrollPort;
   // Where we're currently scrolling to, if we're scrolling asynchronously.
   // If we're not in the middle of an asynchronous scroll then this is
   // just the current scroll position. ScrollBy will choose its
   // destination based on this value.
   nsPoint mDestination;
   nsPoint mScrollPosAtLastPaint;
@@ -452,16 +455,21 @@ public:
     return pt;
   }
 
   // nsIAnonymousContentCreator
   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) MOZ_OVERRIDE;
   virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,
                                         uint32_t aFilter) MOZ_OVERRIDE;
 
+  // nsIScrollbarOwner
+  virtual nsIFrame* GetScrollbarBox(bool aVertical) MOZ_OVERRIDE {
+    return mInner.GetScrollbarBox(aVertical);
+  }
+
   // nsIScrollableFrame
   virtual nsIFrame* GetScrolledFrame() const {
     return mInner.GetScrolledFrame();
   }
   virtual nsGfxScrollFrameInner::ScrollbarStyles GetScrollbarStyles() const {
     return mInner.GetScrollbarStylesFromFrame();
   }
   virtual uint32_t GetScrollbarVisibility() const MOZ_OVERRIDE {
@@ -520,19 +528,16 @@ public:
     mInner.ScrollToRestoredPosition();
   }
   virtual void AddScrollPositionListener(nsIScrollPositionListener* aListener) MOZ_OVERRIDE {
     mInner.AddScrollPositionListener(aListener);
   }
   virtual void RemoveScrollPositionListener(nsIScrollPositionListener* aListener) MOZ_OVERRIDE {
     mInner.RemoveScrollPositionListener(aListener);
   }
-  virtual nsIFrame* GetScrollbarBox(bool aVertical) MOZ_OVERRIDE {
-    return mInner.GetScrollbarBox(aVertical);
-  }
   virtual void CurPosAttributeChanged(nsIContent* aChild) MOZ_OVERRIDE {
     mInner.CurPosAttributeChanged(aChild);
   }
   NS_IMETHOD PostScrolledAreaEventForCurrentArea() MOZ_OVERRIDE {
     mInner.PostScrolledAreaEvent();
     return NS_OK;
   }
   virtual bool IsScrollingActive() MOZ_OVERRIDE {
@@ -708,16 +713,21 @@ public:
   bool AddHorizontalScrollbar (nsBoxLayoutState& aState, bool aOnBottom);
   bool AddVerticalScrollbar   (nsBoxLayoutState& aState, bool aOnRight);
   void RemoveHorizontalScrollbar(nsBoxLayoutState& aState, bool aOnBottom);
   void RemoveVerticalScrollbar  (nsBoxLayoutState& aState, bool aOnRight);
 
   static void AdjustReflowStateForPrintPreview(nsBoxLayoutState& aState, bool& aSetBack);
   static void AdjustReflowStateBack(nsBoxLayoutState& aState, bool aSetBack);
 
+  // nsIScrollbarOwner
+  virtual nsIFrame* GetScrollbarBox(bool aVertical) MOZ_OVERRIDE {
+    return mInner.GetScrollbarBox(aVertical);
+  }
+
   // nsIScrollableFrame
   virtual nsIFrame* GetScrolledFrame() const {
     return mInner.GetScrolledFrame();
   }
   virtual nsGfxScrollFrameInner::ScrollbarStyles GetScrollbarStyles() const {
     return mInner.GetScrollbarStylesFromFrame();
   }
   virtual uint32_t GetScrollbarVisibility() const MOZ_OVERRIDE {
@@ -776,19 +786,16 @@ public:
     mInner.ScrollToRestoredPosition();
   }
   virtual void AddScrollPositionListener(nsIScrollPositionListener* aListener) MOZ_OVERRIDE {
     mInner.AddScrollPositionListener(aListener);
   }
   virtual void RemoveScrollPositionListener(nsIScrollPositionListener* aListener) MOZ_OVERRIDE {
     mInner.RemoveScrollPositionListener(aListener);
   }
-  virtual nsIFrame* GetScrollbarBox(bool aVertical) MOZ_OVERRIDE {
-    return mInner.GetScrollbarBox(aVertical);
-  }
   virtual void CurPosAttributeChanged(nsIContent* aChild) MOZ_OVERRIDE {
     mInner.CurPosAttributeChanged(aChild);
   }
   NS_IMETHOD PostScrolledAreaEventForCurrentArea() MOZ_OVERRIDE {
     mInner.PostScrolledAreaEvent();
     return NS_OK;
   }
   virtual bool IsScrollingActive() MOZ_OVERRIDE {
--- a/layout/generic/nsIScrollableFrame.h
+++ b/layout/generic/nsIScrollableFrame.h
@@ -9,30 +9,31 @@
 
 #ifndef nsIScrollFrame_h___
 #define nsIScrollFrame_h___
 
 #include "nsISupports.h"
 #include "nsCoord.h"
 #include "nsPresContext.h"
 #include "mozilla/gfx/Point.h"
+#include "nsIScrollbarOwner.h"
 
 #define NS_DEFAULT_VERTICAL_SCROLL_DISTANCE   3
 #define NS_DEFAULT_HORIZONTAL_SCROLL_DISTANCE 5
 
 class nsBoxLayoutState;
 class nsIScrollPositionListener;
 class nsIFrame;
 
 /**
  * Interface for frames that are scrollable. This interface exposes
  * APIs for examining scroll state, observing changes to scroll state,
  * and triggering scrolling.
  */
-class nsIScrollableFrame : public nsQueryFrame {
+class nsIScrollableFrame : public nsIScrollbarOwner {
 public:
   typedef mozilla::gfx::Point Point;
 
   NS_DECL_QUERYFRAME_TARGET(nsIScrollableFrame)
 
   /**
    * Get the frame for the content that we are scrolling within
    * this scrollable frame.
@@ -198,24 +199,16 @@ public:
    */
   virtual void AddScrollPositionListener(nsIScrollPositionListener* aListener) = 0;
   /**
    * Remove a scroll position listener.
    */
   virtual void RemoveScrollPositionListener(nsIScrollPositionListener* aListener) = 0;
 
   /**
-   * Obtain the XUL box for the horizontal or vertical scrollbar, or null
-   * if there is no such box. Avoid using this, but may be useful for
-   * setting up a scrollbar mediator if you want to redirect scrollbar
-   * input.
-   */
-  virtual nsIFrame* GetScrollbarBox(bool aVertical) = 0;
-
-  /**
    * Internal method used by scrollbars to notify their scrolling
    * container of changes.
    */
   virtual void CurPosAttributeChanged(nsIContent* aChild) = 0;
 
   /**
    * Allows the docshell to request that the scroll frame post an event
    * after being restored from history.
new file mode 100644
--- /dev/null
+++ b/layout/generic/nsIScrollbarOwner.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; 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/. */
+
+#ifndef nsIScrollbarOwner_h___
+#define nsIScrollbarOwner_h___
+
+#include "nsQueryFrame.h"
+
+class nsIDOMEventTarget;
+class nsIFrame;
+
+/**
+ * An interface that represents a frame which manages scrollbars.
+ */
+class nsIScrollbarOwner : public nsQueryFrame {
+public:
+  NS_DECL_QUERYFRAME_TARGET(nsIScrollbarOwner)
+
+  /**
+   * Obtain the frame for the horizontal or vertical scrollbar, or null
+   * if there is no such box.
+   */
+  virtual nsIFrame* GetScrollbarBox(bool aVertical) = 0;
+};
+
+#endif
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -163,28 +163,28 @@ skip-if(B2G) == 192767-21.xul 192767-31.
 skip-if(B2G) == 192767-22.xul 192767-32.xul
 skip-if(B2G) == 192767-23.xul 192767-33.xul
 skip-if(B2G) == 192767-24.xul 192767-34.xul
 skip-if(B2G) == 192767-25.xul 192767-35.xul
 skip-if(B2G) == 192767-26.xul 192767-36.xul
 skip-if(B2G) == 192767-27.xul 192767-37.xul
 != 192767-01.xul 192767-21.xul
 != 192767-02.xul 192767-22.xul
-fails-if(Android) != 192767-03.xul 192767-23.xul
+skip-if(B2G) fails-if(Android) != 192767-03.xul 192767-23.xul
 != 192767-04.xul 192767-24.xul
 != 192767-05.xul 192767-25.xul
-fails-if(Android) != 192767-06.xul 192767-26.xul
-fails-if(Android) != 192767-07.xul 192767-27.xul
+skip-if(B2G) fails-if(Android) != 192767-06.xul 192767-26.xul
+skip-if(B2G) fails-if(Android) != 192767-07.xul 192767-27.xul
 != 192767-11.xul 192767-31.xul
 != 192767-12.xul 192767-32.xul
-fails-if(Android) != 192767-13.xul 192767-33.xul
+skip-if(B2G) fails-if(Android) != 192767-13.xul 192767-33.xul
 != 192767-14.xul 192767-34.xul
 != 192767-15.xul 192767-35.xul
-fails-if(Android) != 192767-16.xul 192767-36.xul
-fails-if(Android) != 192767-17.xul 192767-37.xul
+skip-if(B2G) fails-if(Android) != 192767-16.xul 192767-36.xul
+skip-if(B2G) fails-if(Android) != 192767-17.xul 192767-37.xul
 != 200774-1.html about:blank
 == 201215-1.html 201215-1-ref.html
 == 201293-1a.html 201293-1-ref.html
 == 201293-1b.html 201293-1-ref.html
 == 201293-1c.html 201293-1-ref.html
 == 201293-1d.html 201293-1-ref.html
 == 203727.html 203727-ref.html
 == 206516-1.html 206516-1-ref.html
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -1129,16 +1129,22 @@ InitSystemMetrics()
 
   metricResult =
     LookAndFeel::GetInt(LookAndFeel::eIntID_ImagesInButtons);
   if (metricResult) {
     sSystemMetrics->AppendElement(nsGkAtoms::images_in_buttons);
   }
 
   metricResult =
+    LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars);
+  if (metricResult) {
+    sSystemMetrics->AppendElement(nsGkAtoms::overlay_scrollbars);
+  }
+
+  metricResult =
     LookAndFeel::GetInt(LookAndFeel::eIntID_MenuBarDrag);
   if (metricResult) {
     sSystemMetrics->AppendElement(nsGkAtoms::menubar_drag);
   }
 
   nsresult rv =
     LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsDefaultTheme, &metricResult);
   if (NS_SUCCEEDED(rv) && metricResult) {
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -504,16 +504,23 @@ nsMediaFeatures::features[] = {
     {
         &nsGkAtoms::_moz_images_in_buttons,
         nsMediaFeature::eMinMaxNotAllowed,
         nsMediaFeature::eBoolInteger,
         { &nsGkAtoms::images_in_buttons },
         GetSystemMetric
     },
     {
+        &nsGkAtoms::_moz_overlay_scrollbars,
+        nsMediaFeature::eMinMaxNotAllowed,
+        nsMediaFeature::eBoolInteger,
+        { &nsGkAtoms::overlay_scrollbars },
+        GetSystemMetric
+    },
+    {
         &nsGkAtoms::_moz_windows_default_theme,
         nsMediaFeature::eMinMaxNotAllowed,
         nsMediaFeature::eBoolInteger,
         { &nsGkAtoms::windows_default_theme },
         GetSystemMetric
     },
     {
         &nsGkAtoms::_moz_mac_graphite_theme,
--- a/layout/style/test/test_media_queries.html
+++ b/layout/style/test/test_media_queries.html
@@ -556,16 +556,17 @@ function run() {
   // System metrics
   expression_should_be_parseable("-moz-scrollbar-start-backward");
   expression_should_be_parseable("-moz-scrollbar-start-forward");
   expression_should_be_parseable("-moz-scrollbar-end-backward");
   expression_should_be_parseable("-moz-scrollbar-end-forward");
   expression_should_be_parseable("-moz-scrollbar-thumb-proportional");
   expression_should_be_parseable("-moz-images-in-menus");
   expression_should_be_parseable("-moz-images-in-buttons");
+  expression_should_be_parseable("-moz-overlay-scrollbars");
   expression_should_be_parseable("-moz-windows-default-theme");
   expression_should_be_parseable("-moz-mac-graphite-theme");
   expression_should_be_parseable("-moz-mac-lion-theme");
   expression_should_be_parseable("-moz-windows-compositor");
   expression_should_be_parseable("-moz-windows-classic");
   expression_should_be_parseable("-moz-windows-glass");
   expression_should_be_parseable("-moz-touch-enabled");
   expression_should_be_parseable("-moz-maemo-classic");
@@ -573,16 +574,17 @@ function run() {
 
   expression_should_be_parseable("-moz-scrollbar-start-backward: 0");
   expression_should_be_parseable("-moz-scrollbar-start-forward: 0");
   expression_should_be_parseable("-moz-scrollbar-end-backward: 0");
   expression_should_be_parseable("-moz-scrollbar-end-forward: 0");
   expression_should_be_parseable("-moz-scrollbar-thumb-proportional: 0");
   expression_should_be_parseable("-moz-images-in-menus: 0");
   expression_should_be_parseable("-moz-images-in-buttons: 0");
+  expression_should_be_parseable("-moz-overlay-scrollbars: 0");
   expression_should_be_parseable("-moz-windows-default-theme: 0");
   expression_should_be_parseable("-moz-mac-graphite-theme: 0");
   expression_should_be_parseable("-moz-mac-lion-theme: 0");
   expression_should_be_parseable("-moz-windows-compositor: 0");
   expression_should_be_parseable("-moz-windows-classic: 0");
   expression_should_be_parseable("-moz-windows-glass: 0");
   expression_should_be_parseable("-moz-touch-enabled: 0");
   expression_should_be_parseable("-moz-maemo-classic: 0");
@@ -590,16 +592,17 @@ function run() {
 
   expression_should_be_parseable("-moz-scrollbar-start-backward: 1");
   expression_should_be_parseable("-moz-scrollbar-start-forward: 1");
   expression_should_be_parseable("-moz-scrollbar-end-backward: 1");
   expression_should_be_parseable("-moz-scrollbar-end-forward: 1");
   expression_should_be_parseable("-moz-scrollbar-thumb-proportional: 1");
   expression_should_be_parseable("-moz-images-in-menus: 1");
   expression_should_be_parseable("-moz-images-in-buttons: 1");
+  expression_should_be_parseable("-moz-overlay-scrollbars: 1");
   expression_should_be_parseable("-moz-windows-default-theme: 1");
   expression_should_be_parseable("-moz-mac-graphite-theme: 1");
   expression_should_be_parseable("-moz-mac-lion-theme: 1");
   expression_should_be_parseable("-moz-windows-compositor: 1");
   expression_should_be_parseable("-moz-windows-classic: 1");
   expression_should_be_parseable("-moz-windows-glass: 1");
   expression_should_be_parseable("-moz-touch-enabled: 1");
   expression_should_be_parseable("-moz-maemo-classic: 1");
@@ -607,16 +610,17 @@ function run() {
 
   expression_should_not_be_parseable("-moz-scrollbar-start-backward: -1");
   expression_should_not_be_parseable("-moz-scrollbar-start-forward: -1");
   expression_should_not_be_parseable("-moz-scrollbar-end-backward: -1");
   expression_should_not_be_parseable("-moz-scrollbar-end-forward: -1");
   expression_should_not_be_parseable("-moz-scrollbar-thumb-proportional: -1");
   expression_should_not_be_parseable("-moz-images-in-menus: -1");
   expression_should_not_be_parseable("-moz-images-in-buttons: -1");
+  expression_should_not_be_parseable("-moz-overlay-scrollbars: -1");
   expression_should_not_be_parseable("-moz-windows-default-theme: -1");
   expression_should_not_be_parseable("-moz-mac-graphite-theme: -1");
   expression_should_not_be_parseable("-moz-mac-lion-theme: -1");
   expression_should_not_be_parseable("-moz-windows-compositor: -1");
   expression_should_not_be_parseable("-moz-windows-classic: -1");
   expression_should_not_be_parseable("-moz-windows-glass: -1");
   expression_should_not_be_parseable("-moz-touch-enabled: -1");
   expression_should_not_be_parseable("-moz-maemo-classic: -1");
@@ -624,16 +628,17 @@ function run() {
 
   expression_should_not_be_parseable("-moz-scrollbar-start-backward: true");
   expression_should_not_be_parseable("-moz-scrollbar-start-forward: true");
   expression_should_not_be_parseable("-moz-scrollbar-end-backward: true");
   expression_should_not_be_parseable("-moz-scrollbar-end-forward: true");
   expression_should_not_be_parseable("-moz-scrollbar-thumb-proportional: true");
   expression_should_not_be_parseable("-moz-images-in-menus: true");
   expression_should_not_be_parseable("-moz-images-in-buttons: true");
+  expression_should_not_be_parseable("-moz-overlay-scrollbars: true");
   expression_should_not_be_parseable("-moz-windows-default-theme: true");
   expression_should_not_be_parseable("-moz-mac-graphite-theme: true");
   expression_should_not_be_parseable("-moz-mac-lion-theme: true");
   expression_should_not_be_parseable("-moz-windows-compositor: true");
   expression_should_not_be_parseable("-moz-windows-classic: true");
   expression_should_not_be_parseable("-moz-windows-glass: true");
   expression_should_not_be_parseable("-moz-touch-enabled: true");
   expression_should_not_be_parseable("-moz-maemo-classic: true");
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -55,25 +55,27 @@
 #include "nsLayoutUtils.h"
 #include "nsIScrollableFrame.h"
 #include "nsEventDispatcher.h"
 #include "nsDisplayList.h"
 #include "nsTreeBoxObject.h"
 #include "nsRenderingContext.h"
 #include "nsIScriptableRegion.h"
 #include <algorithm>
+#include "ScrollbarActivity.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 #ifdef IBMBIDI
 #include "nsBidiUtils.h"
 #endif
 
 using namespace mozilla;
+using namespace mozilla::layout;
 
 // Enumeration function that cancels all the image requests in our cache
 static PLDHashOperator
 CancelImageRequest(const nsAString& aKey,
                    nsTreeImageCacheEntry aEntry, void* aData)
 {
 
   // If our imgIRequest object was registered with the refresh driver,
@@ -97,16 +99,17 @@ NS_NewTreeBodyFrame(nsIPresShell* aPresS
 {
   return new (aPresShell) nsTreeBodyFrame(aPresShell, aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsTreeBodyFrame)
 
 NS_QUERYFRAME_HEAD(nsTreeBodyFrame)
   NS_QUERYFRAME_ENTRY(nsIScrollbarMediator)
+  NS_QUERYFRAME_ENTRY(nsIScrollbarOwner)
   NS_QUERYFRAME_ENTRY(nsTreeBodyFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsLeafBoxFrame)
 
 // Constructor
 nsTreeBodyFrame::nsTreeBodyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 :nsLeafBoxFrame(aPresShell, aContext),
  mSlots(nullptr),
  mTopRowIndex(0),
@@ -164,16 +167,21 @@ nsTreeBodyFrame::Init(nsIContent*     aC
 
   mIndentation = GetIndentation();
   mRowHeight = GetRowHeight();
 
   mCreatedListeners.Init();
 
   mImageCache.Init(16);
   EnsureBoxObject();
+
+  if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
+    mScrollbarActivity = new ScrollbarActivity(
+                           static_cast<nsIScrollbarOwner*>(this));
+  }
 }
 
 nsSize
 nsTreeBodyFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
 {
   EnsureView();
 
   nsIContent* baseElement = GetBaseElement();
@@ -261,16 +269,21 @@ nsTreeBodyFrame::CalcMaxRowWidth()
 
   mStringWidth += rowMargin.left + rowMargin.right;
   return mStringWidth;
 }
 
 void
 nsTreeBodyFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
+  if (mScrollbarActivity) {
+    mScrollbarActivity->Destroy();
+    mScrollbarActivity = nullptr;
+  }
+
   mScrollEvent.Revoke();
   // Make sure we cancel any posted callbacks. 
   if (mReflowCallbackPosted) {
     PresContext()->PresShell()->CancelReflowCallback(this);
     mReflowCallbackPosted = false;
   }
 
   if (mColumns)
@@ -832,34 +845,36 @@ nsTreeBodyFrame::ScrollParts nsTreeBodyF
   return result;
 }
 
 void
 nsTreeBodyFrame::UpdateScrollbars(const ScrollParts& aParts)
 {
   nscoord rowHeightAsPixels = nsPresContext::AppUnitsToIntCSSPixels(mRowHeight);
 
+  nsWeakFrame weakFrame(this);
+
   if (aParts.mVScrollbar) {
-    nsWeakFrame self(this);
     nsAutoString curPos;
     curPos.AppendInt(mTopRowIndex*rowHeightAsPixels);
     aParts.mVScrollbarContent->
       SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curPos, true);
-    if (!self.IsAlive()) {
-      return;
-    }
   }
 
   if (aParts.mHScrollbar) {
     nsAutoString curPos;
     curPos.AppendInt(mHorzPosition);
     aParts.mHScrollbarContent->
       SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curPos, true);
     // 'this' might be deleted here
   }
+
+  if (weakFrame.IsAlive() && mScrollbarActivity) {
+    mScrollbarActivity->ActivityOccurred();
+  }
 }
 
 void
 nsTreeBodyFrame::CheckOverflow(const ScrollParts& aParts)
 {
   bool verticalOverflowChanged = false;
   bool horizontalOverflowChanged = false;
 
@@ -952,16 +967,20 @@ nsTreeBodyFrame::InvalidateScrollbars(co
       SetAttr(kNameSpaceID_None, nsGkAtoms::pageincrement, pageStr, true);
     ENSURE_TRUE(weakFrame.IsAlive());
   
     pageStr.Truncate();
     pageStr.AppendInt(nsPresContext::CSSPixelsToAppUnits(16));
     aParts.mHScrollbarContent->
       SetAttr(kNameSpaceID_None, nsGkAtoms::increment, pageStr, true);
   }
+
+  if (mScrollbarActivity) {
+    mScrollbarActivity->ActivityOccurred();
+  }
 }
 
 // Takes client x/y in pixels, converts them to appunits, and converts into
 // values relative to this nsTreeBodyFrame frame.
 nsPoint
 nsTreeBodyFrame::AdjustClientCoordsToBoxCoordSpace(int32_t aX, int32_t aY)
 {
   nsPoint point(nsPresContext::CSSPixelsToAppUnits(aX),
--- a/layout/xul/tree/nsTreeBodyFrame.h
+++ b/layout/xul/tree/nsTreeBodyFrame.h
@@ -19,20 +19,27 @@
 #include "nsTreeColumns.h"
 #include "nsAutoPtr.h"
 #include "nsDataHashtable.h"
 #include "imgIRequest.h"
 #include "imgINotificationObserver.h"
 #include "nsScrollbarFrame.h"
 #include "nsThreadUtils.h"
 #include "mozilla/LookAndFeel.h"
+#include "nsIScrollbarOwner.h"
 
 class nsOverflowChecker;
 class nsTreeImageListener;
 
+namespace mozilla {
+namespace layout {
+class ScrollbarActivity;
+}
+}
+
 // An entry in the tree's image cache
 struct nsTreeImageCacheEntry
 {
   nsTreeImageCacheEntry() {}
   nsTreeImageCacheEntry(imgIRequest *aRequest, imgINotificationObserver *aListener)
     : request(aRequest), listener(aListener) {}
 
   nsCOMPtr<imgIRequest> request;
@@ -40,18 +47,21 @@ struct nsTreeImageCacheEntry
 };
 
 // The actual frame that paints the cells and rows.
 class nsTreeBodyFrame MOZ_FINAL
   : public nsLeafBoxFrame
   , public nsICSSPseudoComparator
   , public nsIScrollbarMediator
   , public nsIReflowCallback
+  , public nsIScrollbarOwner
 {
 public:
+  typedef mozilla::layout::ScrollbarActivity ScrollbarActivity;
+
   nsTreeBodyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
   ~nsTreeBodyFrame();
 
   NS_DECL_QUERYFRAME_TARGET(nsTreeBodyFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   // Callback handler methods for refresh driver based animations.
@@ -121,16 +131,22 @@ public:
   // nsICSSPseudoComparator
   virtual bool PseudoMatches(nsCSSSelector* aSelector) MOZ_OVERRIDE;
 
   // nsIScrollbarMediator
   NS_IMETHOD PositionChanged(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t& aNewIndex);
   NS_IMETHOD ScrollbarButtonPressed(nsScrollbarFrame* aScrollbar, int32_t aOldIndex, int32_t aNewIndex) MOZ_OVERRIDE;
   NS_IMETHOD VisibilityChanged(bool aVisible) MOZ_OVERRIDE { Invalidate(); return NS_OK; }
 
+  // nsIScrollbarOwner
+  virtual nsIFrame* GetScrollbarBox(bool aVertical) MOZ_OVERRIDE {
+    ScrollParts parts = GetScrollParts();
+    return aVertical ? parts.mVScrollbar : parts.mHScrollbar;
+  }
+
   // Overridden from nsIFrame to cache our pres context.
   virtual void Init(nsIContent*     aContent,
                     nsIFrame*       aParent,
                     nsIFrame*       aPrevInFlow) MOZ_OVERRIDE;
   virtual void DestroyFrom(nsIFrame* aDestructRoot);
 
   NS_IMETHOD GetCursor(const nsPoint& aPoint,
                        nsIFrame::Cursor& aCursor);
@@ -520,16 +536,18 @@ protected: // Data Members
       // An array used to keep track of all spring loaded folders.
       nsTArray<int32_t>        mArray;
   };
 
   Slots* mSlots;
 
   nsRevocableEventPtr<ScrollEvent> mScrollEvent;
 
+  nsCOMPtr<ScrollbarActivity> mScrollbarActivity;
+
   // The cached box object parent.
   nsCOMPtr<nsITreeBoxObject> mTreeBoxObject;
 
   // Cached column information.
   nsRefPtr<nsTreeColumns> mColumns;
 
   // The current view for this tree widget.  We get all of our row and cell data
   // from the view.
--- a/mobile/android/base/gfx/BitmapUtils.java
+++ b/mobile/android/base/gfx/BitmapUtils.java
@@ -50,58 +50,73 @@ public final class BitmapUtils {
         return bitmap;
     }
 
     public static int getDominantColor(Bitmap source) {
         return getDominantColor(source, true);
     }
 
     public static int getDominantColor(Bitmap source, boolean applyThreshold) {
-      int[] colors = new int[37];
-      int[] sat = new int[11];
-      int[] val = new int[11];
-      int maxH = 0;
-      int maxS = 0;
-      int maxV = 0;
       if (source == null)
         return Color.argb(255,255,255,255);
 
+      // Keep track of how many times a hue in a given bin appears in the image.
+      // Hue values range [0 .. 360), so dividing by 10, we get 36 bins.
+      int[] colorBins = new int[36];
+
+      // The bin with the most colors. Initialize to -1 to prevent accidentally
+      // thinking the first bin holds the dominant color.
+      int maxBin = -1;
+
+      // Keep track of sum hue/saturation/value per hue bin, which we'll use to
+      // compute an average to for the dominant color.
+      float[] sumHue = new float[36];
+      float[] sumSat = new float[36];
+      float[] sumVal = new float[36];
+
       for (int row = 0; row < source.getHeight(); row++) {
         for (int col = 0; col < source.getWidth(); col++) {
           int c = source.getPixel(col, row);
+          // Ignore pixels with a certain transparency.
           if (Color.alpha(c) < 128)
             continue;
 
           float[] hsv = new float[3];
           Color.colorToHSV(c, hsv);
 
-          // arbitrarily chosen values for "white" and "black"
-          if (applyThreshold && hsv[1] <= 0.35f && hsv[2] <= 0.35f)
+          // If a threshold is applied, ignore arbitrarily chosen values for "white" and "black".
+          if (applyThreshold && (hsv[1] <= 0.35f || hsv[2] <= 0.35f))
             continue;
 
-          int h = Math.round(hsv[0] / 10.0f);
-          int s = Math.round(hsv[1] * 10.0f);
-          int v = Math.round(hsv[2] * 10.0f);
-          colors[h]++;
-          sat[s]++;
-          val[v]++;
+          // We compute the dominant color by putting colors in bins based on their hue.
+          int bin = (int) Math.floor(hsv[0] / 10.0f);
 
-          // we only care about the most unique non white or black hue - if threshold is applied
-          // we also store its saturation and value params to match the color better
-          if (colors[h] > colors[maxH]) {
-            maxH = h;
-            maxS = s;
-            maxV = v;
-          }
+          // Update the sum hue/saturation/value for this bin.
+          sumHue[bin] = sumHue[bin] + hsv[0];
+          sumSat[bin] = sumSat[bin] + hsv[1];
+          sumVal[bin] = sumVal[bin] + hsv[2];
+
+          // Increment the number of colors in this bin.
+          colorBins[bin]++;
+
+          // Keep track of the bin that holds the most colors.
+          if (maxBin < 0 || colorBins[bin] > colorBins[maxBin])
+            maxBin = bin;
         }
       }
+
+      // maxBin may never get updated if the image holds only transparent and/or black/white pixels.
+      if (maxBin < 0)
+        return Color.argb(255,255,255,255);
+
+      // Return a color with the average hue/saturation/value of the bin with the most colors.
       float[] hsv = new float[3];
-      hsv[0] = maxH*10.0f;
-      hsv[1] = (float)maxS/10.0f;
-      hsv[2] = (float)maxV/10.0f;
+      hsv[0] = sumHue[maxBin]/colorBins[maxBin];
+      hsv[1] = sumSat[maxBin]/colorBins[maxBin];
+      hsv[2] = sumVal[maxBin]/colorBins[maxBin];
       return Color.HSVToColor(hsv);
     }
 
     /**
      * Decodes a bitmap from a Base64 data URI.
      *
      * @param dataURI a Base64-encoded data URI string
      * @return        the decoded bitmap, or null if the data URI is invalid
--- a/mobile/android/chrome/content/aboutAddons.js
+++ b/mobile/android/chrome/content/aboutAddons.js
@@ -47,25 +47,27 @@ var ContextMenus = {
 
     let addon = this.target.addon;
     if (addon.scope == AddonManager.SCOPE_APPLICATION) {
       document.getElementById("contextmenu-uninstall").setAttribute("hidden", "true");
     } else {
       document.getElementById("contextmenu-uninstall").removeAttribute("hidden");
     }
 
-    if (this.target.getAttribute("isDisabled") != "true") {
+    let enabled = this.target.getAttribute("isDisabled") != "true";
+    if (enabled) {
       document.getElementById("contextmenu-enable").setAttribute("hidden", "true");
       document.getElementById("contextmenu-disable").removeAttribute("hidden");
     } else {
       document.getElementById("contextmenu-enable").removeAttribute("hidden");
       document.getElementById("contextmenu-disable").setAttribute("hidden", "true");
     }
 
-    if (addon.type == "search") {
+    // Only show the "Set as Default" menuitem for enabled non-default search engines.
+    if (addon.type == "search" && enabled && addon.id != Services.search.defaultEngine.name) {
       document.getElementById("contextmenu-default").removeAttribute("hidden");
     } else {
       document.getElementById("contextmenu-default").setAttribute("hidden", "true");
     }
   },
 
   enable: function(event) {
     Addons.setEnabled(true, this.target.addon);
--- a/testing/crashtest/crashtests.list
+++ b/testing/crashtest/crashtests.list
@@ -22,17 +22,17 @@ include ../../content/media/test/crashte
 
 include ../../docshell/base/crashtests/crashtests.list
 
 include ../../dom/base/crashtests/crashtests.list
 include ../../dom/bindings/crashtests/crashtests.list
 include ../../dom/indexedDB/crashtests/crashtests.list
 
 # Bug 811873 - mozRTCPeerConnection doesn't support remote browser yet
-skip-if(Android||B2G||browserIsRemote) include ../../dom/media/tests/crashtests/crashtests.list
+skip-if(B2G||browserIsRemote) include ../../dom/media/tests/crashtests/crashtests.list
 
 include ../../dom/src/offline/crashtests/crashtests.list
 include ../../dom/src/jsurl/crashtests/crashtests.list
 
 include ../../editor/crashtests.list
 
 include ../../intl/lwbrk/src/crashtests/crashtests.list
 include ../../intl/uconv/crashtests/crashtests.list
--- a/toolkit/content/license.html
+++ b/toolkit/content/license.html
@@ -63,16 +63,17 @@
       <li><a href="about:license#apple-mozilla">Apple/Mozilla NPRuntime License</a></li>
       <li><a href="about:license#apple-torch">Apple/Torch Mobile License</a></li>
       <li><a href="about:license#bspatch">bspatch License</a></li>
       <li><a href="about:license#cairo">Cairo Component Licenses</a></li>
       <li><a href="about:license#chromium">Chromium License</a></li>
       <li><a href="about:license#dtoa">dtoa License</a></li>
       <li><a href="about:license#hunspell-nl">Dutch Spellchecking Dictionary License</a></li>
       <li><a href="about:license#edl">Eclipse Distribution License</a></li>
+      <li><a href="about:license#hunspell-ee">Estonian Spellchecking Dictionary License</a></li>
       <li><a href="about:license#expat">Expat License</a></li>
       <li><a href="about:license#firebug">Firebug License</a></li>
       <li><a href="about:license#gfx-font-list">gfxFontList License</a></li>
       <li><a href="about:license#google-bsd">Google BSD License</a></li>
       <li><a href="about:license#gears">Google Gears License</a></li>
       <li><a href="about:license#gears-istumbler">Google Gears/iStumbler License</a></li>
       <li><a href="about:license#vp8">Google VP8 License</a></li>
       <li><a href="about:license#growl">Growl License</a></li>
@@ -1210,16 +1211,67 @@ ANY THEORY OF LIABILITY, WHETHER IN CONT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 </pre>
 
 
 
     <hr>
 
+    <h1><a id="hunspell-ee"></a>Estonian Spellchecking Dictionary License</h1>
+
+    <p>This license applies to precursor works to certain files in the directory
+      <span class="path">l10n/ee/extensions/spellcheck/hunspell/</span>. The
+      shipped versions are under the GNU Lesser General Public License. (This
+      code only ships in some localized versions of this product.)</p>
+
+<pre>
+Copyright © Institute of the Estonian Language
+
+E-mail: litsents@eki.ee
+URL: http://www.eki.ee/tarkvara/
+
+The present Licence Agreement gives the user of this Software Product
+(hereinafter: Product) the right to use the Product for whatever purpose
+(incl. distribution, copying, altering, inclusion in other software, and
+selling) on the following conditions:
+
+1. The present Licence Agreement should belong unaltered to each copy ever
+   made of this Product;
+2. Neither the Institute of the Estonian Language (hereinafter: IEL) nor the
+   author(s) of the Product will take responsibility for any detriment, direct
+   or indirect, possibly ensuing from the application of the Product;
+3. The IEL is ready to share the Product with other users as we wish to
+   advance research on the Estonian language and to promote the use of
+   Estonian in rapidly developing infotechnology, yet we refuse to bind
+   ourselves to any further obligation, which means that the IEL is not
+   obliged either to warrant the suitability of the Product for a specific
+   purpose, to improve the software, or to provide a more detailed description
+   of the underlying algorithms. (Which does not mean, though, that we may not
+   do it.)
+
+Notification Request:
+
+As a courtesy, we would appreciate being informed whenever our linguistic
+products are used to create derivative works. If you modify our software or
+include it in other products, please inform us by sending e-mail to
+litsents@eki.ee or by letter to
+
+Institute of the Estonian Language
+Roosikrantsi 6
+10119 Tallinn
+ESTONIA
+
+Phone &amp; Fax: +372 6411443
+</pre>
+
+
+
+    <hr>
+
     <h1><a id="expat"></a>Expat License</h1>
 
     <p>This license applies to certain files in the directory
     <span class="path">parser/expat/</span>.</p>
 
 <pre>
 Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
                                and Clark Cooper
--- a/toolkit/content/tests/browser/browser_bug295977_autoscroll_overflow.js
+++ b/toolkit/content/tests/browser/browser_bug295977_autoscroll_overflow.js
@@ -75,17 +75,17 @@ function test()
     <div id="c" style="width: 100px; height: 100px; overflow-x: auto; overflow-y: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
     <div id="d" style="width: 100px; height: 100px; overflow-y: auto; overflow-x: hidden;"><div style="width: 200px; height: 200px;"></div></div>\
     <select id="e" style="width: 100px; height: 100px;" multiple="multiple"><option>aaaaaaaaaaaaaaaaaaaaaaaa</option><option>a</option><option>a</option>\
     <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option>\
     <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option></select>\
     <select id="f" style="width: 100px; height: 100px;"><option>a</option><option>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</option><option>a</option>\
     <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option>\
     <option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option><option>a</option></select>\
-    <div id="g" style="width: 99px; height: 99px; padding: 10px; border: 10px solid black; margin: 10px; overflow: auto;"><div style="width: 100px; height: 100px; margin: 10px;"></div></div>\
+    <div id="g" style="width: 99px; height: 99px; border: 10px solid black; margin: 10px; overflow: auto;"><div style="width: 100px; height: 100px;"></div></div>\
     <div id="h" style="width: 100px; height: 100px; overflow: -moz-hidden-unscrollable;"><div style="width: 200px; height: 200px;"></div></div>\
     <iframe id="iframe" style="display: none;"></iframe>\
     </body>';
   gBrowser.selectedBrowser.addEventListener("pageshow", onLoad, false);
   gBrowser.loadURI(dataUri);
 
   function onLoad() {
     gBrowser.selectedBrowser.removeEventListener("pageshow", onLoad, false);
--- a/toolkit/content/tests/chrome/test_hiddenpaging.xul
+++ b/toolkit/content/tests/chrome/test_hiddenpaging.xul
@@ -93,21 +93,23 @@ function testRichlistbox()
   is(listbox.getIndexOfFirstVisibleRow(), 0, id + ": Third page up should not have scrolled at all");
 }
 
 function testListbox()
 {
   var id = "listbox";
   var listbox = document.getElementById(id);
 
-  // Check that a scrollbar is visible by comparing the width of the listitem
-  // with the width of the listbox. This is a simple way to do this without
-  // checking the anonymous content.
-  ok(listbox.firstChild.getBoundingClientRect().width < listbox.getBoundingClientRect().width - 10,
-     id + ": Scrollbar visible");
+  if (!window.matchMedia("(-moz-overlay-scrollbars)").matches) {
+   // Check that a scrollbar is visible by comparing the width of the listitem
+   // with the width of the listbox. This is a simple way to do this without
+   // checking the anonymous content.
+   ok(listbox.firstChild.getBoundingClientRect().width < listbox.getBoundingClientRect().width - 10,
+      id + ": Scrollbar visible");
+ }
 
   var rowHeight = listbox.firstChild.getBoundingClientRect().height;
 
   listbox.focus();
   listbox.selectedIndex = 0;
   sendKey("PAGE_DOWN");
   is(listbox.selectedItem.id, id + "_item8", id + ": Page down should go to the item one visible page away");
   is(listbox.getIndexOfFirstVisibleRow(), 7, id + ": Page down should have scrolled down a visible page");
--- a/toolkit/content/tests/chrome/test_menulist_keynav.xul
+++ b/toolkit/content/tests/chrome/test_menulist_keynav.xul
@@ -83,17 +83,18 @@ function differentPressed()
   gShowPopup = true;
 
   for (let i = 0; i < 65; i++) {
     list.appendItem("Item" + i, "item" + i);
   }
   list.open = true;
   is(list.getBoundingClientRect().width, list.firstChild.getBoundingClientRect().width,
      "menu and popup width match");
-  ok(list.getBoundingClientRect().width > list.getItemAtIndex(0).getBoundingClientRect().width + 2,
+  var minScrollbarWidth = window.matchMedia("(-moz-overlay-scrollbars)").matches ? 0 : 3;
+  ok(list.getBoundingClientRect().width >= list.getItemAtIndex(0).getBoundingClientRect().width + minScrollbarWidth,
      "menuitem width accounts for scrollbar");
   list.open = false;
 
   list.menupopup.maxHeight = 100;
   list.open = true;
 
   var rowdiff = list.getItemAtIndex(1).getBoundingClientRect().top -
                 list.getItemAtIndex(0).getBoundingClientRect().top;
--- a/toolkit/content/tests/chrome/test_scrollbar.xul
+++ b/toolkit/content/tests/chrome/test_scrollbar.xul
@@ -13,17 +13,18 @@
   <body xmlns="http://www.w3.org/1999/xhtml"/>
   
   <hbox>
       <scrollbar orient="horizontal"
                  id="scroller"
                  curpos="0"
                  maxpos="600"
                  pageincrement="400"
-                 width="500"/>
+                 width="500"
+                 style="margin:0"/>
   </hbox>
   
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
 
 /** Test for Scrollbar **/
 var scrollbarTester = {
   scrollbar: null,
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -920,17 +920,17 @@ grippy {
   min-width: 0% ! important;
   min-height: 0% ! important;
   -moz-box-ordinal-group: 2147483646;
 }
 
 /********** scrollbar **********/
 
 /* Scrollbars are never flipped even if BiDI kicks in. */
-scrollbar {
+scrollbar[orient="horizontal"] {
   direction: ltr;
 }
 
 thumb {
   -moz-binding: url(chrome://global/content/bindings/scrollbar.xml#thumb);
   display: -moz-box !important;
 }
 
--- a/toolkit/themes/osx/global/nativescrollbars.css
+++ b/toolkit/themes/osx/global/nativescrollbars.css
@@ -12,16 +12,36 @@ scrollbar {
   background-color: white;
 }
 
 html|select[size]:not([size="0"]):not([size="1"]) > scrollbar,
 html|select[multiple] > scrollbar {
   -moz-appearance: scrollbar-small;
 }
 
+@media all and (-moz-overlay-scrollbars) {
+  scrollbar {
+    position: relative;
+    z-index: 2147483647;
+  }
+
+  scrollbar:not([active="true"]),
+  scrollbar[disabled="true"] {
+    visibility: hidden;
+  }
+
+  scrollbar[orient="vertical"] {
+    -moz-margin-start: -16px;
+  }
+
+  scrollbar[orient="horizontal"] {
+    margin-top: -16px;
+  }
+}
+
 /* ..... track ..... */
 
 slider {
   -moz-appearance: scrollbartrack-horizontal;
 }
 
 slider[orient="vertical"] {
   -moz-appearance: scrollbartrack-vertical;
--- a/toolkit/themes/osx/global/resizer.css
+++ b/toolkit/themes/osx/global/resizer.css
@@ -4,17 +4,19 @@
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 
 resizer {
   -moz-appearance: resizer;
   background: url("chrome://global/skin/icons/resizer.png") no-repeat;
   background-size: 100% 100%;
   cursor: se-resize;
+  min-width: 15px;
   width: 15px;
+  min-height: 15px;
   height: 15px;
 }
 @media (min-resolution: 2dppx) {
   resizer {
     background-image: url("chrome://global/skin/icons/resizer@2x.png");
     background-size: 100% 100%;
   }
 }
--- a/widget/LookAndFeel.h
+++ b/widget/LookAndFeel.h
@@ -181,16 +181,18 @@ public:
     // show the caret when text is selected?
     eIntID_ShowCaretDuringSelection,
     // select textfields when focused via tab/accesskey?
     eIntID_SelectTextfieldsOnKeyFocus,
     // delay before submenus open
     eIntID_SubmenuDelay,
     // can popups overlap menu/task bar?
     eIntID_MenusCanOverlapOSBar,
+    // should overlay scrollbars be used?
+    eIntID_UseOverlayScrollbars,
     // show/hide scrollbars based on activity
     eIntID_ShowHideScrollbars,
     // skip navigating to disabled menu item?
     eIntID_SkipNavigatingDisabledMenuItem,
     // begin a drag if the mouse is moved further than the threshold while the
     // button is down
     eIntID_DragThresholdX,
     eIntID_DragThresholdY,
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -2244,16 +2244,21 @@ NSEvent* gLastDragMouseDownEvent = nil;
   [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(systemMetricsChanged)
                                                name:NSControlTintDidChangeNotification
                                              object:nil];
   [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(systemMetricsChanged)
                                                name:NSSystemColorsDidChangeNotification
                                              object:nil];
+  // TODO: replace the string with the constant once we build with the 10.7 SDK
+  [[NSNotificationCenter defaultCenter] addObserver:self
+                                           selector:@selector(systemMetricsChanged)
+                                               name:@"NSPreferredScrollerStyleDidChangeNotification"
+                                             object:nil];
   [[NSDistributedNotificationCenter defaultCenter] addObserver:self
                                                       selector:@selector(systemMetricsChanged)
                                                           name:@"AppleAquaScrollBarVariantChanged"
                                                         object:nil
                                             suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately]; 
   [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(_surfaceNeedsUpdate:)
                                                name:NSViewGlobalFrameDidChangeNotification
--- a/widget/cocoa/nsLookAndFeel.h
+++ b/widget/cocoa/nsLookAndFeel.h
@@ -19,16 +19,18 @@ public:
                            gfxFontStyle& aFontStyle,
                            float aDevPixPerCSSPixel);
   virtual PRUnichar GetPasswordCharacterImpl()
   {
     // unicode value for the bullet character, used for password textfields.
     return 0x2022;
   }
 
+  static bool UseOverlayScrollbars();
+
 protected:
 
   // Apple hasn't defined a constant for scollbars with two arrows on each end, so we'll use this one.
   static const int kThemeScrollBarArrowsBoth = 2;
   static const int kThemeScrollBarArrowsUpperLeft = 3;
 };
 
 #endif // nsLookAndFeel_h_
--- a/widget/cocoa/nsLookAndFeel.mm
+++ b/widget/cocoa/nsLookAndFeel.mm
@@ -10,16 +10,26 @@
 #include "nsStyleConsts.h"
 #include "gfxFont.h"
 
 #import <Cocoa/Cocoa.h>
 
 // This must be included last:
 #include "nsObjCExceptions.h"
 
+enum {
+  mozNSScrollerStyleLegacy       = 0,
+  mozNSScrollerStyleOverlay      = 1
+};
+typedef NSInteger mozNSScrollerStyle;
+
+@interface NSScroller(AvailableSinceLion)
++ (mozNSScrollerStyle)preferredScrollerStyle;
+@end
+
 nsLookAndFeel::nsLookAndFeel() : nsXPLookAndFeel()
 {
 }
 
 nsLookAndFeel::~nsLookAndFeel()
 {
 }
 
@@ -336,16 +346,19 @@ nsLookAndFeel::GetIntImpl(IntID aID, int
         } else {
           aResult = eScrollArrowStyle_BothAtBottom; // The default is BothAtBottom.
         }
       }
       break;
     case eIntID_ScrollSliderStyle:
       aResult = eScrollThumbStyle_Proportional;
       break;
+    case eIntID_UseOverlayScrollbars:
+      aResult = UseOverlayScrollbars();
+      break;
     case eIntID_TreeOpenDelay:
       aResult = 1000;
       break;
     case eIntID_TreeCloseDelay:
       aResult = 1000;
       break;
     case eIntID_TreeLazyScrollDelay:
       aResult = 150;
@@ -448,16 +461,22 @@ nsLookAndFeel::GetFloatImpl(FloatID aID,
     default:
       aResult = -1.0;
       res = NS_ERROR_FAILURE;
   }
 
   return res;
 }
 
+bool nsLookAndFeel::UseOverlayScrollbars()
+{
+  return [NSScroller respondsToSelector:@selector(preferredScrollerStyle)] &&
+         [NSScroller preferredScrollerStyle] == mozNSScrollerStyleOverlay;
+}
+
 // copied from gfxQuartzFontCache.mm, maybe should go in a Cocoa utils
 // file somewhere
 static void GetStringForNSString(const NSString *aSrc, nsAString& aDest)
 {
     aDest.SetLength([aSrc length]);
     [aSrc getCharacters:aDest.BeginWriting()];
 }
 
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -21,16 +21,17 @@
 #include "nsPresContext.h"
 #include "nsGkAtoms.h"
 #include "nsCocoaFeatures.h"
 #include "nsCocoaWindow.h"
 #include "nsNativeThemeColors.h"
 #include "nsIScrollableFrame.h"
 #include "nsIDOMHTMLMeterElement.h"
 #include "mozilla/dom/Element.h"
+#include "nsLookAndFeel.h"
 
 #include "gfxContext.h"
 #include "gfxQuartzSurface.h"
 #include "gfxQuartzNativeDrawing.h"
 #include <algorithm>
 
 #define DRAW_IN_FRAME_DEBUG 0
 #define SCROLLBARS_VISUAL_DEBUG 0
@@ -2279,44 +2280,83 @@ nsNativeThemeCocoa::DrawWidgetBackground
         isVertical ||
         rangeFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
       DrawScale(cgContext, macRect, eventState, isVertical, reverseDir,
                 value, min, max, aFrame);
       break;
     }
 
     case NS_THEME_SCROLLBAR_SMALL:
-    case NS_THEME_SCROLLBAR: {
-      DrawScrollbar(cgContext, macRect, aFrame);
-    }
+    case NS_THEME_SCROLLBAR:
+      if (!nsLookAndFeel::UseOverlayScrollbars()) {
+        DrawScrollbar(cgContext, macRect, aFrame);
+      }
       break;
     case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
     case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
-#if SCROLLBARS_VISUAL_DEBUG
-      CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 0, 0.6);
-      CGContextFillRect(cgContext, macRect);
-    break;
-#endif
+      if (nsLookAndFeel::UseOverlayScrollbars()) {
+        BOOL isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL);
+        BOOL isRolledOver = CheckBooleanAttr(GetParentScrollbarFrame(aFrame),
+                                             nsGkAtoms::hover);
+        if (!isRolledOver) {
+          if (isHorizontal) {
+            macRect.origin.y += 4;
+            macRect.size.height -= 4;
+          } else {
+            macRect.origin.x += 4;
+            macRect.size.width -= 4;
+          }
+        }
+        const BOOL isOnTopOfBrightBackground = YES; // TODO: detect this properly
+        CUIDraw([NSWindow coreUIRenderer], macRect, cgContext,
+                (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
+                  @"kCUIWidgetOverlayScrollBar", @"widget",
+                  @"regular", @"size",
+                  (isRolledOver ? @"rollover" : @""), @"state",
+                  (isHorizontal ? @"kCUIOrientHorizontal" : @"kCUIOrientVertical"), @"kCUIOrientationKey",
+                  (isOnTopOfBrightBackground ? @"" : @"kCUIVariantWhite"), @"kCUIVariantKey",
+                  [NSNumber numberWithBool:YES], @"indiconly",
+                  [NSNumber numberWithBool:YES], @"kCUIThumbProportionKey",
+                  [NSNumber numberWithBool:YES], @"is.flipped",
+                  nil],
+                nil);
+      }
+      break;
     case NS_THEME_SCROLLBAR_BUTTON_UP:
     case NS_THEME_SCROLLBAR_BUTTON_LEFT:
 #if SCROLLBARS_VISUAL_DEBUG
       CGContextSetRGBFillColor(cgContext, 1.0, 0, 0, 0.6);
       CGContextFillRect(cgContext, macRect);
+#endif
     break;
-#endif
     case NS_THEME_SCROLLBAR_BUTTON_DOWN:
     case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
 #if SCROLLBARS_VISUAL_DEBUG
       CGContextSetRGBFillColor(cgContext, 0, 1.0, 0, 0.6);
       CGContextFillRect(cgContext, macRect);
-    break;      
 #endif
+    break;
     case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
     case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
-      // do nothing, drawn by scrollbar
+      if (nsLookAndFeel::UseOverlayScrollbars() &&
+          CheckBooleanAttr(GetParentScrollbarFrame(aFrame), nsGkAtoms::hover)) {
+        BOOL isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL);
+        const BOOL isOnTopOfBrightBackground = YES; // TODO: detect this properly
+        CUIDraw([NSWindow coreUIRenderer], macRect, cgContext,
+                (CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys:
+                  @"kCUIWidgetOverlayScrollBar", @"widget",
+                  @"regular", @"size",
+                  (isHorizontal ? @"kCUIOrientHorizontal" : @"kCUIOrientVertical"), @"kCUIOrientationKey",
+                  (isOnTopOfBrightBackground ? @"" : @"kCUIVariantWhite"), @"kCUIVariantKey",
+                  [NSNumber numberWithBool:YES], @"noindicator",
+                  [NSNumber numberWithBool:YES], @"kCUIThumbProportionKey",
+                  [NSNumber numberWithBool:YES], @"is.flipped",
+                  nil],
+                nil);
+      }
       break;
 
     case NS_THEME_TEXTFIELD_MULTILINE: {
       // we have to draw this by hand because there is no HITheme value for it
       CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
       
       CGContextFillRect(cgContext, macRect);
 
@@ -2478,37 +2518,46 @@ nsNativeThemeCocoa::GetWidgetBorder(nsDe
       ::GetThemeMetric(kThemeMetricListBoxFrameOutset, &frameOutset);
       aResult->SizeTo(frameOutset, frameOutset, frameOutset, frameOutset);
       break;
     }
 
     case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
     case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
     {
+      bool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL);
+
       // On Lion and later, scrollbars have no arrows.
       if (!nsCocoaFeatures::OnLionOrLater()) {
         // There's only an endcap to worry about when both arrows are on the bottom
         NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"];
         if (!buttonPlacement || [buttonPlacement isEqualToString:@"DoubleMax"]) {
-          bool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL);
-
           nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
           if (!scrollbarFrame) return NS_ERROR_FAILURE;
           bool isSmall = (scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
 
           // There isn't a metric for this, so just hardcode a best guess at the value.
           // This value is even less exact due to the fact that the endcap is partially concave.
           int32_t endcapSize = isSmall ? 5 : 6;
 
           if (isHorizontal)
             aResult->SizeTo(0, 0, 0, endcapSize);
           else
             aResult->SizeTo(endcapSize, 0, 0, 0);
         }
       }
+
+      if (nsLookAndFeel::UseOverlayScrollbars()) {
+        if (isHorizontal) {
+          aResult->SizeTo(1, 2, 1, 1);
+        } else {
+          aResult->SizeTo(2, 1, 1, 1);
+        }
+      }
+
       break;
     }
 
     case NS_THEME_STATUSBAR:
       aResult->SizeTo(1, 0, 0, 0);
       break;
   }
 
@@ -2585,17 +2634,17 @@ nsNativeThemeCocoa::GetWidgetOverflow(ns
       aOverflowRect->Inflate(m);
       return true;
     }
   }
 
   return false;
 }
 
-static const int32_t kRegularScrollbarThumbMinSize = 22;
+static const int32_t kRegularScrollbarThumbMinSize = 26;
 static const int32_t kSmallScrollbarThumbMinSize = 19;
 
 NS_IMETHODIMP
 nsNativeThemeCocoa::GetMinimumWidgetSize(nsRenderingContext* aContext,
                                          nsIFrame* aFrame,
                                          uint8_t aWidgetType,
                                          nsIntSize* aResult,
                                          bool* aIsOverridable)
@@ -2724,25 +2773,16 @@ nsNativeThemeCocoa::GetMinimumWidgetSize
     case NS_THEME_SCALE_VERTICAL:
     {
       SInt32 scaleWidth = 0;
       ::GetThemeMetric(kThemeMetricVSliderWidth, &scaleWidth);
       aResult->SizeTo(scaleWidth, scaleWidth);
       *aIsOverridable = false;
       break;
     }
-      
-    case NS_THEME_SCROLLBAR_SMALL:
-    {
-      SInt32 scrollbarWidth = 0;
-      ::GetThemeMetric(kThemeMetricSmallScrollBarWidth, &scrollbarWidth);
-      aResult->SizeTo(scrollbarWidth, scrollbarWidth);
-      *aIsOverridable = false;
-      break;
-    }
 
     case NS_THEME_SCROLLBAR_THUMB_HORIZONTAL:
     case NS_THEME_SCROLLBAR_THUMB_VERTICAL:
     {
       // Find our parent scrollbar frame in order to find out whether we're in
       // a small or a large scrollbar.
       nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
       if (!scrollbarFrame)
@@ -2751,34 +2791,41 @@ nsNativeThemeCocoa::GetMinimumWidgetSize
       bool isSmall = (scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL);
       bool isHorizontal = (aWidgetType == NS_THEME_SCROLLBAR_THUMB_HORIZONTAL);
       int32_t& minSize = isHorizontal ? aResult->width : aResult->height;
       minSize = isSmall ? kSmallScrollbarThumbMinSize : kRegularScrollbarThumbMinSize;
       break;
     }
 
     case NS_THEME_SCROLLBAR:
+    case NS_THEME_SCROLLBAR_SMALL:
     case NS_THEME_SCROLLBAR_TRACK_VERTICAL:
     case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
     {
+      *aIsOverridable = false;
+
+      if (nsLookAndFeel::UseOverlayScrollbars()) {
+        aResult->SizeTo(16, 16);
+        break;
+      }
+
       // yeah, i know i'm cheating a little here, but i figure that it
       // really doesn't matter if the scrollbar is vertical or horizontal
       // and the width metric is a really good metric for every piece
       // of the scrollbar.
 
       nsIFrame *scrollbarFrame = GetParentScrollbarFrame(aFrame);
       if (!scrollbarFrame) return NS_ERROR_FAILURE;
 
       int32_t themeMetric = (scrollbarFrame->StyleDisplay()->mAppearance == NS_THEME_SCROLLBAR_SMALL) ?
                             kThemeMetricSmallScrollBarWidth :
                             kThemeMetricScrollBarWidth;
       SInt32 scrollbarWidth = 0;
       ::GetThemeMetric(themeMetric, &scrollbarWidth);
       aResult->SizeTo(scrollbarWidth, scrollbarWidth);
-      *aIsOverridable = false;
       break;
     }
 
     case NS_THEME_SCROLLBAR_BUTTON_UP:
     case NS_THEME_SCROLLBAR_BUTTON_DOWN:
     case NS_THEME_SCROLLBAR_BUTTON_LEFT:
     case NS_THEME_SCROLLBAR_BUTTON_RIGHT:
     {
@@ -2830,18 +2877,16 @@ NS_IMETHODIMP
 nsNativeThemeCocoa::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType, 
                                      nsIAtom* aAttribute, bool* aShouldRepaint)
 {
   // Some widget types just never change state.
   switch (aWidgetType) {
     case NS_THEME_TOOLBOX:
     case NS_THEME_TOOLBAR:
     case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
-    case NS_THEME_SCROLLBAR_TRACK_VERTICAL: 
-    case NS_THEME_SCROLLBAR_TRACK_HORIZONTAL:
     case NS_THEME_STATUSBAR:
     case NS_THEME_STATUSBAR_PANEL:
     case NS_THEME_STATUSBAR_RESIZER_PANEL:
     case NS_THEME_TOOLTIP:
     case NS_THEME_TAB_PANELS:
     case NS_THEME_TAB_PANEL:
     case NS_THEME_DIALOG:
     case NS_THEME_MENUPOPUP:
@@ -2868,17 +2913,18 @@ nsNativeThemeCocoa::WidgetStateChanged(n
     *aShouldRepaint = false;
     if (aAttribute == nsGkAtoms::disabled ||
         aAttribute == nsGkAtoms::checked ||
         aAttribute == nsGkAtoms::selected ||
         aAttribute == nsGkAtoms::menuactive ||
         aAttribute == nsGkAtoms::sortDirection ||
         aAttribute == nsGkAtoms::focused ||
         aAttribute == nsGkAtoms::_default ||
-        aAttribute == nsGkAtoms::open)
+        aAttribute == nsGkAtoms::open ||
+        aAttribute == nsGkAtoms::hover)
       *aShouldRepaint = true;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNativeThemeCocoa::ThemeChanged()
@@ -2980,21 +3026,22 @@ nsNativeThemeCocoa::ThemeSupportsWidget(
     case NS_THEME_RESIZER:
     {
       nsIFrame* parentFrame = aFrame->GetParent();
       if (!parentFrame || parentFrame->GetType() != nsGkAtoms::scrollFrame)
         return true;
 
       // Note that IsWidgetStyled is not called for resizers on Mac. This is
       // because for scrollable containers, the native resizer looks better
-      // when scrollbars are present even when the style is overriden, and the
-      // custom transparent resizer looks better when scrollbars are not
-      // present.
+      // when (non-overlay) scrollbars are present even when the style is
+      // overriden, and the custom transparent resizer looks better when
+      // scrollbars are not present.
       nsIScrollableFrame* scrollFrame = do_QueryFrame(parentFrame);
-      return (scrollFrame && scrollFrame->GetScrollbarVisibility());
+      return (!nsLookAndFeel::UseOverlayScrollbars() &&
+              scrollFrame && scrollFrame->GetScrollbarVisibility());
       break;
     }
   }
 
   return false;
 }
 
 bool
@@ -3039,16 +3086,18 @@ nsNativeThemeCocoa::GetWidgetTransparenc
 {
   switch (aWidgetType) {
   case NS_THEME_MENUPOPUP:
   case NS_THEME_TOOLTIP:
     return eTransparent;
 
   case NS_THEME_SCROLLBAR_SMALL:
   case NS_THEME_SCROLLBAR:
+    return nsLookAndFeel::UseOverlayScrollbars() ? eTransparent : eOpaque;
+
   case NS_THEME_STATUSBAR:
     // Knowing that scrollbars and statusbars are opaque improves
     // performance, because we create layers for them.
     return eOpaque;
 
   default:
     return eUnknownTransparency;
   }
--- a/widget/tests/test_bug485118.xul
+++ b/widget/tests/test_bug485118.xul
@@ -53,17 +53,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 SimpleTest.waitForExplicitFinish();
 
 function runTest() {
   ["horizontal", "vertical"].forEach(function (orient) {
     ["", "Small"].forEach(function (size) {
       var elem = document.getElementById(orient + size);
       var thumbRect = document.getAnonymousElementByAttribute(elem, 'sbattr', 'scrollbar-thumb').getBoundingClientRect();
       var sizeToCheck = orient == "horizontal" ? "width" : "height";
-      var expectedSize = size == "Small" ? 19 : 22;
+      var expectedSize = size == "Small" ? 19 : 26;
       is(thumbRect[sizeToCheck], expectedSize, size + " scrollbar has wrong minimum " + sizeToCheck);
     });
   });
   SimpleTest.finish();
 }
 window.addEventListener("load", runTest, false);
 
 ]]>
--- a/widget/windows/nsTextStore.cpp
+++ b/widget/windows/nsTextStore.cpp
@@ -43,18 +43,16 @@ using namespace mozilla::widget;
  *   "TSF: 0x%p   nsFoo::Bar("
  * When a static method is called, start with following text:
  *   "TSF: nsFoo::Bar("
  */
 
 PRLogModuleInfo* sTextStoreLog = nullptr;
 #endif // #ifdef PR_LOGGING
 
-#define IS_SEARCH static_cast<InputScope>(50)
-
 /******************************************************************/
 /* InputScopeImpl                                                 */
 /******************************************************************/
 
 class InputScopeImpl MOZ_FINAL : public ITfInputScope
 {
 public:
   InputScopeImpl(const nsTArray<InputScope>& aList) :
--- a/widget/windows/nsTextStore.h
+++ b/widget/windows/nsTextStore.h
@@ -19,16 +19,19 @@
 
 // GUID_PROP_INPUTSCOPE is declared in inputscope.h using INIT_GUID.
 // With initguid.h, we get its instance instead of extern declaration.
 #ifdef INPUTSCOPE_INIT_GUID
 #include <initguid.h>
 #endif
 #include <inputscope.h>
 
+// TSF InputScope, for earlier SDK 8
+#define IS_SEARCH static_cast<InputScope>(50)
+
 struct ITfThreadMgr;
 struct ITfDocumentMgr;
 struct ITfDisplayAttributeMgr;
 struct ITfCategoryMgr;
 class nsWindow;
 class nsTextEvent;
 #ifdef MOZ_METRO
 class MetroWidget;
--- a/widget/xpwidgets/nsXPLookAndFeel.cpp
+++ b/widget/xpwidgets/nsXPLookAndFeel.cpp
@@ -43,16 +43,19 @@ nsLookAndFeelIntPref nsXPLookAndFeel::sI
     eIntID_DragThresholdY,
     false, 0 },
   { "ui.useAccessibilityTheme",
     eIntID_UseAccessibilityTheme,
     false, 0 },
   { "ui.menusCanOverlapOSBar",
     eIntID_MenusCanOverlapOSBar,
     false, 0 },
+  { "ui.useOverlayScrollbars",
+    eIntID_UseOverlayScrollbars,
+    false, 0 },
   { "ui.showHideScrollbars",
     eIntID_ShowHideScrollbars,
     false, 0 },
   { "ui.skipNavigatingDisabledMenuItem",
     eIntID_SkipNavigatingDisabledMenuItem,
     false, 0 },
   { "ui.treeOpenDelay",
     eIntID_TreeOpenDelay,