Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 24 Jan 2014 16:51:04 -0500
changeset 181105 fdc82b2c5584323dfd7deaaa0601e596d6725578
parent 181061 86d2f0068a499f4fd1b3548955306eacfd73957e (current diff)
parent 181104 d319f9ddf227f214bff261fe81fd1638379ade32 (diff)
child 181136 a12c7d7ac590402510356d33fc6acd4f5e9c1b1a
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone29.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 inbound to m-c.
--- a/browser/devtools/webconsole/hudservice.js
+++ b/browser/devtools/webconsole/hudservice.js
@@ -6,19 +6,19 @@
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 
 let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
 let Heritage = require("sdk/core/heritage");
 
-loader.lazyGetter(this, "promise", () => require("sdk/core/promise"));
 loader.lazyGetter(this, "Telemetry", () => require("devtools/shared/telemetry"));
 loader.lazyGetter(this, "WebConsoleFrame", () => require("devtools/webconsole/webconsole").WebConsoleFrame);
+loader.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
 loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
 loader.lazyImporter(this, "devtools", "resource://gre/modules/devtools/Loader.jsm");
 loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
 loader.lazyImporter(this, "DebuggerServer", "resource://gre/modules/devtools/dbg-server.jsm");
 loader.lazyImporter(this, "DebuggerClient", "resource://gre/modules/devtools/dbg-client.jsm");
 
 const STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties";
 let l10n = new WebConsoleUtils.l10n(STRINGS_URI);
@@ -105,16 +105,17 @@ HUD_SERVICE.prototype =
    *        The window of the browser console owner.
    * @return object
    *         A promise object for the opening of the new BrowserConsole instance.
    */
   openBrowserConsole:
   function HS_openBrowserConsole(aTarget, aIframeWindow, aChromeWindow)
   {
     let hud = new BrowserConsole(aTarget, aIframeWindow, aChromeWindow);
+    this._browserConsoleID = hud.hudId;
     this.consoles.set(hud.hudId, hud);
     return hud.init();
   },
 
   /**
    * Returns the Web Console object associated to a content window.
    *
    * @param nsIDOMWindow aContentWindow
@@ -236,17 +237,16 @@ HUD_SERVICE.prototype =
       });
 
       return deferred.promise;
     }
 
     connect().then(getTarget).then(openWindow).then((aWindow) => {
       this.openBrowserConsole(target, aWindow, aWindow)
         .then((aBrowserConsole) => {
-          this._browserConsoleID = aBrowserConsole.hudId;
           this._browserConsoleDefer.resolve(aBrowserConsole);
           this._browserConsoleDefer = null;
         })
     }, console.error);
 
     return this._browserConsoleDefer.promise;
   },
 
--- a/browser/devtools/webconsole/panel.js
+++ b/browser/devtools/webconsole/panel.js
@@ -1,17 +1,17 @@
 /* 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/. */
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 
-loader.lazyGetter(this, "promise", () => require("sdk/core/promise"));
+loader.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
 loader.lazyGetter(this, "HUDService", () => require("devtools/webconsole/hudservice"));
 loader.lazyGetter(this, "EventEmitter", () => require("devtools/shared/event-emitter"));
 
 /**
  * A DevToolPanel that controls the Web Console.
  */
 function WebConsolePanel(iframeWindow, toolbox)
 {
--- a/browser/devtools/webconsole/test/browser_console_dead_objects.js
+++ b/browser/devtools/webconsole/test/browser_console_dead_objects.js
@@ -44,17 +44,20 @@ function test()
           "dead object found");
 
     hud.jsterm.setInputValue("foobarzTezt");
 
     for (let c of ".hello") {
       EventUtils.synthesizeKey(c, {}, hud.iframeWindow);
     }
 
-    hud.jsterm.execute(null, onReadProperty.bind(null, msg));
+    hud.jsterm.execute(null, () => {
+      // executeSoon() is needed to get out of the execute() event loop.
+      executeSoon(onReadProperty.bind(null, msg));
+    });
   }
 
   function onReadProperty(deadObjectMessage)
   {
     isnot(hud.outputNode.textContent.indexOf("can't access dead object"), -1,
           "'cannot access dead object' message found");
 
     // Click the second execute output.
@@ -64,16 +67,17 @@ function test()
           "message text check");
 
     hud.jsterm.once("variablesview-fetched", onFetched);
     EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
   }
 
   function onFetched()
   {
+    ok(true, "variables view fetched");
     hud.jsterm.execute("delete window.foobarzTezt; 2013-26", onCalcResult);
   }
 
   function onCalcResult()
   {
     isnot(hud.outputNode.textContent.indexOf("1987"), -1, "result message found");
 
     // executeSoon() is needed to get out of the execute() event loop.
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_613642_maintain_scroll.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_613642_maintain_scroll.js
@@ -90,47 +90,34 @@ function testGen() {
       // Wait for scroll to bottom.
       return;
     }
     scrollBox.onscroll = null;
     isnot(scrollBox.scrollTop, 0, "scroll location updated (moved to bottom)");
     testNext();
   };
   EventUtils.synthesizeKey("VK_END", {});
-  yield;
+  yield undefined;
 
   let oldScrollTop = scrollBox.scrollTop;
 
   content.console.log("test message 151");
 
-  waitForMessages({
-    webconsole: hud,
-    messages: [{
-      text: "test message 151",
-      category: CATEGORY_WEBDEV,
-      severity: SEVERITY_LOG,
-    }],
-  }).then(() => {
-    scrollBox.onscroll = () => {
-      if (scrollBox.scrollTop == oldScrollTop) {
-        // Wait for scroll to change.
-        return;
-      }
-      scrollBox.onscroll = null;
-      isnot(scrollBox.scrollTop, oldScrollTop, "scroll location updated (moved to bottom again)");
-      testNext();
-    };
-  });
+  scrollBox.onscroll = () => {
+    if (scrollBox.scrollTop == oldScrollTop) {
+      // Wait for scroll to change.
+      return;
+    }
+    scrollBox.onscroll = null;
+    isnot(scrollBox.scrollTop, oldScrollTop, "scroll location updated (moved to bottom again)");
+    hud = testDriver = null;
+    finishTest();
+  };
 
   yield undefined;
-
-  hud = testDriver = null;
-  finishTest();
-  
-  yield undefined;
 }
 
 function test() {
   addTab("data:text/html;charset=utf-8,Web Console test for bug 613642: remember scroll location");
   browser.addEventListener("load", function tabLoad(aEvent) {
     browser.removeEventListener(aEvent.type, tabLoad, true);
     openConsole(null, function(aHud) {
       hud = aHud;
--- a/browser/devtools/webconsole/test/head.js
+++ b/browser/devtools/webconsole/test/head.js
@@ -1,17 +1,17 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 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/. */
 
 let WebConsoleUtils, TargetFactory, require;
 let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
-let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
 
 (() => {
   let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
   let utils = devtools.require("devtools/toolkit/webconsole/utils");
   TargetFactory = devtools.TargetFactory;
   WebConsoleUtils = utils.Utils;
   require = devtools.require;
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -9,17 +9,17 @@
 const {Cc, Ci, Cu} = require("chrome");
 
 let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
 
 loader.lazyServiceGetter(this, "clipboardHelper",
                          "@mozilla.org/widget/clipboardhelper;1",
                          "nsIClipboardHelper");
 loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
-loader.lazyGetter(this, "promise", () => require("sdk/core/promise"));
+loader.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
 loader.lazyGetter(this, "EventEmitter", () => require("devtools/shared/event-emitter"));
 loader.lazyGetter(this, "AutocompletePopup",
                   () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
 loader.lazyGetter(this, "ToolSidebar",
                   () => require("devtools/framework/sidebar").ToolSidebar);
 loader.lazyGetter(this, "NetworkPanel",
                   () => require("devtools/webconsole/network-panel").NetworkPanel);
 loader.lazyGetter(this, "ConsoleOutput",
--- a/browser/installer/windows/nsis/installer.nsi
+++ b/browser/installer/windows/nsis/installer.nsi
@@ -1043,16 +1043,20 @@ Function .onInit
   System::Call 'kernel32::SetDllDirectoryW(w "")'
 
   StrCpy $PageName ""
   StrCpy $LANGUAGE 0
   ${SetBrandNameVars} "$EXEDIR\core\distribution\setup.ini"
 
   ${InstallOnInitCommon} "$(WARN_MIN_SUPPORTED_OS_MSG)"
 
+  ${If} ${AtLeastWinVista}
+    System::Call 'user32::SetProcessDPIAware()'
+  ${EndIf}
+
   !insertmacro InitInstallOptionsFile "options.ini"
   !insertmacro InitInstallOptionsFile "shortcuts.ini"
   !insertmacro InitInstallOptionsFile "components.ini"
   !insertmacro InitInstallOptionsFile "summary.ini"
 
   WriteINIStr "$PLUGINSDIR\options.ini" "Settings" NumFields "5"
 
   WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Type   "label"
--- a/browser/installer/windows/nsis/maintenanceservice_installer.nsi
+++ b/browser/installer/windows/nsis/maintenanceservice_installer.nsi
@@ -127,16 +127,20 @@ Function .onInit
   ${EndUnless}
 FunctionEnd
 
 Function un.onInit
   ; Remove the current exe directory from the search order.
   ; This only effects LoadLibrary calls and not implicitly loaded DLLs.
   System::Call 'kernel32::SetDllDirectoryW(w "")'
 
+  ${If} ${AtLeastWinVista}
+    System::Call 'user32::SetProcessDPIAware()'
+  ${EndIf}
+
   StrCpy $BrandFullNameDA "${MaintFullName}"
   StrCpy $BrandFullName "${MaintFullName}"
 FunctionEnd
 
 Section "MaintenanceService"
   AllowSkipFiles off
 
   CreateDirectory $INSTDIR
--- a/browser/installer/windows/nsis/stub.nsi
+++ b/browser/installer/windows/nsis/stub.nsi
@@ -331,16 +331,20 @@ Function .onInit
       Quit
     ${EndIf}
   ${EndUnless}
 !endif
 
   ; Require elevation if the user can elevate
   ${ElevateUAC}
 
+  ${If} ${AtLeastWinVista}
+    System::Call 'user32::SetProcessDPIAware()'
+  ${EndIf}
+
   ; Create a mutex to prevent multiple launches of the same stub installer in
   ; the same location on the file system. This intentionally won't handle the
   ; case where someone runs multiple copies of the stub on the file system but
   ; it does handle the important case which is a user launching the same stub
   ; multiple times.
   StrCpy $1 "$EXEPATH"
   ; Backslashes are illegal in a mutex name so replace all occurences of a
   ; backslash with a forward slash.
--- a/browser/installer/windows/nsis/uninstaller.nsi
+++ b/browser/installer/windows/nsis/uninstaller.nsi
@@ -680,16 +680,20 @@ Function un.onInit
   ; Remove the current exe directory from the search order.
   ; This only effects LoadLibrary calls and not implicitly loaded DLLs.
   System::Call 'kernel32::SetDllDirectoryW(w "")'
 
   StrCpy $LANGUAGE 0
 
   ${un.UninstallUnOnInitCommon}
 
+  ${If} ${AtLeastWinVista}
+    System::Call 'user32::SetProcessDPIAware()'
+  ${EndIf}
+
   !insertmacro InitInstallOptionsFile "unconfirm.ini"
 FunctionEnd
 
 Function .onGUIEnd
   ${OnEndCommon}
 FunctionEnd
 
 Function un.onGUIEnd
--- a/content/base/src/CSPUtils.jsm
+++ b/content/base/src/CSPUtils.jsm
@@ -381,42 +381,27 @@ CSPRep.fromString = function(aStr, self,
       for (let i in uriStrings) {
         var uri = null;
         try {
           // Relative URIs are okay, but to ensure we send the reports to the
           // right spot, the relative URIs are expanded here during parsing.
           // The resulting CSPRep instance will have only absolute URIs.
           uri = gIoService.newURI(uriStrings[i],null,selfUri);
 
-          // if there's no host, don't do the ETLD+ check.  This will throw
-          // NS_ERROR_FAILURE if the URI doesn't have a host, causing a parse
-          // failure.
+          // if there's no host, this will throw NS_ERROR_FAILURE, causing a
+          // parse failure.
           uri.host;
 
-          // Verify that each report URI is in the same etld + 1 and that the
-          // scheme and port match "self" if "self" is defined, and just that
-          // it's valid otherwise.
-          if (self) {
-            if (gETLDService.getBaseDomain(uri) !==
-                gETLDService.getBaseDomain(selfUri)) {
-              cspWarn(aCSPR,
-                      CSPLocalizer.getFormatStr("reportURInotETLDPlus1",
-                                                [gETLDService.getBaseDomain(uri)]));
-              continue;
-            }
-            if (!uri.schemeIs(selfUri.scheme)) {
-              cspWarn(aCSPR, CSPLocalizer.getFormatStr("reportURInotSameSchemeAsSelf",
-                                                       [uri.asciiSpec]));
-              continue;
-            }
-            if (uri.port && uri.port !== selfUri.port) {
-              cspWarn(aCSPR, CSPLocalizer.getFormatStr("reportURInotSamePortAsSelf",
-                                                       [uri.asciiSpec]));
-              continue;
-            }
+          // warn about, but do not prohibit non-http and non-https schemes for
+          // reporting URIs.  The spec allows unrestricted URIs resolved
+          // relative to "self", but we should let devs know if the scheme is
+          // abnormal and may fail a POST.
+          if (!uri.schemeIs("http") && !uri.schemeIs("https")) {
+            cspWarn(aCSPR, CSPLocalizer.getFormatStr("reportURInotHttpsOrHttp",
+                                                     [uri.asciiSpec]));
           }
         } catch(e) {
           switch (e.result) {
             case Components.results.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS:
             case Components.results.NS_ERROR_HOST_IS_IP_ADDRESS:
               if (uri.host !== selfUri.host) {
                 cspWarn(aCSPR,
                         CSPLocalizer.getFormatStr("pageCannotSendReportsTo",
@@ -426,17 +411,17 @@ CSPRep.fromString = function(aStr, self,
               break;
 
             default:
               cspWarn(aCSPR, CSPLocalizer.getFormatStr("couldNotParseReportURI",
                                                        [uriStrings[i]]));
               continue;
           }
         }
-        // all verification passed: same ETLD+1, scheme, and port.
+        // all verification passed
         okUriStrings.push(uri.asciiSpec);
       }
       aCSPR._directives[UD.REPORT_URI] = okUriStrings.join(' ');
       continue directive;
     }
 
     // POLICY URI //////////////////////////////////////////////////////////
     if (dirname === UD.POLICY_URI) {
@@ -644,44 +629,27 @@ CSPRep.fromStringSpecCompliant = functio
       for (let i in uriStrings) {
         var uri = null;
         try {
           // Relative URIs are okay, but to ensure we send the reports to the
           // right spot, the relative URIs are expanded here during parsing.
           // The resulting CSPRep instance will have only absolute URIs.
           uri = gIoService.newURI(uriStrings[i],null,selfUri);
 
-          // if there's no host, don't do the ETLD+ check.  This will throw
-          // NS_ERROR_FAILURE if the URI doesn't have a host, causing a parse
-          // failure.
+          // if there's no host, this will throw NS_ERROR_FAILURE, causing a
+          // parse failure.
           uri.host;
 
-          // Verify that each report URI is in the same etld + 1 and that the
-          // scheme and port match "self" if "self" is defined, and just that
-          // it's valid otherwise.
-          if (self) {
-            if (gETLDService.getBaseDomain(uri) !==
-                gETLDService.getBaseDomain(selfUri)) {
-              cspWarn(aCSPR, 
-                      CSPLocalizer.getFormatStr("reportURInotETLDPlus1",
-                                                [gETLDService.getBaseDomain(uri)]));
-              continue;
-            }
-            if (!uri.schemeIs(selfUri.scheme)) {
-              cspWarn(aCSPR,
-                      CSPLocalizer.getFormatStr("reportURInotSameSchemeAsSelf",
-                                                [uri.asciiSpec]));
-              continue;
-            }
-            if (uri.port && uri.port !== selfUri.port) {
-              cspWarn(aCSPR,
-                      CSPLocalizer.getFormatStr("reportURInotSamePortAsSelf",
-                                                [uri.asciiSpec]));
-              continue;
-            }
+          // warn about, but do not prohibit non-http and non-https schemes for
+          // reporting URIs.  The spec allows unrestricted URIs resolved
+          // relative to "self", but we should let devs know if the scheme is
+          // abnormal and may fail a POST.
+          if (!uri.schemeIs("http") && !uri.schemeIs("https")) {
+            cspWarn(aCSPR, CSPLocalizer.getFormatStr("reportURInotHttpsOrHttp",
+                                                     [uri.asciiSpec]));
           }
         } catch(e) {
           switch (e.result) {
             case Components.results.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS:
             case Components.results.NS_ERROR_HOST_IS_IP_ADDRESS:
               if (uri.host !== selfUri.host) {
                 cspWarn(aCSPR, CSPLocalizer.getFormatStr("pageCannotSendReportsTo",
                                                          [selfUri.host, uri.host]));
@@ -690,17 +658,17 @@ CSPRep.fromStringSpecCompliant = functio
               break;
 
             default:
               cspWarn(aCSPR, CSPLocalizer.getFormatStr("couldNotParseReportURI", 
                                                        [uriStrings[i]]));
               continue;
           }
         }
-        // all verification passed: same ETLD+1, scheme, and port.
+        // all verification passed.
        okUriStrings.push(uri.asciiSpec);
       }
       aCSPR._directives[UD.REPORT_URI] = okUriStrings.join(' ');
       continue directive;
     }
 
     // POLICY URI //////////////////////////////////////////////////////////
     if (dirname === UD.POLICY_URI) {
--- a/content/base/test/unit/test_csputils.js
+++ b/content/base/test/unit/test_csputils.js
@@ -660,71 +660,88 @@ test(function test_FrameAncestor_ignores
       do_check_true(testPermits(URI("http://user1:pass1@self.com/foo"),
                                 URI("http://username:password@self.com/bar")));
       do_check_true(testPermits(URI("http://self.com/foo"),
                                 URI("http://username:password@self.com/bar")));
      });
 
 test(function test_CSP_ReportURI_parsing() {
       var cspr;
-      var SD = CSPRep.SRC_DIRECTIVES_OLD;
+      var SD = CSPRep.SRC_DIRECTIVES_NEW;
       var self = "http://self.com:34";
       var parsedURIs = [];
 
       var uri_valid_absolute = self + "/report.py";
-      var uri_invalid_host_absolute = "http://foo.org:34/report.py";
+      var uri_other_host_absolute = "http://foo.org:34/report.py";
       var uri_valid_relative = "/report.py";
       var uri_valid_relative_expanded = self + uri_valid_relative;
       var uri_valid_relative2 = "foo/bar/report.py";
       var uri_valid_relative2_expanded = self + "/" + uri_valid_relative2;
       var uri_invalid_relative = "javascript:alert(1)";
+      var uri_other_scheme_absolute = "https://self.com/report.py";
+      var uri_other_scheme_and_host_absolute = "https://foo.com/report.py";
 
-      cspr = CSPRep.fromString("allow *; report-uri " + uri_valid_absolute, URI(self));
+      cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_valid_absolute, URI(self));
       parsedURIs = cspr.getReportURIs().split(/\s+/);
       do_check_in_array(parsedURIs, uri_valid_absolute);
       do_check_eq(parsedURIs.length, 1);
 
-      cspr = CSPRep.fromString("allow *; report-uri " + uri_invalid_host_absolute, URI(self));
+      cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_other_host_absolute, URI(self));
       parsedURIs = cspr.getReportURIs().split(/\s+/);
-      do_check_in_array(parsedURIs, "");
+      do_check_in_array(parsedURIs, uri_other_host_absolute);
       do_check_eq(parsedURIs.length, 1); // the empty string is in there.
 
-      cspr = CSPRep.fromString("allow *; report-uri " + uri_invalid_relative, URI(self));
+      cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_invalid_relative, URI(self));
       parsedURIs = cspr.getReportURIs().split(/\s+/);
       do_check_in_array(parsedURIs, "");
       do_check_eq(parsedURIs.length, 1);
 
-      cspr = CSPRep.fromString("allow *; report-uri " + uri_valid_relative, URI(self));
+      cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_valid_relative, URI(self));
       parsedURIs = cspr.getReportURIs().split(/\s+/);
       do_check_in_array(parsedURIs, uri_valid_relative_expanded);
       do_check_eq(parsedURIs.length, 1);
 
-      cspr = CSPRep.fromString("allow *; report-uri " + uri_valid_relative2, URI(self));
+      cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_valid_relative2, URI(self));
       parsedURIs = cspr.getReportURIs().split(/\s+/);
       dump(parsedURIs.length);
       do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
       do_check_eq(parsedURIs.length, 1);
 
+      // make sure cross-scheme reporting works
+      cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_other_scheme_absolute, URI(self));
+      parsedURIs = cspr.getReportURIs().split(/\s+/);
+      dump(parsedURIs.length);
+      do_check_in_array(parsedURIs, uri_other_scheme_absolute);
+      do_check_eq(parsedURIs.length, 1);
+
+      // make sure cross-scheme, cross-host reporting works
+      cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " + uri_other_scheme_and_host_absolute, URI(self));
+      parsedURIs = cspr.getReportURIs().split(/\s+/);
+      dump(parsedURIs.length);
+      do_check_in_array(parsedURIs, uri_other_scheme_and_host_absolute);
+      do_check_eq(parsedURIs.length, 1);
+
       // combination!
-      cspr = CSPRep.fromString("allow *; report-uri " +
+      cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " +
                                uri_valid_relative2 + " " +
                                uri_valid_absolute, URI(self));
       parsedURIs = cspr.getReportURIs().split(/\s+/);
       do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
       do_check_in_array(parsedURIs, uri_valid_absolute);
       do_check_eq(parsedURIs.length, 2);
 
-      cspr = CSPRep.fromString("allow *; report-uri " +
+      cspr = CSPRep.fromStringSpecCompliant("default-src *; report-uri " +
                                uri_valid_relative2 + " " +
-                               uri_invalid_host_absolute + " " +
+                               uri_other_host_absolute + " " +
                                uri_valid_absolute, URI(self));
       parsedURIs = cspr.getReportURIs().split(/\s+/);
       do_check_in_array(parsedURIs, uri_valid_relative2_expanded);
+      do_check_in_array(parsedURIs, uri_other_host_absolute);
       do_check_in_array(parsedURIs, uri_valid_absolute);
-      do_check_eq(parsedURIs.length, 2);
+      do_check_eq(parsedURIs.length, 3);
     });
 
 test(
      function test_bug634778_duplicateDirective_Detection() {
       var cspr;
       var SD = CSPRep.SRC_DIRECTIVES_OLD;
       var self = "http://self.com:34";
       var firstDomain = "http://first.com";
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1138,20 +1138,22 @@ Navigator::RequestWakeLock(const nsAStri
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   nsRefPtr<power::PowerManagerService> pmService =
     power::PowerManagerService::GetInstance();
   // Maybe it went away for some reason... Or maybe we're just called
   // from our XPCOM method.
-  NS_ENSURE_TRUE(pmService, nullptr);
+  if (!pmService) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
 
-  ErrorResult rv;
-  return pmService->NewWakeLock(aTopic, mWindow, rv);
+  return pmService->NewWakeLock(aTopic, mWindow, aRv);
 }
 
 nsIDOMMozMobileMessageManager*
 Navigator::GetMozMobileMessage()
 {
   if (!mMobileMessageManager) {
     // Check that our window has not gone away
     NS_ENSURE_TRUE(mWindow, nullptr);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -2776,17 +2776,18 @@ ResolvePrototype(nsIXPConnect *aXPConnec
       JSAutoCompartment ac(cx, winobj);
 
       JS::Rooted<JS::Value> val(cx);
       if (!JS_LookupProperty(cx, winobj, CutPrefix(class_parent_name), &val)) {
         return NS_ERROR_UNEXPECTED;
       }
 
       if (val.isObject()) {
-        if (!JS_LookupProperty(cx, &val.toObject(), "prototype", &val)) {
+        JS::Rooted<JSObject*> obj(cx, &val.toObject());
+        if (!JS_LookupProperty(cx, obj, "prototype", &val)) {
           return NS_ERROR_UNEXPECTED;
         }
 
         if (val.isObject()) {
           proto = &val.toObject();
         }
       }
     }
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -6055,17 +6055,17 @@ class CGEnumerateHook(CGAbstractBindingM
                 "}\n"
                 "return true;"))
 
 class CppKeywords():
     """
     A class for checking if method names declared in webidl
     are not in conflict with C++ keywords.
     """
-    keywords = frozenset(['alignas', 'alignof', 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor', 'bool',
+    keywords = frozenset(['alignas', 'alignof', 'and', 'and_eq', 'asm', 'assert', 'auto', 'bitand', 'bitor', 'bool',
     'break', 'case', 'catch', 'char', 'char16_t', 'char32_t', 'class', 'compl', 'const', 'constexpr',
     'const_cast', 'continue', 'decltype', 'default', 'delete', 'do', 'double', 'dynamic_cast', 'else', 'enum',
     'explicit', 'export', 'extern', 'false', 'final', 'float', 'for', 'friend', 'goto', 'if', 'inline',
     'int', 'long', 'mutable', 'namespace', 'new', 'noexcept', 'not', 'not_eq', 'nullptr', 'operator',
     'or', 'or_eq', 'override', 'private', 'protected', 'public', 'register', 'reinterpret_cast', 'return',
     'short', 'signed', 'sizeof', 'static', 'static_assert', 'static_cast', 'struct', 'switch', 'template',
     'this', 'thread_local', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'union', 'unsigned',
     'using', 'virtual', 'void', 'volatile', 'wchar_t', 'while', 'xor', 'xor_eq'])
--- a/dom/events/nsEventStateManager.cpp
+++ b/dom/events/nsEventStateManager.cpp
@@ -2159,16 +2159,25 @@ nsEventStateManager::GenerateDragGesture
       WidgetDragEvent* event = &startEvent;
       if (status != nsEventStatus_eConsumeNoDefault) {
         status = nsEventStatus_eIgnore;
         nsEventDispatcher::Dispatch(targetContent, aPresContext, &gestureEvent, nullptr,
                                     &status);
         event = &gestureEvent;
       }
 
+      nsCOMPtr<nsIObserverService> observerService =
+        mozilla::services::GetObserverService();
+      // Emit observer event to allow addons to modify the DataTransfer object.
+      if (observerService) {
+        observerService->NotifyObservers(dataTransfer,
+                                         "on-datatransfer-available",
+                                         nullptr);
+      }
+
       // now that the dataTransfer has been updated in the dragstart and
       // draggesture events, make it read only so that the data doesn't
       // change during the drag.
       dataTransfer->SetReadOnly();
 
       if (status != nsEventStatus_eConsumeNoDefault) {
         bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
                                               targetContent, selection);
--- a/dom/locales/en-US/chrome/security/csp.properties
+++ b/dom/locales/en-US/chrome/security/csp.properties
@@ -20,23 +20,19 @@ errorWas = error was: "%1$S"
 # %1$S is the report URI that could not be parsed
 couldNotParseReportURI = couldn't parse report URI: %1$S
 # LOCALIZATION NOTE (couldNotProcessUnknownDirective):
 # %1$S is the unknown directive
 couldNotProcessUnknownDirective = Couldn't process unknown directive '%1$S'
 # LOCALIZATION NOTE (ignoringUnknownOption):
 # %1$S is the option that could not be understood
 ignoringUnknownOption = Ignoring unknown option %1$S
-# LOCALIZATION NOTE (reportURInotETLDPlus1):
-# %1$S is the ETLD of the report URI that could not be used
-reportURInotETLDPlus1 = The report URI (%1$S) must be from the same eTLD+1.
-# LOCALIZATION NOTE (reportURInotSameSchemeAsSelf, reportURInotSamePortAsSelf):
-# %1$S is the report URI that could not be used
-reportURInotSameSchemeAsSelf = The report URI (%1$S) must use the same scheme as the originating document.
-reportURInotSamePortAsSelf = The report URI (%1$S) must use the same port as the originating document.
+# LOCALIZATION NOTE (reportURInotHttpsOrHttp):
+# %1$S is the ETLD of the report URI that is not HTTP or HTTPS
+reportURInotHttpsOrHttp = The report URI (%1$) should be an HTTP or HTTPS URI.
 # LOCALIZATION NOTE (pageCannotSendReportsTo):
 # %1$S is the URI of the page with the policy
 # %2$S is the report URI that could not be used
 pageCannotSendReportsTo = page on %1$S cannot send reports to %2$S
 allowOrDefaultSrcRequired = 'allow' or 'default-src' directive required but not present.  Reverting to "default-src 'none'"
 # LOCALIZATION NOTE (failedToParseUnrecognizedSource):
 # %1$S is the CSP Source that could not be parsed
 failedToParseUnrecognizedSource = Failed to parse unrecognized source %1$S
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -1560,23 +1560,27 @@ PeerConnectionWrapper.prototype = {
       return n;
     }
 
     // Use spec way of enumerating stats
     var counters = {};
     for (var key in stats) {
       if (stats.hasOwnProperty(key)) {
         var res = stats[key];
-        counters[res.type] = toNum(counters[res.type]) + 1;
+        if (!res.isRemote) {
+          counters[res.type] = toNum(counters[res.type]) + 1;
+        }
       }
     }
     // Use MapClass way of enumerating stats
     var counters2 = {};
     stats.forEach(function(res) {
-        counters2[res.type] = toNum(counters2[res.type]) + 1;
+        if (!res.isRemote) {
+          counters2[res.type] = toNum(counters2[res.type]) + 1;
+        }
       });
     is(JSON.stringify(counters), JSON.stringify(counters2),
        "Spec and MapClass variant of RTCStatsReport enumeration agree");
     var nin = numTracks(this._pc.getRemoteStreams());
     var nout = numTracks(this._pc.getLocalStreams());
 
     // TODO(Bug 957145): Restore stronger inboundrtp test once Bug 948249 is fixed
     //is(toNum(counters["inboundrtp"]), nin, "Have " + nin + " inboundrtp stat(s)");
--- a/dom/power/test/mochitest.ini
+++ b/dom/power/test/mochitest.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 
+[test_bug957893.html]
 [test_bug957899.html]
 [test_power_basics.html]
 [test_power_set_cpusleepallowed.html]
 [test_power_set_screen_brightness.html]
 [test_power_set_screen_enabled.html]
new file mode 100644
--- /dev/null
+++ b/dom/power/test/test_bug957893.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test bug 957893 - Crash in WakeLock</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+ <script type="application/javascript">
+ try {
+   var wl = navigator.requestWakeLock('');
+   ok(false, "RequestWakeLock throws an exception!");
+ } catch(e) {
+   ok(true, "RequestWakeLock throws an exception!");
+ }
+
+ info("Still alive!");
+
+ </script>
+</body>
+</html>
--- a/dom/system/NetworkGeolocationProvider.js
+++ b/dom/system/NetworkGeolocationProvider.js
@@ -145,19 +145,19 @@ WifiGeoPositionProvider.prototype = {
 
     Cc["@mozilla.org/geolocation/service;1"].getService(Ci.nsIGeolocationUpdate)
         .locationUpdatePending();
 
     let url = Services.urlFormatter.formatURLPref("geo.wifi.uri");
 
     function isPublic(ap) {
         let mask = "_nomap"
-        let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length) == -1;
+        let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length);
         if (result != -1) {
-            LOG("Filtering out " + ap.ssid);
+            LOG("Filtering out " + ap.ssid + " " + result);
         }
         return result;
     };
 
     function sort(a, b) {
       return b.signal - a.signal;
     };
 
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -955,18 +955,16 @@ public:
     nsRefPtr<gfxASurface> surface = mDeprecatedSurface.get();
     return surface.forget();
   }
 
   gfx::IntSize GetSize() { return mSize; }
 
   CairoImage() : Image(nullptr, CAIRO_SURFACE) {}
 
-private:
-
   nsCountedRef<nsMainThreadSurfaceRef> mDeprecatedSurface;
   gfx::IntSize mSize;
 
   // mSourceSurface wraps mDeprrecatedSurface's data, therefore it should not
   // outlive mDeprecatedSurface
   nsCountedRef<nsMainThreadSourceSurfaceRef> mSourceSurface;
 };
 
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -143,17 +143,19 @@ ContentClientRemoteBuffer::BeginPaint()
 void
 ContentClientRemoteBuffer::EndPaint()
 {
   // XXX: We might still not have a texture client if PaintThebes
   // decided we didn't need one yet because the region to draw was empty.
   SetBufferProvider(nullptr);
   SetBufferProviderOnWhite(nullptr);
   for (unsigned i = 0; i< mOldTextures.Length(); ++i) {
-    mOldTextures[i]->Unlock();
+    if (mOldTextures[i]->IsLocked()) {
+      mOldTextures[i]->Unlock();
+    }
   }
   mOldTextures.Clear();
 
   if (mTextureClient) {
     mTextureClient->Unlock();
   }
   if (mTextureClientOnWhite) {
     mTextureClientOnWhite->Unlock();
@@ -552,16 +554,25 @@ ContentClientDoubleBuffered::SwapBuffers
   ContentClientRemoteBuffer::SwapBuffers(aFrontUpdatedRegion);
 }
 
 void
 ContentClientDoubleBuffered::PrepareFrame()
 {
   mIsNewBuffer = false;
 
+  if (mTextureClient) {
+    DebugOnly<bool> locked = mTextureClient->Lock(OPEN_READ_WRITE);
+    MOZ_ASSERT(locked);
+  }
+  if (mTextureClientOnWhite) {
+    DebugOnly<bool> locked = mTextureClientOnWhite->Lock(OPEN_READ_WRITE);
+    MOZ_ASSERT(locked);
+  }
+
   if (!mFrontAndBackBufferDiffer) {
     return;
   }
 
   if (mDidSelfCopy) {
     // We can't easily draw our front buffer into us, since we're going to be
     // copying stuff around anyway it's easiest if we just move our situation
     // to non-rotated while we're at it. If this situation occurs we'll have
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -559,17 +559,17 @@ BufferTextureClient::GetAsDrawTarget()
 
 bool
 BufferTextureClient::Lock(OpenMode aMode)
 {
   // XXX - Turn this into a fatal assertion as soon as Bug 952507 is fixed
   NS_WARN_IF_FALSE(!mLocked, "The TextureClient is already Locked!");
   mOpenMode = aMode;
   mLocked = true;
-  return true;
+  return IsValid() && IsAllocated();
 }
 
 void
 BufferTextureClient::Unlock()
 {
   // XXX - Turn this into a fatal assertion as soon as Bug 952507 is fixed
   NS_WARN_IF_FALSE(mLocked, "The TextureClient is already Unlocked!");
   mLocked = false;
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -167,16 +167,18 @@ public:
    *
    * Please always lock/unlock when accessing the shared data.
    * If Lock() returns false, you should not attempt to access the shared data.
    */
   virtual bool Lock(OpenMode aMode) { return IsValid(); }
 
   virtual void Unlock() {}
 
+  virtual bool IsLocked() const = 0;
+
   /**
    * Returns true if this texture has a lock/unlock mechanism.
    * Textures that do not implement locking should be immutable or should
    * use immediate uploads (see TextureFlags in CompositorTypes.h)
    */
   virtual bool ImplementsLocking() const { return false; }
 
   /**
@@ -308,16 +310,18 @@ public:
   virtual uint8_t* GetBuffer() const = 0;
 
   virtual gfx::IntSize GetSize() const { return mSize; }
 
   virtual bool Lock(OpenMode aMode) MOZ_OVERRIDE;
 
   virtual void Unlock() MOZ_OVERRIDE;
 
+  virtual bool IsLocked() const MOZ_OVERRIDE { return mLocked; }
+
   // TextureClientSurface
 
   virtual TextureClientSurface* AsTextureClientSurface() MOZ_OVERRIDE { return this; }
 
   virtual bool UpdateSurface(gfxASurface* aSurface) MOZ_OVERRIDE;
 
   virtual already_AddRefed<gfxASurface> GetAsSurface() MOZ_OVERRIDE;
 
--- a/gfx/layers/d3d10/ImageLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ImageLayerD3D10.cpp
@@ -208,24 +208,24 @@ ImageLayerD3D10::RenderLayer()
   }
 
   IntSize size = image->GetSize();
 
   SetEffectTransformAndOpacity();
 
   ID3D10EffectTechnique *technique;
   nsRefPtr<IDXGIKeyedMutex> keyedMutex;
-  nsRefPtr<gfxASurface> surf = image->DeprecatedGetAsSurface();
 
   if (image->GetFormat() == ImageFormat::CAIRO_SURFACE ||
       image->GetFormat() == ImageFormat::REMOTE_IMAGE_BITMAP ||
       image->GetFormat() == ImageFormat::REMOTE_IMAGE_DXGI_TEXTURE ||
       image->GetFormat() == ImageFormat::D3D9_RGB32_TEXTURE) {
     NS_ASSERTION(image->GetFormat() != ImageFormat::CAIRO_SURFACE ||
-                 !surf || surf->GetContentType() != gfxContentType::ALPHA,
+                 !static_cast<CairoImage*>(image)->mDeprecatedSurface ||
+                 static_cast<CairoImage*>(image)->mDeprecatedSurface->GetContentType() != gfxContentType::ALPHA,
                  "Image layer has alpha image");
     bool hasAlpha = false;
 
     nsRefPtr<ID3D10ShaderResourceView> srView = GetImageSRView(image, hasAlpha, getter_AddRefs(keyedMutex));
     if (!srView) {
       return;
     }
 
--- a/gfx/layers/d3d11/TextureD3D11.cpp
+++ b/gfx/layers/d3d11/TextureD3D11.cpp
@@ -149,16 +149,19 @@ TextureClientD3D11::TextureClientD3D11(g
 {}
 
 TextureClientD3D11::~TextureClientD3D11()
 {}
 
 bool
 TextureClientD3D11::Lock(OpenMode aMode)
 {
+  if (!IsValid() || !IsAllocated()) {
+    return false;
+  }
   MOZ_ASSERT(!mIsLocked, "The Texture is already locked!");
   LockD3DTexture(mTexture.get());
   mIsLocked = true;
   return true;
 }
 
 void
 TextureClientD3D11::Unlock()
--- a/gfx/layers/d3d11/TextureD3D11.h
+++ b/gfx/layers/d3d11/TextureD3D11.h
@@ -36,16 +36,18 @@ public:
   // TextureClient
 
   virtual bool IsAllocated() const MOZ_OVERRIDE { return !!mTexture; }
 
   virtual bool Lock(OpenMode aOpenMode) MOZ_OVERRIDE;
 
   virtual void Unlock() MOZ_OVERRIDE;
 
+  virtual bool IsLocked() const MOZ_OVERRIDE { return mIsLocked; }
+
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE { return nullptr; }
 
   // TextureClientDrawTarget
 
--- a/gfx/layers/d3d9/ImageLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ImageLayerD3D9.cpp
@@ -409,19 +409,19 @@ ImageLayerD3D9::RenderLayer()
   SetShaderTransformAndOpacity();
 
   gfx::IntSize size = image->GetSize();
 
   if (image->GetFormat() == CAIRO_SURFACE ||
       image->GetFormat() == REMOTE_IMAGE_BITMAP ||
       image->GetFormat() == D3D9_RGB32_TEXTURE)
   {
-    nsRefPtr<gfxASurface> surf = image->DeprecatedGetAsSurface();
     NS_ASSERTION(image->GetFormat() != CAIRO_SURFACE ||
-                 !surf || surf->GetContentType() != gfxContentType::ALPHA,
+                 !static_cast<CairoImage*>(image)->mDeprecatedSurface ||
+                 static_cast<CairoImage*>(image)->mDeprecatedSurface->GetContentType() != gfxContentType::ALPHA,
                  "Image layer has alpha image");
 
     bool hasAlpha = false;
     nsRefPtr<IDirect3DTexture9> texture = GetTexture(image, hasAlpha);
 
     device()->SetVertexShaderConstantF(CBvLayerQuad,
                                        ShaderConstantRect(0,
                                                           0,
--- a/gfx/layers/d3d9/TextureD3D9.cpp
+++ b/gfx/layers/d3d9/TextureD3D9.cpp
@@ -1261,17 +1261,17 @@ CairoTextureClientD3D9::~CairoTextureCli
 {
   MOZ_COUNT_DTOR(CairoTextureClientD3D9);
 }
 
 bool
 CairoTextureClientD3D9::Lock(OpenMode)
 {
   MOZ_ASSERT(!mIsLocked);
-  if (!IsValid()) {
+  if (!IsValid() || !IsAllocated()) {
     return false;
   }
   mIsLocked = true;
   return true;
 }
 
 void
 CairoTextureClientD3D9::Unlock()
--- a/gfx/layers/d3d9/TextureD3D9.h
+++ b/gfx/layers/d3d9/TextureD3D9.h
@@ -189,16 +189,18 @@ public:
   // TextureClient
 
   virtual bool IsAllocated() const MOZ_OVERRIDE { return !!mTexture; }
 
   virtual bool Lock(OpenMode aOpenMode) MOZ_OVERRIDE;
 
   virtual void Unlock() MOZ_OVERRIDE;
 
+  virtual bool IsLocked() const MOZ_OVERRIDE { return mIsLocked; }
+
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual gfx::IntSize GetSize() const { return mSize; }
 
   virtual gfx::SurfaceFormat GetFormat() const { return mFormat; }
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
 
@@ -237,16 +239,18 @@ public:
   // TextureClient
 
   virtual bool IsAllocated() const MOZ_OVERRIDE { return !!mSurface; }
 
   virtual bool Lock(OpenMode aOpenMode) MOZ_OVERRIDE;
 
   virtual void Unlock() MOZ_OVERRIDE;
 
+  virtual bool IsLocked() const MOZ_OVERRIDE { return mIsLocked; }
+
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual gfx::IntSize GetSize() const { return mSize; }
 
   virtual gfx::SurfaceFormat GetFormat() const { return mFormat; }
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
 
@@ -282,16 +286,18 @@ public:
   // TextureClient
 
   virtual bool IsAllocated() const MOZ_OVERRIDE { return !!mTexture; }
 
   virtual bool Lock(OpenMode aOpenMode) MOZ_OVERRIDE;
 
   virtual void Unlock() MOZ_OVERRIDE;
 
+  virtual bool IsLocked() const MOZ_OVERRIDE { return mIsLocked; }
+
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   void InitWith(IDirect3DTexture9* aTexture, HANDLE aSharedHandle, D3DSURFACE_DESC aDesc)
   {
     MOZ_ASSERT(!mTexture);
     mTexture = aTexture;
     mHandle = aSharedHandle;
     mDesc = aDesc;
--- a/gfx/layers/ipc/CompositorChild.h
+++ b/gfx/layers/ipc/CompositorChild.h
@@ -95,17 +95,16 @@ private:
     // the shared FrameMetrics
     mozilla::ipc::SharedMemoryBasic* mBuffer;
     CrossProcessMutex* mMutex;
     // Unique ID of the APZC that is sharing the FrameMetrics
     uint32_t mAPZCId;
   };
 
   nsRefPtr<ClientLayerManager> mLayerManager;
-  nsCOMPtr<nsIObserver> mMemoryPressureObserver;
 
   // The ViewID of the FrameMetrics is used as the key for this hash table.
   // While this should be safe to use since the ViewID is unique
   nsClassHashtable<nsUint64HashKey, SharedFrameMetricsData> mFrameMetricsTable;
 
   // When we're in a child process, this is the process-global
   // compositor that we use to forward transactions directly to the
   // compositor context in another process.
--- a/gfx/layers/opengl/GrallocTextureClient.cpp
+++ b/gfx/layers/opengl/GrallocTextureClient.cpp
@@ -169,16 +169,19 @@ GrallocTextureClientOGL::ToSurfaceDescri
   aOutDescriptor = NewSurfaceDescriptorGralloc(nullptr, mGrallocActor, mSize);
   return true;
 }
 
 bool
 GrallocTextureClientOGL::Lock(OpenMode aMode)
 {
   MOZ_ASSERT(IsValid());
+  if (!IsValid() || !IsAllocated()) {
+    return false;
+  }
   // XXX- it would be cleaner to take the openMode into account or to check
   // that aMode is coherent with mGrallocFlags (which carries more information
   // than OpenMode).
   int32_t rv = mGraphicBuffer->lock(mGrallocFlags, reinterpret_cast<void**>(&mMappedBuffer));
   if (rv) {
     NS_WARNING("Couldn't lock graphic buffer");
     return false;
   }
--- a/gfx/layers/opengl/GrallocTextureHost.cpp
+++ b/gfx/layers/opengl/GrallocTextureHost.cpp
@@ -117,16 +117,20 @@ void GrallocTextureSourceOGL::BindTextur
   MOZ_ASSERT(gl());
   gl()->MakeCurrent();
 
   GLuint tex = GetGLTexture();
   GLuint textureTarget = GetTextureTarget();
 
   gl()->fActiveTexture(aTextureUnit);
   gl()->fBindTexture(textureTarget, tex);
+  if (!mEGLImage) {
+    mEGLImage = EGLImageCreateFromNativeBuffer(gl(), mGraphicBuffer->getNativeBuffer());
+  }
+  gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
   gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
 }
 
 bool
 GrallocTextureSourceOGL::IsValid() const
 {
   return !!gl() && !!mGraphicBuffer.get();
 }
@@ -168,16 +172,23 @@ GrallocTextureSourceOGL::GetFormat() con
 void
 GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
 {
   if (mCompositableBackendData != aBackendData) {
     mNeedsReset = true;
   }
 
   if (!mNeedsReset) {
+    // Update binding to the EGLImage
+    gl()->MakeCurrent();
+    GLuint tex = GetGLTexture();
+    GLuint textureTarget = GetTextureTarget();
+    gl()->fActiveTexture(LOCAL_GL_TEXTURE0);
+    gl()->fBindTexture(textureTarget, tex);
+    gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
     return;
   }
 
   mCompositableBackendData = aBackendData;
 
   if (!mCompositor) {
     return;
   }
--- a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp
+++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.cpp
@@ -6,30 +6,52 @@
 #include "MacIOSurfaceTextureClientOGL.h"
 #include "mozilla/gfx/MacIOSurface.h"
 
 namespace mozilla {
 namespace layers {
 
 MacIOSurfaceTextureClientOGL::MacIOSurfaceTextureClientOGL(TextureFlags aFlags)
   : TextureClient(aFlags)
+  , mIsLocked(false)
 {}
 
 MacIOSurfaceTextureClientOGL::~MacIOSurfaceTextureClientOGL()
 {}
 
 void
 MacIOSurfaceTextureClientOGL::InitWith(MacIOSurface* aSurface)
 {
   MOZ_ASSERT(IsValid());
   MOZ_ASSERT(!IsAllocated());
   mSurface = aSurface;
 }
 
 bool
+MacIOSurfaceTextureClientOGL::Lock(OpenMode aMode)
+{
+  MOZ_ASSERT(!mIsLocked);
+  mIsLocked = true;
+  return IsValid() && IsAllocated();
+}
+
+void
+MacIOSurfaceTextureClientOGL::Unlock()
+{
+  MOZ_ASSERT(mIsLocked);
+  mIsLocked = false;
+}
+
+bool
+MacIOSurfaceTextureClientOGL::IsLocked() const
+{
+  return mIsLocked;
+}
+
+bool
 MacIOSurfaceTextureClientOGL::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
 {
   MOZ_ASSERT(IsValid());
   if (!IsAllocated()) {
     return false;
   }
   aOutDescriptor = SurfaceDescriptorMacIOSurface(mSurface->GetIOSurfaceID(),
                                                  mSurface->GetContentsScaleFactor(),
--- a/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h
+++ b/gfx/layers/opengl/MacIOSurfaceTextureClientOGL.h
@@ -17,24 +17,31 @@ class MacIOSurfaceTextureClientOGL : pub
 {
 public:
   MacIOSurfaceTextureClientOGL(TextureFlags aFlags);
 
   virtual ~MacIOSurfaceTextureClientOGL();
 
   void InitWith(MacIOSurface* aSurface);
 
+  virtual bool Lock(OpenMode aMode) MOZ_OVERRIDE;
+
+  virtual void Unlock() MOZ_OVERRIDE;
+
+  virtual bool IsLocked() const MOZ_OVERRIDE;
+
   virtual bool IsAllocated() const MOZ_OVERRIDE { return !!mSurface; }
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual gfx::IntSize GetSize() const;
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
 
 protected:
   RefPtr<MacIOSurface> mSurface;
+  bool mIsLocked;
 };
 
 }
 }
 
 #endif // MOZILLA_GFX_MACIOSURFACETEXTURECLIENTOGL_H
\ No newline at end of file
--- a/gfx/layers/opengl/TextureClientOGL.cpp
+++ b/gfx/layers/opengl/TextureClientOGL.cpp
@@ -56,33 +56,70 @@ SharedTextureClientOGL::InitWith(gl::Sha
   mShareType = aShareType;
   mInverted = aInverted;
   if (mInverted) {
     AddFlags(TEXTURE_NEEDS_Y_FLIP);
   }
 }
 
 bool
+SharedTextureClientOGL::Lock(OpenMode mode)
+{
+  MOZ_ASSERT(!mIsLocked);
+  if (!IsValid() || !IsAllocated()) {
+    return false;
+  }
+  mIsLocked = true;
+  return true;
+}
+
+void
+SharedTextureClientOGL::Unlock()
+{
+  MOZ_ASSERT(mIsLocked);
+  mIsLocked = false;
+}
+
+bool
 SharedTextureClientOGL::IsAllocated() const
 {
   return mHandle != 0;
 }
 
 StreamTextureClientOGL::StreamTextureClientOGL(TextureFlags aFlags)
   : TextureClient(aFlags)
   , mStream(0)
+  , mIsLocked(false)
 {
 }
 
 StreamTextureClientOGL::~StreamTextureClientOGL()
 {
   // the data is owned externally.
 }
 
 bool
+StreamTextureClientOGL::Lock(OpenMode mode)
+{
+  MOZ_ASSERT(!mIsLocked);
+  if (!IsValid() || !IsAllocated()) {
+    return false;
+  }
+  mIsLocked = true;
+  return true;
+}
+
+void
+StreamTextureClientOGL::Unlock()
+{
+  MOZ_ASSERT(mIsLocked);
+  mIsLocked = false;
+}
+
+bool
 StreamTextureClientOGL::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
 {
   if (!IsAllocated()) {
     return false;
   }
 
   gfx::SurfaceStreamHandle handle = mStream->GetShareHandle();
   aOutDescriptor = SurfaceStreamDescriptor(handle, false);
--- a/gfx/layers/opengl/TextureClientOGL.h
+++ b/gfx/layers/opengl/TextureClientOGL.h
@@ -35,16 +35,22 @@ public:
   SharedTextureClientOGL(TextureFlags aFlags);
 
   ~SharedTextureClientOGL();
 
   virtual bool IsAllocated() const MOZ_OVERRIDE;
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
+  virtual bool Lock(OpenMode mode) MOZ_OVERRIDE;
+
+  virtual void Unlock() MOZ_OVERRIDE;
+
+  virtual bool IsLocked() const MOZ_OVERRIDE { return mIsLocked; }
+
   void InitWith(gl::SharedTextureHandle aHandle,
                 gfx::IntSize aSize,
                 gl::SharedTextureShareType aShareType,
                 bool aInverted = false);
 
   virtual gfx::IntSize GetSize() const { return mSize; }
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE
@@ -56,40 +62,48 @@ public:
     return nullptr;
   }
 
 protected:
   gl::SharedTextureHandle mHandle;
   gfx::IntSize mSize;
   gl::SharedTextureShareType mShareType;
   bool mInverted;
+  bool mIsLocked;
 };
 
 /**
  * A TextureClient implementation to share SurfaceStream.
  */
 class StreamTextureClientOGL : public TextureClient
 {
 public:
   StreamTextureClientOGL(TextureFlags aFlags);
 
   ~StreamTextureClientOGL();
 
   virtual bool IsAllocated() const MOZ_OVERRIDE;
 
+  virtual bool Lock(OpenMode mode) MOZ_OVERRIDE;
+
+  virtual void Unlock() MOZ_OVERRIDE;
+
+  virtual bool IsLocked() const MOZ_OVERRIDE { return mIsLocked; }
+
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE { return nullptr; }
 
   void InitWith(gfx::SurfaceStream* aStream);
 
   virtual gfx::IntSize GetSize() const { return gfx::IntSize(); }
 
 protected:
   gfx::SurfaceStream* mStream;
+  bool mIsLocked;
 };
 
 class DeprecatedTextureClientSharedOGL : public DeprecatedTextureClient
 {
 public:
   DeprecatedTextureClientSharedOGL(CompositableForwarder* aForwarder, const TextureInfo& aTextureInfo);
   ~DeprecatedTextureClientSharedOGL() { ReleaseResources(); }
 
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -220,16 +220,17 @@ GLuint CompositableDataGonkOGL::GetTextu
 
 void
 CompositableDataGonkOGL::DeleteTextureIfPresent()
 {
   if (mTexture) {
     if (gl()->MakeCurrent()) {
       gl()->fDeleteTextures(1, &mTexture);
     }
+    mTexture = 0;
   }
 }
 
 bool
 TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
                                      nsIntRegion* aDestRegion,
                                      gfx::IntPoint* aSrcOffset)
 {
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -154,29 +154,29 @@ class HashMap
         return impl.relookupOrAdd(p, e.key(), mozilla::Move(e));
     }
 
     // |all()| returns a Range containing |count()| elements. E.g.:
     //
     //   typedef HashMap<int,char> HM;
     //   HM h;
     //   for (HM::Range r = h.all(); !r.empty(); r.popFront())
-    //     char c = r.front().value;
+    //     char c = r.front().value();
     //
     // Also see the definition of Range in HashTable above (with T = Entry).
     typedef typename Impl::Range Range;
     Range all() const                                 { return impl.all(); }
 
     // Typedef for the enumeration class. An Enum may be used to examine and
     // remove table entries:
     //
     //   typedef HashMap<int,char> HM;
     //   HM s;
     //   for (HM::Enum e(s); !e.empty(); e.popFront())
-    //     if (e.front().value == 'l')
+    //     if (e.front().value() == 'l')
     //       e.removeFront();
     //
     // Table resize may occur in Enum's destructor. Also see the definition of
     // Enum in HashTable above (with T = Entry).
     typedef typename Impl::Enum Enum;
 
     // Remove all entries. This does not shrink the table. For that consider
     // using the finish() method.
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -204,16 +204,41 @@ struct CodeSizes
     {}
 
     FOR_EACH_SIZE(DECL_SIZE)
     int dummy;  // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
 
 #undef FOR_EACH_SIZE
 };
 
+// Data for tracking GC memory usage.
+struct GCSizes
+{
+#define FOR_EACH_SIZE(macro) \
+    macro(_, _, marker) \
+    macro(_, _, nursery) \
+    macro(_, _, storeBufferVals) \
+    macro(_, _, storeBufferCells) \
+    macro(_, _, storeBufferSlots) \
+    macro(_, _, storeBufferWholeCells) \
+    macro(_, _, storeBufferRelocVals) \
+    macro(_, _, storeBufferRelocCells) \
+    macro(_, _, storeBufferGenerics)
+
+    GCSizes()
+      : FOR_EACH_SIZE(ZERO_SIZE)
+        dummy()
+    {}
+
+    FOR_EACH_SIZE(DECL_SIZE)
+    int dummy;  // present just to absorb the trailing comma from FOR_EACH_SIZE(ZERO_SIZE)
+
+#undef FOR_EACH_SIZE
+};
+
 // This class holds information about the memory taken up by identical copies of
 // a particular string.  Multiple JSStrings may have their sizes aggregated
 // together into one StringInfo object.  Note that two strings with identical
 // chars will not be aggregated together if one is a short string and the other
 // is not.
 struct StringInfo
 {
     StringInfo()
@@ -289,28 +314,30 @@ struct RuntimeSizes
 #define FOR_EACH_SIZE(macro) \
     macro(_, _, object) \
     macro(_, _, atomsTable) \
     macro(_, _, contexts) \
     macro(_, _, dtoa) \
     macro(_, _, temporary) \
     macro(_, _, regexpData) \
     macro(_, _, interpreterStack) \
-    macro(_, _, gcMarker) \
     macro(_, _, mathCache) \
+    macro(_, _, sourceDataCache) \
     macro(_, _, scriptData) \
     macro(_, _, scriptSources)
 
     RuntimeSizes()
       : FOR_EACH_SIZE(ZERO_SIZE)
-        code()
+        code(),
+        gc()
     {}
 
     FOR_EACH_SIZE(DECL_SIZE)
     CodeSizes code;
+    GCSizes   gc;
 
 #undef FOR_EACH_SIZE
 };
 
 struct ZoneStats : js::ZoneStatsPod
 {
     ZoneStats()
       : strings(nullptr)
--- a/js/src/assembler/wtf/Platform.h
+++ b/js/src/assembler/wtf/Platform.h
@@ -205,16 +205,23 @@
 #endif
 
 /* WTF_CPU_S390 - S390 32-bit */
 #if defined(__s390__)
 #define WTF_CPU_S390 1
 #define WTF_CPU_BIG_ENDIAN 1
 #endif
 
+#if defined(__aarch64__)
+#define WTF_CPU_AARCH64 1
+#if defined(__AARCH64EB__)
+#define WTF_CPU_BIG_ENDIAN 1
+#endif
+#endif
+
 /* WTF_CPU_X86 - i386 / x86 32-bit */
 #if   defined(__i386__) \
     || defined(i386)     \
     || defined(_M_IX86)  \
     || defined(_X86_)    \
     || defined(__THW_INTEL)
 #define WTF_CPU_X86 1
 #endif
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -118,16 +118,18 @@ class Nursery
      * returns false and leaves |*ref| unset.
      */
     template <typename T>
     JS_ALWAYS_INLINE bool getForwardedPointer(T **ref);
 
     /* Forward a slots/elements pointer stored in an Ion frame. */
     void forwardBufferPointer(HeapSlot **pSlotsElems);
 
+    size_t sizeOfHeap() { return start() ? NurserySize : 0; }
+
 #ifdef JS_GC_ZEAL
     /*
      * In debug and zeal builds, these bytes indicate the state of an unused
      * segment of nursery-allocated memory.
      */
     static const uint8_t FreshNursery = 0x2a;
     static const uint8_t SweptNursery = 0x2b;
     static const uint8_t AllocatedThing = 0x2c;
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -300,16 +300,29 @@ StoreBuffer::setAboutToOverflow()
 }
 
 bool
 StoreBuffer::inParallelSection() const
 {
     return InParallelSection();
 }
 
+void
+StoreBuffer::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::GCSizes
+*sizes)
+{
+    sizes->storeBufferVals       += bufferVal.sizeOfExcludingThis(mallocSizeOf);
+    sizes->storeBufferCells      += bufferCell.sizeOfExcludingThis(mallocSizeOf);
+    sizes->storeBufferSlots      += bufferSlot.sizeOfExcludingThis(mallocSizeOf);
+    sizes->storeBufferWholeCells += bufferWholeCell.sizeOfExcludingThis(mallocSizeOf);
+    sizes->storeBufferRelocVals  += bufferRelocVal.sizeOfExcludingThis(mallocSizeOf);
+    sizes->storeBufferRelocCells += bufferRelocCell.sizeOfExcludingThis(mallocSizeOf);
+    sizes->storeBufferGenerics   += bufferGeneric.sizeOfExcludingThis(mallocSizeOf);
+}
+
 JS_PUBLIC_API(void)
 JS::HeapCellPostBarrier(js::gc::Cell **cellp)
 {
     JS_ASSERT(*cellp);
     JSRuntime *runtime = (*cellp)->runtimeFromMainThread();
     runtime->gcStoreBuffer.putRelocatableCell(cellp);
 }
 
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -15,16 +15,17 @@
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/ReentrancyGuard.h"
 
 #include "jsalloc.h"
 
 #include "ds/LifoAlloc.h"
 #include "gc/Nursery.h"
+#include "js/MemoryMetrics.h"
 #include "js/Tracer.h"
 
 namespace js {
 namespace gc {
 
 extern void
 CrashAtUnhandlableOOM(const char *);
 
@@ -134,16 +135,20 @@ class StoreBuffer
                 if (isAboutToOverflow())
                     owner->setAboutToOverflow();
             }
         }
 
         /* Mark the source of all edges in the store buffer. */
         void mark(StoreBuffer *owner, JSTracer *trc);
 
+        size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
+            return storage_ ? storage_->sizeOfIncludingThis(mallocSizeOf) : 0;
+        }
+
       private:
         MonoTypeBuffer &operator=(const MonoTypeBuffer& other) MOZ_DELETE;
     };
 
     /*
      * Overrides the MonoTypeBuffer to support pointers that may be moved in
      * memory outside of the GC's control.
      */
@@ -204,16 +209,20 @@ class StoreBuffer
             T *tp = storage_->new_<T>(t);
             if (!tp)
                 CrashAtUnhandlableOOM("Failed to allocate for GenericBuffer::put.");
 
             if (isAboutToOverflow())
                 owner->setAboutToOverflow();
         }
 
+        size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
+            return storage_ ? storage_->sizeOfIncludingThis(mallocSizeOf) : 0;
+        }
+
       private:
         GenericBuffer &operator=(const GenericBuffer& other) MOZ_DELETE;
     };
 
     struct CellPtrEdge
     {
         Cell **edge;
 
@@ -431,17 +440,18 @@ class StoreBuffer
     /* Mark the source of all edges in the store buffer. */
     void mark(JSTracer *trc);
 
     /* We cannot call InParallelSection directly because of a circular dependency. */
     bool inParallelSection() const;
 
     /* For use by our owned buffers and for testing. */
     void setAboutToOverflow();
-    void setOverflowed();
+
+    void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::GCSizes *sizes);
 };
 
 } /* namespace gc */
 } /* namespace js */
 
 #endif /* JSGC_GENERATIONAL */
 
 #endif /* gc_StoreBuffer_h */
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2745,53 +2745,58 @@ LookupResult(JSContext *cx, HandleObject
     }
 
     /* XXX bad API: no way to return "defined but value unknown" */
     vp.setBoolean(true);
     return true;
 }
 
 JS_PUBLIC_API(bool)
-JS_LookupPropertyById(JSContext *cx, JSObject *objArg, jsid idArg, MutableHandleValue vp)
-{
-    RootedId id(cx, idArg);
-    RootedObject obj(cx, objArg);
+JS_LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
+{
     RootedObject obj2(cx);
     RootedShape prop(cx);
 
     return LookupPropertyById(cx, obj, id, 0, &obj2, &prop) &&
            LookupResult(cx, obj, obj2, id, prop, vp);
 }
 
 JS_PUBLIC_API(bool)
-JS_LookupElement(JSContext *cx, JSObject *objArg, uint32_t index, MutableHandleValue vp)
-{
-    RootedObject obj(cx, objArg);
+JS_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
+{
     CHECK_REQUEST(cx);
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
     return JS_LookupPropertyById(cx, obj, id, vp);
 }
 
 JS_PUBLIC_API(bool)
-JS_LookupProperty(JSContext *cx, JSObject *objArg, const char *name, MutableHandleValue vp)
+JS_LookupProperty(JSContext *cx, HandleObject objArg, const char *name, MutableHandleValue vp)
 {
     RootedObject obj(cx, objArg);
     JSAtom *atom = Atomize(cx, name, strlen(name));
-    return atom && JS_LookupPropertyById(cx, obj, AtomToId(atom), vp);
+    if (!atom)
+        return false;
+
+    RootedId id(cx, AtomToId(atom));
+    return JS_LookupPropertyById(cx, obj, id, vp);
 }
 
 JS_PUBLIC_API(bool)
-JS_LookupUCProperty(JSContext *cx, JSObject *objArg, const jschar *name, size_t namelen,
+JS_LookupUCProperty(JSContext *cx, HandleObject objArg, const jschar *name, size_t namelen,
                     MutableHandleValue vp)
 {
     RootedObject obj(cx, objArg);
     JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
-    return atom && JS_LookupPropertyById(cx, obj, AtomToId(atom), vp);
+    if (!atom)
+        return false;
+
+    RootedId id(cx, AtomToId(atom));
+    return JS_LookupPropertyById(cx, obj, id, vp);
 }
 
 JS_PUBLIC_API(bool)
 JS_LookupPropertyWithFlagsById(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
                                MutableHandleObject objp, MutableHandleValue vp)
 {
     RootedShape prop(cx);
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2285,17 +2285,16 @@ class AutoIdArray : private AutoGCRooter
         if (idArray)
             JS_DestroyIdArray(context, idArray);
     }
     bool operator!() {
         return !idArray;
     }
     jsid operator[](size_t i) const {
         JS_ASSERT(idArray);
-        JS_ASSERT(i < length());
         return JS_IdArrayGet(context, idArray, i);
     }
     size_t length() const {
         return JS_IdArrayLength(context, idArray);
     }
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 
@@ -2825,20 +2824,21 @@ JS_AlreadyHasOwnPropertyById(JSContext *
 
 extern JS_PUBLIC_API(bool)
 JS_HasProperty(JSContext *cx, JS::HandleObject obj, const char *name, bool *foundp);
 
 extern JS_PUBLIC_API(bool)
 JS_HasPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *foundp);
 
 extern JS_PUBLIC_API(bool)
-JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, JS::MutableHandleValue vp);
+JS_LookupProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
-JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, JS::MutableHandleValue vp);
+JS_LookupPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
+                      JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_LookupPropertyWithFlags(JSContext *cx, JS::HandleObject obj, const char *name,
                            unsigned flags, JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_LookupPropertyWithFlagsById(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                                unsigned flags, JS::MutableHandleObject objp, JS::MutableHandleValue vp);
@@ -3059,17 +3059,17 @@ JS_AlreadyHasOwnUCProperty(JSContext *cx
                            size_t namelen, bool *foundp);
 
 extern JS_PUBLIC_API(bool)
 JS_HasUCProperty(JSContext *cx, JS::HandleObject obj,
                  const jschar *name, size_t namelen,
                  bool *vp);
 
 extern JS_PUBLIC_API(bool)
-JS_LookupUCProperty(JSContext *cx, JSObject *obj,
+JS_LookupUCProperty(JSContext *cx, JS::HandleObject obj,
                     const jschar *name, size_t namelen,
                     JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_GetUCProperty(JSContext *cx, JSObject *obj,
                  const jschar *name, size_t namelen,
                  JS::MutableHandleValue vp);
 
@@ -3100,17 +3100,17 @@ JS_DefineElement(JSContext *cx, JSObject
 
 extern JS_PUBLIC_API(bool)
 JS_AlreadyHasOwnElement(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *foundp);
 
 extern JS_PUBLIC_API(bool)
 JS_HasElement(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *foundp);
 
 extern JS_PUBLIC_API(bool)
-JS_LookupElement(JSContext *cx, JSObject *obj, uint32_t index, JS::MutableHandleValue vp);
+JS_LookupElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_GetElement(JSContext *cx, JSObject *obj, uint32_t index, JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_ForwardGetElementTo(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf,
                        JS::MutableHandleValue vp);
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1050,16 +1050,22 @@ js_fun_apply(JSContext *cx, unsigned arg
 
         if (!args.init(length))
             return false;
 
         /* Push fval, obj, and aobj's elements as args. */
         args.setCallee(fval);
         args.setThis(vp[2]);
 
+        // Make sure the function is delazified before querying its arguments.
+        if (args.callee().is<JSFunction>()) {
+            JSFunction *fun = &args.callee().as<JSFunction>();
+            if (fun->isInterpreted() && !fun->getOrCreateScript(cx))
+                return false;
+        }
         /* Steps 7-8. */
         if (!GetElements(cx, aobj, length, args.array()))
             return false;
     }
 
     /* Step 9. */
     if (!Invoke(cx, args))
         return false;
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1202,16 +1202,30 @@ SourceDataCache::purge()
 
     for (Map::Range r = map_->all(); !r.empty(); r.popFront())
         js_delete(const_cast<jschar*>(r.front().value()));
 
     js_delete(map_);
     map_ = nullptr;
 }
 
+size_t
+SourceDataCache::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
+{
+    size_t n = 0;
+    if (map_ && !map_->empty()) {
+        n += map_->sizeOfIncludingThis(mallocSizeOf);
+        for (Map::Range r = map_->all(); !r.empty(); r.popFront()) {
+            const jschar *v = r.front().value();
+            n += mallocSizeOf(v);
+        }
+    }
+    return n;
+}
+
 const jschar *
 ScriptSource::chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp)
 {
     if (const jschar *chars = getOffThreadCompressionChars(cx))
         return chars;
     JS_ASSERT(ready());
 
 #ifdef USE_ZLIB
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -348,16 +348,18 @@ class SourceDataCache
         ~AutoSuppressPurge();
         SourceDataCache &cache() const { return cache_; }
     };
 
     const jschar *lookup(ScriptSource *ss, const AutoSuppressPurge &asp);
     bool put(ScriptSource *ss, const jschar *chars, const AutoSuppressPurge &asp);
 
     void purge();
+
+    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
 };
 
 class ScriptSource
 {
     friend class SourceCompressionTask;
 
     union {
         // Before setSourceCopy or setSource are successfully called, this union
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4495,17 +4495,18 @@ Help(JSContext *cx, unsigned argc, jsval
     if (argc == 0) {
         RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
         AutoIdArray ida(cx, JS_Enumerate(cx, global));
         if (!ida)
             return false;
 
         for (size_t i = 0; i < ida.length(); i++) {
             RootedValue v(cx);
-            if (!JS_LookupPropertyById(cx, global, ida[i], &v))
+            RootedId id(cx, ida[i]);
+            if (!JS_LookupPropertyById(cx, global, id, &v))
                 return false;
             if (JSVAL_IS_PRIMITIVE(v)) {
                 JS_ReportError(cx, "primitive arg");
                 return false;
             }
             obj = JSVAL_TO_OBJECT(v);
             if (!PrintHelp(cx, obj))
                 return false;
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -593,40 +593,45 @@ JSRuntime::addSizeOfIncludingThis(mozill
 
     for (ContextIter acx(this); !acx.done(); acx.next())
         rtSizes->contexts += acx->sizeOfIncludingThis(mallocSizeOf);
 
     rtSizes->dtoa += mallocSizeOf(mainThread.dtoaState);
 
     rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
 
+    rtSizes->regexpData += bumpAlloc_ ? bumpAlloc_->sizeOfNonHeapData() : 0;
+
+    rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf);
+
+    rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
+
+    rtSizes->sourceDataCache += sourceDataCache.sizeOfExcludingThis(mallocSizeOf);
+
+    rtSizes->scriptData += scriptDataTable().sizeOfExcludingThis(mallocSizeOf);
+    for (ScriptDataTable::Range r = scriptDataTable().all(); !r.empty(); r.popFront())
+        rtSizes->scriptData += mallocSizeOf(r.front());
+
     if (execAlloc_)
         execAlloc_->addSizeOfCode(&rtSizes->code);
-
 #ifdef JS_ION
     {
         AutoLockForOperationCallback lock(this);
         if (jitRuntime()) {
             if (JSC::ExecutableAllocator *ionAlloc = jitRuntime()->ionAlloc(this))
                 ionAlloc->addSizeOfCode(&rtSizes->code);
         }
     }
 #endif
 
-    rtSizes->regexpData += bumpAlloc_ ? bumpAlloc_->sizeOfNonHeapData() : 0;
-
-    rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf);
-
-    rtSizes->gcMarker += gcMarker.sizeOfExcludingThis(mallocSizeOf);
-
-    rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
-
-    rtSizes->scriptData += scriptDataTable().sizeOfExcludingThis(mallocSizeOf);
-    for (ScriptDataTable::Range r = scriptDataTable().all(); !r.empty(); r.popFront())
-        rtSizes->scriptData += mallocSizeOf(r.front());
+    rtSizes->gc.marker += gcMarker.sizeOfExcludingThis(mallocSizeOf);
+#ifdef JSGC_GENERATIONAL
+    rtSizes->gc.nursery += gcNursery.sizeOfHeap();
+    gcStoreBuffer.addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc);
+#endif
 }
 
 static bool
 SignalBasedTriggersDisabled()
 {
   // Don't bother trying to cache the getenv lookup; this should be called
   // infrequently.
   return !!getenv("JS_DISABLE_SLOW_SCRIPT_SIGNALS");
--- a/js/xpconnect/src/XPCInlines.h
+++ b/js/xpconnect/src/XPCInlines.h
@@ -540,19 +540,20 @@ XPCWrappedNative::SweepTearOffs()
             }
         }
     }
 }
 
 /***************************************************************************/
 
 inline bool
-xpc_ForcePropertyResolve(JSContext* cx, JSObject* obj, jsid id)
+xpc_ForcePropertyResolve(JSContext* cx, JS::HandleObject obj, jsid idArg)
 {
     JS::RootedValue prop(cx);
+    JS::RootedId id(cx, idArg);
 
     if (!JS_LookupPropertyById(cx, obj, id, &prop))
         return false;
     return true;
 }
 
 inline jsid
 GetRTIdByIndex(JSContext *cx, unsigned index)
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2259,24 +2259,25 @@ ReportJSRuntimeExplicitTreeStats(const J
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/regexp-data"),
                   KIND_NONHEAP, rtStats.runtime.regexpData,
                   "Memory used by the regexp JIT to hold data.");
 
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/interpreter-stack"),
                   KIND_HEAP, rtStats.runtime.interpreterStack,
                   "Memory used for JS interpreter frames.");
 
-    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc-marker"),
-                  KIND_HEAP, rtStats.runtime.gcMarker,
-                  "Memory used for the GC mark stack and gray roots.");
-
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/math-cache"),
                   KIND_HEAP, rtStats.runtime.mathCache,
                   "Memory used for the math cache.");
 
+    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/source-data-cache"),
+                  KIND_HEAP, rtStats.runtime.sourceDataCache,
+                  "Memory used for the source data cache, which holds "
+                  "decompressed script source code.");
+
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/script-data"),
                   KIND_HEAP, rtStats.runtime.scriptData,
                   "Memory used for the table holding script data shared in "
                   "the runtime.");
 
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/script-sources"),
                   KIND_HEAP, rtStats.runtime.scriptSources,
                   "Memory use for storing JavaScript source code and filenames.");
@@ -2298,16 +2299,52 @@ ReportJSRuntimeExplicitTreeStats(const J
                   "Memory used by the JITs to hold generated code for "
                   "wrappers and trampolines.");
 
     RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/unused"),
                   KIND_NONHEAP, rtStats.runtime.code.unused,
                   "Memory allocated by one of the JITs to hold code, "
                   "but which is currently unused.");
 
+    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/marker"),
+                  KIND_HEAP, rtStats.runtime.gc.marker,
+                  "Memory used for the GC mark stack and gray roots.");
+
+    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/nursery"),
+                  KIND_NONHEAP, rtStats.runtime.gc.nursery,
+                  "Memory used for the GC nursery.");
+
+    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/vals"),
+                  KIND_HEAP, rtStats.runtime.gc.storeBufferVals,
+                  "Memory used for values in the store buffer.");
+
+    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/cells"),
+                  KIND_HEAP, rtStats.runtime.gc.storeBufferCells,
+                  "Memory used for cells in the store buffer.");
+
+    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/slots"),
+                  KIND_HEAP, rtStats.runtime.gc.storeBufferSlots,
+                  "Memory used for slots in the store buffer.");
+
+    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/whole-cells"),
+                  KIND_HEAP, rtStats.runtime.gc.storeBufferWholeCells,
+                  "Memory used for whole cells in the store buffer.");
+
+    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/reloc-vals"),
+                  KIND_HEAP, rtStats.runtime.gc.storeBufferRelocVals,
+                  "Memory used for relocatable values in the store buffer.");
+
+    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/reloc-cells"),
+                  KIND_HEAP, rtStats.runtime.gc.storeBufferRelocCells,
+                  "Memory used for relocatable cells in the store buffer.");
+
+    RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/gc/store-buffer/generics"),
+                  KIND_HEAP, rtStats.runtime.gc.storeBufferGenerics,
+                  "Memory used for generic things in the store buffer.");
+
     if (rtTotalOut)
         *rtTotalOut = rtTotal;
 
     // Report GC numbers that don't belong to a compartment.
 
     // We don't want to report decommitted memory in "explicit", so we just
     // change the leading "explicit/" to "decommitted/".
     nsCString rtPath2(rtPath);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3494,17 +3494,17 @@ ExportFunction(JSContext *cx, JS::Handle
 
 } /* namespace xpc */
 
 
 /***************************************************************************/
 // Inlined utilities.
 
 inline bool
-xpc_ForcePropertyResolve(JSContext* cx, JSObject* obj, jsid id);
+xpc_ForcePropertyResolve(JSContext* cx, JS::HandleObject obj, jsid id);
 
 inline jsid
 GetRTIdByIndex(JSContext *cx, unsigned index);
 
 namespace xpc {
 
 class CompartmentPrivate
 {
--- a/layout/base/tests/bug106855-1-ref.html
+++ b/layout/base/tests/bug106855-1-ref.html
@@ -1,14 +1,14 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
 x<br>
-<textarea id="t" rows="4">
+<textarea id="t" rows="4" spellcheck="false">
 A
 
 
 </textarea><br>
 y
 <script>
   // Position the caret at the last line
   var sel = window.getSelection();
--- a/layout/base/tests/bug106855-1.html
+++ b/layout/base/tests/bug106855-1.html
@@ -1,14 +1,14 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
 x<br>
-<textarea id="t" rows="4">
+<textarea id="t" rows="4" spellcheck="false">
 A
 
 
 </textarea><br>
 y
 <script>
   // Position the caret at the last line
   var sel = window.getSelection();
--- a/layout/base/tests/bug106855-2.html
+++ b/layout/base/tests/bug106855-2.html
@@ -1,14 +1,14 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
 x<br>
-<textarea id="t" rows="4">
+<textarea id="t" rows="4" spellcheck="false">
 A
 
 
 </textarea><br>
 y
 <script>
   // Position the caret at the last line
   var sel = window.getSelection();
--- a/layout/base/tests/bug482484-ref.html
+++ b/layout/base/tests/bug482484-ref.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML><html><head></head>
 <body>
-<div contentEditable="true" id="div"><p id="p">ABC</p></div>
+<div contentEditable="true" id="div" spellcheck="false"><p id="p">ABC</p></div>
 <script>
   // Position the caret after the "A"
   var div = document.getElementById('div');
   var p = document.getElementById('p');
   div.focus();
   var sel = window.getSelection();
   sel.removeAllRanges();
   var range = document.createRange();
--- a/layout/base/tests/bug482484.html
+++ b/layout/base/tests/bug482484.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
-<div contentEditable="true" id="div"><p id="p">BC</p></div>
+<div contentEditable="true" id="div" spellcheck="false"><p id="p">BC</p></div>
 <script>
   // Position the caret before the "B"
   var div = document.getElementById('div');
   div.focus();
   var p = document.getElementById('p');
   var sel = window.getSelection();
   sel.removeAllRanges();
   var range = document.createRange();
--- a/layout/base/tests/bug512295-1-ref.html
+++ b/layout/base/tests/bug512295-1-ref.html
@@ -1,24 +1,28 @@
-<!DOCTYPE HTML><html><head>
+<!DOCTYPE HTML><html class="reftest-wait"><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
 <div contenteditable="true">
 <p id="p">A B CD EFG<br>
   1234567890</p>
 </div>
 x
 <script>
   // Position the caret at the end of the P element
   var p = document.getElementById('p');
   var div = p.parentNode;
   div.focus();
-  var sel = window.getSelection();
-  sel.removeAllRanges();
-  var range = document.createRange();
-  range.setStart(p, p.childNodes.length);
-  range.setEnd(p, p.childNodes.length);
-  sel.addRange(range);
+  SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", window);
+  onSpellCheck(div, function () {
+    var sel = window.getSelection();
+    sel.removeAllRanges();
+    var range = document.createRange();
+    range.setStart(p, p.childNodes.length);
+    range.setEnd(p, p.childNodes.length);
+    sel.addRange(range);
+    document.documentElement.classList.remove("reftest-wait");
+  });
 </script>
 
 </body>
 </html>
--- a/layout/base/tests/bug512295-1.html
+++ b/layout/base/tests/bug512295-1.html
@@ -1,9 +1,9 @@
-<!DOCTYPE HTML><html><head>
+<!DOCTYPE HTML><html class="reftest-wait"><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
 <div contenteditable="true">
 <p id="p">A B CD EFG<br>
   1234567890</p>
 </div>
 x
@@ -14,17 +14,21 @@ x
   var range = document.createRange();
   var p = document.getElementById('p');
   var t = p.firstChild;
   range.setStart(t, 1);
   range.setEnd(t, 1);
   sel.addRange(range);
   p.parentNode.focus();
 
-  sendKey('DOWN');  // now after "1"
-  sendKey('DOWN');  // now make sure we get to the end
-  sendKey('DOWN');  // now make sure we get to the end
-  sendKey('DOWN');  // now make sure we get to the end
-  sendKey('DOWN');  // now make sure we get to the end
-  sendKey('DOWN');  // now make sure we get to the end
+  SpecialPowers.Cu.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm", window);
+  onSpellCheck(p.parentNode, function () {
+    sendKey('DOWN');  // now after "1"
+    sendKey('DOWN');  // now make sure we get to the end
+    sendKey('DOWN');  // now make sure we get to the end
+    sendKey('DOWN');  // now make sure we get to the end
+    sendKey('DOWN');  // now make sure we get to the end
+    sendKey('DOWN');  // now make sure we get to the end
+    document.documentElement.classList.remove("reftest-wait");
+  });
 </script>
 </body>
 </html>
--- a/layout/base/tests/bug597519-1-ref.html
+++ b/layout/base/tests/bug597519-1-ref.html
@@ -1,12 +1,12 @@
 <!DOCTYPE HTML><html><head>
 </head>
 <body>
-<textarea>ab
+<textarea spellcheck="false">ab
 </textarea>
 <script>
   var t = document.querySelector("textarea");
   t.focus();
   t.selectionStart = t.selectionEnd = t.value.length;
 </script>
 </body>
 </html>
--- a/layout/base/tests/bug597519-1.html
+++ b/layout/base/tests/bug597519-1.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
-<textarea maxlength="3"></textarea>
+<textarea maxlength="3" spellcheck="false"></textarea>
 <script>
   var t = document.querySelector("textarea");
   t.focus();
 
   synthesizeKey("a", {});
   synthesizeKey("b", {});
   synthesizeKey("VK_ENTER", {});
   synthesizeKey("c", {});
--- a/layout/base/tests/bug602141-1-ref.html
+++ b/layout/base/tests/bug602141-1-ref.html
@@ -1,12 +1,12 @@
 <!DOCTYPE HTML><html><head>
 </head>
 <body>
-<span contenteditable="true">navigable__</span><span id="x" contenteditable="true">navigable|unnavigable</span><br />
+<span contenteditable="true" spellcheck="false">navigable__</span><span id="x" contenteditable="true" spellcheck="false">navigable|unnavigable</span><br />
 <script>
   // Position the caret after "u"
   var sel = window.getSelection();
   sel.removeAllRanges();
   var range = document.createRange();
   var x = document.getElementById('x');
   var t = x.firstChild;
   range.setStart(t, 11);
--- a/layout/base/tests/bug602141-1.html
+++ b/layout/base/tests/bug602141-1.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
-<span contenteditable="true">navigable__</span><span id="x" contenteditable="true">navigable|unnavigable</span><br />
+<span contenteditable="true" spellcheck="false">navigable__</span><span id="x" contenteditable="true" spellcheck="false">navigable|unnavigable</span><br />
 <script>
   // Position the caret after "|"
   var sel = window.getSelection();
   sel.removeAllRanges();
   var range = document.createRange();
   var x = document.getElementById('x');
   var t = x.firstChild;
   range.setStart(t, 10);
--- a/layout/base/tests/bug602141-2-ref.html
+++ b/layout/base/tests/bug602141-2-ref.html
@@ -1,12 +1,12 @@
 <!DOCTYPE HTML><html><head>
 </head>
 <body>
-<span id="x" contenteditable="true">navigable__|unnavigable</span><br />
+<span id="x" contenteditable="true" spellcheck="false">navigable__|unnavigable</span><br />
 <script>
   // Position the caret after "u"
   var sel = window.getSelection();
   sel.removeAllRanges();
   var range = document.createRange();
   var x = document.getElementById('x');
   var t = x.firstChild;
   range.setStart(t, 13);
--- a/layout/base/tests/bug602141-2.html
+++ b/layout/base/tests/bug602141-2.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
-<span id="x" contenteditable="true">navigable__|</span><br />
+<span id="x" contenteditable="true" spellcheck="false">navigable__|</span><br />
 <script>
   document.getElementById('x').appendChild(document.createTextNode('unnavigable'));
 
   // Position the caret after "|"
   var sel = window.getSelection();
   sel.removeAllRanges();
   var range = document.createRange();
   var x = document.getElementById('x');
--- a/layout/base/tests/bug602141-3-ref.html
+++ b/layout/base/tests/bug602141-3-ref.html
@@ -1,12 +1,12 @@
 <!DOCTYPE HTML><html><head>
 </head>
 <body>
-noteditable<span id="x" contenteditable="true">navigable|unnavigable</span><br />
+noteditable<span id="x" contenteditable="true" spellcheck="false">navigable|unnavigable</span><br />
 <script>
   // Position the caret after "u"
   var sel = window.getSelection();
   sel.removeAllRanges();
   var range = document.createRange();
   var x = document.getElementById('x');
   var t = x.firstChild;
   range.setStart(t, 11);
--- a/layout/base/tests/bug602141-3.html
+++ b/layout/base/tests/bug602141-3.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
-noteditable<span id="x" contenteditable="true">navigable|unnavigable</span><br />
+noteditable<span id="x" contenteditable="true" spellcheck="false">navigable|unnavigable</span><br />
 <script>
   // Position the caret after "|"
   var sel = window.getSelection();
   sel.removeAllRanges();
   var range = document.createRange();
   var x = document.getElementById('x');
   var t = x.firstChild;
   range.setStart(t, 10);
--- a/layout/base/tests/bug602141-4-ref.html
+++ b/layout/base/tests/bug602141-4-ref.html
@@ -1,12 +1,12 @@
 <!DOCTYPE HTML><html><head>
 </head>
 <body>
-<span>not editable</span><span id="x" contenteditable="true">navigable|unnavigable</span>
+<span>not editable</span><span id="x" contenteditable="true" spellcheck="false">navigable|unnavigable</span>
 <script>
   // Position the caret after "u"
   var sel = window.getSelection();
   sel.removeAllRanges();
   var range = document.createRange();
   var x = document.getElementById('x');
   var t = x.firstChild;
   range.setStart(t, 11);
--- a/layout/base/tests/bug602141-4.html
+++ b/layout/base/tests/bug602141-4.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
-<span>not editable</span><span id="x" contenteditable="true">navigable|unnavigable</span>
+<span>not editable</span><span id="x" contenteditable="true" spellcheck="false">navigable|unnavigable</span>
 <script>
   // Position the caret after "|"
   var sel = window.getSelection();
   sel.removeAllRanges();
   var range = document.createRange();
   var x = document.getElementById('x');
   var t = x.firstChild;
   range.setStart(t, 10);
--- a/layout/base/tests/bug612271-1.html
+++ b/layout/base/tests/bug612271-1.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
- <textarea id="target" style="height: 100px"
+ <textarea id="target" style="height: 100px" spellcheck="false"
     onkeydown="this.style.display='block';this.style.height='200px';">foo</textarea>
 <script>
   var t = document.querySelector("textarea");
   t.focus();
   t.selectionStart = t.selectionEnd = t.value.length;
   sendKey('ENTER');
   document.body.appendChild(document.createTextNode(t.selectionStart + " - " + t.selectionEnd));
 </script>
--- a/layout/base/tests/bug612271-2.html
+++ b/layout/base/tests/bug612271-2.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
-  <textarea id="target" style="height: 100px"
+  <textarea id="target" style="height: 100px" spellcheck="false"
     onkeypress="this.style.display='block';this.style.height='200px';">foo</textarea>
 <script>
   var t = document.querySelector("textarea");
   t.focus();
   t.selectionStart = t.selectionEnd = t.value.length;
   sendKey('ENTER');
   document.body.appendChild(document.createTextNode(t.selectionStart + " - " + t.selectionEnd));
 </script>
--- a/layout/base/tests/bug612271-3.html
+++ b/layout/base/tests/bug612271-3.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
-  <textarea id="target" style="height: 100px"
+  <textarea id="target" style="height: 100px" spellcheck="false"
     onkeyup="this.style.display='block';this.style.height='200px';">foo</textarea>
 <script>
   var t = document.querySelector("textarea");
   t.focus();
   t.selectionStart = t.selectionEnd = t.value.length;
   sendKey('ENTER');
   document.body.appendChild(document.createTextNode(t.selectionStart + " - " + t.selectionEnd));
 </script>
--- a/layout/base/tests/bug612271-ref.html
+++ b/layout/base/tests/bug612271-ref.html
@@ -4,14 +4,14 @@
     function loaded() {
       var t = document.querySelector("textarea");
       t.focus();
       t.selectionStart = t.selectionEnd = 4;
     }
   </script>
 </head>
 <body onload="loaded()">
-  <textarea style="height: 200px; display: block;"
+  <textarea style="height: 200px; display: block;" spellcheck="false"
     >foo
 </textarea>
   4 - 4
 </body>
 </html>
--- a/layout/base/tests/bug632215-1.html
+++ b/layout/base/tests/bug632215-1.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
   <head>
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   </head>
   <body>
-    <iframe src="data:text/html,<body></body>"></iframe>
+    <iframe src="data:text/html,<body spellcheck=false></body>"></iframe>
     <script>
       onload = function() {
         var i = document.querySelector("iframe");
         var d = i.contentDocument;
         var w = i.contentWindow;
         var s = w.getSelection();
         i.focus();
         d.body.contentEditable = true;
--- a/layout/base/tests/bug632215-2.html
+++ b/layout/base/tests/bug632215-2.html
@@ -1,15 +1,15 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
   <head>
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   </head>
   <body>
-    <iframe src="data:text/html,<body contenteditable></body>"></iframe>
+    <iframe src="data:text/html,<body contenteditable spellcheck=false></body>"></iframe>
     <script>
       onload = function() {
         var i = document.querySelector("iframe");
         var d = i.contentDocument;
         var w = i.contentWindow;
         var s = w.getSelection();
         i.focus();
         d.body.contentEditable = false;
--- a/layout/base/tests/bug632215-ref.html
+++ b/layout/base/tests/bug632215-ref.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
   <body>
-    <iframe src="data:text/html,<body>xx</body>"></iframe>
+    <iframe src="data:text/html,<body spellcheck=false>xx</body>"></iframe>
     <script>
       onload = function() {
         var i = document.querySelector("iframe");
         var d = i.contentDocument;
         var w = i.contentWindow;
         d.designMode = "on";
         i.focus();
         d.body.focus();
--- a/layout/base/tests/bug634406-1-ref.html
+++ b/layout/base/tests/bug634406-1-ref.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML><html>
 <body>
-<textarea>ab</textarea>
+<textarea spellcheck="false">ab</textarea>
 <script>
   var t = document.querySelector("textarea");
   t.focus();
   t.selectionStart = t.selectionEnd = t.value.length;
 </script>
 </body>
 </html>
--- a/layout/base/tests/bug634406-1.html
+++ b/layout/base/tests/bug634406-1.html
@@ -1,13 +1,13 @@
 <!DOCTYPE HTML><html><head>
   <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
 </head>
 <body>
-<textarea></textarea>
+<textarea spellcheck="false"></textarea>
 <script>
   var t = document.querySelector("textarea");
   t.focus();
 
   synthesizeKey("a", {});
   synthesizeKey("A", {accelKey: true});
   synthesizeKey("VK_RIGHT", {});
   synthesizeKey("b", {});
--- a/layout/base/tests/bug664087-1-ref.html
+++ b/layout/base/tests/bug664087-1-ref.html
@@ -1,15 +1,15 @@
 <html class="reftest-wait">
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   </head>
   <body onload="start()">
-    <textarea onfocus="done()">אב
+    <textarea onfocus="done()" spellcheck="false">אב
 ג</textarea>
     <script>
       var textarea = document.querySelector("textarea");
       function start() {
         textarea.focus();
       }
       function done() {
         synthesizeKey("VK_LEFT", {});
--- a/layout/base/tests/bug664087-1.html
+++ b/layout/base/tests/bug664087-1.html
@@ -1,15 +1,15 @@
 <html class="reftest-wait">
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   </head>
   <body onload="start()">
-    <textarea onfocus="typeIntoMe()"></textarea>
+    <textarea onfocus="typeIntoMe()" spellcheck="false"></textarea>
     <script>
       function start() {
         document.querySelector("textarea").focus();
       }
       function typeIntoMe() {
         setTimeout(function() {
           synthesizeKey("א", {});
           synthesizeKey("VK_ENTER", {});
--- a/layout/base/tests/bug664087-2-ref.html
+++ b/layout/base/tests/bug664087-2-ref.html
@@ -1,15 +1,15 @@
 <html class="reftest-wait">
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   </head>
   <body onload="start()">
-    <textarea dir="rtl" onfocus="done()">ab
+    <textarea dir="rtl" onfocus="done()" spellcheck="false">ab
 c</textarea>
     <script>
       var textarea = document.querySelector("textarea");
       function start() {
         textarea.focus();
       }
       function done() {
         synthesizeKey("VK_RIGHT", {});
--- a/layout/base/tests/bug664087-2.html
+++ b/layout/base/tests/bug664087-2.html
@@ -1,15 +1,15 @@
 <html class="reftest-wait">
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   </head>
   <body onload="start()">
-    <textarea dir="rtl" onfocus="typeIntoMe()"></textarea>
+    <textarea dir="rtl" onfocus="typeIntoMe()" spellcheck="false"></textarea>
     <script>
       function start() {
         document.querySelector("textarea").focus();
       }
       function typeIntoMe() {
         setTimeout(function() {
           synthesizeKey("a", {});
           synthesizeKey("VK_ENTER", {});
--- a/layout/base/tests/bug682712-1-ref.html
+++ b/layout/base/tests/bug682712-1-ref.html
@@ -1,14 +1,14 @@
 <html class="reftest-wait">
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   </head>
   <body onload="start()">
-    <iframe src="data:text/html,<body contenteditable>foo bar"></iframe>
+    <iframe src="data:text/html,<body contenteditable spellcheck=false>foo bar"></iframe>
     <script>
       function start() {
         var iframe = document.querySelector("iframe");
         var win = iframe.contentWindow;
         var doc = iframe.contentDocument;
 
         setTimeout(function() {
           doc.body.focus();
--- a/layout/base/tests/bug682712-1.html
+++ b/layout/base/tests/bug682712-1.html
@@ -1,15 +1,15 @@
 <html class="reftest-wait">
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   </head>
   <body onload="start()">
-    <iframe src="data:text/html,<body contenteditable>foo bar"></iframe>
+    <iframe src="data:text/html,<body contenteditable spellcheck=false>foo bar"></iframe>
     <script>
       function start() {
         var iframe = document.querySelector("iframe");
         var win = iframe.contentWindow;
         var doc = iframe.contentDocument;
 
         // Reframe the iframe
         iframe.style.display = "none";
--- a/layout/base/tests/bug746993-1-ref.html
+++ b/layout/base/tests/bug746993-1-ref.html
@@ -1,15 +1,15 @@
 <html class="reftest-wait">
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   </head>
   <body onload="start()">
-    <iframe src="data:text/html,<body contenteditable>Here's some text.<br /><br /><div></div></body>"></iframe>
+    <iframe src="data:text/html,<body contenteditable spellcheck=false>Here's some text.<br /><br /><div></div></body>"></iframe>
     <script>
       function start() {
         var iframe = document.querySelector("iframe");
         var win = iframe.contentWindow;
         var doc = iframe.contentDocument;
         iframe.focus();
         doc.body.focus();
         win.getSelection().collapse(doc.body, 3);
--- a/layout/base/tests/bug746993-1.html
+++ b/layout/base/tests/bug746993-1.html
@@ -1,15 +1,15 @@
 <html class="reftest-wait">
   <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   </head>
   <body onload="start()">
-    <iframe src="data:text/html,<body contenteditable><br /><div></div></body>"></iframe>
+    <iframe src="data:text/html,<body contenteditable spellcheck=false><br /><div></div></body>"></iframe>
     <script>
       function start() {
         var iframe = document.querySelector("iframe");
         var win = iframe.contentWindow;
         var doc = iframe.contentDocument;
         iframe.focus();
         doc.body.focus();
         win.getSelection().collapse(doc.body, 0);
--- a/layout/reftests/reftest-sanity/reftest.list
+++ b/layout/reftests/reftest-sanity/reftest.list
@@ -39,17 +39,17 @@ HTTP != blank.html default.html
 skip-if(B2G) HTTP(..) == filter-1.xhtml filter-1-ref.xhtml
 skip-if(B2G) HTTP(..) == filter-2.xhtml filter-2-ref.xhtml # bug 773482
 
 # test that the MozReftestInvalidate event fires
 == invalidation.html about:blank
 == zoom-invalidation.html zoom-invalidation-ref.html # bug 773482
 
 # test that xulRuntime.OS works
-skip-if(B2G) fails-if(xulRuntime.OS!="Linux"&&!Android) == data:text/html,<body>Linux data:text/html,<script>document.write(navigator.platform.substr(0,5))</script>
+skip-if(B2G||B2GDT) fails-if(xulRuntime.OS!="Linux"&&!Android) == data:text/html,<body>Linux data:text/html,<script>document.write(navigator.platform.substr(0,5))</script>
 fails-if(xulRuntime.OS!="WINNT") == data:text/html,<body>Win data:text/html,<script>document.write(navigator.platform.substr(0,3))</script>
 fails-if(xulRuntime.OS!="Darwin") == data:text/html,<body>Mac data:text/html,<script>document.write(navigator.platform.substr(0,3))</script>
 
 # test parsing of asserts() expressions
 asserts(0) load about:blank
 asserts(0-5) load about:blank
 asserts-if(true,0) load about:blank
 asserts-if(false,7) load about:blank
@@ -71,19 +71,19 @@ include default-preferences-tests.list
 # test that all corners are visible
 != corners-1.html corners-1-ref.html
 != corners-2.html corners-2-ref.html
 != corners-3.html corners-3-ref.html
 != corners-4.html corners-4-ref.html
 
 # Test that the harness gives the correct page dimensions.
 != page-width-3.9in.html page-width-4in.html
-skip-if(B2G) == page-width-4.1in.html page-width-4in.html   # bug 774396
-skip-if(B2G) == page-width-auto.html page-width-4in.html    # bug 774396
-skip-if(B2G) != page-height-2in.html page-height-2.1in.html # bug 774396
+skip-if(B2G||B2GDT) == page-width-4.1in.html page-width-4in.html   # bug 774396
+skip-if(B2G||B2GDT) == page-width-auto.html page-width-4in.html    # bug 774396
+skip-if(B2G||B2GDT) != page-height-2in.html page-height-2.1in.html # bug 774396
 == page-height-2in.html page-height-nobreak.html
 == page-height-2.1in.html page-height-forcebreak.html
 
 # Check that tests that need focus are skipped when it's not available
 needs-focus load needs-focus.html
 
 # Bug 632636
 fails == data:text/plain,HELLO about:blank
--- a/layout/tools/reftest/Makefile.in
+++ b/layout/tools/reftest/Makefile.in
@@ -40,16 +40,17 @@ make-xpi:
 copy-harness: make-xpi
 libs:: copy-harness
 endif
 
 _HARNESS_FILES = \
   $(srcdir)/runreftest.py \
   $(srcdir)/remotereftest.py \
   $(srcdir)/runreftestb2g.py \
+  $(srcdir)/b2g_desktop.py \
   $(srcdir)/b2g_start_script.js \
   automation.py \
   $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanager.py \
   $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py \
   $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py \
   $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/droid.py \
   $(topsrcdir)/testing/mozbase/mozdevice/mozdevice/Zeroconf.py \
   $(topsrcdir)/build/mobile/b2gautomation.py \
new file mode 100644
--- /dev/null
+++ b/layout/tools/reftest/b2g_desktop.py
@@ -0,0 +1,170 @@
+# 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/.
+from __future__ import print_function, unicode_literals
+
+import json
+import os
+import signal
+import sys
+import threading
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+from runreftest import RefTest, ReftestOptions
+
+from marionette import Marionette
+from mozprocess import ProcessHandler
+from mozrunner import FirefoxRunner
+import mozinfo
+import mozlog
+
+log = mozlog.getLogger('REFTEST')
+
+class B2GDesktopReftest(RefTest):
+    def __init__(self, marionette):
+        RefTest.__init__(self)
+        self.last_test = os.path.basename(__file__)
+        self.marionette = marionette
+        self.profile = None
+        self.runner = None
+        self.test_script = os.path.join(here, 'b2g_start_script.js')
+        self.timeout = None
+
+    def run_marionette_script(self):
+        assert(self.marionette.wait_for_port())
+        self.marionette.start_session()
+        self.marionette.set_context(self.marionette.CONTEXT_CHROME)
+
+        if os.path.isfile(self.test_script):
+            f = open(self.test_script, 'r')
+            self.test_script = f.read()
+            f.close()
+        self.marionette.execute_script(self.test_script)
+
+    def run_tests(self, test_path, options):
+        reftestlist = self.getManifestPath(test_path)
+        if not reftestlist.startswith('file://'):
+            reftestlist = 'file://%s' % reftestlist
+
+        self.profile = self.create_profile(options, reftestlist,
+                                           profile_to_clone=options.profile)
+        env = self.buildBrowserEnv(options, self.profile.profile)
+        kp_kwargs = { 'processOutputLine': [self._on_output],
+                      'onTimeout': [self._on_timeout],
+                      'kill_on_timeout': False }
+
+        if not options.debugger:
+            if not options.timeout:
+                if mozinfo.info['debug']:
+                    options.timeout = 420
+                else:
+                    options.timeout = 300
+            self.timeout = options.timeout + 30.0
+
+        log.info("%s | Running tests: start.", os.path.basename(__file__))
+        cmd, args = self.build_command_line(options.app,
+                            ignore_window_size=options.ignoreWindowSize)
+        self.runner = FirefoxRunner(profile=self.profile,
+                                    binary=cmd,
+                                    cmdargs=args,
+                                    env=env,
+                                    process_class=ProcessHandler,
+                                    symbols_path=options.symbolsPath,
+                                    kp_kwargs=kp_kwargs)
+
+        status = 0
+        try:
+            self.runner.start(outputTimeout=self.timeout)
+            log.info("%s | Application pid: %d",
+                     os.path.basename(__file__),
+                     self.runner.process_handler.pid)
+
+            # kick starts the reftest harness
+            self.run_marionette_script()
+            status = self.runner.wait()
+        finally:
+            self.runner.check_for_crashes(test_name=self.last_test)
+            self.runner.cleanup()
+
+        if status > 0:
+            log.testFail("%s | application terminated with exit code %s",
+                         self.last_test, status)
+        elif status < 0:
+            log.info("%s | application killed with signal %s",
+                         self.last_test, -status)
+
+        log.info("%s | Running tests: end.", os.path.basename(__file__))
+        return status
+
+    def create_profile(self, options, reftestlist, profile_to_clone=None):
+        profile = RefTest.createReftestProfile(self, options, reftestlist,
+                                               profile_to_clone=profile_to_clone)
+
+        prefs = {}
+        # Turn off the locale picker screen
+        prefs["browser.firstrun.show.localepicker"] = False
+        prefs["browser.homescreenURL"] = "app://test-container.gaiamobile.org/index.html"
+        prefs["browser.manifestURL"] = "app://test-container.gaiamobile.org/manifest.webapp"
+        prefs["browser.tabs.remote"] = False
+        prefs["dom.ipc.tabs.disabled"] = False
+        prefs["dom.mozBrowserFramesEnabled"] = True
+        prefs["font.size.inflation.emPerLine"] = 0
+        prefs["font.size.inflation.minTwips"] = 0
+        prefs["network.dns.localDomains"] = "app://test-container.gaiamobile.org"
+        prefs["reftest.browser.iframe.enabled"] = False
+        prefs["reftest.remote"] = False
+        prefs["reftest.uri"] = "%s" % reftestlist
+        # Set a future policy version to avoid the telemetry prompt.
+        prefs["toolkit.telemetry.prompted"] = 999
+        prefs["toolkit.telemetry.notifiedOptOut"] = 999
+
+        # Set the extra prefs.
+        profile.set_preferences(prefs)
+        return profile
+
+    def build_command_line(self, app, ignore_window_size=False):
+        cmd = os.path.abspath(app)
+        args = []
+
+        if not ignore_window_size:
+            args.extend(['--screen', '800x1000'])
+        return cmd, args
+
+    def _on_output(self, line):
+        print(line)
+        # TODO use structured logging
+        if "TEST-START" in line and "|" in line:
+            self.last_test = line.split("|")[1].strip()
+
+    def _on_timeout(self):
+        msg = "%s | application timed out after %s seconds with no output"
+        log.testFail(msg % (self.last_test, self.timeout))
+
+        # kill process to get a stack
+        self.runner.stop(sig=signal.SIGABRT)
+
+
+def run_desktop_reftests(parser, options, args):
+    kwargs = {}
+    if options.marionette:
+        host, port = options.marionette.split(':')
+        kwargs['host'] = host
+        kwargs['port'] = int(port)
+    marionette = Marionette.getMarionetteOrExit(**kwargs)
+
+    reftest = B2GDesktopReftest(marionette)
+
+    options = ReftestOptions.verifyCommonOptions(parser, options, reftest)
+    if options == None:
+        sys.exit(1)
+
+    # add a -bin suffix if b2g-bin exists, but just b2g was specified
+    if options.app[-4:] != '-bin':
+        if os.path.isfile("%s-bin" % options.app):
+            options.app = "%s-bin" % options.app
+
+    if options.desktop and not options.profile:
+        raise Exception("must specify --profile when specifying --desktop")
+
+    sys.exit(reftest.run_tests(args[0], options))
--- a/layout/tools/reftest/b2g_start_script.js
+++ b/layout/tools/reftest/b2g_start_script.js
@@ -1,15 +1,12 @@
 /* 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/. */
 
-let serverAddr = __marionetteParams[0];
-let serverPort = __marionetteParams[1];
-
 function setDefaultPrefs() {
     // This code sets the preferences for extension-based reftest; for
     // command-line based reftest they are set in function handler_handle in
     // reftest-cmdline.js.  These two locations should stay in sync.
     //
     // FIXME: These should be in only one place.
     var prefs = Cc["@mozilla.org/preferences-service;1"].
                 getService(Ci.nsIPrefService);
@@ -39,16 +36,22 @@ function setDefaultPrefs() {
     // Checking whether two files are the same is slow on Windows.
     // Setting this pref makes tests run much faster there.
     branch.setBoolPref("security.fileuri.strict_origin_policy", false);
     // Disable the thumbnailing service
     branch.setBoolPref("browser.pagethumbnails.capturing_disabled", true);
 }
 
 function setPermissions() {
+  if (__marionetteParams.length < 2) {
+    return;
+  }
+
+  let serverAddr = __marionetteParams[0];
+  let serverPort = __marionetteParams[1];
   let perms = Cc["@mozilla.org/permissionmanager;1"]
               .getService(Ci.nsIPermissionManager);
   let ioService = Cc["@mozilla.org/network/io-service;1"]
                   .getService(Ci.nsIIOService);
   let uri = ioService.newURI("http://" + serverAddr + ":" + serverPort, null, null);
   perms.add(uri, "allowXULXBL", Ci.nsIPermissionManager.ALLOW_ACTION);
 }
 
--- a/layout/tools/reftest/reftest.js
+++ b/layout/tools/reftest/reftest.js
@@ -389,16 +389,25 @@ function InitAndStartRefTests()
     gIOService = CC[IO_SERVICE_CONTRACTID].getService(CI.nsIIOService);
     gDebug = CC[DEBUG_CONTRACTID].getService(CI.nsIDebug2);
 
     RegisterProcessCrashObservers();
 
     if (gRemote) {
         gServer = null;
     } else {
+        // not all gecko applications autoregister xpcom components
+        if (CC["@mozilla.org/server/jshttp;1"] === undefined) {
+            var file = CC["@mozilla.org/file/directory_service;1"].
+                        getService(CI.nsIProperties).get("ProfD", CI.nsIFile);
+            file.appendRelativePath("extensions/reftest@mozilla.org/chrome.manifest");
+
+            registrar = Components.manager.QueryInterface(CI.nsIComponentRegistrar);
+            registrar.autoRegister(file);
+        }
         gServer = CC["@mozilla.org/server/jshttp;1"].
                       createInstance(CI.nsIHttpServer);
     }
     try {
         if (gServer)
             StartHTTPServer();
     } catch (ex) {
         //gBrowser.loadURI('data:text/plain,' + ex);
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -103,17 +103,17 @@ class RemoteOptions(ReftestOptions):
         self.set_defaults(**defaults)
 
     def verifyRemoteOptions(self, options):
         if options.runTestsInParallel:
             self.error("Cannot run parallel tests here")
 
         # Ensure our defaults are set properly for everything we can infer
         if not options.remoteTestRoot:
-            options.remoteTestRoot = self._automation._devicemanager.getDeviceRoot() + '/reftest'
+            options.remoteTestRoot = self.automation._devicemanager.getDeviceRoot() + '/reftest'
         options.remoteProfile = options.remoteTestRoot + "/profile"
 
         # Verify that our remotewebserver is set properly
         if (options.remoteWebServer == None or
             options.remoteWebServer == '127.0.0.1'):
             print "ERROR: Either you specified the loopback for the remote webserver or ",
             print "your local IP cannot be detected.  Please provide the local ip in --remote-webserver"
             return None
@@ -161,70 +161,70 @@ class RemoteOptions(ReftestOptions):
 
         # httpd-path is specified by standard makefile targets and may be specified
         # on the command line to select a particular version of httpd.js. If not
         # specified, try to select the one from hostutils.zip, as required in bug 882932.
         if not options.httpdPath:
             options.httpdPath = os.path.join(options.utilityPath, "components")
 
         # TODO: Copied from main, but I think these are no longer used in a post xulrunner world
-        #options.xrePath = options.remoteTestRoot + self._automation._product + '/xulrunner'
-        #options.utilityPath = options.testRoot + self._automation._product + '/bin'
+        #options.xrePath = options.remoteTestRoot + self.automation._product + '/xulrunner'
+        #options.utilityPath = options.testRoot + self.automation._product + '/bin'
         return options
 
 class ReftestServer:
     """ Web server used to serve Reftests, for closer fidelity to the real web.
         It is virtually identical to the server used in mochitest and will only
         be used for running reftests remotely.
         Bug 581257 has been filed to refactor this wrapper around httpd.js into
         it's own class and use it in both remote and non-remote testing. """
 
     def __init__(self, automation, options, scriptDir):
-        self._automation = automation
+        self.automation = automation
         self._utilityPath = options.utilityPath
         self._xrePath = options.xrePath
         self._profileDir = options.serverProfilePath
         self.webServer = options.remoteWebServer
         self.httpPort = options.httpPort
         self.scriptDir = scriptDir
         self.pidFile = options.pidFile
         self._httpdPath = os.path.abspath(options.httpdPath)
         self.shutdownURL = "http://%(server)s:%(port)s/server/shutdown" % { "server" : self.webServer, "port" : self.httpPort }
 
     def start(self):
         "Run the Refest server, returning the process ID of the server."
 
-        env = self._automation.environment(xrePath = self._xrePath)
+        env = self.automation.environment(xrePath = self._xrePath)
         env["XPCOM_DEBUG_BREAK"] = "warn"
-        if self._automation.IS_WIN32:
+        if self.automation.IS_WIN32:
             env["PATH"] = env["PATH"] + ";" + self._xrePath
 
         args = ["-g", self._xrePath,
                 "-v", "170",
                 "-f", os.path.join(self._httpdPath, "httpd.js"),
                 "-e", "const _PROFILE_PATH = '%(profile)s';const _SERVER_PORT = '%(port)s'; const _SERVER_ADDR ='%(server)s';" %
                        {"profile" : self._profileDir.replace('\\', '\\\\'), "port" : self.httpPort, "server" : self.webServer },
                 "-f", os.path.join(self.scriptDir, "server.js")]
 
         xpcshell = os.path.join(self._utilityPath,
-                                "xpcshell" + self._automation.BIN_SUFFIX)
+                                "xpcshell" + self.automation.BIN_SUFFIX)
 
         if not os.access(xpcshell, os.F_OK):
             raise Exception('xpcshell not found at %s' % xpcshell)
-        if self._automation.elf_arm(xpcshell):
+        if self.automation.elf_arm(xpcshell):
             raise Exception('xpcshell at %s is an ARM binary; please use '
                             'the --utility-path argument to specify the path '
                             'to a desktop version.' % xpcshell)
 
-        self._process = self._automation.Process([xpcshell] + args, env = env)
+        self._process = self.automation.Process([xpcshell] + args, env = env)
         pid = self._process.pid
         if pid < 0:
             print "TEST-UNEXPECTED-FAIL | remotereftests.py | Error starting server."
             return 2
-        self._automation.log.info("INFO | remotereftests.py | Server pid: %d", pid)
+        self.automation.log.info("INFO | remotereftests.py | Server pid: %d", pid)
 
         if (self.pidFile != ""):
             f = open(self.pidFile + ".xpcshell.pid", 'w')
             f.write("%s" % pid)
             f.close()
 
     def ensureReady(self, timeout):
         assert timeout >= 0
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -1,32 +1,37 @@
 # 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/.
 
 """
 Runs the reftest test harness.
 """
 
-import re
-import sys
-import shutil
+from optparse import OptionParser
+import collections
+import json
+import multiprocessing
 import os
-import threading
+import re
+import shutil
 import subprocess
-import collections
-import multiprocessing
+import sys
+import threading
+
 SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
 sys.path.insert(0, SCRIPT_DIRECTORY)
 
 from automation import Automation
-from automationutils import *
-from optparse import OptionParser
-from tempfile import mkdtemp
-
+from automationutils import (
+        addCommonOptions,
+        getDebuggerInfo,
+        isURL,
+        processLeakLog
+)
 import mozprofile
 
 def categoriesToRegex(categoryList):
   return "\\(" + ', '.join(["(?P<%s>\\d+) %s" % c for c in categoryList]) + "\\)"
 summaryLines = [('Successful', [('pass', 'pass'), ('loadOnly', 'load only')]),
                 ('Unexpected', [('fail', 'unexpected fail'),
                                 ('pass', 'unexpected pass'),
                                 ('asserts', 'unexpected asserts'),
@@ -124,21 +129,21 @@ class RefTest(object):
         if os.path.exists(defaultManifestPath):
           path = defaultManifestPath
     return path
 
   def makeJSString(self, s):
     return '"%s"' % re.sub(r'([\\"])', r'\\\1', s)
 
   def createReftestProfile(self, options, manifest, server='localhost',
-                           special_powers=True):
+                           special_powers=True, profile_to_clone=None):
     """
       Sets up a profile for reftest.
       'manifest' is the path to the reftest.list file we want to test with.  This is used in
-      the remote subclass in remotereftest.py so we can write it to a preference for the 
+      the remote subclass in remotereftest.py so we can write it to a preference for the
       bootstrap extension.
     """
 
     locations = mozprofile.permissions.ServerLocations()
     locations.add_host(server, port=0)
     locations.add_host('<file>', port=0)
 
     # Set preferences for communication between our command line arguments
@@ -179,34 +184,37 @@ class RefTest(object):
     if os.path.isdir(distExtDir):
       for f in os.listdir(distExtDir):
         addons.append(os.path.join(distExtDir, f))
 
     # Install custom extensions.
     for f in options.extensionsToInstall:
       addons.append(self.getFullPath(f))
 
-    profile = mozprofile.profile.Profile(
-        addons=addons,
-        preferences=prefs,
-        locations=locations,
-    )
+    kwargs = { 'addons': addons,
+               'preferences': prefs,
+               'locations': locations }
+    if profile_to_clone:
+        profile = mozprofile.Profile.clone(profile_to_clone, **kwargs)
+    else:
+        profile = mozprofile.Profile(**kwargs)
+
     self.copyExtraFilesToProfile(options, profile)
     return profile
 
   def buildBrowserEnv(self, options, profileDir):
     browserEnv = self.automation.environment(xrePath = options.xrePath)
     browserEnv["XPCOM_DEBUG_BREAK"] = "stack"
 
     for v in options.environment:
       ix = v.find("=")
       if ix <= 0:
         print "Error: syntax error in --setenv=" + v
         return None
-      browserEnv[v[:ix]] = v[ix + 1:]    
+      browserEnv[v[:ix]] = v[ix + 1:]
 
     # Enable leaks detection to its own log file.
     self.leakLogFile = os.path.join(profileDir, "runreftest_leaks.log")
     browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leakLogFile
     return browserEnv
 
   def cleanup(self, profileDir):
     if profileDir:
@@ -333,68 +341,68 @@ class RefTest(object):
         shutil.copytree(abspath, dest)
       else:
         self.automation.log.warning("WARNING | runreftest.py | Failed to copy %s to profile", abspath)
         continue
 
 
 class ReftestOptions(OptionParser):
 
-  def __init__(self, automation):
-    self._automation = automation
+  def __init__(self, automation=None):
+    self.automation = automation or Automation()
     OptionParser.__init__(self)
     defaults = {}
 
     # we want to pass down everything from automation.__all__
-    addCommonOptions(self, 
-                     defaults=dict(zip(self._automation.__all__, 
-                            [getattr(self._automation, x) for x in self._automation.__all__])))
-    self._automation.addCommonOptions(self)
+    addCommonOptions(self,
+                     defaults=dict(zip(self.automation.__all__,
+                            [getattr(self.automation, x) for x in self.automation.__all__])))
+    self.automation.addCommonOptions(self)
     self.add_option("--appname",
                     action = "store", type = "string", dest = "app",
                     default = os.path.join(SCRIPT_DIRECTORY, automation.DEFAULT_APP),
                     help = "absolute path to application, overriding default")
     self.add_option("--extra-profile-file",
                     action = "append", dest = "extraProfileFiles",
                     default = [],
                     help = "copy specified files/dirs to testing profile")
-    self.add_option("--timeout",              
-                    action = "store", dest = "timeout", type = "int", 
+    self.add_option("--timeout",
+                    action = "store", dest = "timeout", type = "int",
                     default = 5 * 60, # 5 minutes per bug 479518
                     help = "reftest will timeout in specified number of seconds. [default %default s].")
     self.add_option("--leak-threshold",
                     action = "store", type = "int", dest = "leakThreshold",
                     default = 0,
                     help = "fail if the number of bytes leaked through "
                            "refcounted objects (or bytes in classes with "
                            "MOZ_COUNT_CTOR and MOZ_COUNT_DTOR) is greater "
                            "than the given number")
     self.add_option("--utility-path",
                     action = "store", type = "string", dest = "utilityPath",
-                    default = self._automation.DIST_BIN,
+                    default = self.automation.DIST_BIN,
                     help = "absolute path to directory containing utility "
                            "programs (xpcshell, ssltunnel, certutil)")
-    defaults["utilityPath"] = self._automation.DIST_BIN
+    defaults["utilityPath"] = self.automation.DIST_BIN
 
     self.add_option("--total-chunks",
                     type = "int", dest = "totalChunks",
                     help = "how many chunks to split the tests up into")
     defaults["totalChunks"] = None
 
     self.add_option("--this-chunk",
                     type = "int", dest = "thisChunk",
                     help = "which chunk to run between 1 and --total-chunks")
     defaults["thisChunk"] = None
 
     self.add_option("--log-file",
                     action = "store", type = "string", dest = "logFile",
                     default = None,
                     help = "file to log output to in addition to stdout")
     defaults["logFile"] = None
- 
+
     self.add_option("--skip-slow-tests",
                     dest = "skipSlowTests", action = "store_true",
                     help = "skip tests marked as slow when running")
     defaults["skipSlowTests"] = False
 
     self.add_option("--ignore-window-size",
                     dest = "ignoreWindowSize", action = "store_true",
                     help = "ignore the window size, which may cause spurious failures and passes")
--- a/layout/tools/reftest/runreftestb2g.py
+++ b/layout/tools/reftest/runreftestb2g.py
@@ -4,29 +4,28 @@
 
 import ConfigParser
 import os
 import sys
 import tempfile
 import traceback
 
 # We need to know our current directory so that we can serve our test files from it.
-SCRIPT_DIRECTORY = os.path.abspath(os.path.realpath(os.path.dirname(sys.argv[0])))
-sys.path.insert(0, SCRIPT_DIRECTORY)
+here = os.path.abspath(os.path.dirname(__file__))
 
 from automation import Automation
 from b2gautomation import B2GRemoteAutomation
+from b2g_desktop import run_desktop_reftests
 from runreftest import RefTest
 from runreftest import ReftestOptions
 from remotereftest import ReftestServer
 
 from mozdevice import DeviceManagerADB, DMError
 from marionette import Marionette
 
-
 class B2GOptions(ReftestOptions):
 
     def __init__(self, automation=None, **kwargs):
         defaults = {}
         if not automation:
             automation = B2GRemoteAutomation(None, "fennec", context_chrome=True)
 
         ReftestOptions.__init__(self, automation)
@@ -106,40 +105,49 @@ class B2GOptions(ReftestOptions):
         self.add_option('--busybox', action='store',
                         type='string', dest='busybox',
                         help="Path to busybox binary to install on device")
         defaults['busybox'] = None
         self.add_option("--httpd-path", action = "store",
                     type = "string", dest = "httpdPath",
                     help = "path to the httpd.js file")
         defaults["httpdPath"] = None
+        self.add_option("--profile", action="store",
+                    type="string", dest="profile",
+                    help="for desktop testing, the path to the "
+                         "gaia profile to use")
+        defaults["profile"] = None
+        self.add_option("--desktop", action="store_true",
+                        dest="desktop",
+                        help="Run the tests on a B2G desktop build")
+        defaults["desktop"] = False
         defaults["remoteTestRoot"] = "/data/local/tests"
         defaults["logFile"] = "reftest.log"
         defaults["autorun"] = True
         defaults["closeWhenDone"] = True
         defaults["testPath"] = ""
         defaults["runTestsInParallel"] = False
 
         self.set_defaults(**defaults)
 
     def verifyRemoteOptions(self, options):
         if options.runTestsInParallel:
             self.error("Cannot run parallel tests here")
 
         if not options.remoteTestRoot:
-            options.remoteTestRoot = self._automation._devicemanager.getDeviceRoot() + "/reftest"
+            options.remoteTestRoot = self.automation._devicemanager.getDeviceRoot() + "/reftest"
         options.remoteProfile = options.remoteTestRoot + "/profile"
 
-        productRoot = options.remoteTestRoot + "/" + self._automation._product
-        if options.utilityPath == self._automation.DIST_BIN:
+        productRoot = options.remoteTestRoot + "/" + self.automation._product
+        if options.utilityPath == self.automation.DIST_BIN:
             options.utilityPath = productRoot + "/bin"
 
         if options.remoteWebServer == None:
             if os.name != "nt":
-                options.remoteWebServer = self._automation.getLanIp()
+                options.remoteWebServer = self.automation.getLanIp()
             else:
                 print "ERROR: you must specify a --remote-webserver=<ip address>\n"
                 return None
 
         options.webServer = options.remoteWebServer
 
         if options.geckoPath and not options.emulator:
             self.error("You must specify --emulator if you specify --gecko-path")
@@ -204,43 +212,40 @@ class ProfileConfigParser(ConfigParser.R
             for (key, value) in self._sections[section].items():
                 if key == "__name__":
                     continue
                 if (value is not None) or (self._optcre == self.OPTCRE):
                     key = "=".join((key, str(value).replace('\n', '\n\t')))
                 fp.write("%s\n" % (key))
             fp.write("\n")
 
+class B2GRemoteReftest(RefTest):
 
-class B2GReftest(RefTest):
-
-    _automation = None
     _devicemanager = None
     localProfile = None
     remoteApp = ''
     profile = None
 
     def __init__(self, automation, devicemanager, options, scriptDir):
-        self._automation = automation
-        RefTest.__init__(self, self._automation)
+        RefTest.__init__(self, automation)
         self._devicemanager = devicemanager
         self.runSSLTunnel = False
         self.remoteTestRoot = options.remoteTestRoot
         self.remoteProfile = options.remoteProfile
-        self._automation.setRemoteProfile(self.remoteProfile)
+        self.automation.setRemoteProfile(self.remoteProfile)
         self.localLogName = options.localLogName
         self.remoteLogFile = options.remoteLogFile
         self.bundlesDir = '/system/b2g/distribution/bundles'
         self.userJS = '/data/local/user.js'
         self.remoteMozillaPath = '/data/b2g/mozilla'
         self.remoteProfilesIniPath = os.path.join(self.remoteMozillaPath, 'profiles.ini')
         self.originalProfilesIni = None
         self.scriptDir = scriptDir
         self.SERVER_STARTUP_TIMEOUT = 90
-        if self._automation.IS_DEBUG_BUILD:
+        if self.automation.IS_DEBUG_BUILD:
             self.SERVER_STARTUP_TIMEOUT = 180
 
     def cleanup(self, profileDir):
         # Pull results back from device
         if (self.remoteLogFile):
             try:
                 self._devicemanager.getFile(self.remoteLogFile, self.localLogName)
             except:
@@ -254,34 +259,34 @@ class B2GReftest(RefTest):
                 self._devicemanager._checkCmdAs(['shell', 'rm', '-rf',
                                                  os.path.join(self.bundlesDir, filename)])
             except DMError:
                 pass
 
         # Restore the original profiles.ini.
         if self.originalProfilesIni:
             try:
-                if not self._automation._is_emulator:
+                if not self.automation._is_emulator:
                     self.restoreProfilesIni()
                 os.remove(self.originalProfilesIni)
             except:
                 pass
 
-        if not self._automation._is_emulator:
+        if not self.automation._is_emulator:
             self._devicemanager.removeFile(self.remoteLogFile)
             self._devicemanager.removeDir(self.remoteProfile)
             self._devicemanager.removeDir(self.remoteTestRoot)
 
             # Restore the original user.js.
             self._devicemanager._checkCmdAs(['shell', 'rm', '-f', self.userJS])
             self._devicemanager._checkCmdAs(['shell', 'dd', 'if=%s.orig' % self.userJS, 'of=%s' % self.userJS])
 
             # We've restored the original profile, so reboot the device so that
             # it gets picked up.
-            self._automation.rebootDevice()
+            self.automation.rebootDevice()
 
         RefTest.cleanup(self, profileDir)
         if getattr(self, 'pidFile', '') != '':
             try:
                 os.remove(self.pidFile)
                 os.remove(self.pidFile + ".xpcshell.pid")
             except:
                 print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % self.pidFile
@@ -312,18 +317,18 @@ class B2GReftest(RefTest):
             localAutomation.IS_LINUX = True
             localAutomation.UNIXISH = True
         elif hostos in ['win32', 'win64']:
             localAutomation.BIN_SUFFIX = ".exe"
             localAutomation.IS_WIN32 = True
 
         paths = [options.xrePath,
                  localAutomation.DIST_BIN,
-                 self._automation._product,
-                 os.path.join('..', self._automation._product)]
+                 self.automation._product,
+                 os.path.join('..', self.automation._product)]
         options.xrePath = self.findPath(paths)
         if options.xrePath == None:
             print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name)
             sys.exit(1)
         paths.append("bin")
         paths.append(os.path.join("..", "bin"))
 
         xpcshell = "xpcshell"
@@ -333,17 +338,17 @@ class B2GReftest(RefTest):
         if (options.utilityPath):
             paths.insert(0, options.utilityPath)
         options.utilityPath = self.findPath(paths, xpcshell)
         if options.utilityPath == None:
             print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name)
             sys.exit(1)
 
         xpcshell = os.path.join(options.utilityPath, xpcshell)
-        if self._automation.elf_arm(xpcshell):
+        if self.automation.elf_arm(xpcshell):
             raise Exception('xpcshell at %s is an ARM binary; please use '
                             'the --utility-path argument to specify the path '
                             'to a desktop version.' % xpcshell)
 
         options.serverProfilePath = tempfile.mkdtemp()
         self.server = ReftestServer(localAutomation, options, self.scriptDir)
         retVal = self.server.start()
         if retVal:
@@ -362,17 +367,16 @@ class B2GReftest(RefTest):
         options.utilityPath = remoteUtilityPath
         options.profilePath = remoteProfilePath
         return 0
 
     def stopWebServer(self, options):
         if hasattr(self, 'server'):
             self.server.stop()
 
-
     def restoreProfilesIni(self):
         # restore profiles.ini on the device to its previous state
         if not self.originalProfilesIni or not os.access(self.originalProfilesIni, os.F_OK):
             raise DMError('Unable to install original profiles.ini; file not found: %s',
                           self.originalProfilesIni)
 
         self._devicemanager.pushFile(self.originalProfilesIni, self.remoteProfilesIniPath)
 
@@ -465,16 +469,17 @@ class B2GReftest(RefTest):
             self._devicemanager.pushDir(profileDir, options.remoteProfile)
         except DMError:
             print "Automation Error: Failed to copy extra files to device"
             raise
 
     def getManifestPath(self, path):
         return path
 
+
 def run_remote_reftests(parser, options, args):
     auto = B2GRemoteAutomation(None, "fennec", context_chrome=True)
 
     # create our Marionette instance
     kwargs = {}
     if options.emulator:
         kwargs['emulator'] = options.emulator
         auto.setEmulator(True)
@@ -520,37 +525,37 @@ def run_remote_reftests(parser, options,
         parts = dm.getInfo('screen')['screen'][0].split()
         width = int(parts[0].split(':')[1])
         height = int(parts[1].split(':')[1])
         if (width < 1366 or height < 1050):
             print "ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (width, height)
             return 1
 
     auto.setProduct("b2g")
-    auto.test_script = os.path.join(SCRIPT_DIRECTORY, 'b2g_start_script.js')
+    auto.test_script = os.path.join(here, 'b2g_start_script.js')
     auto.test_script_args = [options.remoteWebServer, options.httpPort]
     auto.logFinish = "REFTEST TEST-START | Shutdown"
 
-    reftest = B2GReftest(auto, dm, options, SCRIPT_DIRECTORY)
+    reftest = B2GRemoteReftest(auto, dm, options, here)
     options = parser.verifyCommonOptions(options, reftest)
 
     logParent = os.path.dirname(options.remoteLogFile)
     dm.mkDir(logParent);
     auto.setRemoteLog(options.remoteLogFile)
     auto.setServerInfo(options.webServer, options.httpPort, options.sslPort)
 
     # Hack in a symbolic link for jsreftest
-    os.system("ln -s %s %s" % (os.path.join('..', 'jsreftest'), os.path.join(SCRIPT_DIRECTORY, 'jsreftest')))
+    os.system("ln -s %s %s" % (os.path.join('..', 'jsreftest'), os.path.join(here, 'jsreftest')))
 
     # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot
     manifest = args[0]
-    if os.path.exists(os.path.join(SCRIPT_DIRECTORY, args[0])):
+    if os.path.exists(os.path.join(here, args[0])):
         manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, args[0])
     elif os.path.exists(args[0]):
-        manifestPath = os.path.abspath(args[0]).split(SCRIPT_DIRECTORY)[1].strip('/')
+        manifestPath = os.path.abspath(args[0]).split(here)[1].strip('/')
         manifest = "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, manifestPath)
     else:
         print "ERROR: Could not find test manifest '%s'" % manifest
         return 1
 
     # Start the webserver
     retVal = 1
     try:
@@ -577,14 +582,17 @@ def run_remote_reftests(parser, options,
         return 1
 
     reftest.stopWebServer(options)
     return retVal
 
 def main(args=sys.argv[1:]):
     parser = B2GOptions()
     options, args = parser.parse_args(args)
+
+    if options.desktop:
+        return run_desktop_reftests(parser, options, args)
     return run_remote_reftests(parser, options, args)
 
 
 if __name__ == "__main__":
     sys.exit(main())
 
--- a/media/mtransport/third_party/nICEr/src/ice/ice_socket.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_socket.c
@@ -76,17 +76,17 @@ static void nr_ice_socket_readable_cb(NR
     if (len_s > (size_t)INT_MAX)
       return;
 
     len = (int)len_s;
 
 #ifdef USE_TURN
   re_process:
 #endif /* USE_TURN */
-    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Read %d bytes",sock->ctx->label,len);
+    r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Read %d bytes from %s",sock->ctx->label,len,addr.as_string);
 
     /* First question: is this STUN or not? */
     is_stun=nr_is_stun_message(buf,len);
 
     if(is_stun){
       is_req=nr_is_stun_request_message(buf,len);
       is_ind=is_req?0:nr_is_stun_indication_message(buf,len);
 
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
@@ -18,16 +18,17 @@
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsThreadUtils.h"
 #ifdef MOZILLA_INTERNAL_API
 #include "Latency.h"
 #endif
 
 #include "webrtc/voice_engine/include/voe_errors.h"
+#include "webrtc/system_wrappers/interface/clock.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidJNIWrapper.h"
 #endif
 
 namespace mozilla {
 
 static const char* logTag ="WebrtcAudioSessionConduit";
@@ -140,23 +141,73 @@ WebrtcAudioConduit::~WebrtcAudioConduit(
 bool WebrtcAudioConduit::GetLocalSSRC(unsigned int* ssrc) {
   return !mPtrRTP->GetLocalSSRC(mChannel, *ssrc);
 }
 
 bool WebrtcAudioConduit::GetRemoteSSRC(unsigned int* ssrc) {
   return !mPtrRTP->GetRemoteSSRC(mChannel, *ssrc);
 }
 
-bool WebrtcAudioConduit::GetReceivedJitter(unsigned int* jitterMs) {
+bool WebrtcAudioConduit::GetRTPJitter(unsigned int* jitterMs) {
   unsigned int maxJitterMs;
   unsigned int discardedPackets;
   return !mPtrRTP->GetRTPStatistics(mChannel, *jitterMs, maxJitterMs,
                                     discardedPackets);
 }
 
+DOMHighResTimeStamp
+NTPtoDOMHighResTimeStamp(uint32_t ntpHigh, uint32_t ntpLow) {
+  return (uint32_t(ntpHigh - webrtc::kNtpJan1970) +
+          double(ntpLow) / webrtc::kMagicNtpFractionalUnit) * 1000;
+}
+
+bool WebrtcAudioConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
+                                               unsigned int* jitterMs,
+                                               unsigned int* packetsReceived,
+                                               uint64_t* bytesReceived) {
+  unsigned int ntpHigh, ntpLow;
+  unsigned int rtpTimestamp, playoutTimestamp;
+  unsigned int packetsSent;
+  unsigned int bytesSent32;
+  unsigned short fractionLost;
+  unsigned int cumulativeLost;
+  bool result = !mPtrRTP->GetRemoteRTCPData(mChannel, ntpHigh, ntpLow,
+                                            rtpTimestamp, playoutTimestamp,
+                                            packetsSent, bytesSent32,
+                                            jitterMs,
+                                            &fractionLost, &cumulativeLost);
+  if (result) {
+    *timestamp = NTPtoDOMHighResTimeStamp(ntpHigh, ntpLow);
+    *packetsReceived = (packetsSent >= cumulativeLost) ?
+                       (packetsSent - cumulativeLost) : 0;
+    *bytesReceived = (packetsSent ?
+                      (bytesSent32 / packetsSent) : 0) * (*packetsReceived);
+  }
+  return result;
+}
+
+bool WebrtcAudioConduit::GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,
+                                             unsigned int* packetsSent,
+                                             uint64_t* bytesSent) {
+  unsigned int ntpHigh, ntpLow;
+  unsigned int rtpTimestamp, playoutTimestamp;
+  unsigned int bytesSent32;
+  unsigned int jitterMs;
+  unsigned short fractionLost;
+  bool result = !mPtrRTP->GetRemoteRTCPData(mChannel, ntpHigh, ntpLow,
+                                            rtpTimestamp, playoutTimestamp,
+                                            *packetsSent, bytesSent32,
+                                            &jitterMs, &fractionLost);
+  if (result) {
+    *timestamp = NTPtoDOMHighResTimeStamp(ntpHigh, ntpLow);
+    *bytesSent = bytesSent32;
+  }
+  return result;
+}
+
 /*
  * WebRTCAudioConduit Implementation
  */
 MediaConduitErrorCode WebrtcAudioConduit::Init(WebrtcAudioConduit *other)
 {
   CSFLogDebug(logTag,  "%s this=%p other=%p", __FUNCTION__, this, other);
 
   if (other) {
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.h
@@ -33,16 +33,21 @@
  using webrtc::VoEVideoSync;
 
 /** This file hosts several structures identifying different aspects
  * of a RTP Session.
  */
 
 namespace mozilla {
 
+// Helper function
+
+DOMHighResTimeStamp
+NTPtoDOMHighResTimeStamp(uint32_t ntpHigh, uint32_t ntpLow);
+
 /**
  * Concrete class for Audio session. Hooks up
  *  - media-source and target to external transport
  */
 class WebrtcAudioConduit:public AudioSessionConduit
 	      		            ,public webrtc::Transport
 {
 public:
@@ -167,17 +172,24 @@ public:
   virtual ~WebrtcAudioConduit();
 
   MediaConduitErrorCode Init(WebrtcAudioConduit *other);
 
   int GetChannel() { return mChannel; }
   webrtc::VoiceEngine* GetVoiceEngine() { return mVoiceEngine; }
   bool GetLocalSSRC(unsigned int* ssrc);
   bool GetRemoteSSRC(unsigned int* ssrc);
-  bool GetReceivedJitter(unsigned int* jitterMs);
+  bool GetRTPJitter(unsigned int* jitterMs);
+  bool GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
+                             unsigned int* jitterMs,
+                             unsigned int* packetsReceived,
+                             uint64_t* bytesReceived);
+  bool GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,
+                           unsigned int* packetsSent,
+                           uint64_t* bytesSent);
 
 private:
   WebrtcAudioConduit(const WebrtcAudioConduit& other) MOZ_DELETE;
   void operator=(const WebrtcAudioConduit& other) MOZ_DELETE;
 
   //Local database of currently applied receive codecs
   typedef std::vector<AudioCodecConfig* > RecvCodecList;
 
--- a/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
+++ b/media/webrtc/signaling/src/media-conduit/MediaConduitInterface.h
@@ -2,16 +2,17 @@
  * 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 MEDIA_CONDUIT_ABSTRACTION_
 #define MEDIA_CONDUIT_ABSTRACTION_
 
 #include "nsISupportsImpl.h"
 #include "nsXPCOM.h"
+#include "nsDOMNavigationTiming.h"
 #include "mozilla/RefPtr.h"
 #include "CodecConfig.h"
 #include "VideoTypes.h"
 #include "MediaConduitErrors.h"
 
 #include <vector>
 
 namespace mozilla {
@@ -133,17 +134,28 @@ public:
    * @param aTransport: Reference to the concrete teansport implementation
    * Note: Multiple invocations of this call , replaces existing transport with
    * with the new one.
    */
   virtual MediaConduitErrorCode AttachTransport(RefPtr<TransportInterface> aTransport) = 0;
 
   virtual bool GetLocalSSRC(unsigned int* ssrc) = 0;
   virtual bool GetRemoteSSRC(unsigned int* ssrc) = 0;
-  virtual bool GetReceivedJitter(unsigned int* jitterMs) = 0;
+
+  /**
+   * Functions returning stats needed by w3c stats model.
+   */
+  virtual bool GetRTPJitter(unsigned int* jitterMs) = 0;
+  virtual bool GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
+                                     unsigned int* jitterMs,
+                                     unsigned int* packetsReceived,
+                                     uint64_t* bytesReceived) = 0;
+  virtual bool GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,
+                                   unsigned int* packetsSent,
+                                   uint64_t* bytesSent) = 0;
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSessionConduit)
 
 };
 
 
 /**
  * MediaSessionConduit for video
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -140,29 +140,84 @@ WebrtcVideoConduit::~WebrtcVideoConduit(
 bool WebrtcVideoConduit::GetLocalSSRC(unsigned int* ssrc) {
   return !mPtrRTP->GetLocalSSRC(mChannel, *ssrc);
 }
 
 bool WebrtcVideoConduit::GetRemoteSSRC(unsigned int* ssrc) {
   return !mPtrRTP->GetRemoteSSRC(mChannel, *ssrc);
 }
 
-bool WebrtcVideoConduit::GetReceivedJitter(unsigned int* jitterMs) {
+bool WebrtcVideoConduit::GetRTPJitter(unsigned int* jitterMs) {
+  unsigned int ntpHigh, ntpLow;
+  unsigned int packetsSent, bytesSent;
   unsigned short fractionLost;
   unsigned int cumulativeLost;
   unsigned extendedMax;
   int rttMs;
-  return !mPtrRTP->GetReceivedRTCPStatistics(mChannel,
+  // GetReceivedRTCPStatistics is a poorly named GetRTPStatistics variant
+  return !mPtrRTP->GetReceivedRTCPStatistics(mChannel, ntpHigh, ntpLow,
+                                             packetsSent, bytesSent,
                                              fractionLost,
                                              cumulativeLost,
                                              extendedMax,
                                              *jitterMs,
                                              rttMs);
 }
 
+bool WebrtcVideoConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
+                                               unsigned int* jitterMs,
+                                               unsigned int* packetsReceived,
+                                               uint64_t* bytesReceived) {
+  unsigned int ntpHigh, ntpLow;
+  unsigned int packetsSent;
+  unsigned int bytesSent32;
+  unsigned short fractionLost;
+  unsigned int cumulativeLost;
+  unsigned extendedMax;
+  int rttMs;
+  bool result = !mPtrRTP->GetSentRTCPStatistics(mChannel, ntpHigh, ntpLow,
+                                                bytesSent32, packetsSent,
+                                                fractionLost,
+                                                cumulativeLost,
+                                                extendedMax,
+                                                *jitterMs,
+                                                rttMs);
+  if (result) {
+    *timestamp = NTPtoDOMHighResTimeStamp(ntpHigh, ntpLow);
+    *packetsReceived = (packetsSent >= cumulativeLost) ?
+                       (packetsSent - cumulativeLost) : 0;
+    *bytesReceived = (packetsSent ?
+                      (bytesSent32 / packetsSent) : 0) * (*packetsReceived);
+  }
+  return result;
+}
+
+bool WebrtcVideoConduit::GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,
+                                             unsigned int* packetsSent,
+                                             uint64_t* bytesSent) {
+  unsigned int ntpHigh, ntpLow;
+  unsigned int bytesSent32;
+  unsigned int jitterMs;
+  unsigned short fractionLost;
+  unsigned int cumulativeLost;
+  unsigned extendedMax;
+  int rttMs;
+  bool result = !mPtrRTP->GetReceivedRTCPStatistics(mChannel, ntpHigh, ntpLow,
+                                                    bytesSent32, *packetsSent,
+                                                    fractionLost,
+                                                    cumulativeLost,
+                                                    jitterMs, extendedMax,
+                                                    rttMs);
+  if (result) {
+    *timestamp = NTPtoDOMHighResTimeStamp(ntpHigh, ntpLow);
+    *bytesSent = bytesSent32;
+  }
+  return result;
+}
+
 /**
  * Peforms intialization of the MANDATORY components of the Video Engine
  */
 MediaConduitErrorCode WebrtcVideoConduit::Init(WebrtcVideoConduit *other)
 {
   CSFLogDebug(logTag,  "%s this=%p other=%p", __FUNCTION__, this, other);
 
   if (other) {
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -205,17 +205,24 @@ public:
   virtual ~WebrtcVideoConduit() ;
 
   MediaConduitErrorCode Init(WebrtcVideoConduit *other);
 
   int GetChannel() { return mChannel; }
   webrtc::VideoEngine* GetVideoEngine() { return mVideoEngine; }
   bool GetLocalSSRC(unsigned int* ssrc);
   bool GetRemoteSSRC(unsigned int* ssrc);
-  bool GetReceivedJitter(unsigned int* jitterMs);
+  bool GetRTPJitter(unsigned int* jitterMs);
+  bool GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
+                             unsigned int* jitterMs,
+                             unsigned int* packetsReceived,
+                             uint64_t* bytesReceived);
+  bool GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,
+                           unsigned int* packetsSent,
+                           uint64_t* bytesSent);
 
 private:
 
   WebrtcVideoConduit(const WebrtcVideoConduit& other) MOZ_DELETE;
   void operator=(const WebrtcVideoConduit& other) MOZ_DELETE;
 
   //Local database of currently applied receive codecs
   typedef std::vector<VideoCodecConfig* > RecvCodecList;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -1320,17 +1320,17 @@ PeerConnectionImpl::GetStats(MediaStream
     // TODO(bcampen@mozilla.com): I may need to revisit this for bundle.
     // (Bug 786234)
     RefPtr<NrIceMediaStream> temp(mMedia->ice_media_stream(level-1));
     if (temp.get()) {
       streams.push_back(temp);
     } else {
        CSFLogError(logTag, "Failed to get NrIceMediaStream for level %u "
                            "in %s:  %s",
-                           level, __FUNCTION__, mHandle.c_str());
+                           uint32_t(level), __FUNCTION__, mHandle.c_str());
        MOZ_CRASH();
     }
   }
 
   DOMHighResTimeStamp now;
   nsresult rv = GetTimeSinceEpoch(&now);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1973,46 +1973,113 @@ PeerConnectionImpl::GetStatsImpl_s(
   for (auto it = pipelines.begin(); it != pipelines.end(); ++it) {
     const MediaPipeline& mp = **it;
     nsString idstr = (mp.Conduit()->type() == MediaSessionConduit::AUDIO) ?
         NS_LITERAL_STRING("audio_") : NS_LITERAL_STRING("video_");
     idstr.AppendInt(mp.trackid());
 
     switch (mp.direction()) {
       case MediaPipeline::TRANSMIT: {
-        RTCOutboundRTPStreamStats s;
-        s.mTimestamp.Construct(now);
-        s.mId.Construct(NS_LITERAL_STRING("outbound_rtp_") + idstr);
-        s.mType.Construct(RTCStatsType::Outboundrtp);
-        unsigned int ssrc;
-        if (mp.Conduit()->GetLocalSSRC(&ssrc)) {
-          nsString str;
-          str.AppendInt(ssrc);
-          s.mSsrc.Construct(str);
+        nsString localId = NS_LITERAL_STRING("outbound_rtp_") + idstr;
+        nsString remoteId;
+        nsString ssrc;
+        unsigned int ssrcval;
+        if (mp.Conduit()->GetLocalSSRC(&ssrcval)) {
+          ssrc.AppendInt(ssrcval);
         }
-        s.mPacketsSent.Construct(mp.rtp_packets_sent());
-        s.mBytesSent.Construct(mp.rtp_bytes_sent());
-        report->mOutboundRTPStreamStats.Value().AppendElement(s);
+        {
+          // First, fill in remote stat with rtcp receiver data, if present.
+          // ReceiverReports have less information than SenderReports,
+          // so fill in what we can.
+          DOMHighResTimeStamp timestamp;
+          uint32_t jitterMs;
+          uint32_t packetsReceived;
+          uint64_t bytesReceived;
+          if (mp.Conduit()->GetRTCPReceiverReport(&timestamp, &jitterMs,
+                                                  &packetsReceived,
+                                                  &bytesReceived)) {
+            remoteId = NS_LITERAL_STRING("outbound_rtcp_") + idstr;
+            RTCInboundRTPStreamStats s;
+            s.mTimestamp.Construct(timestamp);
+            s.mId.Construct(remoteId);
+            s.mType.Construct(RTCStatsType::Inboundrtp);
+            if (ssrc.Length()) {
+              s.mSsrc.Construct(ssrc);
+            }
+            s.mJitter.Construct(double(jitterMs)/1000);
+            s.mRemoteId.Construct(localId);
+            s.mIsRemote = true;
+            s.mPacketsReceived.Construct(packetsReceived);
+            s.mBytesReceived.Construct(bytesReceived);
+            report->mInboundRTPStreamStats.Value().AppendElement(s);
+          }
+        }
+        // Then, fill in local side (with cross-link to remote only if present)
+        {
+          RTCOutboundRTPStreamStats s;
+          s.mTimestamp.Construct(now);
+          s.mId.Construct(localId);
+          s.mType.Construct(RTCStatsType::Outboundrtp);
+          if (ssrc.Length()) {
+            s.mSsrc.Construct(ssrc);
+          }
+          s.mRemoteId.Construct(remoteId);
+          s.mIsRemote = false;
+          s.mPacketsSent.Construct(mp.rtp_packets_sent());
+          s.mBytesSent.Construct(mp.rtp_bytes_sent());
+          report->mOutboundRTPStreamStats.Value().AppendElement(s);
+        }
         break;
       }
       case MediaPipeline::RECEIVE: {
+        nsString localId = NS_LITERAL_STRING("inbound_rtp_") + idstr;
+        nsString remoteId;
+        nsString ssrc;
+        unsigned int ssrcval;
+        if (mp.Conduit()->GetRemoteSSRC(&ssrcval)) {
+          ssrc.AppendInt(ssrcval);
+        }
+        {
+          // First, fill in remote stat with rtcp sender data, if present.
+          DOMHighResTimeStamp timestamp;
+          uint32_t packetsSent;
+          uint64_t bytesSent;
+          if (mp.Conduit()->GetRTCPSenderReport(&timestamp,
+                                                &packetsSent, &bytesSent)) {
+            remoteId = NS_LITERAL_STRING("inbound_rtcp_") + idstr;
+            RTCOutboundRTPStreamStats s;
+            s.mTimestamp.Construct(timestamp);
+            s.mId.Construct(remoteId);
+            s.mType.Construct(RTCStatsType::Outboundrtp);
+            if (ssrc.Length()) {
+              s.mSsrc.Construct(ssrc);
+            }
+            s.mRemoteId.Construct(localId);
+            s.mIsRemote = true;
+            s.mPacketsSent.Construct(packetsSent);
+            s.mBytesSent.Construct(bytesSent);
+            report->mOutboundRTPStreamStats.Value().AppendElement(s);
+          }
+        }
+        // Then, fill in local side (with cross-link to remote only if present)
         RTCInboundRTPStreamStats s;
         s.mTimestamp.Construct(now);
-        s.mId.Construct(NS_LITERAL_STRING("inbound_rtp_") + idstr);
+        s.mId.Construct(localId);
         s.mType.Construct(RTCStatsType::Inboundrtp);
-        unsigned int ssrc;
-        if (mp.Conduit()->GetRemoteSSRC(&ssrc)) {
-          nsString str;
-          str.AppendInt(ssrc);
-          s.mSsrc.Construct(str);
+        if (ssrc.Length()) {
+          s.mSsrc.Construct(ssrc);
         }
         unsigned int jitterMs;
-        if (mp.Conduit()->GetReceivedJitter(&jitterMs)) {
+        if (mp.Conduit()->GetRTPJitter(&jitterMs)) {
           s.mJitter.Construct(double(jitterMs)/1000);
         }
+        if (remoteId.Length()) {
+          s.mRemoteId.Construct(remoteId);
+        }
+        s.mIsRemote = false;
         s.mPacketsReceived.Construct(mp.rtp_packets_received());
         s.mBytesReceived.Construct(mp.rtp_bytes_received());
         report->mInboundRTPStreamStats.Value().AppendElement(s);
         break;
       }
     }
   }
 
--- a/media/webrtc/trunk/webrtc/video_engine/include/vie_rtp_rtcp.h
+++ b/media/webrtc/trunk/webrtc/video_engine/include/vie_rtp_rtcp.h
@@ -259,25 +259,33 @@ class WEBRTC_DLLEXPORT ViERTP_RTCP {
   // back-to-back.
   virtual int SetTransmissionSmoothingStatus(int video_channel,
                                              bool enable) = 0;
 
   // This function returns our locally created statistics of the received RTP
   // stream.
   virtual int GetReceivedRTCPStatistics(
       const int video_channel,
+      unsigned int& ntpHigh,
+      unsigned int& ntpLow,
+      unsigned int& bytes_sent,
+      unsigned int& packets_sent,
       unsigned short& fraction_lost,
       unsigned int& cumulative_lost,
       unsigned int& extended_max,
       unsigned int& jitter,
       int& rtt_ms) const = 0;
 
   // This function returns statistics reported by the remote client in a RTCP
   // packet.
   virtual int GetSentRTCPStatistics(const int video_channel,
+                                    unsigned int& ntpHigh,
+                                    unsigned int& ntpLow,
+                                    unsigned int& bytes_sent,
+                                    unsigned int& packets_sent,
                                     unsigned short& fraction_lost,
                                     unsigned int& cumulative_lost,
                                     unsigned int& extended_max,
                                     unsigned int& jitter,
                                     int& rtt_ms) const = 0;
 
   // The function gets statistics from the sent and received RTP streams.
   virtual int GetRTPStatistics(const int video_channel,
--- a/media/webrtc/trunk/webrtc/video_engine/vie_channel.cc
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_channel.cc
@@ -1172,17 +1172,21 @@ int32_t ViEChannel::SendApplicationDefin
                                                data_length_in_bytes) != 0) {
     WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
                  "%s: Could not send RTCP application data", __FUNCTION__);
     return -1;
   }
   return 0;
 }
 
-int32_t ViEChannel::GetSendRtcpStatistics(uint16_t* fraction_lost,
+int32_t ViEChannel::GetSendRtcpStatistics(uint32_t* ntp_high,
+                                          uint32_t* ntp_low,
+                                          uint32_t* bytes_sent,
+                                          uint32_t* packets_sent,
+                                          uint16_t* fraction_lost,
                                           uint32_t* cumulative_lost,
                                           uint32_t* extended_max,
                                           uint32_t* jitter_samples,
                                           int32_t* rtt_ms) {
   WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_), "%s",
                __FUNCTION__);
 
   // TODO(pwestin) how do we do this for simulcast ? average for all
@@ -1191,16 +1195,30 @@ int32_t ViEChannel::GetSendRtcpStatistic
 
   // for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
   //      it != simulcast_rtp_rtcp_.end();
   //      it++) {
   //   RtpRtcp* rtp_rtcp = *it;
   // }
   uint32_t remote_ssrc = vie_receiver_.GetRemoteSsrc();
 
+  // --- Information from sender info in received RTCP Sender Reports
+
+  RTCPSenderInfo sender_info;
+  if (rtp_rtcp_->RemoteRTCPStat(&sender_info) != 0) {
+    WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
+                 "%s: Could not get sender info for remote side", __FUNCTION__);
+    return -1;
+  }
+
+  *ntp_high = sender_info.NTPseconds;
+  *ntp_low = sender_info.NTPfraction;
+  *bytes_sent = sender_info.sendOctetCount;
+  *packets_sent = sender_info.sendPacketCount;
+
   // Get all RTCP receiver report blocks that have been received on this
   // channel. If we receive RTP packets from a remote source we know the
   // remote SSRC and use the report block from him.
   // Otherwise use the first report block.
   std::vector<RTCPReportBlock> remote_stats;
   if (rtp_rtcp_->RemoteRTCPStat(&remote_stats) != 0 || remote_stats.empty()) {
     WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
                  "%s: Could not get remote stats", __FUNCTION__);
@@ -1235,24 +1253,44 @@ int32_t ViEChannel::GetSendRtcpStatistic
   }
   *rtt_ms = rtt;
   return 0;
 }
 
 // TODO(holmer): This is a bad function name as it implies that it returns the
 // received RTCP, while it actually returns the statistics which will be sent
 // in the RTCP.
-int32_t ViEChannel::GetReceivedRtcpStatistics(uint16_t* fraction_lost,
+int32_t ViEChannel::GetReceivedRtcpStatistics(uint32_t* ntp_high,
+                                              uint32_t* ntp_low,
+                                              uint32_t* bytes_sent,
+                                              uint32_t* packets_sent,
+                                              uint16_t* fraction_lost,
                                               uint32_t* cumulative_lost,
                                               uint32_t* extended_max,
                                               uint32_t* jitter_samples,
                                               int32_t* rtt_ms) {
   WEBRTC_TRACE(kTraceInfo, kTraceVideo, ViEId(engine_id_, channel_id_),
                "%s", __FUNCTION__);
 
+  // --- Information from sender info in received RTCP Sender Reports
+
+  RTCPSenderInfo sender_info;
+  if (rtp_rtcp_->RemoteRTCPStat(&sender_info) != 0) {
+    WEBRTC_TRACE(kTraceWarning, kTraceVideo, ViEId(engine_id_, channel_id_),
+                 "%s: Could not get sender info for remote side", __FUNCTION__);
+    return -1;
+  }
+
+  *ntp_high = sender_info.NTPseconds;
+  *ntp_low = sender_info.NTPfraction;
+  *bytes_sent = sender_info.sendOctetCount;
+  *packets_sent = sender_info.sendPacketCount;
+
+  // --- Locally derived information
+
   uint32_t remote_ssrc = vie_receiver_.GetRemoteSsrc();
   uint8_t frac_lost = 0;
   StreamStatistician* statistician =
       vie_receiver_.GetReceiveStatistics()->GetStatistician(remote_ssrc);
   StreamStatistician::Statistics receive_stats;
   if (!statistician || !statistician->GetStatistics(
       &receive_stats, rtp_rtcp_->RTCP() == kRtcpOff)) {
     WEBRTC_TRACE(kTraceError, kTraceVideo, ViEId(engine_id_, channel_id_),
--- a/media/webrtc/trunk/webrtc/video_engine/vie_channel.h
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_channel.h
@@ -159,24 +159,32 @@ class ViEChannel
   int32_t RegisterRtcpObserver(ViERTCPObserver* observer);
   int32_t SendApplicationDefinedRTCPPacket(
       const uint8_t sub_type,
       uint32_t name,
       const uint8_t* data,
       uint16_t data_length_in_bytes);
 
   // Returns statistics reported by the remote client in an RTCP packet.
-  int32_t GetSendRtcpStatistics(uint16_t* fraction_lost,
+  int32_t GetSendRtcpStatistics(uint32_t* ntp_high,
+                                uint32_t* ntp_low,
+                                uint32_t* bytes_sent,
+                                uint32_t* packets_sent,
+                                uint16_t* fraction_lost,
                                 uint32_t* cumulative_lost,
                                 uint32_t* extended_max,
                                 uint32_t* jitter_samples,
                                 int32_t* rtt_ms);
 
-  // Returns our localy created statistics of the received RTP stream.
-  int32_t GetReceivedRtcpStatistics(uint16_t* fraction_lost,
+  // Returns RTCP sender report + locally created stats of received RTP stream
+  int32_t GetReceivedRtcpStatistics(uint32_t* ntp_high,
+                                    uint32_t* ntp_low,
+                                    uint32_t* bytes_sent,
+                                    uint32_t* packets_sent,
+                                    uint16_t* fraction_lost,
                                     uint32_t* cumulative_lost,
                                     uint32_t* extended_max,
                                     uint32_t* jitter_samples,
                                     int32_t* rtt_ms);
 
   // Gets sent/received packets statistics.
   int32_t GetRtpStatistics(uint32_t* bytes_sent,
                            uint32_t* packets_sent,
--- a/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.cc
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.cc
@@ -819,16 +819,20 @@ int ViERTP_RTCPImpl::SetTransmissionSmoo
     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
     return -1;
   }
   vie_channel->SetTransmissionSmoothingStatus(enable);
   return 0;
 }
 
 int ViERTP_RTCPImpl::GetReceivedRTCPStatistics(const int video_channel,
+                                               unsigned int& ntp_high,
+                                               unsigned int& ntp_low,
+                                               unsigned int& bytes_sent,
+                                               unsigned int& packets_sent,
                                                uint16_t& fraction_lost,
                                                unsigned int& cumulative_lost,
                                                unsigned int& extended_max,
                                                unsigned int& jitter,
                                                int& rtt_ms) const {
   WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
                ViEId(shared_data_->instance_id(), video_channel),
                "%s(channel: %d)", __FUNCTION__, video_channel);
@@ -836,28 +840,36 @@ int ViERTP_RTCPImpl::GetReceivedRTCPStat
   ViEChannel* vie_channel = cs.Channel(video_channel);
   if (!vie_channel) {
     WEBRTC_TRACE(kTraceError, kTraceVideo,
                  ViEId(shared_data_->instance_id(), video_channel),
                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
     return -1;
   }
-  if (vie_channel->GetReceivedRtcpStatistics(&fraction_lost,
+  if (vie_channel->GetReceivedRtcpStatistics(&ntp_high,
+                                             &ntp_low,
+                                             &bytes_sent,
+                                             &packets_sent,
+                                             &fraction_lost,
                                              &cumulative_lost,
                                              &extended_max,
                                              &jitter,
                                              &rtt_ms) != 0) {
     shared_data_->SetLastError(kViERtpRtcpUnknownError);
     return -1;
   }
   return 0;
 }
 
 int ViERTP_RTCPImpl::GetSentRTCPStatistics(const int video_channel,
+                                           unsigned int& ntp_high,
+                                           unsigned int& ntp_low,
+                                           unsigned int& bytes_sent,
+                                           unsigned int& packets_sent,
                                            uint16_t& fraction_lost,
                                            unsigned int& cumulative_lost,
                                            unsigned int& extended_max,
                                            unsigned int& jitter,
                                            int& rtt_ms) const {
   WEBRTC_TRACE(kTraceApiCall, kTraceVideo,
                ViEId(shared_data_->instance_id(), video_channel),
                "%s(channel: %d)", __FUNCTION__, video_channel);
@@ -866,17 +878,19 @@ int ViERTP_RTCPImpl::GetSentRTCPStatisti
   if (!vie_channel) {
     WEBRTC_TRACE(kTraceError, kTraceVideo,
                  ViEId(shared_data_->instance_id(), video_channel),
                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel);
     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
     return -1;
   }
 
-  if (vie_channel->GetSendRtcpStatistics(&fraction_lost, &cumulative_lost,
+  if (vie_channel->GetSendRtcpStatistics(&ntp_high, &ntp_low,
+                                         &bytes_sent, &packets_sent,
+                                         &fraction_lost, &cumulative_lost,
                                          &extended_max, &jitter,
                                          &rtt_ms) != 0) {
     shared_data_->SetLastError(kViERtpRtcpUnknownError);
     return -1;
   }
   return 0;
 }
 
--- a/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.h
+++ b/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.h
@@ -85,22 +85,30 @@ class ViERTP_RTCPImpl
   virtual int SetSendAbsoluteSendTimeStatus(int video_channel,
                                             bool enable,
                                             int id);
   virtual int SetReceiveAbsoluteSendTimeStatus(int video_channel,
                                                bool enable,
                                                int id);
   virtual int SetTransmissionSmoothingStatus(int video_channel, bool enable);
   virtual int GetReceivedRTCPStatistics(const int video_channel,
+                                        unsigned int& ntpHigh,
+                                        unsigned int& ntpLow,
+                                        unsigned int& bytes_sent,
+                                        unsigned int& packets_sent,
                                         uint16_t& fraction_lost,
                                         unsigned int& cumulative_lost,
                                         unsigned int& extended_max,
                                         unsigned int& jitter,
                                         int& rtt_ms) const;
   virtual int GetSentRTCPStatistics(const int video_channel,
+                                    unsigned int& ntpHigh,
+                                    unsigned int& ntpLow,
+                                    unsigned int& bytes_sent,
+                                    unsigned int& packets_sent,
                                     uint16_t& fraction_lost,
                                     unsigned int& cumulative_lost,
                                     unsigned int& extended_max,
                                     unsigned int& jitter, int& rtt_ms) const;
   virtual int GetRTPStatistics(const int video_channel,
                                unsigned int& bytes_sent,
                                unsigned int& packets_sent,
                                unsigned int& bytes_received,
--- a/media/webrtc/trunk/webrtc/voice_engine/channel.cc
+++ b/media/webrtc/trunk/webrtc/voice_engine/channel.cc
@@ -3794,36 +3794,39 @@ Channel::GetRemoteRTCP_CNAME(char cName[
 }
 
 int
 Channel::GetRemoteRTCPData(
     unsigned int& NTPHigh,
     unsigned int& NTPLow,
     unsigned int& timestamp,
     unsigned int& playoutTimestamp,
+    unsigned int& sendPacketCount,
+    unsigned int& sendOctetCount,
     unsigned int* jitter,
-    unsigned short* fractionLost)
+    unsigned short* fractionLost,
+    unsigned int* cumulativeLost)
 {
     // --- Information from sender info in received Sender Reports
 
     RTCPSenderInfo senderInfo;
     if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
     {
         _engineStatisticsPtr->SetLastError(
             VE_RTP_RTCP_MODULE_ERROR, kTraceError,
             "GetRemoteRTCPData() failed to retrieve sender info for remote "
             "side");
         return -1;
     }
 
-    // We only utilize 12 out of 20 bytes in the sender info (ignores packet
-    // and octet count)
     NTPHigh = senderInfo.NTPseconds;
     NTPLow = senderInfo.NTPfraction;
     timestamp = senderInfo.RTPtimeStamp;
+    sendPacketCount = senderInfo.sendPacketCount;
+    sendOctetCount = senderInfo.sendOctetCount;
 
     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
                  VoEId(_instanceId, _channelId),
                  "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
                  "timestamp=%lu",
                  NTPHigh, NTPLow, timestamp);
 
     // --- Locally derived information
@@ -3832,17 +3835,17 @@ Channel::GetRemoteRTCPData(
     // has been received)
     playoutTimestamp = playout_timestamp_rtcp_;
 
     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
                  VoEId(_instanceId, _channelId),
                  "GetRemoteRTCPData() => playoutTimestamp=%lu",
                  playout_timestamp_rtcp_);
 
-    if (NULL != jitter || NULL != fractionLost)
+    if (NULL != jitter || NULL != fractionLost || NULL != cumulativeLost)
     {
         // Get all RTCP receiver report blocks that have been received on this
         // channel. If we receive RTP packets from a remote source we know the
         // remote SSRC and use the report block from him.
         // Otherwise use the first report block.
         std::vector<RTCPReportBlock> remote_stats;
         if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
             remote_stats.empty()) {
@@ -3877,16 +3880,24 @@ Channel::GetRemoteRTCPData(
 
         if (fractionLost) {
           *fractionLost = it->fractionLost;
           WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
                        VoEId(_instanceId, _channelId),
                        "GetRemoteRTCPData() => fractionLost = %lu",
                        *fractionLost);
         }
+
+        if (cumulativeLost) {
+          *cumulativeLost = it->cumulativeLost;
+          WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
+                       VoEId(_instanceId, _channelId),
+                       "GetRemoteRTCPData() => cumulativeLost = %lu",
+                       *cumulativeLost);
+        }
     }
     return 0;
 }
 
 int
 Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
                                              unsigned int name,
                                              const char* data,
--- a/media/webrtc/trunk/webrtc/voice_engine/channel.h
+++ b/media/webrtc/trunk/webrtc/voice_engine/channel.h
@@ -259,18 +259,22 @@ public:
     int GetRTPAudioLevelIndicationStatus(bool& enable, unsigned char& ID);
     int SetRTCPStatus(bool enable);
     int GetRTCPStatus(bool& enabled);
     int SetRTCP_CNAME(const char cName[256]);
     int GetRTCP_CNAME(char cName[256]);
     int GetRemoteRTCP_CNAME(char cName[256]);
     int GetRemoteRTCPData(unsigned int& NTPHigh, unsigned int& NTPLow,
                           unsigned int& timestamp,
-                          unsigned int& playoutTimestamp, unsigned int* jitter,
-                          unsigned short* fractionLost);
+                          unsigned int& playoutTimestamp,
+                          unsigned int& sendPacketCount,
+                          unsigned int& sendOctetCount,
+                          unsigned int* jitter,
+                          unsigned short* fractionLost,
+                          unsigned int* cumulativeLost);
     int SendApplicationDefinedRTCPPacket(unsigned char subType,
                                          unsigned int name, const char* data,
                                          unsigned short dataLengthInBytes);
     int GetRTPStatistics(unsigned int& averageJitterMs,
                          unsigned int& maxJitterMs,
                          unsigned int& discardedPackets);
     int GetRemoteRTCPSenderInfo(SenderInfo* sender_info);
     int GetRemoteRTCPReportBlocks(std::vector<ReportBlock>* report_blocks);
--- a/media/webrtc/trunk/webrtc/voice_engine/include/voe_rtp_rtcp.h
+++ b/media/webrtc/trunk/webrtc/voice_engine/include/voe_rtp_rtcp.h
@@ -180,17 +180,19 @@ public:
     // Gets the canonical name (CNAME) parameter for incoming RTCP reports
     // on a specific channel.
     virtual int GetRemoteRTCP_CNAME(int channel, char cName[256]) = 0;
 
     // Gets RTCP data from incoming RTCP Sender Reports.
     virtual int GetRemoteRTCPData(
         int channel, unsigned int& NTPHigh, unsigned int& NTPLow,
         unsigned int& timestamp, unsigned int& playoutTimestamp,
-        unsigned int* jitter = NULL, unsigned short* fractionLost = NULL) = 0;
+        unsigned int& sendPacketCount, unsigned int& sendOctetCount,
+        unsigned int* jitter = NULL, unsigned short* fractionLost = NULL,
+        unsigned int* cumulativeLost = NULL) = 0;
 
     // Gets RTP statistics for a specific |channel|.
     virtual int GetRTPStatistics(
         int channel, unsigned int& averageJitterMs, unsigned int& maxJitterMs,
         unsigned int& discardedPackets) = 0;
 
     // Gets RTCP statistics for a specific |channel|.
     virtual int GetRTCPStatistics(int channel, CallStatistics& stats) = 0;
--- a/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.cc
+++ b/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.cc
@@ -370,18 +370,21 @@ int VoERTP_RTCPImpl::GetRemoteRTCP_CNAME
 }
 
 int VoERTP_RTCPImpl::GetRemoteRTCPData(
     int channel,
     unsigned int& NTPHigh, // from sender info in SR
     unsigned int& NTPLow, // from sender info in SR
     unsigned int& timestamp, // from sender info in SR
     unsigned int& playoutTimestamp, // derived locally
+    unsigned int& sendPacketCount, // from sender info in SR
+    unsigned int& sendOctetCount, // from sender info in SR
     unsigned int* jitter, // from report block 1 in SR/RR
-    unsigned short* fractionLost) // from report block 1 in SR/RR
+    unsigned short* fractionLost, // from report block 1 in SR/RR
+    unsigned int* cumulativeLost) // from report block 1 in SR/RR
 {
     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
                  "GetRemoteRTCPData(channel=%d,...)", channel);
     if (!_shared->statistics().Initialized())
     {
         _shared->SetLastError(VE_NOT_INITED, kTraceError);
         return -1;
     }
@@ -392,18 +395,21 @@ int VoERTP_RTCPImpl::GetRemoteRTCPData(
         _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
             "GetRemoteRTCP_CNAME() failed to locate channel");
         return -1;
     }
     return channelPtr->GetRemoteRTCPData(NTPHigh,
                                          NTPLow,
                                          timestamp,
                                          playoutTimestamp,
+                                         sendPacketCount,
+                                         sendOctetCount,
                                          jitter,
-                                         fractionLost);
+                                         fractionLost,
+                                         cumulativeLost);
 }
 
 int VoERTP_RTCPImpl::SendApplicationDefinedRTCPPacket(
     int channel,
     unsigned char subType,
     unsigned int name,
     const char* data,
     unsigned short dataLengthInBytes)
--- a/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.h
+++ b/media/webrtc/trunk/webrtc/voice_engine/voe_rtp_rtcp_impl.h
@@ -40,18 +40,21 @@ public:
 
     virtual int GetRemoteRTCP_CNAME(int channel, char cName[256]);
 
     virtual int GetRemoteRTCPData(int channel,
                                   unsigned int& NTPHigh,
                                   unsigned int& NTPLow,
                                   unsigned int& timestamp,
                                   unsigned int& playoutTimestamp,
+                                  unsigned int& sendPacketCount,
+                                  unsigned int& sendOctetCount,
                                   unsigned int* jitter = NULL,
-                                  unsigned short* fractionLost = NULL);
+                                  unsigned short* fractionLost = NULL,
+                                  unsigned int* cumulativeLost = NULL);
 
     virtual int SendApplicationDefinedRTCPPacket(
         int channel,
         unsigned char subType,
         unsigned int name,
         const char* data,
         unsigned short dataLengthInBytes);
 
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -1953,17 +1953,18 @@ public class GeckoAppShell
     private static final String PLUGIN_TYPE = "type";
     private static final String TYPE_NATIVE = "native";
     static public ArrayList<PackageInfo> mPackageInfoCache = new ArrayList<PackageInfo>();
 
     // Returns null if plugins are blocked on the device.
     static String[] getPluginDirectories() {
 
         // An awful hack to detect Tegra devices. Easiest way to do it without spinning up a EGL context.
-        boolean isTegra = (new File("/system/lib/hw/gralloc.tegra.so")).exists();
+        boolean isTegra = (new File("/system/lib/hw/gralloc.tegra.so")).exists() ||
+                          (new File("/system/lib/hw/gralloc.tegra3.so")).exists();
         if (isTegra) {
             // disable Flash on Tegra ICS with CM9 and other custom firmware (bug 736421)
             File vfile = new File("/proc/version");
             FileReader vreader = null;
             try {
                 if (vfile.canRead()) {
                     vreader = new FileReader(vfile);
                     String version = new BufferedReader(vreader).readLine();
@@ -1981,16 +1982,22 @@ public class GeckoAppShell
                 try {
                     if (vreader != null) {
                         vreader.close();
                     }
                 } catch (IOException ex) {
                     // nothing
                 }
             }
+
+            // disable on KitKat (bug 957694)
+            if (Build.VERSION.SDK_INT >= 19) {
+                Log.w(LOGTAG, "Blocking plugins because of Tegra (bug 957694)");
+                return null;
+            }
         }
 
         ArrayList<String> directories = new ArrayList<String>();
         PackageManager pm = getContext().getPackageManager();
         List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(PLUGIN_ACTION),
                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
 
         synchronized(mPackageInfoCache) {
--- a/netwerk/dns/effective_tld_names.dat
+++ b/netwerk/dns/effective_tld_names.dat
@@ -7247,19 +7247,16 @@ best
 country
 
 // KRED : 2013-12-19 KredTLD Pty Ltd
 kred
 
 // feedback : 2013-12-19 Top Level Spectrum, Inc.
 feedback
 
-// works : 2013-12-19 Top Level Domain Holdings Limited
-works
-
 // work : 2013-12-19 Top Level Domain Holdings Limited
 work
 
 // luxe : 2014-01-09 Top Level Domain Holdings Limited 
 luxe
 
 // ryukyu : 2014-01-09 BusinessRalliart inc. 
 ryukyu
--- a/nsprpub/TAG-INFO
+++ b/nsprpub/TAG-INFO
@@ -1,1 +1,1 @@
-NSPR_4_10_3_BETA2
+NSPR_4_10_3_BETA3
--- a/nsprpub/config/prdepend.h
+++ b/nsprpub/config/prdepend.h
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSPR in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/nsprpub/pr/src/pthreads/ptio.c
+++ b/nsprpub/pr/src/pthreads/ptio.c
@@ -3395,42 +3395,46 @@ failed:
 }  /* PR_AllocFileDesc */
 
 #if !defined(_PR_INET6) || defined(_PR_INET6_PROBE)
 PR_EXTERN(PRStatus) _pr_push_ipv6toipv4_layer(PRFileDesc *fd);
 #if defined(_PR_INET6_PROBE)
 extern PRBool _pr_ipv6_is_present(void);
 PR_IMPLEMENT(PRBool) _pr_test_ipv6_socket()
 {
-PRInt32 osfd;
-
 #if defined(DARWIN)
     /*
      * Disable IPv6 if Darwin version is less than 7.0.0 (OS X 10.3).  IPv6 on
      * lesser versions is not ready for general use (see bug 222031).
      */
     {
         struct utsname u;
         if (uname(&u) != 0 || atoi(u.release) < 7)
             return PR_FALSE;
     }
 #endif
 
+#if defined(LINUX)
+    /* If /proc/net/if_inet6 exists, the Linux kernel supports IPv6. */
+    int rv = access("/proc/net/if_inet6", F_OK);
+    return (rv == 0);
+#else
     /*
      * HP-UX only: HP-UX IPv6 Porting Guide (dated February 2001)
      * suggests that we call open("/dev/ip6", O_RDWR) to determine
      * whether IPv6 APIs and the IPv6 stack are on the system.
      * Our portable test below seems to work fine, so I am using it.
      */
-    osfd = socket(AF_INET6, SOCK_STREAM, 0);
+    PRInt32 osfd = socket(AF_INET6, SOCK_STREAM, 0);
     if (osfd != -1) {
         close(osfd);
         return PR_TRUE;
     }
     return PR_FALSE;
+#endif
 }
 #endif	/* _PR_INET6_PROBE */
 #endif
 
 PR_IMPLEMENT(PRFileDesc*) PR_Socket(PRInt32 domain, PRInt32 type, PRInt32 proto)
 {
     PRIntn osfd;
     PRDescType ftype;
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/expected.py
@@ -0,0 +1,265 @@
+# 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/.
+
+import errors
+import types
+
+"""This file provides a set of expected conditions for common use
+cases when writing Marionette tests.
+
+The conditions rely on explicit waits that retries conditions a number
+of times until they are either successfully met, or they time out.
+
+"""
+
+class element_present(object):
+    """Checks that a web element is present in the DOM of the current
+    context.  This does not necessarily mean that the element is
+    visible.
+
+    You can select which element to be checked for presence by
+    supplying a locator:
+
+        el = Wait(marionette).until(expected.element_present(By.ID, "foo"))
+
+    Or by using a function/lambda returning an element:
+
+        el = Wait(marionette).until(expected.element_present(lambda m: m.find_element(By.ID, "foo")))
+
+    :param args: locator or function returning web element
+    :returns: the web element once it is located, or False
+
+    """
+
+    def __init__(self, *args):
+        if len(args) == 1 and isinstance(args[0], types.FunctionType):
+            self.locator = args[0]
+        else:
+            self.locator = lambda m: m.find_element(*args)
+
+    def __call__(self, marionette):
+        return _find(marionette, self.locator)
+
+class element_not_present(element_present):
+    """Checks that a web element is not present in the DOM of the current
+    context.
+
+    You can select which element to be checked for lack of presence by
+    supplying a locator:
+
+        r = Wait(marionette).until(expected.element_not_present(By.ID, "foo"))
+
+    Or by using a function/lambda returning an element:
+
+        r = Wait(marionette).until(expected.element_present(lambda m: m.find_element(By.ID, "foo")))
+
+    :param args: locator or function returning web element
+    :returns: True if element is not present, or False if it is present
+
+    """
+
+    def __init__(self, *args):
+        super(element_not_present, self).__init__(*args)
+
+    def __call__(self, marionette):
+        return not super(element_not_present, self).__call__(marionette)
+
+class element_stale(object):
+    """Check that the given element is no longer attached to DOM of the
+    current context.
+
+    This can be useful for waiting until an element is no longer
+    present.
+
+    Sample usage:
+
+        el = marionette.find_element(By.ID, "foo")
+        # ...
+        Wait(marionette).until(expected.element_stale(el))
+
+    :param element: the element to wait for
+    :returns: False if the element is still attached to the DOM, True
+        otherwise
+
+    """
+
+    def __init__(self, element):
+        self.el = element
+
+    def __call__(self, marionette):
+        try:
+            # Calling any method forces a staleness check
+            self.el.is_enabled()
+            return False
+        except errors.StaleElementException:
+            return True
+
+class elements_present(object):
+    """Checks that web elements are present in the DOM of the current
+    context.  This does not necessarily mean that the elements are
+    visible.
+
+    You can select which elements to be checked for presence by
+    supplying a locator:
+
+        els = Wait(marionette).until(expected.elements_present(By.TAG_NAME, "a"))
+
+    Or by using a function/lambda returning a list of elements:
+
+        els = Wait(marionette).until(expected.elements_present(lambda m: m.find_elements(By.TAG_NAME, "a")))
+
+    :param args: locator or function returning a list of web elements
+    :returns: list of web elements once they are located, or False
+
+    """
+
+    def __init__(self, *args):
+        if len(args) == 1 and isinstance(args[0], types.FunctionType):
+            self.locator = args[0]
+        else:
+            self.locator = lambda m: m.find_elements(*args)
+
+    def __call__(self, marionette):
+        return _find(marionette, self.locator)
+
+class elements_not_present(elements_present):
+    """Checks that web elements are not present in the DOM of the
+    current context.
+
+    You can select which elements to be checked for not being present
+    by supplying a locator:
+
+        r = Wait(marionette).until(expected.elements_not_present(By.TAG_NAME, "a"))
+
+    Or by using a function/lambda returning a list of elements:
+
+        r = Wait(marionette).until(expected.elements_not_present(lambda m: m.find_elements(By.TAG_NAME, "a")))
+
+    :param args: locator or function returning a list of web elements
+    :returns: True if elements are missing, False if one or more are
+        present
+
+    """
+
+    def __init__(self, *args):
+        super(elements_not_present, self).__init__(*args)
+
+    def __call__(self, marionette):
+        return not super(elements_not_present, self).__call__(marionette)
+
+class element_displayed(object):
+    """An expectation for checking that an element is visible.
+
+    Visibility means that the element is not only displayed, but also
+    has a height and width that is greater than 0 pixels.
+
+    Stale elements, meaning elements that have been detached from the
+    DOM of the current context are treated as not being displayed,
+    meaning this expectation is not analogous to the behaviour of
+    calling `is_displayed()` on an `HTMLElement`.
+
+    :param element: the element to perform the visibility check on
+    :returns: True if element is displayed, False if hidden
+
+    """
+
+    def __init__(self, element):
+        self.el = element
+
+    def __call__(self, marionette):
+        try:
+            return self.el.is_displayed()
+        except errors.StaleElementException:
+            return False
+
+class element_not_displayed(element_displayed):
+    """An expectation for checking that an element is not visible.
+
+    Visibility means that the element is not only displayed, but also
+    has a height and width that is greater than 0 pixels.
+
+    Stale elements, meaning elements that have been detached fom the
+    DOM of the current context are treated as not being displayed,
+    meaning this expectation is not analogous to the behaviour of
+    calling `is_displayed()` on an `HTMLElement`.
+
+    :param element: the element to perform the visibility check on
+    :returns: True if element is hidden, False if visible
+
+    """
+
+    def __init__(self, element):
+        super(element_not_displayed, self).__init__(element)
+
+    def __call__(self, marionette):
+        return not super(element_not_displayed, self).__call__(marionette)
+
+class element_selected(object):
+    """An expectation for checking that the given element is selected.
+
+    :param element: the element to be selected
+    :returns: True if element is selected, False otherwise
+
+    """
+
+    def __init__(self, element):
+        self.el = element
+
+    def __call__(self, marionette):
+        return self.el.is_selected()
+
+class element_not_selected(element_selected):
+    """An expectation for checking that the given element is not
+    selected.
+
+    :param element: the element to not be selected
+    :returns True if element is not selected, False if selected
+
+    """
+
+    def __init__(self, element):
+        super(element_not_selected, self).__init__(element)
+
+    def __call__(self, marionette):
+        return not super(element_not_selected, self).__call__(marionette)
+
+class element_enabled(object):
+    """An expectation for checking that the given element is enabled.
+
+    :param element: the element to check if enabled
+    :returns: True if element is enabled, False otherwise
+
+    """
+
+    def __init__(self, element):
+        self.el = element
+
+    def __call__(self, marionette):
+        return self.el.is_enabled()
+
+class element_not_enabled(element_enabled):
+    """An expectation for checking that the given element is disabled.
+
+    :param element: the element to check if disabled
+    :returns: True if element is disabled, False if enabled
+
+    """
+
+    def __init__(self, element):
+        super(element_not_enabled, self).__init__(element)
+
+    def __call__(self, marionette):
+        return not super(element_not_enabled, self).__call__(marionette)
+
+def _find(marionette, func):
+    el = None
+
+    try:
+        el = func(marionette)
+    except errors.NoSuchElementException:
+        pass
+
+    if el is None:
+        return False
+    return el
--- a/testing/marionette/client/marionette/marionette.py
+++ b/testing/marionette/client/marionette/marionette.py
@@ -776,36 +776,45 @@ class Marionette(object):
         that uniquely identifies it within this Marionette instance.
         This can be used to switch to this window at a later point.
 
         :returns: unique window handle
         :rtype: string
 
         """
 
-        self.window = self._send_message("getCurrentWindowHandle", "value")
+        self.window = self._send_message("getWindowHandle", "value")
         return self.window
 
     @property
     def title(self):
         '''
         Current title of the active window.
         '''
         response = self._send_message('getTitle', 'value')
         return response
 
     @property
     def window_handles(self):
-        '''
-        A list of references to all available browser windows if called in
-        content context. If called while in the chrome context, it will list
-        all available windows, not just browser windows (ie: not just
-        'navigator:browser';).
-        '''
-        response = self._send_message('getWindows', 'value')
+        """Get list of windows in the current context.
+
+        If called in the content context it will return a list of
+        references to all available browser windows.  Called in the
+        chrome context, it will list all available windows, not just
+        browser windows (e.g. not just navigator.browser).
+
+        Each window handle is assigned by the server, and the list of
+        strings returned does not have a guaranteed ordering.
+
+        :returns: unordered list of unique window handles as strings
+
+        """
+
+        response = self._send_message("getCurrentWindowHandles",
+                                      "value")
         return response
 
     @property
     def page_source(self):
         '''
         A string representation of the DOM.
         '''
         response = self._send_message('getPageSource', 'value')
@@ -899,22 +908,44 @@ class Marionette(object):
 
         This command only makes sense in a chrome context. You might use this
         method to distinguish a browser window from an editor window.
         '''
         response = self._send_message('getWindowType', 'value')
         return response
 
     def navigate(self, url):
-        '''
-        Causes the browser to navigate to the specified url.
+        """Navigate to to given URL.
+
+        This will follow redirects issued by the server.  When the
+        method returns is based on the page load strategy that the
+        user has selected.
+
+        Documents that contain a META tag with the "http-equiv"
+        attribute set to "refresh" will return if the timeout is
+        greater than 1 second and the other criteria for determining
+        whether a page is loaded are met.  When the refresh period is
+        1 second or less and the page load strategy is "normal" or
+        "conservative", it will wait for the page to complete loading
+        before returning.
+
+        If any modal dialog box, such as those opened on
+        window.onbeforeunload or window.alert, is opened at any point
+        in the page load, it will return immediately.
+
+        If a 401 response is seen by the browser, it will return
+        immediately.  That is, if BASIC, DIGEST, NTLM or similar
+        authentication is required, the page load is assumed to be
+        complete.  This does not include FORM-based authentication.
 
         :param url: The url to navigate to.
-        '''
-        response = self._send_message('goUrl', 'ok', url=url)
+
+        """
+
+        response = self._send_message("get", "ok", url=url)
         return response
 
     def timeouts(self, timeout_type, ms):
         assert(timeout_type == self.TIMEOUT_SEARCH or timeout_type == self.TIMEOUT_SCRIPT or timeout_type == self.TIMEOUT_PAGE)
         response = self._send_message('timeouts', 'ok', type=timeout_type, ms=ms)
         return response
 
     def go_back(self):
@@ -1313,30 +1344,39 @@ class Marionette(object):
 
         return self._send_message("getCookies", "value")
 
     @property
     def application_cache(self):
         return ApplicationCache(self)
 
     def screenshot(self, element=None, highlights=None):
-        '''
-        Creates a base64-encoded screenshot of the element, or the current frame if no element is specified.
+        """Takes a screenshot of a web element or the current frame.
+
+        The screen capture is returned as a lossless PNG image encoded
+        as a base 64 string.  If the `element` argument is defined the
+        capture area will be limited to the bounding box of that
+        element.  Otherwise, the capture area will be the bounding box
+        of the current frame.
 
-        :param element: The element to take a screenshot of. If None, will
-         take a screenshot of the current frame.
-        :param highlights: A list of HTMLElement objects to draw a red box around in the
-         returned screenshot.
-        '''
-        if element is not None:
+        :param element: The element to take a screenshot of.  If None, will
+            take a screenshot of the current frame.
+
+        :param highlights: A list of HTMLElement objects to draw a red
+            box around in the returned screenshot.
+
+        """
+
+        if element:
             element = element.id
         lights = None
-        if highlights is not None:
-            lights = [highlight.id for highlight in highlights if highlights]
-        return self._send_message("screenShot", 'value', id=element, highlights=lights)
+        if highlights:
+            lights = [highlight.id for highlight in highlights]
+        return self._send_message("takeScreenshot", "value",
+                                  id=element, highlights=lights)
 
     @property
     def orientation(self):
         """Get the current browser orientation.
 
         Will return one of the valid primary orientation values
         portrait-primary, landscape-primary, portrait-secondary, or
         landscape-secondary.
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/tests/unit/test_expected.py
@@ -0,0 +1,198 @@
+# 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/.
+
+import urllib
+
+import expected
+import marionette_test
+
+from by import By
+
+def inline(doc):
+    return "data:text/html;charset=utf-8,%s" % urllib.quote(doc)
+
+static_element = inline("""<p>foo</p>""")
+static_elements = static_element + static_element
+
+remove_element_by_tag_name = \
+    """var el = document.getElementsByTagName('%s')[0];
+    document.getElementsByTagName("body")[0].remove(el);"""
+
+hidden_element = inline("<p style='display: none'>hidden</p>")
+
+selected_element = inline("<option selected>selected</option>")
+unselected_element = inline("<option>unselected</option>")
+
+enabled_element = inline("<input>")
+disabled_element = inline("<input disabled>")
+
+def no_such_element(marionette):
+    return marionette.find_element(By.ID, "nosuchelement")
+
+def no_such_elements(marionette):
+    return marionette.find_elements(By.ID, "nosuchelement")
+
+def p(marionette):
+    return marionette.find_element(By.TAG_NAME, "p")
+
+def ps(marionette):
+    return marionette.find_elements(By.TAG_NAME, "p")
+
+class TestExpected(marionette_test.MarionetteTestCase):
+    def test_element_present_func(self):
+        self.marionette.navigate(static_element)
+        el = expected.element_present(p)(self.marionette)
+        self.assertIsNotNone(el)
+
+    def test_element_present_locator(self):
+        self.marionette.navigate(static_element)
+        el = expected.element_present(By.TAG_NAME, "p")(self.marionette)
+        self.assertIsNotNone(el)
+
+    def test_element_present_not_present(self):
+        r = expected.element_present(no_such_element)(self.marionette)
+        self.assertIsInstance(r, bool)
+        self.assertFalse(r)
+
+    def test_element_not_present_func(self):
+        r = expected.element_not_present(no_such_element)(self.marionette)
+        self.assertIsInstance(r, bool)
+        self.assertTrue(r)
+
+    def test_element_not_present_locator(self):
+        r = expected.element_not_present(By.ID, "nosuchelement")(self.marionette)
+        self.assertIsInstance(r, bool)
+        self.assertTrue(r)
+
+    def test_element_not_present_is_present(self):
+        self.marionette.navigate(static_element)
+        r = expected.element_not_present(p)(self.marionette)
+        self.assertIsInstance(r, bool)
+        self.assertFalse(r)
+
+    def test_element_stale(self):
+        self.marionette.navigate(static_element)
+        el = self.marionette.find_element(By.TAG_NAME, "p")
+        self.assertIsNotNone(el)
+        self.marionette.execute_script(remove_element_by_tag_name % "p")
+        r = expected.element_stale(el)(self.marionette)
+        self.assertTrue(r)
+
+    def test_element_stale_is_not_stale(self):
+        self.marionette.navigate(static_element)
+        el = self.marionette.find_element(By.TAG_NAME, "p")
+        r = expected.element_stale(el)(self.marionette)
+        self.assertFalse(r)
+
+    def test_elements_present_func(self):
+        self.marionette.navigate(static_elements)
+        els = expected.elements_present(ps)(self.marionette)
+        self.assertEqual(len(els), 2)
+
+    def test_elements_present_locator(self):
+        self.marionette.navigate(static_elements)
+        els = expected.elements_present(By.TAG_NAME, "p")(self.marionette)
+        self.assertEqual(len(els), 2)
+
+    def test_elements_not_present_func(self):
+        r = expected.element_not_present(no_such_elements)(self.marionette)
+        self.assertIsInstance(r, bool)
+        self.assertTrue(r)
+
+    def test_elements_not_present_locator(self):
+        r = expected.element_not_present(By.ID, "nosuchelement")(self.marionette)
+        self.assertIsInstance(r, bool)
+        self.assertTrue(r)
+
+    def test_elements_not_present_is_present(self):
+        self.marionette.navigate(static_elements)
+        r = expected.elements_not_present(ps)(self.marionette)
+        self.assertIsInstance(r, bool)
+        self.assertFalse(r)
+
+    def test_element_displayed(self):
+        self.marionette.navigate(static_element)
+        el = self.marionette.find_element(By.TAG_NAME, "p")
+        visible = expected.element_displayed(el)(self.marionette)
+        self.assertTrue(visible)
+
+    def test_element_displayed_when_hidden(self):
+        self.marionette.navigate(hidden_element)
+        el = self.marionette.find_element(By.TAG_NAME, "p")
+        hidden = expected.element_displayed(el)(self.marionette)
+        self.assertFalse(hidden)
+
+    def test_element_displayed_when_stale_element(self):
+        self.marionette.navigate(static_element)
+        el = self.marionette.find_element(By.TAG_NAME, "p")
+        self.marionette.navigate("about:blank")
+        missing = expected.element_displayed(el)(self.marionette)
+        self.assertFalse(missing)
+
+    def test_element_not_displayed(self):
+        self.marionette.navigate(hidden_element)
+        el = self.marionette.find_element(By.TAG_NAME, "p")
+        visible = expected.element_not_displayed(el)(self.marionette)
+        self.assertTrue(visible)
+
+    def test_element_not_displayed_when_visible(self):
+        self.marionette.navigate(static_element)
+        el = self.marionette.find_element(By.TAG_NAME, "p")
+        hidden = expected.element_not_displayed(el)(self.marionette)
+        self.assertFalse(hidden)
+
+    def test_element_not_displayed_when_stale_element(self):
+        self.marionette.navigate(static_element)
+        el = self.marionette.find_element(By.TAG_NAME, "p")
+        self.marionette.navigate("about:blank")
+        missing = expected.element_not_displayed(el)(self.marionette)
+        self.assertTrue(missing)
+
+    def test_element_selected(self):
+        self.marionette.navigate(selected_element)
+        el = self.marionette.find_element(By.TAG_NAME, "option")
+        selected = expected.element_selected(el)(self.marionette)
+        self.assertTrue(selected)
+
+    def test_element_selected_when_not_selected(self):
+        self.marionette.navigate(unselected_element)
+        el = self.marionette.find_element(By.TAG_NAME, "option")
+        unselected = expected.element_selected(el)(self.marionette)
+        self.assertFalse(unselected)
+
+    def test_element_not_selected(self):
+        self.marionette.navigate(unselected_element)
+        el = self.marionette.find_element(By.TAG_NAME, "option")
+        unselected = expected.element_not_selected(el)(self.marionette)
+        self.assertTrue(unselected)
+
+    def test_element_not_selected_when_selected(self):
+        self.marionette.navigate(selected_element)
+        el = self.marionette.find_element(By.TAG_NAME, "option")
+        selected = expected.element_not_selected(el)(self.marionette)
+        self.assertFalse(selected)
+
+    def test_element_enabled(self):
+        self.marionette.navigate(enabled_element)
+        el = self.marionette.find_element(By.TAG_NAME, "input")
+        enabled = expected.element_enabled(el)(self.marionette)
+        self.assertTrue(enabled)
+
+    def test_element_enabled_when_disabled(self):
+        self.marionette.navigate(disabled_element)
+        el = self.marionette.find_element(By.TAG_NAME, "input")
+        disabled = expected.element_enabled(el)(self.marionette)
+        self.assertFalse(disabled)
+
+    def test_element_not_enabled(self):
+        self.marionette.navigate(disabled_element)
+        el = self.marionette.find_element(By.TAG_NAME, "input")
+        disabled = expected.element_not_enabled(el)(self.marionette)
+        self.assertTrue(disabled)
+
+    def test_element_not_enabled_when_enabled(self):
+        self.marionette.navigate(enabled_element)
+        el = self.marionette.find_element(By.TAG_NAME, "input")
+        enabled = expected.element_not_enabled(el)(self.marionette)
+        self.assertFalse(enabled)
--- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini
+++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini
@@ -88,16 +88,17 @@ b2g = false
 [test_cookies.py]
 b2g = false
 [test_window_title.py]
 b2g = false
 [test_window_type.py]
 b2g = false
 [test_implicit_waits.py]
 [test_wait.py]
+[test_expected.py]
 [test_date_time_value.py]
 [test_getactiveframe_oop.py]
 disabled = "Bug 925688"
 [test_submit.py]
 [test_chrome_async_finish.js]
 [test_screen_orientation.py]
 browser = false
-[test_errors.py]
\ No newline at end of file
+[test_errors.py]
--- a/testing/marionette/marionette-listener.js
+++ b/testing/marionette/marionette-listener.js
@@ -125,17 +125,17 @@ function removeMessageListenerId(message
 function startListeners() {
   addMessageListenerId("Marionette:newSession", newSession);
   addMessageListenerId("Marionette:executeScript", executeScript);
   addMessageListenerId("Marionette:executeAsyncScript", executeAsyncScript);
   addMessageListenerId("Marionette:executeJSScript", executeJSScript);
   addMessageListenerId("Marionette:singleTap", singleTap);
   addMessageListenerId("Marionette:actionChain", actionChain);
   addMessageListenerId("Marionette:multiAction", multiAction);
-  addMessageListenerId("Marionette:goUrl", goUrl);
+  addMessageListenerId("Marionette:get", get);
   addMessageListenerId("Marionette:getCurrentUrl", getCurrentUrl);
   addMessageListenerId("Marionette:getTitle", getTitle);
   addMessageListenerId("Marionette:getPageSource", getPageSource);
   addMessageListenerId("Marionette:goBack", goBack);
   addMessageListenerId("Marionette:goForward", goForward);
   addMessageListenerId("Marionette:refresh", refresh);
   addMessageListenerId("Marionette:findElementContent", findElementContent);
   addMessageListenerId("Marionette:findElementsContent", findElementsContent);
@@ -155,17 +155,17 @@ function startListeners() {
   addMessageListenerId("Marionette:clearElement", clearElement);
   addMessageListenerId("Marionette:switchToFrame", switchToFrame);
   addMessageListenerId("Marionette:deleteSession", deleteSession);
   addMessageListenerId("Marionette:sleepSession", sleepSession);
   addMessageListenerId("Marionette:emulatorCmdResult", emulatorCmdResult);
   addMessageListenerId("Marionette:importScript", importScript);
   addMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus);
   addMessageListenerId("Marionette:setTestName", setTestName);
-  addMessageListenerId("Marionette:screenShot", screenShot);
+  addMessageListenerId("Marionette:takeScreenshot", takeScreenshot);
   addMessageListenerId("Marionette:addCookie", addCookie);
   addMessageListenerId("Marionette:getCookies", getCookies);
   addMessageListenerId("Marionette:deleteAllCookies", deleteAllCookies);
   addMessageListenerId("Marionette:deleteCookie", deleteCookie);
 }
 
 /**
  * Used during newSession and restart, called to set up the modal dialog listener in b2g
@@ -226,17 +226,17 @@ function restart(msg) {
 function deleteSession(msg) {
   removeMessageListenerId("Marionette:newSession", newSession);
   removeMessageListenerId("Marionette:executeScript", executeScript);
   removeMessageListenerId("Marionette:executeAsyncScript", executeAsyncScript);
   removeMessageListenerId("Marionette:executeJSScript", executeJSScript);
   removeMessageListenerId("Marionette:singleTap", singleTap);
   removeMessageListenerId("Marionette:actionChain", actionChain);
   removeMessageListenerId("Marionette:multiAction", multiAction);
-  removeMessageListenerId("Marionette:goUrl", goUrl);
+  removeMessageListenerId("Marionette:get", get);
   removeMessageListenerId("Marionette:getTitle", getTitle);
   removeMessageListenerId("Marionette:getPageSource", getPageSource);
   removeMessageListenerId("Marionette:getCurrentUrl", getCurrentUrl);
   removeMessageListenerId("Marionette:goBack", goBack);
   removeMessageListenerId("Marionette:goForward", goForward);
   removeMessageListenerId("Marionette:refresh", refresh);
   removeMessageListenerId("Marionette:findElementContent", findElementContent);
   removeMessageListenerId("Marionette:findElementsContent", findElementsContent);
@@ -255,17 +255,17 @@ function deleteSession(msg) {
   removeMessageListenerId("Marionette:clearElement", clearElement);
   removeMessageListenerId("Marionette:switchToFrame", switchToFrame);
   removeMessageListenerId("Marionette:deleteSession", deleteSession);
   removeMessageListenerId("Marionette:sleepSession", sleepSession);
   removeMessageListenerId("Marionette:emulatorCmdResult", emulatorCmdResult);
   removeMessageListenerId("Marionette:importScript", importScript);
   removeMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus);
   removeMessageListenerId("Marionette:setTestName", setTestName);
-  removeMessageListenerId("Marionette:screenShot", screenShot);
+  removeMessageListenerId("Marionette:takeScreenshot", takeScreenshot);
   removeMessageListenerId("Marionette:addCookie", addCookie);
   removeMessageListenerId("Marionette:getCookies", getCookies);
   removeMessageListenerId("Marionette:deleteAllCookies", deleteAllCookies);
   removeMessageListenerId("Marionette:deleteCookie", deleteCookie);
   if (isB2G) {
     content.removeEventListener("mozbrowsershowmodalprompt", modalHandler, false);
   }
   elementManager.reset();
@@ -1178,63 +1178,68 @@ function multiAction(msg) {
     setDispatch(concurrentEvent, pendingTouches, command_id);
   }
   catch (e) {
     sendError(e.message, e.code, e.stack, msg.json.command_id);
   }
 }
 
 /**
- * Navigate to URI. Handles the case where we navigate within an iframe.
- * All other navigation is handled by the server (in chrome space).
+ * Navigate to the given URL.  The operation will be performed on the
+ * current browser context, and handles the case where we navigate
+ * within an iframe.  All other navigation is handled by the server
+ * (in chrome space).
  */
-function goUrl(msg) {
+function get(msg) {
   let command_id = msg.json.command_id;
 
   let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
   let start = new Date().getTime();
   let end = null;
-  function checkLoad(){
+  function checkLoad() {
     checkTimer.cancel();
     end = new Date().getTime();
     let errorRegex = /about:.+(error)|(blocked)\?/;
     let elapse = end - start;
-    if (msg.json.pageTimeout == null || elapse <= msg.json.pageTimeout){
-      if (curFrame.document.readyState == "complete"){
+    if (msg.json.pageTimeout == null || elapse <= msg.json.pageTimeout) {
+      if (curFrame.document.readyState == "complete") {
         removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
         sendOk(command_id);
       }
-      else if (curFrame.document.readyState == "interactive" && errorRegex.exec(curFrame.document.baseURI)){
+      else if (curFrame.document.readyState == "interactive" &&
+               errorRegex.exec(curFrame.document.baseURI)) {
         removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
         sendError("Error loading page", 13, null, command_id);
       }
-      else{
+      else {
         checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
       }
     }
-    else{
+    else {
       removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
-      sendError("Error loading page, timed out (checkLoad)", 21, null, command_id);
+      sendError("Error loading page, timed out (checkLoad)", 21, null,
+                command_id);
     }
   }
-  // Prevent DOMContentLoaded events from frames from invoking this code,
-  // unless the event is coming from the frame associated with the current
-  // window (i.e., someone has used switch_to_frame).
-  let onDOMContentLoaded = function onDOMContentLoaded(event){
+  // Prevent DOMContentLoaded events from frames from invoking this
+  // code, unless the event is coming from the frame associated with
+  // the current window (i.e. someone has used switch_to_frame).
+  let onDOMContentLoaded = function onDOMContentLoaded(event) {
     if (!event.originalTarget.defaultView.frameElement ||
-      event.originalTarget.defaultView.frameElement == curFrame.frameElement) {
+        event.originalTarget.defaultView.frameElement == curFrame.frameElement) {
       checkLoad();
     }
   };
 
-  function timerFunc(){
+  function timerFunc() {
     removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
-    sendError("Error loading page, timed out (onDOMContentLoaded)", 21, null, command_id);
+    sendError("Error loading page, timed out (onDOMContentLoaded)", 21,
+              null, command_id);
   }
-  if (msg.json.pageTimeout != null){
+  if (msg.json.pageTimeout != null) {
     checkTimer.initWithCallback(timerFunc, msg.json.pageTimeout, Ci.nsITimer.TYPE_ONE_SHOT);
   }
   addEventListener("DOMContentLoaded", onDOMContentLoaded, false);
   curFrame.location = msg.json.url;
 }
 
 /**
  * Get URL of the top level browsing context.
@@ -2051,31 +2056,37 @@ function importScript(msg) {
     importedScripts.permissions = parseInt("0666", 8); //actually set permissions
   }
   file.write(msg.json.script, msg.json.script.length);
   file.close();
   sendOk(command_id);
 }
 
 /**
- * Saves a screenshot and returns a Base64 string
+ * Takes a screen capture of the given web element if <code>id</code>
+ * property exists in the message's JSON object, or if null captures
+ * the bounding box of the current frame.
+ *
+ * If given an array of web element references in
+ * <code>msg.json.highlights</code>, a red box will be painted around
+ * them to highlight their position.
  */
-function screenShot(msg) {
+function takeScreenshot(msg) {
   let node = null;
   if (msg.json.id) {
     try {
       node = elementManager.getKnownElement(msg.json.id, curFrame)
     }
     catch (e) {
       sendResponse(e.message, e.code, e.stack, msg.json.command_id);
       return;
     }
   }
   else {
-      node = curFrame;
+    node = curFrame;
   }
   let highlights = msg.json.highlights;
 
   var document = curFrame.document;
   var rect, win, width, height, left, top;
   // node can be either a window or an arbitrary DOM node
   if (node == curFrame) {
     // node is a window
@@ -2090,41 +2101,47 @@ function screenShot(msg) {
     win = node.ownerDocument.defaultView;
     rect = node.getBoundingClientRect();
     width = rect.width;
     height = rect.height;
     top = rect.top;
     left = rect.left;
   }
 
-  var canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+  var canvas = document.createElementNS("http://www.w3.org/1999/xhtml",
+                                        "canvas");
   canvas.width = width;
   canvas.height = height;
   var ctx = canvas.getContext("2d");
   // Draws the DOM contents of the window to the canvas
-  ctx.drawWindow(win, left, top, width, height, 'rgb(255,255,255)');
+  ctx.drawWindow(win, left, top, width, height, "rgb(255,255,255)");
 
-  // This section is for drawing a red rectangle around each element passed in via the highlights array
+  // This section is for drawing a red rectangle around each element
+  // passed in via the highlights array
   if (highlights) {
     ctx.lineWidth = "2";
     ctx.strokeStyle = "red";
     ctx.save();
 
     for (var i = 0; i < highlights.length; ++i) {
-      var elem = elementManager.getKnownElement(highlights[i], curFrame)
+      var elem = elementManager.getKnownElement(highlights[i], curFrame);
       rect = elem.getBoundingClientRect();
 
       var offsetY = -top;
       var offsetX = -left;
 
       // Draw the rectangle
-      ctx.strokeRect(rect.left + offsetX, rect.top + offsetY, rect.width, rect.height);
+      ctx.strokeRect(rect.left + offsetX,
+                     rect.top + offsetY,
+                     rect.width,
+                     rect.height);
     }
   }
 
-  // Return the Base64 String back to the client bindings and they can manage
-  // saving the file to disk if it is required
-  var data_url = canvas.toDataURL("image/png","");
-  sendResponse({value: data_url.substring(data_url.indexOf(",") + 1)}, msg.json.command_id);
+  // Return the Base64 encoded string back to the client so that it
+  // can save the file to disk if it is required
+  var dataUrl = canvas.toDataURL("image/png", "");
+  var data = dataUrl.substring(dataUrl.indexOf(",") + 1);
+  sendResponse({value: data}, msg.json.command_id);
 }
 
-//call register self when we get loaded
+// Call register self when we get loaded
 registerSelf();
--- a/testing/marionette/marionette-server.js
+++ b/testing/marionette/marionette-server.js
@@ -1035,51 +1035,72 @@ MarionetteServerConnection.prototype = {
                                      aRequest.parameters.filename,
                                      aRequest.parameters.line,
                                      script);
       chromeAsyncReturnFunc(error[0], 17, error[1]);
     }
   },
 
   /**
-   * Navigates to given url
+   * Navigate to to given URL.
+   *
+   * This will follow redirects issued by the server.  When the method
+   * returns is based on the page load strategy that the user has
+   * selected.
+   *
+   * Documents that contain a META tag with the "http-equiv" attribute
+   * set to "refresh" will return if the timeout is greater than 1
+   * second and the other criteria for determining whether a page is
+   * loaded are met.  When the refresh period is 1 second or less and
+   * the page load strategy is "normal" or "conservative", it will
+   * wait for the page to complete loading before returning.
    *
-   * @param object aRequest
-   *        'url' member holds the url to navigate to
+   * If any modal dialog box, such as those opened on
+   * window.onbeforeunload or window.alert, is opened at any point in
+   * the page load, it will return immediately.
+   *
+   * If a 401 response is seen by the browser, it will return
+   * immediately.  That is, if BASIC, DIGEST, NTLM or similar
+   * authentication is required, the page load is assumed to be
+   * complete.  This does not include FORM-based authentication.
+   *
+   * @param object aRequest where <code>url</code> property holds the
+   *        URL to navigate to
    */
-  goUrl: function MDA_goUrl(aRequest) {
+  get: function MDA_get(aRequest) {
     let command_id = this.command_id = this.getCommandId();
     if (this.context != "chrome") {
       aRequest.command_id = command_id;
       aRequest.parameters.pageTimeout = this.pageTimeout;
-      this.sendAsync("goUrl", aRequest.parameters, command_id);
+      this.sendAsync("get", aRequest.parameters, command_id);
       return;
     }
 
     this.getCurrentWindow().location.href = aRequest.parameters.url;
     let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     let start = new Date().getTime();
     let end = null;
+
     function checkLoad() {
       end = new Date().getTime();
       let elapse = end - start;
       if (this.pageTimeout == null || elapse <= this.pageTimeout){
         if (curWindow.document.readyState == "complete") {
           sendOk(command_id);
           return;
         }
         else{
           checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
         }
       }
       else{
         sendError("Error loading page", 13, null, command_id);
         return;
       }
-    }//end
+    }
     checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT);
   },
 
   /**
    * Get a string representing the current URL.
    *
    * On Desktop this returns a string representation of the URL of the
    * current top level browsing context.  This is equivalent to
@@ -1167,38 +1188,49 @@ MarionetteServerConnection.prototype = {
    * Get the current window's handle.
    *
    * Return an opaque server-assigned identifier to this window that
    * uniquely identifies it within this Marionette instance.  This can
    * be used to switch to this window at a later point.
    *
    * @return unique window handle (string)
    */
-  getCurrentWindowHandle: function MDA_getCurrentWindowHandle() {
+  getWindowHandle: function MDA_getWindowHandle() {
     this.command_id = this.getCommandId();
     for (let i in this.browsers) {
       if (this.curBrowser == this.browsers[i]) {
         this.sendResponse(i, this.command_id);
         return;
       }
     }
   },
 
   /**
-   * Get the server-assigned IDs of all available windows
+   * Get list of windows in the current context.
+   *
+   * If called in the content context it will return a list of
+   * references to all available browser windows.  Called in the
+   * chrome context, it will list all available windows, not just
+   * browser windows (e.g. not just navigator.browser).
+   *
+   * Each window handle is assigned by the server, and the array of
+   * strings returned does not have a guaranteed ordering.
+   *
+   * @return unordered array of unique window handles as strings
    */
-  getWindows: function MDA_getWindows() {
+  getWindowHandles: function MDA_getWindowHandles() {
     this.command_id = this.getCommandId();
     let res = [];
     let winEn = this.getWinEnumerator();
-    while(winEn.hasMoreElements()) {
+    while (winEn.hasMoreElements()) {
       let foundWin = winEn.getNext();
-      let winId = foundWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
-      winId = winId + ((appName == "B2G") ? '-b2g' : '');
-      res.push(winId)
+      let winId = foundWin.QueryInterface(Ci.nsIInterfaceRequestor)
+            .getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
+      winId = winId + ((appName == "B2G") ? "-b2g" : "");
+      res.push(winId);
     }
     this.sendResponse(res, this.command_id);
   },
 
   /**
    * Switch to a window based on name or server-assigned id.
    * Searches based on name, then id.
    *
@@ -2171,26 +2203,35 @@ MarionetteServerConnection.prototype = {
     catch (e) {
       this.sendError("Could not clear imported scripts", 500, e.name + ": " + e.message, command_id);
       return;
     }
     this.sendOk(command_id);
   },
 
   /**
-   * Takes a screenshot of a DOM node. If there is no node given a screenshot
-   * of the window will be taken.
-   */
-  screenShot: function MDA_saveScreenshot(aRequest) {
+   * Takes a screenshot of a web element or the current frame.
+   *
+   * The screen capture is returned as a lossless PNG image encoded as
+   * a base 64 string.  If the <code>id</code> argument is not null
+   * and refers to a present and visible web element's ID, the capture
+   * area will be limited to the bounding box of that element.
+   * Otherwise, the capture area will be the bounding box of the
+   * current frame.
+   *
+   * @param id an optional reference to a web element
+   * @param highlights an optional list of web elements to draw a red
+   *                   box around in the returned capture
+   * @return PNG image encoded as base 64 string
+    */
+  takeScreenshot: function MDA_takeScreenshot(aRequest) {
     this.command_id = this.getCommandId();
-    this.sendAsync("screenShot",
-                   {
-                     id: aRequest.parameters.id,
-                     highlights: aRequest.parameters.highlights
-                   },
+    this.sendAsync("takeScreenshot",
+                   {id: aRequest.parameters.id,
+                    highlights: aRequest.parameters.highlights},
                    this.command_id);
   },
 
   /**
    * Get the current browser orientation.
    *
    * Will return one of the valid primary orientation values
    * portrait-primary, landscape-primary, portrait-secondary, or
@@ -2219,23 +2260,25 @@ MarionetteServerConnection.prototype = {
                  "portrait-primary", "landscape-primary",
                  "portrait-secondary", "landscape-secondary"];
 
     this.command_id = this.getCommandId();
     let or = String(aRequest.parameters.orientation);
 
     let mozOr = or.toLowerCase();
     if (ors.indexOf(mozOr) < 0) {
-      this.sendError("Unknown screen orientation: " + or, 500, null, this.command_id);
+      this.sendError("Unknown screen orientation: " + or, 500, null,
+                     this.command_id);
       return;
     }
 
     let curWindow = this.getCurrentWindow();
     if (!curWindow.screen.mozLockOrientation(mozOr)) {
-      this.sendError("Unable to set screen orientation: " + or, 500, null, this.command_id);
+      this.sendError("Unable to set screen orientation: " + or, 500,
+                     null, this.command_id);
     }
     this.sendOk(this.command_id);
   },
 
   /**
    * Helper function to convert an outerWindowID into a UID that Marionette
    * tracks.
    */
@@ -2386,37 +2429,41 @@ MarionetteServerConnection.prototype.req
   "isElementSelected": MarionetteServerConnection.prototype.isElementSelected,
   "sendKeysToElement": MarionetteServerConnection.prototype.sendKeysToElement,
   "getElementLocation": MarionetteServerConnection.prototype.getElementLocation,
   "getElementPosition": MarionetteServerConnection.prototype.getElementLocation,  // deprecated
   "clearElement": MarionetteServerConnection.prototype.clearElement,
   "getTitle": MarionetteServerConnection.prototype.getTitle,
   "getWindowType": MarionetteServerConnection.prototype.getWindowType,
   "getPageSource": MarionetteServerConnection.prototype.getPageSource,
-  "goUrl": MarionetteServerConnection.prototype.goUrl,
+  "get": MarionetteServerConnection.prototype.get,
+  "goUrl": MarionetteServerConnection.prototype.get,  // deprecated
   "getCurrentUrl": MarionetteServerConnection.prototype.getCurrentUrl,
   "getUrl": MarionetteServerConnection.prototype.getCurrentUrl,  // deprecated
   "goBack": MarionetteServerConnection.prototype.goBack,
   "goForward": MarionetteServerConnection.prototype.goForward,
   "refresh":  MarionetteServerConnection.prototype.refresh,
-  "getCurrentWindowHandle":  MarionetteServerConnection.prototype.getCurrentWindowHandle,
-  "getWindow":  MarionetteServerConnection.prototype.getCurrentWindowHandle,  // deprecated
-  "getWindows":  MarionetteServerConnection.prototype.getWindows,
+  "getWindowHandle": MarionetteServerConnection.prototype.getWindowHandle,
+  "getCurrentWindowHandle":  MarionetteServerConnection.prototype.getWindowHandle,  // Selenium 2 compat
+  "getWindow":  MarionetteServerConnection.prototype.getWindowHandle,  // deprecated
+  "getCurrentWindowHandles": MarionetteServerConnection.prototype.getWindowHandles,
+  "getWindows":  MarionetteServerConnection.prototype.getWindowHandles,  // deprecated
   "getActiveFrame": MarionetteServerConnection.prototype.getActiveFrame,
   "switchToFrame": MarionetteServerConnection.prototype.switchToFrame,
   "switchToWindow": MarionetteServerConnection.prototype.switchToWindow,
   "deleteSession": MarionetteServerConnection.prototype.deleteSession,
   "emulatorCmdResult": MarionetteServerConnection.prototype.emulatorCmdResult,
   "importScript": MarionetteServerConnection.prototype.importScript,
   "clearImportedScripts": MarionetteServerConnection.prototype.clearImportedScripts,
   "getAppCacheStatus": MarionetteServerConnection.prototype.getAppCacheStatus,
   "close": MarionetteServerConnection.prototype.close,
   "closeWindow": MarionetteServerConnection.prototype.close,  // deprecated
   "setTestName": MarionetteServerConnection.prototype.setTestName,
-  "screenShot": MarionetteServerConnection.prototype.screenShot,
+  "takeScreenshot": MarionetteServerConnection.prototype.takeScreenshot,
+  "screenShot": MarionetteServerConnection.prototype.takeScreenshot,  // deprecated
   "addCookie": MarionetteServerConnection.prototype.addCookie,
   "getCookies": MarionetteServerConnection.prototype.getCookies,
   "getAllCookies": MarionetteServerConnection.prototype.getCookies,  // deprecated
   "deleteAllCookies": MarionetteServerConnection.prototype.deleteAllCookies,
   "deleteCookie": MarionetteServerConnection.prototype.deleteCookie,
   "getActiveElement": MarionetteServerConnection.prototype.getActiveElement,
   "getScreenOrientation": MarionetteServerConnection.prototype.getScreenOrientation,
   "setScreenOrientation": MarionetteServerConnection.prototype.setScreenOrientation
--- a/testing/mozbase/mozrunner/mozrunner/local.py
+++ b/testing/mozbase/mozrunner/mozrunner/local.py
@@ -68,26 +68,26 @@ def debugger_arguments(debugger, argumen
 
 class LocalRunner(Runner):
     """Handles all running operations. Finds bins, runs and kills the process."""
 
     profile_class = Profile # profile class to use by default
 
     @classmethod
     def create(cls, binary=None, cmdargs=None, env=None, kp_kwargs=None, profile_args=None,
-               clean_profile=True, process_class=None):
+               clean_profile=True, process_class=None, **kwargs):
         profile = cls.profile_class(**(profile_args or {}))
         return cls(profile, binary=binary, cmdargs=cmdargs, env=env, kp_kwargs=kp_kwargs,
-                                           clean_profile=clean_profile, process_class=process_class)
+                                           clean_profile=clean_profile, process_class=process_class, **kwargs)
 
     def __init__(self, profile, binary, cmdargs=None, env=None,
-                 kp_kwargs=None, clean_profile=None, process_class=None):
+                 kp_kwargs=None, clean_profile=None, process_class=None, **kwargs):
 
         super(LocalRunner, self).__init__(profile, clean_profile=clean_profile, kp_kwargs=kp_kwargs,
-                                               process_class=process_class, env=env)
+                                          process_class=process_class, env=env, **kwargs)
 
         # find the binary
         self.binary = binary
         if not self.binary:
             raise Exception("Binary not specified")
         if not os.path.exists(self.binary):
             raise OSError("Binary path does not exist: %s" % self.binary)
 
--- a/testing/mozbase/mozrunner/mozrunner/runner.py
+++ b/testing/mozbase/mozrunner/mozrunner/runner.py
@@ -1,13 +1,14 @@
 #!/usr/bin/env python
-
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
 import subprocess
 import traceback
 
 from mozprocess.processhandler import ProcessHandler
 import mozcrash
 import mozlog
 
 # we can replace this method with 'abc'
@@ -33,17 +34,16 @@ class Runner(object):
         self.kp_kwargs = kp_kwargs or {}
         self.process_class = process_class or ProcessHandler
         self.process_handler = None
         self.returncode = None
         self.profile = profile
         self.log = mozlog.getLogger('MozRunner')
         self.symbols_path = symbols_path
 
-    @abstractmethod
     def start(self, *args, **kwargs):
         """
         Run the process
         """
 
         # ensure you are stopped
         self.stop()
 
@@ -107,17 +107,20 @@ class Runner(object):
 
     def reset(self):
         """
         Reset the runner to its default state
         """
         if getattr(self, 'profile', False):
             self.profile.reset()
 
-    def check_for_crashes(self, dump_directory, test_name=None):
+    def check_for_crashes(self, dump_directory=None, test_name=None):
+        if not dump_directory:
+            dump_directory = os.path.join(self.profile.profile, 'minidumps')
+
         crashed = False
         try:
             crashed = mozcrash.check_for_crashes(dump_directory,
                                                  self.symbols_path,
                                                  test_name=test_name)
         except:
             traceback.print_exc()
         return crashed
--- a/testing/talos/talos.json
+++ b/testing/talos/talos.json
@@ -1,16 +1,16 @@
 {
     "talos.zip": {
         "url": "http://talos-bundles.pvt.build.mozilla.org/zips/talos.8c5f2725fbdd.zip",
         "path": ""
     },
     "global": {
         "talos_repo": "http://hg.mozilla.org/build/talos",
-        "talos_revision": "8c5f2725fbdd"
+        "talos_revision": "82b7680f9eaf"
     },
     "suites": {
         "chromez": {
             "tests": ["tresize", "tcanvasmark"]
         },
         "dirtypaint": {
             "tests": ["tspaint_places_generated_med", "tspaint_places_generated_max"],
             "talos_addons": [
--- a/toolkit/content/aboutWebrtc.xhtml
+++ b/toolkit/content/aboutWebrtc.xhtml
@@ -143,47 +143,57 @@ function buildEmptyCandTable(local) {
   candTable.appendChild(buildCandTableHeader(local));
   return candTable;
 }
 
 function round00(num) {
   return Math.round(num * 100) / 100;
 }
 
+function dumpStat(stat, label) {
+  var div = document.createElement('div');
+  var statsString = " " + label + new Date(stat.timestamp).toTimeString() +
+                    " " + stat.type + " SSRC: " + stat.ssrc;
+  if (stat.packetsReceived !== undefined) {
+    statsString += " Received: " + stat.packetsReceived + " packets";
+    if (stat.bytesReceived !== undefined) {
+      statsString += " (" + round00(stat.bytesReceived/1024) + " Kb)";
+    }
+    statsString += " Jitter: " + stat.jitter;
+  } else if (stat.packetsSent !== undefined) {
+    statsString += " Sent: " + stat.packetsSent + " packets";
+    if (stat.bytesSent !== undefined) {
+      statsString += " (" + round00(stat.bytesSent/1024) + " Kb)";
+    }
+  }
+  div.appendChild(document.createTextNode(statsString));
+  return div;
+}
+
 function buildPcDiv(stats, pcDivId) {
   var newPcDiv = document.createElement('div');
 
   var heading = document.createElement('h3');
   heading.appendChild(document.createTextNode(pcDivId));
   newPcDiv.appendChild(heading);
 
   var subDivs = {};
 
   stats.forEach(function(stat) {
     if (!stat.componentId) {
-      var statDiv = document.createElement('div');
-      statDiv.appendChild(document.createElement('strong'))
-             .appendChild(document.createTextNode(stat.id));
-
-      var statsString = " " + new Date(stat.timestamp).toTimeString() +
-                        " " + stat.type + " SSRC: " + stat.ssrc;
-      if (stat.packetsReceived !== undefined) {
-        statsString += " Received: " + stat.packetsReceived + " packets";
-        if (stat.bytesReceived !== undefined) {
-          statsString += " (" + round00(stat.bytesReceived/1024) + " Kb)";
-        }
-        statsString += " Jitter: " + stat.jitter;
-      } else if (stat.packetsSent !== undefined) {
-        statsString += " Sent: " + stat.packetsSent + " packets";
-        if (stat.bytesSent !== undefined) {
-          statsString += " (" + round00(stat.bytesSent/1024) + " Kb)";
+      if (!stat.isRemote) {
+        newPcDiv.appendChild(document.createElement('h4'))
+                .appendChild(document.createTextNode(stat.id));
+        if (stat.remoteId) {
+          newPcDiv.appendChild(dumpStat(stat, "Local: "));
+          newPcDiv.appendChild(dumpStat(stats.get(stat.remoteId), "Remote: "));
+        } else {
+          newPcDiv.appendChild(dumpStat(stat, ""));
         }
       }
-      statDiv.appendChild(document.createTextNode(statsString));
-      newPcDiv.appendChild(statDiv);
       return;
     }
 
     if (!subDivs[stat.componentId]) {
       subDivs[stat.componentId] = {
         candPairTable: buildEmptyCandPairTable(),
         localCandTable: buildEmptyCandTable(true),
         remoteCandTable: buildEmptyCandTable(false)
--- a/toolkit/modules/Finder.jsm
+++ b/toolkit/modules/Finder.jsm
@@ -111,25 +111,22 @@ Finder.prototype = {
       let result = found ? Ci.nsITypeAheadFind.FIND_FOUND
                          : Ci.nsITypeAheadFind.FIND_NOTFOUND;
       this._notify(aWord, result, false, false);
     }
   },
 
   enableSelection: function() {
     this._fastFind.setSelectionModeAndRepaint(Ci.nsISelectionController.SELECTION_ON);
+    this._restoreOriginalOutline();
   },
 
   removeSelection: function() {
-    let fastFind = this._fastFind;
-
-    fastFind.collapseSelection();
+    this._fastFind.collapseSelection();
     this.enableSelection();
-
-    this._restoreOriginalOutline();
   },
 
   focusContent: function() {
     // Allow Finder listeners to cancel focusing the content.
     for (let l of this._listeners) {
       if (!l.shouldFocusContent())
         return;
     }
--- a/toolkit/mozapps/installer/windows/nsis/common.nsh
+++ b/toolkit/mozapps/installer/windows/nsis/common.nsh
@@ -7556,20 +7556,20 @@
                                         i $R2|${DT_SINGLELINE})'
         System::Call '*$6(i, i, i .r8, i .r7)'
         System::Free $6
 
         ; Get the approximate number height needed to display the text starting
         ; with a minimum of 3 lines of text.
         StrCpy $9 $8
         StrCpy $R1 2 ; set the number of lines initially to 2
-        ${While} $9 > $0
+        ${Do}
           IntOp $R1 $R1 + 1 ; increment the number of lines
           IntOp $9 $8 / $R1
-        ${EndWhile}
+        ${LoopUntil} $9 < $0
         IntOp $7 $7 * $R1
 
         StrCpy $R0 $9
         ${Do}
           IntOp $R0 $R0 + 20
           System::Call '*(i, i, i R0, i r7) i .r6'
           System::Call 'user32::DrawTextW(i r4, t $\"$2$\", i r5, i r6, \
                                           i $R2|${DT_WORDBREAK}) i .R1'
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -1561,18 +1561,26 @@ NS_IMETHODIMP nsAndroidBridge::IsContent
 // DO NOT USE THIS unless you need to access JNI from
 // non-main threads.  This is probably not what you want.
 // Questions, ask blassey or dougt.
 
 static void
 JavaThreadDetachFunc(void *arg)
 {
     JNIEnv *env = (JNIEnv*) arg;
+    MOZ_ASSERT(env, "No JNIEnv on Gecko thread");
+    if (!env) {
+        return;
+    }
     JavaVM *vm = nullptr;
     env->GetJavaVM(&vm);
+    MOZ_ASSERT(vm, "No JavaVM on Gecko thread");
+    if (!vm) {
+        return;
+    }
     vm->DetachCurrentThread();
 }
 
 uint32_t
 AndroidBridge::GetScreenOrientation()
 {
     ALOG_BRIDGE("AndroidBridge::GetScreenOrientation");