merge autoland to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 25 Jul 2016 15:46:37 +0200
changeset 346325 f44bb9de08ade45299223de89953c6d0f4d003d1
parent 346264 7c669d5d63efceb12696cd65cfa72c296013dafb (current diff)
parent 346324 d69f9992ba40934b68bbe01a8c30dd786373ec84 (diff)
child 346370 e730a1dca1a41bd6b0824353305abc25284e2d52
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone50.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 autoland to mozilla-central a=merge
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -33,18 +33,16 @@ Cu.import('resource://gre/modules/Presen
 Cu.import('resource://gre/modules/AboutServiceWorkers.jsm');
 
 XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy",
                                   "resource://gre/modules/SystemAppProxy.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Screenshot",
                                   "resource://gre/modules/Screenshot.jsm");
 
-Cu.import('resource://gre/modules/Webapps.jsm');
-
 XPCOMUtils.defineLazyServiceGetter(Services, 'env',
                                    '@mozilla.org/process/environment;1',
                                    'nsIEnvironment');
 
 XPCOMUtils.defineLazyServiceGetter(Services, 'ss',
                                    '@mozilla.org/content/style-sheet-service;1',
                                    'nsIStyleSheetService');
 
@@ -351,16 +349,17 @@ var shell = {
     }
 
     let homeURL = this.homeURL;
     if (!homeURL) {
       let msg = 'Fatal error during startup: No homescreen found: try setting B2G_HOMESCREEN';
       alert(msg);
       return;
     }
+
     let manifestURL = this.manifestURL;
     // <html:iframe id="systemapp"
     //              mozbrowser="true" allowfullscreen="true"
     //              style="overflow: hidden; height: 100%; width: 100%; border: none;"
     //              src="data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;'>"/>
     let systemAppFrame =
       document.createElementNS('http://www.w3.org/1999/xhtml', 'html:iframe');
     systemAppFrame.setAttribute('id', 'systemapp');
@@ -417,21 +416,21 @@ var shell = {
     window.addEventListener('MozAfterPaint', this);
     window.addEventListener('sizemodechange', this);
     window.addEventListener('unload', this);
     this.contentBrowser.addEventListener('mozbrowserloadstart', this, true);
     this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true);
     this.contentBrowser.addEventListener('mozbrowsercaretstatechanged', this);
 
     CustomEventManager.init();
-    WebappsHelper.init();
     UserAgentOverrides.init();
     CaptivePortalLoginHelper.init();
 
     this.contentBrowser.src = homeURL;
+
     this._isEventListenerReady = false;
 
     window.performance.mark('gecko-shell-system-frame-set');
 
     ppmm.addMessageListener("content-handler", this);
     ppmm.addMessageListener("dial-handler", this);
     ppmm.addMessageListener("sms-handler", this);
     ppmm.addMessageListener("mail-handler", this);
@@ -776,25 +775,16 @@ var shell = {
   }
 };
 
 Services.obs.addObserver(function onFullscreenOriginChange(subject, topic, data) {
   shell.sendChromeEvent({ type: "fullscreenoriginchange",
                           fullscreenorigin: data });
 }, "fullscreen-origin-change", false);
 
-DOMApplicationRegistry.registryReady.then(function () {
-  // This event should be sent before System app returns with
-  // system-message-listener-ready mozContentEvent, because it's on
-  // the critical launch path of the app.
-  SystemAppProxy._sendCustomEvent('mozChromeEvent', {
-    type: 'webapps-registry-ready'
-  }, /* noPending */ true);
-});
-
 Services.obs.addObserver(function onBluetoothVolumeChange(subject, topic, data) {
   shell.sendChromeEvent({
     type: "bluetooth-volumeset",
     value: data
   });
 }, 'bluetooth-volume-change', false);
 
 Services.obs.addObserver(function(subject, topic, data) {
@@ -821,22 +811,16 @@ var CustomEventManager = {
     }).bind(this), false);
   },
 
   handleEvent: function custevt_handleEvent(evt) {
     let detail = evt.detail;
     dump('XXX FIXME : Got a mozContentEvent: ' + detail.type + "\n");
 
     switch(detail.type) {
-      case 'webapps-install-granted':
-      case 'webapps-install-denied':
-      case 'webapps-uninstall-granted':
-      case 'webapps-uninstall-denied':
-        WebappsHelper.handleEvent(detail);
-        break;
       case 'system-message-listener-ready':
         Services.obs.notifyObservers(null, 'system-message-listener-ready', null);
         break;
       case 'captive-portal-login-cancel':
         CaptivePortalLoginHelper.handleEvent(detail);
         break;
       case 'inputmethod-update-layouts':
       case 'inputregistry-add':
@@ -885,102 +869,16 @@ var CustomEventManager = {
         break;
       case 'restart':
         restart();
         break;
     }
   }
 }
 
-var WebappsHelper = {
-  _installers: {},
-  _count: 0,
-
-  init: function webapps_init() {
-    Services.obs.addObserver(this, "webapps-launch", false);
-    Services.obs.addObserver(this, "webapps-ask-install", false);
-    Services.obs.addObserver(this, "webapps-ask-uninstall", false);
-    Services.obs.addObserver(this, "webapps-close", false);
-  },
-
-  registerInstaller: function webapps_registerInstaller(data) {
-    let id = "installer" + this._count++;
-    this._installers[id] = data;
-    return id;
-  },
-
-  handleEvent: function webapps_handleEvent(detail) {
-    if (!detail || !detail.id)
-      return;
-
-    let installer = this._installers[detail.id];
-    delete this._installers[detail.id];
-    switch (detail.type) {
-      case "webapps-install-granted":
-        DOMApplicationRegistry.confirmInstall(installer);
-        break;
-      case "webapps-install-denied":
-        DOMApplicationRegistry.denyInstall(installer);
-        break;
-      case "webapps-uninstall-granted":
-        DOMApplicationRegistry.confirmUninstall(installer);
-        break;
-      case "webapps-uninstall-denied":
-        DOMApplicationRegistry.denyUninstall(installer);
-        break;
-    }
-  },
-
-  observe: function webapps_observe(subject, topic, data) {
-    let json = JSON.parse(data);
-    json.mm = subject;
-
-    let id;
-
-    switch(topic) {
-      case "webapps-launch":
-        DOMApplicationRegistry.getManifestFor(json.manifestURL).then((aManifest) => {
-          if (!aManifest)
-            return;
-
-          let manifest = new ManifestHelper(aManifest, json.origin,
-                                            json.manifestURL);
-          let payload = {
-            timestamp: json.timestamp,
-            url: manifest.fullLaunchPath(json.startPoint),
-            manifestURL: json.manifestURL
-          };
-          shell.sendCustomEvent("webapps-launch", payload);
-        });
-        break;
-      case "webapps-ask-install":
-        id = this.registerInstaller(json);
-        shell.sendChromeEvent({
-          type: "webapps-ask-install",
-          id: id,
-          app: json.app
-        });
-        break;
-      case "webapps-ask-uninstall":
-        id = this.registerInstaller(json);
-        shell.sendChromeEvent({
-          type: "webapps-ask-uninstall",
-          id: id,
-          app: json.app
-        });
-        break;
-      case "webapps-close":
-        shell.sendCustomEvent("webapps-close", {
-          "manifestURL": json.manifestURL
-        });
-        break;
-    }
-  }
-}
-
 var KeyboardHelper = {
   handleEvent: function keyboard_handleEvent(detail) {
     switch (detail.type) {
       case 'inputmethod-update-layouts':
         Keyboard.setLayouts(detail.layouts);
 
         break;
       case 'inputregistry-add':
--- a/b2g/components/Bootstraper.jsm
+++ b/b2g/components/Bootstraper.jsm
@@ -7,17 +7,16 @@
 this.EXPORTED_SYMBOLS = ["Bootstraper"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 const CC = Components.Constructor;
 
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Webapps.jsm");
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 
 function debug(aMsg) {
   //dump("-*- Bootstraper: " + aMsg + "\n");
 }
 
 /**
   * This module loads the manifest for app from the --start-url enpoint and
@@ -54,17 +53,17 @@ this.Bootstraper = {
           manifestHash: AppsUtils.computeHash(JSON.stringify(aManifest)),
           appStatus: Ci.nsIPrincipal.APP_STATUS_CERTIFIED
         },
         appId: 1,
         isBrowser: false,
         isPackage: false
       };
 
-      DOMApplicationRegistry.confirmInstall(appData, null, aResolve);
+      //DOMApplicationRegistry.confirmInstall(appData, null, aResolve);
     });
   },
 
   /**
     * Resolves to a json manifest.
     */
   loadManifest: function() {
     return new Promise((aResolve, aReject) => {
@@ -97,16 +96,19 @@ this.Bootstraper = {
     return Promise.resolve();
   },
 
   /**
     * If a system app is already installed, uninstall it so that we can
     * cleanly replace it by the current one.
     */
   uninstallPreviousSystemApp: function() {
+    // TODO: FIXME
+    return Promise.resolve();
+
     let oldManifestURL;
     try{
       oldManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url");
     } catch(e) {
       // No preference set, so nothing to uninstall.
       return Promise.resolve();
     }
 
@@ -138,18 +140,17 @@ this.Bootstraper = {
     debug("Installing app from " + this._manifestURL);
 
     if (!this.isInstallRequired(this._manifestURL)) {
       debug("Already configured for " + this._manifestURL);
       return Promise.resolve();
     }
 
     return new Promise((aResolve, aReject) => {
-      DOMApplicationRegistry.registryReady
-          .then(this.uninstallPreviousSystemApp.bind(this))
+      this.uninstallPreviousSystemApp.bind(this)
           .then(this.loadManifest.bind(this))
           .then(this.installSystemApp.bind(this))
           .then(this.configure.bind(this))
           .then(aResolve)
           .catch(aReject);
     });
   }
 };
new file mode 100644
--- /dev/null
+++ b/b2g/components/GaiaChrome.cpp
@@ -0,0 +1,188 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "GaiaChrome.h"
+
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsChromeRegistry.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsLocalFile.h"
+#include "nsXULAppAPI.h"
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/ModuleUtils.h"
+#include "mozilla/Services.h"
+#include "mozilla/FileLocation.h"
+
+#define NS_GAIACHROME_CID \
+  { 0x83f8f999, 0x6b87, 0x4dd8, { 0xa0, 0x93, 0x72, 0x0b, 0xfb, 0x67, 0x4d, 0x38 } }
+
+using namespace mozilla;
+
+StaticRefPtr<GaiaChrome> gGaiaChrome;
+
+NS_IMPL_ISUPPORTS(GaiaChrome, nsIGaiaChrome)
+
+GaiaChrome::GaiaChrome()
+  : mPackageName(NS_LITERAL_CSTRING("gaia"))
+  , mAppsDir(NS_LITERAL_STRING("apps"))
+  , mDataRoot(NS_LITERAL_STRING("/data/local"))
+  , mSystemRoot(NS_LITERAL_STRING("/system/b2g"))
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  GetProfileDir();
+  Register();
+}
+
+//virtual
+GaiaChrome::~GaiaChrome()
+{
+}
+
+nsresult
+GaiaChrome::GetProfileDir()
+{
+  nsCOMPtr<nsIFile> profDir;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+                                       getter_AddRefs(profDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = profDir->Clone(getter_AddRefs(mProfDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+GaiaChrome::ComputeAppsPath(nsIFile* aPath)
+{
+#if defined(MOZ_MULET)
+  aPath->InitWithFile(mProfDir);
+#elif defined(MOZ_WIDGET_GONK)
+  nsCOMPtr<nsIFile> locationDetection = new nsLocalFile();
+  locationDetection->InitWithPath(mSystemRoot);
+  locationDetection->Append(mAppsDir);
+  bool appsInSystem = EnsureIsDirectory(locationDetection);
+  locationDetection->InitWithPath(mDataRoot);
+  locationDetection->Append(mAppsDir);
+  bool appsInData = EnsureIsDirectory(locationDetection);
+
+  if (!appsInData && !appsInSystem) {
+    printf_stderr("!!! NO root directory with apps found\n");
+    MOZ_ASSERT(false);
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  aPath->InitWithPath(appsInData ? mDataRoot : mSystemRoot);
+#else
+  return NS_ERROR_UNEXPECTED;
+#endif
+
+  aPath->Append(mAppsDir);
+  aPath->Append(NS_LITERAL_STRING("."));
+
+  nsresult rv = EnsureValidPath(aPath);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+bool
+GaiaChrome::EnsureIsDirectory(nsIFile* aPath)
+{
+  bool isDir = false;
+  aPath->IsDirectory(&isDir);
+  return isDir;
+}
+
+nsresult
+GaiaChrome::EnsureValidPath(nsIFile* appsDir)
+{
+  // Ensure there is a valid "apps/system" directory
+  nsCOMPtr<nsIFile> systemAppDir = new nsLocalFile();
+  systemAppDir->InitWithFile(appsDir);
+  systemAppDir->Append(NS_LITERAL_STRING("system"));
+
+  bool hasSystemAppDir = EnsureIsDirectory(systemAppDir);
+  if (!hasSystemAppDir) {
+    nsCString path; appsDir->GetNativePath(path);
+    // We don't want to continue if the apps path does not exists ...
+    printf_stderr("!!! Gaia chrome package is not a directory: %s\n", path.get());
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+GaiaChrome::Register()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(nsChromeRegistry::gChromeRegistry != nullptr);
+
+  nsCOMPtr<nsIFile> aPath = new nsLocalFile();
+  nsresult rv = ComputeAppsPath(aPath);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  FileLocation appsLocation(aPath);
+  nsCString uri;
+  appsLocation.GetURIString(uri);
+
+  char* argv[2];
+  argv[0] = (char*)mPackageName.get();
+  argv[1] = (char*)uri.get();
+
+  nsChromeRegistry::ManifestProcessingContext cx(NS_APP_LOCATION, appsLocation);
+  nsChromeRegistry::gChromeRegistry->ManifestContent(cx, 0, argv, 0);
+
+  return NS_OK;
+}
+
+already_AddRefed<GaiaChrome>
+GaiaChrome::FactoryCreate()
+{
+  if (!XRE_IsParentProcess()) {
+    return nullptr;
+  }
+
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!gGaiaChrome) {
+    gGaiaChrome = new GaiaChrome();
+    ClearOnShutdown(&gGaiaChrome);
+  }
+
+  RefPtr<GaiaChrome> service = gGaiaChrome.get();
+  return service.forget();
+}
+
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(GaiaChrome,
+                                         GaiaChrome::FactoryCreate)
+
+NS_DEFINE_NAMED_CID(NS_GAIACHROME_CID);
+
+static const mozilla::Module::CIDEntry kGaiaChromeCIDs[] = {
+  { &kNS_GAIACHROME_CID, false, nullptr, GaiaChromeConstructor },
+  { nullptr }
+};
+
+static const mozilla::Module::ContractIDEntry kGaiaChromeContracts[] = {
+  { "@mozilla.org/b2g/gaia-chrome;1", &kNS_GAIACHROME_CID },
+  { nullptr }
+};
+
+static const mozilla::Module::CategoryEntry kGaiaChromeCategories[] = {
+  { "profile-after-change", "Gaia Chrome Registration", GAIACHROME_CONTRACTID },
+  { nullptr }
+};
+
+static const mozilla::Module kGaiaChromeModule = {
+  mozilla::Module::kVersion,
+  kGaiaChromeCIDs,
+  kGaiaChromeContracts,
+  kGaiaChromeCategories
+};
+
+NSMODULE_DEFN(GaiaChromeModule) = &kGaiaChromeModule;
new file mode 100644
--- /dev/null
+++ b/b2g/components/GaiaChrome.h
@@ -0,0 +1,44 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef __GAIACHROME_H__
+#define __GAIACHROME_H__
+
+#include "nsIGaiaChrome.h"
+
+#include "nsIFile.h"
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+using namespace mozilla;
+
+class GaiaChrome final : public nsIGaiaChrome
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIGAIACHROME
+
+  static already_AddRefed<GaiaChrome>
+  FactoryCreate();
+
+private:
+  nsCString mPackageName;
+
+  nsAutoString mAppsDir;
+  nsAutoString mDataRoot;
+  nsAutoString mSystemRoot;
+
+  nsCOMPtr<nsIFile> mProfDir;
+
+  GaiaChrome();
+  ~GaiaChrome();
+
+  nsresult ComputeAppsPath(nsIFile*);
+  bool EnsureIsDirectory(nsIFile*);
+  nsresult EnsureValidPath(nsIFile*);
+  nsresult GetProfileDir();
+};
+
+#endif  // __GAIACHROME_H__
--- a/b2g/components/SafeMode.jsm
+++ b/b2g/components/SafeMode.jsm
@@ -5,17 +5,16 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["SafeMode"];
 
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/AppConstants.jsm");
-Cu.import("resource://gre/modules/Webapps.jsm");
 
 const kSafeModePref = "b2g.safe_mode";
 const kSafeModePage = "safe_mode.html";
 
 function debug(aStr) {
   //dump("-*- SafeMode: " + aStr + "\n");
 }
 
@@ -63,81 +62,80 @@ this.SafeMode = {
     let isSafeMode = Services.prefs.getCharPref(kSafeModePref) === "yes";
     if (!isSafeMode) {
       return Promise.resolve();
     }
     debug("Starting in Safe Mode!");
 
     // Load $system_app/safe_mode.html as a full screen iframe, and wait for
     // the user to make a choice.
-    return DOMApplicationRegistry.registryReady.then(() => {
-      let shell = SafeMode.window.shell;
-      let document = SafeMode.window.document;
-      SafeMode.window.screen.mozLockOrientation("portrait");
+    let shell = SafeMode.window.shell;
+    let document = SafeMode.window.document;
+    SafeMode.window.screen.mozLockOrientation("portrait");
+
+    let url = Services.io.newURI(shell.homeURL, null, null)
+                         .resolve(kSafeModePage);
+    debug("Registry is ready, loading " + url);
+    let frame = document.createElementNS("http://www.w3.org/1999/xhtml", "html:iframe");
+    frame.setAttribute("mozbrowser", "true");
+    frame.setAttribute("mozapp", shell.manifestURL);
+    frame.setAttribute("id", "systemapp"); // To keep screen.js happy.
+    let contentBrowser = document.body.appendChild(frame);
 
-      let url = Services.io.newURI(shell.homeURL, null, null)
-                           .resolve(kSafeModePage);
-      debug("Registry is ready, loading " + url);
-      let frame = document.createElementNS("http://www.w3.org/1999/xhtml", "html:iframe");
-      frame.setAttribute("mozbrowser", "true");
-      frame.setAttribute("mozapp", shell.manifestURL);
-      frame.setAttribute("id", "systemapp"); // To keep screen.js happy.
-      let contentBrowser = document.body.appendChild(frame);
+    return new Promise((aResolve, aReject) => {
+      let content = contentBrowser.contentWindow;
 
-      return new Promise((aResolve, aReject) => {
-        let content = contentBrowser.contentWindow;
-
-        // Stripped down version of the system app bootstrap.
-        function handleEvent(e) {
-          switch(e.type) {
-            case "mozbrowserloadstart":
-              if (content.document.location == "about:blank") {
-                contentBrowser.addEventListener("mozbrowserlocationchange", handleEvent, true);
-                contentBrowser.removeEventListener("mozbrowserloadstart", handleEvent, true);
-                return;
-              }
+      // Stripped down version of the system app bootstrap.
+      function handleEvent(e) {
+        switch(e.type) {
+          case "mozbrowserloadstart":
+            if (content.document.location == "about:blank") {
+              contentBrowser.addEventListener("mozbrowserlocationchange", handleEvent, true);
+              contentBrowser.removeEventListener("mozbrowserloadstart", handleEvent, true);
+              return;
+            }
 
-              notifyContentStart();
-              break;
-            case "mozbrowserlocationchange":
-              if (content.document.location == "about:blank") {
-                return;
-              }
+            notifyContentStart();
+            break;
+          case "mozbrowserlocationchange":
+            if (content.document.location == "about:blank") {
+              return;
+            }
 
-              contentBrowser.removeEventListener("mozbrowserlocationchange", handleEvent, true);
-              notifyContentStart();
-              break;
-            case "mozContentEvent":
-              content.removeEventListener("mozContentEvent", handleEvent, true);
-              contentBrowser.parentNode.removeChild(contentBrowser);
+            contentBrowser.removeEventListener("mozbrowserlocationchange", handleEvent, true);
+            notifyContentStart();
+            break;
+          case "mozContentEvent":
+            content.removeEventListener("mozContentEvent", handleEvent, true);
+            contentBrowser.parentNode.removeChild(contentBrowser);
 
-              if (e.detail == "safemode-yes")  {
-                // Really starting in safe mode, let's disable add-ons first.
-                DOMApplicationRegistry.disableAllAddons().then(aResolve);
-              } else {
-                aResolve();
-              }
-              break;
-          }
+            if (e.detail == "safemode-yes")  {
+              // Really starting in safe mode, let's disable add-ons first.
+              // TODO: disable add-ons
+              aResolve();
+            } else {
+              aResolve();
+            }
+            break;
         }
+      }
 
-        function notifyContentStart() {
-          let window = SafeMode.window;
-          window.shell.sendEvent(window, "SafeModeStart");
-          contentBrowser.setVisible(true);
+      function notifyContentStart() {
+        let window = SafeMode.window;
+        window.shell.sendEvent(window, "SafeModeStart");
+        contentBrowser.setVisible(true);
 
-          // browser-ui-startup-complete is used by the AppShell to stop the
-          // boot animation and start gecko rendering.
-          Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
-          content.addEventListener("mozContentEvent", handleEvent, true);
-        }
+        // browser-ui-startup-complete is used by the AppShell to stop the
+        // boot animation and start gecko rendering.
+        Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
+        content.addEventListener("mozContentEvent", handleEvent, true);
+      }
 
-        contentBrowser.addEventListener("mozbrowserloadstart", handleEvent, true);
-        contentBrowser.src = url;
-      });
+      contentBrowser.addEventListener("mozbrowserloadstart", handleEvent, true);
+      contentBrowser.src = url;
     });
   },
 
   // Returns a Promise that resolves once we have decided to run in safe mode
   // or not. All the safe mode switching actions happen before resolving the
   // promise.
   check: function(aWindow) {
     debug("check");
--- a/b2g/components/moz.build
+++ b/b2g/components/moz.build
@@ -74,12 +74,23 @@ EXTRA_JS_MODULES += [
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
     EXTRA_JS_MODULES += [
       'GlobalSimulatorScreen.jsm'
     ]
 
 XPIDL_SOURCES += [
+    'nsIGaiaChrome.idl',
     'nsISystemMessagesInternal.idl'
 ]
 
 XPIDL_MODULE = 'gaia_chrome'
+
+UNIFIED_SOURCES += [
+    'GaiaChrome.cpp'
+]
+
+LOCAL_INCLUDES += [
+    '/chrome'
+]
+
+FINAL_LIBRARY = 'xul'
new file mode 100644
--- /dev/null
+++ b/b2g/components/nsIGaiaChrome.idl
@@ -0,0 +1,15 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(92a18a98-ab5d-4d02-a024-bdbb3bc89ce1)]
+interface nsIGaiaChrome : nsISupports
+{
+    void register();
+};
+
+%{ C++
+#define GAIACHROME_CONTRACTID "@mozilla.org/b2g/gaia-chrome;1"
+%}
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -226,16 +226,17 @@
 @RESPATH@/components/exthelper.xpt
 @RESPATH@/components/fastfind.xpt
 @RESPATH@/components/feeds.xpt
 #ifdef MOZ_GTK
 @RESPATH@/components/filepicker.xpt
 #endif
 @RESPATH@/components/find.xpt
 @RESPATH@/components/gfx.xpt
+@RESPATH@/components/gaia_chrome.xpt
 @RESPATH@/components/hal.xpt
 @RESPATH@/components/html5.xpt
 @RESPATH@/components/htmlparser.xpt
 @RESPATH@/components/identity.xpt
 @RESPATH@/components/imglib2.xpt
 @RESPATH@/components/inspector.xpt
 @RESPATH@/components/intl.xpt
 @RESPATH@/components/jar.xpt
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -909,16 +909,40 @@ function RedirectLoad({ target: browser,
       }
     };
     Services.obs.addObserver(delayedStartupFinished,
                              "browser-delayed-startup-finished",
                              false);
   }
 }
 
+addEventListener("DOMContentLoaded", function onDCL() {
+  removeEventListener("DOMContentLoaded", onDCL);
+
+  // There are some windows, like macBrowserOverlay.xul, that
+  // load browser.js, but never load tabbrowser.xml. We can ignore
+  // those cases.
+  if (!gBrowser || !gBrowser.updateBrowserRemoteness) {
+    return;
+  }
+
+  window.QueryInterface(Ci.nsIInterfaceRequestor)
+        .getInterface(nsIWebNavigation)
+        .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner
+        .QueryInterface(Ci.nsIInterfaceRequestor)
+        .getInterface(Ci.nsIXULWindow)
+        .XULBrowserWindow = window.XULBrowserWindow;
+  window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow =
+    new nsBrowserAccess();
+
+  let initBrowser =
+    document.getAnonymousElementByAttribute(gBrowser, "anonid", "initialBrowser");
+  gBrowser.updateBrowserRemoteness(initBrowser, gMultiProcessBrowser);
+});
+
 var gBrowserInit = {
   delayedStartupFinished: false,
 
   onLoad: function() {
     gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver, false);
 
     Services.obs.addObserver(gPluginHandler.NPAPIPluginCrashed, "plugin-crashed", false);
 
@@ -939,29 +963,21 @@ var gBrowserInit = {
     RefreshBlocker.init();
 
     let mm = window.getGroupMessageManager("browsers");
     mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
     mm.loadFrameScript("chrome://browser/content/content.js", true);
     mm.loadFrameScript("chrome://browser/content/content-UITour.js", true);
     mm.loadFrameScript("chrome://global/content/manifestMessages.js", true);
 
-    window.messageManager.addMessageListener("Browser:LoadURI", RedirectLoad);
-
     // initialize observers and listeners
     // and give C++ access to gBrowser
     XULBrowserWindow.init();
-    window.QueryInterface(Ci.nsIInterfaceRequestor)
-          .getInterface(nsIWebNavigation)
-          .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner
-          .QueryInterface(Ci.nsIInterfaceRequestor)
-          .getInterface(Ci.nsIXULWindow)
-          .XULBrowserWindow = window.XULBrowserWindow;
-    window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow =
-      new nsBrowserAccess();
+
+    window.messageManager.addMessageListener("Browser:LoadURI", RedirectLoad);
 
     if (!gMultiProcessBrowser) {
       // There is a Content:Click message manually sent from content.
       Cc["@mozilla.org/eventlistenerservice;1"]
         .getService(Ci.nsIEventListenerService)
         .addSystemEventListener(gBrowser, "click", contentAreaClick, true);
     }
 
@@ -1098,33 +1114,38 @@ var gBrowserInit = {
           window.arguments[0] = null;
         }
 
         // Stop the about:blank load
         gBrowser.stop();
         // make sure it has a docshell
         gBrowser.docShell;
 
+        // We must set usercontextid before updateBrowserRemoteness()
+        // so that the newly created remote tab child has correct usercontextid
+        if (tabToOpen.hasAttribute("usercontextid")) {
+          let usercontextid = tabToOpen.getAttribute("usercontextid");
+          gBrowser.selectedBrowser.setAttribute("usercontextid", usercontextid);
+        }
+
         // If the browser that we're swapping in was remote, then we'd better
         // be able to support remote browsers, and then make our selectedTab
         // remote.
         try {
           if (tabToOpen.linkedBrowser.isRemoteBrowser) {
             if (!gMultiProcessBrowser) {
               throw new Error("Cannot drag a remote browser into a window " +
                               "without the remote tabs load context.");
             }
-
-            // We must set usercontextid before updateBrowserRemoteness()
-            // so that the newly created remote tab child has correct usercontextid
-            if (tabToOpen.hasAttribute("usercontextid")) {
-              let usercontextid = tabToOpen.getAttribute("usercontextid");
-              gBrowser.selectedBrowser.setAttribute("usercontextid", usercontextid);
-            }
             gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser, true);
+          } else if (gBrowser.selectedBrowser.isRemoteBrowser) {
+            // If the browser is remote, then it's implied that
+            // gMultiProcessBrowser is true. We need to flip the remoteness
+            // of this tab to false in order for the tab drag to work.
+            gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser, false);
           }
           gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
         } catch(e) {
           Cu.reportError(e);
         }
       }
       // window.arguments[2]: referrer (nsIURI | string)
       //                 [3]: postData (nsIInputStream)
@@ -4193,20 +4214,25 @@ var XULBrowserWindow = {
 
   setJSStatus: function () {
     // unsupported
   },
 
   forceInitialBrowserRemote: function() {
     let initBrowser =
       document.getAnonymousElementByAttribute(gBrowser, "anonid", "initialBrowser");
-    gBrowser.updateBrowserRemoteness(initBrowser, true);
     return initBrowser.frameLoader.tabParent;
   },
 
+  forceInitialBrowserNonRemote: function() {
+    let initBrowser =
+      document.getAnonymousElementByAttribute(gBrowser, "anonid", "initialBrowser");
+    gBrowser.updateBrowserRemoteness(initBrowser, false);
+  },
+
   setDefaultStatus: function (status) {
     this.defaultStatus = status;
     this.updateStatusField();
   },
 
   setOverLink: function (url, anchorElt) {
     // Encode bidirectional formatting characters.
     // (RFC 3987 sections 3.2 and 4.1 paragraph 6)
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -660,22 +660,16 @@
 #ifdef XP_MACOSX
       <hbox class="titlebar-placeholder" type="fullscreen-button"
             id="titlebar-placeholder-on-TabsToolbar-for-fullscreen-button" persist="width"
             skipintoolbarset="true"/>
 #endif
 #endif
     </toolbar>
 
-    <!--
-           CAVEAT EMPTOR
-           Should you need to add items to the toolbar here, make sure to also add them
-           to the default placements of buttons in CustomizableUI.jsm, so the
-           customization code doesn't get confused.
-      -->
     <toolbar id="nav-bar"
              aria-label="&navbarCmd.label;"
              fullscreentoolbar="true" mode="icons" customizable="true"
              iconsize="small"
              customizationtarget="nav-bar-customization-target"
              overflowable="true"
              overflowbutton="nav-bar-overflow-button"
              overflowtarget="widget-overflow-list"
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -274,16 +274,17 @@ tags = mcb
 [browser_bug1015721.js]
 skip-if = os == 'win'
 [browser_bug1064280_changeUrlInPinnedTab.js]
 [browser_accesskeys.js]
 [browser_clipboard.js]
 subsuite = clipboard
 [browser_clipboard_pastefile.js]
 [browser_contentAreaClick.js]
+skip-if = e10s # Clicks in content don't go through contentAreaClick with e10s.
 [browser_contextmenu.js]
 subsuite = clipboard
 tags = fullscreen
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [browser_contextmenu_input.js]
 skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
 [browser_ctrlTab.js]
 [browser_datachoices_notification.js]
--- a/browser/base/content/test/general/browser_bug495058.js
+++ b/browser/base/content/test/general/browser_bug495058.js
@@ -10,41 +10,29 @@ const URIS = [
 ];
 
 add_task(function*() {
   for (let uri of URIS) {
     let tab = gBrowser.addTab();
     yield BrowserTestUtils.loadURI(tab.linkedBrowser, uri);
 
     let win = gBrowser.replaceTabWithWindow(tab);
-    yield BrowserTestUtils.waitForEvent(win, "load");
-
+    yield TestUtils.topicObserved("browser-delayed-startup-finished",
+                                  subject => subject == win);
     tab = win.gBrowser.selectedTab;
 
-    // By default, we'll wait for MozAfterPaint to come up through the
-    // browser element. We'll handle the e10s case in the next block.
-    let contentPainted = BrowserTestUtils.waitForEvent(tab.linkedBrowser,
-                                                       "MozAfterPaint");
-
-    let delayedStartup =
-      TestUtils.topicObserved("browser-delayed-startup-finished",
-                              subject => subject == win);
-
-    if (gMultiProcessBrowser &&
-        E10SUtils.canLoadURIInProcess(uri, Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT)) {
-      // Until bug 1261842 is fixed, the initial browser is going to be
-      // non-remote. If we're transitioning to a URL that can be loaded
-      // remotely, we'll need to wait until that remoteness switch is done
-      // before we send any framescripts down to the browser.
-      yield BrowserTestUtils.waitForEvent(tab, "TabRemotenessChange");
-      contentPainted = BrowserTestUtils.contentPainted(tab.linkedBrowser);
+    // BrowserTestUtils doesn't get the add-on shims, which means that
+    // MozAfterPaint won't get shimmed over if we add an event handler
+    // for it in the parent.
+    if (tab.linkedBrowser.isRemoteBrowser) {
+      yield BrowserTestUtils.waitForContentEvent(tab.linkedBrowser, "MozAfterPaint");
+    } else {
+      yield BrowserTestUtils.waitForEvent(tab.linkedBrowser, "MozAfterPaint");
     }
 
-    yield Promise.all([delayedStartup, contentPainted]);
-
     Assert.equal(win.gBrowser.currentURI.spec, uri, uri + ": uri loaded in detached tab");
     Assert.equal(win.document.activeElement, win.gBrowser.selectedBrowser, uri + ": browser is focused");
     Assert.equal(win.gURLBar.value, "", uri + ": urlbar is empty");
     Assert.ok(win.gURLBar.placeholder, uri + ": placeholder text is present");
 
     yield BrowserTestUtils.closeWindow(win);
   }
 });
--- a/browser/base/content/test/general/browser_testOpenNewRemoteTabsFromNonRemoteBrowsers.js
+++ b/browser/base/content/test/general/browser_testOpenNewRemoteTabsFromNonRemoteBrowsers.js
@@ -33,23 +33,23 @@ registerCleanupFunction(() => {
   Services.prefs.clearUserPref(OPEN_LOCATION_PREF);
 });
 
 /**
  * Test that if we open a new tab from a link in a non-remote
  * browser in an e10s window, that the new tab will load properly.
  */
 add_task(function* test_new_tab() {
-  let normalWindow = yield promiseOpenAndLoadWindow({
-    remote: true
-  }, true);
-  let privateWindow = yield promiseOpenAndLoadWindow({
+  let normalWindow = yield BrowserTestUtils.openNewBrowserWindow({
+    remote: true,
+  });
+  let privateWindow = yield BrowserTestUtils.openNewBrowserWindow({
     remote: true,
     private: true,
-  }, true);
+  });
 
   for (let testWindow of [normalWindow, privateWindow]) {
     yield promiseWaitForFocus(testWindow);
     let testBrowser = testWindow.gBrowser.selectedBrowser;
     info("Preparing non-remote browser");
     yield prepareNonRemoteBrowser(testWindow, testBrowser);
     info("Non-remote browser prepared - sending frame script");
 
@@ -75,20 +75,20 @@ add_task(function* test_new_tab() {
 });
 
 /**
  * Test that if we open a new window from a link in a non-remote
  * browser in an e10s window, that the new window is not an e10s
  * window. Also tests with a private browsing window.
  */
 add_task(function* test_new_window() {
-  let normalWindow = yield promiseOpenAndLoadWindow({
+  let normalWindow = yield BrowserTestUtils.openNewBrowserWindow({
     remote: true
   }, true);
-  let privateWindow = yield promiseOpenAndLoadWindow({
+  let privateWindow = yield BrowserTestUtils.openNewBrowserWindow({
     remote: true,
     private: true,
   }, true);
 
   // Fiddle with the prefs so that we open target="_blank" links
   // in new windows instead of new tabs.
   Services.prefs.setIntPref(OPEN_LOCATION_PREF,
                             Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW);
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -721,46 +721,48 @@ var CustomizableUIInternal = {
         }
 
         let [provider, node] = this.getWidgetNode(id, window);
         if (!node) {
           log.debug("Unknown widget: " + id);
           continue;
         }
 
+        let widget = null;
         // If the placements have items in them which are (now) no longer removable,
         // we shouldn't be moving them:
         if (provider == CustomizableUI.PROVIDER_API) {
-          let widgetInfo = gPalette.get(id);
-          if (!widgetInfo.removable && aArea != widgetInfo.defaultArea) {
+          widget = gPalette.get(id);
+          if (!widget.removable && aArea != widget.defaultArea) {
             placementsToRemove.add(id);
             continue;
           }
         } else if (provider == CustomizableUI.PROVIDER_XUL &&
                    node.parentNode != container && !this.isWidgetRemovable(node)) {
           placementsToRemove.add(id);
           continue;
         } // Special widgets are always removable, so no need to check them
 
-        if (inPrivateWindow && provider == CustomizableUI.PROVIDER_API) {
-          let widget = gPalette.get(id);
-          if (!widget.showInPrivateBrowsing && inPrivateWindow) {
-            continue;
-          }
+        if (inPrivateWindow && widget && !widget.showInPrivateBrowsing) {
+          continue;
         }
 
         this.ensureButtonContextMenu(node, aAreaNode);
         if (node.localName == "toolbarbutton") {
           if (areaIsPanel) {
             node.setAttribute("wrap", "true");
           } else {
             node.removeAttribute("wrap");
           }
         }
 
+        // This needs updating in case we're resetting / undoing a reset.
+        if (widget) {
+          widget.currentArea = aArea;
+        }
         this.insertWidgetBefore(node, currentNode, container, aArea);
         if (gResetting) {
           this.notifyListeners("onWidgetReset", node, container);
         } else if (gUndoResetting) {
           this.notifyListeners("onWidgetUndoMove", node, container);
         }
       }
 
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -743,16 +743,23 @@ const CustomizableWidgets = [
 
         onWidgetReset: function(aWidgetNode) {
           if (aWidgetNode != node)
             return;
           updateCombinedWidgetStyle(node, this.currentArea, true);
           updateZoomResetButton();
         }.bind(this),
 
+        onWidgetUndoMove: function(aWidgetNode) {
+          if (aWidgetNode != node)
+            return;
+          updateCombinedWidgetStyle(node, this.currentArea, true);
+          updateZoomResetButton();
+        }.bind(this),
+
         onWidgetMoved: function(aWidgetId, aArea) {
           if (aWidgetId != this.id)
             return;
           updateCombinedWidgetStyle(node, aArea, true);
           updateZoomResetButton();
         }.bind(this),
 
         onWidgetInstanceRemoved: function(aWidgetId, aDoc) {
@@ -854,16 +861,22 @@ const CustomizableWidgets = [
         }.bind(this),
 
         onWidgetReset: function(aWidgetNode) {
           if (aWidgetNode != node)
             return;
           updateCombinedWidgetStyle(node, this.currentArea);
         }.bind(this),
 
+        onWidgetUndoMove: function(aWidgetNode) {
+          if (aWidgetNode != node)
+            return;
+          updateCombinedWidgetStyle(node, this.currentArea);
+        }.bind(this),
+
         onWidgetMoved: function(aWidgetId, aArea) {
           if (aWidgetId != this.id)
             return;
           updateCombinedWidgetStyle(node, aArea);
         }.bind(this),
 
         onWidgetInstanceRemoved: function(aWidgetId, aDoc) {
           if (aWidgetId != this.id || aDoc != aDocument)
--- a/browser/components/privatebrowsing/test/browser/browser.ini
+++ b/browser/components/privatebrowsing/test/browser/browser.ini
@@ -19,16 +19,17 @@ support-files =
 [browser_privatebrowsing_DownloadLastDirWithCPS.js]
 [browser_privatebrowsing_about.js]
 tags = trackingprotection
 [browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js]
 [browser_privatebrowsing_aboutSessionRestore.js]
 [browser_privatebrowsing_cache.js]
 [browser_privatebrowsing_certexceptionsui.js]
 [browser_privatebrowsing_concurrent.js]
+[browser_privatebrowsing_context_and_chromeFlags.js]
 [browser_privatebrowsing_crh.js]
 [browser_privatebrowsing_downloadLastDir.js]
 [browser_privatebrowsing_downloadLastDir_c.js]
 [browser_privatebrowsing_downloadLastDir_toggle.js]
 [browser_privatebrowsing_geoprompt.js]
 [browser_privatebrowsing_lastpbcontextexited.js]
 [browser_privatebrowsing_localStorage.js]
 [browser_privatebrowsing_localStorage_before_after.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_context_and_chromeFlags.js
@@ -0,0 +1,60 @@
+"use strict";
+
+/**
+ * Given some window in the parent process, ensure that
+ * the nsIXULWindow has the CHROME_PRIVATE_WINDOW chromeFlag,
+ * and that the usePrivateBrowsing property is set to true on
+ * both the window's nsILoadContext, as well as on the initial
+ * browser's content docShell nsILoadContext.
+ *
+ * @param win (nsIDOMWindow)
+ *        An nsIDOMWindow in the parent process.
+ * @return Promise
+ */
+function assertWindowIsPrivate(win) {
+  let winDocShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                       .getInterface(Ci.nsIDocShell);
+  let chromeFlags = winDocShell.QueryInterface(Ci.nsIDocShellTreeItem)
+                               .treeOwner
+                               .QueryInterface(Ci.nsIInterfaceRequestor)
+                               .getInterface(Ci.nsIXULWindow)
+                               .chromeFlags;
+
+  if (!win.gBrowser.selectedBrowser.hasContentOpener) {
+    Assert.ok(chromeFlags & Ci.nsIWebBrowserChrome.CHROME_PRIVATE_WINDOW,
+              "Should have the private window chrome flag");
+  }
+
+  let loadContext = winDocShell.QueryInterface(Ci.nsILoadContext);
+  Assert.ok(loadContext.usePrivateBrowsing,
+            "The parent window should be using private browsing");
+
+  return ContentTask.spawn(win.gBrowser.selectedBrowser, null, function*() {
+    let loadContext = docShell.QueryInterface(Ci.nsILoadContext);
+    Assert.ok(loadContext.usePrivateBrowsing,
+              "Content docShell should be using private browsing");
+  });
+}
+
+/**
+ * Tests that chromeFlags bits and the nsILoadContext.usePrivateBrowsing
+ * attribute are properly set when opening a new private browsing
+ * window.
+ */
+add_task(function* test_context_and_chromeFlags() {
+  let win = yield BrowserTestUtils.openNewBrowserWindow({ private: true });
+  yield assertWindowIsPrivate(win);
+
+  let browser = win.gBrowser.selectedBrowser;
+
+  let newWinPromise = BrowserTestUtils.waitForNewWindow();
+  yield ContentTask.spawn(browser, null, function*() {
+    content.open("http://example.com", "_blank", "width=100,height=100");
+  });
+
+  let win2 = yield newWinPromise;
+  yield assertWindowIsPrivate(win2);
+
+  yield BrowserTestUtils.closeWindow(win2);
+  yield BrowserTestUtils.closeWindow(win);
+});
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_downloadLastDir_toggle.js
@@ -1,97 +1,105 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/DownloadLastDir.jsm");
 
-function test() {
-  waitForExplicitFinish();
-
-  let FileUtils =
-    Cu.import("resource://gre/modules/FileUtils.jsm", {}).FileUtils;
-  let DownloadLastDir =
-    Cu.import("resource://gre/modules/DownloadLastDir.jsm", {}).DownloadLastDir;
-
+/**
+ * Tests how the browser remembers the last download folder
+ * from download to download, with a particular emphasis
+ * on how it behaves when private browsing windows open.
+ */
+add_task(function* test_downloads_last_dir_toggle() {
   let tmpDir = FileUtils.getDir("TmpD", [], true);
   let dir1 = newDirectory();
 
   registerCleanupFunction(function () {
     Services.prefs.clearUserPref("browser.download.lastDir");
     dir1.remove(true);
   });
 
-  function testOnWindow(aPrivate, aCallback) {
-    whenNewWindowLoaded({private: aPrivate}, function(win) {
-      let gDownloadLastDir = new DownloadLastDir(win);
-      aCallback(win, gDownloadLastDir);
-      gDownloadLastDir.cleanupPrivateFile();
-      win.close();
-    });
-  }
+  let win = yield BrowserTestUtils.openNewBrowserWindow();
+  let gDownloadLastDir = new DownloadLastDir(win);
+  is(typeof gDownloadLastDir, "object",
+     "gDownloadLastDir should be a valid object");
+  is(gDownloadLastDir.file, null,
+     "gDownloadLastDir.file should be null to start with");
 
-  function checkDownloadLastDirInit(aWin, gDownloadLastDir, aCallback) {
-    is(typeof gDownloadLastDir, "object",
-       "gDownloadLastDir should be a valid object");
-    is(gDownloadLastDir.file, null,
-       "gDownloadLastDir.file should be null to start with");
+  gDownloadLastDir.file = tmpDir;
+  is(gDownloadLastDir.file.path, tmpDir.path,
+     "LastDir should point to the temporary directory");
+  isnot(gDownloadLastDir.file, tmpDir,
+        "gDownloadLastDir.file should not be pointing to the tmpDir");
+
+  gDownloadLastDir.file = 1; // not an nsIFile
+  is(gDownloadLastDir.file, null, "gDownloadLastDir.file should be null");
 
-    gDownloadLastDir.file = tmpDir;
-    is(gDownloadLastDir.file.path, tmpDir.path,
-       "LastDir should point to the temporary directory");
-    isnot(gDownloadLastDir.file, tmpDir,
-          "gDownloadLastDir.file should not be pointing to the tmpDir");
+  gDownloadLastDir.file = tmpDir;
+  clearHistory();
+  is(gDownloadLastDir.file, null, "gDownloadLastDir.file should be null");
+
+  gDownloadLastDir.file = tmpDir;
+  yield BrowserTestUtils.closeWindow(win);
 
-    gDownloadLastDir.file = 1; // not an nsIFile
-    is(gDownloadLastDir.file, null, "gDownloadLastDir.file should be null");
-
-    gDownloadLastDir.file = tmpDir;
-    clearHistory();
-    is(gDownloadLastDir.file, null, "gDownloadLastDir.file should be null");
-
-    gDownloadLastDir.file = tmpDir;
-    aCallback();
-  }
+  info("Opening the first private window");
+  yield testHelper({ private: true, expectedDir: tmpDir });
+  info("Opening a non-private window");
+  yield testHelper({ private: false, expectedDir: tmpDir });
+  info("Opening a private window and setting download directory");
+  yield testHelper({ private: true, setDir: dir1, expectedDir: dir1 });
+  info("Opening a non-private window and checking download directory");
+  yield testHelper({ private: false, expectedDir: tmpDir });
+  info("Opening private window and clearing history");
+  yield testHelper({ private: true, clearHistory: true, expectedDir: null });
+  info("Opening a non-private window and checking download directory");
+  yield testHelper({ private: true, expectedDir: null });
+});
 
-  function checkDownloadLastDir(aWin, gDownloadLastDir, aLastDir, aUpdate, aCallback) {
-    if (aUpdate)
-      gDownloadLastDir.file = aLastDir;
-    is(gDownloadLastDir.file.path, aLastDir.path,
-       "gDownloadLastDir should point to the expected last directory");
-    isnot(gDownloadLastDir.file, aLastDir,
-          "gDownloadLastDir.file should not be pointing to the last directory");
-    aCallback();
-  }
-
-  function checkDownloadLastDirNull(aWin, gDownloadLastDir, aCallback) {
-    is(gDownloadLastDir.file, null, "gDownloadLastDir should be null");
-    aCallback();
-  }
+/**
+ * Opens a new window and performs some test actions on it based
+ * on the options object that have been passed in.
+ *
+ * @param options (Object)
+ *        An object with the following properties:
+ *
+ *        clearHistory (bool, optional):
+ *          Whether or not to simulate clearing session history.
+ *          Defaults to false.
+ *
+ *        setDir (nsIFile, optional):
+ *          An nsIFile for setting the last download directory.
+ *          If not set, the load download directory is not changed.
+ *
+ *        expectedDir (nsIFile, expectedDir):
+ *          An nsIFile for what we expect the last download directory
+ *          should be. The nsIFile is not compared directly - only
+ *          paths are compared. If expectedDir is not set, then the
+ *          last download directory is expected to be null.
+ *
+ * @returns Promise
+ */
+function testHelper(options) {
+  return new Task.spawn(function() {
+    let win = yield BrowserTestUtils.openNewBrowserWindow(options);
+    let gDownloadLastDir = new DownloadLastDir(win);
 
-  testOnWindow(false, function(win, downloadDir) {
-    checkDownloadLastDirInit(win, downloadDir, function() {
-      testOnWindow(true, function(win, downloadDir) {
-        checkDownloadLastDir(win, downloadDir, tmpDir, false, function() {
-          testOnWindow(false, function(win, downloadDir) {
-            checkDownloadLastDir(win, downloadDir, tmpDir, false, function() {
-              testOnWindow(true, function(win, downloadDir) {
-                checkDownloadLastDir(win, downloadDir, dir1, true, function() {
-                  testOnWindow(false, function(win, downloadDir) {
-                    checkDownloadLastDir(win, downloadDir, tmpDir, false, function() {
-                      testOnWindow(true, function(win, downloadDir) {
-                        clearHistory();
-                        checkDownloadLastDirNull(win, downloadDir, function() {
-                          testOnWindow(false, function(win, downloadDir) {
-                            checkDownloadLastDirNull(win, downloadDir, finish);
-                          });
-                        });
-                      });
-                    });
-                  });
-                });
-              });
-            });
-          });
-        });
-      });
-    });
+    if (options.clearHistory) {
+      clearHistory();
+    }
+
+    if (options.setDir) {
+      gDownloadLastDir.file = options.setDir;
+    }
+
+    let expectedDir = options.expectedDir;
+
+    if (expectedDir) {
+      is(gDownloadLastDir.file.path, expectedDir.path,
+         "gDownloadLastDir should point to the expected last directory");
+      isnot(gDownloadLastDir.file, expectedDir,
+            "gDownloadLastDir.file should not be pointing to the last directory");
+    } else {
+      is(gDownloadLastDir.file, null, "gDownloadLastDir should be null");
+    }
+
+    gDownloadLastDir.cleanupPrivateFile();
+    yield BrowserTestUtils.closeWindow(win);
   });
 }
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_noSessionRestoreMenuOption.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_noSessionRestoreMenuOption.js
@@ -1,34 +1,23 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// This test checks that the Session Restore menu option is not enabled in private mode
-
-function test() {
-  waitForExplicitFinish();
+"use strict";
 
-  function testNoSessionRestoreMenuItem() { 
-    let win = OpenBrowserWindow({private: true});
-    win.addEventListener("load", function onLoad() {
-      win.removeEventListener("load", onLoad, false);
-      ok(true, "The second private window got loaded");
-      let srCommand = win.document.getElementById("Browser:RestoreLastSession");
-      ok(srCommand, "The Session Restore command should exist");
-      is(PrivateBrowsingUtils.isWindowPrivate(win), true,
-         "PrivateBrowsingUtils should report the correct per-window private browsing status");
-      is(srCommand.hasAttribute("disabled"), true,
-         "The Session Restore command should be disabled in private browsing mode");
-      win.close();
-      finish();
-    }, false);
-  }
+/**
+ * Tests that if we open a tab within a private browsing window, and then
+ * close that private browsing window, that subsequent private browsing
+ * windows do not allow the command for restoring the last session.
+ */
+add_task(function* test_no_session_restore_menu_option() {
+  let win = yield BrowserTestUtils.openNewBrowserWindow({ private: true });
+  ok(true, "The first private window got loaded");
+  win.gBrowser.addTab("about:mozilla");
+  yield BrowserTestUtils.closeWindow(win);
 
-  let win = OpenBrowserWindow({private: true});
-  win.addEventListener("load", function onload() {
-    win.removeEventListener("load", onload, false);
-    ok(true, "The first private window got loaded");
-    win.gBrowser.addTab("about:mozilla");
-    win.close();
-    testNoSessionRestoreMenuItem();
-  }, false);
-}
+  win = yield BrowserTestUtils.openNewBrowserWindow({ private: true });
+  let srCommand = win.document.getElementById("Browser:RestoreLastSession");
+  ok(srCommand, "The Session Restore command should exist");
+  is(PrivateBrowsingUtils.isWindowPrivate(win), true,
+     "PrivateBrowsingUtils should report the correct per-window private browsing status");
+  is(srCommand.hasAttribute("disabled"), true,
+     "The Session Restore command should be disabled in private browsing mode");
+
+  yield BrowserTestUtils.closeWindow(win);
+});
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_nonbrowser.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_nonbrowser.js
@@ -1,34 +1,19 @@
-/* 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/. */
-
-function test() {
-  waitForExplicitFinish();
-
-  let windowsToClose = [];
-  registerCleanupFunction(function() {
-    windowsToClose.forEach(function(win) {
-      win.close();
-    });
-  });
+"use strict";
 
-  let win = OpenBrowserWindow({private: true});
-  win.addEventListener("load", function onLoad() {
-    win.removeEventListener("load", onLoad, false);
-    let chromeWin = win.open("chrome://browser/content/places/places.xul",
-      "_blank", "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
-    chromeWin.addEventListener("load", function chromeWinLoad() {
-      chromeWin.removeEventListener("load", chromeWinLoad, false);
-      win.close();
-    }, false);
-    windowsToClose.push(chromeWin);
-  }, false);
+/**
+ * Tests that we fire the last-pb-context-exited observer notification
+ * when the last private browsing window closes, even if a chrome window
+ * was opened from that private browsing window.
+ */
+add_task(function* () {
+  let win = yield BrowserTestUtils.openNewBrowserWindow({private: true});
+  let chromeWin = win.open("chrome://browser/content/places/places.xul", "_blank",
+    "chrome,extrachrome,menubar,resizable,scrollbars,status,toolbar");
+  yield BrowserTestUtils.waitForEvent(chromeWin, "load");
+  let obsPromise = TestUtils.topicObserved("last-pb-context-exited");
+  yield BrowserTestUtils.closeWindow(win);
+  yield obsPromise;
+  Assert.ok(true, "Got the last-pb-context-exited notification");
+  chromeWin.close();
+});
 
-  let observer = function() {
-    is(true, true, "observer fired");
-    Services.obs.removeObserver(observer, "last-pb-context-exited");
-    executeSoon(finish);
-  };
-  Services.obs.addObserver(observer, "last-pb-context-exited", false);
-  windowsToClose.push(win);
-}
\ No newline at end of file
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -3209,16 +3209,28 @@ var SessionStoreInternal = {
 
     let restoreImmediately = options.restoreImmediately;
     let loadArguments = options.loadArguments;
     let browser = tab.linkedBrowser;
     let window = tab.ownerGlobal;
     let tabbrowser = window.gBrowser;
     let forceOnDemand = options.forceOnDemand;
 
+    // If the browser we're attempting to restore happens to be
+    // remote, we need to flip it back to non-remote if it's going
+    // to go into the pending background tab state. This is to make
+    // sure that the background tab can't crash if it hasn't yet
+    // been restored. Normally, when a window is restored, the tabs
+    // that SessionStore inserts are non-remote - but the initial
+    // browser is, by default, remote, so this check and flip is
+    // mostly for that case.
+    if (browser.isRemoteBrowser && (!restoreImmediately || forceOnDemand)) {
+      tabbrowser.updateBrowserRemoteness(browser, false);
+    }
+
     // Increase the busy state counter before modifying the tab.
     this._setWindowStateBusy(window);
 
     // It's important to set the window state to dirty so that
     // we collect their data for the first time when saving state.
     DirtyWindows.add(window);
 
     // In case we didn't collect/receive data for any tabs yet we'll have to
--- a/browser/components/sessionstore/test/browser_394759_behavior.js
+++ b/browser/components/sessionstore/test/browser_394759_behavior.js
@@ -21,26 +21,19 @@
  */
 function testWindows(windowsToOpen, expectedResults) {
   return Task.spawn(function*() {
     for (let winData of windowsToOpen) {
       let features = "chrome,dialog=no," +
                      (winData.isPopup ? "all=no" : "all");
       let url = "http://example.com/?window=" + windowsToOpen.length;
 
-      let openWindowPromise = BrowserTestUtils.waitForNewWindow();
+      let openWindowPromise = BrowserTestUtils.waitForNewWindow(true, url);
       openDialog(getBrowserURL(), "", features, url);
       let win = yield openWindowPromise;
-      yield BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
-
-      if (win.gMultiProcessBrowser) {
-        let tab = win.gBrowser.selectedTab;
-        yield promiseTabRestored(tab);
-      }
-
       yield BrowserTestUtils.closeWindow(win);
     }
 
     let closedWindowData = JSON.parse(ss.getClosedWindowData());
     let numPopups = closedWindowData.filter(function(el, i, arr) {
       return el.isPopup;
     }).length;
     let numNormal = ss.getClosedWindowCount() - numPopups;
--- a/browser/components/sessionstore/test/browser_423132.js
+++ b/browser/components/sessionstore/test/browser_423132.js
@@ -68,19 +68,14 @@ function test() {
           cs.removeAll();
           BrowserTestUtils.closeWindow(newWin).then(finish);
         };
 
         function flushAndReady() {
           TabStateFlusher.flush(newWin.gBrowser.selectedBrowser).then(ready);
         }
 
-        if (newWin.gMultiProcessBrowser) {
-          let tab = newWin.gBrowser.selectedTab;
-          promiseTabRestored(tab).then(flushAndReady);
-        } else {
-          flushAndReady();
-        }
+        flushAndReady();
       }, true, testURL);
     });
   }, false);
 }
 
--- a/browser/components/sessionstore/test/browser_async_window_flushing.js
+++ b/browser/components/sessionstore/test/browser_async_window_flushing.js
@@ -31,25 +31,16 @@ add_task(function* test_add_interesting_
 
   // Send a message that will cause the content to change its location
   // to someplace more interesting. We've disabled auto updates from
   // the browser, so the parent won't know about this
   yield ContentTask.spawn(browser, PAGE, function*(PAGE) {
     content.location = PAGE;
   });
 
-  // for e10s, this will cause a remoteness switch, since the
-  // initial browser in a newly opened window will not be remote.
-  // We need to wait for that remoteness change before we attach
-  // our OnHistoryReplaceEntry listener.
-  if (gMultiProcessBrowser) {
-    yield BrowserTestUtils.waitForEvent(newWin.gBrowser.selectedTab,
-                                        "TabRemotenessChange");
-  }
-
   yield promiseContentMessage(browser, "ss-test:OnHistoryReplaceEntry");
 
   // Clear out the userTypedValue so that the new window looks like
   // it's really not worth restoring.
   browser.userTypedValue = null;
 
   // Once the domWindowClosed Promise resolves, the window should
   // have closed, and SessionStore's onClose handler should have just
--- a/browser/components/sessionstore/test/browser_windowStateContainer.js
+++ b/browser/components/sessionstore/test/browser_windowStateContainer.js
@@ -1,15 +1,14 @@
 "use strict";
 
 requestLongerTimeout(2);
 
 add_task(function* () {
-  let win = window.openDialog(location, "_blank", "chrome,all,dialog=no");
-  yield promiseWindowLoaded(win);
+  let win = yield BrowserTestUtils.openNewBrowserWindow();
 
   // Create 4 tabs with different userContextId.
   for (let userContextId = 1; userContextId < 5; userContextId++) {
     let tab = win.gBrowser.addTab("http://example.com/", {userContextId});
     yield promiseBrowserLoaded(tab.linkedBrowser);
     yield TabStateFlusher.flush(tab.linkedBrowser);
   }
 
@@ -21,18 +20,17 @@ add_task(function* () {
 
   let winState = JSON.parse(ss.getWindowState(win));
 
   for (let i = 0; i < 4; i++) {
     Assert.equal(winState.windows[0].tabs[i].userContextId, i + 1,
                  "1st Window: tabs[" + i + "].userContextId should exist.");
   }
 
-  let win2 = window.openDialog(location, "_blank", "chrome,all,dialog=no");
-  yield promiseWindowLoaded(win2);
+  let win2 = yield BrowserTestUtils.openNewBrowserWindow();
 
   // Create tabs with different userContextId, but this time we create them with
   // fewer tabs and with different order with win.
   for (let userContextId = 3; userContextId > 0; userContextId--) {
     let tab = win2.gBrowser.addTab("http://example.com/", {userContextId});
     yield promiseBrowserLoaded(tab.linkedBrowser);
     yield TabStateFlusher.flush(tab.linkedBrowser);
   }
@@ -64,35 +62,34 @@ add_task(function* () {
                  "The document has the correct userContextId");
   });
 
   yield BrowserTestUtils.closeWindow(win);
   yield BrowserTestUtils.closeWindow(win2);
 });
 
 add_task(function* () {
-  let win = window.openDialog(location, "_blank", "chrome,all,dialog=no");
-  yield promiseWindowLoaded(win);
+  let win = yield BrowserTestUtils.openNewBrowserWindow();
+  yield TabStateFlusher.flush(win.gBrowser.selectedBrowser);
 
   let tab = win.gBrowser.addTab("http://example.com/", { userContextId: 1 });
   yield promiseBrowserLoaded(tab.linkedBrowser);
   yield TabStateFlusher.flush(tab.linkedBrowser);
 
   // win should have 1 default tab, and 1 container tab.
   Assert.equal(win.gBrowser.tabs.length, 2, "win should have 2 tabs");
 
   let winState = JSON.parse(ss.getWindowState(win));
 
   for (let i = 0; i < 2; i++) {
     Assert.equal(winState.windows[0].tabs[i].userContextId, i,
                  "1st Window: tabs[" + i + "].userContextId should be " + i);
   }
 
-  let win2 = window.openDialog(location, "_blank", "chrome,all,dialog=no");
-  yield promiseWindowLoaded(win2);
+  let win2 = yield BrowserTestUtils.openNewBrowserWindow();
 
   let tab2 = win2.gBrowser.addTab("http://example.com/", { userContextId : 1 });
   yield promiseBrowserLoaded(tab2.linkedBrowser);
   yield TabStateFlusher.flush(tab2.linkedBrowser);
 
   // Move the first normal tab to end, so the first tab of win2 will be a
   // container tab.
   win2.gBrowser.moveTabTo(win2.gBrowser.tabs[0], win2.gBrowser.tabs.length - 1);
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -400,26 +400,25 @@ def split_triplet(triplet):
     elif cpu.startswith('sparc') or cpu == 'sun4u':
         canonical_cpu = 'sparc'
         endianness = 'big'
     elif cpu.startswith('arm'):
         canonical_cpu = 'arm'
         endianness = 'big' if cpu.startswith(('armeb', 'armbe')) else 'little'
     elif cpu in ('mips', 'mipsel'):
         canonical_cpu = 'mips32'
-        endianness = 'little' if 'le' in cpu else 'big'
+        endianness = 'little' if 'el' in cpu else 'big'
     elif cpu in ('mips64', 'mips64el'):
         canonical_cpu = 'mips64'
-        endianness = 'little' if 'le' in cpu else 'big'
+        endianness = 'little' if 'el' in cpu else 'big'
     elif cpu.startswith('aarch64'):
         canonical_cpu = 'aarch64'
         endianness = 'little'
     else:
-        canonical_cpu = cpu
-        endianness = 'unknown'
+        die('Unknown CPU type: %s' % cpu)
 
     return namespace(
         alias=triplet,
         cpu=CPU(canonical_cpu),
         kernel=Kernel(canonical_kernel),
         os=OS(canonical_os),
         endianness=Endianness(endianness),
         raw_cpu=cpu,
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -190,16 +190,20 @@ def try_preprocess(compiler, language, s
         os.close(fd)
         cmd = compiler + ['-E', path]
         return check_cmd_output(*cmd)
     finally:
         os.remove(path)
 
 
 @imports(_from='mozbuild.configure.constants', _import='CompilerType')
+@imports(_from='mozbuild.configure.constants',
+         _import='CPU_preprocessor_checks')
+@imports(_from='mozbuild.configure.constants',
+         _import='kernel_preprocessor_checks')
 @imports(_from='textwrap', _import='dedent')
 def get_compiler_info(compiler, language):
     '''Returns information about the given `compiler` (command line in the
     form of a list or tuple), in the given `language`.
 
     The returned information includes:
     - the compiler type (msvc, clang-cl, clang or gcc)
     - the compiler version
@@ -240,16 +244,46 @@ def get_compiler_info(compiler, language
         %cplusplus __cplusplus
         #elif __STDC_VERSION__
         %STDC_VERSION __STDC_VERSION__
         #elif __STDC__
         %STDC_VERSION 198900L
         #endif
     ''')
 
+    # While we're doing some preprocessing, we might as well do some more
+    # preprocessor-based tests at the same time, to check the toolchain
+    # matches what we want.
+    for name, preprocessor_checks in (
+        ('CPU', CPU_preprocessor_checks),
+        ('KERNEL', kernel_preprocessor_checks),
+    ):
+        for n, (value, condition) in enumerate(preprocessor_checks.iteritems()):
+            check += dedent('''\
+                #%(if)s %(condition)s
+                %%%(name)s %(value)s
+            ''' % {
+                'if': 'elif' if n else 'if',
+                'condition': condition,
+                'name': name,
+                'value': value,
+            })
+        check += '#endif\n'
+
+    # Also check for endianness. The advantage of living in modern times is
+    # that all the modern compilers we support now have __BYTE_ORDER__ defined
+    # by the preprocessor, except MSVC, which only supports little endian.
+    check += dedent('''\
+        #if _MSC_VER || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+        %ENDIANNESS little
+        #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+        %ENDIANNESS big
+        #endif
+    ''')
+
     result = try_preprocess(compiler, language, check)
 
     if not result:
         raise FatalCheckError(
             'Unknown compiler or compiler not supported.')
 
     data = {}
     for line in result.splitlines():
@@ -278,23 +312,26 @@ def get_compiler_info(compiler, language
             version += '.' + msc_ver[4:]
 
     if version:
         version = Version(version)
 
     return namespace(
         type=type,
         version=version,
+        cpu=data.get('CPU'),
+        kernel=data.get('KERNEL'),
+        endianness=data.get('ENDIANNESS'),
         language='C++' if cplusplus else 'C',
         language_version=cplusplus if cplusplus else stdc_version,
     )
 
 
 @imports(_from='mozbuild.shellutil', _import='quote')
-def check_compiler(compiler, language):
+def check_compiler(compiler, language, target):
     info = get_compiler_info(compiler, language)
 
     flags = []
 
     def append_flag(flag):
         if flag not in flags:
             if info.type == 'clang-cl':
                 flags.append('-Xclang')
@@ -324,19 +361,46 @@ def check_compiler(compiler, language):
     # We force clang-cl to emulate Visual C++ 2013 Update 3 with fallback to
     # cl.exe.
     if info.type == 'clang-cl' and info.version != '18.00.30723':
         # Those flags are direct clang-cl flags that don't need -Xclang, add
         # them directly.
         flags.append('-fms-compatibility-version=18.00.30723')
         flags.append('-fallback')
 
+    # Check compiler target
+    # --------------------------------------------------------------------
+    if not info.cpu or info.cpu != target.cpu:
+        if info.type == 'clang':
+            append_flag('--target=%s' % target.toolchain)
+        elif info.type == 'gcc':
+            same_arch_different_bits = (
+                ('x86', 'x86_64'),
+                ('ppc', 'ppc64'),
+                ('sparc', 'sparc64'),
+            )
+            if (target.cpu, info.cpu) in same_arch_different_bits:
+                append_flag('-m32')
+            elif (info.cpu, target.cpu) in same_arch_different_bits:
+                append_flag('-m64')
+
+    if not info.kernel or info.kernel != target.kernel:
+        if info.type == 'clang':
+            append_flag('--target=%s' % target.toolchain)
+
+    if not info.endianness or info.endianness != target.endianness:
+        if info.type == 'clang':
+            append_flag('--target=%s' % target.toolchain)
+
     return namespace(
         type=info.type,
         version=info.version,
+        target_cpu=info.cpu,
+        target_kernel=info.kernel,
+        target_endianness=info.endianness,
         flags=flags,
     )
 
 
 @template
 def default_c_compilers(host_or_target):
     '''Template defining the set of default C compilers for the host and
     target platforms.
@@ -448,38 +512,47 @@ def compiler(language, host_or_target, c
             compiler=without_flags[-1],
             flags=cmd[len(without_flags):],
         )
 
     # Derive the host compiler from the corresponding target compiler when no
     # explicit compiler was given and we're not cross compiling. For the C++
     # compiler, though, prefer to derive from the host C compiler when it
     # doesn't match the target C compiler.
+    # As a special case, since clang supports all kinds of targets in the same
+    # executable, when cross compiling with clang, default to the same compiler
+    # as the target compiler, resetting flags.
     if host_or_target == host:
         args = (c_compiler, other_c_compiler) if other_c_compiler else ()
 
         @depends(provided_compiler, other_compiler, cross_compiling, *args)
         def provided_compiler(value, other_compiler, cross_compiling, *args):
             if value:
                 return value
             c_compiler, other_c_compiler = args if args else (None, None)
             if not cross_compiling and c_compiler == other_c_compiler:
                 return other_compiler
+            if cross_compiling and other_compiler.type == 'clang':
+                return namespace(**{
+                    k: [] if k == 'flags' else v
+                    for k, v in other_compiler.__dict__.iteritems()
+                })
 
     # Normally, we'd use `var` instead of `_var`, but the interaction with
     # old-configure complicates things, and for now, we a) can't take the plain
     # result from check_prog as CC/CXX/HOST_CC/HOST_CXX and b) have to let
     # old-configure AC_SUBST it (because it's autoconf doing it, not us)
     compiler = check_prog('_%s' % var, what=what, progs=default_compilers,
                           input=delayed_getattr(provided_compiler, 'compiler'))
 
-    @depends(compiler, provided_compiler, compiler_wrapper)
+    @depends(compiler, provided_compiler, compiler_wrapper, host_or_target)
     @checking('whether %s can be used' % what, lambda x: bool(x))
     @imports(_from='mozbuild.shellutil', _import='quote')
-    def valid_compiler(compiler, provided_compiler, compiler_wrapper):
+    def valid_compiler(compiler, provided_compiler, compiler_wrapper,
+                       host_or_target):
         wrapper = list(compiler_wrapper or ())
         if provided_compiler:
             provided_wrapper = list(provided_compiler.wrapper)
             # When doing a subconfigure, the compiler is set by old-configure
             # and it contains the wrappers from --with-compiler-wrapper and
             # --with-ccache.
             if provided_wrapper[:len(wrapper)] == wrapper:
                 provided_wrapper = provided_wrapper[len(wrapper):]
@@ -503,23 +576,49 @@ def compiler(language, host_or_target, c
                     % quote(os.path.dirname(full_path)))
             if os.path.normcase(find_program(compiler)) != os.path.normcase(
                     full_path):
                 die('Found `%s` before `%s` in your $PATH. '
                     'Please reorder your $PATH.',
                     quote(os.path.dirname(found_compiler)),
                     quote(os.path.dirname(full_path)))
 
-        info = check_compiler(wrapper + [compiler] + flags, language)
+        info = check_compiler(wrapper + [compiler] + flags, language,
+                              host_or_target)
 
         # Check that the additional flags we got are enough to not require any
         # more flags.
         if info.flags:
             flags += info.flags
-            info = check_compiler(wrapper + [compiler] + flags, language)
+            info = check_compiler(wrapper + [compiler] + flags, language,
+                                  host_or_target)
+
+        if not info.target_cpu or info.target_cpu != host_or_target.cpu:
+            raise FatalCheckError(
+                '%s %s compiler target CPU (%s) does not match --%s CPU (%s)'
+                % (host_or_target_str.capitalize(), language,
+                   info.target_cpu or 'unknown', host_or_target_str,
+                   host_or_target.raw_cpu))
+
+        if not info.target_kernel or (info.target_kernel !=
+                                      host_or_target.kernel):
+            raise FatalCheckError(
+                '%s %s compiler target kernel (%s) does not match --%s kernel (%s)'
+                % (host_or_target_str.capitalize(), language,
+                   info.target_kernel or 'unknown', host_or_target_str,
+                   host_or_target.kernel))
+
+        if not info.target_endianness or (info.target_endianness !=
+                                          host_or_target.endianness):
+            raise FatalCheckError(
+                '%s %s compiler target endianness (%s) does not match --%s '
+                'endianness (%s)'
+                % (host_or_target_str.capitalize(), language,
+                   info.target_endianness or 'unknown', host_or_target_str,
+                   host_or_target.endianness))
 
         if info.flags:
             raise FatalCheckError(
                 'Unknown compiler or compiler not supported.')
 
         # Compiler version checks
         # ===================================================
         # Check the compiler version here instead of in `compiler_version` so
--- a/caps/tests/mochitest/chrome.ini
+++ b/caps/tests/mochitest/chrome.ini
@@ -4,9 +4,9 @@ support-files =
   file_disableScript.html
   !/caps/tests/mochitest/file_disableScript.html
 
 [test_bug995943.xul]
 [test_addonMayLoad.html]
 [test_disableScript.xul]
 [test_principal_jarprefix_origin_appid_appstatus.html]
 # jarPrefix test doesn't work on Windows, see bug 776296.
-skip-if = os == "win"
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
--- a/devtools/client/framework/test/browser_devtools_api.js
+++ b/devtools/client/framework/test/browser_devtools_api.js
@@ -13,19 +13,17 @@ thisTestLeaksUncaughtRejectionsAndShould
 // When running in a standalone directory, we get this error
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.doc is undefined");
 
 // Tests devtools API
 
 const toolId1 = "test-tool-1";
 const toolId2 = "test-tool-2";
 
-var tempScope = {};
-Cu.import("resource://devtools/shared/event-emitter.js", tempScope);
-var EventEmitter = tempScope.EventEmitter;
+var EventEmitter = require("devtools/shared/event-emitter");
 
 function test() {
   addTab("about:blank").then(runTests1);
 }
 
 // Test scenario 1: the tool definition build method returns a promise.
 function runTests1(aTab) {
   let toolDefinition = {
@@ -204,17 +202,16 @@ function destroyToolbox(toolbox) {
     let target = TargetFactory.forTab(gBrowser.selectedTab);
     ok(gDevTools._toolboxes.get(target) == null, "gDevTools doesn't know about target");
     ok(toolbox._target == null, "toolbox doesn't know about target.");
     finishUp();
   });
 }
 
 function finishUp() {
-  tempScope = null;
   gBrowser.removeCurrentTab();
   finish();
 }
 
 /**
 * When a Toolbox is started it creates a DevToolPanel for each of the tools
 * by calling toolDefinition.build(). The returned object should
 * at least implement these functions. They will be used by the ToolBox.
--- a/devtools/client/locales/en-US/webconsole.properties
+++ b/devtools/client/locales/en-US/webconsole.properties
@@ -253,16 +253,17 @@ table.key=Key
 table.value=Values
 
 # LOCALIZATION NOTE (severity.error, severity.warn, severity.info, severity.log):
 # tooltip for icons next to console output
 severity.error=Error
 severity.warn=Warning
 severity.info=Info
 severity.log=Log
+severity.debug=Debug
 
 # LOCALIZATION NOTE (webconsole.find.key)
 # Key shortcut used to focus the search box on upper right of the console
 webconsole.find.key=CmdOrCtrl+F
 
 # LOCALIZATION NOTE (webconsole.close.key)
 # Key shortcut used to close the Browser console (doesn't work in regular web console)
 webconsole.close.key=CmdOrCtrl+W
--- a/devtools/client/shared/css-angle.js
+++ b/devtools/client/shared/css-angle.js
@@ -11,17 +11,16 @@ const SPECIALVALUES = new Set([
 ]);
 
 const {getCSSLexer} = require("devtools/shared/css-lexer");
 
 /**
  * This module is used to convert between various angle units.
  *
  * Usage:
- *   let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
  *   let {angleUtils} = require("devtools/client/shared/css-angle");
  *   let angle = new angleUtils.CssAngle("180deg");
  *
  *   angle.authored === "180deg"
  *   angle.valid === true
  *   angle.rad === "3,14rad"
  *   angle.grad === "200grad"
  *   angle.turn === "0.5turn"
--- a/devtools/client/shared/css-color.js
+++ b/devtools/client/shared/css-color.js
@@ -18,17 +18,16 @@ const SPECIALVALUES = new Set([
   "transparent",
   "unset"
 ]);
 
 /**
  * This module is used to convert between various color types.
  *
  * Usage:
- *   let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
  *   let {colorUtils} = require("devtools/shared/css-color");
  *   let color = new colorUtils.CssColor("red");
  *
  *   color.authored === "red"
  *   color.hasAlpha === false
  *   color.valid === true
  *   color.transparent === false // transparent has a special status.
  *   color.name === "red"        // returns hex when no name available.
--- a/devtools/client/shared/developer-toolbar.js
+++ b/devtools/client/shared/developer-toolbar.js
@@ -11,32 +11,32 @@ const Services = require("Services");
 const { TargetFactory } = require("devtools/client/framework/target");
 const Telemetry = require("devtools/client/shared/telemetry");
 const {ViewHelpers} = require("devtools/client/shared/widgets/view-helpers");
 
 const NS_XHTML = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 loader.lazyImporter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
-loader.lazyImporter(this, "EventEmitter", "resource://devtools/shared/event-emitter.js");
 
 loader.lazyGetter(this, "prefBranch", function () {
   return Services.prefs.getBranch(null)
                     .QueryInterface(Ci.nsIPrefBranch2);
 });
 loader.lazyGetter(this, "toolboxStrings", function () {
   return Services.strings.createBundle("chrome://devtools/locale/toolbox.properties");
 });
 
 loader.lazyRequireGetter(this, "gcliInit", "devtools/shared/gcli/commands/index");
 loader.lazyRequireGetter(this, "util", "gcli/util/util");
 loader.lazyRequireGetter(this, "ConsoleServiceListener", "devtools/shared/webconsole/utils", true);
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
 loader.lazyRequireGetter(this, "gDevToolsBrowser", "devtools/client/framework/devtools-browser", true);
 loader.lazyRequireGetter(this, "nodeConstants", "devtools/shared/dom-node-constants", true);
+loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
 
 /**
  * A collection of utilities to help working with commands
  */
 var CommandUtils = {
   /**
    * Utility to ensure that things are loaded in the correct order
    */
--- a/devtools/client/shared/output-parser.js
+++ b/devtools/client/shared/output-parser.js
@@ -25,18 +25,16 @@ loader.lazyGetter(this, "DOMUtils", func
 /**
  * This module is used to process text for output by developer tools. This means
  * linking JS files with the debugger, CSS files with the style editor, JS
  * functions with the debugger, placing color swatches next to colors and
  * adding doorhanger previews where possible (images, angles, lengths,
  * border radius, cubic-bezier etc.).
  *
  * Usage:
- *   const {require} =
- *      Cu.import("resource://devtools/shared/Loader.jsm", {});
  *   const {OutputParser} = require("devtools/client/shared/output-parser");
  *
  *   let parser = new OutputParser(document, supportsType);
  *
  *   parser.parseCssProperty("color", "red"); // Returns document fragment.
  *
  * @param {Document} document Used to create DOM nodes.
  * @param {Function} supportsTypes A function that returns a boolean when asked if a css
--- a/devtools/client/shared/shim/Services.js
+++ b/devtools/client/shared/shim/Services.js
@@ -496,16 +496,34 @@ const Services = {
     },
 
     // This is only used by telemetry, which is disabled for the
     // content case.  So, being totally wrong is ok.
     get is64Bit() {
       return true;
     },
   },
+
+  /**
+   * A no-op implementation of Services.telemetry.  This supports just
+   * the subset of Services.telemetry that is used by devtools.
+   */
+  telemetry: {
+    getHistogramById: function (name) {
+      return {
+        add: () => {}
+      };
+    },
+
+    getKeyedHistogramById: function (name) {
+      return {
+        add: () => {}
+      };
+    },
+  },
 };
 
 /**
  * Create a new preference.  This is used during startup (see
  * devtools/client/preferences/devtools.js) to install the
  * default preferences.
  *
  * @param {String} name the name of the preference
--- a/devtools/client/webconsole/new-console-output/components/message-container.js
+++ b/devtools/client/webconsole/new-console-output/components/message-container.js
@@ -8,16 +8,21 @@
 
 // React & Redux
 const {
   createClass,
   createFactory,
   PropTypes
 } = require("devtools/client/shared/vendor/react");
 
+const {
+  MESSAGE_SOURCE,
+  MESSAGE_TYPE
+} = require("devtools/client/webconsole/new-console-output/constants");
+
 const componentMap = new Map([
   ["ConsoleApiCall", require("./message-types/console-api-call").ConsoleApiCall],
   ["ConsoleCommand", require("./message-types/console-command").ConsoleCommand],
   ["DefaultRenderer", require("./message-types/default-renderer").DefaultRenderer],
   ["EvaluationResult", require("./message-types/evaluation-result").EvaluationResult],
   ["PageError", require("./message-types/page-error").PageError]
 ]);
 
@@ -31,32 +36,34 @@ const MessageContainer = createClass({
   render() {
     const { message } = this.props;
     let MessageComponent = createFactory(getMessageComponent(message));
     return MessageComponent({ message });
   }
 });
 
 function getMessageComponent(message) {
-  // @TODO Once packets have been converted to Chrome RDP structure, remove.
-  if (message.messageType) {
-    let {messageType} = message;
-    if (!componentMap.has(messageType)) {
-      return componentMap.get("DefaultRenderer");
-    }
-    return componentMap.get(messageType);
-  }
-
   switch (message.source) {
-    case "javascript":
+    case MESSAGE_SOURCE.CONSOLE_API:
+      return componentMap.get("ConsoleApiCall");
+    case MESSAGE_SOURCE.JAVASCRIPT:
       switch (message.type) {
-        case "command":
+        case MESSAGE_TYPE.COMMAND:
           return componentMap.get("ConsoleCommand");
+        case MESSAGE_TYPE.RESULT:
+          return componentMap.get("EvaluationResult");
+        // @TODO this is probably not the right behavior, but works for now.
+        // Chrome doesn't distinguish between page errors and log messages. We
+        // may want to remove the PageError component and just handle errors
+        // with ConsoleApiCall.
+        case MESSAGE_TYPE.LOG:
+          return componentMap.get("PageError");
+        default:
+          componentMap.get("DefaultRenderer");
       }
-      break;
   }
 
   return componentMap.get("DefaultRenderer");
 }
 
 module.exports.MessageContainer = MessageContainer;
 
 // Exported so we can test it with unit tests.
--- a/devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/console-api-call.js
@@ -20,20 +20,19 @@ ConsoleApiCall.displayName = "ConsoleApi
 
 ConsoleApiCall.propTypes = {
   message: PropTypes.object.isRequired,
 };
 
 function ConsoleApiCall(props) {
   const { message } = props;
 
-  const counter = message.data.counter;
-  const messageBody = counter ?
-    `${counter.label}: ${counter.count}` :
-    message.data.arguments.map((arg) => GripMessageBody({grip: arg}));
+  const messageBody = message.parameters ?
+    message.parameters.map((grip) => GripMessageBody({grip})) :
+    message.messageText;
 
   const icon = MessageIcon({severity: message.severity});
   const repeat = MessageRepeat({repeat: message.repeat});
 
   // @TODO Use of "is" is a temporary hack to get the category and severity
   // attributes to be applied. There are targeted in webconsole's CSS rules,
   // so if we remove this hack, we have to modify the CSS rules accordingly.
   return dom.div({
--- a/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/evaluation-result.js
@@ -35,15 +35,15 @@ function EvaluationResult(props) {
     severity: message.severity
   },
     // @TODO add timestamp
     // @TODO add indent if needed with console.group
     icon,
     dom.span(
       {className: "message-body-wrapper message-body devtools-monospace"},
       dom.span({},
-        GripMessageBody({grip: message.data})
+        GripMessageBody({grip: message.parameters})
       )
     )
   );
 }
 
 module.exports.EvaluationResult = EvaluationResult;
--- a/devtools/client/webconsole/new-console-output/components/message-types/page-error.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/page-error.js
@@ -18,39 +18,32 @@ const MessageIcon = createFactory(requir
 PageError.displayName = "PageError";
 
 PageError.propTypes = {
   message: PropTypes.object.isRequired,
 };
 
 function PageError(props) {
   const { message } = props;
-  const messageBody =
-    dom.span({className: "message-body devtools-monospace"},
-      message.data.errorMessage);
   const repeat = MessageRepeat({repeat: message.repeat});
   const icon = MessageIcon({severity: message.severity});
-  const children = [
-    messageBody,
-    repeat
-  ];
 
   // @TODO Use of "is" is a temporary hack to get the category and severity
   // attributes to be applied. There are targeted in webconsole's CSS rules,
   // so if we remove this hack, we have to modify the CSS rules accordingly.
   return dom.div({
-    class: "message cm-s-mozilla",
+    class: "message",
     is: "fdt-message",
     category: message.category,
     severity: message.severity
   },
     icon,
-    dom.span({className: "message-body-wrapper"},
+    dom.span(
+      {className: "message-body-wrapper message-body devtools-monospace"},
       dom.span({},
-        dom.span({className: "message-flex-body"},
-          children
-        )
+        message.messageText
       )
-    )
+    ),
+    repeat
   );
 }
 
 module.exports.PageError = PageError;
--- a/devtools/client/webconsole/new-console-output/constants.js
+++ b/devtools/client/webconsole/new-console-output/constants.js
@@ -6,51 +6,31 @@
 "use strict";
 
 const actionTypes = {
   MESSAGE_ADD: "MESSAGE_ADD",
   MESSAGES_CLEAR: "MESSAGES_CLEAR",
 };
 
 const categories = {
-  CATEGORY_NETWORK: 0,
-  CATEGORY_CSS: 1,
-  CATEGORY_JS: 2,
-  CATEGORY_WEBDEV: 3,
-  CATEGORY_INPUT: 4,
-  CATEGORY_OUTPUT: 5,
-  CATEGORY_SECURITY: 6,
-  CATEGORY_SERVER: 7
+  CATEGORY_NETWORK: "network",
+  CATEGORY_CSS: "cssparser",
+  CATEGORY_JS: "exception",
+  CATEGORY_WEBDEV: "console",
+  CATEGORY_INPUT: "input",
+  CATEGORY_OUTPUT: "output",
+  CATEGORY_SECURITY: "security",
+  CATEGORY_SERVER: "server"
 };
 
 const severities = {
-  SEVERITY_ERROR: 0,
-  SEVERITY_WARNING: 1,
-  SEVERITY_INFO: 2,
-  SEVERITY_LOG: 3
-};
-
-// The fragment of a CSS class name that identifies categories/severities.
-const fragments = {
-  CATEGORY_CLASS_FRAGMENTS: [
-    "network",
-    "cssparser",
-    "exception",
-    "console",
-    "input",
-    "output",
-    "security",
-    "server",
-  ],
-  SEVERITY_CLASS_FRAGMENTS: [
-    "error",
-    "warn",
-    "info",
-    "log",
-  ]
+  SEVERITY_ERROR: "error",
+  SEVERITY_WARNING: "warn",
+  SEVERITY_INFO: "info",
+  SEVERITY_LOG: "log"
 };
 
 // A mapping from the console API log event levels to the Web Console
 // severities.
 const levels = {
   LEVELS: {
     error: severities.SEVERITY_ERROR,
     exception: severities.SEVERITY_ERROR,
@@ -68,11 +48,50 @@ const levels = {
     groupCollapsed: severities.SEVERITY_LOG,
     groupEnd: severities.SEVERITY_LOG,
     time: severities.SEVERITY_LOG,
     timeEnd: severities.SEVERITY_LOG,
     count: severities.SEVERITY_LOG
   }
 };
 
+const chromeRDPEnums = {
+  MESSAGE_SOURCE: {
+    XML: "xml",
+    JAVASCRIPT: "javascript",
+    NETWORK: "network",
+    CONSOLE_API: "console-api",
+    STORAGE: "storage",
+    APPCACHE: "appcache",
+    RENDERING: "rendering",
+    SECURITY: "security",
+    OTHER: "other",
+    DEPRECATION: "deprecation"
+  },
+  MESSAGE_TYPE: {
+    LOG: "log",
+    DIR: "dir",
+    TABLE: "table",
+    TRACE: "trace",
+    CLEAR: "clear",
+    START_GROUP: "startGroup",
+    START_GROUP_COLLAPSED: "startGroupCollapsed",
+    END_GROUP: "endGroup",
+    ASSERT: "assert",
+    PROFILE: "profile",
+    PROFILE_END: "profileEnd",
+    // Undocumented in Chrome RDP, but is used for evaluation results.
+    RESULT: "result",
+    // Undocumented in Chrome RDP, but is used for input.
+    COMMAND: "command"
+  },
+  MESSAGE_LEVEL: {
+    LOG: "log",
+    ERROR: "error",
+    WARN: "warn",
+    DEBUG: "debug",
+    INFO: "info"
+  }
+};
+
 // Combine into a single constants object
-module.exports = Object.assign({}, actionTypes, categories, severities,
-  fragments, levels);
+module.exports = Object.assign({}, actionTypes, categories, severities, levels,
+  chromeRDPEnums);
--- a/devtools/client/webconsole/new-console-output/reducers/messages.js
+++ b/devtools/client/webconsole/new-console-output/reducers/messages.js
@@ -8,18 +8,17 @@
 const Immutable = require("devtools/client/shared/vendor/immutable");
 const constants = require("devtools/client/webconsole/new-console-output/constants");
 
 function messages(state = Immutable.List(), action) {
   switch (action.type) {
     case constants.MESSAGE_ADD:
       let newMessage = action.message;
 
-      // @TODO clean this up once we've switched to Chrome RDP packet structure.
-      if (newMessage.data && newMessage.data.level === "clear") {
+      if (newMessage.type === "clear") {
         return Immutable.List([newMessage]);
       }
 
       if (newMessage.allowRepeating && state.size > 0) {
         let lastMessage = state.last();
         if (lastMessage.repeatId === newMessage.repeatId) {
           return state.pop().push(
             newMessage.set("repeat", lastMessage.repeat + 1)
--- a/devtools/client/webconsole/new-console-output/test/components/test_message-icon.html
+++ b/devtools/client/webconsole/new-console-output/test/components/test_message-icon.html
@@ -9,22 +9,21 @@
      - http://creativecommons.org/publicdomain/zero/1.0/ -->
 </head>
 <body>
 <p>Test for MessageIcon component</p>
 
 <script type="text/javascript;version=1.8">
 window.onload = Task.async(function* () {
   const {
-    SEVERITY_CLASS_FRAGMENTS,
     SEVERITY_ERROR,
   } = require("devtools/client/webconsole/new-console-output/constants");
   const { MessageIcon } = require("devtools/client/webconsole/new-console-output/components/message-icon");
 
-  let severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_ERROR];
+  let severity = SEVERITY_ERROR;
   const iconRendered = renderComponent(MessageIcon, { severity });
   ok(iconRendered.classList.contains("icon"), "MessageIcon has expected class");
   is(iconRendered.getAttribute("title"), "Error",
     "MessageIcon shows correct title attribute");
 
   SimpleTest.finish();
 });
 </script>
--- a/devtools/client/webconsole/new-console-output/test/components/test_page-error.html
+++ b/devtools/client/webconsole/new-console-output/test/components/test_page-error.html
@@ -15,17 +15,17 @@
 window.onload = Task.async(function* () {
   const { prepareMessage } = require("devtools/client/webconsole/new-console-output/utils/messages");
   const { PageError } = require("devtools/client/webconsole/new-console-output/components/message-types/page-error");
 
   const packet = yield getPacket(null, "pageError");
   const message = prepareMessage(packet);
   const rendered = renderComponent(PageError, {message});
 
-  const queryPath = "div.message.cm-s-mozilla span span.message-flex-body span.message-body.devtools-monospace";
+  const queryPath = "div.message span.message-body-wrapper.message-body.devtools-monospace";
   const messageBody = rendered.querySelectorAll(queryPath);
   is(messageBody.length, 1, "PageError outputs expected HTML structure");
   is(messageBody[0].textContent, testCommands.get("pageError").expectedText, "PageError outputs expected text");
 
   SimpleTest.finish()
 });
 </script>
 </body>
--- a/devtools/client/webconsole/new-console-output/test/store/test_messages.js
+++ b/devtools/client/webconsole/new-console-output/test/store/test_messages.js
@@ -53,43 +53,41 @@ add_task(function* () {
     "Non-repeated messages aren't clobbered");
 });
 
 /**
  * Test getRepeatId().
  */
 add_task(function* () {
   const message1 = prepareMessage(packet);
-  const message2 = prepareMessage(packet);
+  let message2 = prepareMessage(packet);
   equal(getRepeatId(message1), getRepeatId(message2),
     "getRepeatId() returns same repeat id for objects with the same values");
 
-  message2.data.arguments = ["new args"];
+  message2 = message2.set("parameters", ["new args"]);
   notEqual(getRepeatId(message1), getRepeatId(message2),
     "getRepeatId() returns different repeat ids for different values");
 });
 
 /**
  * Test adding a console.clear message to the store.
  */
 add_task(function*() {
   const { getState, dispatch } = storeFactory();
 
   dispatch(actions.messageAdd(packet));
 
-  const expectedMessage = prepareMessage(packet);
-
   let messages = getAllMessages(getState());
-  deepEqual(messages.toArray(), [expectedMessage],
+  equal(messages.size, 1,
     "MESSAGE_ADD action adds a message");
 
   dispatch(actions.messageAdd(clearPacket));
 
   messages = getAllMessages(getState());
-  deepEqual(messages.toArray(), [prepareMessage(clearPacket)],
+  deepEqual(messages.first(), prepareMessage(clearPacket),
     "console.clear clears existing messages and add a new one");
 });
 
 /**
  * Test message limit on the store.
  */
 add_task(function* () {
   const { getState, dispatch } = storeFactory();
@@ -99,31 +97,31 @@ add_task(function* () {
   let newPacket = Object.assign({}, packet);
   for (let i = 1; i <= messageNumber; i++) {
     newPacket.message.arguments = [i];
     dispatch(actions.messageAdd(newPacket));
   }
 
   let messages = getAllMessages(getState());
   equal(messages.count(), logLimit, "Messages are pruned up to the log limit");
-  deepEqual(messages.last().data.arguments, [messageNumber],
+  deepEqual(messages.last().parameters, [messageNumber],
     "The last message is the expected one");
 });
 
 /**
  * Test message limit on the store with user set prefs.
  */
 add_task(function* () {
   const userSetLimit = 10;
   Services.prefs.setIntPref("devtools.hud.loglimit", userSetLimit);
 
   const { getState, dispatch } = storeFactory();
 
   let newPacket = Object.assign({}, packet);
   for (let i = 1; i <= userSetLimit + 1; i++) {
-    newPacket.message.arguments = [i];
+    newPacket.message.parameters = [i];
     dispatch(actions.messageAdd(newPacket));
   }
 
   let messages = getAllMessages(getState());
   equal(messages.count(), userSetLimit,
     "Messages are pruned up to the user set log limit");
 });
--- a/devtools/client/webconsole/new-console-output/test/utils/test_getRepeatId.html
+++ b/devtools/client/webconsole/new-console-output/test/utils/test_getRepeatId.html
@@ -22,87 +22,67 @@ window.onload = Task.async(function* () 
   yield testDifferentValues();
   yield testDifferentSeverities();
   yield testFalsyValues();
   yield testConsoleVsJSTerm();
 
   SimpleTest.finish();
 
   function testDuplicateValues() {
-    const packet1 = yield getPacket("console.log('same')", "consoleAPICall");
-    const packet2 = yield getPacket("console.log('same')", "consoleAPICall");
+    const {message: message1} = yield getPacket("console.log('same')", "consoleAPICall");
+    const {message: message2} = yield getPacket("console.log('same')", "consoleAPICall");
 
-    const message1 = prepareMessage(packet1);
-    const message2 = prepareMessage(packet2);
-
-    is(getRepeatId(message1.data), getRepeatId(message2.data),
+    is(getRepeatId(message1), getRepeatId(message2),
       "getRepeatId() returns same repeat id for objects with the same values");
   }
 
   function testDifferentValues() {
-    const packet1 = yield getPacket("console.log('same')", "consoleAPICall");
-    const packet2 = yield getPacket("console.log('diff')", "consoleAPICall");
+    const {message: message1} = yield getPacket("console.log('same')", "consoleAPICall");
+    const {message: message2} = yield getPacket("console.log('diff')", "consoleAPICall");
 
-    const message1 = prepareMessage(packet1);
-    const message2 = prepareMessage(packet2);
-
-    isnot(getRepeatId(message1.data), getRepeatId(message2.data),
+    isnot(getRepeatId(message1), getRepeatId(message2),
       "getRepeatId() returns different repeat ids for different values");
   }
 
   function testDifferentSeverities() {
-    const packet1 = yield getPacket("console.log('test')", "consoleAPICall");
-    const packet2 = yield getPacket("console.warn('test')", "consoleAPICall");
+    const {message: message1} = yield getPacket("console.log('test')", "consoleAPICall");
+    const {message: message2} = yield getPacket("console.warn('test')", "consoleAPICall");
 
-    const message1 = prepareMessage(packet1);
-    const message2 = prepareMessage(packet2);
-
-    isnot(getRepeatId(message1.data), getRepeatId(message2.data),
+    isnot(getRepeatId(message1), getRepeatId(message2),
       "getRepeatId() returns different repeat ids for different severities");
   }
 
   function testFalsyValues() {
-    const packetNaN = yield getPacket("console.log(NaN)", "consoleAPICall");
-    const packetUnd = yield getPacket("console.log(undefined)", "consoleAPICall");
-    const packetNul = yield getPacket("console.log(null)", "consoleAPICall");
-
-    const messageNaN = prepareMessage(packetNaN);
-    const messageUnd = prepareMessage(packetUnd);
-    const messageNul = prepareMessage(packetNul);
+    const {message: messageNaN} = yield getPacket("console.log(NaN)", "consoleAPICall");
+    const {message: messageUnd} = yield getPacket("console.log(undefined)", "consoleAPICall");
+    const {message: messageNul} = yield getPacket("console.log(null)", "consoleAPICall");
 
     const repeatIds = new Set([
-      getRepeatId(messageNaN.data),
-      getRepeatId(messageUnd.data),
-      getRepeatId(messageNul.data)]
+      getRepeatId(messageNaN),
+      getRepeatId(messageUnd),
+      getRepeatId(messageNul)]
     );
     is(repeatIds.size, 3,
       "getRepeatId() handles falsy values distinctly");
 
-    const packetNaN2 = yield getPacket("console.log(NaN)", "consoleAPICall");
-    const packetUnd2 = yield getPacket("console.log(undefined)", "consoleAPICall");
-    const packetNul2 = yield getPacket("console.log(null)", "consoleAPICall");
+    const {message: messageNaN2} = yield getPacket("console.log(NaN)", "consoleAPICall");
+    const {message: messageUnd2} = yield getPacket("console.log(undefined)", "consoleAPICall");
+    const {message: messageNul2} = yield getPacket("console.log(null)", "consoleAPICall");
 
-    const messageNaN2 = prepareMessage(packetNaN2);
-    const messageUnd2 = prepareMessage(packetUnd2);
-    const messageNul2 = prepareMessage(packetNul2);
-
-    is(getRepeatId(messageNaN.data), getRepeatId(messageNaN2.data),
+    is(getRepeatId(messageNaN), getRepeatId(messageNaN2),
       "getRepeatId() handles NaN values");
-    is(getRepeatId(messageUnd.data), getRepeatId(messageUnd2.data),
+    is(getRepeatId(messageUnd), getRepeatId(messageUnd2),
       "getRepeatId() handles undefined values");
-    is(getRepeatId(messageNul.data), getRepeatId(messageNul2.data),
+    is(getRepeatId(messageNul), getRepeatId(messageNul2),
       "getRepeatId() handles null values");
   }
 
   function testConsoleVsJSTerm() {
-    const packet1 = yield getPacket("console.log(undefined)", "consoleAPICall");
-    const packet2 = yield getPacket("undefined");
+    const {message: message1} = yield getPacket("console.log(undefined)", "consoleAPICall");
+    const {result: message2} = yield getPacket("undefined");
 
-    const message1 = prepareMessage(packet1);
-    const message2 = prepareMessage(packet2);
-
-    isnot(getRepeatId(message1.data), getRepeatId(message2.data),
+    isnot(getRepeatId(message1), getRepeatId(message2),
       "getRepeatId() returns different repeat ids for console vs JSTerm");
   }
 });
 </script>
 </body>
 </html>
--- a/devtools/client/webconsole/new-console-output/types.js
+++ b/devtools/client/webconsole/new-console-output/types.js
@@ -13,15 +13,18 @@ exports.ConsoleCommand = Immutable.Recor
   source: null,
   type: null,
   category: null,
   severity: null,
 });
 
 exports.ConsoleMessage = Immutable.Record({
   allowRepeating: true,
+  source: null,
+  type: null,
+  level: null,
+  messageText: null,
+  parameters: null,
+  repeat: 1,
+  repeatId: null,
   category: "output",
   severity: "log",
-  data: null,
-  messageType: null,
-  repeat: 1,
-  repeatId: null,
 });
--- a/devtools/client/webconsole/new-console-output/utils/messages.js
+++ b/devtools/client/webconsole/new-console-output/utils/messages.js
@@ -2,87 +2,115 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {
-  CATEGORY_CLASS_FRAGMENTS,
+  MESSAGE_SOURCE,
+  MESSAGE_TYPE,
+  MESSAGE_LEVEL,
+  // Legacy
   CATEGORY_JS,
-  CATEGORY_WEBDEV,
   CATEGORY_OUTPUT,
+  CATEGORY_WEBDEV,
   LEVELS,
-  SEVERITY_CLASS_FRAGMENTS,
-  SEVERITY_ERROR,
-  SEVERITY_WARNING,
   SEVERITY_LOG,
 } = require("../constants");
 const WebConsoleUtils = require("devtools/shared/webconsole/utils").Utils;
 const STRINGS_URI = "chrome://devtools/locale/webconsole.properties";
 const l10n = new WebConsoleUtils.L10n(STRINGS_URI);
 const { ConsoleMessage } = require("../types");
 
 function prepareMessage(packet) {
+  // This packet is already in the expected packet structure. Simply return.
   if (packet.source) {
     return packet;
   }
 
+  return transformPacket(packet);
+}
+
+/**
+ * Transforms a packet from Firefox RDP structure to Chrome RDP structure.
+ */
+function transformPacket(packet) {
   if (packet._type) {
     packet = convertCachedPacket(packet);
   }
 
   switch (packet.type) {
     case "consoleAPICall": {
-      let data = Object.assign({}, packet.message);
-      if (data.level === "clear") {
-        data.arguments = [l10n.getStr("consoleCleared")];
-      }
+      let { message } = packet;
+
+      let parameters = message.arguments;
+      let type = message.level;
+      let level = LEVELS[type] || MESSAGE_TYPE.LOG;
+      let messageText = null;
 
-      return new ConsoleMessage({
-        category: CATEGORY_CLASS_FRAGMENTS[CATEGORY_WEBDEV],
-        data,
-        messageType: "ConsoleApiCall",
-        repeatId: getRepeatId(data),
-        severity: SEVERITY_CLASS_FRAGMENTS[LEVELS[data.level]] || "log",
-      });
-    }
-    case "pageError": {
-      let data = Object.assign({}, packet.pageError);
-      let severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_ERROR];
-      if (data.warning || data.strict) {
-        severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_WARNING];
-      } else if (data.info) {
-        severity = SEVERITY_CLASS_FRAGMENTS[SEVERITY_LOG];
+      // Special per-type conversion.
+      switch (type) {
+        case "clear":
+          // We show a message to users when calls console.clear() is called.
+          parameters = [l10n.getStr("consoleCleared")];
+          break;
+        case "count":
+          // Chrome RDP doesn't have a special type for count.
+          type = MESSAGE_TYPE.LOG;
+          level = MESSAGE_LEVEL.DEBUG;
+          messageText = `${message.counter.label}: ${message.counter.count}`;
+          parameters = null;
+          break;
       }
 
       return new ConsoleMessage({
-        category: CATEGORY_CLASS_FRAGMENTS[CATEGORY_JS],
-        data,
-        messageType: "PageError",
-        repeatId: getRepeatId(data),
-        severity,
+        source: MESSAGE_SOURCE.CONSOLE_API,
+        type,
+        level,
+        parameters,
+        messageText,
+        repeatId: getRepeatId(message),
+        category: CATEGORY_WEBDEV,
+        severity: level,
       });
     }
-    case "evaluationResult":
-    default: {
-      let data;
-      if (typeof packet.result === "object") {
-        data = Object.assign({}, packet.result);
-      } else {
-        data = packet.result;
+
+    case "pageError": {
+      let { pageError } = packet;
+      let level = MESSAGE_LEVEL.ERROR;
+      if (pageError.warning || pageError.strict) {
+        level = MESSAGE_LEVEL.WARN;
+      } else if (pageError.info) {
+        level = MESSAGE_LEVEL.INFO;
       }
 
       return new ConsoleMessage({
-        category: CATEGORY_CLASS_FRAGMENTS[CATEGORY_OUTPUT],
-        data,
-        messageType: "EvaluationResult",
-        repeatId: getRepeatId(data),
-        severity: SEVERITY_CLASS_FRAGMENTS[SEVERITY_LOG],
+        source: MESSAGE_SOURCE.JAVASCRIPT,
+        type: MESSAGE_TYPE.LOG,
+        messageText: pageError.errorMessage,
+        repeatId: getRepeatId(pageError),
+        category: CATEGORY_JS,
+        severity: level,
+      });
+    }
+
+    case "evaluationResult":
+    default: {
+      let { result } = packet;
+
+      return new ConsoleMessage({
+        source: MESSAGE_SOURCE.JAVASCRIPT,
+        type: MESSAGE_TYPE.RESULT,
+        level: MESSAGE_LEVEL.LOG,
+        parameters: result,
+        repeatId: getRepeatId(result),
+        category: CATEGORY_OUTPUT,
+        severity: SEVERITY_LOG,
       });
     }
   }
 }
 
 // Helpers
 function getRepeatId(message) {
   let clonedMessage = JSON.parse(JSON.stringify(message));
--- a/devtools/client/webide/modules/app-projects.js
+++ b/devtools/client/webide/modules/app-projects.js
@@ -1,16 +1,16 @@
 /* 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/. */
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
 const promise = require("promise");
 
-const {EventEmitter} = Cu.import("resource://devtools/shared/event-emitter.js", {});
+const EventEmitter = require("devtools/shared/event-emitter");
 const {generateUUID} = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
 const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
 const {indexedDB} = require("sdk/indexed-db");
 
 /**
  * IndexedDB wrapper that just save project objects
  *
  * The only constraint is that project objects have to have
--- a/devtools/shared/apps/tests/mochitest.ini
+++ b/devtools/shared/apps/tests/mochitest.ini
@@ -1,7 +1,7 @@
 [DEFAULT]
-skip-if = (buildapp != 'b2g' && buildapp != 'mulet')
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 support-files =
   debugger-protocol-helper.js
   redirect.sjs
 
 [test_webapps_actor.html]
--- a/devtools/shared/tests/mochitest/test_eventemitter_basic.html
+++ b/devtools/shared/tests/mochitest/test_eventemitter_basic.html
@@ -19,18 +19,17 @@
   <body>
 
     <script type="application/javascript;version=1.8">
       "use strict";
 
       const { utils: Cu } = Components;
       const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
       const promise = require("promise");
-      const { EventEmitter } =
-        Cu.import("resource://devtools/shared/event-emitter.js", {});
+      const EventEmitter = require("devtools/shared/event-emitter");
       const { Task } = require("devtools/shared/task");
 
       SimpleTest.waitForExplicitFinish();
 
       testEmitter();
       testEmitter({});
 
       Task.spawn(testPromise)
--- a/docshell/base/nsIDocShellTreeOwner.idl
+++ b/docshell/base/nsIDocShellTreeOwner.idl
@@ -76,16 +76,36 @@ interface nsIDocShellTreeOwner : nsISupp
 
 	/*
 	Tells the tree owner to size its window or parent window in such a way
 	that the shell passed along will be the size specified.
 	*/
 	void sizeShellTo(in nsIDocShellTreeItem shell, in long cx, in long cy);
 
 	/*
+	Gets the size of the primary content area in CSS pixels. This should work
+	for both in-process and out-of-process content areas.
+	*/
+	void getPrimaryContentSize(out long width, out long height);
+	/*
+	Sets the size of the primary content area in CSS pixels. This should work
+	for both in-process and out-of-process content areas.
+	*/
+	void setPrimaryContentSize(in long width, in long height);
+
+	/*
+	Gets the size of the root docshell in CSS pixels.
+	*/
+	void getRootShellSize(out long width, out long height);
+	/*
+	Sets the size of the root docshell in CSS pixels.
+	*/
+	void setRootShellSize(in long width, in long height);
+
+	/*
 	Sets the persistence of different attributes of the window.
 	*/
 	void setPersistence(in boolean aPersistPosition,
                             in boolean aPersistSize,
                             in boolean aPersistSizeMode);
 
 	/*
 	Gets the current persistence states of the window.
@@ -93,9 +113,15 @@ interface nsIDocShellTreeOwner : nsISupp
 	void getPersistence(out boolean aPersistPosition,
                             out boolean aPersistSize,
                             out boolean aPersistSizeMode);
 
 	/*
 	Gets the number of targettable docshells.
 	*/
 	readonly attribute unsigned long targetableShellCount;
+
+	/*
+	Returns true if there is a primary content shell or a primary
+	tab parent.
+	*/
+	readonly attribute bool hasPrimaryContent;
 };
--- a/dom/apps/AppsServiceChild.jsm
+++ b/dom/apps/AppsServiceChild.jsm
@@ -104,17 +104,17 @@ this.DOMApplicationRegistry = {
     }).bind(this));
 
     this.cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
       messages: APPS_IPC_MSG_NAMES
     });
 
     // We need to prime the cache with the list of apps.
     let list = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
-    this.webapps = list.webapps;
+    this.webapps = list ? list.webapps : { };
     // We need a fast mapping from localId -> app, so we add an index.
     // We also add the manifest to the app object.
     this.localIdIndex = { };
     for (let id in this.webapps) {
       let app = this.webapps[id];
       this.localIdIndex[app.localId] = app;
       app.manifest = list.manifests[id];
     }
--- a/dom/apps/PermissionsTable.jsm
+++ b/dom/apps/PermissionsTable.jsm
@@ -497,16 +497,22 @@ this.PermissionsTable =  { geolocation: 
                               trusted: DENY_ACTION,
                               privileged: ALLOW_ACTION,
                               certified: ALLOW_ACTION
                            },
                            "system-app-only-audio-channels-in-app": {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
+                           },
+                           "previously-certified-app": {
+                             app: DENY_ACTION,
+                             trusted: DENY_ACTION,
+                             privileged: DENY_ACTION,
+                             certified: ALLOW_ACTION
                            }
                          };
 
 /**
  * Append access modes to the permission name as suffixes.
  *   e.g. permission name 'contacts' with ['read', 'write'] =
  *   ['contacts-read', contacts-write']
  * @param string aPermName
--- a/dom/apps/Webapps.jsm
+++ b/dom/apps/Webapps.jsm
@@ -4809,9 +4809,10 @@ AppcacheObserver.prototype = {
     }
   },
 
   applicationCacheAvailable: function appObs_CacheAvail(aApplicationCache) {
     // Nothing to do.
   }
 };
 
-DOMApplicationRegistry.init();
+// FIXME: Properly remove Cu.import(Webapps.jsm) from every place.
+//DOMApplicationRegistry.init();
--- a/dom/apps/tests/mochitest.ini
+++ b/dom/apps/tests/mochitest.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp != 'b2g' && buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 support-files =
   addons/application.zip
   addons/invalid.webapp
   addons/invalid.webapp^headers^
   addons/update.webapp
   addons/update.webapp^headers^
   addons/index.html
   chromeAddCert.js
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -12364,16 +12364,49 @@ GetPointerLockError(Element* aElement, E
     if (!top->GetExtantDoc()->HasFocus(rv)) {
       return "PointerLockDeniedNotFocused";
     }
   }
 
   return nullptr;
 }
 
+static void
+ChangePointerLockedElement(Element* aElement, nsIDocument* aDocument,
+                           Element* aPointerLockedElement)
+{
+  // aDocument here is not really necessary, as it is the uncomposed
+  // document of both aElement and aPointerLockedElement as far as one
+  // is not nullptr, and they wouldn't both be nullptr in any case.
+  // But since the caller of this function should have known what the
+  // document is, we just don't try to figure out what it should be.
+  MOZ_ASSERT(aDocument);
+  MOZ_ASSERT(aElement != aPointerLockedElement);
+  if (aPointerLockedElement) {
+    MOZ_ASSERT(aPointerLockedElement->GetUncomposedDoc() == aDocument);
+    aPointerLockedElement->ClearPointerLock();
+  }
+  if (aElement) {
+    MOZ_ASSERT(aElement->GetUncomposedDoc() == aDocument);
+    aElement->SetPointerLock();
+    EventStateManager::sPointerLockedElement = do_GetWeakReference(aElement);
+    EventStateManager::sPointerLockedDoc = do_GetWeakReference(aDocument);
+    NS_ASSERTION(EventStateManager::sPointerLockedElement &&
+                 EventStateManager::sPointerLockedDoc,
+                 "aElement and this should support weak references!");
+  } else {
+    EventStateManager::sPointerLockedElement = nullptr;
+    EventStateManager::sPointerLockedDoc = nullptr;
+  }
+  // Retarget all events to aElement via capture or
+  // stop retargeting if aElement is nullptr.
+  nsIPresShell::SetCapturingContent(aElement, CAPTURE_POINTERLOCK);
+  DispatchPointerLockChange(aDocument);
+}
+
 NS_IMETHODIMP
 PointerLockRequest::Run()
 {
   nsCOMPtr<Element> e = do_QueryReferent(mElement);
   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
   nsDocument* d = static_cast<nsDocument*>(doc.get());
   const char* error = nullptr;
   if (!e || !d || !e->GetUncomposedDoc()) {
@@ -12385,42 +12418,40 @@ PointerLockRequest::Run()
     nsCOMPtr<Element> pointerLockedElement =
       do_QueryReferent(EventStateManager::sPointerLockedElement);
     if (e == pointerLockedElement) {
       DispatchPointerLockChange(d);
       return NS_OK;
     }
     // Note, we must bypass focus change, so pass true as the last parameter!
     error = GetPointerLockError(e, pointerLockedElement, true);
+    // Another element in the same document is requesting pointer lock,
+    // just grant it without user input check.
+    if (!error && pointerLockedElement) {
+      ChangePointerLockedElement(e, d, pointerLockedElement);
+      return NS_OK;
+    }
   }
   // If it is neither user input initiated, nor requested in fullscreen,
   // it should be rejected.
   if (!error && !mUserInputOrChromeCaller && !doc->GetFullscreenElement()) {
     error = "PointerLockDeniedNotInputDriven";
   }
   if (!error && !d->SetPointerLock(e, NS_STYLE_CURSOR_NONE)) {
     error = "PointerLockDeniedFailedToLock";
   }
   if (error) {
     DispatchPointerLockError(d, error);
     return NS_OK;
   }
 
-  e->SetPointerLock();
-  EventStateManager::sPointerLockedElement = do_GetWeakReference(e);
-  EventStateManager::sPointerLockedDoc = do_GetWeakReference(doc);
-  NS_ASSERTION(EventStateManager::sPointerLockedElement &&
-               EventStateManager::sPointerLockedDoc,
-               "aElement and this should support weak references!");
-
+  ChangePointerLockedElement(e, d, nullptr);
   nsContentUtils::DispatchEventOnlyToChrome(
     doc, ToSupports(e), NS_LITERAL_STRING("MozDOMPointerLock:Entered"),
     /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
-
-  DispatchPointerLockChange(d);
   return NS_OK;
 }
 
 void
 nsDocument::RequestPointerLock(Element* aElement)
 {
   NS_ASSERTION(aElement,
     "Must pass non-null element to nsDocument::RequestPointerLock");
@@ -12502,29 +12533,22 @@ nsDocument::UnlockPointer(nsIDocument* a
   }
   nsDocument* doc = static_cast<nsDocument*>(pointerLockedDoc.get());
   if (!doc->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO)) {
     return;
   }
 
   nsCOMPtr<Element> pointerLockedElement =
     do_QueryReferent(EventStateManager::sPointerLockedElement);
-  if (pointerLockedElement) {
-    pointerLockedElement->ClearPointerLock();
-  }
-
-  EventStateManager::sPointerLockedElement = nullptr;
-  EventStateManager::sPointerLockedDoc = nullptr;
+  ChangePointerLockedElement(nullptr, doc, pointerLockedElement);
 
   nsContentUtils::DispatchEventOnlyToChrome(
     doc, ToSupports(pointerLockedElement),
     NS_LITERAL_STRING("MozDOMPointerLock:Exited"),
     /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
-
-  DispatchPointerLockChange(pointerLockedDoc);
 }
 
 void
 nsIDocument::UnlockPointer(nsIDocument* aDoc)
 {
   nsDocument::UnlockPointer(aDoc);
 }
 
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1574,18 +1574,18 @@ nsFocusManager::CheckIfFocusable(nsICont
 
   // if this is a child frame content node, check if it is visible and
   // call the content node's IsFocusable method instead of the frame's
   // IsFocusable method. This skips checking the style system and ensures that
   // offscreen browsers can still be focused.
   nsIDocument* subdoc = doc->GetSubDocumentFor(aContent);
   if (subdoc && IsWindowVisible(subdoc->GetWindow())) {
     const nsStyleUserInterface* ui = frame->StyleUserInterface();
-    int32_t tabIndex = (ui->mUserFocus == NS_STYLE_USER_FOCUS_IGNORE ||
-                        ui->mUserFocus == NS_STYLE_USER_FOCUS_NONE) ? -1 : 0;
+    int32_t tabIndex = (ui->mUserFocus == StyleUserFocus::Ignore ||
+                        ui->mUserFocus == StyleUserFocus::None_) ? -1 : 0;
     return aContent->IsFocusable(&tabIndex, aFlags & FLAG_BYMOUSE) ? aContent : nullptr;
   }
   
   return frame->IsFocusable(nullptr, aFlags & FLAG_BYMOUSE) ? aContent : nullptr;
 }
 
 bool
 nsFocusManager::Blur(nsPIDOMWindowOuter* aWindowToClear,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -11828,17 +11828,17 @@ nsGlobalWindow::OpenInternal(const nsASt
     // dialog is open.
     nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
     if (!aCalledNoScript) {
       // We asserted at the top of this function that aNavigate is true for
       // !aCalledNoScript.
       rv = pwwatch->OpenWindow2(AsOuter(), url.get(), name_ptr,
                                 options_ptr, /* aCalledFromScript = */ true,
-                                aDialog, aNavigate, nullptr, argv,
+                                aDialog, aNavigate, argv,
                                 1.0f, 0, getter_AddRefs(domReturn));
     } else {
       // Force a system caller here so that the window watcher won't screw us
       // up.  We do NOT want this case looking at the JS context on the stack
       // when searching.  Compare comments on
       // nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.
 
       // Note: Because nsWindowWatcher is so broken, it's actually important
@@ -11848,17 +11848,17 @@ nsGlobalWindow::OpenInternal(const nsASt
       Maybe<AutoNoJSAPI> nojsapi;
       if (!aContentModal) {
         nojsapi.emplace();
       }
 
 
       rv = pwwatch->OpenWindow2(AsOuter(), url.get(), name_ptr,
                                 options_ptr, /* aCalledFromScript = */ false,
-                                aDialog, aNavigate, nullptr, aExtraArgument,
+                                aDialog, aNavigate, aExtraArgument,
                                 1.0f, 0, getter_AddRefs(domReturn));
 
     }
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // success!
--- a/dom/broadcastchannel/tests/mochitest.ini
+++ b/dom/broadcastchannel/tests/mochitest.ini
@@ -16,15 +16,15 @@ support-files =
 [test_broadcastchannel_basic.html]
 [test_broadcastchannel_close.html]
 [test_broadcastchannel_close2.html]
 [test_broadcastchannel_self.html]
 [test_broadcastchannel_sharedWorker.html]
 [test_broadcastchannel_worker.html]
 [test_broadcastchannel_worker_alive.html]
 [test_broadcastchannel_mozbrowser.html]
-skip-if = buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_broadcastchannel_mozbrowser2.html]
-skip-if = buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_bfcache.html]
 [test_invalidState.html]
 [test_ordering.html]
 [test_dataCloning.html]
--- a/dom/cache/test/mochitest/mochitest.ini
+++ b/dom/cache/test/mochitest/mochitest.ini
@@ -37,13 +37,13 @@ support-files =
 [test_cache_requestCache.html]
 [test_cache_delete.html]
 [test_cache_put_reorder.html]
 [test_cache_https.html]
   skip-if = buildapp == 'b2g' # bug 1162353
 [test_cache_restart.html]
 [test_cache_shrink.html]
 [test_cache_clear_on_app_uninstall.html]
-  skip-if = buildapp != 'mulet' || e10s # bug 1178685
+  skip-if = true || e10s # bug 1178685 ### Bug 1255339: blacklist because no more mozApps
 [test_cache_orphaned_cache.html]
 [test_cache_orphaned_body.html]
 [test_cache_untrusted.html]
 [test_chrome_constructor.html]
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -2949,17 +2949,17 @@ EventStateManager::PostHandleEvent(nsPre
           // 3. XUL control element has the disabled property set to 'true'.
           //
           // We can't use nsIFrame::IsFocusable() because we want to blur when
           // we click on a visibility: none element.
           // We can't use nsIContent::IsFocusable() because we want to blur when
           // we click on a non-focusable element like a <div>.
           // We have to use |aEvent->mTarget| to not make sure we do not check
           // an anonymous node of the targeted element.
-          suppressBlur = (ui->mUserFocus == NS_STYLE_USER_FOCUS_IGNORE);
+          suppressBlur = (ui->mUserFocus == StyleUserFocus::Ignore);
 
           if (!suppressBlur) {
             nsCOMPtr<Element> element = do_QueryInterface(aEvent->mTarget);
             suppressBlur = element &&
                            element->State().HasState(NS_EVENT_STATE_DISABLED);
           }
 
           if (!suppressBlur) {
@@ -4341,19 +4341,16 @@ EventStateManager::SetPointerLock(nsIWid
 
     // Fire a synthetic mouse move to ensure event state is updated. We first
     // set the mouse to the center of the window, so that the mouse event
     // doesn't report any movement.
     sLastRefPoint = GetWindowClientRectCenter(aWidget);
     aWidget->SynthesizeNativeMouseMove(
       sLastRefPoint + aWidget->WidgetToScreenOffset(), nullptr);
 
-    // Retarget all events to this element via capture.
-    nsIPresShell::SetCapturingContent(aElement, CAPTURE_POINTERLOCK);
-
     // Suppress DnD
     if (dragService) {
       dragService->Suppress();
     }
   } else {
     // Unlocking, so return pointer to the original position by firing a
     // synthetic mouse event. We first reset sLastRefPoint to its
     // pre-pointerlock position, so that the synthetic mouse event reports
@@ -4362,19 +4359,16 @@ EventStateManager::SetPointerLock(nsIWid
     // Reset SynthCenteringPoint to invalid so that next time we start
     // locking pointer, it has its initial value.
     sSynthCenteringPoint = kInvalidRefPoint;
     if (aWidget) {
       aWidget->SynthesizeNativeMouseMove(
         mPreLockPoint + aWidget->WidgetToScreenOffset(), nullptr);
     }
 
-    // Don't retarget events to this element any more.
-    nsIPresShell::SetCapturingContent(nullptr, CAPTURE_POINTERLOCK);
-
     // Unsuppress DnD
     if (dragService) {
       dragService->Unsuppress();
     }
   }
 }
 
 void
--- a/dom/indexedDB/test/mochitest.ini
+++ b/dom/indexedDB/test/mochitest.ini
@@ -379,19 +379,19 @@ skip-if = (buildapp == 'b2g' && toolkit 
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_transaction_ordering.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_unique_index_update.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
 [test_webapp_clearBrowserData_inproc_inproc.html]
 # The clearBrowserData tests are only supposed to run in the main process.
 # They currently time out on android.
-skip-if = buildapp == 'b2g' || e10s || toolkit == 'android'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_webapp_clearBrowserData_inproc_oop.html]
 # The clearBrowserData tests are only supposed to run in the main process.
 # They currently time out on android.
-skip-if = buildapp == 'b2g' || e10s || toolkit == 'android'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_webapp_clearBrowserData_oop_inproc.html]
 # The clearBrowserData tests are only supposed to run in the main process.
 # They currently time out on android.
-skip-if = buildapp == 'b2g' || e10s || toolkit == 'android'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_serviceworker.html]
 skip-if = buildapp == 'b2g'
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -857,17 +857,17 @@ ContentChild::ProvideWindowCommon(TabChi
         cv->GetFullZoom(&fullZoom);
       }
     }
 
     nsresult rv;
     if (!SendCreateWindow(aTabOpener, newChild, renderFrame,
                           aChromeFlags, aCalledFromJS, aPositionSpecified,
                           aSizeSpecified,
-                          name, features,
+                          features,
                           baseURIString,
                           openerDocShell
                             ? openerDocShell->GetOriginAttributes()
                             : DocShellOriginAttributes(),
                           fullZoom,
                           &rv,
                           aWindowIsNew,
                           &frameScripts,
@@ -1678,16 +1678,19 @@ ContentChild::RecvNotifyPresentationRece
 
   return true;
 }
 
 bool
 ContentChild::RecvNotifyGMPsChanged()
 {
   GMPDecoderModule::UpdateUsableCodecs();
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  obs->NotifyObservers(nullptr, "gmp-changed", nullptr);
   return true;
 }
 
 PCrashReporterChild*
 ContentChild::AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
                                        const uint32_t& processType)
 {
 #ifdef MOZ_CRASHREPORTER
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -5277,30 +5277,30 @@ ContentParent::DeallocPWebBrowserPersist
 bool
 ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
                                 PBrowserParent* aNewTab,
                                 PRenderFrameParent* aRenderFrame,
                                 const uint32_t& aChromeFlags,
                                 const bool& aCalledFromJS,
                                 const bool& aPositionSpecified,
                                 const bool& aSizeSpecified,
-                                const nsString& aName,
                                 const nsCString& aFeatures,
                                 const nsCString& aBaseURI,
                                 const DocShellOriginAttributes& aOpenerOriginAttributes,
                                 const float& aFullZoom,
                                 nsresult* aResult,
                                 bool* aWindowIsNew,
                                 InfallibleTArray<FrameScriptInfo>* aFrameScripts,
                                 nsCString* aURLToLoad,
                                 TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                 uint64_t* aLayersId)
 {
   // We always expect to open a new window here. If we don't, it's an error.
   *aWindowIsNew = true;
+  *aResult = NS_OK;
 
   // The content process should never be in charge of computing whether or
   // not a window should be private or remote - the parent will do that.
   const uint32_t badFlags =
         nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW
       | nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW
       | nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME
       | nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
@@ -5312,23 +5312,16 @@ ContentParent::RecvCreateWindow(PBrowser
   if (aThisTab) {
     thisTabParent = TabParent::GetFrom(aThisTab);
   }
 
   if (NS_WARN_IF(thisTabParent && thisTabParent->IsMozBrowserOrApp())) {
     return false;
   }
 
-  nsCOMPtr<nsPIWindowWatcher> pwwatch =
-    do_GetService(NS_WINDOWWATCHER_CONTRACTID, aResult);
-
-  if (NS_WARN_IF(NS_FAILED(*aResult))) {
-    return true;
-  }
-
   TabParent* newTab = TabParent::GetFrom(aNewTab);
   MOZ_ASSERT(newTab);
 
   // Content has requested that we open this new content window, so
   // we must have an opener.
   newTab->SetHasContentOpener(true);
 
   nsCOMPtr<nsIContent> frame;
@@ -5412,53 +5405,32 @@ ContentParent::RecvCreateWindow(PBrowser
     }
 
     return true;
   }
 
   nsCOMPtr<mozIDOMWindowProxy> window;
   TabParent::AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
 
-  const char* features = aFeatures.IsVoid() ? nullptr : aFeatures.get();
-
-  *aResult = pwwatch->OpenWindow2(parent, nullptr,
-                                  aName.IsVoid() ?
-                                    nullptr :
-                                    NS_ConvertUTF16toUTF8(aName).get(),
-                                  features, aCalledFromJS,
-                                  false, false, thisTabParent, nullptr,
-                                  aFullZoom, 1, getter_AddRefs(window));
-
-  if (NS_WARN_IF(!window)) {
-    return true;
-  }
-
-  *aResult = NS_ERROR_FAILURE;
-  auto* pwindow = nsPIDOMWindowOuter::From(window);
-  nsCOMPtr<nsIDocShell> windowDocShell = pwindow->GetDocShell();
-  if (NS_WARN_IF(!windowDocShell)) {
-    return true;
-  }
-
-  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
-  windowDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
-
-  nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(treeOwner);
-  if (NS_WARN_IF(!xulWin)) {
-    return true;
-  }
-
-  nsCOMPtr<nsIXULBrowserWindow> xulBrowserWin;
-  xulWin->GetXULBrowserWindow(getter_AddRefs(xulBrowserWin));
-  if (NS_WARN_IF(!xulBrowserWin)) {
+  nsCOMPtr<nsPIWindowWatcher> pwwatch =
+    do_GetService(NS_WINDOWWATCHER_CONTRACTID, aResult);
+
+  if (NS_WARN_IF(NS_FAILED(*aResult))) {
     return true;
   }
 
   nsCOMPtr<nsITabParent> newRemoteTab;
-  *aResult = xulBrowserWin->ForceInitialBrowserRemote(getter_AddRefs(newRemoteTab));
+  if (!thisTabParent) {
+    // Because we weren't passed an opener tab, the content process has asked us
+    // to open a new window that is unrelated to a pre-existing tab.
+    *aResult = pwwatch->OpenWindowWithoutParent(getter_AddRefs(newRemoteTab));
+  } else {
+    *aResult = pwwatch->OpenWindowWithTabParent(thisTabParent, aFeatures, aCalledFromJS,
+                                                aFullZoom, getter_AddRefs(newRemoteTab));
+  }
 
   if (NS_WARN_IF(NS_FAILED(*aResult))) {
     return true;
   }
 
   MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab);
 
   newTab->SwapFrameScriptsFrom(*aFrameScripts);
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -555,17 +555,16 @@ public:
 
   virtual bool RecvCreateWindow(PBrowserParent* aThisTabParent,
                                 PBrowserParent* aOpener,
                                 layout::PRenderFrameParent* aRenderFrame,
                                 const uint32_t& aChromeFlags,
                                 const bool& aCalledFromJS,
                                 const bool& aPositionSpecified,
                                 const bool& aSizeSpecified,
-                                const nsString& aName,
                                 const nsCString& aFeatures,
                                 const nsCString& aBaseURI,
                                 const DocShellOriginAttributes& aOpenerOriginAttributes,
                                 const float& aFullZoom,
                                 nsresult* aResult,
                                 bool* aWindowIsNew,
                                 InfallibleTArray<FrameScriptInfo>* aFrameScripts,
                                 nsCString* aURLToLoad,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1137,17 +1137,16 @@ parent:
 
     sync CreateWindow(nullable PBrowser aThisTab,
                       PBrowser aNewTab,
                       PRenderFrame aRenderFrame,
                       uint32_t aChromeFlags,
                       bool aCalledFromJS,
                       bool aPositionSpecified,
                       bool aSizeSpecified,
-                      nsString aName,
                       nsCString aFeatures,
                       nsCString aBaseURI,
                       DocShellOriginAttributes aOpenerOriginAttributes,
                       float aFullZoom)
       returns (nsresult rv,
                bool windowOpened,
                FrameScriptInfo[] frameScripts,
                nsCString urlToLoad,
--- a/dom/ipc/tests/mochitest.ini
+++ b/dom/ipc/tests/mochitest.ini
@@ -17,43 +17,43 @@ skip-if = buildapp == 'b2g' || buildapp 
 skip-if = toolkit != 'gonk'
 [test_NuwaProcessDeadlock.html]
 skip-if = toolkit != 'gonk'
 [test_child_docshell.html]
 skip-if = toolkit == 'cocoa' # disabled due to hangs, see changeset 6852e7c47edf
 [test_CrashService_crash.html]
 skip-if = !(crashreporter && !e10s && (toolkit == 'gtk2' || toolkit == 'gtk3' || toolkit == 'cocoa' || toolkit == 'windows') && (buildapp != 'b2g' || toolkit == 'gonk') && (buildapp != 'mulet')) # TC: Bug 1144079 - Re-enable Mulet mochitests and reftests taskcluster-specific disables.
 [test_permission_for_in_process_app.html]
-skip-if = e10s || (buildapp != 'b2g' && buildapp != 'mulet') || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
+skip-if = e10s || true || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app  ### Bug 1255339: blacklist because no more mozApps
 support-files =
   test_permission_helper.js
 [test_permission_for_oop_app.html]
-skip-if = (buildapp != 'b2g' && buildapp != 'mulet') || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
+skip-if = true || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app  ### Bug 1255339: blacklist because no more mozApps
 support-files =
   file_app.sjs
   file_app.template.webapp
   test_permission_helper.js
   test_permission_embed.html
   test_permission_framescript.js
 [test_permission_for_nested_oop_app.html]
-skip-if = (buildapp != 'b2g' && buildapp != 'mulet') || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
+skip-if = true || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app  ### Bug 1255339: blacklist because no more mozApps
 support-files =
   file_app.sjs
   file_app.template.webapp
   test_permission_helper.js
   test_permission_embed.html
   test_permission_framescript.js
 [test_permission_for_two_oop_apps.html]
-skip-if = (buildapp != 'b2g' && buildapp != 'mulet') || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
+skip-if = true || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app  ### Bug 1255339: blacklist because no more mozApps
 support-files =
   file_app.sjs
   file_app.template.webapp
   test_permission_helper.js
   test_permission_embed.html
   test_permission_framescript.js
 [test_permission_when_oop_app_crashes.html]
-skip-if = buildapp != 'b2g' || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app
+skip-if = true || os == "android" || toolkit == "gonk" # embed-apps doesn't work in mochitest app  ### Bug 1255339: blacklist because no more mozApps
 support-files =
   file_app.sjs
   file_app.template.webapp
   test_permission_helper.js
   test_permission_embed.html
   test_permission_framescript.js
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -119,16 +119,18 @@ MediaLoadSourceMediaNotMatched=Specified “media” attribute of “%1$S” does not match the environment. Load of media resource %2$S failed.
 # LOCALIZATION NOTE: %1$S is the MIME type HTTP header being sent by the web server, %2$S is the URL of the media resource which failed to load.
 MediaLoadUnsupportedMimeType=HTTP “Content-Type” of “%1$S” is not supported. Load of media resource %2$S failed.
 # LOCALIZATION NOTE: %S is the URL of the media resource which failed to load because of error in decoding.
 MediaLoadDecodeError=Media resource %S could not be decoded.
 MediaWidevineNoWMFNoSilverlight=Trying to play Widevine with no Windows Media Foundation (nor Silverlight fallback), see https://support.mozilla.org/kb/fix-video-audio-problems-firefox-windows
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaWMFNeeded=To play video formats %S, you need to install extra Microsoft software, see https://support.mozilla.org/kb/fix-video-audio-problems-firefox-windows
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
+MediaUnsupportedBeforeWindowsVista=Video formats %S unsupported by Microsoft before Windows Vista
+# LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaPlatformDecoderNotFound=The video on this page can’t be played. Your system may not have the required video codecs for: %S
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaCannotPlayNoDecoders=Cannot play media. No decoders for requested formats: %S
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaNoDecoders=No decoders for some of the requested formats: %S
 # LOCALIZATION NOTE: Do not translate "MediaRecorder".
 MediaRecorderMultiTracksNotSupported=MediaRecorder does not support recording multiple tracks of the same type at this time.
 # LOCALIZATION NOTE: %S is the ID of the MediaStreamTrack passed to MediaStream.addTrack(). Do not translate "MediaStreamTrack" and "AudioChannel".
--- a/dom/media/DecoderDoctorDiagnostics.cpp
+++ b/dom/media/DecoderDoctorDiagnostics.cpp
@@ -14,27 +14,33 @@
 #include "nsIDocument.h"
 #include "nsIObserverService.h"
 #include "nsIScriptError.h"
 #include "nsITimer.h"
 #include "nsIWeakReference.h"
 #include "nsPluginHost.h"
 #include "VideoUtils.h"
 
+#if defined(XP_WIN)
+#include "mozilla/WindowsVersion.h"
+#endif
+
 static mozilla::LazyLogModule sDecoderDoctorLog("DecoderDoctor");
 #define DD_LOG(level, arg, ...) MOZ_LOG(sDecoderDoctorLog, level, (arg, ##__VA_ARGS__))
 #define DD_DEBUG(arg, ...) DD_LOG(mozilla::LogLevel::Debug, arg, ##__VA_ARGS__)
 #define DD_INFO(arg, ...) DD_LOG(mozilla::LogLevel::Info, arg, ##__VA_ARGS__)
 #define DD_WARN(arg, ...) DD_LOG(mozilla::LogLevel::Warning, arg, ##__VA_ARGS__)
 
 namespace mozilla {
 
 struct NotificationAndReportStringId
 {
+  // Notification type, handled by browser-media.js.
   dom::DecoderDoctorNotificationType mNotificationType;
+  // Console message id. Key in dom/locales/.../chrome/dom/dom.properties.
   const char* mReportStringId;
 };
 
 // Class that collects a sequence of diagnostics from the same document over a
 // small period of time, in order to provide a synthesized analysis.
 //
 // Referenced by the document through a nsINode property, mTimer, and
 // inter-task captures.
@@ -244,31 +250,35 @@ DecoderDoctorDocumentWatcher::EnsureTime
 }
 
 static const NotificationAndReportStringId sMediaWidevineNoWMFNoSilverlight =
   { dom::DecoderDoctorNotificationType::Platform_decoder_not_found,
     "MediaWidevineNoWMFNoSilverlight" };
 static const NotificationAndReportStringId sMediaWMFNeeded =
   { dom::DecoderDoctorNotificationType::Platform_decoder_not_found,
     "MediaWMFNeeded" };
+static const NotificationAndReportStringId sMediaUnsupportedBeforeWindowsVista =
+  { dom::DecoderDoctorNotificationType::Platform_decoder_not_found,
+    "MediaUnsupportedBeforeWindowsVista" };
 static const NotificationAndReportStringId sMediaPlatformDecoderNotFound =
   { dom::DecoderDoctorNotificationType::Platform_decoder_not_found,
     "MediaPlatformDecoderNotFound" };
 static const NotificationAndReportStringId sMediaCannotPlayNoDecoders =
   { dom::DecoderDoctorNotificationType::Cannot_play,
     "MediaCannotPlayNoDecoders" };
 static const NotificationAndReportStringId sMediaNoDecoders =
   { dom::DecoderDoctorNotificationType::Can_play_but_some_missing_decoders,
     "MediaNoDecoders" };
 
 static const NotificationAndReportStringId*
 sAllNotificationsAndReportStringIds[] =
 {
   &sMediaWidevineNoWMFNoSilverlight,
   &sMediaWMFNeeded,
+  &sMediaUnsupportedBeforeWindowsVista,
   &sMediaPlatformDecoderNotFound,
   &sMediaCannotPlayNoDecoders,
   &sMediaNoDecoders
 };
 
 static void
 DispatchNotification(nsISupports* aSubject,
                      const NotificationAndReportStringId& aNotification,
@@ -537,19 +547,25 @@ DecoderDoctorDocumentWatcher::Synthesize
   // Next, check playability of requested formats.
   if (!unplayableFormats.IsEmpty()) {
     // Some requested formats cannot be played.
     if (playableFormats.IsEmpty()) {
       // No requested formats can be played. See if we can help the user, by
       // going through expected decoders from most to least desirable.
 #if defined(XP_WIN)
       if (!formatsRequiringWMF.IsEmpty()) {
-        DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> Cannot play media because WMF was not found",
-                this, mDocument, NS_ConvertUTF16toUTF8(formatsRequiringWMF).get());
-        ReportAnalysis(sMediaWMFNeeded, false, formatsRequiringWMF);
+        if (IsVistaOrLater()) {
+          DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> Cannot play media because WMF was not found",
+                  this, mDocument, NS_ConvertUTF16toUTF8(formatsRequiringWMF).get());
+          ReportAnalysis(sMediaWMFNeeded, false, formatsRequiringWMF);
+        } else {
+          DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> Cannot play media before Windows Vista",
+                  this, mDocument, NS_ConvertUTF16toUTF8(formatsRequiringWMF).get());
+          ReportAnalysis(sMediaUnsupportedBeforeWindowsVista, false, formatsRequiringWMF);
+        }
         return;
       }
 #endif
 #if defined(MOZ_FFMPEG)
       if (!formatsRequiringFFMpeg.IsEmpty()) {
         DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::SynthesizeAnalysis() - unplayable formats: %s -> Cannot play media because platform decoder was not found",
                 this, mDocument, NS_ConvertUTF16toUTF8(formatsRequiringFFMpeg).get());
         ReportAnalysis(sMediaPlatformDecoderNotFound,
--- a/dom/media/eme/MediaKeySystemAccessManager.cpp
+++ b/dom/media/eme/MediaKeySystemAccessManager.cpp
@@ -258,18 +258,41 @@ MediaKeySystemAccessManager::RetryReques
 
 nsresult
 MediaKeySystemAccessManager::Observe(nsISupports* aSubject,
                                      const char* aTopic,
                                      const char16_t* aData)
 {
   EME_LOG("MediaKeySystemAccessManager::Observe %s", aTopic);
 
-  if (!strcmp(aTopic, "gmp-path-added")) {
-    nsTArray<PendingRequest> requests(Move(mRequests));
+  if (!strcmp(aTopic, "gmp-changed")) {
+    // Filter out the requests where the CDM's install-status is no longer
+    // "unavailable". This will be the CDMs which have downloaded since the
+    // initial request.
+    // Note: We don't have a way to communicate from chrome that the CDM has
+    // failed to download, so we'll just let the timeout fail us in that case.
+    nsTArray<PendingRequest> requests;
+    for (size_t i = mRequests.Length(); i > 0; i--) {
+      const size_t index = i - i;
+      PendingRequest& request = mRequests[index];
+      nsAutoCString message;
+      nsAutoCString cdmVersion;
+      MediaKeySystemStatus status =
+        MediaKeySystemAccess::GetKeySystemStatus(request.mKeySystem,
+                                                 NO_CDM_VERSION,
+                                                 message,
+                                                 cdmVersion);
+      if (status == MediaKeySystemStatus::Cdm_not_installed) {
+        // Not yet installed, don't retry. Keep waiting until timeout.
+        continue;
+      }
+      // Status has changed, retry request.
+      requests.AppendElement(Move(request));
+      mRequests.RemoveElementAt(index);
+    }
     // Retry all pending requests, but this time fail if the CDM is not installed.
     for (PendingRequest& request : requests) {
       RetryRequest(request);
     }
   } else if (!strcmp(aTopic, "timer-callback")) {
     // Find the timer that expired and re-run the request for it.
     nsCOMPtr<nsITimer> timer(do_QueryInterface(aSubject));
     for (size_t i = 0; i < mRequests.Length(); i++) {
@@ -291,33 +314,33 @@ MediaKeySystemAccessManager::EnsureObser
   if (mAddedObservers) {
     return true;
   }
 
   nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
   if (NS_WARN_IF(!obsService)) {
     return false;
   }
-  mAddedObservers = NS_SUCCEEDED(obsService->AddObserver(this, "gmp-path-added", false));
+  mAddedObservers = NS_SUCCEEDED(obsService->AddObserver(this, "gmp-changed", false));
   return mAddedObservers;
 }
 
 void
 MediaKeySystemAccessManager::Shutdown()
 {
   EME_LOG("MediaKeySystemAccessManager::Shutdown");
   nsTArray<PendingRequest> requests(Move(mRequests));
   for (PendingRequest& request : requests) {
     // Cancel all requests; we're shutting down.
     request.CancelTimer();
     request.RejectPromise(NS_LITERAL_CSTRING("Promise still outstanding at MediaKeySystemAccessManager shutdown"));
   }
   if (mAddedObservers) {
     nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
     if (obsService) {
-      obsService->RemoveObserver(this, "gmp-path-added");
+      obsService->RemoveObserver(this, "gmp-changed");
       mAddedObservers = false;
     }
   }
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -1102,17 +1102,16 @@ GeckoMediaPluginServiceParent::AddOnGMPT
   RefPtr<GeckoMediaPluginServiceParent> self(this);
   return gmp->Init(this, directory)->Then(thread, __func__,
     [gmp, self, dir]() -> void {
       LOGD(("%s::%s: %s Succeeded", __CLASS__, __FUNCTION__, dir.get()));
       {
         MutexAutoLock lock(self->mMutex);
         self->mPlugins.AppendElement(gmp);
       }
-      NS_DispatchToMainThread(new NotifyObserversTask("gmp-path-added"), NS_DISPATCH_NORMAL);
     },
     [dir]() -> void {
       LOGD(("%s::%s: %s Failed", __CLASS__, __FUNCTION__, dir.get()));
     })
     ->CompletionPromise();
 }
 
 void
--- a/dom/security/test/csp/chrome.ini
+++ b/dom/security/test/csp/chrome.ini
@@ -1,7 +1,7 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g' || os == 'android'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 support-files =
   !/dom/security/test/csp/file_bug768029.html
 
 [test_bug768029.html]
 [test_bug773891.html]
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -215,17 +215,17 @@ skip-if = (buildapp == 'b2g' && (toolkit
 skip-if = buildapp == 'b2g' # http-on-opening-request observers are not available in child processes
 [test_hash_source.html]
 skip-if = buildapp == 'b2g' # can't compute hashes in child process (bug 958702)
 [test_scheme_relative_sources.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_ignore_unsafe_inline.html]
 [test_self_none_as_hostname_confusion.html]
 [test_bug949549.html]
-skip-if = buildapp != 'b2g' && buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_path_matching.html]
 [test_path_matching_redirect.html]
 [test_report_uri_missing_in_report_only_header.html]
 [test_report.html]
 [test_301_redirect.html]
 skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490)
 [test_302_redirect.html]
 skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490)
--- a/dom/tests/mochitest/fetch/mochitest.ini
+++ b/dom/tests/mochitest/fetch/mochitest.ini
@@ -30,17 +30,17 @@ support-files =
   !/dom/html/test/form_submit_server.sjs
   !/dom/security/test/cors/file_CrossSiteXHR_server.sjs
 
 [test_headers.html]
 [test_headers_sw_reroute.html]
 skip-if = buildapp == 'b2g' # Bug 1137683
 [test_headers_mainthread.html]
 [test_fetch_app_protocol.html]
-skip-if = (buildapp != 'b2g' && buildapp != 'mulet')
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_fetch_basic.html]
 [test_fetch_basic_sw_reroute.html]
 skip-if = buildapp == 'b2g' # Bug 1137683
 [test_fetch_basic_sw_empty_reroute.html]
 skip-if = buildapp == 'b2g'
 [test_fetch_basic_http.html]
 [test_fetch_basic_http_sw_reroute.html]
 skip-if = buildapp == 'b2g' # Bug 1137683
--- a/dom/tests/mochitest/localstorage/mochitest.ini
+++ b/dom/tests/mochitest/localstorage/mochitest.ini
@@ -14,17 +14,17 @@ support-files =
   frameSlaveNotEqual.html
   interOriginFrame.js
   interOriginTest.js
   interOriginTest2.js
   localStorageCommon.js
   frameLocalStorageSessionOnly.html
 
 [test_appIsolation.html]
-skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 793211 # b2g(needs https to work) b2g-debug(needs https to work) b2g-desktop(needs https to work)
+skip-if = true || buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s #bug 793211 # b2g(needs https to work) b2g-debug(needs https to work) b2g-desktop(needs https to work) ### Bug 1255339: blacklist because no more mozApps
 [test_brokenUTF-16.html]
 [test_bug600307-DBOps.html]
 [test_bug746272-1.html]
 [test_bug746272-2.html]
 skip-if = os == "android" || toolkit == 'gonk' # bug 962029
 [test_cookieBlock.html]
 skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(bug 913706) b2g-desktop(bug 913706)
 [test_cookieSession.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/pointerlock/file_changeLockElement.html
@@ -0,0 +1,115 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 1284788</title>
+  <script src="/tests/SimpleTest/EventUtils.js"></script>
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script src="pointerlock_utils.js"></script>
+  <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+  <style>
+    #block1, #block2, #block3 {
+      background: blue;
+      width: 50px; height: 50px;
+      margin: 10px;
+    }
+  </style>
+</head>
+<body>
+  <div id="block1"></div>
+  <div id="block2"></div>
+  <div id="block3"></div>
+  <div id="test">
+    <script>
+      SimpleTest.waitForExplicitFinish();
+      SimpleTest.requestFlakyTimeout("For changing pointer lock element not in a valid user event handler");
+
+      var block1 = document.getElementById("block1");
+      var block2 = document.getElementById("block2");
+      var block3 = document.getElementById("block3");
+
+      class ClickTester {
+        constructor(target) {
+          this._target = target;
+          this._callback = null;
+          document.addEventListener("click", this);
+        }
+
+        synthesize(callback) {
+          ok(!this._callback, "No callback should have been hooked");
+          this._callback = callback;
+          synthesizeMouseAtCenter(this._target, {}, window);
+        }
+
+        handleEvent(e) {
+          ok(!!this._callback, "Should have hooked a callback");
+          var callback = this._callback;
+          this._callback = null;
+          callback(e);
+        }
+      };
+
+      var tester = new ClickTester(block3);
+      // It would be called in handler of load event in pointerlock_utils.js
+      function start() {
+        tester.synthesize(firstClick);
+      }
+
+      function firstClick(e) {
+        is(e.target, block3, "Click is triggered inside block3");
+        document.addEventListener("mozpointerlockchange", lockedPointerOnBlock1);
+        block1.mozRequestPointerLock();
+      }
+
+      function lockedPointerOnBlock1() {
+        document.removeEventListener("mozpointerlockchange", lockedPointerOnBlock1);
+        is(document.mozPointerLockElement, block1, "Pointer should be locked on #block1");
+        SimpleTest.executeSoon(() => {
+          tester.synthesize(secondClick);
+        });
+      }
+
+      function secondClick(e) {
+        is(e.target, block1, "Event should be redirected to block1");
+        // Use 2s to ensure that we never consider this as an extension of user input.
+        setTimeout(() => {
+          document.addEventListener("mozpointerlockchange", lockedPointerOnBlock2);
+          block2.mozRequestPointerLock();
+        }, 2000);
+      }
+
+      function lockedPointerOnBlock2() {
+        document.removeEventListener("mozpointerlockchange", lockedPointerOnBlock2);
+        is(document.mozPointerLockElement, block2, "Pointer should be locked on #block2");
+        SimpleTest.executeSoon(() => {
+          tester.synthesize(thirdClick);
+        });
+      }
+
+      function thirdClick(e) {
+        is(e.target, block2, "Event should be redirected to block2");
+        // Use 2s to ensure that we never consider this as an extension of user input.
+        setTimeout(() => {
+          document.addEventListener("mozpointerlockchange", lockedPointerOnBlock1Again);
+          block1.mozRequestPointerLock();
+        }, 2000);
+      }
+
+      function lockedPointerOnBlock1Again() {
+        document.removeEventListener("mozpointerlockchange", lockedPointerOnBlock1Again);
+        is(document.mozPointerLockElement, block1, "Pointer should be locked on #block1 again");
+        SimpleTest.executeSoon(() => {
+          tester.synthesize(fourthClick);
+        });
+      }
+
+      function fourthClick(e) {
+        is(e.target, block1, "Event should be redirected to block1 again");
+        document.addEventListener("mozpointerlockchange", () => SimpleTest.finish());
+        document.mozExitPointerLock();
+      }
+
+    </script>
+  </div>
+</body>
+</html>
--- a/dom/tests/mochitest/pointerlock/mochitest.ini
+++ b/dom/tests/mochitest/pointerlock/mochitest.ini
@@ -13,13 +13,14 @@ support-files =
   file_movementXY.html
   file_infiniteMovement.html
   file_retargetMouseEvents.html
   file_targetOutOfFocus.html
   file_screenClientXYConst.html
   file_suppressSomeMouseEvents.html
   file_locksvgelement.html
   file_allowPointerLockSandboxFlag.html
+  file_changeLockElement.html
   iframe_differentDOM.html
 
 [test_pointerlock-api.html]
 tags = fullscreen
 skip-if = buildapp == 'b2g' || toolkit == 'android' || os == 'win' # B2G - window.open focus issues using fullscreen. Win: Bug 931445
--- a/dom/tests/mochitest/pointerlock/test_pointerlock-api.html
+++ b/dom/tests/mochitest/pointerlock/test_pointerlock-api.html
@@ -51,17 +51,18 @@ https://bugzilla.mozilla.org/show_bug.cg
           "file_pointerlock-api.html",
           "file_pointerlockerror.html",
           "file_pointerLockPref.html",
           "file_removedFromDOM.html",
           "file_retargetMouseEvents.html",
           "file_suppressSomeMouseEvents.html",
           "file_targetOutOfFocus.html",
           "file_withoutDOM.html",
-          "file_allowPointerLockSandboxFlag.html"
+          "file_allowPointerLockSandboxFlag.html",
+          "file_changeLockElement.html",
         ];
 
         var gDisableList = [
         ];
 
         var gTestWindow = null;
         var gTestIndex = 0;
 
--- a/dom/workers/ServiceWorkerClients.cpp
+++ b/dom/workers/ServiceWorkerClients.cpp
@@ -601,17 +601,17 @@ private:
       nsCString spec;
       uri->GetSpec(spec);
 
       nsCOMPtr<mozIDOMWindowProxy> newWindow;
       pwwatch->OpenWindow2(nullptr,
                            spec.get(),
                            nullptr,
                            nullptr,
-                           false, false, true, nullptr, nullptr, 1.0f, 0,
+                           false, false, true, nullptr, 1.0f, 0,
                            getter_AddRefs(newWindow));
       nsCOMPtr<nsPIDOMWindowOuter> pwindow = nsPIDOMWindowOuter::From(newWindow);
       pwindow.forget(aWindow);
       return NS_OK;
     }
 
     // Find the most recent browser window and open a new tab in it.
     nsCOMPtr<nsPIDOMWindowOuter> browserWindow =
--- a/dom/xul/nsXULPopupListener.cpp
+++ b/dom/xul/nsXULPopupListener.cpp
@@ -237,17 +237,17 @@ nsXULPopupListener::FireFocusOnTargetCon
     // XXXbz between what events?  We don't use this local at all!
     RefPtr<nsPresContext> context = shell->GetPresContext();
  
     nsCOMPtr<nsIContent> content = do_QueryInterface(aTargetNode);
     nsIFrame* targetFrame = content->GetPrimaryFrame();
     if (!targetFrame) return NS_ERROR_FAILURE;
 
     const nsStyleUserInterface* ui = targetFrame->StyleUserInterface();
-    bool suppressBlur = (ui->mUserFocus == NS_STYLE_USER_FOCUS_IGNORE);
+    bool suppressBlur = (ui->mUserFocus == StyleUserFocus::Ignore);
 
     nsCOMPtr<nsIDOMElement> element;
     nsCOMPtr<nsIContent> newFocus = do_QueryInterface(content);
 
     nsIFrame* currFrame = targetFrame;
     // Look for the nearest enclosing focusable frame.
     while (currFrame) {
         int32_t tabIndexUnused;
--- a/embedding/browser/nsDocShellTreeOwner.cpp
+++ b/embedding/browser/nsDocShellTreeOwner.cpp
@@ -439,16 +439,44 @@ nsDocShellTreeOwner::GetPrimaryTabParent
   }
 
   nsCOMPtr<nsITabParent> tab = mPrimaryTabParent;
   tab.forget(aTab);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocShellTreeOwner::GetPrimaryContentSize(int32_t* aWidth,
+                                           int32_t* aHeight)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsDocShellTreeOwner::SetPrimaryContentSize(int32_t aWidth,
+                                           int32_t aHeight)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsDocShellTreeOwner::GetRootShellSize(int32_t* aWidth,
+                                      int32_t* aHeight)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsDocShellTreeOwner::SetRootShellSize(int32_t aWidth,
+                                      int32_t aHeight)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem,
                                  int32_t aCX, int32_t aCY)
 {
   nsCOMPtr<nsIWebBrowserChrome> webBrowserChrome = GetWebBrowserChrome();
 
   NS_ENSURE_STATE(mTreeOwner || webBrowserChrome);
 
   if (mTreeOwner) {
@@ -532,16 +560,23 @@ nsDocShellTreeOwner::GetTargetableShellC
     mTreeOwner->GetTargetableShellCount(aResult);
   } else {
     *aResult = 0;
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDocShellTreeOwner::GetHasPrimaryContent(bool* aResult)
+{
+  *aResult = mPrimaryTabParent || mPrimaryContentShell;
+  return NS_OK;
+}
+
 //*****************************************************************************
 // nsDocShellTreeOwner::nsIBaseWindow
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow,
                                 nsIWidget* aParentWidget, int32_t aX,
                                 int32_t aY, int32_t aCX, int32_t aCY)
--- a/embedding/components/windowwatcher/moz.build
+++ b/embedding/components/windowwatcher/moz.build
@@ -40,8 +40,10 @@ FINAL_LIBRARY = 'xul'
 # For nsJSUtils
 LOCAL_INCLUDES += [
     '/docshell/base',
     '/dom/base',
 ]
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
+
+include('/ipc/chromium/chromium-config.mozbuild')
--- a/embedding/components/windowwatcher/nsPIWindowWatcher.idl
+++ b/embedding/components/windowwatcher/nsPIWindowWatcher.idl
@@ -49,19 +49,16 @@ interface nsPIWindowWatcher : nsISupport
       @param aName window name from JS window.open. can be null.  If a window
              with this name already exists, the openWindow call may just load
              aUrl in it (if aUrl is not null) and return it.
       @param aFeatures window features from JS window.open. can be null.
       @param aCalledFromScript true if we were called from script.
       @param aDialog use dialog defaults (see nsIDOMWindow::openDialog)
       @param aNavigate true if we should navigate the new window to the
              specified URL.
-      @param aOpeningTab the nsITabParent that is opening the new window. The
-                         nsITabParent is a remote tab belonging to aParent. Can
-                         be nullptr if this window is not being opened from a tab.
       @param aArgs Window argument
       @param aOpenerFullZoom the full zoom multiplier for the opener window.
                              this can be null in the single process case where
                              the opener full zoom is obtained from aParent.
       @return the new window
 
       @note This method may examine the JS context stack for purposes of
             determining the security context to use for the search for a given
@@ -72,21 +69,52 @@ interface nsPIWindowWatcher : nsISupport
             aParent).  This is not guaranteed, however.
   */
   [optional_argc]
   mozIDOMWindowProxy openWindow2(in mozIDOMWindowProxy aParent, in string aUrl,
                                  in string aName, in string aFeatures,
                                  in boolean aCalledFromScript,
                                  in boolean aDialog,
                                  in boolean aNavigate,
-                                 in nsITabParent aOpeningTab,
                                  in nsISupports aArgs,
                                  [optional] in float aOpenerFullZoom);
 
   /**
+   * Opens a new window using the most recent non-private browser
+   * window as its parent.
+   *
+   * @return the nsITabParent of the initial browser for the newly opened
+   *         window.
+   */
+  nsITabParent openWindowWithoutParent();
+
+  /**
+   * Opens a new window so that the window that aOpeningTab belongs to
+   * is set as the parent window. The newly opened window will also
+   * inherit load context information from aOpeningTab.
+   *
+   * @param aOpeningTab
+   *        The nsITabParent that is requesting the new window be opened.
+   * @param aFeatures
+   *        Window features if called with window.open or similar.
+   * @param aCalledFromJS
+   *        True if called via window.open or similar.
+   * @param aOpenerFullZoom
+   *        The current zoom multiplier for the opener tab. This is then
+   *        applied to the newly opened window.
+   *
+   * @return the nsITabParent of the initial browser for the newly opened
+   *         window.
+   */
+  nsITabParent openWindowWithTabParent(in nsITabParent aOpeningTab,
+                                       in ACString aFeatures,
+                                       in boolean aCalledFromJS,
+                                       in float aOpenerFullZoom);
+
+  /**
    * Find a named docshell tree item amongst all windows registered
    * with the window watcher.  This may be a subframe in some window,
    * for example.
    *
    * @param aName the name of the window.  Must not be null.
    * @param aRequestor the tree item immediately making the request.
    *        We should make sure to not recurse down into its findItemWithName
    *        method.
--- a/embedding/components/windowwatcher/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp
@@ -59,16 +59,19 @@
 #include "nsPresContext.h"
 #include "nsContentUtils.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsSandboxFlags.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/DOMStorage.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/dom/TabParent.h"
+#include "nsIXULWindow.h"
+#include "nsIXULBrowserWindow.h"
 
 #ifdef USEWEAKREFS
 #include "nsIWeakReference.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
@@ -363,17 +366,17 @@ nsWindowWatcher::OpenWindow(mozIDOMWindo
   uint32_t argc = 0;
   if (argv) {
     argv->GetLength(&argc);
   }
   bool dialog = (argc != 0);
 
   return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
                             /* calledFromJS = */ false, dialog,
-                            /* navigate = */ true, nullptr, argv,
+                            /* navigate = */ true, argv,
                             /* openerFullZoom = */ nullptr, aResult);
 }
 
 struct SizeSpec
 {
   SizeSpec()
     : mLeftSpecified(false)
     , mTopSpecified(false)
@@ -420,17 +423,16 @@ struct SizeSpec
 NS_IMETHODIMP
 nsWindowWatcher::OpenWindow2(mozIDOMWindowProxy* aParent,
                              const char* aUrl,
                              const char* aName,
                              const char* aFeatures,
                              bool aCalledFromScript,
                              bool aDialog,
                              bool aNavigate,
-                             nsITabParent* aOpeningTab,
                              nsISupports* aArguments,
                              float aOpenerFullZoom,
                              uint8_t aOptionalArgc,
                              mozIDOMWindowProxy** aResult)
 {
   nsCOMPtr<nsIArray> argv = ConvertArgsToArray(aArguments);
 
   uint32_t argc = 0;
@@ -443,17 +445,17 @@ nsWindowWatcher::OpenWindow2(mozIDOMWind
   // called from script.  Fixing this is bug 779939.
   bool dialog = aDialog;
   if (!aCalledFromScript) {
     dialog = argc > 0;
   }
 
   return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
                             aCalledFromScript, dialog,
-                            aNavigate, aOpeningTab, argv,
+                            aNavigate, argv,
                             aOptionalArgc >= 1 ? &aOpenerFullZoom : nullptr,
                             aResult);
 }
 
 // This static function checks if the aDocShell uses an UserContextId equal to
 // the userContextId of subjectPrincipal, if not null.
 static bool
 CheckUserContextCompatibility(nsIDocShell* aDocShell)
@@ -481,104 +483,280 @@ CheckUserContextCompatibility(nsIDocShel
 
   uint32_t principalUserContextId;
   nsresult rv = subjectPrincipal->GetUserContextId(&principalUserContextId);
   NS_ENSURE_SUCCESS(rv, false);
 
   return principalUserContextId == userContextId;
 }
 
+NS_IMETHODIMP
+nsWindowWatcher::OpenWindowWithoutParent(nsITabParent** aResult)
+{
+  return OpenWindowWithTabParent(nullptr, EmptyCString(), true, 1.0f, aResult);
+}
+
+nsresult
+nsWindowWatcher::CreateChromeWindow(const nsACString& aFeatures,
+                                    nsIWebBrowserChrome* aParentChrome,
+                                    uint32_t aChromeFlags,
+                                    uint32_t aContextFlags,
+                                    nsITabParent* aOpeningTabParent,
+                                    nsIWebBrowserChrome** aResult)
+{
+  nsCOMPtr<nsIWindowCreator2> windowCreator2(do_QueryInterface(mWindowCreator));
+  if (NS_WARN_IF(!windowCreator2)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  // B2G multi-screen support. mozDisplayId is returned from the
+  // "display-changed" event, it is also platform-dependent.
+#ifdef MOZ_WIDGET_GONK
+  int retval = WinHasOption(aFeatures, "mozDisplayId", 0, nullptr);
+  windowCreator2->SetScreenId(retval);
+#endif
+
+  bool cancel = false;
+  nsCOMPtr<nsIWebBrowserChrome> newWindowChrome;
+  nsresult rv =
+    windowCreator2->CreateChromeWindow2(aParentChrome, aChromeFlags, aContextFlags,
+                                        aOpeningTabParent, &cancel,
+                                        getter_AddRefs(newWindowChrome));
+
+  if (NS_SUCCEEDED(rv) && cancel) {
+    newWindowChrome = nullptr;
+    return NS_ERROR_ABORT;
+  }
+
+  newWindowChrome.forget(aResult);
+  return NS_OK;
+}
+
+/**
+ * Disable persistence of size/position in popups (determined by
+ * determining whether the features parameter specifies width or height
+ * in any way). We consider any overriding of the window's size or position
+ * in the open call as disabling persistence of those attributes.
+ * Popup windows (which should not persist size or position) generally set
+ * the size.
+ *
+ * @param aFeatures
+ *        The features string that was used to open the window.
+ * @param aTreeOwner
+ *        The nsIDocShellTreeOwner of the newly opened window. If null,
+ *        this function is a no-op.
+ */
+void
+nsWindowWatcher::MaybeDisablePersistence(const nsACString& aFeatures,
+                                         nsIDocShellTreeOwner* aTreeOwner)
+{
+  if (!aTreeOwner) {
+    return;
+  }
+
+ // At the moment, the strings "height=" or "width=" never happen
+ // outside a size specification, so we can do this the Q&D way.
+  if (PL_strcasestr(aFeatures.BeginReading(), "width=") ||
+      PL_strcasestr(aFeatures.BeginReading(), "height=")) {
+    aTreeOwner->SetPersistence(false, false, false);
+  }
+}
+
+NS_IMETHODIMP
+nsWindowWatcher::OpenWindowWithTabParent(nsITabParent* aOpeningTabParent,
+                                         const nsACString& aFeatures,
+                                         bool aCalledFromJS,
+                                         float aOpenerFullZoom,
+                                         nsITabParent** aResult)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(mWindowCreator);
+
+  if (!nsContentUtils::IsSafeToRunScript()) {
+    nsContentUtils::WarnScriptWasIgnored(nullptr);
+    return NS_ERROR_FAILURE;
+  }
+
+  if (NS_WARN_IF(!mWindowCreator)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  bool isPrivateBrowsingWindow =
+    Preferences::GetBool("browser.privatebrowsing.autostart");
+
+  nsCOMPtr<nsPIDOMWindowOuter> parentWindowOuter;
+  if (aOpeningTabParent) {
+    // We need to examine the window that aOpeningTabParent belongs to in
+    // order to inform us of what kind of window we're going to open.
+    TabParent* openingTab = TabParent::GetFrom(aOpeningTabParent);
+    parentWindowOuter = openingTab->GetParentWindowOuter();
+
+    // Propagate the privacy status of the parent window, if
+    // available, to the child.
+    if (!isPrivateBrowsingWindow) {
+      nsCOMPtr<nsILoadContext> parentContext = openingTab->GetLoadContext();
+      if (parentContext) {
+        isPrivateBrowsingWindow = parentContext->UsePrivateBrowsing();
+      }
+    }
+  }
+
+  if (!parentWindowOuter) {
+    // We couldn't find a browser window for the opener, so either we
+    // never were passed aOpeningTabParent, the window is closed,
+    // or it's in the process of closing. Either way, we'll use
+    // the most recently opened browser window instead.
+    parentWindowOuter = nsContentUtils::GetMostRecentNonPBWindow();
+  }
+
+  if (NS_WARN_IF(!parentWindowOuter)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
+  GetWindowTreeOwner(parentWindowOuter, getter_AddRefs(parentTreeOwner));
+  if (NS_WARN_IF(!parentTreeOwner)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  nsCOMPtr<nsIWindowCreator2> windowCreator2(do_QueryInterface(mWindowCreator));
+  if (NS_WARN_IF(!windowCreator2)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  uint32_t contextFlags = 0;
+  if (parentWindowOuter->IsLoadingOrRunningTimeout()) {
+    contextFlags |=
+            nsIWindowCreator2::PARENT_IS_LOADING_OR_RUNNING_TIMEOUT;
+  }
+
+  uint32_t chromeFlags = CalculateChromeFlagsForChild(aFeatures);
+
+  // A content process has asked for a new window, which implies
+  // that the new window will need to be remote.
+  chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
+
+  nsCOMPtr<nsIWebBrowserChrome> parentChrome(do_GetInterface(parentTreeOwner));
+  nsCOMPtr<nsIWebBrowserChrome> newWindowChrome;
+
+  CreateChromeWindow(aFeatures, parentChrome, chromeFlags, contextFlags,
+                     aOpeningTabParent, getter_AddRefs(newWindowChrome));
+
+  if (NS_WARN_IF(!newWindowChrome)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  nsCOMPtr<nsIDocShellTreeItem> chromeTreeItem = do_GetInterface(newWindowChrome);
+  if (NS_WARN_IF(!chromeTreeItem)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  nsCOMPtr<nsIDocShellTreeOwner> chromeTreeOwner;
+  chromeTreeItem->GetTreeOwner(getter_AddRefs(chromeTreeOwner));
+  if (NS_WARN_IF(!chromeTreeOwner)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  nsCOMPtr<nsILoadContext> chromeContext = do_QueryInterface(chromeTreeItem);
+  if (NS_WARN_IF(!chromeContext)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  chromeContext->SetPrivateBrowsing(isPrivateBrowsingWindow);
+
+  // Tabs opened from a content process can only open new windows
+  // that will also run with out-of-process tabs.
+  chromeContext->SetRemoteTabs(true);
+
+  MaybeDisablePersistence(aFeatures, chromeTreeOwner);
+
+  SizeSpec sizeSpec;
+  CalcSizeSpec(aFeatures, sizeSpec);
+  SizeOpenedWindow(chromeTreeOwner, parentWindowOuter, false, sizeSpec,
+                   &aOpenerFullZoom);
+
+  nsCOMPtr<nsITabParent> newTabParent;
+  chromeTreeOwner->GetPrimaryTabParent(getter_AddRefs(newTabParent));
+  if (NS_WARN_IF(!newTabParent)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  newTabParent.forget(aResult);
+  return NS_OK;
+}
+
 nsresult
 nsWindowWatcher::OpenWindowInternal(mozIDOMWindowProxy* aParent,
                                     const char* aUrl,
                                     const char* aName,
                                     const char* aFeatures,
                                     bool aCalledFromJS,
                                     bool aDialog,
                                     bool aNavigate,
-                                    nsITabParent* aOpeningTab,
                                     nsIArray* aArgv,
                                     float* aOpenerFullZoom,
                                     mozIDOMWindowProxy** aResult)
 {
   nsresult rv = NS_OK;
   bool isNewToplevelWindow = false;
   bool windowIsNew = false;
   bool windowNeedsName = false;
   bool windowIsModal = false;
   bool uriToLoadIsChrome = false;
   bool windowIsModalContentDialog = false;
 
-  // Opening tabs are only ever passed to OpenWindowInternal if we're opening
-  // a window from a remote tab.
-  bool openedFromRemoteTab = !!aOpeningTab;
-
   uint32_t chromeFlags;
   nsAutoString name;          // string version of aName
   nsAutoCString features;     // string version of aFeatures
   nsCOMPtr<nsIURI> uriToLoad; // from aUrl, if any
   nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner; // from the parent window, if any
   nsCOMPtr<nsIDocShellTreeItem> newDocShellItem; // from the new window
 
   nsCOMPtr<nsPIDOMWindowOuter> parent =
     aParent ? nsPIDOMWindowOuter::From(aParent) : nullptr;
 
-  // When the opener is a remote tab, the url passed from the child process
-  // isn't actually used. This code needs some serious refactoring.
-  MOZ_ASSERT_IF(openedFromRemoteTab, !aUrl);
-  MOZ_ASSERT_IF(openedFromRemoteTab, XRE_IsParentProcess());
   NS_ENSURE_ARG_POINTER(aResult);
   *aResult = 0;
 
   if (!nsContentUtils::IsSafeToRunScript()) {
     nsContentUtils::WarnScriptWasIgnored(nullptr);
     return NS_ERROR_FAILURE;
   }
 
   GetWindowTreeOwner(parent, getter_AddRefs(parentTreeOwner));
 
   // We expect TabParent to have provided us the absolute URI of the window
   // we're to open, so there's no need to call URIfromURL (or more importantly,
   // to check for a chrome URI, which cannot be opened from a remote tab).
-  if (aUrl && !openedFromRemoteTab) {
+  if (aUrl) {
     rv = URIfromURL(aUrl, aParent, getter_AddRefs(uriToLoad));
     if (NS_FAILED(rv)) {
       return rv;
     }
     uriToLoad->SchemeIs("chrome", &uriToLoadIsChrome);
   }
 
   bool nameSpecified = false;
   if (aName) {
     CopyUTF8toUTF16(aName, name);
     nameSpecified = true;
   } else {
     name.SetIsVoid(true);
   }
 
-  bool featuresSpecified = false;
   if (aFeatures) {
     features.Assign(aFeatures);
-    featuresSpecified = true;
     features.StripWhitespace();
   } else {
     features.SetIsVoid(true);
   }
 
-  // We only want to check for existing named windows if:
-  // a) We're the child process
-  // b) We're the parent process, and aOpeningTab wasn't passed
-  //    in.
-  // This is because when using child processes, the parent process shouldn't
-  // know or care about names - unless we're opening named windows from chrome.
-  if (!aOpeningTab) {
-    // try to find an extant window with the given name
-    nsCOMPtr<nsPIDOMWindowOuter> foundWindow = SafeGetWindowByName(name, aParent);
-    GetWindowTreeItem(foundWindow, getter_AddRefs(newDocShellItem));
-  }
+  // try to find an extant window with the given name
+  nsCOMPtr<nsPIDOMWindowOuter> foundWindow = SafeGetWindowByName(name, aParent);
+  GetWindowTreeItem(foundWindow, getter_AddRefs(newDocShellItem));
 
   // Do sandbox checks here, instead of waiting until nsIDocShell::LoadURI.
   // The state of the window can change before this call and if we are blocked
   // because of sandboxing, we wouldn't want that to happen.
   nsCOMPtr<nsPIDOMWindowOuter> parentWindow =
     aParent ? nsPIDOMWindowOuter::From(aParent) : nullptr;
   nsCOMPtr<nsIDocShell> parentDocShell;
   if (parentWindow) {
@@ -593,58 +771,62 @@ nsWindowWatcher::OpenWindowInternal(mozI
 
   // no extant window? make a new one.
 
   // If no parent, consider it chrome when running in the parent process.
   bool hasChromeParent = XRE_IsContentProcess() ? false : true;
   if (aParent) {
     // Check if the parent document has chrome privileges.
     nsIDocument* doc = parentWindow->GetDoc();
-    hasChromeParent =
-      doc && nsContentUtils::IsChromeDoc(doc) && !openedFromRemoteTab;
+    hasChromeParent = doc && nsContentUtils::IsChromeDoc(doc);
   }
 
-  // Make sure we call CalculateChromeFlags() *before* we push the
+  bool isCallerChrome = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
+
+  // Make sure we calculate the chromeFlags *before* we push the
   // callee context onto the context stack so that
-  // CalculateChromeFlags() sees the actual caller when doing its
+  // the calculation sees the actual caller when doing its
   // security checks.
-  chromeFlags = CalculateChromeFlags(aParent, features.get(), featuresSpecified,
-                                     aDialog, uriToLoadIsChrome,
-                                     hasChromeParent, aCalledFromJS,
-                                     openedFromRemoteTab);
+  if (isCallerChrome && XRE_IsParentProcess()) {
+    chromeFlags = CalculateChromeFlagsForParent(aParent, features,
+                                                aDialog, uriToLoadIsChrome,
+                                                hasChromeParent, aCalledFromJS);
+  } else {
+    chromeFlags = CalculateChromeFlagsForChild(features);
 
-  // If we are opening a window from a remote browser, the resulting window
-  // should also be remote.
-  MOZ_ASSERT_IF(openedFromRemoteTab,
-                chromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
+    // Until ShowModalDialog is removed, it's still possible for content to
+    // request dialogs, but only in single-process mode.
+    if (aDialog) {
+      MOZ_ASSERT(XRE_IsParentProcess());
+      chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
+    }
+  }
 
   // If we're not called through our JS version of the API, and we got
   // our internal modal option, treat the window we're opening as a
   // modal content window (and set the modal chrome flag).
   if (!aCalledFromJS && aArgv &&
-      WinHasOption(features.get(), "-moz-internal-modal", 0, nullptr)) {
+      WinHasOption(features, "-moz-internal-modal", 0, nullptr)) {
     windowIsModalContentDialog = true;
 
     // CHROME_MODAL gets inherited by dependent windows, which affects various
     // platform-specific window state (especially on OSX). So we need some way
     // to determine that this window was actually opened by nsGlobalWindow::
     // ShowModalDialog(), and that somebody is actually going to be watching
     // for return values and all that.
     chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL_CONTENT_WINDOW;
     chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL;
   }
 
   SizeSpec sizeSpec;
-  CalcSizeSpec(features.get(), sizeSpec);
+  CalcSizeSpec(features, sizeSpec);
 
   nsCOMPtr<nsIScriptSecurityManager> sm(
     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
 
-  bool isCallerChrome =
-    nsContentUtils::LegacyIsCallerChromeOrNativeCode() && !openedFromRemoteTab;
 
   // XXXbz Why is an AutoJSAPI good enough here?  Wouldn't AutoEntryScript (so
   // we affect the entry global) make more sense?  Or do we just want to affect
   // GetSubjectPrincipal()?
   dom::AutoJSAPI jsapiChromeGuard;
 
   bool windowTypeIsChrome =
     chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
@@ -822,39 +1004,33 @@ nsWindowWatcher::OpenWindowInternal(mozI
           popupConditions = !isCallerChrome;
         }
 
         if (popupConditions) {
           contextFlags |=
             nsIWindowCreator2::PARENT_IS_LOADING_OR_RUNNING_TIMEOUT;
         }
 
-        // B2G multi-screen support. mozDisplayId is returned from the
-        // "display-changed" event, it is also platform-dependent.
-#ifdef MOZ_WIDGET_GONK
-        int retval = WinHasOption(features.get(), "mozDisplayId", 0, nullptr);
-        windowCreator2->SetScreenId(retval);
-#endif
-
+        rv = CreateChromeWindow(features, parentChrome, chromeFlags, contextFlags,
+                                nullptr, getter_AddRefs(newChrome));
 
-        bool cancel = false;
-        rv = windowCreator2->CreateChromeWindow2(parentChrome, chromeFlags,
-                                                 contextFlags, uriToLoad,
-                                                 aOpeningTab, &cancel,
-                                                 getter_AddRefs(newChrome));
-        if (NS_SUCCEEDED(rv) && cancel) {
-          newChrome = 0; // just in case
-          rv = NS_ERROR_ABORT;
-        }
       } else {
         rv = mWindowCreator->CreateChromeWindow(parentChrome, chromeFlags,
                                                 getter_AddRefs(newChrome));
       }
 
       if (newChrome) {
+        nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(newChrome);
+        if (xulWin) {
+          nsCOMPtr<nsIXULBrowserWindow> xulBrowserWin;
+          xulWin->GetXULBrowserWindow(getter_AddRefs(xulBrowserWin));
+          if (xulBrowserWin) {
+            xulBrowserWin->ForceInitialBrowserNonRemote();
+          }
+        }
         /* It might be a chrome nsXULWindow, in which case it won't have
             an nsIDOMWindow (primary content shell). But in that case, it'll
             be able to hand over an nsIDocShellTreeItem directly. */
         nsCOMPtr<nsPIDOMWindowOuter> newWindow(do_GetInterface(newChrome));
         if (newWindow) {
           GetWindowTreeItem(newWindow, getter_AddRefs(newDocShellItem));
         }
         if (!newDocShellItem) {
@@ -887,35 +1063,20 @@ nsWindowWatcher::OpenWindowInternal(mozI
     }
   }
 
   rv = ReadyOpenedDocShellItem(newDocShellItem, parentWindow, windowIsNew, aResult);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  /* disable persistence of size/position in popups (determined by
-     determining whether the features parameter specifies width or height
-     in any way). We consider any overriding of the window's size or position
-     in the open call as disabling persistence of those attributes.
-     Popup windows (which should not persist size or position) generally set
-     the size. */
   if (isNewToplevelWindow) {
-    /* at the moment, the strings "height=" or "width=" never happen
-       outside a size specification, so we can do this the Q&D way. */
-
-    if (PL_strcasestr(features.get(), "width=") ||
-        PL_strcasestr(features.get(), "height=")) {
-
-      nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
-      newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
-      if (newTreeOwner) {
-        newTreeOwner->SetPersistence(false, false, false);
-      }
-    }
+    nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
+    newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
+    MaybeDisablePersistence(features, newTreeOwner);
   }
 
   if ((aDialog || windowIsModalContentDialog) && aArgv) {
     // Set the args on the new window.
     nsCOMPtr<nsPIDOMWindowOuter> piwin(do_QueryInterface(*aResult));
     NS_ENSURE_TRUE(piwin, NS_ERROR_UNEXPECTED);
 
     rv = piwin->SetArguments(aArgv);
@@ -1081,18 +1242,20 @@ nsWindowWatcher::OpenWindowInternal(mozI
                                        getter_AddRefs(storage));
       if (storage) {
         newStorageManager->CloneStorage(storage);
       }
     }
   }
 
   if (isNewToplevelWindow) {
-    SizeOpenedDocShellItem(newDocShellItem, aParent, isCallerChrome, sizeSpec,
-                           aOpenerFullZoom);
+    nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
+    newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
+    SizeOpenedWindow(newTreeOwner, aParent, isCallerChrome, sizeSpec,
+                     aOpenerFullZoom);
   }
 
   // XXXbz isn't windowIsModal always true when windowIsModalContentDialog?
   if (windowIsModal || windowIsModalContentDialog) {
     nsCOMPtr<nsIDocShellTreeOwner> newTreeOwner;
     newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
     nsCOMPtr<nsIWebBrowserChrome> newChrome(do_GetInterface(newTreeOwner));
 
@@ -1536,118 +1699,51 @@ nsWindowWatcher::URIfromURL(const char* 
       baseURI = doc->GetDocBaseURI();
     }
   }
 
   // build and return the absolute URI
   return NS_NewURI(aURI, aURL, baseURI);
 }
 
-#define NS_CALCULATE_CHROME_FLAG_FOR(feature, flag)                            \
-  prefBranch->GetBoolPref(feature, &forceEnable);                              \
-  if (forceEnable && !(aDialog && !openedFromContentScript) &&                 \
-      !(!openedFromContentScript && aHasChromeParent) && !aChromeURL) {        \
-    chromeFlags |= flag;                                                       \
-  } else {                                                                     \
-    chromeFlags |=                                                             \
-      WinHasOption(aFeatures, feature, 0, &presenceFlag) ? flag : 0;           \
-  }
-
-/**
- * Calculate the chrome bitmask from a string list of features.
- * @param aParent the opener window
- * @param aFeatures a string containing a list of named chrome features
- * @param aNullFeatures true if aFeatures was a null pointer (which fact
- *                      is lost by its conversion to a string in the caller)
- * @param aDialog affects the assumptions made about unnamed features
- * @return the chrome bitmask
- */
-// static
-uint32_t
-nsWindowWatcher::CalculateChromeFlags(mozIDOMWindowProxy* aParent,
-                                      const char* aFeatures,
-                                      bool aFeaturesSpecified,
-                                      bool aDialog,
-                                      bool aChromeURL,
-                                      bool aHasChromeParent,
-                                      bool aCalledFromJS,
-                                      bool aOpenedFromRemoteTab)
-{
-  const bool inContentProcess = XRE_IsContentProcess();
-  uint32_t chromeFlags = 0;
-
-  if (!aFeaturesSpecified || !aFeatures) {
-    chromeFlags = nsIWebBrowserChrome::CHROME_ALL;
-    if (aDialog) {
-      chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
-                     nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
-    }
-
-    if (inContentProcess) {
-      return chromeFlags;
-    }
-  } else {
-    chromeFlags = nsIWebBrowserChrome::CHROME_WINDOW_BORDERS;
+#define NS_CALCULATE_CHROME_FLAG_FOR(feature, flag)                       \
+  prefBranch->GetBoolPref(feature, &forceEnable);                     \
+  if (forceEnable && !aDialog && !aHasChromeParent && !aChromeURL) {  \
+    chromeFlags |= flag;                                              \
+  } else {                                                            \
+    chromeFlags |=                                                    \
+      WinHasOption(aFeatures, feature, 0, &presenceFlag) ? flag : 0;  \
   }
 
-  bool openedFromContentScript =
-    aOpenedFromRemoteTab ? aCalledFromJS
-                         : !nsContentUtils::LegacyIsCallerChromeOrNativeCode();
-
-  /* This function has become complicated since browser windows and
-     dialogs diverged. The difference is, browser windows assume all
-     chrome not explicitly mentioned is off, if the features string
-     is not null. Exceptions are some OS border chrome new with Mozilla.
-     Dialogs interpret a (mostly) empty features string to mean
-     "OS's choice," and also support an "all" flag explicitly disallowed
-     in the standards-compliant window.(normal)open. */
-
-  bool presenceFlag = false;
-  if (aDialog && WinHasOption(aFeatures, "all", 0, &presenceFlag)) {
-    chromeFlags = nsIWebBrowserChrome::CHROME_ALL;
-  }
-
-  /* Next, allow explicitly named options to override the initial settings */
-
-  if (!inContentProcess && !openedFromContentScript) {
-    // Determine whether the window is a private browsing window
-    chromeFlags |= WinHasOption(aFeatures, "private", 0, &presenceFlag) ?
-      nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW : 0;
-    chromeFlags |= WinHasOption(aFeatures, "non-private", 0, &presenceFlag) ?
-      nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW : 0;
-  }
-
-  if (!inContentProcess) {
-    // Determine whether the window should have remote tabs.
-    bool remote = BrowserTabsRemoteAutostart();
-
-    if (!openedFromContentScript) {
-      if (remote) {
-        remote = !WinHasOption(aFeatures, "non-remote", 0, &presenceFlag);
-      } else {
-        remote = WinHasOption(aFeatures, "remote", 0, &presenceFlag);
-      }
-    }
-
-    if (remote) {
-      chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
-    }
-  }
+// static
+uint32_t
+nsWindowWatcher::CalculateChromeFlagsHelper(uint32_t aInitialFlags,
+                                            const nsACString& aFeatures,
+                                            bool& presenceFlag,
+                                            bool aDialog,
+                                            bool aHasChromeParent,
+                                            bool aChromeURL)
+{
+  uint32_t chromeFlags = aInitialFlags;
 
   nsresult rv;
-
   nsCOMPtr<nsIPrefBranch> prefBranch;
   nsCOMPtr<nsIPrefService> prefs =
     do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, true);
+
+  NS_ENSURE_SUCCESS(rv, nsIWebBrowserChrome::CHROME_DEFAULT);
 
   rv = prefs->GetBranch("dom.disable_window_open_feature.",
                         getter_AddRefs(prefBranch));
-  NS_ENSURE_SUCCESS(rv, true);
+
+  NS_ENSURE_SUCCESS(rv, nsIWebBrowserChrome::CHROME_DEFAULT);
 
+  // NS_CALCULATE_CHROME_FLAG_FOR requires aFeatures, forceEnable, aDialog
+  // aHasChromeParent, aChromeURL, presenceFlag and chromeFlags to be in
+  // scope.
   bool forceEnable = false;
 
   NS_CALCULATE_CHROME_FLAG_FOR("titlebar",
                                nsIWebBrowserChrome::CHROME_TITLEBAR);
   NS_CALCULATE_CHROME_FLAG_FOR("close",
                                nsIWebBrowserChrome::CHROME_WINDOW_CLOSE);
   NS_CALCULATE_CHROME_FLAG_FOR("toolbar",
                                nsIWebBrowserChrome::CHROME_TOOLBAR);
@@ -1664,37 +1760,161 @@ nsWindowWatcher::CalculateChromeFlags(mo
   NS_CALCULATE_CHROME_FLAG_FOR("minimizable",
                                nsIWebBrowserChrome::CHROME_WINDOW_MIN);
 
   // default scrollbar to "on," unless explicitly turned off
   if (WinHasOption(aFeatures, "scrollbars", 1, &presenceFlag) || !presenceFlag) {
     chromeFlags |= nsIWebBrowserChrome::CHROME_SCROLLBARS;
   }
 
+  return chromeFlags;
+}
+
+// static
+uint32_t
+nsWindowWatcher::EnsureFlagsSafeForContent(uint32_t aChromeFlags,
+                                           bool aChromeURL)
+{
+  aChromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR;
+  aChromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE;
+  aChromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_LOWERED;
+  aChromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_RAISED;
+  aChromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_POPUP;
+  /* Untrusted script is allowed to pose modal windows with a chrome
+     scheme. This check could stand to be better. But it effectively
+     prevents untrusted script from opening modal windows in general
+     while still allowing alerts and the like. */
+  if (!aChromeURL) {
+    aChromeFlags &= ~(nsIWebBrowserChrome::CHROME_MODAL |
+                     nsIWebBrowserChrome::CHROME_OPENAS_CHROME);
+  }
+
+  if (!(aChromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)) {
+    aChromeFlags &= ~nsIWebBrowserChrome::CHROME_DEPENDENT;
+  }
+
+  return aChromeFlags;
+}
+
+/**
+ * Calculate the chrome bitmask from a string list of features requested
+ * from a child process. Feature strings that are restricted to the parent
+ * process are ignored here.
+ * @param aFeatures a string containing a list of named features
+ * @return the chrome bitmask
+ */
+// static
+uint32_t
+nsWindowWatcher::CalculateChromeFlagsForChild(const nsACString& aFeatures)
+{
+  if (aFeatures.IsVoid()) {
+    return nsIWebBrowserChrome::CHROME_ALL;
+  }
+
+  bool presenceFlag = false;
+  uint32_t chromeFlags = CalculateChromeFlagsHelper(
+    nsIWebBrowserChrome::CHROME_WINDOW_BORDERS, aFeatures, presenceFlag);
+
+  return EnsureFlagsSafeForContent(chromeFlags);
+}
+
+/**
+ * Calculate the chrome bitmask from a string list of features for a new
+ * privileged window.
+ * @param aParent the opener window
+ * @param aFeatures a string containing a list of named chrome features
+ * @param aDialog affects the assumptions made about unnamed features
+ * @param aChromeURL true if the window is being sent to a chrome:// URL
+ * @param aHasChromeParent true if the parent window is privileged
+ * @param aCalledFromJS true if the window open request came from script.
+ * @return the chrome bitmask
+ */
+// static
+uint32_t
+nsWindowWatcher::CalculateChromeFlagsForParent(mozIDOMWindowProxy* aParent,
+                                               const nsACString& aFeatures,
+                                               bool aDialog,
+                                               bool aChromeURL,
+                                               bool aHasChromeParent,
+                                               bool aCalledFromJS)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(nsContentUtils::LegacyIsCallerChromeOrNativeCode());
+
+  uint32_t chromeFlags = 0;
+
+  // The features string is made void by OpenWindowInternal
+  // if nullptr was originally passed as the features string.
+  if (aFeatures.IsVoid()) {
+    chromeFlags = nsIWebBrowserChrome::CHROME_ALL;
+    if (aDialog) {
+      chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG |
+                     nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
+    }
+  } else {
+    chromeFlags = nsIWebBrowserChrome::CHROME_WINDOW_BORDERS;
+  }
+
+  /* This function has become complicated since browser windows and
+     dialogs diverged. The difference is, browser windows assume all
+     chrome not explicitly mentioned is off, if the features string
+     is not null. Exceptions are some OS border chrome new with Mozilla.
+     Dialogs interpret a (mostly) empty features string to mean
+     "OS's choice," and also support an "all" flag explicitly disallowed
+     in the standards-compliant window.(normal)open. */
+
+  bool presenceFlag = false;
+  if (aDialog && WinHasOption(aFeatures, "all", 0, &presenceFlag)) {
+    chromeFlags = nsIWebBrowserChrome::CHROME_ALL;
+  }
+
+  /* Next, allow explicitly named options to override the initial settings */
+  chromeFlags = CalculateChromeFlagsHelper(chromeFlags, aFeatures, presenceFlag,
+                                           aDialog, aHasChromeParent, aChromeURL);
+
+  // Determine whether the window is a private browsing window
+  chromeFlags |= WinHasOption(aFeatures, "private", 0, &presenceFlag) ?
+    nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW : 0;
+  chromeFlags |= WinHasOption(aFeatures, "non-private", 0, &presenceFlag) ?
+    nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW : 0;
+
+  // Determine whether the window should have remote tabs.
+  bool remote = BrowserTabsRemoteAutostart();
+
+  if (remote) {
+    remote = !WinHasOption(aFeatures, "non-remote", 0, &presenceFlag);
+  } else {
+    remote = WinHasOption(aFeatures, "remote", 0, &presenceFlag);
+  }
+
+  if (remote) {
+    chromeFlags |= nsIWebBrowserChrome::CHROME_REMOTE_WINDOW;
+  }
+
   chromeFlags |= WinHasOption(aFeatures, "popup", 0, &presenceFlag) ?
     nsIWebBrowserChrome::CHROME_WINDOW_POPUP : 0;
 
   /* OK.
      Normal browser windows, in spite of a stated pattern of turning off
      all chrome not mentioned explicitly, will want the new OS chrome (window
      borders, titlebars, closebox) on, unless explicitly turned off.
      Dialogs, on the other hand, take the absence of any explicit settings
      to mean "OS' choice." */
 
   // default titlebar and closebox to "on," if not mentioned at all
   if (!(chromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_POPUP)) {
-    if (!PL_strcasestr(aFeatures, "titlebar")) {
+    if (!PL_strcasestr(aFeatures.BeginReading(), "titlebar")) {
       chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR;
     }
-    if (!PL_strcasestr(aFeatures, "close")) {
+    if (!PL_strcasestr(aFeatures.BeginReading(), "close")) {
       chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE;
     }
   }
 
-  if (aDialog && aFeaturesSpecified && !presenceFlag) {
+  if (aDialog && !aFeatures.IsVoid() && !presenceFlag) {
     chromeFlags = nsIWebBrowserChrome::CHROME_DEFAULT;
   }
 
   /* Finally, once all the above normal chrome has been divined, deal
      with the features that are more operating hints than appearance
      instructions. (Note modality implies dependence.) */
 
   if (WinHasOption(aFeatures, "alwaysLowered", 0, nullptr) ||
@@ -1717,109 +1937,85 @@ nsWindowWatcher::CalculateChromeFlags(mo
     nsIWebBrowserChrome::CHROME_DEPENDENT : 0;
   chromeFlags |= WinHasOption(aFeatures, "modal", 0, nullptr) ?
     (nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT) : 0;
 
   /* On mobile we want to ignore the dialog window feature, since the mobile UI
      does not provide any affordance for dialog windows. This does not interfere
      with dialog windows created through openDialog. */
   bool disableDialogFeature = false;
-  nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
+  nsCOMPtr<nsIPrefBranch> branch = do_GetService(NS_PREFSERVICE_CONTRACTID);
+
   branch->GetBoolPref("dom.disable_window_open_dialog_feature",
                       &disableDialogFeature);
 
-  if (openedFromContentScript) {
-    // If the caller context is content, we do not support the
-    // dialog feature. See bug 1095236.
-    disableDialogFeature = true;
-  }
-
   if (!disableDialogFeature) {
     chromeFlags |= WinHasOption(aFeatures, "dialog", 0, nullptr) ?
       nsIWebBrowserChrome::CHROME_OPENAS_DIALOG : 0;
   }
 
   /* and dialogs need to have the last word. assume dialogs are dialogs,
      and opened as chrome, unless explicitly told otherwise. */
   if (aDialog) {
-    if (!PL_strcasestr(aFeatures, "dialog")) {
+    if (!PL_strcasestr(aFeatures.BeginReading(), "dialog")) {
       chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
     }
-    if (!PL_strcasestr(aFeatures, "chrome")) {
+    if (!PL_strcasestr(aFeatures.BeginReading(), "chrome")) {
       chromeFlags |= nsIWebBrowserChrome::CHROME_OPENAS_CHROME;
     }
   }
 
   /* missing
      chromeFlags->copy_history
    */
 
   // Check security state for use in determing window dimensions
-  if (openedFromContentScript || !aHasChromeParent) {
-    // If priv check fails (or if we're called from chrome, but the
-    // parent is not a chrome window), set all elements to minimum
-    // reqs., else leave them alone.
-    chromeFlags |= nsIWebBrowserChrome::CHROME_TITLEBAR;
-    chromeFlags |= nsIWebBrowserChrome::CHROME_WINDOW_CLOSE;
-    chromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_LOWERED;
-    chromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_RAISED;
-    chromeFlags &= ~nsIWebBrowserChrome::CHROME_WINDOW_POPUP;
-    /* Untrusted script is allowed to pose modal windows with a chrome
-       scheme. This check could stand to be better. But it effectively
-       prevents untrusted script from opening modal windows in general
-       while still allowing alerts and the like. */
-    if (!aChromeURL)
-      chromeFlags &= ~(nsIWebBrowserChrome::CHROME_MODAL |
-                       nsIWebBrowserChrome::CHROME_OPENAS_CHROME);
-  }
-
-  if (!(chromeFlags & nsIWebBrowserChrome::CHROME_OPENAS_CHROME)) {
-    // Remove the dependent flag if we're not opening as chrome
-    chromeFlags &= ~nsIWebBrowserChrome::CHROME_DEPENDENT;
+  if (!aHasChromeParent) {
+    chromeFlags = EnsureFlagsSafeForContent(chromeFlags, aChromeURL);
   }
 
   // Disable CHROME_OPENAS_DIALOG if the window is inside <iframe mozbrowser>.
   // It's up to the embedder to interpret what dialog=1 means.
   nsCOMPtr<nsIDocShell> docshell = do_GetInterface(aParent);
   if (docshell && docshell->GetIsInMozBrowserOrApp()) {
     chromeFlags &= ~nsIWebBrowserChrome::CHROME_OPENAS_DIALOG;
   }
 
   return chromeFlags;
 }
 
 // static
 int32_t
-nsWindowWatcher::WinHasOption(const char* aOptions, const char* aName,
+nsWindowWatcher::WinHasOption(const nsACString& aOptions, const char* aName,
                               int32_t aDefault, bool* aPresenceFlag)
 {
-  if (!aOptions) {
+  if (aOptions.IsEmpty()) {
     return 0;
   }
 
+  const char* options = aOptions.BeginReading();
   char* comma;
   char* equal;
   int32_t found = 0;
 
 #ifdef DEBUG
-  nsAutoCString options(aOptions);
-  NS_ASSERTION(options.FindCharInSet(" \n\r\t") == kNotFound,
+  NS_ASSERTION(nsAutoCString(aOptions).FindCharInSet(" \n\r\t") == kNotFound,
                "There should be no whitespace in this string!");
 #endif
 
   while (true) {
-    comma = PL_strchr(aOptions, ',');
+    comma = PL_strchr(options, ',');
     if (comma) {
       *comma = '\0';
     }
-    equal = PL_strchr(aOptions, '=');
+    equal = PL_strchr(options, '=');
     if (equal) {
       *equal = '\0';
     }
-    if (nsCRT::strcasecmp(aOptions, aName) == 0) {
+    if (nsCRT::strcasecmp(options, aName) == 0) {
       if (aPresenceFlag) {
         *aPresenceFlag = true;
       }
       if (equal)
         if (*(equal + 1) == '*') {
           found = aDefault;
         } else if (nsCRT::strcasecmp(equal + 1, "yes") == 0) {
           found = 1;
@@ -1834,17 +2030,17 @@ nsWindowWatcher::WinHasOption(const char
       *equal = '=';
     }
     if (comma) {
       *comma = ',';
     }
     if (found || !comma) {
       break;
     }
-    aOptions = comma + 1;
+    options = comma + 1;
   }
   return found;
 }
 
 /* try to find an nsIDocShellTreeItem with the given name in any
    known open window. a failure to find the item will not
    necessarily return a failure method value. check aFoundItem.
 */
@@ -1993,17 +2189,17 @@ nsWindowWatcher::ReadyOpenedDocShellItem
     }
     rv = CallQueryInterface(piOpenedWindow, aOpenedWindow);
   }
   return rv;
 }
 
 // static
 void
-nsWindowWatcher::CalcSizeSpec(const char* aFeatures, SizeSpec& aResult)
+nsWindowWatcher::CalcSizeSpec(const nsACString& aFeatures, SizeSpec& aResult)
 {
   // Parse position spec, if any, from aFeatures
   bool present;
   int32_t temp;
 
   present = false;
   if ((temp = WinHasOption(aFeatures, "left", 0, &present)) || present) {
     aResult.mLeft = temp;
@@ -2056,81 +2252,95 @@ nsWindowWatcher::CalcSizeSpec(const char
       aResult.mUseDefaultHeight = true;
     } else {
       aResult.mInnerHeight = temp;
     }
     aResult.mInnerHeightSpecified = true;
   }
 }
 
-/* Size and position the new window according to aSizeSpec. This method
+/* Size and position a new window according to aSizeSpec. This method
    is assumed to be called after the window has already been given
    a default position and size; thus its current position and size are
    accurate defaults. The new window is made visible at method end.
+   @param aTreeOwner
+          The top-level nsIDocShellTreeOwner of the newly opened window.
+   @param aParent (optional)
+          The parent window from which to inherit zoom factors from if
+          aOpenerFullZoom isn't passed.
+   @param aIsCallerChrome
+          True if the code requesting the new window is privileged.
+   @param aSizeSpec
+          The size that the new window should be.
+   @param aOpenerFullZoom
+          An optional pointer to a zoom factor to scale the content
+          to.
 */
 void
-nsWindowWatcher::SizeOpenedDocShellItem(nsIDocShellTreeItem* aDocShellItem,
-                                        mozIDOMWindowProxy* aParent,
-                                        bool aIsCallerChrome,
-                                        const SizeSpec& aSizeSpec,
-                                        float* aOpenerFullZoom)
+nsWindowWatcher::SizeOpenedWindow(nsIDocShellTreeOwner* aTreeOwner,
+                                  mozIDOMWindowProxy* aParent,
+                                  bool aIsCallerChrome,
+                                  const SizeSpec& aSizeSpec,
+                                  float* aOpenerFullZoom)
 {
+  // We should only be sizing top-level windows if we're in the parent
+  // process.
+  MOZ_ASSERT(XRE_IsParentProcess());
+
   // position and size of window
   int32_t left = 0, top = 0, width = 100, height = 100;
   // difference between chrome and content size
   int32_t chromeWidth = 0, chromeHeight = 0;
   // whether the window size spec refers to chrome or content
   bool sizeChromeWidth = true, sizeChromeHeight = true;
 
   // get various interfaces for aDocShellItem, used throughout this method
-  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
-  aDocShellItem->GetTreeOwner(getter_AddRefs(treeOwner));
-  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(treeOwner));
+  nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(aTreeOwner));
   if (!treeOwnerAsWin) { // we'll need this to actually size the docshell
     return;
   }
 
   double openerZoom = aOpenerFullZoom ? *aOpenerFullZoom : 1.0;
   if (aParent && !aOpenerFullZoom) {
     nsCOMPtr<nsPIDOMWindowOuter> piWindow = nsPIDOMWindowOuter::From(aParent);
     if (nsIDocument* doc = piWindow->GetDoc()) {
       if (nsIPresShell* shell = doc->GetShell()) {
         if (nsPresContext* presContext = shell->GetPresContext()) {
           openerZoom = presContext->GetFullZoom();
         }
       }
     }
   }
 
-  double scale;
+  double scale = 1.0;
   treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale);
 
   /* The current position and size will be unchanged if not specified
      (and they fit entirely onscreen). Also, calculate the difference
      between chrome and content sizes on aDocShellItem's window.
      This latter point becomes important if chrome and content
      specifications are mixed in aFeatures, and when bringing the window
      back from too far off the right or bottom edges of the screen. */
 
   treeOwnerAsWin->GetPositionAndSize(&left, &top, &width, &height);
   left = NSToIntRound(left / scale);
   top = NSToIntRound(top / scale);
   width = NSToIntRound(width / scale);
   height = NSToIntRound(height / scale);
   {
-    // scope shellWindow why not
-    nsCOMPtr<nsIBaseWindow> shellWindow(do_QueryInterface(aDocShellItem));
-    if (shellWindow) {
-      int32_t cox, coy;
-      double shellScale;
-      shellWindow->GetSize(&cox, &coy);
-      shellWindow->GetUnscaledDevicePixelsPerCSSPixel(&shellScale);
-      chromeWidth = width - NSToIntRound(cox / shellScale);
-      chromeHeight = height - NSToIntRound(coy / shellScale);
+    int32_t contentWidth, contentHeight;
+    bool hasPrimaryContent = false;
+    aTreeOwner->GetHasPrimaryContent(&hasPrimaryContent);
+    if (hasPrimaryContent) {
+      aTreeOwner->GetPrimaryContentSize(&contentWidth, &contentHeight);
+    } else {
+      aTreeOwner->GetRootShellSize(&contentWidth, &contentHeight);
     }
+    chromeWidth = width - contentWidth;
+    chromeHeight = height - contentHeight;
   }
 
   // Set up left/top
   if (aSizeSpec.mLeftSpecified) {
     left = NSToIntRound(aSizeSpec.mLeft * openerZoom);
   }
 
   if (aSizeSpec.mTopSpecified) {
@@ -2172,17 +2382,16 @@ nsWindowWatcher::SizeOpenedDocShellItem(
   if (aIsCallerChrome) {
     // Only enable special priveleges for chrome when chrome calls
     // open() on a chrome window
     nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(aParent));
     enabled = !aParent || chromeWin;
   }
 
   if (!enabled) {
-
     // Security check failed.  Ensure all args meet minimum reqs.
 
     int32_t oldTop = top, oldLeft = left;
 
     // We'll also need the screen dimensions
     nsCOMPtr<nsIScreen> screen;
     nsCOMPtr<nsIScreenManager> screenMgr(
       do_GetService("@mozilla.org/gfx/screenmanager;1"));
@@ -2275,17 +2484,23 @@ nsWindowWatcher::SizeOpenedDocShellItem(
     // wherever it really ended up
     treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale);
   }
   if (aSizeSpec.SizeSpecified()) {
     /* Prefer to trust the interfaces, which think in terms of pure
        chrome or content sizes. If we have a mix, use the chrome size
        adjusted by the chrome/content differences calculated earlier. */
     if (!sizeChromeWidth && !sizeChromeHeight) {
-      treeOwner->SizeShellTo(aDocShellItem, width * scale, height * scale);
+      bool hasPrimaryContent = false;
+      aTreeOwner->GetHasPrimaryContent(&hasPrimaryContent);
+      if (hasPrimaryContent) {
+        aTreeOwner->SetPrimaryContentSize(width * scale, height * scale);
+      } else {
+        aTreeOwner->SetRootShellSize(width * scale, height * scale);
+      }
     } else {
       if (!sizeChromeWidth) {
         width += chromeWidth;
       }
       if (!sizeChromeHeight) {
         height += chromeHeight;
       }
       treeOwnerAsWin->SetSize(width * scale, height * scale, false);
--- a/embedding/components/windowwatcher/nsWindowWatcher.h
+++ b/embedding/components/windowwatcher/nsWindowWatcher.h
@@ -77,51 +77,72 @@ protected:
   // (which means called from script) or called via OpenWindow.
   nsresult OpenWindowInternal(mozIDOMWindowProxy* aParent,
                               const char* aUrl,
                               const char* aName,
                               const char* aFeatures,
                               bool aCalledFromJS,
                               bool aDialog,
                               bool aNavigate,
-                              nsITabParent* aOpeningTab,
                               nsIArray* aArgv,
                               float* aOpenerFullZoom,
                               mozIDOMWindowProxy** aResult);
 
   static nsresult URIfromURL(const char* aURL,
                              mozIDOMWindowProxy* aParent,
                              nsIURI** aURI);
 
-  static uint32_t CalculateChromeFlags(mozIDOMWindowProxy* aParent,
-                                       const char* aFeatures,
-                                       bool aFeaturesSpecified,
-                                       bool aDialog,
-                                       bool aChromeURL,
-                                       bool aHasChromeParent,
-                                       bool aCalledFromJS,
-                                       bool aOpenedFromRemoteTab);
-  static int32_t WinHasOption(const char* aOptions, const char* aName,
+  static uint32_t CalculateChromeFlagsForChild(const nsACString& aFeaturesStr);
+
+  static uint32_t CalculateChromeFlagsForParent(mozIDOMWindowProxy* aParent,
+                                                const nsACString& aFeaturesStr,
+                                                bool aDialog,
+                                                bool aChromeURL,
+                                                bool aHasChromeParent,
+                                                bool aCalledFromJS);
+
+  static int32_t WinHasOption(const nsACString& aOptions, const char* aName,
                               int32_t aDefault, bool* aPresenceFlag);
   /* Compute the right SizeSpec based on aFeatures */
-  static void CalcSizeSpec(const char* aFeatures, SizeSpec& aResult);
+  static void CalcSizeSpec(const nsACString& aFeatures, SizeSpec& aResult);
   static nsresult ReadyOpenedDocShellItem(nsIDocShellTreeItem* aOpenedItem,
                                           nsPIDOMWindowOuter* aParent,
                                           bool aWindowIsNew,
                                           mozIDOMWindowProxy** aOpenedWindow);
-  static void SizeOpenedDocShellItem(nsIDocShellTreeItem* aDocShellItem,
-                                     mozIDOMWindowProxy* aParent,
-                                     bool aIsCallerChrome,
-                                     const SizeSpec& aSizeSpec,
-                                     float* aOpenerFullZoom);
+  static void SizeOpenedWindow(nsIDocShellTreeOwner* aTreeOwner,
+                               mozIDOMWindowProxy* aParent,
+                               bool aIsCallerChrome,
+                               const SizeSpec& aSizeSpec,
+                               float* aOpenerFullZoom);
   static void GetWindowTreeItem(mozIDOMWindowProxy* aWindow,
                                 nsIDocShellTreeItem** aResult);
   static void GetWindowTreeOwner(nsPIDOMWindowOuter* aWindow,
                                  nsIDocShellTreeOwner** aResult);
 
+private:
+  nsresult CreateChromeWindow(const nsACString& aFeatures,
+                              nsIWebBrowserChrome* aParentChrome,
+                              uint32_t aChromeFlags,
+                              uint32_t aContextFlags,
+                              nsITabParent* aOpeningTabParent,
+                              nsIWebBrowserChrome** aResult);
+
+  void MaybeDisablePersistence(const nsACString& aFeatures,
+                               nsIDocShellTreeOwner* aTreeOwner);
+
+  static uint32_t CalculateChromeFlagsHelper(uint32_t aInitialFlags,
+                                             const nsACString& aFeatures,
+                                             bool &presenceFlag,
+                                             bool aDialog = false,
+                                             bool aHasChromeParent = false,
+                                             bool aChromeURL = false);
+  static uint32_t EnsureFlagsSafeForContent(uint32_t aChromeFlags,
+                                            bool aChromeURL = false);
+
+protected:
   nsTArray<nsWatcherWindowEnumerator*> mEnumeratorList;
   nsWatcherWindowEntry* mOldestWindow;
   mozilla::Mutex mListLock;
 
   nsCOMPtr<nsIWindowCreator> mWindowCreator;
 };
 
 #endif
--- a/embedding/components/windowwatcher/test/browser.ini
+++ b/embedding/components/windowwatcher/test/browser.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 tags = openwindow
 
+[browser_new_content_window_chromeflags.js]
 [browser_new_remote_window_flags.js]
 run-if = e10s
 [browser_new_content_window_from_chrome_principal.js]
 [browser_new_sized_window.js]
 skip-if = os == 'win' # Bug 1276802 - Opening windows from content on Windows might not get the size right
new file mode 100644
--- /dev/null
+++ b/embedding/components/windowwatcher/test/browser_new_content_window_chromeflags.js
@@ -0,0 +1,278 @@
+/**
+ * Tests that chromeFlags are set properly on windows that are
+ * being opened from content.
+ */
+
+// The following features set chrome flags on new windows and are
+// supported by web content. The schema for each property on this
+// object is as follows:
+//
+// <feature string>: {
+//   flag: <associated nsIWebBrowserChrome flag>,
+//   defaults_to: <what this feature defaults to normally>
+// }
+const ALLOWED = {
+  "toolbar": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_TOOLBAR,
+    defaults_to: true,
+  },
+  "personalbar": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_PERSONAL_TOOLBAR,
+    defaults_to: true,
+  },
+  "menubar": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_MENUBAR,
+    defaults_to: true,
+  },
+  "scrollbars": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_SCROLLBARS,
+    defaults_to: false,
+  },
+  "minimizable": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_WINDOW_MIN,
+    defaults_to: true,
+  },
+};
+
+// Construct a features string that flips all ALLOWED features
+// to not be their defaults.
+const ALLOWED_STRING = Object.keys(ALLOWED).map(feature => {
+  let toValue = ALLOWED[feature].defaults_to ? "no" : "yes";
+  return `${feature}=${toValue}`;
+}).join(",");
+
+// The following are not allowed from web content, at least
+// in the default case (since some are disabled by default
+// via the dom.disable_window_open_feature pref branch).
+const DISALLOWED = {
+  "location": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_LOCATIONBAR,
+    defaults_to: true,
+  },
+  "chrome": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_OPENAS_CHROME,
+    defaults_to: false,
+  },
+  "dialog": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_OPENAS_DIALOG,
+    defaults_to: false,
+  },
+  "private": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_PRIVATE_WINDOW,
+    defaults_to: false,
+  },
+  "non-private": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_NON_PRIVATE_WINDOW,
+    defaults_to: false,
+  },
+  // "all":
+  //   checked manually, since this is an aggregate
+  //   flag.
+  //
+  // "remote":
+  //   checked manually, since its default value will
+  //   depend on whether or not e10s is enabled by default.
+  "popup": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_WINDOW_POPUP,
+    defaults_to: false,
+  },
+  "alwaysLowered": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_WINDOW_LOWERED,
+    defaults_to: false,
+  },
+  "z-lock": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_WINDOW_LOWERED, // Renamed to alwaysLowered
+    defaults_to: false,
+  },
+  "alwaysRaised": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_WINDOW_RAISED,
+    defaults_to: false,
+  },
+  "macsuppressanimation": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_MAC_SUPPRESS_ANIMATION,
+    defaults_to: false,
+  },
+  "extrachrome": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_EXTRA,
+    defaults_to: false,
+  },
+  "centerscreen": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_CENTER_SCREEN,
+    defaults_to: false,
+  },
+  "dependent": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_DEPENDENT,
+    defaults_to: false,
+  },
+  "modal": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_MODAL,
+    defaults_to: false,
+  },
+  "titlebar": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_TITLEBAR,
+    defaults_to: true,
+  },
+  "close": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_WINDOW_CLOSE,
+    defaults_to: true,
+  },
+  "resizable": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_WINDOW_RESIZE,
+    defaults_to: true,
+  },
+  "status": {
+    flag: Ci.nsIWebBrowserChrome.CHROME_STATUSBAR,
+    defaults_to: true,
+  },
+};
+
+// Construct a features string that flips all DISALLOWED features
+// to not be their defaults.
+const DISALLOWED_STRING = Object.keys(DISALLOWED).map(feature => {
+  let toValue = DISALLOWED[feature].defaults_to ? "no" : "yes";
+  return `${feature}=${toValue}`;
+}).join(",");
+
+const FEATURES = [ALLOWED_STRING, DISALLOWED_STRING].join(",");
+
+const SCRIPT_PAGE = `data:text/html,<script>window.open("about:blank", "_blank", "${FEATURES}");</script>`;
+const SCRIPT_PAGE_FOR_CHROME_ALL = `data:text/html,<script>window.open("about:blank", "_blank", "all");</script>`;
+
+// This magic value of 2 means that by default, when content tries
+// to open a new window, it'll actually open in a new window instead
+// of a new tab.
+Services.prefs.setIntPref("browser.link.open_newwindow", 2);
+registerCleanupFunction(() => {
+  Services.prefs.clearUserPref("browser.link.open_newwindow");
+});
+
+/**
+ * Given some nsIDOMWindow for a window running in the parent
+ * process, return the nsIWebBrowserChrome chrome flags for
+ * the associated XUL window.
+ *
+ * @param win (nsIDOMWindow)
+ *        Some window in the parent process.
+ * @returns int
+ */
+function getParentChromeFlags(win) {
+  return win.QueryInterface(Ci.nsIInterfaceRequestor)
+            .getInterface(Ci.nsIWebNavigation)
+            .QueryInterface(Ci.nsIDocShellTreeItem)
+            .treeOwner
+            .QueryInterface(Ci.nsIInterfaceRequestor)
+            .getInterface(Ci.nsIXULWindow)
+            .chromeFlags;
+}
+
+/**
+ * For some chromeFlags, ensures that flags that are in the
+ * ALLOWED group were modified, and that flags in the DISALLOWED
+ * group were not modified.
+ *
+ * @param chromeFlags (int)
+ *        Some chromeFlags to check.
+ */
+function assertContentFlags(chromeFlags) {
+  for (let feature in ALLOWED) {
+    let flag = ALLOWED[feature].flag;
+
+    if (ALLOWED[feature].defaults_to) {
+      // The feature is supposed to default to true, so we should
+      // have been able to flip it off.
+      Assert.ok(!(chromeFlags & flag),
+                `Expected feature ${feature} to be disabled`);
+    } else {
+      // The feature is supposed to default to false, so we should
+      // have been able to flip it on.
+      Assert.ok((chromeFlags & flag),
+                `Expected feature ${feature} to be enabled`);
+    }
+  }
+
+  for (let feature in DISALLOWED) {
+    let flag = DISALLOWED[feature].flag;
+    if (DISALLOWED[feature].defaults_to) {
+      // The feature is supposed to default to true, so it should
+      // stay true.
+      Assert.ok((chromeFlags & flag),
+                `Expected feature ${feature} to be unchanged`);
+    } else {
+      // The feature is supposed to default to false, so it should
+      // stay false.
+      Assert.ok(!(chromeFlags & flag),
+                `Expected feature ${feature} to be unchanged`);
+    }
+  }
+}
+
+/**
+ * Opens a window from content using window.open with the
+ * features computed from ALLOWED and DISALLOWED. The computed
+ * feature string attempts to flip every feature away from their
+ * default.
+ */
+add_task(function* test_new_remote_window_flags() {
+  let newWinPromise = BrowserTestUtils.waitForNewWindow();
+
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: SCRIPT_PAGE,
+  }, function*(browser) {
+    let win = yield newWinPromise;
+    let parentChromeFlags = getParentChromeFlags(win);
+    assertContentFlags(parentChromeFlags);
+
+    if (win.gMultiProcessBrowser) {
+      Assert.ok(parentChromeFlags &
+                Ci.nsIWebBrowserChrome.CHROME_REMOTE_WINDOW,
+                "Should be remote by default");
+    } else {
+      Assert.ok(!(parentChromeFlags &
+                  Ci.nsIWebBrowserChrome.CHROME_REMOTE_WINDOW),
+                "Should not be remote by default");
+    }
+
+    // Confusingly, chromeFlags also exist in the content process
+    // as part of the TabChild, so we have to check those too.
+    let b = win.gBrowser.selectedBrowser;
+    let contentChromeFlags = yield ContentTask.spawn(b, null, function*() {
+      docShell.QueryInterface(Ci.nsIInterfaceRequestor);
+      try {
+        // This will throw if we're not a remote browser.
+        return docShell.getInterface(Ci.nsITabChild)
+                       .QueryInterface(Ci.nsIWebBrowserChrome)
+                       .chromeFlags;
+      } catch(e) {
+        // This must be a non-remote browser...
+        return docShell.QueryInterface(Ci.nsIDocShellTreeItem)
+                       .treeOwner
+                       .QueryInterface(Ci.nsIWebBrowserChrome)
+                       .chromeFlags;
+      }
+    });
+
+    assertContentFlags(contentChromeFlags);
+    Assert.ok(!(contentChromeFlags &
+                Ci.nsIWebBrowserChrome.CHROME_REMOTE_WINDOW),
+              "Should not be remote in the content process.");
+
+    yield BrowserTestUtils.closeWindow(win);
+  });
+
+  // We check "all" manually, since that's an aggregate flag
+  // and doesn't fit nicely into the ALLOWED / DISALLOWED scheme
+  newWinPromise = BrowserTestUtils.waitForNewWindow();
+
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: SCRIPT_PAGE_FOR_CHROME_ALL,
+  }, function*(browser) {
+    let win = yield newWinPromise;
+    let parentChromeFlags = getParentChromeFlags(win);
+    Assert.notEqual((parentChromeFlags & Ci.nsIWebBrowserChrome.CHROME_ALL),
+                    Ci.nsIWebBrowserChrome.CHROME_ALL,
+                    "Should not have been able to set CHROME_ALL");
+    yield BrowserTestUtils.closeWindow(win);
+  });
+});
--- a/embedding/nsIWindowCreator2.idl
+++ b/embedding/nsIWindowCreator2.idl
@@ -35,33 +35,27 @@ interface nsIWindowCreator2 : nsIWindowC
   /** Create a new window. Gecko will/may call this method, if made
       available to it, to create new windows.
       @param parent Parent window, if any. Null if not. The newly created
                     window should be made a child/dependent window of
                     the parent, if any (and if the concept applies
                     to the underlying OS).
       @param chromeFlags Chrome features from nsIWebBrowserChrome
       @param contextFlags Flags about the context of the window being created.
-      @param uri The URL for which this window is intended. It can be null
-                 or zero-length. The implementation of this interface
-                 may use the URL to help determine what sort of window
-                 to open or whether to cancel window creation. It will not
-                 load the URL.
       @param aOpeningTab The TabParent that is trying to open this new chrome
                          window. Can be nullptr.
       @param cancel Return |true| to reject window creation. If true the
                     implementation has determined the window should not
                     be created at all. The caller should not default
                     to any possible backup scheme for creating the window.
       @return the new window. Will be null if canceled or an error occurred.
   */
   nsIWebBrowserChrome createChromeWindow2(in nsIWebBrowserChrome parent,
                                           in uint32_t chromeFlags,
                                           in uint32_t contextFlags,
-                                          in nsIURI uri,
                                           in nsITabParent aOpeningTab,
                                           out boolean cancel);
 
   /**
    * B2G multi-screen support. When open another top-level window on b2g,
    * a screen ID is needed for identifying which screen this window is
    * opened to.
    * @param aScreenId Differentiate screens of windows. It is platform-
--- a/extensions/cookie/test/chrome.ini
+++ b/extensions/cookie/test/chrome.ini
@@ -1,10 +1,10 @@
 [DEFAULT]
-skip-if = buildapp == 'b2g' || os == 'android'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 support-files = channel_utils.js
 
 [test_app_uninstall_cookies.html]
 skip-if = buildapp != 'mulet'
 [test_app_uninstall_permissions.html]
 skip-if = buildapp != 'mulet'
 
 [test_permissionmanager_app_isolation.html]
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -184,16 +184,20 @@ public:
 
     void SetFailureId(nsACString* const aFailureId)
     {
       mFailureId = aFailureId;
     }
 
     void logError(const char *errorMessage) override
     {
+        if (!mFailureId) {
+            return;
+        }
+
         nsCString str(errorMessage);
         Tokenizer tokenizer(str);
 
         // Parse "ANGLE Display::initialize error " << error.getID() << ": "
         //       << error.getMessage()
         nsCString currWord;
         Tokenizer::Token intToken;
         if (tokenizer.CheckWord("ANGLE") &&
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsDataHashtable.h"            // for nsDataHashtable
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsHashKeys.h"                 // for nsPtrHashKey
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRect.h"                     // for IntRect
 #include "nsTArray.h"                   // for AutoTArray, nsTArray_Impl
+#include "mozilla/Poison.h"
 #include "mozilla/layers/ImageHost.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "TreeTraversal.h"              // for ForEachNode
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
@@ -165,16 +166,17 @@ struct LayerPropertiesBase : public Laye
                                          NotifySubDocInvalidationFunc aCallback,
                                          bool* aGeometryChanged);
 
   virtual void MoveBy(const IntPoint& aOffset);
 
   nsIntRegion ComputeChange(NotifySubDocInvalidationFunc aCallback,
                             bool& aGeometryChanged)
   {
+    mCanary.Check();
     bool transformChanged = !mTransform.FuzzyEqual(GetTransformForInvalidation(mLayer)) ||
                              mLayer->GetPostXScale() != mPostXScale ||
                              mLayer->GetPostYScale() != mPostYScale;
     const Maybe<ParentLayerIntRect>& otherClip = mLayer->GetLocalClipRect();
     nsIntRegion result;
 
     bool ancestorMaskChanged = mAncestorMaskLayers.Length() != mLayer->GetAncestorMaskLayerCount();
     if (!ancestorMaskChanged) {
@@ -252,37 +254,41 @@ struct LayerPropertiesBase : public Laye
   nsTArray<UniquePtr<LayerPropertiesBase>> mAncestorMaskLayers;
   nsIntRegion mVisibleRegion;
   Matrix4x4 mTransform;
   float mPostXScale;
   float mPostYScale;
   float mOpacity;
   ParentLayerIntRect mClipRect;
   bool mUseClipRect;
+  mozilla::CorruptionCanary mCanary;
 };
 
 struct ContainerLayerProperties : public LayerPropertiesBase
 {
   explicit ContainerLayerProperties(ContainerLayer* aLayer)
     : LayerPropertiesBase(aLayer)
     , mPreXScale(aLayer->GetPreXScale())
     , mPreYScale(aLayer->GetPreYScale())
   {
     for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) {
+      child->CheckCanary();
       mChildren.AppendElement(Move(CloneLayerTreePropertiesInternal(child)));
     }
   }
 
   nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
                                     bool& aGeometryChanged) override
   {
     ContainerLayer* container = mLayer->AsContainerLayer();
     nsIntRegion invalidOfLayer; // Invalid regions of this layer.
     nsIntRegion result;         // Invliad regions for children only.
 
+    container->CheckCanary();
+
     bool childrenChanged = false;
 
     if (mPreXScale != container->GetPreXScale() ||
         mPreYScale != container->GetPreYScale()) {
       aGeometryChanged = true;
       invalidOfLayer = OldTransformedBounds();
       AddRegion(invalidOfLayer, NewTransformedBounds());
       childrenChanged = true;
@@ -296,16 +302,17 @@ struct ContainerLayerProperties : public
     // other children are added to or removed from our container layer, since
     // that may be caused by children being scrolled in or out of view. We are
     // less concerned with children changing order.
     // TODO: Consider how we could avoid unnecessary invalidation when children
     // change order, and whether the overhead would be worth it.
 
     nsDataHashtable<nsPtrHashKey<Layer>, uint32_t> oldIndexMap(mChildren.Length());
     for (uint32_t i = 0; i < mChildren.Length(); ++i) {
+      mChildren[i]->mLayer->CheckCanary();
       oldIndexMap.Put(mChildren[i]->mLayer, i);
     }
 
     uint32_t i = 0; // cursor into the old child list mChildren
     for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
       bool invalidateChildsCurrentArea = false;
       if (i < mChildren.Length()) {
         uint32_t childsOldIndex;
@@ -554,16 +561,18 @@ UniquePtr<LayerPropertiesBase>
 CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask /* = false */)
 {
   if (!aRoot) {
     return MakeUnique<LayerPropertiesBase>();
   }
 
   MOZ_ASSERT(!aIsMask || aRoot->GetType() == Layer::TYPE_IMAGE);
 
+  aRoot->CheckCanary();
+
   switch (aRoot->GetType()) {
     case Layer::TYPE_CONTAINER:
     case Layer::TYPE_REF:
       return MakeUnique<ContainerLayerProperties>(aRoot->AsContainerLayer());
     case Layer::TYPE_COLOR:
       return MakeUnique<ColorLayerProperties>(static_cast<ColorLayer*>(aRoot));
     case Layer::TYPE_IMAGE:
       return MakeUnique<ImageLayerProperties>(static_cast<ImageLayer*>(aRoot), aIsMask);
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -16,16 +16,17 @@
 #include "gfxTypes.h"
 #include "gfxPoint.h"                   // for gfxPoint
 #include "gfxRect.h"                    // for gfxRect
 #include "gfx2DGlue.h"
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2, etc
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/EventForwards.h"      // for nsPaintEvent
 #include "mozilla/Maybe.h"              // for Maybe
+#include "mozilla/Poison.h"
 #include "mozilla/RefPtr.h"             // for already_AddRefed
 #include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
 #include "mozilla/TimeStamp.h"          // for TimeStamp, TimeDuration
 #include "mozilla/UniquePtr.h"          // for UniquePtr
 #include "mozilla/gfx/BaseMargin.h"     // for BaseMargin
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/TiledRegion.h"    // for TiledIntRegion
@@ -1312,18 +1313,28 @@ public:
   const ScrollMetadata& GetScrollMetadata(uint32_t aIndex) const;
   const FrameMetrics& GetFrameMetrics(uint32_t aIndex) const;
   uint32_t GetScrollMetadataCount() const { return mScrollMetadata.Length(); }
   const nsTArray<ScrollMetadata>& GetAllScrollMetadata() { return mScrollMetadata; }
   bool HasScrollableFrameMetrics() const;
   bool IsScrollInfoLayer() const;
   const EventRegions& GetEventRegions() const { return mEventRegions; }
   ContainerLayer* GetParent() { return mParent; }
-  Layer* GetNextSibling() { return mNextSibling; }
-  const Layer* GetNextSibling() const { return mNextSibling; }
+  Layer* GetNextSibling() {
+    if (mNextSibling) {
+      mNextSibling->CheckCanary();
+    }
+    return mNextSibling;
+  }
+  const Layer* GetNextSibling() const {
+    if (mNextSibling) {
+      mNextSibling->CheckCanary();
+    }
+    return mNextSibling;
+  }
   Layer* GetPrevSibling() { return mPrevSibling; }
   const Layer* GetPrevSibling() const { return mPrevSibling; }
   virtual Layer* GetFirstChild() const { return nullptr; }
   virtual Layer* GetLastChild() const { return nullptr; }
   gfx::Matrix4x4 GetTransform() const;
   // Same as GetTransform(), but returns the transform as a strongly-typed
   // matrix. Eventually this will replace GetTransform().
   const CSSTransformMatrix GetTransformTyped() const;
@@ -1340,16 +1351,17 @@ public:
   FrameMetrics::ViewID GetStickyScrollContainerId() { return mStickyPositionData->mScrollId; }
   const LayerRect& GetStickyScrollRangeOuter() { return mStickyPositionData->mOuter; }
   const LayerRect& GetStickyScrollRangeInner() { return mStickyPositionData->mInner; }
   FrameMetrics::ViewID GetScrollbarTargetContainerId() { return mScrollbarTargetId; }
   ScrollDirection GetScrollbarDirection() { return mScrollbarDirection; }
   float GetScrollbarThumbRatio() { return mScrollbarThumbRatio; }
   bool IsScrollbarContainer() { return mIsScrollbarContainer; }
   Layer* GetMaskLayer() const { return mMaskLayer; }
+  void CheckCanary() const { mCanary.Check(); }
 
   // Ancestor mask layers are associated with FrameMetrics, but for simplicity
   // in maintaining the layer tree structure we attach them to the layer.
   size_t GetAncestorMaskLayerCount() const {
     return mAncestorMaskLayers.Length();
   }
   Layer* GetAncestorMaskLayerAt(size_t aIndex) const {
     return mAncestorMaskLayers.ElementAt(aIndex);
@@ -1851,16 +1863,18 @@ protected:
 
   LayerManager* mManager;
   ContainerLayer* mParent;
   Layer* mNextSibling;
   Layer* mPrevSibling;
   void* mImplData;
   RefPtr<Layer> mMaskLayer;
   nsTArray<RefPtr<Layer>> mAncestorMaskLayers;
+  // Look for out-of-bound in the middle of the structure
+  mozilla::CorruptionCanary mCanary;
   gfx::UserData mUserData;
   gfx::IntRect mLayerBounds;
   LayerIntRegion mVisibleRegion;
   nsTArray<ScrollMetadata> mScrollMetadata;
   EventRegions mEventRegions;
   gfx::Matrix4x4 mTransform;
   // A mutation of |mTransform| that we've queued to be applied at the
   // end of the next transaction (if nothing else overrides it in the
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -345,19 +345,20 @@ CompositorOGL::Initialize(nsCString* con
   mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
 
   if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
     /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
      * extension -- the EXT variant does not provide support for
      * texture rectangle access inside GLSL (sampler2DRect,
      * texture2DRect).
      */
-    if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle))
+    if (!mGLContext->IsExtensionSupported(gl::GLContext::ARB_texture_rectangle)){
       *out_failureReason = "FEATURE_FAILURE_OPENGL_ARB_EXT";
       return false;
+    }
   }
 
   /* Create a simple quad VBO */
 
   mGLContext->fGenBuffers(1, &mQuadVBO);
   mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO);
 
   // 4 quads, with the number of the quad (vertexID) encoded in w.
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -26,18 +26,18 @@
 #include "mozilla/dom/Promise.h"
 
 #include "nsDOMMutationObserver.h"
 #include "nsICycleCollectorListener.h"
 #include "mozilla/XPTInterfaceInfoManager.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsScriptSecurityManager.h"
+#include "nsIPermissionManager.h"
 #include "nsContentUtils.h"
-
 #include "jsfriendapi.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace xpc;
 using namespace JS;
 
 NS_IMPL_ISUPPORTS(nsXPConnect, nsIXPConnect)
@@ -432,30 +432,26 @@ InitGlobalObjectOptions(JS::CompartmentO
     bool shouldDiscardSystemSource = ShouldDiscardSystemSource();
     bool extraWarningsForSystemJS = ExtraWarningsForSystemJS();
 
     bool isSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
 
     if (isSystem) {
         // Make sure [SecureContext] APIs are visible:
         aOptions.creationOptions().setSecureContext(true);
-    }
 
-    short status = aPrincipal->GetAppStatus();
-
-    // Enable the ECMA-402 experimental formatToParts in certified apps.
-    if (status == nsIPrincipal::APP_STATUS_CERTIFIED) {
+#if 0 // TODO: Reenable in Bug 1288653
+        // Enable the ECMA-402 experimental formatToParts in any chrome page
         aOptions.creationOptions()
                 .setExperimentalDateTimeFormatFormatToPartsEnabled(true);
+#endif
     }
 
     if (shouldDiscardSystemSource) {
-        bool discardSource = isSystem ||
-                             (status == nsIPrincipal::APP_STATUS_PRIVILEGED ||
-                              status == nsIPrincipal::APP_STATUS_CERTIFIED);
+        bool discardSource = isSystem;
 
         aOptions.behaviors().setDiscardSource(discardSource);
     }
 
     if (extraWarningsForSystemJS) {
         if (isSystem)
             aOptions.behaviors().extraWarningsOverride().set(true);
     }
--- a/layout/generic/BlockReflowInput.cpp
+++ b/layout/generic/BlockReflowInput.cpp
@@ -259,23 +259,23 @@ BlockReflowInput::ComputeBlockAvailSpace
                "unexpected replaced width");
   if (!aBlockAvoidsFloats) {
     if (aFloatAvailableSpace.mHasFloats) {
       // Use the float-edge property to determine how the child block
       // will interact with the float.
       const nsStyleBorder* borderStyle = aFrame->StyleBorder();
       switch (borderStyle->mFloatEdge) {
         default:
-        case NS_STYLE_FLOAT_EDGE_CONTENT_BOX:  // content and only content does runaround of floats
+        case StyleFloatEdge::ContentBox:  // content and only content does runaround of floats
           // The child block will flow around the float. Therefore
           // give it all of the available space.
           aResult.IStart(wm) = mContentArea.IStart(wm);
           aResult.ISize(wm) = mContentArea.ISize(wm);
           break;
-        case NS_STYLE_FLOAT_EDGE_MARGIN_BOX:
+        case StyleFloatEdge::MarginBox:
           {
             // The child block's margins should be placed adjacent to,
             // but not overlap the float.
             aResult.IStart(wm) = aFloatAvailableSpace.mRect.IStart(wm);
             aResult.ISize(wm) = aFloatAvailableSpace.mRect.ISize(wm);
           }
           break;
       }
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -8538,18 +8538,18 @@ nsIFrame::IsFocusable(int32_t *aTabIndex
     *aTabIndex = -1; // Default for early return is not focusable
   }
   bool isFocusable = false;
 
   if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors() &&
       StyleContext()->GetPseudo() != nsCSSAnonBoxes::anonymousFlexItem &&
       StyleContext()->GetPseudo() != nsCSSAnonBoxes::anonymousGridItem) {
     const nsStyleUserInterface* ui = StyleUserInterface();
-    if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
-        ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {
+    if (ui->mUserFocus != StyleUserFocus::Ignore &&
+        ui->mUserFocus != StyleUserFocus::None_) {
       // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
       tabIndex = 0;
     }
     isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
     if (!isFocusable && !aWithMouse &&
         GetType() == nsGkAtoms::scrollFrame &&
         mContent->IsHTMLElement() &&
         !mContent->IsRootOfNativeAnonymousSubtree() &&
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -270,17 +270,17 @@ AppendCSSShadowValue(const nsCSSShadowIt
   nscoordToCSSValue(aShadow->mRadius, arr->Item(2));
   // NOTE: This code sometimes stores mSpread: 0 even when
   // the parser would be required to leave it null.
   nscoordToCSSValue(aShadow->mSpread, arr->Item(3));
   if (aShadow->mHasColor) {
     arr->Item(4).SetColorValue(aShadow->mColor);
   }
   if (aShadow->mInset) {
-    arr->Item(5).SetIntValue(NS_STYLE_BOX_SHADOW_INSET,
+    arr->Item(5).SetIntValue(uint8_t(StyleBoxShadowType::Inset),
                              eCSSUnit_Enumerated);
   }
 
   nsCSSValueList *resultItem = new nsCSSValueList;
   resultItem->mValue.SetArrayValue(arr, eCSSUnit_Array);
   *aResultTail = resultItem;
   aResultTail = &resultItem->mNext;
 }
@@ -3944,42 +3944,42 @@ StyleAnimationValue::ExtractComputedValu
           break;
         }
 #endif
 
         case eCSSProperty_clip_path: {
           const nsStyleSVGReset* svgReset =
             static_cast<const nsStyleSVGReset*>(styleStruct);
           const nsStyleClipPath& clipPath = svgReset->mClipPath;
-          const int32_t type = clipPath.GetType();
-
-          if (type == NS_STYLE_CLIP_PATH_URL) {
+          const StyleClipPathType type = clipPath.GetType();
+
+          if (type == StyleClipPathType::URL) {
             nsIDocument* doc = aStyleContext->PresContext()->Document();
             RefPtr<nsStringBuffer> uriAsStringBuffer =
               GetURIAsUtf16StringBuffer(clipPath.GetURL());
             RefPtr<mozilla::css::URLValue> url =
               new mozilla::css::URLValue(clipPath.GetURL(),
                                          uriAsStringBuffer,
                                          doc->GetDocumentURI(),
                                          doc->NodePrincipal());
             auto result = MakeUnique<nsCSSValue>();
             result->SetURLValue(url);
             aComputedValue.SetAndAdoptCSSValueValue(result.release(), eUnit_URL);
-          } else if (type == NS_STYLE_CLIP_PATH_BOX) {
+          } else if (type == StyleClipPathType::Box) {
             aComputedValue.SetIntValue(uint8_t(clipPath.GetSizingBox()),
                                        eUnit_Enumerated);
-          } else if (type == NS_STYLE_CLIP_PATH_SHAPE) {
+          } else if (type == StyleClipPathType::Shape) {
             RefPtr<nsCSSValue::Array> result = nsCSSValue::Array::Create(2);
             if (!StyleClipBasicShapeToCSSArray(clipPath, result)) {
               return false;
             }
             aComputedValue.SetCSSValueArrayValue(result, eUnit_Shape);
 
           } else {
-            MOZ_ASSERT(type == NS_STYLE_CLIP_PATH_NONE, "unknown type");
+            MOZ_ASSERT(type == StyleClipPathType::None_, "unknown type");
             aComputedValue.SetNoneValue();
           }
           break;
         }
 
         case eCSSProperty_filter: {
           const nsStyleEffects* effects =
             static_cast<const nsStyleEffects*>(styleStruct);
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1035,17 +1035,17 @@ const KTableEntry nsCSSProps::kBorderWid
 
 const KTableEntry nsCSSProps::kBoxDecorationBreakKTable[] = {
   { eCSSKeyword_slice, NS_STYLE_BOX_DECORATION_BREAK_SLICE },
   { eCSSKeyword_clone, NS_STYLE_BOX_DECORATION_BREAK_CLONE },
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kBoxShadowTypeKTable[] = {
-  { eCSSKeyword_inset, NS_STYLE_BOX_SHADOW_INSET },
+  { eCSSKeyword_inset, uint8_t(StyleBoxShadowType::Inset) },
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kBoxSizingKTable[] = {
   { eCSSKeyword_content_box,  uint8_t(StyleBoxSizing::Content) },
   { eCSSKeyword_border_box,   uint8_t(StyleBoxSizing::Border) },
   { eCSSKeyword_UNKNOWN,      -1 }
 };
@@ -1486,18 +1486,18 @@ KTableEntry nsCSSProps::kFloatKTable[] =
   { eCSSKeyword_left,         NS_STYLE_FLOAT_LEFT },
   { eCSSKeyword_right,        NS_STYLE_FLOAT_RIGHT },
   { eCSSKeyword_inline_start, NS_STYLE_FLOAT_INLINE_START },
   { eCSSKeyword_inline_end,   NS_STYLE_FLOAT_INLINE_END },
   { eCSSKeyword_UNKNOWN,      -1 }
 };
 
 const KTableEntry nsCSSProps::kFloatEdgeKTable[] = {
-  { eCSSKeyword_content_box, NS_STYLE_FLOAT_EDGE_CONTENT_BOX },
-  { eCSSKeyword_margin_box, NS_STYLE_FLOAT_EDGE_MARGIN_BOX },
+  { eCSSKeyword_content_box, uint8_t(StyleFloatEdge::ContentBox) },
+  { eCSSKeyword_margin_box, uint8_t(StyleFloatEdge::MarginBox) },
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kFontDisplayKTable[] = {
   { eCSSKeyword_auto, NS_FONT_DISPLAY_AUTO },
   { eCSSKeyword_block, NS_FONT_DISPLAY_BLOCK },
   { eCSSKeyword_swap, NS_FONT_DISPLAY_SWAP },
   { eCSSKeyword_fallback, NS_FONT_DISPLAY_FALLBACK },
@@ -2115,24 +2115,24 @@ const KTableEntry nsCSSProps::kUnicodeBi
   { eCSSKeyword_plaintext, NS_STYLE_UNICODE_BIDI_PLAINTEXT },
   { eCSSKeyword__moz_isolate, NS_STYLE_UNICODE_BIDI_ISOLATE },
   { eCSSKeyword__moz_isolate_override, NS_STYLE_UNICODE_BIDI_ISOLATE_OVERRIDE },
   { eCSSKeyword__moz_plaintext, NS_STYLE_UNICODE_BIDI_PLAINTEXT },
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kUserFocusKTable[] = {
-  { eCSSKeyword_none,           NS_STYLE_USER_FOCUS_NONE },
-  { eCSSKeyword_normal,         NS_STYLE_USER_FOCUS_NORMAL },
-  { eCSSKeyword_ignore,         NS_STYLE_USER_FOCUS_IGNORE },
-  { eCSSKeyword_select_all,     NS_STYLE_USER_FOCUS_SELECT_ALL },
-  { eCSSKeyword_select_before,  NS_STYLE_USER_FOCUS_SELECT_BEFORE },
-  { eCSSKeyword_select_after,   NS_STYLE_USER_FOCUS_SELECT_AFTER },
-  { eCSSKeyword_select_same,    NS_STYLE_USER_FOCUS_SELECT_SAME },
-  { eCSSKeyword_select_menu,    NS_STYLE_USER_FOCUS_SELECT_MENU },
+  { eCSSKeyword_none,           uint8_t(StyleUserFocus::None_) },
+  { eCSSKeyword_normal,         uint8_t(StyleUserFocus::Normal) },
+  { eCSSKeyword_ignore,         uint8_t(StyleUserFocus::Ignore) },
+  { eCSSKeyword_select_all,     uint8_t(StyleUserFocus::SelectAll) },
+  { eCSSKeyword_select_before,  uint8_t(StyleUserFocus::SelectBefore) },
+  { eCSSKeyword_select_after,   uint8_t(StyleUserFocus::SelectAfter) },
+  { eCSSKeyword_select_same,    uint8_t(StyleUserFocus::SelectSame) },
+  { eCSSKeyword_select_menu,    uint8_t(StyleUserFocus::SelectMenu) },
   { eCSSKeyword_UNKNOWN,        -1 }
 };
 
 const KTableEntry nsCSSProps::kUserInputKTable[] = {
   { eCSSKeyword_none,     NS_STYLE_USER_INPUT_NONE },
   { eCSSKeyword_auto,     NS_STYLE_USER_INPUT_AUTO },
   { eCSSKeyword_enabled,  NS_STYLE_USER_INPUT_ENABLED },
   { eCSSKeyword_disabled, NS_STYLE_USER_INPUT_DISABLED },
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3399,18 +3399,19 @@ nsComputedDOMStyle::GetCSSShadowArray(ns
       val->SetAppUnits(item->*(shadowValues[i]));
       itemList->AppendCSSValue(val.forget());
     }
 
     if (item->mInset && aIsBoxShadow) {
       // This is an inset box-shadow
       val = new nsROCSSPrimitiveValue;
       val->SetIdent(
-        nsCSSProps::ValueToKeywordEnum(NS_STYLE_BOX_SHADOW_INSET,
-                                       nsCSSProps::kBoxShadowTypeKTable));
+        nsCSSProps::ValueToKeywordEnum(
+            uint8_t(StyleBoxShadowType::Inset),
+            nsCSSProps::kBoxShadowTypeKTable));
       itemList->AppendCSSValue(val.forget());
     }
     valueList->AppendCSSValue(itemList.forget());
   }
 
   return valueList.forget();
 }
 
@@ -4398,17 +4399,17 @@ nsComputedDOMStyle::DoGetJustifySelf()
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFloatEdge()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
-    nsCSSProps::ValueToKeywordEnum(StyleBorder()->mFloatEdge,
+    nsCSSProps::ValueToKeywordEnum(uint8_t(StyleBorder()->mFloatEdge),
                                    nsCSSProps::kFloatEdgeKTable));
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetForceBrokenImageIcon()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
@@ -4447,17 +4448,17 @@ nsComputedDOMStyle::DoGetIMEMode()
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetUserFocus()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
-    nsCSSProps::ValueToKeywordEnum(StyleUserInterface()->mUserFocus,
+    nsCSSProps::ValueToKeywordEnum(uint8_t(StyleUserInterface()->mUserFocus),
                                    nsCSSProps::kUserFocusKTable));
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetUserInput()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
@@ -5971,17 +5972,17 @@ nsComputedDOMStyle::CreatePrimitiveValue
   RefPtr<nsROCSSPrimitiveValue> functionValue = new nsROCSSPrimitiveValue;
   functionValue->SetString(shapeFunctionString);
   return functionValue.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
   const nsStyleBasicShape* aStyleBasicShape,
-  mozilla::StyleClipShapeSizing aSizingBox)
+  StyleClipShapeSizing aSizingBox)
 {
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
   if (aStyleBasicShape) {
     valueList->AppendCSSValue(
       CreatePrimitiveValueForBasicShape(aStyleBasicShape));
   }
 
   if (aSizingBox == StyleClipShapeSizing::NoBox) {
@@ -6000,28 +6001,28 @@ nsComputedDOMStyle::CreatePrimitiveValue
   return valueList.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetClipPath()
 {
   const nsStyleSVGReset* svg = StyleSVGReset();
   switch (svg->mClipPath.GetType()) {
-    case NS_STYLE_CLIP_PATH_SHAPE:
+    case StyleClipPathType::Shape:
       return CreatePrimitiveValueForClipPath(svg->mClipPath.GetBasicShape(),
                                              svg->mClipPath.GetSizingBox());
-    case NS_STYLE_CLIP_PATH_BOX:
+    case StyleClipPathType::Box:
       return CreatePrimitiveValueForClipPath(nullptr,
                                              svg->mClipPath.GetSizingBox());
-    case NS_STYLE_CLIP_PATH_URL: {
+    case StyleClipPathType::URL: {
       RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
       val->SetURI(svg->mClipPath.GetURL());
       return val.forget();
     }
-    case NS_STYLE_CLIP_PATH_NONE: {
+    case StyleClipPathType::None_: {
       RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
       val->SetIdent(eCSSKeyword_none);
       return val.forget();
     }
     default:
       NS_NOTREACHED("unexpected type");
   }
   return nullptr;
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -1296,16 +1296,18 @@ struct SetEnumValueHelper
     auto value = aValue.GetIntValue(); \
     MOZ_ASSERT(value >= static_cast<decltype(value)>(type_::min_) && \
                value <= static_cast<decltype(value)>(type_::max_), \
                "inappropriate value"); \
     aField = static_cast<type_>(value); \
   }
 
   DEFINE_ENUM_CLASS_SETTER(StyleBoxSizing, Content, Border)
+  DEFINE_ENUM_CLASS_SETTER(StyleFloatEdge, ContentBox, MarginBox)
+  DEFINE_ENUM_CLASS_SETTER(StyleUserFocus, None_, SelectMenu)
 
 #undef DEF_SET_ENUMERATED_VALUE
 };
 
 template<typename FieldT>
 struct SetIntegerValueHelper
 {
   static void SetIntegerValue(FieldT& aField, const nsCSSValue& aValue)
@@ -4248,17 +4250,18 @@ nsRuleNode::GetShadowData(const nsCSSVal
       item->mHasColor = true;
       // 2nd argument can be bogus since inherit is not a valid color
       unitOK = SetColor(arr->Item(4), 0, mPresContext, aContext, item->mColor,
                         aConditions);
       NS_ASSERTION(unitOK, "unexpected unit");
     }
 
     if (aIsBoxShadow && arr->Item(5).GetUnit() == eCSSUnit_Enumerated) {
-      NS_ASSERTION(arr->Item(5).GetIntValue() == NS_STYLE_BOX_SHADOW_INSET,
+      NS_ASSERTION(arr->Item(5).GetIntValue()
+                   == uint8_t(StyleBoxShadowType::Inset),
                    "invalid keyword type for box shadow");
       item->mInset = true;
     } else {
       item->mInset = false;
     }
   }
 
   return shadowList.forget();
@@ -5062,17 +5065,17 @@ nsRuleNode::ComputeUserInterfaceData(voi
            parentUI->mUserModify,
            NS_STYLE_USER_MODIFY_READ_ONLY);
 
   // user-focus: enum, inherit, initial
   SetValue(*aRuleData->ValueForUserFocus(),
            ui->mUserFocus, conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
            parentUI->mUserFocus,
-           NS_STYLE_USER_FOCUS_NONE);
+           StyleUserFocus::None_);
 
   // pointer-events: enum, inherit, initial
   SetValue(*aRuleData->ValueForPointerEvents(), ui->mPointerEvents,
            conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
            parentUI->mPointerEvents,
            NS_STYLE_POINTER_EVENTS_AUTO);
 
@@ -7572,17 +7575,17 @@ nsRuleNode::ComputeBorderData(void* aSta
     }
   }
 
   // float-edge: enum, inherit, initial
   SetValue(*aRuleData->ValueForFloatEdge(),
            border->mFloatEdge, conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
            parentBorder->mFloatEdge,
-           NS_STYLE_FLOAT_EDGE_CONTENT_BOX);
+           StyleFloatEdge::ContentBox);
 
   // border-image-source
   const nsCSSValue* borderImageSource = aRuleData->ValueForBorderImageSource();
   if (borderImageSource->GetUnit() == eCSSUnit_Inherit) {
     conditions.SetUncacheable();
     border->mBorderImageSource = parentBorder->mBorderImageSource;
   } else {
     SetStyleImage(aContext,
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -49,56 +49,74 @@ static inline css::Side operator++(css::
 #define NS_FULL_TO_HALF_CORNER(var_, vert_) ((var_)*2 + !!(vert_))
 
 #define NS_SIDE_IS_VERTICAL(side_) ((side_) % 2)
 #define NS_SIDE_TO_FULL_CORNER(side_, second_) \
   (((side_) + !!(second_)) % 4)
 #define NS_SIDE_TO_HALF_CORNER(side_, second_, parallel_) \
   ((((side_) + !!(second_))*2 + ((side_) + !(parallel_))%2) % 8)
 
+// Basic Shapes (currently unused)
+enum class StyleBasicShape : uint8_t{
+  Polygon,
+  Circle,
+  Ellipse,
+  Inset,
+};
+
 // box-sizing
 enum class StyleBoxSizing : uint8_t {
   Content,
   Border
 };
 
+// box-shadow
+enum class StyleBoxShadowType : uint8_t {
+  Inset,
+};
+
+// clip-path type
+// X11 has a #define for None causing conflicts, so we use None_ here
+enum class StyleClipPathType : uint8_t {
+  None_,
+  URL,
+  Shape,
+  Box,
+};
+
 // clip-path sizing
 enum class StyleClipShapeSizing : uint8_t {
   NoBox,
   Content,
   Padding,
   Border,
   Margin,
   Fill,
   Stroke,
   View,
 };
 
-// Basic Shapes
-#define NS_STYLE_BASIC_SHAPE_POLYGON       0
-#define NS_STYLE_BASIC_SHAPE_CIRCLE        1
-#define NS_STYLE_BASIC_SHAPE_ELLIPSE       2
-#define NS_STYLE_BASIC_SHAPE_INSET         3
-
-// box-shadow
-#define NS_STYLE_BOX_SHADOW_INSET         0
-
 // float-edge
-#define NS_STYLE_FLOAT_EDGE_CONTENT_BOX    0
-#define NS_STYLE_FLOAT_EDGE_MARGIN_BOX     1
+enum class StyleFloatEdge : uint8_t {
+  ContentBox,
+  MarginBox,
+};
 
 // user-focus
-#define NS_STYLE_USER_FOCUS_NONE            0
-#define NS_STYLE_USER_FOCUS_IGNORE          1
-#define NS_STYLE_USER_FOCUS_NORMAL          2
-#define NS_STYLE_USER_FOCUS_SELECT_ALL      3
-#define NS_STYLE_USER_FOCUS_SELECT_BEFORE   4
-#define NS_STYLE_USER_FOCUS_SELECT_AFTER    5
-#define NS_STYLE_USER_FOCUS_SELECT_SAME     6
-#define NS_STYLE_USER_FOCUS_SELECT_MENU     7
+// X11 has a #define for None causing conflicts, so we use None_ here
+enum class StyleUserFocus : uint8_t {
+  None_,
+  Ignore,
+  Normal,
+  SelectAll,
+  SelectBefore,
+  SelectAfter,
+  SelectSame,
+  SelectMenu,
+};
 
 // user-select
 #define NS_STYLE_USER_SELECT_NONE       0
 #define NS_STYLE_USER_SELECT_TEXT       1
 #define NS_STYLE_USER_SELECT_ELEMENT    2
 #define NS_STYLE_USER_SELECT_ELEMENTS   3
 #define NS_STYLE_USER_SELECT_ALL        4
 #define NS_STYLE_USER_SELECT_TOGGLE     5
@@ -558,22 +576,16 @@ enum class FillMode : uint32_t;
 
 // See nsStyleDisplay
 #define NS_STYLE_FLOAT_NONE                     0
 #define NS_STYLE_FLOAT_LEFT                     1
 #define NS_STYLE_FLOAT_RIGHT                    2
 #define NS_STYLE_FLOAT_INLINE_START             3
 #define NS_STYLE_FLOAT_INLINE_END               4
 
-// See nsStyleClipPath
-#define NS_STYLE_CLIP_PATH_NONE                 0
-#define NS_STYLE_CLIP_PATH_URL                  1
-#define NS_STYLE_CLIP_PATH_SHAPE                2
-#define NS_STYLE_CLIP_PATH_BOX                  3
-
 // See nsStyleFilter
 #define NS_STYLE_FILTER_NONE                    0
 #define NS_STYLE_FILTER_URL                     1
 #define NS_STYLE_FILTER_BLUR                    2
 #define NS_STYLE_FILTER_BRIGHTNESS              3
 #define NS_STYLE_FILTER_CONTRAST                4
 #define NS_STYLE_FILTER_GRAYSCALE               5
 #define NS_STYLE_FILTER_INVERT                  6
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -327,17 +327,17 @@ nsStylePadding::CalcDifference(const nsS
   return NS_STYLE_HINT_REFLOW & ~nsChangeHint_ClearDescendantIntrinsics;
 }
 
 nsStyleBorder::nsStyleBorder(StyleStructContext aContext)
   : mBorderColors(nullptr)
   , mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL)
   , mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH)
   , mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH)
-  , mFloatEdge(NS_STYLE_FLOAT_EDGE_CONTENT_BOX)
+  , mFloatEdge(StyleFloatEdge::ContentBox)
   , mBoxDecorationBreak(NS_STYLE_BOX_DECORATION_BREAK_SLICE)
   , mComputedBorder(0, 0, 0, 0)
 {
   MOZ_COUNT_CTOR(nsStyleBorder);
 
   NS_FOR_CSS_HALF_CORNERS (corner) {
     mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
   }
@@ -1000,124 +1000,124 @@ nsStyleBasicShape::GetShapeTypeName() co
   NS_NOTREACHED("unexpected type");
   return eCSSKeyword_UNKNOWN;
 }
 
 // --------------------
 // nsStyleClipPath
 //
 nsStyleClipPath::nsStyleClipPath()
-  : mType(NS_STYLE_CLIP_PATH_NONE)
-  , mURL(nullptr)
-  , mSizingBox(mozilla::StyleClipShapeSizing::NoBox)
+  : mURL(nullptr)
+  , mType(StyleClipPathType::None_)
+  , mSizingBox(StyleClipShapeSizing::NoBox)
 {
 }
 
 nsStyleClipPath::nsStyleClipPath(const nsStyleClipPath& aSource)
-  : mType(NS_STYLE_CLIP_PATH_NONE)
-  , mURL(nullptr)
-  , mSizingBox(mozilla::StyleClipShapeSizing::NoBox)
+  : mURL(nullptr)
+  , mType(StyleClipPathType::None_)
+  , mSizingBox(StyleClipShapeSizing::NoBox)
 {
-  if (aSource.mType == NS_STYLE_CLIP_PATH_URL) {
+  if (aSource.mType == StyleClipPathType::URL) {
     SetURL(aSource.mURL);
-  } else if (aSource.mType == NS_STYLE_CLIP_PATH_SHAPE) {
+  } else if (aSource.mType == StyleClipPathType::Shape) {
     SetBasicShape(aSource.mBasicShape, aSource.mSizingBox);
-  } else if (aSource.mType == NS_STYLE_CLIP_PATH_BOX) {
+  } else if (aSource.mType == StyleClipPathType::Box) {
     SetSizingBox(aSource.mSizingBox);
   }
 }
 
 nsStyleClipPath::~nsStyleClipPath()
 {
   ReleaseRef();
 }
 
 nsStyleClipPath&
 nsStyleClipPath::operator=(const nsStyleClipPath& aOther)
 {
   if (this == &aOther) {
     return *this;
   }
 
-  if (aOther.mType == NS_STYLE_CLIP_PATH_URL) {
+  if (aOther.mType == StyleClipPathType::URL) {
     SetURL(aOther.mURL);
-  } else if (aOther.mType == NS_STYLE_CLIP_PATH_SHAPE) {
+  } else if (aOther.mType == StyleClipPathType::Shape) {
     SetBasicShape(aOther.mBasicShape, aOther.mSizingBox);
-  } else if (aOther.mType == NS_STYLE_CLIP_PATH_BOX) {
+  } else if (aOther.mType == StyleClipPathType::Box) {
     SetSizingBox(aOther.mSizingBox);
   } else {
     ReleaseRef();
-    mSizingBox = mozilla::StyleClipShapeSizing::NoBox;
-    mType = NS_STYLE_CLIP_PATH_NONE;
+    mSizingBox = StyleClipShapeSizing::NoBox;
+    mType = StyleClipPathType::None_;
   }
   return *this;
 }
 
 bool
 nsStyleClipPath::operator==(const nsStyleClipPath& aOther) const
 {
   if (mType != aOther.mType) {
     return false;
   }
 
-  if (mType == NS_STYLE_CLIP_PATH_URL) {
+  if (mType == StyleClipPathType::URL) {
     return EqualURIs(mURL, aOther.mURL);
-  } else if (mType == NS_STYLE_CLIP_PATH_SHAPE) {
+  } else if (mType == StyleClipPathType::Shape) {
     return *mBasicShape == *aOther.mBasicShape &&
            mSizingBox == aOther.mSizingBox;
-  } else if (mType == NS_STYLE_CLIP_PATH_BOX) {
+  } else if (mType == StyleClipPathType::Box) {
     return mSizingBox == aOther.mSizingBox;
   }
 
   return true;
 }
 
 void
 nsStyleClipPath::ReleaseRef()
 {
-  if (mType == NS_STYLE_CLIP_PATH_SHAPE) {
+  if (mType == StyleClipPathType::Shape) {
     NS_ASSERTION(mBasicShape, "expected pointer");
     mBasicShape->Release();
-  } else if (mType == NS_STYLE_CLIP_PATH_URL) {
+  } else if (mType == StyleClipPathType::URL) {
     NS_ASSERTION(mURL, "expected pointer");
     mURL->Release();
   }
   // mBasicShap, mURL, etc. are all pointers in a union of pointers. Nulling
   // one of them nulls all of them:
   mURL = nullptr;
 }
 
 void
 nsStyleClipPath::SetURL(nsIURI* aURL)
 {
   NS_ASSERTION(aURL, "expected pointer");
   ReleaseRef();
   mURL = aURL;
   mURL->AddRef();
-  mType = NS_STYLE_CLIP_PATH_URL;
+  mType = StyleClipPathType::URL;
 }
 
 void
 nsStyleClipPath::SetBasicShape(nsStyleBasicShape* aBasicShape,
-                               mozilla::StyleClipShapeSizing aSizingBox)
+                               StyleClipShapeSizing aSizingBox)
 {
   NS_ASSERTION(aBasicShape, "expected pointer");
   ReleaseRef();
   mBasicShape = aBasicShape;
   mBasicShape->AddRef();
   mSizingBox = aSizingBox;
-  mType = NS_STYLE_CLIP_PATH_SHAPE;
+  mType = StyleClipPathType::Shape;
 }
 
 void
-nsStyleClipPath::SetSizingBox(mozilla::StyleClipShapeSizing aSizingBox)
+nsStyleClipPath::SetSizingBox(StyleClipShapeSizing aSizingBox)
 {
   ReleaseRef();
   mSizingBox = aSizingBox;
-  mType = NS_STYLE_CLIP_PATH_BOX;
+  mType = StyleClipPathType::Box;
 }
 
 // --------------------
 // nsStyleFilter
 //
 nsStyleFilter::nsStyleFilter()
   : mType(NS_STYLE_FILTER_NONE)
   , mDropShadow(nullptr)
@@ -2816,87 +2816,87 @@ nsTimingFunction::AssignFromKeyword(int3
   MOZ_ASSERT(0 <= aTimingFunctionType && aTimingFunctionType < 5,
              "keyword out of range");
   mFunc.mX1 = timingFunctionValues[aTimingFunctionType][0];
   mFunc.mY1 = timingFunctionValues[aTimingFunctionType][1];
   mFunc.mX2 = timingFunctionValues[aTimingFunctionType][2];
   mFunc.mY2 = timingFunctionValues[aTimingFunctionType][3];
 }
 
-mozilla::StyleTransition::StyleTransition(const StyleTransition& aCopy)
+StyleTransition::StyleTransition(const StyleTransition& aCopy)
   : mTimingFunction(aCopy.mTimingFunction)
   , mDuration(aCopy.mDuration)
   , mDelay(aCopy.mDelay)
   , mProperty(aCopy.mProperty)
   , mUnknownProperty(aCopy.mUnknownProperty)
 {
 }
 
 void
-mozilla::StyleTransition::SetInitialValues()
+StyleTransition::SetInitialValues()
 {
   mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
   mDuration = 0.0;
   mDelay = 0.0;
   mProperty = eCSSPropertyExtra_all_properties;
 }
 
 void
-mozilla::StyleTransition::SetUnknownProperty(nsCSSProperty aProperty,
+StyleTransition::SetUnknownProperty(nsCSSProperty aProperty,
                                              const nsAString& aPropertyString)
 {
   MOZ_ASSERT(nsCSSProps::LookupProperty(aPropertyString,
                                         CSSEnabledState::eForAllContent) ==
                aProperty,
              "property and property string should match");
   MOZ_ASSERT(aProperty == eCSSProperty_UNKNOWN ||
              aProperty == eCSSPropertyExtra_variable,
              "should be either unknown or custom property");
   mProperty = aProperty;
   mUnknownProperty = NS_Atomize(aPropertyString);
 }
 
 bool
-mozilla::StyleTransition::operator==(const mozilla::StyleTransition& aOther) const
+StyleTransition::operator==(const StyleTransition& aOther) const
 {
   return mTimingFunction == aOther.mTimingFunction &&
          mDuration == aOther.mDuration &&
          mDelay == aOther.mDelay &&
          mProperty == aOther.mProperty &&
          (mProperty != eCSSProperty_UNKNOWN ||
           mUnknownProperty == aOther.mUnknownProperty);
 }
 
-mozilla::StyleAnimation::StyleAnimation(const mozilla::StyleAnimation& aCopy)
+StyleAnimation::StyleAnimation(const StyleAnimation& aCopy)
   : mTimingFunction(aCopy.mTimingFunction)
   , mDuration(aCopy.mDuration)
   , mDelay(aCopy.mDelay)
   , mName(aCopy.mName)
   , mDirection(aCopy.mDirection)
   , mFillMode(aCopy.mFillMode)
   , mPlayState(aCopy.mPlayState)
   , mIterationCount(aCopy.mIterationCount)
 {
 }
 
 void
-mozilla::StyleAnimation::SetInitialValues()
+StyleAnimation::SetInitialValues()
 {
   mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
   mDuration = 0.0;
   mDelay = 0.0;
   mName = EmptyString();
   mDirection = dom::PlaybackDirection::Normal;
   mFillMode = dom::FillMode::None;
   mPlayState = NS_STYLE_ANIMATION_PLAY_STATE_RUNNING;
   mIterationCount = 1.0f;
 }
 
 bool
-mozilla::StyleAnimation::operator==(const mozilla::StyleAnimation& aOther) const
+StyleAnimation::operator==(const StyleAnimation& aOther) const
 {
   return mTimingFunction == aOther.mTimingFunction &&
          mDuration == aOther.mDuration &&
          mDelay == aOther.mDelay &&
          mName == aOther.mName &&
          mDirection == aOther.mDirection &&
          mFillMode == aOther.mFillMode &&
          mPlayState == aOther.mPlayState &&
@@ -3878,17 +3878,17 @@ nsCursorImage::operator=(const nsCursorI
   }
 
   return *this;
 }
 
 nsStyleUserInterface::nsStyleUserInterface(StyleStructContext aContext)
   : mUserInput(NS_STYLE_USER_INPUT_AUTO)
   , mUserModify(NS_STYLE_USER_MODIFY_READ_ONLY)
-  , mUserFocus(NS_STYLE_USER_FOCUS_NONE)
+  , mUserFocus(StyleUserFocus::None_)
   , mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO)
   , mCursor(NS_STYLE_CURSOR_AUTO)
   , mCursorArrayLength(0)
   , mCursorArray(nullptr)
 {
   MOZ_COUNT_CTOR(nsStyleUserInterface);
 }
 
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1255,27 +1255,27 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   {
     if (mBorderImageSource.GetType() == eStyleImageType_Image) {
       return mBorderImageSource.GetImageData();
     }
     return nullptr;
   }
 
 public:
-  nsBorderColors** mBorderColors;        // [reset] composite (stripe) colors
+  nsBorderColors** mBorderColors;     // [reset] composite (stripe) colors
   nsStyleCorners mBorderRadius;       // [reset] coord, percent
   nsStyleImage   mBorderImageSource;  // [reset]
   nsStyleSides   mBorderImageSlice;   // [reset] factor, percent
   nsStyleSides   mBorderImageWidth;   // [reset] length, factor, percent, auto
   nsStyleSides   mBorderImageOutset;  // [reset] length, factor
 
   uint8_t        mBorderImageFill;    // [reset]
   uint8_t        mBorderImageRepeatH; // [reset] see nsStyleConsts.h
   uint8_t        mBorderImageRepeatV; // [reset]
-  uint8_t        mFloatEdge;          // [reset]
+  mozilla::StyleFloatEdge mFloatEdge; // [reset]
   uint8_t        mBoxDecorationBreak; // [reset] see nsStyleConsts.h
 
 protected:
   // mComputedBorder holds the CSS2.1 computed border-width values.
   // In particular, these widths take into account the border-style
   // for the relevant side, and the values are rounded to the nearest
   // device pixel (which is not part of the definition of computed
   // values). The presence or absence of a border-image does not
@@ -3100,20 +3100,20 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
            nsChangeHint_NeutralChange;
   }
   static nsChangeHint DifferenceAlwaysHandledForDescendants() {
     // CalcDifference never returns the reflow hints that are sometimes
     // handled for descendants as hints not handled for descendants.
     return nsChangeHint_NeedReflow;
   }
 
-  uint8_t   mUserInput;       // [inherited]
-  uint8_t   mUserModify;      // [inherited] (modify-content)
-  uint8_t   mUserFocus;       // [inherited] (auto-select)
-  uint8_t   mPointerEvents;   // [inherited] see nsStyleConsts.h
+  uint8_t                   mUserInput;       // [inherited]
+  uint8_t                   mUserModify;      // [inherited] (modify-content)
+  mozilla::StyleUserFocus   mUserFocus;       // [inherited] (auto-select)
+  uint8_t                   mPointerEvents;   // [inherited] see nsStyleConsts.h
 
   uint8_t   mCursor;          // [inherited] See nsStyleConsts.h
 
   uint32_t mCursorArrayLength;
   nsCursorImage *mCursorArray;// [inherited] The specified URL values
                               //   and coordinates.  Takes precedence over
                               //   mCursor.  Zero-length array is represented
                               //   by null pointer.
@@ -3501,47 +3501,47 @@ struct nsStyleClipPath
 
   nsStyleClipPath& operator=(const nsStyleClipPath& aOther);
 
   bool operator==(const nsStyleClipPath& aOther) const;
   bool operator!=(const nsStyleClipPath& aOther) const {
     return !(*this == aOther);
   }
 
-  int32_t GetType() const {
+  mozilla::StyleClipPathType GetType() const {
     return mType;
   }
 
   nsIURI* GetURL() const {
-    NS_ASSERTION(mType == NS_STYLE_CLIP_PATH_URL, "wrong clip-path type");
+    NS_ASSERTION(mType == mozilla::StyleClipPathType::URL, "wrong clip-path type");
     return mURL;
   }
   void SetURL(nsIURI* aURL);
 
   nsStyleBasicShape* GetBasicShape() const {
-    NS_ASSERTION(mType == NS_STYLE_CLIP_PATH_SHAPE, "wrong clip-path type");
+    NS_ASSERTION(mType == mozilla::StyleClipPathType::Shape, "wrong clip-path type");
     return mBasicShape;
   }
 
   void SetBasicShape(nsStyleBasicShape* mBasicShape,
                      mozilla::StyleClipShapeSizing aSizingBox =
                      mozilla::StyleClipShapeSizing::NoBox);
 
   mozilla::StyleClipShapeSizing GetSizingBox() const { return mSizingBox; }
   void SetSizingBox(mozilla::StyleClipShapeSizing aSizingBox);
 
 private:
   void ReleaseRef();
   void* operator new(size_t) = delete;
 
-  int32_t mType; // see NS_STYLE_CLIP_PATH_* constants in nsStyleConsts.h
   union {
     nsStyleBasicShape* mBasicShape;
     nsIURI* mURL;
   };
+  mozilla::StyleClipPathType    mType;
   mozilla::StyleClipShapeSizing mSizingBox;
 };
 
 struct nsStyleFilter
 {
   nsStyleFilter();
   nsStyleFilter(const nsStyleFilter& aSource);
   ~nsStyleFilter();
@@ -3620,17 +3620,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
     // CalcDifference never returns the reflow hints that are sometimes
     // handled for descendants as hints not handled for descendants.
     return nsChangeHint_NeedReflow |
            nsChangeHint_ReflowChangesSizeOrPosition |
            nsChangeHint_ClearAncestorIntrinsics;
   }
 
   bool HasClipPath() const {
-    return mClipPath.GetType() != NS_STYLE_CLIP_PATH_NONE;
+    return mClipPath.GetType() != mozilla::StyleClipPathType::None_;
   }
 
   bool HasNonScalingStroke() const {
     return mVectorEffect == NS_STYLE_VECTOR_EFFECT_NON_SCALING_STROKE;
   }
 
   nsStyleImageLayers    mMask;
   nsStyleClipPath  mClipPath;         // [reset]
--- a/layout/svg/nsCSSClipPathInstance.cpp
+++ b/layout/svg/nsCSSClipPathInstance.cpp
@@ -18,42 +18,42 @@
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 /* static*/ void
 nsCSSClipPathInstance::ApplyBasicShapeClip(gfxContext& aContext,
                                            nsIFrame* aFrame)
 {
   auto& clipPathStyle = aFrame->StyleSVGReset()->mClipPath;
-  int32_t type = clipPathStyle.GetType();
-  MOZ_ASSERT(type != NS_STYLE_CLIP_PATH_NONE, "unexpected none value");
+  StyleClipPathType type = clipPathStyle.GetType();
+  MOZ_ASSERT(type != StyleClipPathType::None_, "unexpected none value");
   // In the future nsCSSClipPathInstance may handle <clipPath> references as
   // well. For the time being return early.
-  if (type == NS_STYLE_CLIP_PATH_URL) {
+  if (type == StyleClipPathType::URL) {
     return;
   }
 
   nsCSSClipPathInstance instance(aFrame, clipPathStyle);
 
   aContext.NewPath();
   RefPtr<Path> path = instance.CreateClipPath(aContext.GetDrawTarget());
   aContext.SetPath(path);
   aContext.Clip();
 }
 
 /* static*/ bool
 nsCSSClipPathInstance::HitTestBasicShapeClip(nsIFrame* aFrame,
                                              const gfxPoint& aPoint)
 {
   auto& clipPathStyle = aFrame->StyleSVGReset()->mClipPath;
-  int32_t type = clipPathStyle.GetType();
-  MOZ_ASSERT(type != NS_STYLE_CLIP_PATH_NONE, "unexpected none value");
+  StyleClipPathType type = clipPathStyle.GetType();
+  MOZ_ASSERT(type != StyleClipPathType::None_, "unexpected none value");
   // In the future nsCSSClipPathInstance may handle <clipPath> references as
   // well. For the time being return early.
-  if (type == NS_STYLE_CLIP_PATH_URL) {
+  if (type == StyleClipPathType::URL) {
     return false;
   }
 
   nsCSSClipPathInstance instance(aFrame, clipPathStyle);
 
   RefPtr<DrawTarget> drawTarget =
     gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
   RefPtr<Path> path = instance.CreateClipPath(drawTarget);
@@ -76,17 +76,17 @@ nsCSSClipPathInstance::CreateClipPath(Dr
       break;
     case StyleClipShapeSizing::Margin:
       r = mTargetFrame->GetMarginRectRelativeToSelf();
       break;
     default: // Use the border box
       r = mTargetFrame->GetRectRelativeToSelf();
   }
 
-  if (mClipPathStyle.GetType() != NS_STYLE_CLIP_PATH_SHAPE) {
+  if (mClipPathStyle.GetType() != StyleClipPathType::Shape) {
     // TODO Clip to border-radius/reference box if no shape
     // was specified.
     RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
     return builder->Finish();
   }
 
   nscoord appUnitsPerDevPixel =
     mTargetFrame->PresContext()->AppUnitsPerDevPixel();
--- a/layout/svg/nsSVGEffects.cpp
+++ b/layout/svg/nsSVGEffects.cpp
@@ -566,17 +566,17 @@ nsSVGEffects::GetEffectProperties(nsIFra
 {
   NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
 
   EffectProperties result;
   const nsStyleSVGReset *style = aFrame->StyleSVGReset();
 
   result.mFilter = GetOrCreateFilterProperty(aFrame);
 
-  if (style->mClipPath.GetType() == NS_STYLE_CLIP_PATH_URL) {
+  if (style->mClipPath.GetType() == StyleClipPathType::URL) {
     result.mClipPath =
       GetPaintingProperty(style->mClipPath.GetURL(), aFrame, ClipPathProperty());
   } else {
     result.mClipPath = nullptr;
   }
 
   MOZ_ASSERT(style->mMask.mImageCount > 0);
   result.mMask = style->mMask.HasLayerWithImage()
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -761,16 +761,20 @@ public class BrowserApp extends GeckoApp
                       .run();
         }
 
         AudioFocusAgent.getInstance().attachToContext(this);
 
         for (final BrowserAppDelegate delegate : delegates) {
             delegate.onCreate(this, savedInstanceState);
         }
+
+        // We want to get an understanding of how our user base is spread (bug 1221646).
+        final String installerPackageName = getPackageManager().getInstallerPackageName(getPackageName());
+        Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH, TelemetryContract.Method.SYSTEM, "installer_" + installerPackageName);
     }
 
     /**
      * Gets whether or not we're in automation from the passed in environment variables.
      *
      * We need to read environment variables from the intent string
      * extra because environment variables from our test harness aren't set
      * until Gecko is loaded, and we need to know this before then.
--- a/mobile/android/base/java/org/mozilla/gecko/media/MediaControlService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/MediaControlService.java
@@ -97,23 +97,33 @@ public class MediaControlService extends
     }
 
     @Override
     public void onTabChanged(Tab tab, Tabs.TabEvents msg, String data) {
         if (!mIsInitMediaSession) {
             return;
         }
 
-        if (tab == mTabReference.get()) {
-            return;
-        }
+        switch (msg) {
+            case AUDIO_PLAYING_CHANGE:
+                if (tab == mTabReference.get()) {
+                    return;
+                }
 
-        if (msg == Tabs.TabEvents.AUDIO_PLAYING_CHANGE && tab.isAudioPlaying()) {
-            mTabReference = new WeakReference<Tab>(tab);
-            notifyControlInterfaceChanged(ACTION_PAUSE);
+                mTabReference = new WeakReference<>(tab);
+                notifyControlInterfaceChanged(ACTION_PAUSE);
+                break;
+
+            case CLOSED:
+                final Tab playingTab = mTabReference.get();
+                if (playingTab == null || playingTab == tab) {
+                    // The playing tab disappeared or was closed. Remove the controls and stop the service.
+                    notifyControlInterfaceChanged(ACTION_REMOVE_CONTROL);
+                }
+                break;
         }
     }
 
     private boolean isAndroidVersionLollopopOrHigher() {
         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
     }
 
     private void handleIntent(Intent intent) {
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -70,16 +70,24 @@
 class PrefCallback;
 
 namespace mozilla {
 
 // Definitions
 #define INITIAL_PREF_FILES 10
 static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
 
+void
+Preferences::DirtyCallback()
+{
+  if (gHashTable && sPreferences && !sPreferences->mDirty) {
+    sPreferences->mDirty = true;
+  }
+}
+
 // Prototypes
 static nsresult openPrefFile(nsIFile* aFile);
 static nsresult pref_InitInitialObjects(void);
 static nsresult pref_LoadPrefsInDirList(const char *listId);
 static nsresult ReadExtensionPrefs(nsIFile *aFile);
 
 static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
 static const char kOldTelemetryPref[] = "toolkit.telemetry.enabledPreRelease";
@@ -474,16 +482,17 @@ Preferences::Shutdown()
 
 //-----------------------------------------------------------------------------
 
 /*
  * Constructor/Destructor
  */
 
 Preferences::Preferences()
+  : mDirty(false)
 {
 }
 
 Preferences::~Preferences()
 {
   NS_ASSERTION(sPreferences == this, "Isn't this the singleton instance?");
 
   delete gObserverTable;
@@ -523,16 +532,17 @@ NS_INTERFACE_MAP_END
  * nsIPrefService Implementation
  */
 
 nsresult
 Preferences::Init()
 {
   nsresult rv;
 
+  PREF_SetDirtyCallback(&DirtyCallback);
   PREF_Init();
 
   rv = pref_InitInitialObjects();
   NS_ENSURE_SUCCESS(rv, rv);
 
   using mozilla::dom::ContentChild;
   if (XRE_IsContentProcess()) {
     InfallibleTArray<PrefSetting> prefs;
@@ -790,17 +800,17 @@ Preferences::GetDefaultBranch(const char
     return NS_ERROR_OUT_OF_MEMORY;
 
   prefBranch.forget(_retval);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 Preferences::GetDirty(bool *_retval) {
-  *_retval = gDirty;
+  *_retval = mDirty;
   return NS_OK;
 }
 
 nsresult
 Preferences::NotifyServiceObservers(const char *aTopic)
 {
   nsCOMPtr<nsIObserverService> observerService = 
     mozilla::services::GetObserverService();  
@@ -909,21 +919,22 @@ Preferences::ReadAndOwnUserPrefFile(nsIF
 
   return rv;
 }
 
 nsresult
 Preferences::SavePrefFileInternal(nsIFile *aFile)
 {
   if (nullptr == aFile) {
-    // the gDirty flag tells us if we should write to mCurrentFile
+    // the mDirty flag tells us if we should write to mCurrentFile
     // we only check this flag when the caller wants to write to the default
-    if (!gDirty)
+    if (!mDirty) {
       return NS_OK;
-    
+    }
+
     // It's possible that we never got a prefs file.
     nsresult rv = NS_OK;
     if (mCurrentFile)
       rv = WritePrefFile(mCurrentFile);
 
     return rv;
   } else {
     return WritePrefFile(aFile);
@@ -999,17 +1010,17 @@ Preferences::WritePrefFile(nsIFile* aFil
   if (safeStream) {
     rv = safeStream->Finish();
     if (NS_FAILED(rv)) {
       NS_WARNING("failed to save prefs file! possible data loss");
       return rv;
     }
   }
 
-  gDirty = false;
+  mDirty = false;
   return NS_OK;
 }
 
 static nsresult openPrefFile(nsIFile* aFile)
 {
   nsCOMPtr<nsIInputStream> inStr;
 
   nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), aFile);
--- a/modules/libpref/Preferences.h
+++ b/modules/libpref/Preferences.h
@@ -363,16 +363,18 @@ public:
 
   // Used to synchronise preferences between chrome and content processes.
   static void GetPreferences(InfallibleTArray<PrefSetting>* aPrefs);
   static void GetPreference(PrefSetting* aPref);
   static void SetPreference(const PrefSetting& aPref);
 
   static int64_t SizeOfIncludingThisAndOtherStuff(mozilla::MallocSizeOf aMallocSizeOf);
 
+  static void DirtyCallback();
+
 protected:
   virtual ~Preferences();
 
   nsresult NotifyServiceObservers(const char *aSubject);
   /**
    * Reads the default pref file or, if that failed, try to save a new one.
    *
    * @return NS_OK if either action succeeded,
@@ -383,16 +385,17 @@ protected:
   nsresult ReadAndOwnUserPrefFile(nsIFile *aFile);
   nsresult ReadAndOwnSharedUserPrefFile(nsIFile *aFile);
   nsresult SavePrefFileInternal(nsIFile* aFile);
   nsresult WritePrefFile(nsIFile* aFile);
   nsresult MakeBackupPrefFile(nsIFile *aFile);
 
 private:
   nsCOMPtr<nsIFile>        mCurrentFile;
+  bool                     mDirty;
 
   static Preferences*      sPreferences;
   static nsIPrefBranch*    sRootBranch;
   static nsIPrefBranch*    sDefaultRootBranch;
   static bool              sShutdown;
 
   /**
    * Init static members.  TRUE if it succeeded.  Otherwise, FALSE.
--- a/modules/libpref/prefapi.cpp
+++ b/modules/libpref/prefapi.cpp
@@ -64,17 +64,16 @@ matchPrefEntry(const PLDHashEntryHdr* en
     if (!prefEntry->key || !key) return false;
 
     const char *otherKey = reinterpret_cast<const char*>(key);
     return (strcmp(prefEntry->key, otherKey) == 0);
 }
 
 PLDHashTable*       gHashTable;
 static PLArenaPool  gPrefNameArena;
-bool                gDirty = false;
 
 static struct CallbackNode* gCallbacks = nullptr;
 static bool         gIsAnyPrefLocked = false;
 // These are only used during the call to pref_DoCallback
 static bool         gCallbacksInProgress = false;
 static bool         gShouldCleanupDeadNodes = false;
 
 
@@ -109,16 +108,35 @@ static char *ArenaStrDup(const char* str
     void* mem;
     uint32_t len = strlen(str);
     PL_ARENA_ALLOCATE(mem, aArena, len+1);
     if (mem)
         memcpy(mem, str, len+1);
     return static_cast<char*>(mem);
 }
 
+static PrefsDirtyFunc gDirtyCallback = nullptr;
+
+inline void MakeDirtyCallback()
+{
+    // Right now the callback function is always set, so we don't need
+    // to complicate the code to cover the scenario where we set the callback
+    // after we've already tried to make it dirty.  If this assert triggers
+    // we will add that code.
+    MOZ_ASSERT(gDirtyCallback);
+    if (gDirtyCallback) {
+        gDirtyCallback();
+    }
+}
+
+void PREF_SetDirtyCallback(PrefsDirtyFunc aFunc)
+{
+    gDirtyCallback = aFunc;
+}
+
 /*---------------------------------------------------------------------------*/
 
 static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type);
 /* -- Privates */
 struct CallbackNode {
     char*                   domain;
     // If someone attempts to remove the node from the callback list while
     // pref_DoCallback is running, |func| is set to nullptr. Such nodes will
@@ -577,17 +595,17 @@ PREF_DeleteBranch(const char *branch_nam
             and "ldap" (if such a leaf node exists) but not "ldap_1.xxx" */
         if (PL_strncmp(entry->key, to_delete, (uint32_t) len) == 0 ||
             (len-1 == (int)strlen(entry->key) &&
              PL_strncmp(entry->key, to_delete, (uint32_t)(len-1)) == 0)) {
             iter.Remove();
         }
     }
 
-    gDirty = true;
+    MakeDirtyCallback();
     return NS_OK;
 }
 
 
 nsresult
 PREF_ClearUserPref(const char *pref_name)
 {
     if (!gHashTable)
@@ -597,17 +615,17 @@ PREF_ClearUserPref(const char *pref_name
     if (pref && pref->prefFlags.HasUserValue()) {
         pref->prefFlags.SetHasUserValue(false);
 
         if (!pref->prefFlags.HasDefault()) {
             gHashTable->RemoveEntry(pref);
         }
 
         pref_DoCallback(pref_name);
-        gDirty = true;
+        MakeDirtyCallback();
     }
     return NS_OK;
 }
 
 nsresult
 PREF_ClearAllUserPrefs()
 {
 #ifndef MOZ_B2G
@@ -630,17 +648,17 @@ PREF_ClearAllUserPrefs()
             }
         }
     }
 
     for (std::string& prefString : prefStrings) {
         pref_DoCallback(prefString.c_str());
     }
 
-    gDirty = true;
+    MakeDirtyCallback();
     return NS_OK;
 }
 
 nsresult PREF_LockPref(const char *key, bool lockit)
 {
     if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
@@ -770,26 +788,26 @@ nsresult pref_HashPref(const char *key, 
         if ((pref->prefFlags.HasDefault()) &&
             !(pref->prefFlags.HasStickyDefault()) &&
             !pref_ValueChanged(pref->defaultPref, value, type) &&
             !(flags & kPrefForceSet)) {
             if (pref->prefFlags.HasUserValue()) {
                 /* XXX should we free a user-set string value if there is one? */
                 pref->prefFlags.SetHasUserValue(false);
                 if (!pref->prefFlags.IsLocked()) {
-                    gDirty = true;
+                    MakeDirtyCallback();
                     valueChanged = true;
                 }
             }
         } else if (!pref->prefFlags.HasUserValue() ||
                  !pref->prefFlags.IsPrefType(type) ||
                  pref_ValueChanged(pref->userPref, value, type) ) {
             pref->prefFlags = pref_SetValue(&pref->userPref, pref->prefFlags, value, type).SetHasUserValue(true);
             if (!pref->prefFlags.IsLocked()) {
-                gDirty = true;
+                MakeDirtyCallback();
                 valueChanged = true;
             }
         }
     }
 
     if (valueChanged) {
         return pref_DoCallback(key);
     }
--- a/modules/libpref/prefapi.h
+++ b/modules/libpref/prefapi.h
@@ -240,12 +240,19 @@ nsresult PREF_UnregisterCallback(const c
  */
 void PREF_ReaderCallback( void *closure,
                           const char *pref,
                           PrefValue   value,
                           PrefType    type,
                           bool        isDefault,
                           bool        isStickyDefault);
 
+
+/*
+ * Callback whenever we change a preference
+ */
+typedef void (*PrefsDirtyFunc) ();
+void PREF_SetDirtyCallback(PrefsDirtyFunc);
+
 #ifdef __cplusplus
 }
 #endif
 #endif
--- a/modules/libpref/prefapi_private_data.h
+++ b/modules/libpref/prefapi_private_data.h
@@ -7,17 +7,16 @@
 
 #ifndef prefapi_private_data_h
 #define prefapi_private_data_h
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/UniquePtr.h"
 
 extern PLDHashTable* gHashTable;
-extern bool gDirty;
 
 namespace mozilla {
 namespace dom {
 class PrefSetting;
 } // namespace dom
 } // namespace mozilla
 
 mozilla::UniquePtr<char*[]>
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -20,13 +20,13 @@ support-files =
 [test_rel_preconnect.html]
 [test_uri_scheme.html]
 [test_user_agent_overrides.html]
 [test_user_agent_updates.html]
 [test_user_agent_updates_reset.html]
 [test_viewsource_unlinkable.html]
 [test_xhr_method_case.html]
 [test_web_packaged_app.html]
-skip-if = buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 [test_loadinfo_redirectchain.html]
 skip-if = buildapp == 'b2g' #no ssl support
 [test_idn_redirect.html]
 [test_redirect_ref.html]
--- a/python/mozbuild/mozbuild/configure/constants.py
+++ b/python/mozbuild/mozbuild/configure/constants.py
@@ -1,15 +1,16 @@
 # 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 absolute_import, print_function, unicode_literals
 
 from mozbuild.util import EnumString
+from collections import OrderedDict
 
 
 CompilerType = EnumString.subclass(
     'clang',
     'clang-cl',
     'gcc',
     'msvc',
 )
@@ -54,8 +55,42 @@ CPU = EnumString.subclass(
     'x86',
     'x86_64',
 )
 
 Endianness = EnumString.subclass(
     'big',
     'little',
 )
+
+# The order of those checks matter
+CPU_preprocessor_checks = OrderedDict((
+    ('x86', '__i386__ || _M_IX86'),
+    ('x86_64', '__x86_64__ || _M_X64'),
+    ('arm', '__arm__ || _M_ARM'),
+    ('aarch64', '__aarch64__'),
+    ('ia64', '__ia64__'),
+    ('s390x', '__s390x__'),
+    ('s390', '__s390__'),
+    ('ppc64', '__powerpc64__'),
+    ('ppc', '__powerpc__'),
+    ('Alpha', '__alpha__'),
+    ('hppa', '__hppa__'),
+    ('sparc64', '__sparc__ && __arch64__'),
+    ('sparc', '__sparc__'),
+    ('mips64', '__mips64'),
+    ('mips32', '__mips__'),
+))
+
+assert sorted(CPU_preprocessor_checks.keys()) == sorted(CPU.POSSIBLE_VALUES)
+
+kernel_preprocessor_checks = {
+    'Darwin': '__APPLE__',
+    'DragonFly': '__DragonFly__',
+    'FreeBSD': '__FreeBSD__',
+    'kFreeBSD': '__FreeBSD_kernel__',
+    'Linux': '__linux__',
+    'NetBSD': '__NetBSD__',
+    'OpenBSD': '__OpenBSD__',
+    'WINNT': '_WIN32 || __CYGWIN__',
+}
+
+assert sorted(kernel_preprocessor_checks.keys()) == sorted(Kernel.POSSIBLE_VALUES)
--- a/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
@@ -49,16 +49,18 @@ SUPPORTS_GNUXX11 = {
 @memoize
 def GCC_BASE(version):
     version = Version(version)
     return FakeCompiler({
         '__GNUC__': version.major,
         '__GNUC_MINOR__': version.minor,
         '__GNUC_PATCHLEVEL__': version.patch,
         '__STDC__': 1,
+        '__ORDER_LITTLE_ENDIAN__': 1234,
+        '__ORDER_BIG_ENDIAN__': 4321,
     })
 
 
 @memoize
 def GCC(version):
     return GCC_BASE(version) + SUPPORTS_GNU99
 
 
@@ -69,16 +71,70 @@ def GXX(version):
 
 GCC_4_7 = GCC('4.7.3')
 GXX_4_7 = GXX('4.7.3')
 GCC_4_9 = GCC('4.9.3')
 GXX_4_9 = GXX('4.9.3')
 GCC_5 = GCC('5.2.1') + DEFAULT_C11
 GXX_5 = GXX('5.2.1')
 
+GCC_PLATFORM_LITTLE_ENDIAN = {
+    '__BYTE_ORDER__': 1234,
+}
+
+GCC_PLATFORM_BIG_ENDIAN = {
+    '__BYTE_ORDER__': 4321,
+}
+
+GCC_PLATFORM_X86 = FakeCompiler(GCC_PLATFORM_LITTLE_ENDIAN) + {
+    None: {
+        '__i386__': 1,
+    },
+    '-m64': {
+        '__i386__': False,
+        '__x86_64__': 1,
+    },
+}
+
+GCC_PLATFORM_X86_64 = FakeCompiler(GCC_PLATFORM_LITTLE_ENDIAN) + {
+    None: {
+        '__x86_64__': 1,
+    },
+    '-m32': {
+        '__x86_64__': False,
+        '__i386__': 1,
+    },
+}
+
+GCC_PLATFORM_ARM = FakeCompiler(GCC_PLATFORM_LITTLE_ENDIAN) + {
+    '__arm__': 1,
+}
+
+GCC_PLATFORM_LINUX = {
+    '__linux__': 1,
+}
+
+GCC_PLATFORM_DARWIN = {
+    '__APPLE__': 1,
+}
+
+GCC_PLATFORM_WIN = {
+    '_WIN32': 1,
+}
+
+GCC_PLATFORM_X86_LINUX = FakeCompiler(GCC_PLATFORM_X86, GCC_PLATFORM_LINUX)
+GCC_PLATFORM_X86_64_LINUX = FakeCompiler(GCC_PLATFORM_X86_64,
+                                         GCC_PLATFORM_LINUX)
+GCC_PLATFORM_ARM_LINUX = FakeCompiler(GCC_PLATFORM_ARM, GCC_PLATFORM_LINUX)
+GCC_PLATFORM_X86_OSX = FakeCompiler(GCC_PLATFORM_X86, GCC_PLATFORM_DARWIN)
+GCC_PLATFORM_X86_64_OSX = FakeCompiler(GCC_PLATFORM_X86_64,
+                                       GCC_PLATFORM_DARWIN)
+GCC_PLATFORM_X86_WIN = FakeCompiler(GCC_PLATFORM_X86, GCC_PLATFORM_WIN)
+GCC_PLATFORM_X86_64_WIN = FakeCompiler(GCC_PLATFORM_X86_64, GCC_PLATFORM_WIN)
+
 
 @memoize
 def CLANG_BASE(version):
     version = Version(version)
     return FakeCompiler({
         '__clang__': 1,
         '__clang_major__': version.major,
         '__clang_minor__': version.minor,
@@ -102,16 +158,39 @@ CLANGXX_3_3 = CLANGXX('3.3.0')
 CLANG_3_6 = CLANG('3.6.2') + DEFAULT_C11
 CLANGXX_3_6 = CLANGXX('3.6.2') + {
     '-std=gnu++11': {
         '__has_feature(cxx_alignof)': '1',
     },
 }
 
 
+def CLANG_PLATFORM(gcc_platform):
+    base = {
+        '--target=x86_64-linux-gnu': GCC_PLATFORM_X86_64_LINUX[None],
+        '--target=x86_64-darwin11.2.0': GCC_PLATFORM_X86_64_OSX[None],
+        '--target=i686-linux-gnu': GCC_PLATFORM_X86_LINUX[None],
+        '--target=i686-darwin11.2.0': GCC_PLATFORM_X86_OSX[None],
+        '--target=arm-linux-gnu': GCC_PLATFORM_ARM_LINUX[None],
+    }
+    undo_gcc_platform = {
+        k: {symbol: False for symbol in gcc_platform[None]}
+        for k in base
+    }
+    return FakeCompiler(gcc_platform, undo_gcc_platform, base)
+
+
+CLANG_PLATFORM_X86_LINUX = CLANG_PLATFORM(GCC_PLATFORM_X86_LINUX)
+CLANG_PLATFORM_X86_64_LINUX = CLANG_PLATFORM(GCC_PLATFORM_X86_64_LINUX)
+CLANG_PLATFORM_X86_OSX = CLANG_PLATFORM(GCC_PLATFORM_X86_OSX)
+CLANG_PLATFORM_X86_64_OSX = CLANG_PLATFORM(GCC_PLATFORM_X86_64_OSX)
+CLANG_PLATFORM_X86_WIN = CLANG_PLATFORM(GCC_PLATFORM_X86_WIN)
+CLANG_PLATFORM_X86_64_WIN = CLANG_PLATFORM(GCC_PLATFORM_X86_64_WIN)
+
+
 @memoize
 def VS(version):
     version = Version(version)
     return FakeCompiler({
         None: {
             '_MSC_VER': '%02d%02d' % (version.major, version.minor),
             '_MSC_FULL_VER': '%02d%02d%05d' % (version.major, version.minor,
                                                version.patch),
@@ -121,27 +200,41 @@ def VS(version):
 
 
 VS_2013u2 = VS('18.00.30501')
 VS_2013u3 = VS('18.00.30723')
 VS_2015 = VS('19.00.23026')
 VS_2015u1 = VS('19.00.23506')
 VS_2015u2 = VS('19.00.23918')
 
+VS_PLATFORM_X86 = {
+    '_M_IX86': 600,
+    '_WIN32': 1,
+}
+
+VS_PLATFORM_X86_64 = {
+    '_M_X64': 100,
+    '_WIN32': 1,
+    '_WIN64': 1,
+}
+
 # Note: In reality, the -std=gnu* options are only supported when preceded by
 # -Xclang.
 CLANG_CL_3_9 = (CLANG_BASE('3.9.0') + VS('18.00.00000') + DEFAULT_C11 +
                 SUPPORTS_GNU99 + SUPPORTS_GNUXX11) + {
     '*.cpp': {
         '__STDC_VERSION__': False,
         '__cplusplus': '201103L',
     },
     '-fms-compatibility-version=18.00.30723': VS('18.00.30723')[None],
 }
 
+CLANG_CL_PLATFORM_X86 = FakeCompiler(VS_PLATFORM_X86, GCC_PLATFORM_X86[None])
+CLANG_CL_PLATFORM_X86_64 = FakeCompiler(VS_PLATFORM_X86_64, GCC_PLATFORM_X86_64[None])
+
 
 class BaseToolchainTest(BaseConfigureTest):
     def setUp(self):
         super(BaseToolchainTest, self).setUp()
         self.out = StringIO()
         self.logger = logging.getLogger('BaseToolchainTest')
         self.logger.setLevel(logging.ERROR)
         self.handler = logging.StreamHandler(self.out)
@@ -192,28 +285,28 @@ class BaseToolchainTest(BaseConfigureTes
             except SystemExit:
                 self.assertEquals((var, result),
                                   (var, self.out.getvalue().strip()))
                 return
 
 
 class LinuxToolchainTest(BaseToolchainTest):
     PATHS = {
-        '/usr/bin/gcc': GCC_4_9,
-        '/usr/bin/g++': GXX_4_9,
-        '/usr/bin/gcc-4.7': GCC_4_7,
-        '/usr/bin/g++-4.7': GXX_4_7,
-        '/usr/bin/gcc-5': GCC_5,
-        '/usr/bin/g++-5': GXX_5,
-        '/usr/bin/clang': CLANG_3_6,
-        '/usr/bin/clang++': CLANGXX_3_6,
-        '/usr/bin/clang-3.6': CLANG_3_6,
-        '/usr/bin/clang++-3.6': CLANGXX_3_6,
-        '/usr/bin/clang-3.3': CLANG_3_3,
-        '/usr/bin/clang++-3.3': CLANGXX_3_3,
+        '/usr/bin/gcc': GCC_4_9 + GCC_PLATFORM_X86_64_LINUX,
+        '/usr/bin/g++': GXX_4_9 + GCC_PLATFORM_X86_64_LINUX,
+        '/usr/bin/gcc-4.7': GCC_4_7 + GCC_PLATFORM_X86_64_LINUX,
+        '/usr/bin/g++-4.7': GXX_4_7 + GCC_PLATFORM_X86_64_LINUX,
+        '/usr/bin/gcc-5': GCC_5 + GCC_PLATFORM_X86_64_LINUX,
+        '/usr/bin/g++-5': GXX_5 + GCC_PLATFORM_X86_64_LINUX,
+        '/usr/bin/clang': CLANG_3_6 + CLANG_PLATFORM_X86_64_LINUX,
+        '/usr/bin/clang++': CLANGXX_3_6 + CLANG_PLATFORM_X86_64_LINUX,
+        '/usr/bin/clang-3.6': CLANG_3_6 + CLANG_PLATFORM_X86_64_LINUX,
+        '/usr/bin/clang++-3.6': CLANGXX_3_6 + CLANG_PLATFORM_X86_64_LINUX,
+        '/usr/bin/clang-3.3': CLANG_3_3 + CLANG_PLATFORM_X86_64_LINUX,
+        '/usr/bin/clang++-3.3': CLANGXX_3_3 + CLANG_PLATFORM_X86_64_LINUX,
     }
     GCC_4_7_RESULT = ('Only GCC 4.8 or newer is supported '
                       '(found version 4.7.3).')
     GXX_4_7_RESULT = GCC_4_7_RESULT
     GCC_4_9_RESULT = CompilerResult(
         flags=['-std=gnu99'],
         version='4.9.3',
         type='gcc',
@@ -401,18 +494,18 @@ class LinuxToolchainTest(BaseToolchainTe
         }
         self.do_toolchain_test(paths, {
             'c_compiler': 'Cannot find the target C compiler',
         })
 
     def test_absolute_path(self):
         paths = dict(self.PATHS)
         paths.update({
-            '/opt/clang/bin/clang': CLANG_3_6,
-            '/opt/clang/bin/clang++': CLANGXX_3_6,
+            '/opt/clang/bin/clang': paths['/usr/bin/clang'],
+            '/opt/clang/bin/clang++': paths['/usr/bin/clang++'],
         })
         result = {
             'c_compiler': self.CLANG_3_6_RESULT + {
                 'compiler': '/opt/clang/bin/clang',
             },
             'cxx_compiler': self.CLANGXX_3_6_RESULT + {
                 'compiler': '/opt/clang/bin/clang++'
             },
@@ -424,18 +517,18 @@ class LinuxToolchainTest(BaseToolchainTe
         # With CXX guess too.
         self.do_toolchain_test(paths, result, environ={
             'CC': '/opt/clang/bin/clang',
         })
 
     def test_atypical_name(self):
         paths = dict(self.PATHS)
         paths.update({
-            '/usr/bin/afl-clang-fast': CLANG_3_6,
-            '/usr/bin/afl-clang-fast++': CLANGXX_3_6,
+            '/usr/bin/afl-clang-fast': paths['/usr/bin/clang'],
+            '/usr/bin/afl-clang-fast++': paths['/usr/bin/clang++'],
         })
         self.do_toolchain_test(paths, {
             'c_compiler': self.CLANG_3_6_RESULT + {
                 'compiler': '/usr/bin/afl-clang-fast',
             },
             'cxx_compiler': self.CLANGXX_3_6_RESULT + {
                 'compiler': '/usr/bin/afl-clang-fast++',
             },
@@ -462,19 +555,108 @@ class LinuxToolchainTest(BaseToolchainTe
             'host_cxx_compiler': self.GXX_4_9_RESULT,
         }, environ={
             'CC': 'clang',
             'CXX': 'clang++',
             'HOST_CC': 'gcc',
         })
 
 
+class LinuxSimpleCrossToolchainTest(BaseToolchainTest):
+    TARGET = 'i686-pc-linux-gnu'
+    PATHS = LinuxToolchainTest.PATHS
+    GCC_4_9_RESULT = LinuxToolchainTest.GCC_4_9_RESULT
+    GXX_4_9_RESULT = LinuxToolchainTest.GXX_4_9_RESULT
+    CLANG_3_6_RESULT = LinuxToolchainTest.CLANG_3_6_RESULT
+    CLANGXX_3_6_RESULT = LinuxToolchainTest.CLANGXX_3_6_RESULT
+
+    def test_cross_gcc(self):
+        self.do_toolchain_test(self.PATHS, {
+            'c_compiler': self.GCC_4_9_RESULT + {
+                'flags': ['-m32']
+            },
+            'cxx_compiler': self.GXX_4_9_RESULT + {
+                'flags': ['-m32']
+            },
+            'host_c_compiler': self.GCC_4_9_RESULT,
+            'host_cxx_compiler': self.GXX_4_9_RESULT,
+        })
+
+    def test_cross_clang(self):
+        self.do_toolchain_test(self.PATHS, {
+            'c_compiler': self.CLANG_3_6_RESULT + {
+                'flags': ['--target=i686-linux-gnu'],
+            },
+            'cxx_compiler': self.CLANGXX_3_6_RESULT + {
+                'flags': ['--target=i686-linux-gnu'],
+            },
+            'host_c_compiler': self.CLANG_3_6_RESULT,
+            'host_cxx_compiler': self.CLANGXX_3_6_RESULT,
+        }, environ={
+            'CC': 'clang',
+        })
+
+
+class LinuxX86_64CrossToolchainTest(BaseToolchainTest):
+    HOST = 'i686-pc-linux-gnu'
+    TARGET = 'x86_64-pc-linux-gnu'
+    PATHS = {
+        '/usr/bin/gcc': GCC_4_9 + GCC_PLATFORM_X86_LINUX,
+        '/usr/bin/g++': GXX_4_9 + GCC_PLATFORM_X86_LINUX,
+        '/usr/bin/clang': CLANG_3_6 + CLANG_PLATFORM_X86_LINUX,
+        '/usr/bin/clang++': CLANGXX_3_6 + CLANG_PLATFORM_X86_LINUX,
+    }
+    GCC_4_9_RESULT = LinuxToolchainTest.GCC_4_9_RESULT
+    GXX_4_9_RESULT = LinuxToolchainTest.GXX_4_9_RESULT
+    CLANG_3_6_RESULT = LinuxToolchainTest.CLANG_3_6_RESULT
+    CLANGXX_3_6_RESULT = LinuxToolchainTest.CLANGXX_3_6_RESULT
+
+    def test_cross_gcc(self):
+        self.do_toolchain_test(self.PATHS, {
+            'c_compiler': self.GCC_4_9_RESULT + {
+                'flags': ['-m64']
+            },
+            'cxx_compiler': self.GXX_4_9_RESULT + {
+                'flags': ['-m64']
+            },
+            'host_c_compiler': self.GCC_4_9_RESULT,
+            'host_cxx_compiler': self.GXX_4_9_RESULT,
+        })
+
+    def test_cross_clang(self):
+        self.do_toolchain_test(self.PATHS, {
+            'c_compiler': self.CLANG_3_6_RESULT + {
+                'flags': ['--target=x86_64-linux-gnu'],
+            },
+            'cxx_compiler': self.CLANGXX_3_6_RESULT + {
+                'flags': ['--target=x86_64-linux-gnu'],
+            },
+            'host_c_compiler': self.CLANG_3_6_RESULT,
+            'host_cxx_compiler': self.CLANGXX_3_6_RESULT,
+        }, environ={
+            'CC': 'clang',
+        })
+
+
 class OSXToolchainTest(BaseToolchainTest):
     HOST = 'x86_64-apple-darwin11.2.0'
-    PATHS = LinuxToolchainTest.PATHS
+    PATHS = {
+        '/usr/bin/gcc': GCC_4_9 + GCC_PLATFORM_X86_64_OSX,
+        '/usr/bin/g++': GXX_4_9 + GCC_PLATFORM_X86_64_OSX,
+        '/usr/bin/gcc-4.7': GCC_4_7 + GCC_PLATFORM_X86_64_OSX,
+        '/usr/bin/g++-4.7': GXX_4_7 + GCC_PLATFORM_X86_64_OSX,
+        '/usr/bin/gcc-5': GCC_5 + GCC_PLATFORM_X86_64_OSX,
+        '/usr/bin/g++-5': GXX_5 + GCC_PLATFORM_X86_64_OSX,
+        '/usr/bin/clang': CLANG_3_6 + CLANG_PLATFORM_X86_64_OSX,
+        '/usr/bin/clang++': CLANGXX_3_6 + CLANG_PLATFORM_X86_64_OSX,
+        '/usr/bin/clang-3.6': CLANG_3_6 + CLANG_PLATFORM_X86_64_OSX,
+        '/usr/bin/clang++-3.6': CLANGXX_3_6 + CLANG_PLATFORM_X86_64_OSX,
+        '/usr/bin/clang-3.3': CLANG_3_3 + CLANG_PLATFORM_X86_64_OSX,
+        '/usr/bin/clang++-3.3': CLANGXX_3_3 + CLANG_PLATFORM_X86_64_OSX,
+    }
     CLANG_3_3_RESULT = LinuxToolchainTest.CLANG_3_3_RESULT
     CLANGXX_3_3_RESULT = LinuxToolchainTest.CLANGXX_3_3_RESULT
     CLANG_3_6_RESULT = LinuxToolchainTest.CLANG_3_6_RESULT
     CLANGXX_3_6_RESULT = LinuxToolchainTest.CLANGXX_3_6_RESULT
     GCC_4_7_RESULT = LinuxToolchainTest.GCC_4_7_RESULT
     GCC_5_RESULT = LinuxToolchainTest.GCC_5_RESULT
     GXX_5_RESULT = LinuxToolchainTest.GXX_5_RESULT
 
@@ -525,24 +707,35 @@ class OSXToolchainTest(BaseToolchainTest
 
 
 class WindowsToolchainTest(BaseToolchainTest):
     HOST = 'i686-pc-mingw32'
 
     # For the purpose of this test, it doesn't matter that the paths are not
     # real Windows paths.
     PATHS = {
-        '/opt/VS_2013u2/bin/cl': VS_2013u2,
-        '/opt/VS_2013u3/bin/cl': VS_2013u3,
-        '/opt/VS_2015/bin/cl': VS_2015,
-        '/opt/VS_2015u1/bin/cl': VS_2015u1,
-        '/usr/bin/cl': VS_2015u2,
-        '/usr/bin/clang-cl': CLANG_CL_3_9,
+        '/opt/VS_2013u2/bin/cl': VS_2013u2 + VS_PLATFORM_X86,
+        '/opt/VS_2013u3/bin/cl': VS_2013u3 + VS_PLATFORM_X86,
+        '/opt/VS_2015/bin/cl': VS_2015 + VS_PLATFORM_X86,
+        '/opt/VS_2015u1/bin/cl': VS_2015u1 + VS_PLATFORM_X86,
+        '/usr/bin/cl': VS_2015u2 + VS_PLATFORM_X86,
+        '/usr/bin/clang-cl': CLANG_CL_3_9 + CLANG_CL_PLATFORM_X86,
+        '/usr/bin/gcc': GCC_4_9 + GCC_PLATFORM_X86_WIN,
+        '/usr/bin/g++': GXX_4_9 + GCC_PLATFORM_X86_WIN,
+        '/usr/bin/gcc-4.7': GCC_4_7 + GCC_PLATFORM_X86_WIN,
+        '/usr/bin/g++-4.7': GXX_4_7 + GCC_PLATFORM_X86_WIN,
+        '/usr/bin/gcc-5': GCC_5 + GCC_PLATFORM_X86_WIN,
+        '/usr/bin/g++-5': GXX_5 + GCC_PLATFORM_X86_WIN,
+        '/usr/bin/clang': CLANG_3_6 + CLANG_PLATFORM_X86_WIN,
+        '/usr/bin/clang++': CLANGXX_3_6 + CLANG_PLATFORM_X86_WIN,
+        '/usr/bin/clang-3.6': CLANG_3_6 + CLANG_PLATFORM_X86_WIN,
+        '/usr/bin/clang++-3.6': CLANGXX_3_6 + CLANG_PLATFORM_X86_WIN,
+        '/usr/bin/clang-3.3': CLANG_3_3 + CLANG_PLATFORM_X86_WIN,
+        '/usr/bin/clang++-3.3': CLANGXX_3_3 + CLANG_PLATFORM_X86_WIN,
     }
-    PATHS.update(LinuxToolchainTest.PATHS)
 
     VS_2013u2_RESULT = (
         'This version (18.00.30501) of the MSVC compiler is not supported.\n'
         'You must install Visual C++ 2015 Update 2 or newer in order to build.\n'
         'See https://developer.mozilla.org/en/Windows_Build_Prerequisites')
     VS_2013u3_RESULT = (
         'This version (18.00.30723) of the MSVC compiler is not supported.\n'
         'You must install Visual C++ 2015 Update 2 or newer in order to build.\n'
@@ -662,51 +855,249 @@ class WindowsToolchainTest(BaseToolchain
         self.do_toolchain_test(self.PATHS, {
             'c_compiler': self.CLANG_3_3_RESULT,
             'cxx_compiler': self.CLANGXX_3_3_RESULT,
         }, environ={
             'CC': 'clang-3.3',
             'CXX': 'clang++-3.3',
         })
 
+    def test_cannot_cross(self):
+        paths = {
+            '/usr/bin/cl': VS_2015u2 + VS_PLATFORM_X86_64,
+        }
+        self.do_toolchain_test(paths, {
+            'c_compiler': ('Target C compiler target CPU (x86_64) '
+                           'does not match --target CPU (i686)'),
+        })
 
-class CrossCompileToolchainTest(BaseToolchainTest):
+
+class Windows64ToolchainTest(WindowsToolchainTest):
+    HOST = 'x86_64-pc-mingw32'
+
+    # For the purpose of this test, it doesn't matter that the paths are not
+    # real Windows paths.
+    PATHS = {
+        '/opt/VS_2013u2/bin/cl': VS_2013u2 + VS_PLATFORM_X86_64,
+        '/opt/VS_2013u3/bin/cl': VS_2013u3 + VS_PLATFORM_X86_64,
+        '/opt/VS_2015/bin/cl': VS_2015 + VS_PLATFORM_X86_64,
+        '/opt/VS_2015u1/bin/cl': VS_2015u1 + VS_PLATFORM_X86_64,
+        '/usr/bin/cl': VS_2015u2 + VS_PLATFORM_X86_64,
+        '/usr/bin/clang-cl': CLANG_CL_3_9 + CLANG_CL_PLATFORM_X86_64,
+        '/usr/bin/gcc': GCC_4_9 + GCC_PLATFORM_X86_64_WIN,
+        '/usr/bin/g++': GXX_4_9 + GCC_PLATFORM_X86_64_WIN,
+        '/usr/bin/gcc-4.7': GCC_4_7 + GCC_PLATFORM_X86_64_WIN,
+        '/usr/bin/g++-4.7': GXX_4_7 + GCC_PLATFORM_X86_64_WIN,
+        '/usr/bin/gcc-5': GCC_5 + GCC_PLATFORM_X86_64_WIN,
+        '/usr/bin/g++-5': GXX_5 + GCC_PLATFORM_X86_64_WIN,
+        '/usr/bin/clang': CLANG_3_6 + CLANG_PLATFORM_X86_64_WIN,
+        '/usr/bin/clang++': CLANGXX_3_6 + CLANG_PLATFORM_X86_64_WIN,
+        '/usr/bin/clang-3.6': CLANG_3_6 + CLANG_PLATFORM_X86_64_WIN,
+        '/usr/bin/clang++-3.6': CLANGXX_3_6 + CLANG_PLATFORM_X86_64_WIN,
+        '/usr/bin/clang-3.3': CLANG_3_3 + CLANG_PLATFORM_X86_64_WIN,
+        '/usr/bin/clang++-3.3': CLANGXX_3_3 + CLANG_PLATFORM_X86_64_WIN,
+    }
+
+    def test_cannot_cross(self):
+        paths = {
+            '/usr/bin/cl': VS_2015u2 + VS_PLATFORM_X86,
+        }
+        self.do_toolchain_test(paths, {
+            'c_compiler': ('Target C compiler target CPU (x86) '
+                           'does not match --target CPU (x86_64)'),
+        })
+
+
+class LinuxCrossCompileToolchainTest(BaseToolchainTest):
     TARGET = 'arm-unknown-linux-gnu'
     PATHS = {
-        '/usr/bin/arm-linux-gnu-gcc': GCC_4_9,
-        '/usr/bin/arm-linux-gnu-g++': GXX_4_9,
-        '/usr/bin/arm-linux-gnu-gcc-4.7': GCC_4_7,
-        '/usr/bin/arm-linux-gnu-g++-4.7': GXX_4_7,
-        '/usr/bin/arm-linux-gnu-gcc-5': GCC_5,
-        '/usr/bin/arm-linux-gnu-g++-5': GXX_5,
+        '/usr/bin/arm-linux-gnu-gcc': GCC_4_9 + GCC_PLATFORM_ARM_LINUX,
+        '/usr/bin/arm-linux-gnu-g++': GXX_4_9 + GCC_PLATFORM_ARM_LINUX,
+        '/usr/bin/arm-linux-gnu-gcc-4.7': GCC_4_7 + GCC_PLATFORM_ARM_LINUX,
+        '/usr/bin/arm-linux-gnu-g++-4.7': GXX_4_7 + GCC_PLATFORM_ARM_LINUX,
+        '/usr/bin/arm-linux-gnu-gcc-5': GCC_5 + GCC_PLATFORM_ARM_LINUX,
+        '/usr/bin/arm-linux-gnu-g++-5': GXX_5 + GCC_PLATFORM_ARM_LINUX,
     }
     PATHS.update(LinuxToolchainTest.PATHS)
     ARM_GCC_4_7_RESULT = LinuxToolchainTest.GXX_4_7_RESULT
     ARM_GCC_5_RESULT = LinuxToolchainTest.GCC_5_RESULT + {
         'compiler': '/usr/bin/arm-linux-gnu-gcc-5',
     }
     ARM_GXX_5_RESULT = LinuxToolchainTest.GXX_5_RESULT + {
         'compiler': '/usr/bin/arm-linux-gnu-g++-5',
     }
     CLANG_3_6_RESULT = LinuxToolchainTest.CLANG_3_6_RESULT
     CLANGXX_3_6_RESULT = LinuxToolchainTest.CLANGXX_3_6_RESULT
     GCC_4_9_RESULT = LinuxToolchainTest.GCC_4_9_RESULT
     GXX_4_9_RESULT = LinuxToolchainTest.GXX_4_9_RESULT
 
-    def test_cross_gcc(self):
-        self.do_toolchain_test(self.PATHS, {
+    little_endian = FakeCompiler(GCC_PLATFORM_LINUX,
+                                 GCC_PLATFORM_LITTLE_ENDIAN)
+    big_endian = FakeCompiler(GCC_PLATFORM_LINUX, GCC_PLATFORM_BIG_ENDIAN)
+
+    PLATFORMS = {
+        'i686-pc-linux-gnu': GCC_PLATFORM_X86_LINUX,
+        'x86_64-pc-linux-gnu': GCC_PLATFORM_X86_64_LINUX,
+        'arm-unknown-linux-gnu': GCC_PLATFORM_ARM_LINUX,
+        'aarch64-unknown-linux-gnu': little_endian + {
+            '__aarch64__': 1,
+        },
+        'ia64-unknown-linux-gnu': little_endian + {
+            '__ia64__': 1,
+        },
+        's390x-unknown-linux-gnu': big_endian + {
+            '__s390x__': 1,
+            '__s390__': 1,
+        },
+        's390-unknown-linux-gnu': big_endian + {
+            '__s390__': 1,
+        },
+        'powerpc64-unknown-linux-gnu': big_endian + {
+            None: {
+                '__powerpc64__': 1,
+                '__powerpc__': 1,
+            },
+            '-m32': {
+                '__powerpc64__': False,
+            },
+        },
+        'powerpc-unknown-linux-gnu': big_endian + {
+            None: {
+                '__powerpc__': 1,
+            },
+            '-m64': {
+                '__powerpc64__': 1,
+            },
+        },
+        'alpha-unknown-linux-gnu': little_endian + {
+            '__alpha__': 1,
+        },
+        'hppa-unknown-linux-gnu': big_endian + {
+            '__hppa__': 1,
+        },
+        'sparc64-unknown-linux-gnu': big_endian + {
+            None: {
+                '__arch64__': 1,
+                '__sparc__': 1,
+            },
+            '-m32': {
+                '__arch64__': False,
+            },
+        },
+        'sparc-unknown-linux-gnu': big_endian + {
+            None: {
+                '__sparc__': 1,
+            },
+            '-m64': {
+                '__arch64__': 1,
+            },
+        },
+        'mips64-unknown-linux-gnuabi64': big_endian + {
+            '__mips64': 1,
+            '__mips__': 1,
+        },
+        'mips-unknown-linux-gnu': big_endian + {
+            '__mips__': 1,
+        },
+    }
+
+    PLATFORMS['powerpc64le-unknown-linux-gnu'] = \
+        PLATFORMS['powerpc64-unknown-linux-gnu'] + GCC_PLATFORM_LITTLE_ENDIAN
+    PLATFORMS['mips64el-unknown-linux-gnuabi64'] = \
+        PLATFORMS['mips64-unknown-linux-gnuabi64'] + GCC_PLATFORM_LITTLE_ENDIAN
+    PLATFORMS['mipsel-unknown-linux-gnu'] = \
+        PLATFORMS['mips-unknown-linux-gnu'] + GCC_PLATFORM_LITTLE_ENDIAN
+
+    def do_test_cross_gcc_32_64(self, host, target):
+        self.HOST = host
+        self.TARGET = target
+        paths = {
+            '/usr/bin/gcc': GCC_4_9 + self.PLATFORMS[host],
+            '/usr/bin/g++': GXX_4_9 + self.PLATFORMS[host],
+        }
+        cross_flags = {
+            'flags': ['-m64' if '64' in target else '-m32']
+        }
+        self.do_toolchain_test(paths, {
+            'c_compiler': self.GCC_4_9_RESULT + cross_flags,
+            'cxx_compiler': self.GXX_4_9_RESULT + cross_flags,
+            'host_c_compiler': self.GCC_4_9_RESULT,
+            'host_cxx_compiler': self.GXX_4_9_RESULT,
+        })
+        self.HOST = LinuxCrossCompileToolchainTest.HOST
+        self.TARGET = LinuxCrossCompileToolchainTest.TARGET
+
+    def test_cross_x86_x64(self):
+        self.do_test_cross_gcc_32_64(
+            'i686-pc-linux-gnu', 'x86_64-pc-linux-gnu')
+        self.do_test_cross_gcc_32_64(
+            'x86_64-pc-linux-gnu', 'i686-pc-linux-gnu')
+
+    def test_cross_sparc_sparc64(self):
+        self.do_test_cross_gcc_32_64(
+            'sparc-unknown-linux-gnu', 'sparc64-unknown-linux-gnu')
+        self.do_test_cross_gcc_32_64(
+            'sparc64-unknown-linux-gnu', 'sparc-unknown-linux-gnu')
+
+    def test_cross_ppc_ppc64(self):
+        self.do_test_cross_gcc_32_64(
+            'powerpc-unknown-linux-gnu', 'powerpc64-unknown-linux-gnu')
+        self.do_test_cross_gcc_32_64(
+            'powerpc64-unknown-linux-gnu', 'powerpc-unknown-linux-gnu')
+
+    def do_test_cross_gcc(self, host, target):
+        self.HOST = host
+        self.TARGET = target
+        host_cpu = host.split('-')[0]
+        cpu, manufacturer, os = target.split('-', 2)
+        toolchain_prefix = '/usr/bin/%s-%s' % (cpu, os)
+        paths = {
+            '/usr/bin/gcc': GCC_4_9 + self.PLATFORMS[host],
+            '/usr/bin/g++': GXX_4_9 + self.PLATFORMS[host],
+        }
+        self.do_toolchain_test(paths, {
+            'c_compiler': ('Target C compiler target CPU (%s) '
+                           'does not match --target CPU (%s)'
+                           % (host_cpu, cpu)),
+        })
+
+        paths.update({
+            '%s-gcc' % toolchain_prefix: GCC_4_9 + self.PLATFORMS[target],
+            '%s-g++' % toolchain_prefix: GXX_4_9 + self.PLATFORMS[target],
+        })
+        self.do_toolchain_test(paths, {
             'c_compiler': self.GCC_4_9_RESULT + {
-                'compiler': '/usr/bin/arm-linux-gnu-gcc',
+                'compiler': '%s-gcc' % toolchain_prefix,
             },
             'cxx_compiler': self.GXX_4_9_RESULT + {
-                'compiler': '/usr/bin/arm-linux-gnu-g++',
+                'compiler': '%s-g++' % toolchain_prefix,
             },
             'host_c_compiler': self.GCC_4_9_RESULT,
             'host_cxx_compiler': self.GXX_4_9_RESULT,
         })
+        self.HOST = LinuxCrossCompileToolchainTest.HOST
+        self.TARGET = LinuxCrossCompileToolchainTest.TARGET
+
+    def test_cross_gcc_misc(self):
+        for target in self.PLATFORMS:
+            if not target.endswith('-pc-linux-gnu'):
+                self.do_test_cross_gcc('x86_64-pc-linux-gnu', target)
+
+    def test_cannot_cross(self):
+        self.TARGET = 'mipsel-unknown-linux-gnu'
+
+        paths = {
+            '/usr/bin/gcc': GCC_4_9 + self.PLATFORMS['mips-unknown-linux-gnu'],
+            '/usr/bin/g++': GXX_4_9 + self.PLATFORMS['mips-unknown-linux-gnu'],
+        }
+        self.do_toolchain_test(paths, {
+            'c_compiler': ('Target C compiler target endianness (big) '
+                           'does not match --target endianness (little)'),
+        })
+        self.TARGET = LinuxCrossCompileToolchainTest.TARGET
 
     def test_overridden_cross_gcc(self):
         self.do_toolchain_test(self.PATHS, {
             'c_compiler': self.ARM_GCC_5_RESULT,
             'cxx_compiler': self.ARM_GXX_5_RESULT,
             'host_c_compiler': self.GCC_4_9_RESULT,
             'host_cxx_compiler': self.GXX_4_9_RESULT,
         }, environ={
@@ -749,11 +1140,92 @@ class CrossCompileToolchainTest(BaseTool
             'host_c_compiler': self.CLANG_3_6_RESULT,
             'host_cxx_compiler': self.CLANGXX_3_6_RESULT,
         }, environ={
             'CC': 'arm-linux-gnu-gcc-5',
             'CXX': 'arm-linux-gnu-g++-5',
             'HOST_CC': 'clang',
         })
 
+    def test_cross_clang(self):
+        cross_clang_result = self.CLANG_3_6_RESULT + {
+            'flags': ['--target=arm-linux-gnu'],
+        }
+        cross_clangxx_result = self.CLANGXX_3_6_RESULT + {
+            'flags': ['--target=arm-linux-gnu'],
+        }
+        self.do_toolchain_test(self.PATHS, {
+            'c_compiler': cross_clang_result,
+            'cxx_compiler': cross_clangxx_result,
+            'host_c_compiler': self.CLANG_3_6_RESULT,
+            'host_cxx_compiler': self.CLANGXX_3_6_RESULT,
+        }, environ={
+            'CC': 'clang',
+            'HOST_CC': 'clang',
+        })
+
+        self.do_toolchain_test(self.PATHS, {
+            'c_compiler': cross_clang_result,
+            'cxx_compiler': cross_clangxx_result,
+            'host_c_compiler': self.CLANG_3_6_RESULT,
+            'host_cxx_compiler': self.CLANGXX_3_6_RESULT,
+        }, environ={
+            'CC': 'clang',
+        })
+
+    def test_cross_atypical_clang(self):
+        paths = dict(self.PATHS)
+        paths.update({
+            '/usr/bin/afl-clang-fast': paths['/usr/bin/clang'],
+            '/usr/bin/afl-clang-fast++': paths['/usr/bin/clang++'],
+        })
+        afl_clang_result = self.CLANG_3_6_RESULT + {
+            'compiler': '/usr/bin/afl-clang-fast',
+        }
+        afl_clangxx_result = self.CLANGXX_3_6_RESULT + {
+            'compiler': '/usr/bin/afl-clang-fast++',
+        }
+        self.do_toolchain_test(paths, {
+            'c_compiler': afl_clang_result + {
+                'flags': ['--target=arm-linux-gnu'],
+            },
+            'cxx_compiler': afl_clangxx_result + {
+                'flags': ['--target=arm-linux-gnu'],
+            },
+            'host_c_compiler': afl_clang_result,
+            'host_cxx_compiler': afl_clangxx_result,
+        }, environ={
+            'CC': 'afl-clang-fast',
+            'CXX': 'afl-clang-fast++',
+        })
+
+
+class OSXCrossToolchainTest(BaseToolchainTest):
+    TARGET = 'i686-apple-darwin11.2.0'
+    PATHS = LinuxToolchainTest.PATHS
+    CLANG_3_6_RESULT = LinuxToolchainTest.CLANG_3_6_RESULT
+    CLANGXX_3_6_RESULT = LinuxToolchainTest.CLANGXX_3_6_RESULT
+
+    def test_osx_cross(self):
+        self.do_toolchain_test(self.PATHS, {
+            'c_compiler': self.CLANG_3_6_RESULT + {
+                'flags': ['--target=i686-darwin11.2.0'],
+            },
+            'cxx_compiler': self.CLANGXX_3_6_RESULT + {
+                'flags': ['--target=i686-darwin11.2.0'],
+            },
+            'host_c_compiler': self.CLANG_3_6_RESULT,
+            'host_cxx_compiler': self.CLANGXX_3_6_RESULT,
+        }, environ={
+            'CC': 'clang',
+        })
+
+    def test_cannot_osx_cross(self):
+        self.do_toolchain_test(self.PATHS, {
+            'c_compiler': 'Target C compiler target kernel (Linux) does not '
+                          'match --target kernel (Darwin)',
+        }, environ={
+            'CC': 'gcc',
+        })
+
 
 if __name__ == '__main__':
     main()
--- a/python/mozbuild/mozbuild/util.py
+++ b/python/mozbuild/mozbuild/util.py
@@ -99,17 +99,18 @@ class ReadOnlyNamespace(object):
 
     def __setattr__(self, key, value):
         raise Exception('Object does not support assignment.')
 
     def __ne__(self, other):
         return not (self == other)
 
     def __eq__(self, other):
-        return self is other or self.__dict__ == other.__dict__
+        return self is other or (
+            hasattr(other, '__dict__') and self.__dict__ == other.__dict__)
 
     def __repr__(self):
         return '<%s %r>' % (self.__class__.__name__, self.__dict__)
 
 
 class ReadOnlyDict(dict):
     """A read-only dictionary."""
     def __init__(self, *args, **kwargs):
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -1531,12 +1531,13 @@ BookmarksTracker.prototype = {
   },
 
   onBeginUpdateBatch: function () {
     ++this._batchDepth;
   },
   onEndUpdateBatch: function () {
     if (--this._batchDepth === 0 && this._batchSawScoreIncrement) {
       this.score += SCORE_INCREMENT_XLARGE;
+      this._batchSawScoreIncrement = false;
     }
   },
   onItemVisited: function () {}
 };
--- a/taskcluster/ci/legacy/tasks/branches/base_jobs.yml
+++ b/taskcluster/ci/legacy/tasks/branches/base_jobs.yml
@@ -268,17 +268,16 @@ tasks:
     root: true
     when:
       file_patterns:
         - '**/*.py'
         - '**/.flake8'
         - 'python/mozlint/**'
         - 'tools/lint/**'
         - 'testing/docker/lint/**'
-        - 'taskcluster/**'
   taskgraph-tests:
     task: tasks/tests/taskgraph-tests.yml
     root: true
     when:
       file_patterns:
         - 'taskcluster/**.py'
         - 'config/mozunit.py'
         - 'python/mach/**.py'
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -302,18 +302,17 @@ GeckoDriver.prototype.addBrowser = funct
  * frame script will be loaded into it.  If isNewSession is true, we will
  * switch focus to the start frame when it registers.
  *
  * @param {nsIDOMWindow} win
  *     Window whose browser we need to access.
  * @param {boolean=false} isNewSession
  *     True if this is the first time we're talking to this browser.
  */
-GeckoDriver.prototype.startBrowser = function(win, isNewSession=false) {
-  logger.info(`startBrowser ${this.sessionId}`)
+GeckoDriver.prototype.startBrowser = function(win, isNewSession = false) {
   this.mainFrame = win;
   this.curFrame = null;
   this.addBrowser(win);
   this.curBrowser.isNewSession = isNewSession;
   this.curBrowser.startSession(isNewSession, win, this.whenBrowserStarted.bind(this));
 };
 
 /**
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -25,16 +25,18 @@ Cu.import("chrome://marionette/content/i
 Cu.import("chrome://marionette/content/logging.js");
 Cu.import("chrome://marionette/content/proxy.js");
 Cu.import("chrome://marionette/content/simpletest.js");
 
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+Cu.importGlobalProperties(["URL"]);
+
 var contentLog = new logging.ContentLogger();
 
 var isB2G = false;
 
 var marionetteTestName;
 var winUtil = content.QueryInterface(Ci.nsIInterfaceRequestor)
     .getInterface(Ci.nsIDOMWindowUtils);
 var listenerId = null; // unique ID of this listener
@@ -922,44 +924,115 @@ function pollForReadyState(msg, start, c
 /**
  * Navigate to the given URL.  The operation will be performed on the
  * current browsing context, which means it handles the case where we
  * navigate within an iframe.  All other navigation is handled by the
  * driver (in chrome space).
  */
 function get(msg) {
   let start = new Date().getTime();
+  let requestedURL = new URL(msg.json.url).toString();
+  let docShell = curContainer.frame
+                             .document
+                             .defaultView
+                             .QueryInterface(Ci.nsIInterfaceRequestor)
+                             .getInterface(Ci.nsIWebNavigation)
+                             .QueryInterface(Ci.nsIDocShell);
+  let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                            .getInterface(Ci.nsIWebProgress);
+  let sawLoad = false;
+
+  // It's possible that a site we're being sent to will end up redirecting
+  // us before we end up on a page that fires DOMContentLoaded. We can ensure
+  // This loadListener ensures that we don't send a success signal back to
+  // the caller until we've seen the load of the requested URL attempted
+  // on this frame.
+  let loadListener = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+                                           Ci.nsISupportsWeakReference]),
+    onStateChange(webProgress, request, state, status) {
+      if (!(request instanceof Ci.nsIChannel)) {
+        return;
+      }
+
+      let isDocument = state & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
+      let isStart = state & Ci.nsIWebProgressListener.STATE_START;
+      let loadedURL = request.URI.spec;
+      // We have to look at the originalURL because for about: pages,
+      // the loadedURL is what the about: page resolves to, and is
+      // not the one that was requested.
+      let originalURL = request.originalURI.spec;
+      let isRequestedURL = loadedURL == requestedURL ||
+                           originalURL == requestedURL;
+
+      if (isDocument && isStart && isRequestedURL) {
+        // We started loading the requested document. This document
+        // might not be the one that ends up firing DOMContentLoaded
+        // (if it, for example, redirects), but because we've started
+        // loading this URL, we know that any future DOMContentLoaded's
+        // are fair game to tell the Marionette client about.
+        sawLoad = true;
+      }
+    },
+
+    onLocationChange() {},
+    onProgressChange() {},
+    onStatusChange() {},
+    onSecurityChange() {},
+  };
+
+  webProgress.addProgressListener(loadListener,
+                                  Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
 
   // 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).
   onDOMContentLoaded = function onDOMContentLoaded(event) {
-    if (!event.originalTarget.defaultView.frameElement ||
-        event.originalTarget.defaultView.frameElement == curContainer.frame.frameElement) {
+    let correctFrame =
+      !event.originalTarget.defaultView.frameElement ||
+      event.originalTarget.defaultView.frameElement == curContainer.frame.frameElement;
+
+    // If the page we're at fired DOMContentLoaded and appears
+    // to be the one we asked to load, then we definitely
+    // saw the load occur. We need this because for error
+    // pages, like about:neterror for unsupported protocols,
+    // we don't end up opening a channel that our
+    // WebProgressListener can monitor.
+    if (curContainer.frame.location == requestedURL) {
+      sawLoad = true;
+    }
+
+    // We also need to make sure that the DOMContentLoaded we saw isn't
+    // for the initial about:blank of a newly created docShell.
+    let loadedNonAboutBlank = docShell.hasLoadedNonBlankURI;
+
+    if (correctFrame && sawLoad && loadedNonAboutBlank) {
+      webProgress.removeProgressListener(loadListener);
       pollForReadyState(msg, start, () => {
         removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
       });
     }
   };
 
   function timerFunc() {
     removeEventListener("DOMContentLoaded", onDOMContentLoaded, false);
+    webProgress.removeProgressListener(loadListener);
     sendError(new TimeoutError("Error loading page, timed out (onDOMContentLoaded)"), msg.json.command_id);
   }
   if (msg.json.pageTimeout != null) {
     navTimer.initWithCallback(timerFunc, msg.json.pageTimeout, Ci.nsITimer.TYPE_ONE_SHOT);
   }
   addEventListener("DOMContentLoaded", onDOMContentLoaded, false);
   if (isB2G) {
-    curContainer.frame.location = msg.json.url;
+    curContainer.frame.location = requestedURL;
   } else {
     // We need to move to the top frame before navigating
     sendSyncMessage("Marionette:switchedToFrame", { frameValue: null });
     curContainer.frame = content;
-    curContainer.frame.location = msg.json.url;
+    curContainer.frame.location = requestedURL;
   }
 }
 
  /**
  * Cancel the polling and remove the event listener associated with a current
  * navigation request in case we're interupted by an onbeforeunload handler
  * and navigation doesn't complete.
  */
--- a/testing/mochitest/tests/Harness_sanity/mochitest.ini
+++ b/testing/mochitest/tests/Harness_sanity/mochitest.ini
@@ -17,30 +17,30 @@ support-files = empty.js
 [test_sanityWindowSnapshot.html]
 [test_SpecialPowersExtension.html]
 [test_SpecialPowersExtension2.html]
 support-files = file_SpecialPowersFrame1.html
 [test_SpecialPowersPushPermissions.html]
 support-files =
     specialPowers_framescript.js
 [test_SpecialPowersPushAppPermissions.html]
-skip-if = buildapp != 'mulet'
+skip-if = true ### Bug 1255339: blacklist because no more mozApps
 support-files =
     file_app.sjs
     file_app.template.webapp
     app.html
 [test_SpecialPowersPushPrefEnv.html]
 [test_SimpletestGetTestFileURL.html]
 [test_SpecialPowersLoadChromeScript.html]
 support-files = SpecialPowersLoadChromeScript.js
 [test_SpecialPowersLoadChromeScript_function.html]
 [test_SpecialPowersLoadPrivilegedScript.html]
 [test_bug649012.html]
 [test_bug816847.html]
-skip-if = toolkit == 'android' || e10s #No test app installed
+skip-if = true || toolkit == 'android' || buildapp == 'b2g' || buildapp == 'mulet' || e10s #No test app installed ### Bug 1255339: blacklist because no more mozApps
 [test_sanity_cleanup.html]
 [test_sanity_cleanup2.html]
 [test_sanityEventUtils.html]
 skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 688052
 [test_sanitySimpletest.html]
 subsuite = clipboard
 skip-if = toolkit == 'android' #bug 688052
 [test_sanity_manifest.html]
--- a/testing/mozharness/mozharness/base/python.py
+++ b/testing/mozharness/mozharness/base/python.py
@@ -461,16 +461,22 @@ class ResourceMonitoringMixin(object):
         super(ResourceMonitoringMixin, self).__init__(*args, **kwargs)
 
         self.register_virtualenv_module('psutil>=3.1.1', method='pip',
                                         optional=True)
         self.register_virtualenv_module('mozsystemmonitor==0.3',
                                         method='pip', optional=True)
         self.register_virtualenv_module('jsonschema==2.5.1',
                                         method='pip')
+        # explicitly install functools32, because some slaves aren't using
+        # a version of pip recent enough to install it automatically with
+        # jsonschema (which depends on it)
+        # https://github.com/Julian/jsonschema/issues/233
+        self.register_virtualenv_module('functools32==3.2.3-2',
+                                        method='pip')
         self._resource_monitor = None
 
         # 2-tuple of (name, options) to assign Perfherder resource monitor
         # metrics to. This needs to be assigned by a script in order for
         # Perfherder metrics to be reported.
         self.resource_monitor_perfherder_id = None
 
     @PostScriptAction('create-virtualenv')
--- a/testing/talos/talos/pageloader/chrome/pageloader.js
+++ b/testing/talos/talos/pageloader/chrome/pageloader.js
@@ -224,34 +224,33 @@ function plInit() {
         function firstPageCanLoadAsRemote() {
           return E10SUtils.canLoadURIInProcess(pageUrls[0], Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT);
         }
 
         // do this half a second after load, because we need to be
         // able to resize the window and not have it get clobbered
         // by the persisted values
         setTimeout(function () {
-                     // For e10s windows, the initial browser is not remote until it attempts to
-                     // browse to a URI that should be remote (landed at bug 1047603).
-                     // However, when it loads such URI and reinitialize as remote, we lose the
+                     // For e10s windows, since bug 1261842, the initial browser is remote unless
+                     // it attempts to browse to a URI that should be non-remote (landed at bug 1047603).
+                     //
+                     // However, when it loads such URI and reinitializes as non-remote, we lose the
                      // load listener and the injected tpRecordTime.
-                     // The same thing happens if the initial browser starts as remote but the
-                     // first page is not-remote (such as with TART/CART which load a chrome URI).
                      //
                      // The preferred pageloader behaviour in e10s is to run the pages as as remote,
                      // so if the page can load as remote, we will load it as remote.
                      //
                      // It also probably means that per test (or, in fact, per pageloader browser
                      // instance which adds the load listener and injects tpRecordTime), all the
                      // pages should be able to load in the same mode as the initial page - due
                      // to this reinitialization on the switch.
                      if (browserWindow.gMultiProcessBrowser) {
-                       if (firstPageCanLoadAsRemote())
-                         browserWindow.XULBrowserWindow.forceInitialBrowserRemote();
-                       // Implicit else: initial browser in e10s is non-remote by default.
+                       if (!firstPageCanLoadAsRemote())
+                         browserWindow.XULBrowserWindow.forceInitialBrowserNonRemote();
+                       // Implicit else: initial browser in e10s is remote by default.
                      }
 
                      browserWindow.resizeTo(winWidth, winHeight);
                      browserWindow.moveTo(0, 0);
                      browserWindow.focus();
 
                      content = browserWindow.getBrowser();
                      gUseE10S = !gDisableE10S || (plPageFlags() & EXECUTE_SCROLL_TEST) ||
--- a/testing/talos/talos/pageloader/install.rdf
+++ b/testing/talos/talos/pageloader/install.rdf
@@ -1,15 +1,15 @@
 <?xml version="1.0"?>
 
 <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
      xmlns:em="http://www.mozilla.org/2004/em-rdf#">
   <Description about="urn:mozilla:install-manifest">
     <em:id>pageloader@mozilla.org</em:id>
-    <em:version>1.0.9</em:version>
+    <em:version>1.0.10</em:version>
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>44.0</em:minVersion>
         <em:maxVersion>*</em:maxVersion>
       </Description>
     </em:targetApplication>
     <!-- Front End MetaData -->
index cc0778d7614a19ae9a22d2c0dd14f7aecca8c468..325e71a4c4e742a52f361c6a42cbfd5bcd8bfb16
GIT binary patch
literal 29177
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
B>Q(>%
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -20,16 +20,17 @@ const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.importGlobalProperties(["TextEncoder"]);
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/ExtensionContent.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
                                   "resource://devtools/shared/event-emitter.js");
 XPCOMUtils.defineLazyModuleGetter(this, "Locale",
                                   "resource://gre/modules/Locale.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Log",
                                   "resource://gre/modules/Log.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "MatchGlobs",
--- a/toolkit/components/startup/nsAppStartup.cpp
+++ b/toolkit/components/startup/nsAppStartup.cpp
@@ -609,17 +609,17 @@ nsAppStartup::GetInterrupted(bool *aInte
 //
 
 NS_IMETHODIMP
 nsAppStartup::CreateChromeWindow(nsIWebBrowserChrome *aParent,
                                  uint32_t aChromeFlags,
                                  nsIWebBrowserChrome **_retval)
 {
   bool cancel;
-  return CreateChromeWindow2(aParent, aChromeFlags, 0, 0, nullptr, &cancel, _retval);
+  return CreateChromeWindow2(aParent, aChromeFlags, 0, nullptr, &cancel, _retval);
 }
 
 
 //
 // nsAppStartup->nsIWindowCreator2
 //
 
 NS_IMETHODIMP
@@ -632,17 +632,16 @@ nsAppStartup::SetScreenId(uint32_t aScre
 
   return appShell->SetScreenId(aScreenId);
 }
 
 NS_IMETHODIMP
 nsAppStartup::CreateChromeWindow2(nsIWebBrowserChrome *aParent,
                                   uint32_t aChromeFlags,
                                   uint32_t aContextFlags,
-                                  nsIURI *aURI,
                                   nsITabParent *aOpeningTab,
                                   bool *aCancel,
                                   nsIWebBrowserChrome **_retval)
 {
   NS_ENSURE_ARG_POINTER(aCancel);
   NS_ENSURE_ARG_POINTER(_retval);
   *aCancel = false;
   *_retval = 0;
--- a/toolkit/components/url-classifier/nsUrlClassifierUtils.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierUtils.cpp
@@ -86,17 +86,17 @@ GetPlatformType()
   return ANDROID_PLATFORM;
 #elif defined(XP_MACOSX)
   return OSX_PLATFORM;
 #elif defined(XP_LINUX)
   return LINUX_PLATFORM;
 #elif defined(XP_WIN)
   return WINDOWS_PLATFORM;
 #else
-  #error Unrecognized platform type.
+  return PLATFORM_TYPE_UNSPECIFIED;
 #endif
 }
 
 typedef FetchThreatListUpdatesRequest_ListUpdateRequest ListUpdateRequest;
 typedef FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints Constraints;
 
 static void
 InitListUpdateRequest(ThreatType aThreatType,
--- a/widget/gonk/GeckoTouchDispatcher.cpp
+++ b/widget/gonk/GeckoTouchDispatcher.cpp
@@ -339,16 +339,19 @@ GeckoTouchDispatcher::DispatchTouchEvent
         break;
       case MultiTouchInput::MULTITOUCH_MOVE:
         touchAction = "Touch_Event_Move";
         break;
       case MultiTouchInput::MULTITOUCH_END:
       case MultiTouchInput::MULTITOUCH_CANCEL:
         touchAction = "Touch_Event_Up";
         break;
+      case MultiTouchInput::MULTITOUCH_SENTINEL:
+        MOZ_ASSERT_UNREACHABLE("Invalid MultTouchInput.");
+        break;
     }
 
     const ScreenIntPoint& touchPoint = aMultiTouch.mTouches[0].mScreenPoint;
     TouchDataPayload* payload = new TouchDataPayload(touchPoint);
     PROFILER_MARKER_PAYLOAD(touchAction, payload);
   }
 }
 
--- a/widget/windows/GfxInfo.cpp
+++ b/widget/windows/GfxInfo.cpp
@@ -903,22 +903,16 @@ GfxInfo::GetGfxDriverInfo()
       (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices,
       GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
       DRIVER_LESS_THAN, V(8,56,1,15), "FEATURE_FAILURE_AMD1", "8.56.1.15" );
     APPEND_TO_DRIVER_BLOCKLIST(OperatingSystem::Windows,
       (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorAMD), GfxDriverInfo::allDevices,
       GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
       DRIVER_LESS_THAN, V(8,56,1,15), "FEATURE_FAILURE_AMD2", "8.56.1.15" );
 
-    // Bug 1277526
-    APPEND_TO_DRIVER_BLOCKLIST2(OperatingSystem::Windows7,
-      (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices,
-      GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
-      DRIVER_EQUAL, V(8,850,0,0), "FEATURE_FAILURE_BUG_1277526");
-
     // Bug 1099252
     APPEND_TO_DRIVER_BLOCKLIST2(OperatingSystem::Windows7,
       (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorATI), GfxDriverInfo::allDevices,
       GfxDriverInfo::allFeatures, nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION,
       DRIVER_EQUAL, V(8,832,0,0), "FEATURE_FAILURE_BUG_1099252");
 
     // Bug 1118695
     APPEND_TO_DRIVER_BLOCKLIST2(OperatingSystem::Windows7,
--- a/widget/windows/TSFTextStore.cpp
+++ b/widget/windows/TSFTextStore.cpp
@@ -1239,17 +1239,18 @@ TSFTextStore::TSFTextStore()
 
 TSFTextStore::~TSFTextStore()
 {
   MOZ_LOG(sTextStoreLog, LogLevel::Info,
     ("0x%p TSFTextStore instance is destroyed", this));
 }
 
 bool
-TSFTextStore::Init(nsWindowBase* aWidget)
+TSFTextStore::Init(nsWindowBase* aWidget,
+                   const InputContext& aContext)
 {
   MOZ_LOG(sTextStoreLog, LogLevel::Info,
     ("0x%p TSFTextStore::Init(aWidget=0x%p)",
      this, aWidget));
 
   TSFStaticSink::GetInstance()->EnsureInitActiveTIPKeyboard();
 
   if (mDocumentMgr) {
@@ -1289,16 +1290,18 @@ TSFTextStore::Init(nsWindowBase* aWidget
   if (FAILED(hr)) {
     MOZ_LOG(sTextStoreLog, LogLevel::Error,
       ("0x%p   TSFTextStore::Init() FAILED to create the context "
        "(0x%08X)", this, hr));
     mDocumentMgr = nullptr;
     return false;
   }
 
+  SetInputScope(aContext.mHTMLInputType, aContext.mHTMLInputInputmode);
+
   hr = mDocumentMgr->Push(mContext);
   if (FAILED(hr)) {
     MOZ_LOG(sTextStoreLog, LogLevel::Error,
       ("0x%p   TSFTextStore::Init() FAILED to push the context (0x%08X)",
        this, hr));
     // XXX Why don't we use NS_IF_RELEASE() here??
     mContext = nullptr;
     mDocumentMgr = nullptr;
@@ -4591,17 +4594,17 @@ bool
 TSFTextStore::CreateAndSetFocus(nsWindowBase* aFocusedWidget,
                                 const InputContext& aContext)
 {
   // TSF might do something which causes that we need to access static methods
   // of TSFTextStore.  At that time, sEnabledTextStore may be necessary.
   // So, we should set sEnabledTextStore directly.
   RefPtr<TSFTextStore> textStore = new TSFTextStore();
   sEnabledTextStore = textStore;
-  if (NS_WARN_IF(!textStore->Init(aFocusedWidget))) {
+  if (NS_WARN_IF(!textStore->Init(aFocusedWidget, aContext))) {
     MOZ_LOG(sTextStoreLog, LogLevel::Error,
       ("  TSFTextStore::CreateAndSetFocus() FAILED due to "
        "TSFTextStore::Init() failure"));
     return false;
   }
   if (NS_WARN_IF(!textStore->mDocumentMgr)) {
     MOZ_LOG(sTextStoreLog, LogLevel::Error,
       ("  TSFTextStore::CreateAndSetFocus() FAILED due to "
@@ -4630,18 +4633,16 @@ TSFTextStore::CreateAndSetFocus(nsWindow
                                   textStore->mDocumentMgr,
                                   getter_AddRefs(prevFocusedDocumentMgr));
   if (NS_WARN_IF(FAILED(hr))) {
     MOZ_LOG(sTextStoreLog, LogLevel::Error,
       ("  TSFTextStore::CreateAndSetFocus() FAILED due to "
        "ITfTheadMgr::AssociateFocus() failure"));
     return false;
   }
-  textStore->SetInputScope(aContext.mHTMLInputType,
-                           aContext.mHTMLInputInputmode);
 
   if (textStore->mSink) {
     MOZ_LOG(sTextStoreLog, LogLevel::Info,
       ("  TSFTextStore::CreateAndSetFocus(), calling "
        "ITextStoreACPSink::OnLayoutChange(TS_LC_CREATE) for 0x%p...",
        textStore.get()));
     textStore->mSink->OnLayoutChange(TS_LC_CREATE, TEXTSTORE_DEFAULT_VIEW);
   }
--- a/widget/windows/TSFTextStore.h
+++ b/widget/windows/TSFTextStore.h
@@ -246,17 +246,17 @@ protected:
   TSFTextStore();
   ~TSFTextStore();
 
   static bool CreateAndSetFocus(nsWindowBase* aFocusedWidget,
                                 const InputContext& aContext);
   static void MarkContextAsKeyboardDisabled(ITfContext* aContext);
   static void MarkContextAsEmpty(ITfContext* aContext);
 
-  bool     Init(nsWindowBase* aWidget);
+  bool     Init(nsWindowBase* aWidget, const InputContext& aContext);
   void     Destroy();
   void     ReleaseTSFObjects();
 
   bool     IsReadLock(DWORD aLock) const
   {
     return (TS_LF_READ == (aLock & TS_LF_READ));
   }
   bool     IsReadWriteLock(DWORD aLock) const
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -3193,17 +3193,17 @@ nsresult nsNativeThemeWin::ClassicGetThe
         aState |= DFCS_PUSHED;
       else if (IsCheckedButton(aFrame))
         aState |= DFCS_CHECKED;
       else {
         if (contentState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER)) {
           aState |= DFCS_PUSHED;
           const nsStyleUserInterface *uiData = aFrame->StyleUserInterface();
           // The down state is flat if the button is focusable
-          if (uiData->mUserFocus == NS_STYLE_USER_FOCUS_NORMAL) {
+          if (uiData->mUserFocus == StyleUserFocus::Normal) {
             if (!aFrame->GetContent()->IsHTMLElement())
               aState |= DFCS_FLAT;
 
             aFocused = true;
           }
         }
         if (contentState.HasState(NS_EVENT_STATE_FOCUS) ||
             (aState == DFCS_BUTTONPUSH && IsDefaultButton(aFrame))) {
--- a/xpfe/appshell/moz.build
+++ b/xpfe/appshell/moz.build
@@ -33,8 +33,10 @@ UNIFIED_SOURCES += [
     'nsXULWindow.cpp',
 ]
 
 LOCAL_INCLUDES += [
     '/dom/base',
 ]
 
 FINAL_LIBRARY = 'xul'
+
+include('/ipc/chromium/chromium-config.mozbuild')
\ No newline at end of file
--- a/xpfe/appshell/nsChromeTreeOwner.cpp
+++ b/xpfe/appshell/nsChromeTreeOwner.cpp
@@ -264,16 +264,48 @@ nsChromeTreeOwner::TabParentRemoved(nsIT
 
 NS_IMETHODIMP
 nsChromeTreeOwner::GetPrimaryTabParent(nsITabParent** aTab)
 {
   NS_ENSURE_STATE(mXULWindow);
   return mXULWindow->GetPrimaryTabParent(aTab);
 }
 
+NS_IMETHODIMP
+nsChromeTreeOwner::GetPrimaryContentSize(int32_t* aWidth,
+                                         int32_t* aHeight)
+{
+  NS_ENSURE_STATE(mXULWindow);
+  return mXULWindow->GetPrimaryContentSize(aWidth, aHeight);
+}
+
+NS_IMETHODIMP
+nsChromeTreeOwner::SetPrimaryContentSize(int32_t aWidth,
+                                         int32_t aHeight)
+{
+  NS_ENSURE_STATE(mXULWindow);
+  return mXULWindow->SetPrimaryContentSize(aWidth, aHeight);
+}
+
+NS_IMETHODIMP
+nsChromeTreeOwner::GetRootShellSize(int32_t* aWidth,
+                                    int32_t* aHeight)
+{
+  NS_ENSURE_STATE(mXULWindow);
+  return mXULWindow->GetRootShellSize(aWidth, aHeight);
+}
+
+NS_IMETHODIMP
+nsChromeTreeOwner::SetRootShellSize(int32_t aWidth,
+                                    int32_t aHeight)
+{
+  NS_ENSURE_STATE(mXULWindow);
+  return mXULWindow->SetRootShellSize(aWidth, aHeight);
+}
+
 NS_IMETHODIMP nsChromeTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem,
    int32_t aCX, int32_t aCY)
 {
    NS_ENSURE_STATE(mXULWindow);
    return mXULWindow->SizeShellTo(aShellItem, aCX, aCY);
 }
 
 NS_IMETHODIMP
@@ -344,16 +376,23 @@ nsChromeTreeOwner::GetPersistence(bool* 
 
 NS_IMETHODIMP
 nsChromeTreeOwner::GetTargetableShellCount(uint32_t* aResult)
 {
   *aResult = 0;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsChromeTreeOwner::GetHasPrimaryContent(bool* aResult)
+{
+  NS_ENSURE_STATE(mXULWindow);
+  return mXULWindow->GetHasPrimaryContent(aResult);
+}
+
 //*****************************************************************************
 // nsChromeTreeOwner::nsIBaseWindow
 //*****************************************************************************   
 
 NS_IMETHODIMP nsChromeTreeOwner::InitWindow(nativeWindow aParentNativeWindow,
    nsIWidget* parentWidget, int32_t x, int32_t y, int32_t cx, int32_t cy)   
 {
    // Ignore widget parents for now.  Don't think those are a vaild thing to call.
--- a/xpfe/appshell/nsContentTreeOwner.cpp
+++ b/xpfe/appshell/nsContentTreeOwner.cpp
@@ -329,16 +329,48 @@ nsContentTreeOwner::TabParentRemoved(nsI
 
 NS_IMETHODIMP
 nsContentTreeOwner::GetPrimaryTabParent(nsITabParent** aTab)
 {
   NS_ENSURE_STATE(mXULWindow);
   return mXULWindow->GetPrimaryTabParent(aTab);
 }
 
+NS_IMETHODIMP
+nsContentTreeOwner::GetPrimaryContentSize(int32_t* aWidth,
+                                          int32_t* aHeight)
+{
+  NS_ENSURE_STATE(mXULWindow);
+  return mXULWindow->GetPrimaryContentSize(aWidth, aHeight);
+}
+
+NS_IMETHODIMP
+nsContentTreeOwner::SetPrimaryContentSize(int32_t aWidth,
+                                          int32_t aHeight)
+{
+  NS_ENSURE_STATE(mXULWindow);
+  return mXULWindow->SetPrimaryContentSize(aWidth, aHeight);
+}
+
+NS_IMETHODIMP
+nsContentTreeOwner::GetRootShellSize(int32_t* aWidth,
+                                     int32_t* aHeight)
+{
+  NS_ENSURE_STATE(mXULWindow);
+  return mXULWindow->GetRootShellSize(aWidth, aHeight);
+}
+
+NS_IMETHODIMP
+nsContentTreeOwner::SetRootShellSize(int32_t aWidth,
+                                     int32_t aHeight)
+{
+  NS_ENSURE_STATE(mXULWindow);
+  return mXULWindow->SetRootShellSize(aWidth, aHeight);
+}
+
 NS_IMETHODIMP nsContentTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem,
    int32_t aCX, int32_t aCY)
 {
    NS_ENSURE_STATE(mXULWindow);
    return mXULWindow->SizeShellTo(aShellItem, aCX, aCY);
 }
 
 NS_IMETHODIMP
@@ -439,16 +471,23 @@ nsContentTreeOwner::GetPersistence(bool*
 NS_IMETHODIMP
 nsContentTreeOwner::GetTargetableShellCount(uint32_t* aResult)
 {
   NS_ENSURE_STATE(mXULWindow);
   *aResult = mXULWindow->mTargetableShells.Count();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsContentTreeOwner::GetHasPrimaryContent(bool* aResult)
+{
+  NS_ENSURE_STATE(mXULWindow);
+  return mXULWindow->GetHasPrimaryContent(aResult);
+}
+
 //*****************************************************************************
 // nsContentTreeOwner::nsIWebBrowserChrome3
 //*****************************************************************************   
 
 NS_IMETHODIMP nsContentTreeOwner::OnBeforeLinkTraversal(const nsAString &originalTarget,
                                                         nsIURI *linkURI,
                                                         nsIDOMNode *linkNode,
                                                         bool isAppTab,
--- a/xpfe/appshell/nsIXULBrowserWindow.idl
+++ b/xpfe/appshell/nsIXULBrowserWindow.idl
@@ -43,16 +43,17 @@ interface nsIXULBrowserWindow : nsISuppo
 
   /**
    * Find the initial browser of the window and set its remote attribute.
    * This can be used to ensure that there is a remote browser in a new
    * window when it first spawns.
    *
    */
   nsITabParent forceInitialBrowserRemote();
+  void forceInitialBrowserNonRemote();
 
   /**
    * Determines whether a load should continue.
    *
    * @param aDocShell
    *        The docshell performing the load.
    * @param aURI
    *        The URI being loaded.
--- a/xpfe/appshell/nsIXULWindow.idl
+++ b/xpfe/appshell/nsIXULWindow.idl
@@ -130,17 +130,36 @@ interface nsIXULWindow : nsISupports
   /**
    * Back-door method to force application of chrome flags at a particular
    * time.  Do NOT call this unless you know what you're doing!  In particular,
    * calling this when this XUL window doesn't yet have a document in its
    * docshell could cause problems.
    */
   [noscript] void applyChromeFlags();
 
-
   /**
-   * Sometimes the child's nsDocShellTreeOwner needs to propogate a SizeShellTo call to the parent. But the
-   * shellItem argument of the call will not be available on the parent side, so we pass its dimensions here.
+   * Given the dimensions of some content area held within this
+   * XUL window, and assuming that that content area will change
+   * its dimensions in linear proportion to the dimensions of this
+   * XUL window, changes the size of the XUL window so that the
+   * content area reaches a particular size.
+   *
+   * We need to supply the content area dimensions because sometimes
+   * the child's nsDocShellTreeOwner needs to propagate a SizeShellTo
+   * call to the parent. But the shellItem argument of the call will
+   * not be available on the parent side.
+   *
    * Note: this is an internal method, other consumers should never call this.
+   *
+   * @param aDesiredWidth
+   *        The desired width of the content area in device pixels.
+   * @param aDesiredHeight
+   *        The desired height of the content area in device pixels.
+   * @param shellItemWidth
+   *        The current width of the content area.
+   * @param shellItemHeight
+   *        The current height of the content area.
    */
-  [noscript, notxpcom] void sizeShellToWithLimit(in int32_t aCx, in int32_t aCy,
-                                                 in int32_t shellItemCx, in int32_t shellItemCy);
+  [noscript, notxpcom] void sizeShellToWithLimit(in int32_t aDesiredWidth,
+                                                 in int32_t aDesiredHeight,
+                                                 in int32_t shellItemWidth,
+                                                 in int32_t shellItemHeight);
 };
--- a/xpfe/appshell/nsXULWindow.cpp
+++ b/xpfe/appshell/nsXULWindow.cpp
@@ -56,16 +56,17 @@
 #include "prenv.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/dom/BarProps.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/dom/TabParent.h"
 
 using namespace mozilla;
 using dom::AutoNoJSAPI;
 
 #define SIZEMODE_NORMAL     NS_LITERAL_STRING("normal")
 #define SIZEMODE_MAXIMIZED  NS_LITERAL_STRING("maximized")
 #define SIZEMODE_MINIMIZED  NS_LITERAL_STRING("minimized")
 #define SIZEMODE_FULLSCREEN NS_LITERAL_STRING("fullscreen")
@@ -1796,16 +1797,107 @@ nsresult nsXULWindow::ContentShellRemove
     if (!curItem || SameCOMIdentity(curItem, aContentShell)) {
       mTargetableShells.RemoveObjectAt(i);
     }
   }
   
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsXULWindow::GetPrimaryContentSize(int32_t* aWidth,
+                                   int32_t* aHeight)
+{
+  if (mPrimaryTabParent) {
+    return GetPrimaryTabParentSize(aWidth, aHeight);
+  } else if (mPrimaryContentShell) {
+    return GetPrimaryContentShellSize(aWidth, aHeight);
+  }
+  return NS_ERROR_UNEXPECTED;
+}
+
+nsresult
+nsXULWindow::GetPrimaryTabParentSize(int32_t* aWidth,
+                                     int32_t* aHeight)
+{
+  TabParent* tabParent = TabParent::GetFrom(mPrimaryTabParent);
+  Element* element = tabParent->GetOwnerElement();
+  NS_ENSURE_STATE(element);
+
+  *aWidth = element->ClientWidth();
+  *aHeight = element->ClientHeight();
+  return NS_OK;
+}
+
+nsresult
+nsXULWindow::GetPrimaryContentShellSize(int32_t* aWidth,
+                                        int32_t* aHeight)
+{
+  NS_ENSURE_STATE(mPrimaryContentShell);
+
+  nsCOMPtr<nsIBaseWindow> shellWindow(do_QueryInterface(mPrimaryContentShell));
+  NS_ENSURE_STATE(shellWindow);
+
+  int32_t devicePixelWidth, devicePixelHeight;
+  double shellScale = 1.0;
+  // We want to return CSS pixels. First, we get device pixels
+  // from the content area...
+  shellWindow->GetSize(&devicePixelWidth, &devicePixelHeight);
+  // And then get the device pixel scaling factor. Dividing device
+  // pixels by this scaling factor gives us CSS pixels.
+  shellWindow->GetUnscaledDevicePixelsPerCSSPixel(&shellScale);
+  *aWidth = NSToIntRound(devicePixelWidth / shellScale);
+  *aHeight = NSToIntRound(devicePixelHeight / shellScale);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULWindow::SetPrimaryContentSize(int32_t aWidth,
+                                   int32_t aHeight)
+{
+  if (mPrimaryTabParent) {
+    return SetPrimaryTabParentSize(aWidth, aHeight);
+  } else if (mPrimaryContentShell) {
+    return SizeShellTo(mPrimaryContentShell, aWidth, aHeight);
+  }
+  return NS_ERROR_UNEXPECTED;
+}
+
+nsresult
+nsXULWindow::SetPrimaryTabParentSize(int32_t aWidth,
+                                     int32_t aHeight)
+{
+  int32_t shellWidth, shellHeight;
+  GetPrimaryTabParentSize(&shellWidth, &shellHeight);
+
+  double scale = 1.0;
+  GetUnscaledDevicePixelsPerCSSPixel(&scale);
+
+  SizeShellToWithLimit(aWidth, aHeight,
+                       shellWidth * scale, shellHeight * scale);
+  return NS_OK;
+}
+
+nsresult
+nsXULWindow::GetRootShellSize(int32_t* aWidth,
+                              int32_t* aHeight)
+{
+  nsCOMPtr<nsIBaseWindow> shellAsWin = do_QueryInterface(mDocShell);
+  NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE);
+  return shellAsWin->GetSize(aWidth, aHeight);
+}
+
+nsresult
+nsXULWindow::SetRootShellSize(int32_t aWidth,
+                              int32_t aHeight)
+{
+  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem = do_QueryInterface(mDocShell);
+  return SizeShellTo(docShellAsItem, aWidth, aHeight);
+}
+
 NS_IMETHODIMP nsXULWindow::SizeShellTo(nsIDocShellTreeItem* aShellItem,
    int32_t aCX, int32_t aCY)
 {
   // XXXTAB This is wrong, we should actually reflow based on the passed in
   // shell.  For now we are hacking and doing delta sizing.  This is bad
   // because it assumes all size we add will go to the shell which probably
   // won't happen.
 
@@ -1916,24 +2008,30 @@ NS_IMETHODIMP nsXULWindow::CreateNewCont
     AutoNoJSAPI nojsapi;
     nsIThread *thread = NS_GetCurrentThread();
     while (xulWin->IsLocked()) {
       if (!NS_ProcessNextEvent(thread))
         break;
     }
   }
 
-  NS_ENSURE_STATE(xulWin->mPrimaryContentShell);
+  NS_ENSURE_STATE(xulWin->mPrimaryContentShell || xulWin->mPrimaryTabParent);
 
   *_retval = newWindow;
   NS_ADDREF(*_retval);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP nsXULWindow::GetHasPrimaryContent(bool* aResult)
+{
+  *aResult = mPrimaryTabParent || mPrimaryContentShell;
+  return NS_OK;
+}
+
 void nsXULWindow::EnableParent(bool aEnable)
 {
   nsCOMPtr<nsIBaseWindow> parentWindow;
   nsCOMPtr<nsIWidget>     parentWidget;
 
   parentWindow = do_QueryReferent(mParentWindow);
   if (parentWindow)
     parentWindow->GetMainWidget(getter_AddRefs(parentWidget));
@@ -2177,34 +2275,36 @@ NS_IMETHODIMP nsXULWindow::GetXULBrowser
 }
 
 NS_IMETHODIMP nsXULWindow::SetXULBrowserWindow(nsIXULBrowserWindow * aXULBrowserWindow)
 {
   mXULBrowserWindow = aXULBrowserWindow;
   return NS_OK;
 }
 
-void nsXULWindow::SizeShellToWithLimit(int32_t aCX, int32_t aCY,
-                                       int32_t shellItemCx, int32_t shellItemCy)
+void nsXULWindow::SizeShellToWithLimit(int32_t aDesiredWidth,
+                                       int32_t aDesiredHeight,
+                                       int32_t shellItemWidth,
+                                       int32_t shellItemHeight)
 {
-  int32_t widthDelta = aCX - shellItemCx;
-  int32_t heightDelta = aCY - shellItemCy;
+  int32_t widthDelta = aDesiredWidth - shellItemWidth;
+  int32_t heightDelta = aDesiredHeight - shellItemHeight;
 
   if (widthDelta || heightDelta) {
-    int32_t winCX = 0;
-    int32_t winCY = 0;
+    int32_t winWidth = 0;
+    int32_t winHeight = 0;
 
-    GetSize(&winCX, &winCY);
+    GetSize(&winWidth, &winHeight);
     // There's no point in trying to make the window smaller than the
-    // desired docshell size --- that's not likely to work. This whole
+    // desired content area size --- that's not likely to work. This whole
     // function assumes that the outer docshell is adding some constant
-    // "border" chrome to aShellItem.
-    winCX = std::max(winCX + widthDelta, aCX);
-    winCY = std::max(winCY + heightDelta, aCY);
-    SetSize(winCX, winCY, true);
+    // "border" chrome to the content area.
+    winWidth = std::max(winWidth + widthDelta, aDesiredWidth);
+    winHeight = std::max(winHeight + heightDelta, aDesiredHeight);
+    SetSize(winWidth, winHeight, true);
   }
 }
 
 //*****************************************************************************
 //*** nsContentShellInfo: Object Management
 //*****************************************************************************   
 
 nsContentShellInfo::nsContentShellInfo(const nsAString& aID,
--- a/xpfe/appshell/nsXULWindow.h
+++ b/xpfe/appshell/nsXULWindow.h
@@ -104,21 +104,31 @@ protected:
    NS_IMETHOD GetWindowDOMWindow(mozIDOMWindowProxy** aDOMWindow);
    mozilla::dom::Element* GetWindowDOMElement() const;
 
    // See nsIDocShellTreeOwner for docs on next two methods
    nsresult ContentShellAdded(nsIDocShellTreeItem* aContentShell,
                                           bool aPrimary, bool aTargetable,
                                           const nsAString& aID);
    nsresult ContentShellRemoved(nsIDocShellTreeItem* aContentShell);
+   NS_IMETHOD GetPrimaryContentSize(int32_t* aWidth,
+                                    int32_t* aHeight);
+   NS_IMETHOD SetPrimaryContentSize(int32_t aWidth,
+                                    int32_t aHeight);
+   nsresult GetRootShellSize(int32_t* aWidth,
+                             int32_t* aHeight);
+   nsresult SetRootShellSize(int32_t aWidth,
+                             int32_t aHeight);
+
    NS_IMETHOD SizeShellTo(nsIDocShellTreeItem* aShellItem, int32_t aCX, 
       int32_t aCY);
    NS_IMETHOD ExitModalLoop(nsresult aStatus);
    NS_IMETHOD CreateNewChromeWindow(int32_t aChromeFlags, nsITabParent* aOpeningTab, nsIXULWindow **_retval);
    NS_IMETHOD CreateNewContentWindow(int32_t aChromeFlags, nsITabParent* aOpeningTab, nsIXULWindow **_retval);
+   NS_IMETHOD GetHasPrimaryContent(bool* aResult);
 
    void       EnableParent(bool aEnable);
    bool       ConstrainToZLevel(bool aImmediate, nsWindowZ *aPlacement,
                                 nsIWidget *aReqBelow, nsIWidget **aActualBelow);
    void       PlaceWindowLayersBehind(uint32_t aLowLevel, uint32_t aHighLevel,
                                       nsIXULWindow *aBehind);
    void       SetContentScrollbarVisibility(bool aVisible);
    bool       GetContentScrollbarVisibility();
@@ -158,16 +168,20 @@ protected:
    uint32_t                mPersistentAttributesMask;
    uint32_t                mChromeFlags;
    nsString                mTitle;
    nsIntRect               mOpenerScreenRect; // the screen rect of the opener
 
    nsCOMArray<nsIWeakReference> mTargetableShells; // targetable shells only
 
    nsCOMPtr<nsITabParent> mPrimaryTabParent;
+private:
+   nsresult GetPrimaryTabParentSize(int32_t* aWidth, int32_t* aHeight);
+   nsresult GetPrimaryContentShellSize(int32_t* aWidth, int32_t* aHeight);
+   nsresult SetPrimaryTabParentSize(int32_t aWidth, int32_t aHeight);
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsXULWindow, NS_XULWINDOW_IMPL_CID)
 
 // nsContentShellInfo
 // Used to map shell IDs to nsIDocShellTreeItems.
 
 class nsContentShellInfo