Merge mozilla-central to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 20 Feb 2015 15:48:44 +0100
changeset 258866 2404e82f59d56f7f66a36484ac1c417c8e54eba8
parent 258865 2f03ad51053e556290ebf1f81970a64c2ebabe79 (current diff)
parent 258749 5f1009731a977b83d2b177099c6ae3b12085ec7a (diff)
child 258867 4f2240fd9394267bb5e0fa6d9e71959c8f074127
push id721
push userjlund@mozilla.com
push dateTue, 21 Apr 2015 23:03:33 +0000
treeherdermozilla-release@d27c9211ebb3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone38.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 mozilla-central to b2g-inbound
dom/media/eme/EMELog.cpp
dom/media/eme/EMELog.h
dom/media/eme/EMEUtils.cpp
dom/media/eme/EMEUtils.h
--- a/browser/base/content/browser-eme.js
+++ b/browser/base/content/browser-eme.js
@@ -1,36 +1,191 @@
 # -*- 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/.
 
-function gEMEListener(msg /*{target: browser, data: data} */) {
-  let browser = msg.target;
-  let notificationId = "drmContentPlaying";
-  // Don't need to show if disabled, nor reshow if it's already there
-  if (!Services.prefs.getBoolPref("browser.eme.ui.enabled") ||
-      PopupNotifications.getNotification(notificationId, browser)) {
-    return;
-  }
+let gEMEHandler = {
+  ensureEMEEnabled: function(browser, keySystem) {
+    Services.prefs.setBoolPref("media.eme.enabled", true);
+    if (keySystem) {
+      if (keySystem.startsWith("com.adobe") &&
+          Services.prefs.getPrefType("media.gmp-eme-adobe.enabled") &&
+          !Services.prefs.getBoolPref("media.gmp-eme-adobe.enabled")) {
+        Services.prefs.setBoolPref("media.gmp-eme-adobe.enabled", true);
+      } else if (keySystem == "org.w3.clearkey" &&
+                 Services.prefs.getPrefType("media.eme.clearkey.enabled") &&
+                 !Services.prefs.getBoolPref("media.eme.clearkey.enabled")) {
+        Services.prefs.setBoolPref("media.eme.clearkey.enabled", true);
+      }
+    }
+    browser.reload();
+  },
+  getLearnMoreLink: function(msgId) {
+    let text = gNavigatorBundle.getString("emeNotifications." + msgId + ".learnMoreLabel");
+    let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
+    return "<label class='text-link' href='" + baseURL + "drm-content'>" +
+           text + "</label>";
+  },
+  getDRMLabel: function(keySystem) {
+    if (keySystem.startsWith("com.adobe")) {
+      return "Adobe Primetime";
+    }
+    if (keySystem == "org.w3.clearkey") {
+      return "ClearKey";
+    }
+    return gNavigatorBundle.getString("emeNotifications.unknownDRMSoftware");
+  },
+  onDontAskAgain: function(menuPopupItem) {
+    let button = menuPopupItem.parentNode.anchorNode;
+    let bar = button.parentNode;
+    Services.prefs.setBoolPref("browser.eme.ui." + bar.value + ".disabled", true);
+    bar.close();
+  },
+  onNotNow: function(menuPopupItem) {
+    let button = menuPopupItem.parentNode.anchorNode;
+    button.parentNode.close();
+  },
+  receiveMessage: function({target: browser, data: data}) {
+    let parsedData;
+    try {
+      parsedData = JSON.parse(data);
+    } catch (ex) {
+      Cu.reportError("Malformed EME video message with data: " + data);
+      return;
+    }
+    let {status: status, keySystem: keySystem} = parsedData;
+    // Don't need to show if disabled
+    if (!Services.prefs.getBoolPref("browser.eme.ui.enabled")) {
+      return;
+    }
+
+    let notificationId;
+    let buttonCallback;
+    let params = [];
+    switch (status) {
+      case "available":
+      case "cdm-created":
+        this.showPopupNotificationForSuccess(browser, keySystem);
+        // ... and bail!
+        return;
+
+      case "api-disabled":
+      case "cdm-disabled":
+        notificationId = "drmContentDisabled";
+        buttonCallback = gEMEHandler.ensureEMEEnabled.bind(gEMEHandler, browser, keySystem)
+        params = [this.getLearnMoreLink(notificationId)];
+        break;
+
+      case "cdm-not-supported":
+        notificationId = "drmContentCDMNotSupported";
+        params = [this._brandShortName, this.getLearnMoreLink(notificationId)];
+        break;
+
+      case "cdm-insufficient-version":
+        notificationId = "drmContentCDMInsufficientVersion";
+        params = [this._brandShortName];
+        break;
+
+      case "cdm-not-installed":
+        notificationId = "drmContentCDMInstalling";
+        params = [this._brandShortName];
+        break;
 
-  let msgId = "emeNotifications.drmContentPlaying.message";
-  let brandName = document.getElementById("bundle_brand").getString("brandShortName");
-  let message = gNavigatorBundle.getFormattedString(msgId, [msg.data.drmProvider, brandName]);
-  let anchorId = "eme-notification-icon";
+      case "error":
+        // Fall through and do the same for unknown messages:
+      default:
+        let typeOfIssue = status == "error" ? "error" : "message ('" + status + "')";
+        Cu.reportError("Unknown " + typeOfIssue + " dealing with EME key request: " + data);
+        return;
+    }
+
+    this.showNotificationBar(browser, notificationId, params, buttonCallback);
+  },
+  showNotificationBar: function(browser, notificationId, labelParams, callback) {
+    let box = gBrowser.getNotificationBox(browser);
+    if (box.getNotificationWithValue(notificationId)) {
+      return;
+    }
+
+    // If the user turned these off, bail out:
+    try {
+      if (Services.prefs.getBoolPref("browser.eme.ui." + notificationId + ".disabled")) {
+        return;
+      }
+    } catch (ex) { /* Don't care if the pref doesn't exist */ }
+
+    let msgPrefix = "emeNotifications." + notificationId + ".";
+    let msgId = msgPrefix + "message";
+
+    let message = labelParams.length ?
+                  gNavigatorBundle.getFormattedString(msgId, labelParams) :
+                  gNavigatorBundle.getString(msgId);
+
+    let buttons = [];
+    if (callback) {
+      let btnLabelId = msgPrefix + "button.label";
+      let btnAccessKeyId = msgPrefix + "button.accesskey";
+      buttons.push({
+        label: gNavigatorBundle.getString(btnLabelId),
+        accesskey: gNavigatorBundle.getString(btnAccessKeyId),
+        callback: callback
+      });
 
-  let mainAction = {
-    label: gNavigatorBundle.getString("emeNotifications.drmContentPlaying.button.label"),
-    accessKey: gNavigatorBundle.getString("emeNotifications.drmContentPlaying.button.accesskey"),
-    callback: function() { openPreferences("paneContent"); },
-    dismiss: true
-  };
-  let options = {
-    dismissed: true,
-    eventCallback: aTopic => aTopic == "swapping",
-  };
-  PopupNotifications.show(browser, notificationId, message, anchorId, mainAction, null, options);
+      let optionsId = "emeNotifications.optionsButton";
+      buttons.push({
+        label: gNavigatorBundle.getString(optionsId + ".label"),
+        accesskey: gNavigatorBundle.getString(optionsId + ".accesskey"),
+        popup: "emeNotificationsPopup"
+      });
+    }
+
+    let iconURL = "chrome://browser/skin/drm-icon.svg#chains-black";
+
+    // Do a little dance to get rich content into the notification:
+    let fragment = document.createDocumentFragment();
+    let descriptionContainer = document.createElement("description");
+    descriptionContainer.innerHTML = message;
+    while (descriptionContainer.childNodes.length) {
+      fragment.appendChild(descriptionContainer.childNodes[0]);
+    }
+
+    box.appendNotification(fragment, notificationId, iconURL, box.PRIORITY_WARNING_MEDIUM,
+                           buttons);
+  },
+  showPopupNotificationForSuccess: function(browser, keySystem) {
+    // Don't bother creating it if it's already there:
+    if (PopupNotifications.getNotification("drmContentPlaying", browser)) {
+      return;
+    }
+
+    let msgPrefix = "emeNotifications.drmContentPlaying.";
+    let msgId = msgPrefix + "message";
+    let btnLabelId = msgPrefix + "button.label";
+    let btnAccessKeyId = msgPrefix + "button.accesskey";
+
+    let drmProvider = this.getDRMLabel(keySystem);
+    let message = gNavigatorBundle.getFormattedString(msgId, [drmProvider, this._brandShortName]);
+    let anchorId = "eme-notification-icon";
+
+    let mainAction = {
+      label: gNavigatorBundle.getString(btnLabelId),
+      accessKey: gNavigatorBundle.getString(btnAccessKeyId),
+      callback: function() { openPreferences("paneContent"); },
+      dismiss: true
+    };
+    let options = {
+      dismissed: true,
+      eventCallback: aTopic => aTopic == "swapping",
+    };
+    PopupNotifications.show(browser, "drmContentPlaying", message, anchorId, mainAction, null, options);
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener])
 };
 
-window.messageManager.addMessageListener("EMEVideo:MetadataLoaded", gEMEListener);
+XPCOMUtils.defineLazyGetter(gEMEHandler, "_brandShortName", function() {
+  return document.getElementById("bundle_brand").getString("brandShortName");
+});
+
+window.messageManager.addMessageListener("EMEVideo:ContentMediaKeysRequest", gEMEHandler);
 window.addEventListener("unload", function() {
-  window.messageManager.removeMessageListener("EMEVideo:MetadataLoaded", gEMEListener);
+  window.messageManager.removeMessageListener("EMEVideo:ContentMediaKeysRequest", gEMEHandler);
 }, false);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7414,16 +7414,21 @@ let gPrivateBrowsingUI = {
 let gRemoteTabsUI = {
   init: function() {
     if (window.location.href != getBrowserURL() &&
         // Also check hidden window for the Mac no-window case
         window.location.href != "chrome://browser/content/hiddenWindow.xul") {
       return;
     }
 
+    if (Services.appinfo.inSafeMode) {
+      // e10s isn't supported in safe mode, so don't show the menu items for it
+      return;
+    }
+
     let newRemoteWindow = document.getElementById("menu_newRemoteWindow");
     let newNonRemoteWindow = document.getElementById("menu_newNonRemoteWindow");
     let autostart = Services.appinfo.browserTabsRemoteAutostart;
     newRemoteWindow.hidden = autostart;
     newNonRemoteWindow.hidden = !autostart;
   }
 };
 
@@ -7632,42 +7637,18 @@ Object.defineProperty(this, "HUDService"
     let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
     return devtools.require("devtools/webconsole/hudservice");
   },
   configurable: true,
   enumerable: true
 });
 
 // Prompt user to restart the browser in safe mode
-function safeModeRestart()
-{
-  // prompt the user to confirm
-  let promptTitle = gNavigatorBundle.getString("safeModeRestartPromptTitle");
-  let promptMessage =
-    gNavigatorBundle.getString("safeModeRestartPromptMessage");
-  let restartText = gNavigatorBundle.getString("safeModeRestartButton");
-  let buttonFlags = (Services.prompt.BUTTON_POS_0 *
-                     Services.prompt.BUTTON_TITLE_IS_STRING) +
-                    (Services.prompt.BUTTON_POS_1 *
-                     Services.prompt.BUTTON_TITLE_CANCEL) +
-                    Services.prompt.BUTTON_POS_0_DEFAULT;
-
-  let rv = Services.prompt.confirmEx(window, promptTitle, promptMessage,
-                                     buttonFlags, restartText, null, null,
-                                     null, {});
-  if (rv != 0)
-    return;
-
-  let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
-                     .createInstance(Ci.nsISupportsPRBool);
-  Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
-
-  if (!cancelQuit.data) {
-    Services.startup.restartInSafeMode(Ci.nsIAppStartup.eAttemptQuit);
-  }
+function safeModeRestart() {
+  Services.obs.notifyObservers(null, "restart-in-safe-mode", "");
 }
 
 /* duplicateTabIn duplicates tab in a place specified by the parameter |where|.
  *
  * |where| can be:
  *  "tab"         new tab
  *  "tabshifted"  same as "tab" but in background if default is to select new
  *                tabs, and vice versa
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -562,16 +562,27 @@
       </vbox>
       <vbox id="bookmarked-notification-dropmarker-anchor">
         <image id="bookmarked-notification-dropmarker-icon"/>
       </vbox>
     </hbox>
 
     <tooltip id="dynamic-shortcut-tooltip"
              onpopupshowing="UpdateDynamicShortcutTooltipText(this);"/>
+
+    <menupopup id="emeNotificationsPopup">
+      <menuitem id="emeNotificationsNotNow"
+                label="&emeNotificationsNotNow.label;"
+                acceskey="&emeNotificationsNotNow.accesskey;"
+                oncommand="gEMEHandler.onNotNow(this);"/>
+      <menuitem id="emeNotificationsDontAskAgain"
+                label="&emeNotificationsDontAskAgain.label;"
+                acceskey="&emeNotificationsDontAskAgain.accesskey;"
+                oncommand="gEMEHandler.onDontAskAgain(this);"/>
+    </menupopup>
   </popupset>
 
 #ifdef CAN_DRAW_IN_TITLEBAR
 <vbox id="titlebar">
   <hbox id="titlebar-content">
     <spacer id="titlebar-spacer" flex="1"/>
     <hbox id="titlebar-buttonbox-container">
 #ifdef XP_WIN
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -430,16 +430,17 @@ skip-if = e10s # Bug 1100664 - test reli
 [browser_testOpenNewRemoteTabsFromNonRemoteBrowsers.js]
 run-if = e10s
 [browser_trackingUI.js]
 support-files =
   trackingPage.html
   benignPage.html
 [browser_typeAheadFind.js]
 skip-if = buildapp == 'mulet' || e10s # Bug 921935 - focusmanager issues with e10s (test calls waitForFocus)
+[browser_unknownContentType_title.js]
 [browser_unloaddialogs.js]
 skip-if = e10s # Bug 1100700 - test relies on unload event firing on closed tabs, which it doesn't
 [browser_urlHighlight.js]
 [browser_urlbarAutoFillTrimURLs.js]
 skip-if = e10s # Bug 1093941 - Waits indefinitely for onSearchComplete
 [browser_urlbarCopying.js]
 [browser_urlbarEnter.js]
 skip-if = e10s # Bug 1093941 - used to cause obscure non-windows child process crashes on try
@@ -479,18 +480,18 @@ skip-if = e10s
 skip-if = e10s
 [browser_bug1025195_switchToTabHavingURI_aOpenParams.js]
 [browser_addCertException.js]
 skip-if = e10s # Bug 1100687 - test directly manipulates content (content.document.getElementById)
 [browser_bug1045809.js]
 [browser_e10s_switchbrowser.js]
 [browser_e10s_about_process.js]
 [browser_e10s_chrome_process.js]
+[browser_e10s_javascript.js]
 [browser_blockHPKP.js]
 skip-if = e10s # bug 1100687 - test directly manipulates content (content.document.getElementById)
 [browser_mcb_redirect.js]
-skip-if = e10s # bug 1084504 - [e10s] Mixed content detection does not take redirection into account
 [browser_windowactivation.js]
 [browser_contextmenu_childprocess.js]
 [browser_bug963945.js]
 [browser_readerMode.js]
 support-files =
   readerModeArticle.html
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_e10s_javascript.js
@@ -0,0 +1,11 @@
+const CHROME_PROCESS = Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+const CONTENT_PROCESS = Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT;
+
+add_task(function*() {
+  let url = "javascript:dosomething()";
+
+  ok(E10SUtils.canLoadURIInProcess(url, CHROME_PROCESS),
+     "Check URL in chrome process.");
+  ok(E10SUtils.canLoadURIInProcess(url, CONTENT_PROCESS),
+     "Check URL in content process.");
+});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_unknownContentType_title.js
@@ -0,0 +1,33 @@
+const url = "data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3Ctitle%3ETest%20Page%3C%2Ftitle%3E%3C%2Fhead%3E%3C%2Fhtml%3E";
+const unknown_url = "http://example.com/browser/browser/base/content/test/general/unknownContentType_file.pif";
+
+function waitForNewWindow() {
+  return new Promise(resolve => {
+    let listener = (win) => {
+      Services.obs.removeObserver(listener, "toplevel-window-ready");
+      win.addEventListener("load", () => {
+        resolve(win);
+      });
+    };
+
+    Services.obs.addObserver(listener, "toplevel-window-ready", false)
+  });
+}
+
+add_task(function*() {
+  let tab = gBrowser.selectedTab = gBrowser.addTab(url);
+  let browser = tab.linkedBrowser;
+  yield promiseTabLoaded(gBrowser.selectedTab);
+
+  is(gBrowser.contentTitle, "Test Page", "Should have the right title.")
+
+  browser.loadURI(unknown_url);
+  let win = yield waitForNewWindow();
+  is(win.location, "chrome://mozapps/content/downloads/unknownContentType.xul",
+     "Should have seen the unknown content dialog.");
+  is(gBrowser.contentTitle, "Test Page", "Should still have the right title.")
+
+  win.close();
+  yield promiseWaitForFocus(window);
+  gBrowser.removeCurrentTab();
+});
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -158,28 +158,19 @@ AboutRedirector::NewChannel(nsIURI* aURI
 
   for (int i = 0; i < kRedirTotal; i++) {
     if (!strcmp(path.get(), kRedirMap[i].id)) {
       nsCOMPtr<nsIChannel> tempChannel;
       nsCOMPtr<nsIURI> tempURI;
       rv = NS_NewURI(getter_AddRefs(tempURI),
                      nsDependentCString(kRedirMap[i].url));
       NS_ENSURE_SUCCESS(rv, rv);
-      // Bug 1087720 (and Bug 1099296):
-      // Once all callsites have been updated to call NewChannel2()
-      // instead of NewChannel() we should have a non-null loadInfo
-      // consistently. Until then we have to branch on the loadInfo.
-      if (aLoadInfo) {
-        rv = NS_NewChannelInternal(getter_AddRefs(tempChannel),
-                                   tempURI,
-                                   aLoadInfo);
-      }
-      else {
-        rv = ioService->NewChannelFromURI(tempURI, getter_AddRefs(tempChannel));
-      }
+      rv = NS_NewChannelInternal(getter_AddRefs(tempChannel),
+                                 tempURI,
+                                 aLoadInfo);
       NS_ENSURE_SUCCESS(rv, rv);
 
       tempChannel->SetOriginalURI(aURI);
 
       NS_ADDREF(*result = tempChannel);
       return rv;
     }
   }
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -1071,12 +1071,13 @@ let openRemote = !Services.appinfo.brows
 // this button should never roll into production.
 let buttonLabel = openRemote ? "New e10s Window"
                               : "New Non-e10s Window";
 
 CustomizableWidgets.push({
   id: "e10s-button",
   label: buttonLabel,
   tooltiptext: buttonLabel,
+  disabled: Services.appinfo.inSafeMode,
   defaultArea: CustomizableUI.AREA_PANEL,
   onCommand: getCommandFunction(openRemote),
 });
 #endif
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -278,16 +278,19 @@ BrowserGlue.prototype = {
       case "sessionstore-windows-restored":
         this._onWindowsRestored();
         break;
       case "browser:purge-session-history":
         // reset the console service's error buffer
         Services.console.logStringMessage(null); // clear the console (in case it's open)
         Services.console.reset();
         break;
+      case "restart-in-safe-mode":
+        this._onSafeModeRestart();
+        break;
       case "quit-application-requested":
         this._onQuitRequest(subject, data);
         break;
       case "quit-application-granted":
         this._onQuitApplicationGranted();
         break;
 #ifdef OBSERVE_LASTWINDOW_CLOSE_TOPICS
       case "browser-lastwindow-close-requested":
@@ -515,27 +518,29 @@ BrowserGlue.prototype = {
     this._isPlacesShutdownObserver = true;
     os.addObserver(this, "handle-xul-text-link", false);
     os.addObserver(this, "profile-before-change", false);
 #ifdef MOZ_SERVICES_HEALTHREPORT
     os.addObserver(this, "keyword-search", false);
 #endif
     os.addObserver(this, "browser-search-engine-modified", false);
     os.addObserver(this, "browser-search-service", false);
+    os.addObserver(this, "restart-in-safe-mode", false);
   },
 
   // cleanup (called on application shutdown)
   _dispose: function BG__dispose() {
     let os = Services.obs;
     os.removeObserver(this, "prefservice:after-app-defaults");
     os.removeObserver(this, "final-ui-startup");
     os.removeObserver(this, "sessionstore-windows-restored");
     os.removeObserver(this, "browser:purge-session-history");
     os.removeObserver(this, "quit-application-requested");
     os.removeObserver(this, "quit-application-granted");
+    os.removeObserver(this, "restart-in-safe-mode");
 #ifdef OBSERVE_LASTWINDOW_CLOSE_TOPICS
     os.removeObserver(this, "browser-lastwindow-close-requested");
     os.removeObserver(this, "browser-lastwindow-close-granted");
 #endif
 #ifdef MOZ_SERVICES_SYNC
     os.removeObserver(this, "weave:service:ready");
     os.removeObserver(this, "weave:engine:clients:display-uri");
 #endif
@@ -645,16 +650,43 @@ BrowserGlue.prototype = {
       let acceptableAge = Services.prefs.getIntPref("app.update.checkInstallTime.days") * millisecondsIn24Hours;
 
       if (buildDate + acceptableAge < today) {
         Cc["@mozilla.org/updates/update-service;1"].getService(Ci.nsIApplicationUpdateService).checkForBackgroundUpdates();
       }
     }
   },
 
+  _onSafeModeRestart: function BG_onSafeModeRestart() {
+    // prompt the user to confirm
+    let strings = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+    let promptTitle = strings.GetStringFromName("safeModeRestartPromptTitle");
+    let promptMessage = strings.GetStringFromName("safeModeRestartPromptMessage");
+    let restartText = strings.GetStringFromName("safeModeRestartButton");
+    let buttonFlags = (Services.prompt.BUTTON_POS_0 *
+                       Services.prompt.BUTTON_TITLE_IS_STRING) +
+                      (Services.prompt.BUTTON_POS_1 *
+                       Services.prompt.BUTTON_TITLE_CANCEL) +
+                      Services.prompt.BUTTON_POS_0_DEFAULT;
+
+    let rv = Services.prompt.confirmEx(null, promptTitle, promptMessage,
+                                       buttonFlags, restartText, null, null,
+                                       null, {});
+    if (rv != 0)
+      return;
+
+    let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
+                       .createInstance(Ci.nsISupportsPRBool);
+    Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
+
+    if (!cancelQuit.data) {
+      Services.startup.restartInSafeMode(Ci.nsIAppStartup.eAttemptQuit);
+    }
+  },
+
   _trackSlowStartup: function () {
     if (Services.startup.interrupted ||
         Services.prefs.getBoolPref("browser.slowStartup.notificationDisabled"))
       return;
 
     let currentTime = Date.now() - Services.startup.getStartupInfo().process;
     let averageTime = 0;
     let samples = 0;
--- a/browser/components/preferences/advanced.js
+++ b/browser/components/preferences/advanced.js
@@ -229,16 +229,34 @@ var gAdvancedPane = {
    */
   initTelemetry: function ()
   {
 #ifdef MOZ_TELEMETRY_REPORTING
     this._setupLearnMoreLink("toolkit.telemetry.infoURL", "telemetryLearnMore");
 #endif
   },
 
+  /**
+   * Set the status of the telemetry controls based on the input argument.
+   * @param {Boolean} aEnabled False disables the controls, true enables them.
+   */
+  setTelemetrySectionEnabled: function (aEnabled)
+  {
+#ifdef MOZ_TELEMETRY_REPORTING
+    // If FHR is disabled, additional data sharing should be disabled as well.
+    let disabled = !aEnabled;
+    document.getElementById("submitTelemetryBox").disabled = disabled;
+    if (disabled) {
+      // If we disable FHR, untick the telemetry checkbox.
+      document.getElementById("submitTelemetryBox").checked = false;
+    }
+    document.getElementById("telemetryDataDesc").disabled = disabled;
+#endif
+  },
+
 #ifdef MOZ_SERVICES_HEALTHREPORT
   /**
    * Initialize the health report service reference and checkbox.
    */
   initSubmitHealthReport: function () {
     this._setupLearnMoreLink("datareporting.healthreport.infoURL", "FHRLearnMore");
 
     let policy = Components.classes["@mozilla.org/datareporting/service;1"]
@@ -249,16 +267,17 @@ var gAdvancedPane = {
     let checkbox = document.getElementById("submitHealthReportBox");
 
     if (!policy || policy.healthReportUploadLocked) {
       checkbox.setAttribute("disabled", "true");
       return;
     }
 
     checkbox.checked = policy.healthReportUploadEnabled;
+    this.setTelemetrySectionEnabled(checkbox.checked);
   },
 
   /**
    * Update the health report policy acceptance with state from checkbox.
    */
   updateSubmitHealthReport: function () {
     let policy = Components.classes["@mozilla.org/datareporting/service;1"]
                                    .getService(Components.interfaces.nsISupports)
@@ -267,16 +286,17 @@ var gAdvancedPane = {
 
     if (!policy) {
       return;
     }
 
     let checkbox = document.getElementById("submitHealthReportBox");
     policy.recordHealthReportUploadEnabled(checkbox.checked,
                                            "Checkbox from preferences pane");
+    this.setTelemetrySectionEnabled(checkbox.checked);
   },
 #endif
 
   // NETWORK TAB
 
   /*
    * Preferences:
    *
--- a/browser/components/preferences/advanced.xul
+++ b/browser/components/preferences/advanced.xul
@@ -162,61 +162,60 @@
                       onsynctopreference="return gAdvancedPane.writeCheckSpelling();"
                       preference="layout.spellcheckDefault"/>
           </groupbox>
         </tabpanel>
 
 #ifdef MOZ_DATA_REPORTING
         <!-- Data Choices -->
         <tabpanel id="dataChoicesPanel" orient="vertical">
-#ifdef MOZ_TELEMETRY_REPORTING
-          <groupbox>
-            <caption label="&telemetrySection.label;"/>
-            <description>&telemetryDesc.label;</description>
-            <hbox>
-              <checkbox id="submitTelemetryBox"
-                        preference="toolkit.telemetry.enabled"
-                        label="&enableTelemetry.label;"
-                        accesskey="&enableTelemetry.accesskey;"/>
-              <spacer flex="1"/>
-              <label id="telemetryLearnMore"
-                     class="text-link"
-                     value="&telemetryLearnMore.label;"
-                     onclick="gAdvancedPane.openTextLink(event)"/>
-            </hbox>
-          </groupbox>
-#endif
 #ifdef MOZ_SERVICES_HEALTHREPORT
           <groupbox>
-            <caption label="&healthReportSection.label;"/>
-            <description>&healthReportDesc.label;</description>
-            <hbox>
-              <checkbox id="submitHealthReportBox"
+            <caption>
+              <checkbox id="submitHealthReportBox" label="&enableHealthReport.label;"
                         oncommand="gAdvancedPane.updateSubmitHealthReport();"
-                        label="&enableHealthReport.label;"
                         accesskey="&enableHealthReport.accesskey;"/>
-              <spacer flex="1"/>
-              <label id="FHRLearnMore"
-                     class="text-link"
-                     value="&healthReportLearnMore.label;"
-                     onclick="gAdvancedPane.openTextLink(event)"/>
-            </hbox>
+            </caption>
+            <vbox>
+              <hbox class="indent">
+                <label flex="1">&healthReportDesc.label;</label>
+                <spacer flex="10"/>
+                <label id="FHRLearnMore" class="text-link"
+                       value="&healthReportLearnMore.label;"
+                       onclick="gAdvancedPane.openTextLink(event)"/>
+              </hbox>
+#ifdef MOZ_TELEMETRY_REPORTING
+              <hbox class="indent">
+                <vbox flex="1">
+                  <checkbox id="submitTelemetryBox" label="&enableTelemetryData.label;"
+                            preference="toolkit.telemetry.enabled"
+                            accesskey="&enableTelemetryData.accesskey;"/>
+                  <hbox class="indent">
+                    <label id="telemetryDataDesc" flex="1">&telemetryDesc.label;</label>
+                    <spacer flex="10"/>
+                    <label id="telemetryLearnMore" class="text-link"
+                           value="&telemetryLearnMore.label;"
+                           onclick="gAdvancedPane.openTextLink(event)"/>
+                  </hbox>
+                </vbox>
+              </hbox>
+#endif
+            </vbox>
           </groupbox>
 #endif
 #ifdef MOZ_CRASHREPORTER
           <groupbox>
-            <caption label="&crashReporterSection.label;"/>
-            <description>&crashReporterDesc.label;</description>
-            <hbox>
-              <checkbox id="submitCrashesBox"
+            <caption>
+              <checkbox id="submitCrashesBox" label="&enableCrashReporter.label;"
                         oncommand="gAdvancedPane.updateSubmitCrashes();"
-                        label="&enableCrashReporter.label;"
                         accesskey="&enableCrashReporter.accesskey;"/>
-
-              <spacer flex="1"/>
+            </caption>
+            <hbox class="indent">
+              <label flex="1">&crashReporterDesc.label;</label>
+              <spacer flex="10"/>
               <label id="crashReporterLearnMore"
                      class="text-link"
                      value="&crashReporterLearnMore.label;"
                      onclick="gAdvancedPane.openTextLink(event)"/>
             </hbox>
           </groupbox>
 #endif
         </tabpanel>
--- a/browser/components/preferences/in-content/advanced.js
+++ b/browser/components/preferences/in-content/advanced.js
@@ -258,16 +258,34 @@ var gAdvancedPane = {
    */
   initTelemetry: function ()
   {
 #ifdef MOZ_TELEMETRY_REPORTING
     this._setupLearnMoreLink("toolkit.telemetry.infoURL", "telemetryLearnMore");
 #endif
   },
 
+  /**
+   * Set the status of the telemetry controls based on the input argument.
+   * @param {Boolean} aEnabled False disables the controls, true enables them.
+   */
+  setTelemetrySectionEnabled: function (aEnabled)
+  {
+#ifdef MOZ_TELEMETRY_REPORTING
+    // If FHR is disabled, additional data sharing should be disabled as well.
+    let disabled = !aEnabled;
+    document.getElementById("submitTelemetryBox").disabled = disabled;
+    if (disabled) {
+      // If we disable FHR, untick the telemetry checkbox.
+      document.getElementById("submitTelemetryBox").checked = false;
+    }
+    document.getElementById("telemetryDataDesc").disabled = disabled;
+#endif
+  },
+
 #ifdef MOZ_SERVICES_HEALTHREPORT
   /**
    * Initialize the health report service reference and checkbox.
    */
   initSubmitHealthReport: function () {
     this._setupLearnMoreLink("datareporting.healthreport.infoURL", "FHRLearnMore");
 
     let policy = Components.classes["@mozilla.org/datareporting/service;1"]
@@ -278,16 +296,17 @@ var gAdvancedPane = {
     let checkbox = document.getElementById("submitHealthReportBox");
 
     if (!policy || policy.healthReportUploadLocked) {
       checkbox.setAttribute("disabled", "true");
       return;
     }
 
     checkbox.checked = policy.healthReportUploadEnabled;
+    this.setTelemetrySectionEnabled(checkbox.checked);
   },
 
   /**
    * Update the health report policy acceptance with state from checkbox.
    */
   updateSubmitHealthReport: function () {
     let policy = Components.classes["@mozilla.org/datareporting/service;1"]
                                    .getService(Components.interfaces.nsISupports)
@@ -296,16 +315,17 @@ var gAdvancedPane = {
 
     if (!policy) {
       return;
     }
 
     let checkbox = document.getElementById("submitHealthReportBox");
     policy.recordHealthReportUploadEnabled(checkbox.checked,
                                            "Checkbox from preferences pane");
+    this.setTelemetrySectionEnabled(checkbox.checked);
   },
 #endif
 
   // NETWORK TAB
 
   /*
    * Preferences:
    *
--- a/browser/components/preferences/in-content/advanced.xul
+++ b/browser/components/preferences/in-content/advanced.xul
@@ -187,55 +187,58 @@
                   onsyncfrompreference="return gAdvancedPane.readCheckSpelling();"
                   onsynctopreference="return gAdvancedPane.writeCheckSpelling();"
                   preference="layout.spellcheckDefault"/>
       </groupbox>
     </tabpanel>
 #ifdef MOZ_DATA_REPORTING
     <!-- Data Choices -->
     <tabpanel id="dataChoicesPanel" orient="vertical">
-#ifdef MOZ_TELEMETRY_REPORTING
-      <groupbox>
-        <caption><label>&telemetrySection.label;</label></caption>
-        <description>&telemetryDesc.label;</description>
-        <hbox>
-          <checkbox id="submitTelemetryBox"
-                    preference="toolkit.telemetry.enabled"
-                    label="&enableTelemetry.label;"
-                    accesskey="&enableTelemetry.accesskey;"/>
-          <spacer flex="1"/>
-          <label id="telemetryLearnMore"
-                 class="text-link">&telemetryLearnMore.label;</label>
-        </hbox>
-      </groupbox>
-#endif
 #ifdef MOZ_SERVICES_HEALTHREPORT
       <groupbox>
-        <caption><label>&healthReportSection.label;</label></caption>
-        <description>&healthReportDesc.label;</description>
-        <hbox>
-          <checkbox id="submitHealthReportBox"
-                    label="&enableHealthReport.label;"
+        <caption>
+          <checkbox id="submitHealthReportBox" label="&enableHealthReport.label;"
                     accesskey="&enableHealthReport.accesskey;"/>
-          <spacer flex="1"/>
-          <label id="FHRLearnMore"
-                 class="text-link">&healthReportLearnMore.label;</label>
-        </hbox>
+        </caption>
+        <vbox>
+          <hbox class="indent">
+            <label flex="1">&healthReportDesc.label;</label>
+            <spacer flex="10"/>
+            <label id="FHRLearnMore"
+                   class="text-link">&healthReportLearnMore.label;</label>
+          </hbox>
+#ifdef MOZ_TELEMETRY_REPORTING
+          <hbox class="indent">
+            <groupbox flex="1">
+              <caption>
+                <checkbox id="submitTelemetryBox" preference="toolkit.telemetry.enabled"
+                          label="&enableTelemetryData.label;"
+                          accesskey="&enableTelemetryData.accesskey;"/>
+              </caption>
+              <hbox class="indent">
+                <label id="telemetryDataDesc" flex="1">&telemetryDesc.label;</label>
+                <spacer flex="10"/>
+                <label id="telemetryLearnMore"
+                       class="text-link">&telemetryLearnMore.label;</label>
+              </hbox>
+            </groupbox>
+          </hbox>
+#endif
+        </vbox>
       </groupbox>
 #endif
 #ifdef MOZ_CRASHREPORTER
       <groupbox>
-        <caption><label>&crashReporterSection.label;</label></caption>
-        <description>&crashReporterDesc.label;</description>
-        <hbox>
-          <checkbox id="submitCrashesBox"
-                    label="&enableCrashReporter.label;"
+        <caption>
+          <checkbox id="submitCrashesBox" label="&enableCrashReporter.label;"
                     accesskey="&enableCrashReporter.accesskey;"/>
-
-          <spacer flex="1"/>
+        </caption>
+        <hbox class="indent">
+          <label flex="1">&crashReporterDesc.label;</label>
+          <spacer flex="10"/>
           <label id="crashReporterLearnMore"
                  class="text-link">&crashReporterLearnMore.label;</label>
         </hbox>
       </groupbox>
 #endif
     </tabpanel>
 #endif
 
--- a/browser/components/preferences/in-content/tests/browser.ini
+++ b/browser/components/preferences/in-content/tests/browser.ini
@@ -21,8 +21,11 @@ skip-if = !healthreport || (os == 'linux
 [browser_privacypane_3.js]
 [browser_privacypane_4.js]
 [browser_privacypane_5.js]
 [browser_privacypane_8.js]
 skip-if = e10s # Bug ?????? -  "leaked until shutdown [nsGlobalWindow #99 about:preferences]"
 [browser_subdialogs.js]
 skip-if = e10s # Bug 1087114
 support-files = subdialog.xul
+[browser_telemetry.js]
+# Skip this test on Android and B2G as FHR and Telemetry are separate systems there.
+skip-if = !healthreport || !telemetry || (os == 'linux' && debug) || (os == 'android') || (os == 'b2g')
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/in-content/tests/browser_telemetry.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+function runPaneTest(fn) {
+  open_preferences((win) => {
+    let doc = win.document;
+    win.gotoPref("paneAdvanced");
+    let advancedPrefs = doc.getElementById("advancedPrefs");
+    let tab = doc.getElementById("dataChoicesTab");
+    advancedPrefs.selectedTab = tab;
+    fn(win, doc);
+  });
+}
+
+function test() {
+  waitForExplicitFinish();
+  resetPreferences();
+  registerCleanupFunction(resetPreferences);
+  runPaneTest(testTelemetryState);
+}
+
+function testTelemetryState(win, doc) {
+  let fhrCheckbox = doc.getElementById("submitHealthReportBox");
+  Assert.ok(fhrCheckbox.checked, "Health Report checkbox is checked on app first run.");
+
+  let telmetryCheckbox = doc.getElementById("submitTelemetryBox");
+  Assert.ok(!telmetryCheckbox.disabled,
+            "Telemetry checkbox must be enabled if FHR is checked.");
+
+  // Uncheck the FHR checkbox and make sure that Telemetry checkbox gets disabled.
+  fhrCheckbox.click();
+
+  Assert.ok(telmetryCheckbox.disabled,
+            "Telemetry checkbox must be disabled if FHR is unchecked.");
+
+  win.close();
+  finish();
+}
+
+function resetPreferences() {
+  Services.prefs.clearUserPref("datareporting.healthreport.uploadEnabled");
+}
+
--- a/browser/components/preferences/tests/browser.ini
+++ b/browser/components/preferences/tests/browser.ini
@@ -15,8 +15,11 @@ skip-if = e10s # Bug 941459 - pushPrefEn
 skip-if = !healthreport || (os == 'linux' && debug)
 [browser_permissions.js]
 [browser_privacypane_1.js]
 [browser_privacypane_3.js]
 [browser_privacypane_4.js]
 skip-if = e10s # leaks windows
 [browser_privacypane_5.js]
 [browser_privacypane_8.js]
+[browser_telemetry.js]
+# Skip this test on Android and B2G as FHR and Telemetry are separate systems there.
+skip-if = !healthreport || !telemetry || (os == 'linux' && debug) || (os == 'android') || (os == 'b2g')
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/components/preferences/tests/browser_telemetry.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+function runPaneTest(fn) {
+  function observer(win, topic, data) {
+    Services.obs.removeObserver(observer, "advanced-pane-loaded");
+
+    let policy = Components.classes["@mozilla.org/datareporting/service;1"]
+                                   .getService(Components.interfaces.nsISupports)
+                                   .wrappedJSObject
+                                   .policy;
+    Assert.ok(policy, "Policy object defined.");
+
+    resetPreferences();
+
+    fn(win);
+  }
+
+  Services.obs.addObserver(observer, "advanced-pane-loaded", false);
+  openDialog("chrome://browser/content/preferences/preferences.xul", "Preferences",
+             "chrome,titlebar,toolbar,centerscreen,dialog=no", "paneAdvanced");
+}
+
+function test() {
+  waitForExplicitFinish();
+  resetPreferences();
+  registerCleanupFunction(resetPreferences);
+
+  runPaneTest(testTelemetryState);
+}
+
+function testTelemetryState(win) {
+  let doc = win.document;
+
+  let fhrCheckbox = doc.getElementById("submitHealthReportBox");
+  Assert.ok(fhrCheckbox.checked, "Health Report checkbox is checked on app first run.");
+
+  let telmetryCheckbox = doc.getElementById("submitTelemetryBox");
+  Assert.ok(!telmetryCheckbox.disabled,
+            "Telemetry checkbox must be enabled if FHR is checked.");
+
+  // Uncheck the FHR checkbox and make sure that Telemetry checkbox gets disabled.
+  fhrCheckbox.click();
+
+  Assert.ok(telmetryCheckbox.disabled,
+            "Telemetry checkbox must be disabled if FHR is unchecked.");
+
+  win.close();
+  finish();
+}
+
+function resetPreferences() {
+  let service = Cc["@mozilla.org/datareporting/service;1"]
+                  .getService(Ci.nsISupports)
+                  .wrappedJSObject;
+  service.policy._prefs.resetBranch("datareporting.policy.");
+  service.policy.dataSubmissionPolicyBypassNotification = true;
+}
+
--- a/browser/components/uitour/UITour.jsm
+++ b/browser/components/uitour/UITour.jsm
@@ -671,42 +671,32 @@ this.UITour = {
       }
     }
 
     if (!this.tourBrowsersByWindow.has(window)) {
       this.tourBrowsersByWindow.set(window, new Set());
     }
     this.tourBrowsersByWindow.get(window).add(browser);
 
-    // We don't have a tab if we're in a <browser> without a tab.
-    if (tab) {
-      tab.addEventListener("TabClose", this);
-    }
+    Services.obs.addObserver(this, "message-manager-disconnect", false);
 
     window.addEventListener("SSWindowClosing", this);
 
     return true;
   },
 
   handleEvent: function(aEvent) {
     log.debug("handleEvent: type =", aEvent.type, "event =", aEvent);
     switch (aEvent.type) {
       case "pagehide": {
         let window = this.getChromeWindow(aEvent.target);
         this.teardownTourForWindow(window);
         break;
       }
 
-      case "TabClose": {
-        let tab = aEvent.target;
-        let window = tab.ownerDocument.defaultView;
-        this.teardownTourForBrowser(window, tab.linkedBrowser, true);
-        break;
-      }
-
       case "TabSelect": {
         let window = aEvent.target.ownerDocument.defaultView;
 
         // Teardown the browser of the tab we just switched away from.
         if (aEvent.detail && aEvent.detail.previousTab) {
           let previousTab = aEvent.detail.previousTab;
           let openTourWindows = this.tourBrowsersByWindow.get(window);
           if (openTourWindows.has(previousTab.linkedBrowser)) {
@@ -728,16 +718,47 @@ this.UITour = {
           let window = aEvent.target.ownerDocument.defaultView;
           this.handleUrlbarInput(window);
         }
         break;
       }
     }
   },
 
+  observe: function(aSubject, aTopic, aData) {
+    log.debug("observe: aTopic =", aTopic);
+    switch (aTopic) {
+      // The browser message manager is disconnected when the <browser> is
+      // destroyed and we want to teardown at that point.
+      case "message-manager-disconnect": {
+        let winEnum = Services.wm.getEnumerator("navigator:browser");
+        while (winEnum.hasMoreElements()) {
+          let window = winEnum.getNext();
+          if (window.closed)
+            continue;
+
+          let tourBrowsers = this.tourBrowsersByWindow.get(window);
+          if (!tourBrowsers)
+            continue;
+
+          for (let browser of tourBrowsers) {
+            let messageManager = browser.messageManager;
+            if (aSubject != messageManager) {
+              continue;
+            }
+
+            this.teardownTourForBrowser(window, browser, true);
+            return;
+          }
+        }
+        break;
+      }
+    }
+  },
+
   setTelemetryBucket: function(aPageID) {
     let bucket = BUCKET_NAME + BrowserUITelemetry.BUCKET_SEPARATOR + aPageID;
     BrowserUITelemetry.setBucket(bucket);
   },
 
   setExpiringTelemetryBucket: function(aPageID, aType) {
     let bucket = BUCKET_NAME + BrowserUITelemetry.BUCKET_SEPARATOR + aPageID +
                  BrowserUITelemetry.BUCKET_SEPARATOR + aType;
@@ -761,24 +782,18 @@ this.UITour = {
     log.debug("teardownTourForBrowser: aBrowser = ", aBrowser, aTourPageClosing);
 
     if (this.pageIDSourceBrowsers.has(aBrowser)) {
       let pageID = this.pageIDSourceBrowsers.get(aBrowser);
       this.setExpiringTelemetryBucket(pageID, aTourPageClosing ? "closed" : "inactive");
     }
 
     let openTourBrowsers = this.tourBrowsersByWindow.get(aWindow);
-    if (aTourPageClosing) {
-      let tab = aWindow.gBrowser.getTabForBrowser(aBrowser);
-      if (tab) { // Handle standalone <browser>
-        tab.removeEventListener("TabClose", this);
-        if (openTourBrowsers) {
-          openTourBrowsers.delete(aBrowser);
-        }
-      }
+    if (aTourPageClosing && openTourBrowsers) {
+      openTourBrowsers.delete(aBrowser);
     }
 
     this.hideHighlight(aWindow);
     this.hideInfo(aWindow);
     // Ensure the menu panel is hidden before calling recreatePopup so popup events occur.
     this.hideMenu(aWindow, "appMenu");
     this.hideMenu(aWindow, "loop");
 
@@ -809,19 +824,16 @@ this.UITour = {
 
     let openTourBrowsers = this.tourBrowsersByWindow.get(aWindow);
     if (openTourBrowsers) {
       for (let browser of openTourBrowsers) {
         if (this.pageIDSourceBrowsers.has(browser)) {
           let pageID = this.pageIDSourceBrowsers.get(browser);
           this.setExpiringTelemetryBucket(pageID, "closed");
         }
-
-        let tab = aWindow.gBrowser.getTabForBrowser(browser);
-        tab.removeEventListener("TabClose", this);
       }
     }
 
     this.tourBrowsersByWindow.delete(aWindow);
   },
 
   getChromeWindow: function(aContentDocument) {
     return aContentDocument.defaultView
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -835,8 +835,13 @@ just addresses the organization to follo
 <!ENTITY processHang.debugScript.accessKey        "D">
 <!ENTITY processHang.terminatePlugin.label        "Kill Plugin">
 <!ENTITY processHang.terminatePlugin.accessKey    "P">
 <!ENTITY processHang.terminateProcess.label       "Kill Web Process">
 <!ENTITY processHang.terminateProcess.accessKey   "K">
 
 <!ENTITY emeLearnMoreContextMenu.label            "Learn more about DRM…">
 <!ENTITY emeLearnMoreContextMenu.accesskey        "D">
+
+<!ENTITY emeNotificationsNotNow.label             "Not now">
+<!ENTITY emeNotificationsNotNow.accesskey         "N">
+<!ENTITY emeNotificationsDontAskAgain.label       "Don't ask me again">
+<!ENTITY emeNotificationsDontAskAgain.accesskey   "D">
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -591,16 +591,39 @@ getUserMedia.sharingMenuMicrophoneWindow
 # origin for the sharing menu if no readable origin could be deduced from the URL.
 getUserMedia.sharingMenuUnknownHost = Unknown origin
 
 # LOCALIZATION NOTE(emeNotifications.drmContentPlaying.message): %1$S is the vendor name of the DRM that's in use, %2$S is brandShortName.
 emeNotifications.drmContentPlaying.message = Some audio or video on this site uses %1$S DRM software, which may limit what %2$S can let you do with it.
 emeNotifications.drmContentPlaying.button.label = Configure…
 emeNotifications.drmContentPlaying.button.accesskey = C
 
+# LOCALIZATION NOTE(emeNotifications.drmContentDisabled.message): NB: inserted via innerHTML, so please don't use <, > or & in this string. %S will be the 'learn more' link
+emeNotifications.drmContentDisabled.message = You must enable DRM to play some audio or video on this page. %S
+emeNotifications.drmContentDisabled.button.label = Enable DRM
+emeNotifications.drmContentDisabled.button.accesskey = E
+# LOCALIZATION NOTE(emeNotifications.drmContentDisabled.learnMoreLabel): NB: inserted via innerHTML, so please don't use <, > or & in this string.
+emeNotifications.drmContentDisabled.learnMoreLabel = Learn More
+
+# LOCALIZATION NOTE(emeNotifications.drmContentCDMNotSupported.message): NB: inserted via innerHTML, so please don't use <, > or & in this string. %1$S is brandShortName, %2$S will be the 'learn more' link
+emeNotifications.drmContentCDMNotSupported.message = The audio or video on this page requires DRM software that %1$S does not support. %2$S
+# LOCALIZATION NOTE(emeNotifications.drmContentCDMNotSupported.learnMoreLabel): NB: inserted via innerHTML, so please don't use <, > or & in this string.
+emeNotifications.drmContentCDMNotSupported.learnMoreLabel = Learn More
+
+# LOCALIZATION NOTE(emeNotifications.drmContentCDMInsufficientVersion.message): NB: inserted via innerHTML, so please don't use <, > or & in this string. %S is brandShortName
+emeNotifications.drmContentCDMInsufficientVersion.message = %S is installing updates needed to play the audio or video on this page. Please try again later.
+
+# LOCALIZATION NOTE(emeNotifications.drmContentCDMInstalling.message): NB: inserted via innerHTML, so please don't use <, > or & in this string. %S is brandShortName
+emeNotifications.drmContentCDMInstalling.message = %S is installing components needed to play the audio or video on this page. Please try again later.
+
+emeNotifications.optionsButton.label = Options
+emeNotifications.optionsButton.accesskey = O
+
+emeNotifications.unknownDRMSoftware = Unknown
+
 # LOCALIZATION NOTE - %S is brandShortName
 slowStartup.message = %S seems slow… to… start.
 slowStartup.helpButton.label = Learn How to Speed It Up
 slowStartup.helpButton.accesskey = L
 slowStartup.disableNotificationButton.label = Don't Tell Me Again
 slowStartup.disableNotificationButton.accesskey = A
 
 
--- a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
@@ -23,29 +23,26 @@
 <!ENTITY useSmoothScrolling.accesskey    "m">
 <!ENTITY allowHWAccel.label              "Use hardware acceleration when available">
 <!ENTITY allowHWAccel.accesskey          "r">
 <!ENTITY checkSpelling.label             "Check my spelling as I type">
 <!ENTITY checkSpelling.accesskey         "t">
 
 <!ENTITY dataChoicesTab.label            "Data Choices">
 
-<!ENTITY healthReportSection.label       "&brandShortName; Health Report">
 <!ENTITY healthReportDesc.label          "Helps you understand your browser performance and shares data with &vendorShortName; about your browser health">
 <!ENTITY enableHealthReport.label        "Enable &brandShortName; Health Report">
 <!ENTITY enableHealthReport.accesskey    "R">
 <!ENTITY healthReportLearnMore.label     "Learn More">
 
-<!ENTITY telemetrySection.label          "Telemetry">
 <!ENTITY telemetryDesc.label             "Shares performance, usage, hardware and customization data about your browser with &vendorShortName; to help us make &brandShortName; better">
-<!ENTITY enableTelemetry.label           "Enable Telemetry">
-<!ENTITY enableTelemetry.accesskey       "T">
+<!ENTITY enableTelemetryData.label       "Share additional data (i.e., Telemetry)">
+<!ENTITY enableTelemetryData.accesskey   "T">
 <!ENTITY telemetryLearnMore.label        "Learn More">
 
-<!ENTITY crashReporterSection.label      "Crash Reporter">
 <!ENTITY crashReporterDesc.label         "&brandShortName; submits crash reports to help &vendorShortName; make your browser more stable and secure">
 <!ENTITY enableCrashReporter.label       "Enable Crash Reporter">
 <!ENTITY enableCrashReporter.accesskey   "C">
 <!ENTITY crashReporterLearnMore.label    "Learn More">
 
 <!ENTITY networkTab.label                "Network">
 
 <!ENTITY connection.label                "Connection">
--- a/browser/locales/en-US/chrome/browser/readerMode.properties
+++ b/browser/locales/en-US/chrome/browser/readerMode.properties
@@ -1,6 +1,6 @@
 # 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/.
 
-readerMode.enter=Enter Reader Mode
-readerMode.exit=Exit Reader Mode
+readerView.enter=Enter Reader View
+readerView.exit=Exit Reader View
--- a/browser/modules/ContentObservers.jsm
+++ b/browser/modules/ContentObservers.jsm
@@ -15,33 +15,29 @@
 
 this.EXPORTED_SYMBOLS = [];
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 let gEMEUIObserver = function(subject, topic, data) {
-  let win = subject.ownerDocument.defaultView.top;
+  let win = subject.top;
   let mm = getMessageManagerForWindow(win);
   if (mm) {
-    mm.sendAsyncMessage("EMEVideo:MetadataLoaded", {
-      // bug 1129370 covers making this the actual DRM provider inferred from
-      // either |subject| or |data| here.
-      drmProvider: "Adobe"
-    });
+    mm.sendAsyncMessage("EMEVideo:ContentMediaKeysRequest", data);
   }
 };
 
 function getMessageManagerForWindow(aContentWindow) {
   let ir = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIDocShell)
                          .sameTypeRootTreeItem
                          .QueryInterface(Ci.nsIInterfaceRequestor);
   try {
     // If e10s is disabled, this throws NS_NOINTERFACE for closed tabs.
     return ir.getInterface(Ci.nsIContentFrameMessageManager);
   } catch(e if e.result == Cr.NS_NOINTERFACE) {
     return null;
   }
 }
 
-Services.obs.addObserver(gEMEUIObserver, "media-eme-metadataloaded", false);
+Services.obs.addObserver(gEMEUIObserver, "mediakeys-request", false);
--- a/browser/modules/E10SUtils.jsm
+++ b/browser/modules/E10SUtils.jsm
@@ -25,16 +25,20 @@ function getAboutModule(aURL) {
 }
 
 this.E10SUtils = {
   canLoadURIInProcess: function(aURL, aProcess) {
     // loadURI in browser.xml treats null as about:blank
     if (!aURL)
       aURL = "about:blank";
 
+    // Javascript urls can load in any process, they apply to the current document
+    if (aURL.startsWith("javascript:"))
+      return true;
+
     let processIsRemote = aProcess == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT;
 
     let canLoadRemote = true;
     let mustLoadRemote = true;
 
     if (aURL.startsWith("about:")) {
       let url = Services.io.newURI(aURL, null, null);
       let module = getAboutModule(url);
--- a/browser/modules/ReaderParent.jsm
+++ b/browser/modules/ReaderParent.jsm
@@ -88,20 +88,20 @@ let ReaderParent = {
     if (browser != win.gBrowser.selectedBrowser) {
       return;
     }
 
     let button = win.document.getElementById("reader-mode-button");
     if (browser.currentURI.spec.startsWith("about:reader")) {
       button.setAttribute("readeractive", true);
       button.hidden = false;
-      button.setAttribute("tooltiptext", gStringBundle.GetStringFromName("readerMode.exit"));
+      button.setAttribute("tooltiptext", gStringBundle.GetStringFromName("readerView.exit"));
     } else {
       button.removeAttribute("readeractive");
-      button.setAttribute("tooltiptext", gStringBundle.GetStringFromName("readerMode.enter"));
+      button.setAttribute("tooltiptext", gStringBundle.GetStringFromName("readerView.enter"));
       button.hidden = !browser.isArticle;
     }
   },
 
   handleReaderButtonEvent: function(event) {
     event.stopPropagation();
 
     if ((event.type == "click" && event.button != 0) ||
--- a/browser/themes/shared/drm-icon.svg
+++ b/browser/themes/shared/drm-icon.svg
@@ -3,16 +3,19 @@
      viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
   <style>
     #chains > use > path {
       fill: url(#baseGradient);
     }
     #chains-pressed > use > path {
       fill: url(#pressedGradient);
     }
+    #chains-black > use > path {
+      fill: black;
+    }
 
     g:not(:target) {
       display: none;
     }
   </style>
   <defs>
     <linearGradient id="baseGradient" gradientUnits="userSpaceOnUse" x1="8" x2="8" y1="16" y2="0">
       <stop offset="0" style="stop-color:#808080"/>
@@ -39,9 +42,14 @@
     <use xlink:href="#path2"/>
     <use xlink:href="#path3"/>
   </g>
   <g id="chains-pressed">
     <use xlink:href="#path1"/>
     <use xlink:href="#path2"/>
     <use xlink:href="#path3"/>
   </g>
+  <g id="chains-black">
+    <use xlink:href="#path1"/>
+    <use xlink:href="#path2"/>
+    <use xlink:href="#path3"/>
+  </g>
 </svg>
--- a/chrome/nsChromeProtocolHandler.cpp
+++ b/chrome/nsChromeProtocolHandler.cpp
@@ -142,30 +142,19 @@ nsChromeProtocolHandler::NewChannel2(nsI
 #ifdef DEBUG
         nsAutoCString spec;
         aURI->GetSpec(spec);
         printf("Couldn't convert chrome URL: %s\n", spec.get());
 #endif
         return rv;
     }
 
-    // Bug 1087720 (and Bug 1099296):
-    // Once all callsites have been updated to call NewChannel2() instead of NewChannel()
-    // we should have a non-null loadInfo consistently. Until then we have to branch on the
-    // loadInfo.
-    if (aLoadInfo) {
-        rv = NS_NewChannelInternal(getter_AddRefs(result),
-                                   resolvedURI,
-                                   aLoadInfo);
-    }
-    else {
-        nsCOMPtr<nsIIOService> ioServ(do_GetIOService(&rv));
-        NS_ENSURE_SUCCESS(rv, rv);
-        rv = ioServ->NewChannelFromURI(resolvedURI, getter_AddRefs(result));
-    }
+    rv = NS_NewChannelInternal(getter_AddRefs(result),
+                               resolvedURI,
+                               aLoadInfo);
     NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
     nsCOMPtr<nsIFileChannel> fileChan(do_QueryInterface(result));
     if (fileChan) {
         nsCOMPtr<nsIFile> file;
         fileChan->GetFile(getter_AddRefs(file));
 
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -126,27 +126,19 @@ nsAboutRedirector::NewChannel(nsIURI* aU
   NS_ENSURE_SUCCESS(rv, rv);
 
   for (int i = 0; i < kRedirTotal; i++) {
     if (!strcmp(path.get(), kRedirMap[i].id)) {
       nsCOMPtr<nsIChannel> tempChannel;
       nsCOMPtr<nsIURI> tempURI;
       rv = NS_NewURI(getter_AddRefs(tempURI), kRedirMap[i].url);
       NS_ENSURE_SUCCESS(rv, rv);
-      // Bug 1087720 (and Bug 1099296):
-      // Once all callsites have been updated to call NewChannel2()
-      // instead of NewChannel() we should have a non-null loadInfo
-      // consistently. Until then we have to branch on the loadInfo.
-      if (aLoadInfo) {
-        rv = NS_NewChannelInternal(getter_AddRefs(tempChannel),
-                                   tempURI,
-                                   aLoadInfo);
-      } else {
-        rv = ioService->NewChannelFromURI(tempURI, getter_AddRefs(tempChannel));
-      }
+      rv = NS_NewChannelInternal(getter_AddRefs(tempChannel),
+                                 tempURI,
+                                 aLoadInfo);
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       tempChannel->SetOriginalURI(aURI);
 
       NS_ADDREF(*aResult = tempChannel);
       return rv;
--- a/dom/apps/Langpacks.jsm
+++ b/dom/apps/Langpacks.jsm
@@ -27,17 +27,17 @@ let debug = Services.prefs.getBoolPref("
 /**
   * Langpack support
   *
   * Manifest format is:
   *
   * "languages-target" : { "app://*.gaiamobile.org/manifest.webapp": "2.2" },
   * "languages-provided": {
   * "de": {
-  *   "version": 201411051234,
+  *   "revision": 201411051234,
   *   "name": "Deutsch",
   *   "apps": {
   *     "app://calendar.gaiamobile.org/manifest.webapp": "/de/calendar",
   *     "app://email.gaiamobile.org/manifest.webapp": "/de/email"
   *    }
   *  },
   *  "role" : "langpack"
   */
@@ -76,17 +76,17 @@ this.Langpacks = {
     if (this._data[aManifestURL]) {
       res.appId = this._data[aManifestURL].appId;
       for (let lang in this._data[aManifestURL].langs) {
         if (!langs[lang]) {
           langs[lang] = [];
         }
         let current = this._data[aManifestURL].langs[lang];
         langs[lang].push({
-          version: current.version,
+          revision: current.revision,
           name: current.name,
           target: current.target
         });
       }
     }
     debug("Languages found: " + uneval(res));
     return res;
   },
@@ -123,17 +123,17 @@ this.Langpacks = {
     }
 
     // We have langpack(s) for this app, but not for this language.
     if (!this._data[aData.manifestURL].langs[aData.lang]) {
       return sendError("No language " + aData.lang + " for this app.",
                        "UnavailableLanguage");
     }
 
-    // Check that we have the right version.
+    // Check that we have the langpack for the right app version.
     let item = this._data[aData.manifestURL].langs[aData.lang];
     if (item.target != aData.version) {
       return sendError("No version " + aData.version + " for this app.",
                        "UnavailableVersion");
     }
 
     // The path can't be an absolute uri.
     if (isAbsoluteURI(aData.path)) {
@@ -182,24 +182,24 @@ this.Langpacks = {
     if (!("languages-provided" in aManifest)) {
       debug("Error: no 'languages-provided' property.")
       return false;
     }
 
     for (let lang in aManifest["languages-provided"]) {
       let item = aManifest["languages-provided"][lang];
 
-      if (!item.version) {
-        debug("Error: missing 'version' in languages-provided." + lang);
+      if (!item.revision) {
+        debug("Error: missing 'revision' in languages-provided." + lang);
         return false;
       }
 
-      if (typeof item.version !== "number") {
+      if (typeof item.revision !== "number") {
         debug("Error: languages-provided." + lang +
-              ".version must be a number but is a " + (typeof item.version));
+              ".revision must be a number but is a " + (typeof item.revision));
         return false;
       }
 
       if (!item.apps) {
         debug("Error: missing 'apps' in languages-provided." + lang);
         return false;
       }
 
@@ -237,31 +237,31 @@ this.Langpacks = {
     }
 
     let platformVersion = aManifest["languages-target"]
                                    ["app://*.gaiamobile.org/manifest.webapp"];
     let origin = Services.io.newURI(aApp.origin, null, null);
 
     for (let lang in aManifest["languages-provided"]) {
       let item = aManifest["languages-provided"][lang];
-      let version = item.version;   // The langpack version, not the platform.
+      let revision = item.revision;
       let name = item.name || lang; // If no name specified, default to lang.
       for (let app in item.apps) {
         let sendEvent = false;
         if (!this._data[app] ||
             !this._data[app].langs[lang] ||
-            this._data[app].langs[lang].version > version) {
+            this._data[app].langs[lang].revision > revision) {
           if (!this._data[app]) {
             this._data[app] = {
               appId: this._appIdFromManifestURL(app),
               langs: {}
             };
           }
           this._data[app].langs[lang] = {
-            version: version,
+            revision: revision,
             target: platformVersion,
             name: name,
             url: origin.resolve(item.apps[app]),
             from: aApp.manifestURL
           }
           sendEvent = true;
           debug("Registered " + app + " -> " + uneval(this._data[app].langs[lang]));
         }
--- a/dom/apps/tests/langpack/lang1.webapp
+++ b/dom/apps/tests/langpack/lang1.webapp
@@ -1,14 +1,14 @@
 {
   "name": "French locale",
   "languages-target" : { "app://*.gaiamobile.org/manifest.webapp": "2.2" },
   "languages-provided": {
     "fr": {
-      "version": 201411051234,
+      "revision": 201411051234,
       "name": "Français",
       "apps": {
         "http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/fr/"
        }
      }
    },
    "role" : "langpack"
 }
--- a/dom/apps/tests/langpack/lang2.webapp
+++ b/dom/apps/tests/langpack/lang2.webapp
@@ -1,21 +1,21 @@
 {
   "name": "German an Polish locales",
   "languages-target" : { "app://*.gaiamobile.org/manifest.webapp": "2.2" },
   "languages-provided": {
     "de": {
-      "version": 201411051234,
+      "revision": 201411051234,
       "name": "Deutsch",
       "apps": {
         "http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/de/"
        }
      },
      "pl": {
-      "version": 201411051234,
+      "revision": 201411051234,
       "name": "Polski",
       "apps": {
         "http://mochi.test:8888/tests/dom/apps/tests/langpack/manifest.webapp": "tests/dom/apps/tests/langpack/pl/"
        }
      }
    },
    "role" : "langpack"
 }
--- a/dom/apps/tests/test_langpacks.html
+++ b/dom/apps/tests/test_langpacks.html
@@ -128,43 +128,43 @@ function runTest() {
 
   // Install the fr langpack.
   installApp(lang1ManifestURL);
   yield undefined;
 
   // Opens the iframe to the test page.
   // Only the French locale is available.
   openPage("index.html",
-    [_({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}]})]);
+    [_({"fr":[{"revision":201411051234,"name":"Français","target":"2.2"}]})]);
   yield undefined;
 
   // Install the de and pl langpack.
   installApp(lang2ManifestURL);
   yield undefined;
 
   // Opens the iframe to the test page.
   // French, German and Polish locales are available.
   openPage("index.html",
-    [_({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}],"de":[{"version":201411051234,"name":"Deutsch","target":"2.2"}],"pl":[{"version":201411051234,"name":"Polski","target":"2.2"}]})]);
+    [_({"fr":[{"revision":201411051234,"name":"Français","target":"2.2"}],"de":[{"revision":201411051234,"name":"Deutsch","target":"2.2"}],"pl":[{"revision":201411051234,"name":"Polski","target":"2.2"}]})]);
   yield undefined;
 
   // Uninstall the second langpack.
   {
     let app = apps.pop();
     info("Uninstalling " + app.manifestURL);
     req = navigator.mozApps.mgmt.uninstall(app);
     req.onsuccess = continueTest;
     req.onerror = mozAppsError;
     yield undefined;
   }
 
   // Opens the iframe to the test page.
   // Only the French locale is available.
   openPage("index.html",
-    [_({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}]})]);
+    [_({"fr":[{"revision":201411051234,"name":"Français","target":"2.2"}]})]);
   yield undefined;
 
   // Uninstall the first langpack.
   {
     let app = apps.pop();
     info("Uninstalling " + app.manifestURL);
     req = navigator.mozApps.mgmt.uninstall(app);
     req.onsuccess = continueTest;
@@ -176,19 +176,19 @@ function runTest() {
   // No locale is available.
   openPage("index.html",
     ["{}"]);
   yield undefined;
 
   // Opens the iframe to the event test page.
   // Will get additionallanguageschange events.
   openPage("event.html",
-    [_({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}]}),
-     _({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}],"de":[{"version":201411051234,"name":"Deutsch","target":"2.2"}]}),
-     _({"fr":[{"version":201411051234,"name":"Français","target":"2.2"}],"de":[{"version":201411051234,"name":"Deutsch","target":"2.2"}],"pl":[{"version":201411051234,"name":"Polski","target":"2.2"}]})]);
+    [_({"fr":[{"revision":201411051234,"name":"Français","target":"2.2"}]}),
+     _({"fr":[{"revision":201411051234,"name":"Français","target":"2.2"}],"de":[{"revision":201411051234,"name":"Deutsch","target":"2.2"}]}),
+     _({"fr":[{"revision":201411051234,"name":"Français","target":"2.2"}],"de":[{"revision":201411051234,"name":"Deutsch","target":"2.2"}],"pl":[{"revision":201411051234,"name":"Polski","target":"2.2"}]})]);
   yield undefined;
 
   // Opens the iframe to the resource test page.
   openPage("resources.html",
     ["UnavailableResource",
      "UnavailableLanguage",
      "UnavailableVersion",
      "BadUrl",
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -107,16 +107,20 @@
 
 #if defined(XP_LINUX)
 #include "mozilla/Hal.h"
 #endif
 #include "mozilla/dom/ContentChild.h"
 
 #include "mozilla/dom/FeatureList.h"
 
+#ifdef MOZ_EME
+#include "mozilla/EMEUtils.h"
+#endif
+
 namespace mozilla {
 namespace dom {
 
 static bool sDoNotTrackEnabled = false;
 static bool sVibratorEnabled   = false;
 static uint32_t sMaxVibrateMS  = 0;
 static uint32_t sMaxVibrateListLen = 0;
 
@@ -2632,33 +2636,46 @@ Navigator::RequestMediaKeySystemAccess(c
   }
 
   if (aKeySystem.IsEmpty() ||
       (aOptions.WasPassed() && aOptions.Value().IsEmpty())) {
     p->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return p.forget();
   }
 
-  MediaKeySystemStatus status = MediaKeySystemAccess::GetKeySystemStatus(aKeySystem);
+  // Parse keysystem, split it out into keySystem prefix, and version suffix.
+  nsAutoString keySystem;
+  int32_t minCdmVersion = NO_CDM_VERSION;
+  if (!ParseKeySystem(aKeySystem,
+                      keySystem,
+                      minCdmVersion)) {
+    // Invalid keySystem string, or unsupported keySystem. Send notification
+    // to chrome to show a failure notice.
+    MediaKeySystemAccess::NotifyObservers(mWindow, aKeySystem, MediaKeySystemStatus::Cdm_not_supported);
+    p->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return p.forget();
+  }
+
+  MediaKeySystemStatus status = MediaKeySystemAccess::GetKeySystemStatus(keySystem, minCdmVersion);
   if (status != MediaKeySystemStatus::Available) {
     if (status != MediaKeySystemStatus::Error) {
       // Failed due to user disabling something, send a notification to
       // chrome, so we can show some UI to explain how the user can rectify
       // the situation.
-      MediaKeySystemAccess::NotifyObservers(mWindow, aKeySystem, status);
+      MediaKeySystemAccess::NotifyObservers(mWindow, keySystem, status);
     }
     p->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return p.forget();
   }
 
   // TODO: Wait (async) until the CDM is downloaded, if it's not already.
 
   if (!aOptions.WasPassed() ||
-      MediaKeySystemAccess::IsSupported(aKeySystem, aOptions.Value())) {
-    nsRefPtr<MediaKeySystemAccess> access(new MediaKeySystemAccess(mWindow, aKeySystem));
+      MediaKeySystemAccess::IsSupported(keySystem, aOptions.Value())) {
+    nsRefPtr<MediaKeySystemAccess> access(new MediaKeySystemAccess(mWindow, keySystem));
     p->MaybeResolve(access);
     return p.forget();
   }
 
   p->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
 
   return p.forget();
 }
new file mode 100644
--- /dev/null
+++ b/dom/base/ProcessGlobal.cpp
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */
+/* vim: set sw=4 ts=8 et 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/. */
+
+#include "ProcessGlobal.h"
+
+#include "nsContentCID.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+ProcessGlobal::ProcessGlobal(nsFrameMessageManager* aMessageManager)
+ : mInitialized(false),
+   mMessageManager(aMessageManager)
+{
+  SetIsNotDOMBinding();
+  mozilla::HoldJSObjects(this);
+}
+
+ProcessGlobal::~ProcessGlobal()
+{
+  mAnonymousGlobalScopes.Clear();
+  mozilla::DropJSObjects(this);
+}
+
+ProcessGlobal*
+ProcessGlobal::Get()
+{
+  nsCOMPtr<nsISyncMessageSender> service = do_GetService(NS_CHILDPROCESSMESSAGEMANAGER_CONTRACTID);
+  if (!service) {
+    return nullptr;
+  }
+  return static_cast<ProcessGlobal*>(service.get());
+}
+
+/* [notxpcom] boolean markForCC (); */
+// This method isn't automatically forwarded safely because it's notxpcom, so
+// the IDL binding doesn't know what value to return.
+NS_IMETHODIMP_(bool)
+ProcessGlobal::MarkForCC()
+{
+  return mMessageManager ? mMessageManager->MarkForCC() : false;
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(ProcessGlobal)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ProcessGlobal)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlobal)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ProcessGlobal)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+  for (uint32_t i = 0; i < tmp->mAnonymousGlobalScopes.Length(); ++i) {
+    NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAnonymousGlobalScopes[i])
+  }
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ProcessGlobal)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlobal)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnonymousGlobalScopes)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ProcessGlobal)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentProcessMessageManager)
+  NS_INTERFACE_MAP_ENTRY(nsIMessageListenerManager)
+  NS_INTERFACE_MAP_ENTRY(nsIMessageSender)
+  NS_INTERFACE_MAP_ENTRY(nsISyncMessageSender)
+  NS_INTERFACE_MAP_ENTRY(nsIContentProcessMessageManager)
+  NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
+  NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ContentProcessMessageManager)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(ProcessGlobal)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(ProcessGlobal)
+
+bool
+ProcessGlobal::Init()
+{
+  if (mInitialized) {
+    return true;
+  }
+  mInitialized = true;
+
+  nsISupports* scopeSupports = NS_ISUPPORTS_CAST(nsIContentProcessMessageManager*, this);
+  return InitChildGlobalInternal(scopeSupports, NS_LITERAL_CSTRING("processChildGlobal"));
+}
+
+void
+ProcessGlobal::LoadScript(const nsAString& aURL)
+{
+  Init();
+  LoadScriptInternal(aURL, false);
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/ProcessGlobal.h
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */
+/* vim: set sw=4 ts=8 et 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/. */
+
+#ifndef mozilla_dom_ProcessGlobal_h
+#define mozilla_dom_ProcessGlobal_h
+
+#include "mozilla/Attributes.h"
+#include "nsCOMPtr.h"
+#include "nsFrameMessageManager.h"
+#include "nsIScriptContext.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "nsIScriptContext.h"
+#include "nsIClassInfo.h"
+#include "nsIRunnable.h"
+#include "nsIGlobalObject.h"
+#include "nsIScriptObjectPrincipal.h"
+#include "nsWeakReference.h"
+
+namespace mozilla {
+namespace dom {
+
+class ProcessGlobal :
+  public nsMessageManagerScriptExecutor,
+  public nsIContentProcessMessageManager,
+  public nsIGlobalObject,
+  public nsIScriptObjectPrincipal,
+  public nsSupportsWeakReference,
+  public mozilla::dom::ipc::MessageManagerCallback,
+  public nsWrapperCache
+{
+public:
+  explicit ProcessGlobal(nsFrameMessageManager* aMessageManager);
+
+  bool Init();
+
+  static ProcessGlobal* Get();
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(ProcessGlobal, nsIContentProcessMessageManager)
+
+  NS_FORWARD_SAFE_NSIMESSAGELISTENERMANAGER(mMessageManager)
+  NS_FORWARD_SAFE_NSIMESSAGESENDER(mMessageManager)
+  NS_FORWARD_SAFE_NSISYNCMESSAGESENDER(mMessageManager)
+  NS_FORWARD_SAFE_NSIMESSAGEMANAGERGLOBAL(mMessageManager)
+
+  virtual void LoadScript(const nsAString& aURL);
+
+  virtual JSObject* GetGlobalJSObject() MOZ_OVERRIDE
+  {
+    if (!mGlobal) {
+      return nullptr;
+    }
+
+    return mGlobal->GetJSObject();
+  }
+  virtual nsIPrincipal* GetPrincipal() MOZ_OVERRIDE { return mPrincipal; }
+
+  virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE
+  {
+    MOZ_CRASH("ProcessGlobal doesn't use DOM bindings!");
+  }
+
+protected:
+  virtual ~ProcessGlobal();
+
+private:
+  bool mInitialized;
+  nsRefPtr<nsFrameMessageManager> mMessageManager;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_ProcessGlobal_h
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -178,16 +178,17 @@ EXPORTS.mozilla.dom += [
     'Navigator.h',
     'NodeInfo.h',
     'NodeInfoInlines.h',
     'NodeIterator.h',
     'PerformanceEntry.h',
     'PerformanceMark.h',
     'PerformanceMeasure.h',
     'PerformanceResourceTiming.h',
+    'ProcessGlobal.h',
     'ResponsiveImageSelector.h',
     'ScreenOrientation.h',
     'ScriptSettings.h',
     'ShadowRoot.h',
     'StructuredCloneTags.h',
     'StyleSheetList.h',
     'SubtleCrypto.h',
     'Text.h',
@@ -313,16 +314,17 @@ UNIFIED_SOURCES += [
     'nsXHTMLContentSerializer.cpp',
     'nsXMLContentSerializer.cpp',
     'nsXMLHttpRequest.cpp',
     'nsXMLNameSpaceMap.cpp',
     'PerformanceEntry.cpp',
     'PerformanceMark.cpp',
     'PerformanceMeasure.cpp',
     'PerformanceResourceTiming.cpp',
+    'ProcessGlobal.cpp',
     'ResponsiveImageSelector.cpp',
     'ScriptSettings.cpp',
     'ShadowRoot.cpp',
     'StyleSheetList.cpp',
     'SubtleCrypto.cpp',
     'Text.cpp',
     'TextInputProcessor.cpp',
     'ThirdPartyUtil.cpp',
--- a/dom/base/nsCCUncollectableMarker.cpp
+++ b/dom/base/nsCCUncollectableMarker.cpp
@@ -164,18 +164,18 @@ MarkMessageManagers()
       nsIMessageListenerManager* child = childMM;
       childMM = nullptr;
       child->MarkForCC();
     }
   }
   if (nsFrameMessageManager::sSameProcessParentManager) {
     nsFrameMessageManager::sSameProcessParentManager->MarkForCC();
   }
-  if (nsFrameMessageManager::sChildProcessManager) {
-    nsFrameMessageManager::sChildProcessManager->MarkForCC();
+  if (nsFrameMessageManager::GetChildProcessManager()) {
+    nsFrameMessageManager::GetChildProcessManager()->MarkForCC();
   }
 }
 
 void
 MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS,
                   bool aPrepareForCC)
 {
   if (!aViewer) {
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -255,16 +255,19 @@ static nsDOMClassInfoData sClassInfoData
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CSSFontFaceRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentFrameMessageManager, nsEventTargetSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS |
                                        nsIXPCScriptable::IS_GLOBAL_OBJECT)
+  NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ContentProcessMessageManager, nsDOMGenericSH,
+                                       DOM_DEFAULT_SCRIPTABLE_FLAGS |
+                                       nsIXPCScriptable::IS_GLOBAL_OBJECT)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageBroadcaster, nsDOMGenericSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_ONLY_CLASSINFO_DATA(ChromeMessageSender, nsDOMGenericSH,
                                        DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
 
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframeRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -669,25 +672,34 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentFrameMessageManager, nsISupports)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
     DOM_CLASSINFO_MAP_ENTRY(nsISyncMessageSender)
     DOM_CLASSINFO_MAP_ENTRY(nsIContentFrameMessageManager)
   DOM_CLASSINFO_MAP_END
 
+  DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ContentProcessMessageManager, nsISupports)
+    DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
+    DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
+    DOM_CLASSINFO_MAP_ENTRY(nsISyncMessageSender)
+    DOM_CLASSINFO_MAP_ENTRY(nsIContentProcessMessageManager)
+  DOM_CLASSINFO_MAP_END
+
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageBroadcaster, nsISupports)
     DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
+    DOM_CLASSINFO_MAP_ENTRY(nsIProcessScriptLoader)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageBroadcaster)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(ChromeMessageSender, nsISupports)
     DOM_CLASSINFO_MAP_ENTRY(nsIProcessChecker)
     DOM_CLASSINFO_MAP_ENTRY(nsIFrameScriptLoader)
+    DOM_CLASSINFO_MAP_ENTRY(nsIProcessScriptLoader)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageListenerManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIMessageSender)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframeRule, nsIDOMMozCSSKeyframeRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframeRule)
   DOM_CLASSINFO_MAP_END
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -35,16 +35,17 @@ DOMCI_CLASS(CSSSupportsRule)
 DOMCI_CLASS(MozSmsMessage)
 DOMCI_CLASS(MozMmsMessage)
 DOMCI_CLASS(MozMobileMessageThread)
 
 // @font-face in CSS
 DOMCI_CLASS(CSSFontFaceRule)
 
 DOMCI_CLASS(ContentFrameMessageManager)
+DOMCI_CLASS(ContentProcessMessageManager)
 DOMCI_CLASS(ChromeMessageBroadcaster)
 DOMCI_CLASS(ChromeMessageSender)
 
 DOMCI_CLASS(MozCSSKeyframeRule)
 DOMCI_CLASS(MozCSSKeyframesRule)
 
 // @counter-style in CSS
 DOMCI_CLASS(CSSCounterStyleRule)
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -2298,17 +2298,17 @@ nsFrameLoader::CreateStaticClone(nsIFram
   nsCOMPtr<nsIDocument> clonedDoc = doc->CreateStaticClone(dest->mDocShell);
   nsCOMPtr<nsIDOMDocument> clonedDOMDoc = do_QueryInterface(clonedDoc);
 
   viewer->SetDOMDocument(clonedDOMDoc);
   return NS_OK;
 }
 
 bool
-nsFrameLoader::DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
+nsFrameLoader::DoLoadMessageManagerScript(const nsAString& aURL, bool aRunInGlobalScope)
 {
   auto* tabParent = TabParent::GetFrom(GetRemoteBrowser());
   if (tabParent) {
     return tabParent->SendLoadRemoteScript(nsString(aURL), aRunInGlobalScope);
   }
   nsRefPtr<nsInProcessTabChildGlobal> tabChild =
     static_cast<nsInProcessTabChildGlobal*>(GetTabChildGlobalAsEventTarget());
   if (tabChild) {
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -81,18 +81,18 @@ public:
   void Finalize();
   nsIDocShell* GetExistingDocShell() { return mDocShell; }
   mozilla::dom::EventTarget* GetTabChildGlobalAsEventTarget();
   nsresult CreateStaticClone(nsIFrameLoader* aDest);
 
   /**
    * MessageManagerCallback methods that we override.
    */
-  virtual bool DoLoadFrameScript(const nsAString& aURL,
-                                 bool aRunInGlobalScope) MOZ_OVERRIDE;
+  virtual bool DoLoadMessageManagerScript(const nsAString& aURL,
+                                          bool aRunInGlobalScope) MOZ_OVERRIDE;
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
                                   const mozilla::dom::StructuredCloneData& aData,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal) MOZ_OVERRIDE;
   virtual bool CheckPermission(const nsAString& aPermission) MOZ_OVERRIDE;
   virtual bool CheckManifestURL(const nsAString& aManifestURL) MOZ_OVERRIDE;
   virtual bool CheckAppHasPermission(const nsAString& aPermission) MOZ_OVERRIDE;
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -24,20 +24,22 @@
 #include "nsIConsoleService.h"
 #include "nsIMemoryReporter.h"
 #include "nsIProtocolHandler.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIDOMClassInfo.h"
 #include "xpcpublic.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
+#include "mozilla/IntentionalCrash.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/nsIContentParent.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
+#include "mozilla/dom/ProcessGlobal.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/StructuredCloneUtils.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/DOMStringList.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "nsPrintfCString.h"
 #include "nsXULAppAPI.h"
@@ -115,16 +117,20 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   /* nsIContentFrameMessageManager is accessible only in TabChildGlobal. */
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIContentFrameMessageManager,
                                      !mChrome && !mIsProcessManager)
 
   /* Frame message managers (non-process message managers) support nsIFrameScriptLoader. */
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFrameScriptLoader,
                                      mChrome && !mIsProcessManager)
 
+  /* Process message managers (process message managers) support nsIProcessScriptLoader. */
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIProcessScriptLoader,
+                                     mChrome && mIsProcessManager)
+
   /* Message senders in the chrome process support nsIProcessChecker. */
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIProcessChecker,
                                      mChrome && !mIsBroadcaster)
 
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageBroadcaster,
                                                    mChrome && mIsBroadcaster)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(ChromeMessageSender,
                                                    mChrome && !mIsBroadcaster)
@@ -426,19 +432,19 @@ nsFrameMessageManager::RemoveWeakMessage
   }
 
   return NS_OK;
 }
 
 // nsIFrameScriptLoader
 
 NS_IMETHODIMP
-nsFrameMessageManager::LoadFrameScript(const nsAString& aURL,
-                                       bool aAllowDelayedLoad,
-                                       bool aRunInGlobalScope)
+nsFrameMessageManager::LoadScript(const nsAString& aURL,
+                                  bool aAllowDelayedLoad,
+                                  bool aRunInGlobalScope)
 {
   if (aAllowDelayedLoad) {
     if (IsGlobal() || IsBroadcaster()) {
       // Cache for future windows or frames
       mPendingScripts.AppendElement(aURL);
       mPendingScriptsGlobalStates.AppendElement(aRunInGlobalScope);
     } else if (!mCallback) {
       // We're frame message manager, which isn't connected yet.
@@ -447,47 +453,47 @@ nsFrameMessageManager::LoadFrameScript(c
       return NS_OK;
     }
   }
 
   if (mCallback) {
 #ifdef DEBUG_smaug
     printf("Will load %s \n", NS_ConvertUTF16toUTF8(aURL).get());
 #endif
-    NS_ENSURE_TRUE(mCallback->DoLoadFrameScript(aURL, aRunInGlobalScope),
+    NS_ENSURE_TRUE(mCallback->DoLoadMessageManagerScript(aURL, aRunInGlobalScope),
                    NS_ERROR_FAILURE);
   }
 
   for (int32_t i = 0; i < mChildManagers.Count(); ++i) {
     nsRefPtr<nsFrameMessageManager> mm =
       static_cast<nsFrameMessageManager*>(mChildManagers[i]);
     if (mm) {
       // Use false here, so that child managers don't cache the script, which
       // is already cached in the parent.
-      mm->LoadFrameScript(aURL, false, aRunInGlobalScope);
+      mm->LoadScript(aURL, false, aRunInGlobalScope);
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsFrameMessageManager::RemoveDelayedFrameScript(const nsAString& aURL)
+nsFrameMessageManager::RemoveDelayedScript(const nsAString& aURL)
 {
   for (uint32_t i = 0; i < mPendingScripts.Length(); ++i) {
     if (mPendingScripts[i] == aURL) {
       mPendingScripts.RemoveElementAt(i);
       mPendingScriptsGlobalStates.RemoveElementAt(i);
       break;
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsFrameMessageManager::GetDelayedFrameScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList)
+nsFrameMessageManager::GetDelayedScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList)
 {
   // Frame message managers may return an incomplete list because scripts
   // that were loaded after it was connected are not added to the list.
   if (!IsGlobal() && !IsBroadcaster()) {
     NS_WARNING("Cannot retrieve list of pending frame scripts for frame"
                "message managers as it may be incomplete");
     return NS_ERROR_NOT_IMPLEMENTED;
   }
@@ -511,16 +517,59 @@ nsFrameMessageManager::GetDelayedFrameSc
     NS_ENSURE_TRUE(JS_SetElement(aCx, array, i, pair),
                    NS_ERROR_OUT_OF_MEMORY);
   }
 
   aList.setObject(*array);
   return NS_OK;
 }
 
+// nsIFrameScriptLoader
+
+NS_IMETHODIMP
+nsFrameMessageManager::LoadFrameScript(const nsAString& aURL,
+                                       bool aAllowDelayedLoad,
+                                       bool aRunInGlobalScope)
+{
+  return LoadScript(aURL, aAllowDelayedLoad, aRunInGlobalScope);
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::RemoveDelayedFrameScript(const nsAString& aURL)
+{
+  return RemoveDelayedScript(aURL);
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::GetDelayedFrameScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList)
+{
+  return GetDelayedScripts(aCx, aList);
+}
+
+// nsIProcessScriptLoader
+
+NS_IMETHODIMP
+nsFrameMessageManager::LoadProcessScript(const nsAString& aURL,
+                                         bool aAllowDelayedLoad)
+{
+  return LoadScript(aURL, aAllowDelayedLoad, false);
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::RemoveDelayedProcessScript(const nsAString& aURL)
+{
+  return RemoveDelayedScript(aURL);
+}
+
+NS_IMETHODIMP
+nsFrameMessageManager::GetDelayedProcessScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList)
+{
+  return GetDelayedScripts(aCx, aList);
+}
+
 static bool
 JSONCreator(const char16_t* aBuf, uint32_t aLen, void* aData)
 {
   nsAString* result = static_cast<nsAString*>(aData);
   result->Append(static_cast<const char16_t*>(aBuf),
                  static_cast<uint32_t>(aLen));
   return true;
 }
@@ -770,17 +819,22 @@ nsFrameMessageManager::Dump(const nsAStr
   fputs(NS_ConvertUTF16toUTF8(aStr).get(), stdout);
   fflush(stdout);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFrameMessageManager::PrivateNoteIntentionalCrash()
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    mozilla::NoteIntentionalCrash("tab");
+    return NS_OK;
+  } else {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
 }
 
 NS_IMETHODIMP
 nsFrameMessageManager::GetContent(nsIDOMWindow** aContent)
 {
   *aContent = nullptr;
   return NS_OK;
 }
@@ -791,24 +845,24 @@ nsFrameMessageManager::GetDocShell(nsIDo
   *aDocShell = nullptr;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFrameMessageManager::Btoa(const nsAString& aBinaryData,
                             nsAString& aAsciiBase64String)
 {
-  return NS_OK;
+  return nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
 }
 
 NS_IMETHODIMP
 nsFrameMessageManager::Atob(const nsAString& aAsciiString,
                             nsAString& aBinaryData)
 {
-  return NS_OK;
+  return nsContentUtils::Atob(aAsciiString, aBinaryData);
 }
 
 // nsIProcessChecker
 
 NS_IMETHODIMP
 nsFrameMessageManager::KillChild(bool *aValid)
 {
   if (!mCallback) {
@@ -1388,72 +1442,72 @@ NS_NewGlobalMessageManager(nsIMessageBro
                  NS_ERROR_NOT_AVAILABLE);
   nsFrameMessageManager* mm = new nsFrameMessageManager(nullptr,
                                                         nullptr,
                                                         MM_CHROME | MM_GLOBAL | MM_BROADCASTER);
   RegisterStrongMemoryReporter(new MessageManagerReporter());
   return CallQueryInterface(mm, aResult);
 }
 
-nsDataHashtable<nsStringHashKey, nsFrameScriptObjectExecutorHolder*>*
-  nsFrameScriptExecutor::sCachedScripts = nullptr;
-nsScriptCacheCleaner* nsFrameScriptExecutor::sScriptCacheCleaner = nullptr;
+nsDataHashtable<nsStringHashKey, nsMessageManagerScriptHolder*>*
+  nsMessageManagerScriptExecutor::sCachedScripts = nullptr;
+nsScriptCacheCleaner* nsMessageManagerScriptExecutor::sScriptCacheCleaner = nullptr;
 
 void
-nsFrameScriptExecutor::DidCreateGlobal()
+nsMessageManagerScriptExecutor::DidCreateGlobal()
 {
   NS_ASSERTION(mGlobal, "Should have mGlobal!");
   if (!sCachedScripts) {
     sCachedScripts =
-      new nsDataHashtable<nsStringHashKey, nsFrameScriptObjectExecutorHolder*>;
+      new nsDataHashtable<nsStringHashKey, nsMessageManagerScriptHolder*>;
 
     nsRefPtr<nsScriptCacheCleaner> scriptCacheCleaner =
       new nsScriptCacheCleaner();
     scriptCacheCleaner.forget(&sScriptCacheCleaner);
   }
 }
 
 static PLDHashOperator
 RemoveCachedScriptEntry(const nsAString& aKey,
-                        nsFrameScriptObjectExecutorHolder*& aData,
+                        nsMessageManagerScriptHolder*& aData,
                         void* aUserArg)
 {
   delete aData;
   return PL_DHASH_REMOVE;
 }
 
 // static
 void
-nsFrameScriptExecutor::Shutdown()
+nsMessageManagerScriptExecutor::Shutdown()
 {
   if (sCachedScripts) {
     AutoSafeJSContext cx;
     NS_ASSERTION(sCachedScripts != nullptr, "Need cached scripts");
     sCachedScripts->Enumerate(RemoveCachedScriptEntry, nullptr);
 
     delete sCachedScripts;
     sCachedScripts = nullptr;
 
     nsRefPtr<nsScriptCacheCleaner> scriptCacheCleaner;
     scriptCacheCleaner.swap(sScriptCacheCleaner);
   }
 }
 
 void
-nsFrameScriptExecutor::LoadFrameScriptInternal(const nsAString& aURL,
-                                               bool aRunInGlobalScope)
+nsMessageManagerScriptExecutor::LoadScriptInternal(const nsAString& aURL,
+                                                   bool aRunInGlobalScope)
 {
   if (!mGlobal || !sCachedScripts) {
     return;
   }
 
   JSRuntime* rt = CycleCollectedJSRuntime::Get()->Runtime();
   JS::Rooted<JSScript*> script(rt);
 
-  nsFrameScriptObjectExecutorHolder* holder = sCachedScripts->Get(aURL);
+  nsMessageManagerScriptHolder* holder = sCachedScripts->Get(aURL);
   if (holder && holder->WillRunInGlobalScope() == aRunInGlobalScope) {
     script = holder->mScript;
   } else {
     // Don't put anything in the cache if we already have an entry
     // with a different WillRunInGlobalScope() value.
     bool shouldCache = !holder;
     TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope,
                                  shouldCache, &script);
@@ -1475,20 +1529,21 @@ nsFrameScriptExecutor::LoadFrameScriptIn
           mAnonymousGlobalScopes.AppendElement(scope);
         }
       }
     }
   }
 }
 
 void
-nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
-                                                    bool aRunInGlobalScope,
-                                                    bool aShouldCache,
-                                                    JS::MutableHandle<JSScript*> aScriptp)
+nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
+  const nsAString& aURL,
+  bool aRunInGlobalScope,
+  bool aShouldCache,
+  JS::MutableHandle<JSScript*> aScriptp)
 {
   nsCString url = NS_ConvertUTF16toUTF8(aURL);
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
   if (NS_FAILED(rv)) {
     return;
   }
 
@@ -1560,39 +1615,41 @@ nsFrameScriptExecutor::TryCacheLoadAndCo
     }
 
     aScriptp.set(script);
 
     nsAutoCString scheme;
     uri->GetScheme(scheme);
     // We don't cache data: scripts!
     if (aShouldCache && !scheme.EqualsLiteral("data")) {
-      nsFrameScriptObjectExecutorHolder* holder;
+      nsMessageManagerScriptHolder* holder;
 
       // Root the object also for caching.
       if (script) {
-        holder = new nsFrameScriptObjectExecutorHolder(cx, script, aRunInGlobalScope);
+        holder = new nsMessageManagerScriptHolder(cx, script, aRunInGlobalScope);
       }
       sCachedScripts->Put(aURL, holder);
     }
   }
 }
 
 void
-nsFrameScriptExecutor::TryCacheLoadAndCompileScript(const nsAString& aURL,
-                                                    bool aRunInGlobalScope)
+nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
+  const nsAString& aURL,
+  bool aRunInGlobalScope)
 {
   AutoSafeJSContext cx;
   JS::Rooted<JSScript*> script(cx);
   TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope, true, &script);
 }
 
 bool
-nsFrameScriptExecutor::InitTabChildGlobalInternal(nsISupports* aScope,
-                                                  const nsACString& aID)
+nsMessageManagerScriptExecutor::InitChildGlobalInternal(
+  nsISupports* aScope,
+  const nsACString& aID)
 {
 
   nsCOMPtr<nsIJSRuntimeService> runtimeSvc =
     do_GetService("@mozilla.org/js/xpc/RuntimeService;1");
   NS_ENSURE_TRUE(runtimeSvc, false);
 
   JSRuntime* rt = nullptr;
   runtimeSvc->GetRuntime(&rt);
@@ -1642,17 +1699,17 @@ public:
                                    JS::Handle<JSObject *> aCpows,
                                    nsIPrincipal* aPrincipal)
     : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal)
   {
   }
 
   NS_IMETHOD Run()
   {
-    nsFrameMessageManager* ppm = nsFrameMessageManager::sChildProcessManager;
+    nsFrameMessageManager* ppm = nsFrameMessageManager::GetChildProcessManager();
     ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm), ppm);
     return NS_OK;
   }
 };
 
 
 /**
  * Send messages to an imaginary child process in a single-process scenario.
@@ -1664,16 +1721,25 @@ public:
   {
     MOZ_COUNT_CTOR(SameParentProcessMessageManagerCallback);
   }
   virtual ~SameParentProcessMessageManagerCallback()
   {
     MOZ_COUNT_DTOR(SameParentProcessMessageManagerCallback);
   }
 
+  virtual bool DoLoadMessageManagerScript(const nsAString& aURL,
+                                          bool aRunInGlobalScope) MOZ_OVERRIDE
+  {
+    ProcessGlobal* global = ProcessGlobal::Get();
+    MOZ_ASSERT(!aRunInGlobalScope);
+    global->LoadScript(aURL);
+    return true;
+  }
+
   virtual bool DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
                                   const StructuredCloneData& aData,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal)
   {
     nsRefPtr<nsIRunnable> ev =
       new nsAsyncMessageToSameProcessChild(aCx, aMessage, aData, aCpows,
@@ -1906,31 +1972,34 @@ nsFrameMessageManager::NewProcessMessage
     sSameProcessParentManager = mm;
   }
   return mm;
 }
 
 nsresult
 NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult)
 {
-  NS_ASSERTION(!nsFrameMessageManager::sChildProcessManager,
+  NS_ASSERTION(!nsFrameMessageManager::GetChildProcessManager(),
                "Re-creating sChildProcessManager");
 
   MessageManagerCallback* cb;
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     cb = new SameChildProcessMessageManagerCallback();
   } else {
     cb = new ChildProcessMessageManagerCallback();
     RegisterStrongMemoryReporter(new MessageManagerReporter());
   }
   nsFrameMessageManager* mm = new nsFrameMessageManager(cb,
                                                         nullptr,
                                                         MM_PROCESSMANAGER | MM_OWNSCALLBACK);
-  nsFrameMessageManager::sChildProcessManager = mm;
-  return CallQueryInterface(mm, aResult);
+  nsFrameMessageManager::SetChildProcessManager(mm);
+  ProcessGlobal* global = new ProcessGlobal(mm);
+  NS_ENSURE_TRUE(global->Init(), NS_ERROR_UNEXPECTED);
+  return CallQueryInterface(global, aResult);
+
 }
 
 static PLDHashOperator
 CycleCollectorMarkListeners(const nsAString& aKey,
                             nsAutoTObserverArray<nsMessageListenerInfo, 1>* aListeners,
                             void* aData)
 {
   uint32_t count = aListeners->Length();
--- a/dom/base/nsFrameMessageManager.h
+++ b/dom/base/nsFrameMessageManager.h
@@ -49,17 +49,17 @@ enum MessageManagerFlags {
   MM_OWNSCALLBACK = 16
 };
 
 class MessageManagerCallback
 {
 public:
   virtual ~MessageManagerCallback() {}
 
-  virtual bool DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope)
+  virtual bool DoLoadMessageManagerScript(const nsAString& aURL, bool aRunInGlobalScope)
   {
     return true;
   }
 
   virtual bool DoSendBlockingMessage(JSContext* aCx,
                                      const nsAString& aMessage,
                                      const StructuredCloneData& aData,
                                      JS::Handle<JSObject*> aCpows,
@@ -149,16 +149,17 @@ public:
 
 private:
   JS::Rooted<JSObject*> mObj;
 };
 
 class nsFrameMessageManager MOZ_FINAL : public nsIContentFrameMessageManager,
                                         public nsIMessageBroadcaster,
                                         public nsIFrameScriptLoader,
+                                        public nsIProcessScriptLoader,
                                         public nsIProcessChecker
 {
   friend class mozilla::dom::MessageManagerReporter;
   typedef mozilla::dom::StructuredCloneData StructuredCloneData;
 public:
   nsFrameMessageManager(mozilla::dom::ipc::MessageManagerCallback* aCallback,
                         nsFrameMessageManager* aParentManager,
                         /* mozilla::dom::ipc::MessageManagerFlags */ uint32_t aFlags)
@@ -212,18 +213,20 @@ private:
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsFrameMessageManager,
                                            nsIContentFrameMessageManager)
   NS_DECL_NSIMESSAGELISTENERMANAGER
   NS_DECL_NSIMESSAGESENDER
   NS_DECL_NSIMESSAGEBROADCASTER
   NS_DECL_NSISYNCMESSAGESENDER
+  NS_DECL_NSIMESSAGEMANAGERGLOBAL
   NS_DECL_NSICONTENTFRAMEMESSAGEMANAGER
   NS_DECL_NSIFRAMESCRIPTLOADER
+  NS_DECL_NSIPROCESSSCRIPTLOADER
   NS_DECL_NSIPROCESSCHECKER
 
   static nsFrameMessageManager*
   NewProcessMessageManager(mozilla::dom::nsIContentParent* aProcess);
 
   nsresult ReceiveMessage(nsISupports* aTarget, const nsAString& aMessage,
                           bool aIsSync, const StructuredCloneData* aCloneData,
                           mozilla::jsipc::CpowHolder* aCpows, nsIPrincipal* aPrincipal,
@@ -268,25 +271,36 @@ public:
   static nsFrameMessageManager* GetParentProcessManager()
   {
     return sParentProcessManager;
   }
   static nsFrameMessageManager* GetChildProcessManager()
   {
     return sChildProcessManager;
   }
+  static void SetChildProcessManager(nsFrameMessageManager* aManager)
+  {
+    sChildProcessManager = aManager;
+  }
 private:
   nsresult SendMessage(const nsAString& aMessageName,
                        JS::Handle<JS::Value> aJSON,
                        JS::Handle<JS::Value> aObjects,
                        nsIPrincipal* aPrincipal,
                        JSContext* aCx,
                        uint8_t aArgc,
                        JS::MutableHandle<JS::Value> aRetval,
                        bool aIsSync);
+
+  NS_IMETHOD LoadScript(const nsAString& aURL,
+                        bool aAllowDelayedLoad,
+                        bool aRunInGlobalScope);
+  NS_IMETHOD RemoveDelayedScript(const nsAString& aURL);
+  NS_IMETHOD GetDelayedScripts(JSContext* aCx, JS::MutableHandle<JS::Value> aList);
+
 protected:
   friend class MMListenerRemover;
   // We keep the message listeners as arrays in a hastable indexed by the
   // message name. That gives us fast lookups in ReceiveMessage().
   nsClassHashtable<nsStringHashKey,
                    nsAutoTObserverArray<nsMessageListenerInfo, 1>> mListeners;
   nsCOMArray<nsIContentFrameMessageManager> mChildManagers;
   bool mChrome;     // true if we're in the chrome process
@@ -301,20 +315,20 @@ protected:
   nsFrameMessageManager* mParentManager;
   nsTArray<nsString> mPendingScripts;
   nsTArray<bool> mPendingScriptsGlobalStates;
 
   void LoadPendingScripts(nsFrameMessageManager* aManager,
                           nsFrameMessageManager* aChildMM);
 public:
   static nsFrameMessageManager* sParentProcessManager;
-  static nsFrameMessageManager* sChildProcessManager;
   static nsFrameMessageManager* sSameProcessParentManager;
   static nsTArray<nsCOMPtr<nsIRunnable> >* sPendingSameProcessAsyncMessages;
 private:
+  static nsFrameMessageManager* sChildProcessManager;
   enum ProcessCheckerType {
     PROCESS_CHECKER_PERMISSION,
     PROCESS_CHECKER_MANIFEST_URL,
     ASSERT_APP_HAS_PERMISSION
   };
   nsresult AssertProcessInternal(ProcessCheckerType aType,
                                  const nsAString& aCapability,
                                  bool* aValid);
@@ -356,61 +370,61 @@ private:
   JSAutoStructuredCloneBuffer mData;
   StructuredCloneClosure mClosure;
   JS::PersistentRooted<JSObject*> mCpows;
   nsCOMPtr<nsIPrincipal> mPrincipal;
 };
 
 class nsScriptCacheCleaner;
 
-struct nsFrameScriptObjectExecutorHolder
+struct nsMessageManagerScriptHolder
 {
-  nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSScript* aScript, bool aRunInGlobalScope)
+  nsMessageManagerScriptHolder(JSContext* aCx,
+                               JSScript* aScript,
+                               bool aRunInGlobalScope)
    : mScript(aCx, aScript), mRunInGlobalScope(aRunInGlobalScope)
-  { MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder); }
+  { MOZ_COUNT_CTOR(nsMessageManagerScriptHolder); }
 
-  ~nsFrameScriptObjectExecutorHolder()
-  { MOZ_COUNT_DTOR(nsFrameScriptObjectExecutorHolder); }
+  ~nsMessageManagerScriptHolder()
+  { MOZ_COUNT_DTOR(nsMessageManagerScriptHolder); }
 
   bool WillRunInGlobalScope() { return mRunInGlobalScope; }
 
   JS::PersistentRooted<JSScript*> mScript;
   bool mRunInGlobalScope;
 };
 
-class nsFrameScriptObjectExecutorStackHolder;
-
-class nsFrameScriptExecutor
+class nsMessageManagerScriptExecutor
 {
 public:
   static void Shutdown();
   already_AddRefed<nsIXPConnectJSObjectHolder> GetGlobal()
   {
     nsCOMPtr<nsIXPConnectJSObjectHolder> ref = mGlobal;
     return ref.forget();
   }
 protected:
-  friend class nsFrameScriptCx;
-  nsFrameScriptExecutor() { MOZ_COUNT_CTOR(nsFrameScriptExecutor); }
-  ~nsFrameScriptExecutor() { MOZ_COUNT_DTOR(nsFrameScriptExecutor); }
+  friend class nsMessageManagerScriptCx;
+  nsMessageManagerScriptExecutor() { MOZ_COUNT_CTOR(nsMessageManagerScriptExecutor); }
+  ~nsMessageManagerScriptExecutor() { MOZ_COUNT_DTOR(nsMessageManagerScriptExecutor); }
 
   void DidCreateGlobal();
-  void LoadFrameScriptInternal(const nsAString& aURL, bool aRunInGlobalScope);
+  void LoadScriptInternal(const nsAString& aURL, bool aRunInGlobalScope);
   void TryCacheLoadAndCompileScript(const nsAString& aURL,
                                     bool aRunInGlobalScope,
                                     bool aShouldCache,
                                     JS::MutableHandle<JSScript*> aScriptp);
   void TryCacheLoadAndCompileScript(const nsAString& aURL,
                                     bool aRunInGlobalScope);
-  bool InitTabChildGlobalInternal(nsISupports* aScope, const nsACString& aID);
+  bool InitChildGlobalInternal(nsISupports* aScope, const nsACString& aID);
   nsCOMPtr<nsIXPConnectJSObjectHolder> mGlobal;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsAutoTArray<JS::Heap<JSObject*>, 2> mAnonymousGlobalScopes;
 
-  static nsDataHashtable<nsStringHashKey, nsFrameScriptObjectExecutorHolder*>* sCachedScripts;
+  static nsDataHashtable<nsStringHashKey, nsMessageManagerScriptHolder*>* sCachedScripts;
   static nsScriptCacheCleaner* sScriptCacheCleaner;
 };
 
 class nsScriptCacheCleaner MOZ_FINAL : public nsIObserver
 {
   ~nsScriptCacheCleaner() {}
 
   NS_DECL_ISUPPORTS
@@ -421,14 +435,14 @@ class nsScriptCacheCleaner MOZ_FINAL : p
     if (obsSvc)
       obsSvc->AddObserver(this, "xpcom-shutdown", false);
   }
 
   NS_IMETHODIMP Observe(nsISupports *aSubject,
                         const char *aTopic,
                         const char16_t *aData) MOZ_OVERRIDE
   {
-    nsFrameScriptExecutor::Shutdown();
+    nsMessageManagerScriptExecutor::Shutdown();
     return NS_OK;
   }
 };
 
 #endif
--- a/dom/base/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -513,36 +513,22 @@ nsHostObjectProtocolHandler::NewChannel2
   }
 #endif
 
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = blob->GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIChannel> channel;
-  // Bug 1087720 (and Bug 1099296):
-  // Once all callsites have been updated to call NewChannel2() instead of NewChannel()
-  // we should have a non-null loadInfo consistently. Until then we have to brach on the
-  // loadInfo and provide default arguments to create a NewInputStreamChannel.
-  if (aLoadInfo) {
-    rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
-                                          uri,
-                                          stream,
-                                          EmptyCString(), // aContentType
-                                          EmptyCString(), // aContentCharset
-                                          aLoadInfo);
-  }
-  else {
-    rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
-                                  uri,
-                                  stream,
-                                  info->mPrincipal,
-                                  nsILoadInfo::SEC_NORMAL,
-                                  nsIContentPolicy::TYPE_OTHER);
-  }
+  rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
+                                        uri,
+                                        stream,
+                                        EmptyCString(), // aContentType
+                                        EmptyCString(), // aContentCharset
+                                        aLoadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsString type;
   blob->GetType(type);
 
   if (blob->IsFile()) {
     nsString filename;
     blob->GetName(filename);
--- a/dom/base/nsIMessageManager.idl
+++ b/dom/base/nsIMessageManager.idl
@@ -336,53 +336,62 @@ interface nsISyncMessageSender : nsIMess
    */
   [implicit_jscontext, optional_argc]
   jsval sendRpcMessage([optional] in AString messageName,
                        [optional] in jsval obj,
                        [optional] in jsval objects,
                        [optional] in nsIPrincipal principal);
 };
 
-[scriptable, builtinclass, uuid(894ff2d4-39a3-4df8-9d76-8ee329975488)]
-interface nsIContentFrameMessageManager : nsISyncMessageSender
+[scriptable, builtinclass, uuid(e04a7ade-c61a-46ec-9f13-efeabedd9d3d)]
+interface nsIMessageManagerGlobal : nsISyncMessageSender
 {
   /**
-   * The current top level window in the frame or null.
-   */
-  readonly attribute nsIDOMWindow content;
-
-  /**
-   * The top level docshell or null.
-   */
-  readonly attribute nsIDocShell docShell;
-
-  /**
    * Print a string to stdout.
    */
   void dump(in DOMString aStr);
 
   /**
    * If leak detection is enabled, print a note to the leak log that this
    * process will intentionally crash.
    */
   void privateNoteIntentionalCrash();
 
-   /**
-    * Ascii base64 data to binary data and vice versa
-    */
-   DOMString atob(in DOMString aAsciiString);
-   DOMString btoa(in DOMString aBase64Data);
+  /**
+   * Ascii base64 data to binary data and vice versa
+   */
+  DOMString atob(in DOMString aAsciiString);
+  DOMString btoa(in DOMString aBase64Data);
+};
+
+[scriptable, builtinclass, uuid(fff36099-9f84-4c7c-b69a-1cbf103d1708)]
+interface nsIContentFrameMessageManager : nsIMessageManagerGlobal
+{
+  /**
+   * The current top level window in the frame or null.
+   */
+  readonly attribute nsIDOMWindow content;
+
+  /**
+   * The top level docshell or null.
+   */
+  readonly attribute nsIDocShell docShell;
 };
 
 [uuid(a2325927-9c0c-437d-9215-749c79235031)]
 interface nsIInProcessContentFrameMessageManager : nsIContentFrameMessageManager
 {
   [notxpcom] nsIContent getOwnerContent();
 };
 
+[scriptable, builtinclass, uuid(9ca95410-b253-11e4-ab27-0800200c9a66)]
+interface nsIContentProcessMessageManager : nsIMessageManagerGlobal
+{
+};
+
 [scriptable, builtinclass, uuid(6fb78110-45ae-11e3-8f96-0800200c9a66)]
 interface nsIFrameScriptLoader : nsISupports
 {
   /**
    * Load a script in the (remote) frame. aURL must be the absolute URL.
    * data: URLs are also supported. For example data:,dump("foo\n");
    * If aAllowDelayedLoad is true, script will be loaded when the
    * remote frame becomes available. Otherwise the script will be loaded
@@ -400,16 +409,41 @@ interface nsIFrameScriptLoader : nsISupp
    * Returns all delayed scripts that will be loaded once a (remote)
    * frame becomes available. The return value is a list of pairs
    * [<URL>, <WasLoadedInGlobalScope>].
    */
   [implicit_jscontext]
   jsval getDelayedFrameScripts();
 };
 
+[scriptable, builtinclass, uuid(7e1e1a20-b24f-11e4-ab27-0800200c9a66)]
+interface nsIProcessScriptLoader : nsISupports
+{
+  /**
+   * Load a script in the (possibly remote) process. aURL must be the absolute URL.
+   * data: URLs are also supported. For example data:,dump("foo\n");
+   * If aAllowDelayedLoad is true, script will be loaded when the
+   * remote frame becomes available. Otherwise the script will be loaded
+   * only if the frame is already available.
+   */
+  void loadProcessScript(in AString aURL, in boolean aAllowDelayedLoad);
+
+  /**
+   * Removes aURL from the list of scripts which support delayed load.
+   */
+  void removeDelayedProcessScript(in AString aURL);
+
+  /**
+   * Returns all delayed scripts that will be loaded once a (remote)
+   * frame becomes available. The return value is a list of URLs.
+   */
+  [implicit_jscontext]
+  jsval getDelayedProcessScripts();
+};
+
 [scriptable, builtinclass, uuid(637e8538-4f8f-4a3d-8510-e74386233e19)]
 interface nsIProcessChecker : nsISupports
 {
   bool killChild();
 
   /**
    * Return true if the "remote" process has |aPermission|.  This is
    * intended to be used by JS implementations of cross-process DOM
--- a/dom/base/nsInProcessTabChildGlobal.cpp
+++ b/dom/base/nsInProcessTabChildGlobal.cpp
@@ -200,37 +200,16 @@ nsInProcessTabChildGlobal::GetContent(ns
 
 NS_IMETHODIMP
 nsInProcessTabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
 {
   NS_IF_ADDREF(*aDocShell = mDocShell);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsInProcessTabChildGlobal::Btoa(const nsAString& aBinaryData,
-                            nsAString& aAsciiBase64String)
-{
-  return nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
-}
-
-NS_IMETHODIMP
-nsInProcessTabChildGlobal::Atob(const nsAString& aAsciiString,
-                            nsAString& aBinaryData)
-{
-  return nsContentUtils::Atob(aAsciiString, aBinaryData);
-}
-
-
-NS_IMETHODIMP
-nsInProcessTabChildGlobal::PrivateNoteIntentionalCrash()
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
 void
 nsInProcessTabChildGlobal::Disconnect()
 {
   // Let the frame scripts know the child is being closed. We do any other
   // cleanup after the event has been fired. See DelayedDisconnect
   nsContentUtils::AddScriptRunner(
      NS_NewRunnableMethod(this, &nsInProcessTabChildGlobal::DelayedDisconnect)
   );
@@ -313,17 +292,17 @@ nsInProcessTabChildGlobal::InitTabChildG
   nsIURI* uri = mOwner->OwnerDoc()->GetDocumentURI();
   if (uri) {
     nsAutoCString u;
     uri->GetSpec(u);
     id.AppendLiteral("?ownedBy=");
     id.Append(u);
   }
   nsISupports* scopeSupports = NS_ISUPPORTS_CAST(EventTarget*, this);
-  NS_ENSURE_STATE(InitTabChildGlobalInternal(scopeSupports, id));
+  NS_ENSURE_STATE(InitChildGlobalInternal(scopeSupports, id));
   return NS_OK;
 }
 
 class nsAsyncScriptLoad : public nsRunnable
 {
 public:
     nsAsyncScriptLoad(nsInProcessTabChildGlobal* aTabChild, const nsAString& aURL,
                       bool aRunInGlobalScope)
@@ -347,11 +326,11 @@ nsInProcessTabChildGlobal::LoadFrameScri
     return;
   }
   if (!mInitialized) {
     mInitialized = true;
     Init();
   }
   bool tmp = mLoadingScript;
   mLoadingScript = true;
-  LoadFrameScriptInternal(aURL, aRunInGlobalScope);
+  LoadScriptInternal(aURL, aRunInGlobalScope);
   mLoadingScript = tmp;
 }
--- a/dom/base/nsInProcessTabChildGlobal.h
+++ b/dom/base/nsInProcessTabChildGlobal.h
@@ -23,32 +23,33 @@
 #include "nsIScriptObjectPrincipal.h"
 #include "nsWeakReference.h"
 
 namespace mozilla {
 class EventChainPreVisitor;
 } // namespace mozilla
 
 class nsInProcessTabChildGlobal : public mozilla::DOMEventTargetHelper,
-                                  public nsFrameScriptExecutor,
+                                  public nsMessageManagerScriptExecutor,
                                   public nsIInProcessContentFrameMessageManager,
                                   public nsIGlobalObject,
                                   public nsIScriptObjectPrincipal,
                                   public nsSupportsWeakReference,
                                   public mozilla::dom::ipc::MessageManagerCallback
 {
 public:
   nsInProcessTabChildGlobal(nsIDocShell* aShell, nsIContent* aOwner,
                             nsFrameMessageManager* aChrome);
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(nsInProcessTabChildGlobal,
                                                          mozilla::DOMEventTargetHelper)
 
   NS_FORWARD_SAFE_NSIMESSAGELISTENERMANAGER(mMessageManager)
   NS_FORWARD_SAFE_NSIMESSAGESENDER(mMessageManager)
+  NS_FORWARD_SAFE_NSIMESSAGEMANAGERGLOBAL(mMessageManager)
   NS_IMETHOD SendSyncMessage(const nsAString& aMessageName,
                              JS::Handle<JS::Value> aObject,
                              JS::Handle<JS::Value> aRemote,
                              nsIPrincipal* aPrincipal,
                              JSContext* aCx,
                              uint8_t aArgc,
                              JS::MutableHandle<JS::Value> aRetval) MOZ_OVERRIDE
   {
@@ -67,25 +68,16 @@ public:
   {
     return mMessageManager
       ? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote,
                                         aPrincipal, aCx, aArgc, aRetval)
       : NS_ERROR_NULL_POINTER;
   }
   NS_IMETHOD GetContent(nsIDOMWindow** aContent) MOZ_OVERRIDE;
   NS_IMETHOD GetDocShell(nsIDocShell** aDocShell) MOZ_OVERRIDE;
-  NS_IMETHOD Dump(const nsAString& aStr) MOZ_OVERRIDE
-  {
-    return mMessageManager ? mMessageManager->Dump(aStr) : NS_OK;
-  }
-  NS_IMETHOD PrivateNoteIntentionalCrash() MOZ_OVERRIDE;
-  NS_IMETHOD Btoa(const nsAString& aBinaryData,
-                  nsAString& aAsciiBase64String) MOZ_OVERRIDE;
-  NS_IMETHOD Atob(const nsAString& aAsciiString,
-                  nsAString& aBinaryData) MOZ_OVERRIDE;
 
   NS_DECL_NSIINPROCESSCONTENTFRAMEMESSAGEMANAGER
 
   /**
    * MessageManagerCallback methods that we override.
    */
   virtual bool DoSendBlockingMessage(JSContext* aCx,
                                       const nsAString& aMessage,
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -366,8 +366,14 @@ nsJSUtils::GetScopeChainForElement(JSCon
 JSObject* GetDefaultScopeFromJSContext(JSContext *cx)
 {
   // DOM JSContexts don't store their default compartment object on
   // the cx, so in those cases we need to fetch it via the scx
   // instead.
   nsIScriptContext *scx = GetScriptContextFromJSContext(cx);
   return  scx ? scx->GetWindowProxy() : nullptr;
 }
+
+bool nsAutoJSString::init(const JS::Value &v)
+{
+  return init(nsContentUtils::RootingCxForThread(), v);
+}
+
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -212,12 +212,14 @@ public:
   }
 
   bool init(JSContext* aContext, jsid id)
   {
     JS::Rooted<JS::Value> v(aContext);
     return JS_IdToValue(aContext, id, &v) && init(aContext, v);
   }
 
+  bool init(const JS::Value &v);
+
   ~nsAutoJSString() {}
 };
 
 #endif /* nsJSUtils_h__ */
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -12,16 +12,17 @@
 #include "js/Id.h"          // must come before js/RootingAPI.h
 #include "js/Value.h"       // must come before js/RootingAPI.h
 #include "js/RootingAPI.h"
 #include "js/TracingAPI.h"
 
 namespace mozilla {
 namespace dom {
 class TabChildGlobal;
+class ProcessGlobal;
 } // namespace dom
 } // namespace mozilla
 class SandboxPrivate;
 class nsInProcessTabChildGlobal;
 class nsWindowRoot;
 class XPCWrappedNativeScope;
 
 #define NS_WRAPPERCACHE_IID \
@@ -258,16 +259,17 @@ protected:
   {
     if (mWrapper) {
       mWrapper.setToCrashOnTouch();
     }
   }
 
 private:
   friend class mozilla::dom::TabChildGlobal;
+  friend class mozilla::dom::ProcessGlobal;
   friend class SandboxPrivate;
   friend class nsInProcessTabChildGlobal;
   friend class nsWindowRoot;
   void SetIsNotDOMBinding()
   {
     MOZ_ASSERT(!mWrapper && !(GetWrapperFlags() & ~WRAPPER_IS_NOT_DOM_BINDING),
                "This flag should be set before creating any wrappers.");
     SetWrapperFlags(WRAPPER_IS_NOT_DOM_BINDING);
--- a/dom/base/test/browser.ini
+++ b/dom/base/test/browser.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 
 [browser_bug593387.js]
 skip-if = e10s # Bug ?????? - test directly touches content (contentWindow.iframe.addEventListener)
 [browser_bug902350.js]
 skip-if = e10s # Bug ?????? - test e10s utils don't support load events from iframe etc, which this test relies on.
+[browser_messagemanager_loadprocessscript.js]
 [browser_state_notifications.js]
 # skip-if = e10s # Bug ?????? - content-document-* notifications come while document's URI is still about:blank, but test expects real URL.
 skip-if = true # Intermittent failures - bug 987493. Restore the skip-if above once fixed
 [browser_bug1058164.js]
 skip-if = e10s # We need bug 918634 to land before this can be tested with e10s.
new file mode 100644
--- /dev/null
+++ b/dom/base/test/browser_messagemanager_loadprocessscript.js
@@ -0,0 +1,44 @@
+let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
+           .getService(Ci.nsIMessageBroadcaster);
+ppmm.QueryInterface(Ci.nsIProcessScriptLoader);
+
+function processScript() {
+  let cpmm = Components.classes["@mozilla.org/childprocessmessagemanager;1"]
+           .getService(Components.interfaces.nsISyncMessageSender);
+  if (cpmm !== this) {
+    dump("Test failed: wrong global object\n");
+    return;
+  }
+
+  this.cpmm = cpmm;
+
+  addMessageListener("ProcessTest:Reply", function listener(msg) {
+    removeMessageListener("ProcessTest:Reply", listener);
+    sendAsyncMessage("ProcessTest:Finished");
+  });
+  sendSyncMessage("ProcessTest:Loaded");
+}
+
+function test() {
+  waitForExplicitFinish();
+
+  let replyCount = 0;
+
+  function loadListener(msg) {
+    replyCount++;
+    msg.target.sendAsyncMessage("ProcessTest:Reply");
+  }
+
+  ppmm.addMessageListener("ProcessTest:Loaded", loadListener);
+  ppmm.addMessageListener("ProcessTest:Finished", function finishListener(msg) {
+    if (replyCount < ppmm.childCount) {
+      return;
+    }
+    info("Got " + replyCount + " replies");
+    ok(replyCount, "Got message reply");
+    ppmm.removeMessageListener("ProcessTest:Loaded", loadListener);
+    ppmm.removeMessageListener("ProcessTest:Finished", finishListener);
+    finish();
+  });
+  ppmm.loadProcessScript("data:,(" + processScript.toString() + ")()", true);
+}
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -57,17 +57,17 @@ MSG_DEF(MSG_METADATA_NOT_CONFIGURED, 0, 
 MSG_DEF(MSG_INVALID_READ_SIZE, 0, JSEXN_TYPEERR, "0 (Zero) is not a valid read size.")
 MSG_DEF(MSG_HEADERS_IMMUTABLE, 0, JSEXN_TYPEERR, "Headers are immutable and cannot be modified.")
 MSG_DEF(MSG_INVALID_HEADER_NAME, 1, JSEXN_TYPEERR, "{0} is an invalid header name.")
 MSG_DEF(MSG_INVALID_HEADER_VALUE, 1, JSEXN_TYPEERR, "{0} is an invalid header value.")
 MSG_DEF(MSG_INVALID_HEADER_SEQUENCE, 0, JSEXN_TYPEERR, "Headers require name/value tuples when being initialized by a sequence.")
 MSG_DEF(MSG_PERMISSION_DENIED_TO_PASS_ARG, 1, JSEXN_TYPEERR, "Permission denied to pass cross-origin object as {0}.")
 MSG_DEF(MSG_MISSING_REQUIRED_DICTIONARY_MEMBER, 1, JSEXN_TYPEERR, "Missing required {0}.")
 MSG_DEF(MSG_INVALID_REQUEST_METHOD, 1, JSEXN_TYPEERR, "Invalid request method {0}.")
-MSG_DEF(MSG_REQUEST_BODY_CONSUMED_ERROR, 0, JSEXN_TYPEERR, "Request body has already been consumed.")
+MSG_DEF(MSG_FETCH_BODY_CONSUMED_ERROR, 0, JSEXN_TYPEERR, "Body has already been consumed.")
 MSG_DEF(MSG_RESPONSE_INVALID_STATUSTEXT_ERROR, 0, JSEXN_TYPEERR, "Response statusText may not contain newline or carriage return.")
 MSG_DEF(MSG_FETCH_FAILED, 0, JSEXN_TYPEERR, "NetworkError when attempting to fetch resource.")
 MSG_DEF(MSG_NO_BODY_ALLOWED_FOR_GET_AND_HEAD, 0, JSEXN_TYPEERR, "HEAD or GET Request cannot have a body.")
 MSG_DEF(MSG_DEFINE_NON_CONFIGURABLE_PROP_ON_WINDOW, 0, JSEXN_TYPEERR, "Not allowed to define a non-configurable property on the WindowProxy object")
 MSG_DEF(MSG_INVALID_ZOOMANDPAN_VALUE_ERROR, 0, JSEXN_RANGEERR, "Invalid zoom and pan value.")
 MSG_DEF(MSG_INVALID_TRANSFORM_ANGLE_ERROR, 0, JSEXN_RANGEERR, "Invalid transform angle.")
 MSG_DEF(MSG_INVALID_RESPONSE_STATUSCODE_ERROR, 0, JSEXN_RANGEERR, "Invalid response status code.")
 MSG_DEF(MSG_INVALID_REDIRECT_STATUSCODE_ERROR, 0, JSEXN_RANGEERR, "Invalid redirect status code.")
--- a/dom/broadcastchannel/BroadcastChannel.cpp
+++ b/dom/broadcastchannel/BroadcastChannel.cpp
@@ -330,17 +330,17 @@ public:
   explicit BroadcastChannelFeature(BroadcastChannel* aChannel)
     : mChannel(aChannel)
   {
     MOZ_COUNT_CTOR(BroadcastChannelFeature);
   }
 
   virtual bool Notify(JSContext* aCx, workers::Status aStatus) MOZ_OVERRIDE
   {
-    if (aStatus >= Canceling) {
+    if (aStatus >= Closing) {
       mChannel->Shutdown();
     }
 
     return true;
   }
 
 private:
   ~BroadcastChannelFeature()
@@ -631,37 +631,37 @@ BroadcastChannel::ActorCreated(PBackgrou
   }
 }
 
 void
 BroadcastChannel::Shutdown()
 {
   mState = StateClosed;
 
-  // If shutdown() is called we have to release the reference if we still keep
-  // it.
-  if (mIsKeptAlive) {
-    mIsKeptAlive = false;
-    Release();
-  }
-
   if (mWorkerFeature) {
     WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     workerPrivate->RemoveFeature(workerPrivate->GetJSContext(), mWorkerFeature);
     mWorkerFeature = nullptr;
   }
 
   if (mActor) {
     mActor->SetParent(nullptr);
 
     nsRefPtr<TeardownRunnable> runnable = new TeardownRunnable(mActor);
     NS_DispatchToCurrentThread(runnable);
 
     mActor = nullptr;
   }
+
+  // If shutdown() is called we have to release the reference if we still keep
+  // it.
+  if (mIsKeptAlive) {
+    mIsKeptAlive = false;
+    Release();
+  }
 }
 
 EventHandlerNonNull*
 BroadcastChannel::GetOnmessage()
 {
   if (NS_IsMainThread()) {
     return GetEventHandler(nsGkAtoms::onmessage, EmptyString());
   }
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -1159,17 +1159,17 @@ FetchBody<Derived>::ContinueConsumeBody(
 }
 
 template <class Derived>
 already_AddRefed<Promise>
 FetchBody<Derived>::ConsumeBody(ConsumeType aType, ErrorResult& aRv)
 {
   mConsumeType = aType;
   if (BodyUsed()) {
-    aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR);
+    aRv.ThrowTypeError(MSG_FETCH_BODY_CONSUMED_ERROR);
     return nullptr;
   }
 
   SetBodyUsed();
 
   mConsumePromise = Promise::Create(DerivedClass()->GetParentObject(), aRv);
   if (aRv.Failed()) {
     return nullptr;
--- a/dom/fetch/Fetch.h
+++ b/dom/fetch/Fetch.h
@@ -94,17 +94,17 @@ template <class Derived> class FetchBody
  *    worry about keeping anything alive.
  *
  * The pump is always released on the main thread.
  */
 template <class Derived>
 class FetchBody {
 public:
   bool
-  BodyUsed() { return mBodyUsed; }
+  BodyUsed() const { return mBodyUsed; }
 
   already_AddRefed<Promise>
   ArrayBuffer(ErrorResult& aRv)
   {
     return ConsumeBody(CONSUME_ARRAYBUFFER, aRv);
   }
 
   already_AddRefed<Promise>
--- a/dom/fetch/InternalRequest.cpp
+++ b/dom/fetch/InternalRequest.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "InternalRequest.h"
 
 #include "nsIContentPolicy.h"
 #include "nsIDocument.h"
+#include "nsStreamUtils.h"
 
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/workers/Workers.h"
 
 #include "WorkerPrivate.h"
 
 namespace mozilla {
@@ -38,14 +39,61 @@ InternalRequest::GetRequestConstructorCo
 
   copy->mContentPolicyType = nsIContentPolicy::TYPE_FETCH;
   copy->mMode = mMode;
   copy->mCredentialsMode = mCredentialsMode;
   copy->mCacheMode = mCacheMode;
   return copy.forget();
 }
 
+already_AddRefed<InternalRequest>
+InternalRequest::Clone()
+{
+  nsRefPtr<InternalRequest> clone = new InternalRequest(*this);
+
+  if (!mBodyStream) {
+    return clone.forget();
+  }
+
+  nsCOMPtr<nsIInputStream> clonedBody;
+  nsCOMPtr<nsIInputStream> replacementBody;
+
+  nsresult rv = NS_CloneInputStream(mBodyStream, getter_AddRefs(clonedBody),
+                                    getter_AddRefs(replacementBody));
+  if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; }
+
+  clone->mBodyStream.swap(clonedBody);
+  if (replacementBody) {
+    mBodyStream.swap(replacementBody);
+  }
+
+  return clone.forget();
+}
+
+InternalRequest::InternalRequest(const InternalRequest& aOther)
+  : mMethod(aOther.mMethod)
+  , mURL(aOther.mURL)
+  , mHeaders(new InternalHeaders(*aOther.mHeaders))
+  , mContentPolicyType(aOther.mContentPolicyType)
+  , mReferrer(aOther.mReferrer)
+  , mMode(aOther.mMode)
+  , mCredentialsMode(aOther.mCredentialsMode)
+  , mResponseTainting(aOther.mResponseTainting)
+  , mCacheMode(aOther.mCacheMode)
+  , mAuthenticationFlag(aOther.mAuthenticationFlag)
+  , mForceOriginHeader(aOther.mForceOriginHeader)
+  , mPreserveContentCodings(aOther.mPreserveContentCodings)
+  , mSameOriginDataURL(aOther.mSameOriginDataURL)
+  , mSandboxedStorageAreaURLs(aOther.mSandboxedStorageAreaURLs)
+  , mSkipServiceWorker(aOther.mSkipServiceWorker)
+  , mSynchronous(aOther.mSynchronous)
+  , mUnsafeRequest(aOther.mUnsafeRequest)
+  , mUseURLCredentials(aOther.mUseURLCredentials)
+{
+  // NOTE: does not copy body stream... use the fallible Clone() for that
+}
+
 InternalRequest::~InternalRequest()
 {
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/fetch/InternalRequest.h
+++ b/dom/fetch/InternalRequest.h
@@ -62,38 +62,17 @@ public:
     , mSameOriginDataURL(true)
     , mSkipServiceWorker(false)
     , mSynchronous(false)
     , mUnsafeRequest(false)
     , mUseURLCredentials(false)
   {
   }
 
-  explicit InternalRequest(const InternalRequest& aOther)
-    : mMethod(aOther.mMethod)
-    , mURL(aOther.mURL)
-    , mHeaders(aOther.mHeaders)
-    , mBodyStream(aOther.mBodyStream)
-    , mContentPolicyType(aOther.mContentPolicyType)
-    , mReferrer(aOther.mReferrer)
-    , mMode(aOther.mMode)
-    , mCredentialsMode(aOther.mCredentialsMode)
-    , mResponseTainting(aOther.mResponseTainting)
-    , mCacheMode(aOther.mCacheMode)
-    , mAuthenticationFlag(aOther.mAuthenticationFlag)
-    , mForceOriginHeader(aOther.mForceOriginHeader)
-    , mPreserveContentCodings(aOther.mPreserveContentCodings)
-    , mSameOriginDataURL(aOther.mSameOriginDataURL)
-    , mSandboxedStorageAreaURLs(aOther.mSandboxedStorageAreaURLs)
-    , mSkipServiceWorker(aOther.mSkipServiceWorker)
-    , mSynchronous(aOther.mSynchronous)
-    , mUnsafeRequest(aOther.mUnsafeRequest)
-    , mUseURLCredentials(aOther.mUseURLCredentials)
-  {
-  }
+  already_AddRefed<InternalRequest> Clone();
 
   void
   GetMethod(nsCString& aMethod) const
   {
     aMethod.Assign(mMethod);
   }
 
   void
@@ -288,16 +267,19 @@ public:
     s.forget(aStream);
   }
 
   // The global is used as the client for the new object.
   already_AddRefed<InternalRequest>
   GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult& aRv) const;
 
 private:
+  // Does not copy mBodyStream.  Use fallible Clone() for complete copy.
+  explicit InternalRequest(const InternalRequest& aOther);
+
   ~InternalRequest();
 
   nsCString mMethod;
   nsCString mURL;
   nsRefPtr<InternalHeaders> mHeaders;
   nsCOMPtr<nsIInputStream> mBodyStream;
 
   // nsContentPolicyType does not cover the complete set defined in the spec,
--- a/dom/fetch/InternalResponse.cpp
+++ b/dom/fetch/InternalResponse.cpp
@@ -3,59 +3,86 @@
  * 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 "InternalResponse.h"
 
 #include "nsIDOMFile.h"
 
 #include "mozilla/dom/InternalHeaders.h"
+#include "nsStreamUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusText)
   : mType(ResponseType::Default)
   , mFinalURL(false)
   , mStatus(aStatus)
   , mStatusText(aStatusText)
   , mHeaders(new InternalHeaders(HeadersGuardEnum::Response))
 {
 }
 
 // Headers are not copied since BasicResponse and CORSResponse both need custom
-// header handling.
+// header handling.  Body is not copied as it cannot be shared directly.
 InternalResponse::InternalResponse(const InternalResponse& aOther)
   : mType(aOther.mType)
   , mTerminationReason(aOther.mTerminationReason)
   , mURL(aOther.mURL)
   , mFinalURL(aOther.mFinalURL)
   , mStatus(aOther.mStatus)
   , mStatusText(aOther.mStatusText)
-  , mBody(aOther.mBody)
   , mContentType(aOther.mContentType)
 {
 }
 
+already_AddRefed<InternalResponse>
+InternalResponse::Clone()
+{
+  nsRefPtr<InternalResponse> clone = new InternalResponse(*this);
+  clone->mHeaders = new InternalHeaders(*mHeaders);
+
+  if (!mBody) {
+    return clone.forget();
+  }
+
+  nsCOMPtr<nsIInputStream> clonedBody;
+  nsCOMPtr<nsIInputStream> replacementBody;
+
+  nsresult rv = NS_CloneInputStream(mBody, getter_AddRefs(clonedBody),
+                                    getter_AddRefs(replacementBody));
+  if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; }
+
+  clone->mBody.swap(clonedBody);
+  if (replacementBody) {
+    mBody.swap(replacementBody);
+  }
+
+  return clone.forget();
+}
+
 // static
 already_AddRefed<InternalResponse>
 InternalResponse::BasicResponse(InternalResponse* aInner)
 {
   MOZ_ASSERT(aInner);
   nsRefPtr<InternalResponse> basic = new InternalResponse(*aInner);
   basic->mType = ResponseType::Basic;
   basic->mHeaders = InternalHeaders::BasicHeaders(aInner->mHeaders);
+  basic->mBody.swap(aInner->mBody);
   return basic.forget();
 }
 
 // static
 already_AddRefed<InternalResponse>
 InternalResponse::CORSResponse(InternalResponse* aInner)
 {
   MOZ_ASSERT(aInner);
   nsRefPtr<InternalResponse> cors = new InternalResponse(*aInner);
   cors->mType = ResponseType::Cors;
   cors->mHeaders = InternalHeaders::CORSHeaders(aInner->mHeaders);
+  cors->mBody.swap(aInner->mBody);
   return cors.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/fetch/InternalResponse.h
+++ b/dom/fetch/InternalResponse.h
@@ -20,16 +20,18 @@ class InternalResponse MOZ_FINAL
 {
   friend class FetchDriver;
 
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InternalResponse)
 
   InternalResponse(uint16_t aStatus, const nsACString& aStatusText);
 
+  already_AddRefed<InternalResponse> Clone();
+
   static already_AddRefed<InternalResponse>
   NetworkError()
   {
     nsRefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString());
     response->mType = ResponseType::Error;
     return response.forget();
   }
 
@@ -120,18 +122,18 @@ public:
     MOZ_ASSERT(!mBody);
     mBody = aBody;
   }
 
 private:
   ~InternalResponse()
   { }
 
-  // Used to create filtered responses.
-  // Does not copy headers.
+  // Used to create filtered and cloned responses.
+  // Does not copy headers or body stream.
   explicit InternalResponse(const InternalResponse& aOther);
 
   ResponseType mType;
   nsCString mTerminationReason;
   nsCString mURL;
   bool mFinalURL;
   const uint16_t mStatus;
   const nsCString mStatusText;
--- a/dom/fetch/Request.cpp
+++ b/dom/fetch/Request.cpp
@@ -58,17 +58,17 @@ Request::Constructor(const GlobalObject&
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
 
   if (aInput.IsRequest()) {
     nsRefPtr<Request> inputReq = &aInput.GetAsRequest();
     nsCOMPtr<nsIInputStream> body;
     inputReq->GetBody(getter_AddRefs(body));
     if (body) {
       if (inputReq->BodyUsed()) {
-        aRv.ThrowTypeError(MSG_REQUEST_BODY_CONSUMED_ERROR);
+        aRv.ThrowTypeError(MSG_FETCH_BODY_CONSUMED_ERROR);
         return nullptr;
       } else {
         inputReq->SetBodyUsed();
       }
     }
 
     request = inputReq->GetInternalRequest();
   } else {
@@ -250,22 +250,30 @@ Request::Constructor(const GlobalObject&
   }
 
   nsRefPtr<Request> domRequest = new Request(global, request);
   domRequest->SetMimeType(aRv);
   return domRequest.forget();
 }
 
 already_AddRefed<Request>
-Request::Clone() const
+Request::Clone(ErrorResult& aRv) const
 {
-  // FIXME(nsm): Bug 1073231. This is incorrect, but the clone method isn't
-  // well defined yet.
-  nsRefPtr<Request> request = new Request(mOwner,
-                                          new InternalRequest(*mRequest));
+  if (BodyUsed()) {
+    aRv.ThrowTypeError(MSG_FETCH_BODY_CONSUMED_ERROR);
+    return nullptr;
+  }
+
+  nsRefPtr<InternalRequest> ir = mRequest->Clone();
+  if (!ir) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<Request> request = new Request(mOwner, ir);
   return request.forget();
 }
 
 Headers*
 Request::Headers_()
 {
   if (!mHeaders) {
     mHeaders = new Headers(mOwner, mRequest->Headers());
--- a/dom/fetch/Request.h
+++ b/dom/fetch/Request.h
@@ -110,17 +110,17 @@ public:
               const RequestInit& aInit, ErrorResult& rv);
 
   nsIGlobalObject* GetParentObject() const
   {
     return mOwner;
   }
 
   already_AddRefed<Request>
-  Clone() const;
+  Clone(ErrorResult& aRv) const;
 
   already_AddRefed<InternalRequest>
   GetInternalRequest();
 private:
   ~Request();
 
   nsCOMPtr<nsIGlobalObject> mOwner;
   nsRefPtr<InternalRequest> mRequest;
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -185,29 +185,33 @@ Response::Constructor(const GlobalObject
       return nullptr;
     }
   }
 
   r->SetMimeType(aRv);
   return r.forget();
 }
 
-// FIXME(nsm): Bug 1073231: This is currently unspecced!
 already_AddRefed<Response>
-Response::Clone()
+Response::Clone(ErrorResult& aRv) const
 {
-  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mOwner);
-  nsRefPtr<Response> response = new Response(global, mInternalResponse);
+  if (BodyUsed()) {
+    aRv.ThrowTypeError(MSG_FETCH_BODY_CONSUMED_ERROR);
+    return nullptr;
+  }
+
+  nsRefPtr<InternalResponse> ir = mInternalResponse->Clone();
+  nsRefPtr<Response> response = new Response(mOwner, ir);
   return response.forget();
 }
 
 void
 Response::SetBody(nsIInputStream* aBody)
 {
-  // FIXME(nsm): Do we flip bodyUsed here?
+  MOZ_ASSERT(!BodyUsed());
   mInternalResponse->SetBody(aBody);
 }
 
 Headers*
 Response::Headers_()
 {
   if (!mHeaders) {
     mHeaders = new Headers(mOwner, mInternalResponse->Headers());
--- a/dom/fetch/Response.h
+++ b/dom/fetch/Response.h
@@ -107,17 +107,17 @@ public:
               const ResponseInit& aInit, ErrorResult& rv);
 
   nsIGlobalObject* GetParentObject() const
   {
     return mOwner;
   }
 
   already_AddRefed<Response>
-  Clone();
+  Clone(ErrorResult& aRv) const;
 
   void
   SetBody(nsIInputStream* aBody);
 private:
   ~Response();
 
   nsCOMPtr<nsIGlobalObject> mOwner;
   nsRefPtr<InternalResponse> mInternalResponse;
--- a/dom/html/HTMLAnchorElement.cpp
+++ b/dom/html/HTMLAnchorElement.cpp
@@ -87,17 +87,17 @@ NS_IMPL_STRING_ATTR(HTMLAnchorElement, D
 
 int32_t
 HTMLAnchorElement::TabIndexDefault()
 {
   return 0;
 }
 
 void
-HTMLAnchorElement::GetItemValueText(nsAString& aValue)
+HTMLAnchorElement::GetItemValueText(DOMString& aValue)
 {
   GetHref(aValue);
 }
 
 void
 HTMLAnchorElement::SetItemValueText(const nsAString& aValue)
 {
   SetHref(aValue);
--- a/dom/html/HTMLAnchorElement.h
+++ b/dom/html/HTMLAnchorElement.h
@@ -100,47 +100,47 @@ public:
   {
     SetHTMLAttr(nsGkAtoms::href, aValue, rv);
   }
   // The XPCOM GetTarget is OK for us
   void SetTarget(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::target, aValue, rv);
   }
-  void GetDownload(nsString& aValue)
+  void GetDownload(DOMString& aValue)
   {
     GetHTMLAttr(nsGkAtoms::download, aValue);
   }
   void SetDownload(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::download, aValue, rv);
   }
   // The XPCOM GetPing is OK for us
   void SetPing(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::ping, aValue, rv);
   }
-  void GetRel(nsString& aValue)
+  void GetRel(DOMString& aValue)
   {
     GetHTMLAttr(nsGkAtoms::rel, aValue);
   }
   void SetRel(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::rel, aValue, rv);
   }
   nsDOMTokenList* RelList();
-  void GetHreflang(nsString& aValue)
+  void GetHreflang(DOMString& aValue)
   {
     GetHTMLAttr(nsGkAtoms::hreflang, aValue);
   }
   void SetHreflang(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::hreflang, aValue, rv);
   }
-  void GetType(nsString& aValue)
+  void GetType(DOMString& aValue)
   {
     GetHTMLAttr(nsGkAtoms::type, aValue);
   }
   void SetType(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::type, aValue, rv);
   }
   // The XPCOM GetText is OK for us
@@ -174,65 +174,65 @@ public:
 
   using Link::GetSearch;
   using Link::SetSearch;
 
   using Link::GetHash;
   using Link::SetHash;
 
   // The XPCOM URI decomposition attributes are fine for us
-  void GetCoords(nsString& aValue)
+  void GetCoords(DOMString& aValue)
   {
     GetHTMLAttr(nsGkAtoms::coords, aValue);
   }
   void SetCoords(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::coords, aValue, rv);
   }
-  void GetCharset(nsString& aValue)
+  void GetCharset(DOMString& aValue)
   {
     GetHTMLAttr(nsGkAtoms::charset, aValue);
   }
   void SetCharset(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::charset, aValue, rv);
   }
-  void GetName(nsString& aValue)
+  void GetName(DOMString& aValue)
   {
     GetHTMLAttr(nsGkAtoms::name, aValue);
   }
   void SetName(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::name, aValue, rv);
   }
-  void GetRev(nsString& aValue)
+  void GetRev(DOMString& aValue)
   {
     GetHTMLAttr(nsGkAtoms::rev, aValue);
   }
   void SetRev(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::rev, aValue, rv);
   }
-  void GetShape(nsString& aValue)
+  void GetShape(DOMString& aValue)
   {
     GetHTMLAttr(nsGkAtoms::shape, aValue);
   }
   void SetShape(const nsAString& aValue, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::shape, aValue, rv);
   }
   void Stringify(nsAString& aResult, ErrorResult& aError)
   {
     GetHref(aResult, aError);
   }
 
 protected:
   virtual ~HTMLAnchorElement();
 
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
   virtual JSObject* WrapNode(JSContext *aCx) MOZ_OVERRIDE;
   nsRefPtr<nsDOMTokenList > mRelList;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/html/HTMLAreaElement.cpp
+++ b/dom/html/HTMLAreaElement.cpp
@@ -62,17 +62,17 @@ NS_IMPL_STRING_ATTR(HTMLAreaElement, Dow
 
 int32_t
 HTMLAreaElement::TabIndexDefault()
 {
   return 0;
 }
 
 void
-HTMLAreaElement::GetItemValueText(nsAString& aValue)
+HTMLAreaElement::GetItemValueText(DOMString& aValue)
 {
   GetHref(aValue);
 }
 
 void
 HTMLAreaElement::SetItemValueText(const nsAString& aValue)
 {
   SetHref(aValue);
--- a/dom/html/HTMLAreaElement.h
+++ b/dom/html/HTMLAreaElement.h
@@ -112,17 +112,17 @@ public:
   }
 
   // The XPCOM GetPing is OK for us
   void SetPing(const nsAString& aPing, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::ping, aPing, aError);
   }
   
-  void GetRel(nsString& aValue)
+  void GetRel(DOMString& aValue)
   {
     GetHTMLAttr(nsGkAtoms::rel, aValue);
   }
 
   void SetRel(const nsAString& aRel, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::rel, aRel, aError);
   } 
@@ -175,17 +175,17 @@ public:
     GetHref(aResult, aError);
   }
 
 protected:
   virtual ~HTMLAreaElement();
 
   virtual JSObject* WrapNode(JSContext* aCx) MOZ_OVERRIDE;
 
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
   nsRefPtr<nsDOMTokenList > mRelList;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLAreaElement_h */
--- a/dom/html/HTMLBodyElement.cpp
+++ b/dom/html/HTMLBodyElement.cpp
@@ -205,104 +205,104 @@ HTMLBodyElement::SetBackground(const nsA
   ErrorResult rv;
   SetBackground(aBackground, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLBodyElement::GetBackground(nsAString& aBackground)
 {
-  nsString background;
+  DOMString background;
   GetBackground(background);
-  aBackground = background;
+  background.ToString(aBackground);
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 HTMLBodyElement::SetVLink(const nsAString& aVLink)
 {
   ErrorResult rv;
   SetVLink(aVLink, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLBodyElement::GetVLink(nsAString& aVLink)
 {
-  nsString vLink;
+  DOMString vLink;
   GetVLink(vLink);
-  aVLink = vLink;
+  vLink.ToString(aVLink);
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 HTMLBodyElement::SetALink(const nsAString& aALink)
 {
   ErrorResult rv;
   SetALink(aALink, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLBodyElement::GetALink(nsAString& aALink)
 {
-  nsString aLink;
+  DOMString aLink;
   GetALink(aLink);
-  aALink = aLink;
+  aLink.ToString(aALink);
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 HTMLBodyElement::SetLink(const nsAString& aLink)
 {
   ErrorResult rv;
   SetLink(aLink, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLBodyElement::GetLink(nsAString& aLink)
 {
-  nsString link;
+  DOMString link;
   GetLink(link);
-  aLink = link;
+  link.ToString(aLink);
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 HTMLBodyElement::SetText(const nsAString& aText)
 {
   ErrorResult rv;
   SetText(aText, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLBodyElement::GetText(nsAString& aText)
 {
-  nsString text;
+  DOMString text;
   GetText(text);
-  aText = text;
+  text.ToString(aText);
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 HTMLBodyElement::SetBgColor(const nsAString& aBgColor)
 {
   ErrorResult rv;
   SetBgColor(aBgColor, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLBodyElement::GetBgColor(nsAString& aBgColor)
 {
-  nsString bgColor;
+  DOMString bgColor;
   GetBgColor(bgColor);
-  aBgColor = bgColor;
+  bgColor.ToString(aBgColor);
   return NS_OK;
 }
 
 bool
 HTMLBodyElement::ParseAttribute(int32_t aNamespaceID,
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult)
--- a/dom/html/HTMLBodyElement.h
+++ b/dom/html/HTMLBodyElement.h
@@ -63,57 +63,57 @@ public:
 #define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_)                  \
   WINDOW_EVENT_HELPER(name_, OnBeforeUnloadEventHandlerNonNull)
 #include "mozilla/EventNameList.h" // IWYU pragma: keep
 #undef BEFOREUNLOAD_EVENT
 #undef WINDOW_EVENT
 #undef WINDOW_EVENT_HELPER
 #undef EVENT
 
-  void GetText(nsString& aText)
+  void GetText(DOMString& aText)
   {
     GetHTMLAttr(nsGkAtoms::text, aText);
   }
   void SetText(const nsAString& aText, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::text, aText, aError);
   }
-  void GetLink(nsString& aLink)
+  void GetLink(DOMString& aLink)
   {
     GetHTMLAttr(nsGkAtoms::link, aLink);
   }
   void SetLink(const nsAString& aLink, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::link, aLink, aError);
   }
-  void GetVLink(nsString& aVLink)
+  void GetVLink(DOMString& aVLink)
   {
     GetHTMLAttr(nsGkAtoms::vlink, aVLink);
   }
   void SetVLink(const nsAString& aVLink, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::vlink, aVLink, aError);
   }
-  void GetALink(nsString& aALink)
+  void GetALink(DOMString& aALink)
   {
     GetHTMLAttr(nsGkAtoms::alink, aALink);
   }
   void SetALink(const nsAString& aALink, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::alink, aALink, aError);
   }
-  void GetBgColor(nsString& aBgColor)
+  void GetBgColor(DOMString& aBgColor)
   {
     GetHTMLAttr(nsGkAtoms::bgcolor, aBgColor);
   }
   void SetBgColor(const nsAString& aBgColor, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::bgcolor, aBgColor, aError);
   }
-  void GetBackground(nsString& aBackground)
+  void GetBackground(DOMString& aBackground)
   {
     GetHTMLAttr(nsGkAtoms::background, aBackground);
   }
   void SetBackground(const nsAString& aBackground, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::background, aBackground, aError);
   }
 
--- a/dom/html/HTMLDataElement.cpp
+++ b/dom/html/HTMLDataElement.cpp
@@ -25,17 +25,17 @@ NS_IMPL_ELEMENT_CLONE(HTMLDataElement)
 
 JSObject*
 HTMLDataElement::WrapNode(JSContext* aCx)
 {
   return HTMLDataElementBinding::Wrap(aCx, this);
 }
 
 void
-HTMLDataElement::GetItemValueText(nsAString& text)
+HTMLDataElement::GetItemValueText(DOMString& text)
 {
   GetValue(text);
 }
 
 void
 HTMLDataElement::SetItemValueText(const nsAString& text)
 {
   ErrorResult rv;
--- a/dom/html/HTMLDataElement.h
+++ b/dom/html/HTMLDataElement.h
@@ -15,27 +15,27 @@ namespace mozilla {
 namespace dom {
 
 class HTMLDataElement MOZ_FINAL : public nsGenericHTMLElement
 {
 public:
   explicit HTMLDataElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
 
   // HTMLDataElement WebIDL
-  void GetValue(nsAString& aValue)
+  void GetValue(DOMString& aValue)
   {
     GetHTMLAttr(nsGkAtoms::value, aValue);
   }
 
   void SetValue(const nsAString& aValue, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::value, aValue, aError);
   }
 
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
   virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const MOZ_OVERRIDE;
 
 protected:
   virtual ~HTMLDataElement();
 
   virtual JSObject* WrapNode(JSContext* aCx) MOZ_OVERRIDE;
 };
--- a/dom/html/HTMLDivElement.h
+++ b/dom/html/HTMLDivElement.h
@@ -22,29 +22,29 @@ public:
   }
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMHTMLDivElement
   NS_IMETHOD GetAlign(nsAString& aAlign) MOZ_OVERRIDE
   {
-    nsString align;
+    DOMString align;
     GetAlign(align);
-    aAlign = align;
+    align.ToString(aAlign);
     return NS_OK;
   }
   NS_IMETHOD SetAlign(const nsAString& aAlign) MOZ_OVERRIDE
   {
     mozilla::ErrorResult rv;
     SetAlign(aAlign, rv);
     return rv.ErrorCode();
   }
 
-  void GetAlign(nsString& aAlign)
+  void GetAlign(DOMString& aAlign)
   {
     GetHTMLAttr(nsGkAtoms::align, aAlign);
   }
   void SetAlign(const nsAString& aAlign, mozilla::ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
 
--- a/dom/html/HTMLFontElement.h
+++ b/dom/html/HTMLFontElement.h
@@ -14,33 +14,33 @@ namespace dom {
 class HTMLFontElement MOZ_FINAL : public nsGenericHTMLElement
 {
 public:
   explicit HTMLFontElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
     : nsGenericHTMLElement(aNodeInfo)
   {
   }
 
-  void GetColor(nsString& aColor)
+  void GetColor(DOMString& aColor)
   {
     GetHTMLAttr(nsGkAtoms::color, aColor);
   }
   void SetColor(const nsAString& aColor, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::color, aColor, aError);
   }
-  void GetFace(nsString& aFace)
+  void GetFace(DOMString& aFace)
   {
     GetHTMLAttr(nsGkAtoms::face, aFace);
   }
   void SetFace(const nsAString& aFace, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::face, aFace, aError);
   }
-  void GetSize(nsString& aSize)
+  void GetSize(DOMString& aSize)
   {
     GetHTMLAttr(nsGkAtoms::size, aSize);
   }
   void SetSize(const nsAString& aSize, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::size, aSize, aError);
   }
 
--- a/dom/html/HTMLFrameSetElement.cpp
+++ b/dom/html/HTMLFrameSetElement.cpp
@@ -34,36 +34,36 @@ HTMLFrameSetElement::SetCols(const nsASt
   ErrorResult rv;
   SetCols(aCols, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLFrameSetElement::GetCols(nsAString& aCols)
 {
-  nsString cols;
+  DOMString cols;
   GetCols(cols);
-  aCols = cols;
+  cols.ToString(aCols);
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 HTMLFrameSetElement::SetRows(const nsAString& aRows)
 {
   ErrorResult rv;
   SetRows(aRows, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLFrameSetElement::GetRows(nsAString& aRows)
 {
-  nsString rows;
+  DOMString rows;
   GetRows(rows);
-  aRows = rows;
+  rows.ToString(aRows);
   return NS_OK;
 }
 
 nsresult
 HTMLFrameSetElement::SetAttr(int32_t aNameSpaceID,
                              nsIAtom* aAttribute,
                              nsIAtom* aPrefix,
                              const nsAString& aValue,
--- a/dom/html/HTMLFrameSetElement.h
+++ b/dom/html/HTMLFrameSetElement.h
@@ -58,25 +58,25 @@ public:
   NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLFrameSetElement, frameset)
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMHTMLFrameSetElement
   NS_DECL_NSIDOMHTMLFRAMESETELEMENT
 
-  void GetCols(nsString& aCols)
+  void GetCols(DOMString& aCols)
   {
     GetHTMLAttr(nsGkAtoms::cols, aCols);
   }
   void SetCols(const nsAString& aCols, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::cols, aCols, aError);
   }
-  void GetRows(nsString& aRows)
+  void GetRows(DOMString& aRows)
   {
     GetHTMLAttr(nsGkAtoms::rows, aRows);
   }
   void SetRows(const nsAString& aRows, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::rows, aRows, aError);
   }
 
--- a/dom/html/HTMLIFrameElement.cpp
+++ b/dom/html/HTMLIFrameElement.cpp
@@ -41,17 +41,17 @@ NS_IMPL_STRING_ATTR(HTMLIFrameElement, M
 NS_IMPL_STRING_ATTR(HTMLIFrameElement, Name, name)
 NS_IMPL_STRING_ATTR(HTMLIFrameElement, Scrolling, scrolling)
 NS_IMPL_URI_ATTR(HTMLIFrameElement, Src, src)
 NS_IMPL_STRING_ATTR(HTMLIFrameElement, Width, width)
 NS_IMPL_BOOL_ATTR(HTMLIFrameElement, AllowFullscreen, allowfullscreen)
 NS_IMPL_STRING_ATTR(HTMLIFrameElement, Srcdoc, srcdoc)
 
 void
-HTMLIFrameElement::GetItemValueText(nsAString& aValue)
+HTMLIFrameElement::GetItemValueText(DOMString& aValue)
 {
   GetSrc(aValue);
 }
 
 void
 HTMLIFrameElement::SetItemValueText(const nsAString& aValue)
 {
   SetSrc(aValue);
--- a/dom/html/HTMLIFrameElement.h
+++ b/dom/html/HTMLIFrameElement.h
@@ -172,17 +172,17 @@ public:
   }
   using nsGenericHTMLFrameElement::SetMozbrowser;
   // nsGenericHTMLFrameElement::GetFrameLoader is fine
   // nsGenericHTMLFrameElement::GetAppManifestURL is fine
 
 protected:
   virtual ~HTMLIFrameElement();
 
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
 
   virtual JSObject* WrapNode(JSContext* aCx) MOZ_OVERRIDE;
 
 private:
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
                                     nsRuleData* aData);
 };
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -176,17 +176,17 @@ HTMLImageElement::GetCurrentSrc(nsAStrin
   } else {
     SetDOMStringToNull(aValue);
   }
 
   return NS_OK;
 }
 
 void
-HTMLImageElement::GetItemValueText(nsAString& aValue)
+HTMLImageElement::GetItemValueText(DOMString& aValue)
 {
   GetSrc(aValue);
 }
 
 void
 HTMLImageElement::SetItemValueText(const nsAString& aValue)
 {
   SetSrc(aValue);
--- a/dom/html/HTMLImageElement.h
+++ b/dom/html/HTMLImageElement.h
@@ -306,17 +306,17 @@ protected:
   // If the node's srcset/sizes make for an invalid selector, returns
   // false. This does not guarantee the resulting selector matches an image,
   // only that it is valid.
   bool TryCreateResponsiveSelector(nsIContent *aSourceNode,
                                    const nsAString *aSrcset = nullptr,
                                    const nsAString *aSizes = nullptr);
 
   CSSIntPoint GetXY();
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
   virtual JSObject* WrapNode(JSContext *aCx) MOZ_OVERRIDE;
   void UpdateFormOwner();
 
   virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                  const nsAttrValueOrString* aValue,
                                  bool aNotify) MOZ_OVERRIDE;
 
--- a/dom/html/HTMLLIElement.h
+++ b/dom/html/HTMLLIElement.h
@@ -33,17 +33,17 @@ public:
                                 nsIAtom* aAttribute,
                                 const nsAString& aValue,
                                 nsAttrValue& aResult) MOZ_OVERRIDE;
   NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE;
   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const MOZ_OVERRIDE;
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL API
-  void GetType(nsString& aType)
+  void GetType(DOMString& aType)
   {
     GetHTMLAttr(nsGkAtoms::type, aType);
   }
   void SetType(const nsAString& aType, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::type, aType, rv);
   }
   int32_t Value() const
--- a/dom/html/HTMLLegendElement.h
+++ b/dom/html/HTMLLegendElement.h
@@ -62,17 +62,17 @@ public:
   }
 
   /**
    * WebIDL Interface
    */
 
   already_AddRefed<HTMLFormElement> GetForm();
 
-  void GetAlign(nsAString& aAlign)
+  void GetAlign(DOMString& aAlign)
   {
     GetHTMLAttr(nsGkAtoms::align, aAlign);
   }
 
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
--- a/dom/html/HTMLLinkElement.cpp
+++ b/dom/html/HTMLLinkElement.cpp
@@ -114,17 +114,17 @@ NS_IMPL_URI_ATTR(HTMLLinkElement, Href, 
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Hreflang, hreflang)
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Media, media)
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Rel, rel)
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Rev, rev)
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Target, target)
 NS_IMPL_STRING_ATTR(HTMLLinkElement, Type, type)
 
 void
-HTMLLinkElement::GetItemValueText(nsAString& aValue)
+HTMLLinkElement::GetItemValueText(DOMString& aValue)
 {
   GetHref(aValue);
 }
 
 void
 HTMLLinkElement::SetItemValueText(const nsAString& aValue)
 {
   SetHref(aValue);
--- a/dom/html/HTMLLinkElement.h
+++ b/dom/html/HTMLLinkElement.h
@@ -156,17 +156,17 @@ protected:
   virtual void GetStyleSheetInfo(nsAString& aTitle,
                                  nsAString& aType,
                                  nsAString& aMedia,
                                  bool* aIsScoped,
                                  bool* aIsAlternate) MOZ_OVERRIDE;
   virtual CORSMode GetCORSMode() const MOZ_OVERRIDE;
 protected:
   // nsGenericHTMLElement
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
   nsRefPtr<nsDOMTokenList > mRelList;
 private:
   nsRefPtr<ImportLoader> mImportLoader;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -80,16 +80,17 @@
 #include "mozilla/dom/WakeLock.h"
 
 #include "mozilla/dom/AudioTrack.h"
 #include "mozilla/dom/AudioTrackList.h"
 #include "mozilla/dom/VideoTrack.h"
 #include "mozilla/dom/VideoTrackList.h"
 #include "mozilla/dom/TextTrack.h"
 #include "nsIContentPolicy.h"
+#include "mozilla/Telemetry.h"
 
 #include "ImageContainer.h"
 #include "nsRange.h"
 #include <algorithm>
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gMediaElementLog;
 static PRLogModuleInfo* gMediaElementEventsLog;
@@ -2135,17 +2136,17 @@ HTMLMediaElement::~HTMLMediaElement()
   if (mChannel) {
     mChannel->Cancel(NS_BINDING_ABORTED);
   }
 
   WakeLockRelease();
 }
 
 void
-HTMLMediaElement::GetItemValueText(nsAString& aValue)
+HTMLMediaElement::GetItemValueText(DOMString& aValue)
 {
   // Can't call GetSrc because we don't have a JSContext
   GetURIAttr(nsGkAtoms::src, nullptr, aValue);
 }
 
 void
 HTMLMediaElement::SetItemValueText(const nsAString& aValue)
 {
@@ -2543,21 +2544,71 @@ nsresult HTMLMediaElement::BindToTree(ns
     // When the MediaElement is binding to tree, the dormant status is
     // aligned to document's hidden status.
     mDecoder->NotifyOwnerActivityChanged();
   }
 
   return rv;
 }
 
+void
+HTMLMediaElement::ReportMSETelemetry()
+{
+  // Report telemetry for videos when a page is unloaded. We
+  // want to know data on what state the video is at when
+  // the user has exited.
+  enum UnloadedState {
+    ENDED = 0,
+    PAUSED = 1,
+    STALLED = 2,
+    SEEKING = 3,
+    OTHER = 4
+  };
+
+  UnloadedState state = OTHER;
+  if (Seeking()) {
+    state = SEEKING;
+  }
+  else if (Ended()) {
+    state = ENDED;
+  }
+  else if (Paused()) {
+    state = PAUSED;
+  }
+  else {
+    // For buffering we check if the current playback position is at the end
+    // of a buffered range, within a margin of error. We also consider to be
+    // buffering if the last frame status was buffering and the ready state is
+    // HAVE_CURRENT_DATA to account for times where we are in a buffering state
+    // regardless of what actual data we have buffered.
+    bool stalled = false;
+    nsRefPtr<TimeRanges> ranges = Buffered();
+    const double errorMargin = 0.05;
+    double t = CurrentTime();
+    TimeRanges::index_type index = ranges->Find(t, errorMargin);
+    ErrorResult ignore;
+    stalled = index != TimeRanges::NoIndex &&
+              (ranges->End(index, ignore) - t) < errorMargin;
+    stalled |= mLastNextFrameStatus == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING &&
+                                       mReadyState == HTMLMediaElement::HAVE_CURRENT_DATA;
+    if (stalled) {
+      state = STALLED;
+    }
+  }
+
+  Telemetry::Accumulate(Telemetry::VIDEO_MSE_UNLOAD_STATE, state);
+  LOG(PR_LOG_DEBUG, ("%p VIDEO_MSE_UNLOAD_STATE = %d", this, state));
+}
+
 void HTMLMediaElement::UnbindFromTree(bool aDeep,
                                       bool aNullParent)
 {
-  if (!mPaused && mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY)
+  if (!mPaused && mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
     Pause();
+  }
 
   mElementInTreeState = ELEMENT_NOT_INTREE_HAD_INTREE;
 
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
 
   if (mDecoder) {
     MOZ_ASSERT(IsHidden());
     mDecoder->NotifyOwnerActivityChanged();
@@ -3696,16 +3747,20 @@ void HTMLMediaElement::UpdateMediaSize(n
   UpdateReadyStateForData(mLastNextFrameStatus);
 }
 
 void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendEvents)
 {
   if (aPauseElement != mPausedForInactiveDocumentOrChannel) {
     mPausedForInactiveDocumentOrChannel = aPauseElement;
     if (aPauseElement) {
+      if (mMediaSource) {
+        ReportMSETelemetry();
+      }
+
 #ifdef MOZ_EME
       // For EME content, force destruction of the CDM client (and CDM
       // instance if this is the last client for that CDM instance) and
       // the CDM's decoder. This ensures the CDM gets reliable and prompt
       // shutdown notifications, as it may have book-keeping it needs
       // to do on shutdown.
       if (mMediaKeys) {
         mMediaKeys->Shutdown();
@@ -3737,21 +3792,31 @@ void HTMLMediaElement::SuspendOrResumeEl
       if (mEventDeliveryPaused) {
         mEventDeliveryPaused = false;
         DispatchPendingMediaEvents();
       }
     }
   }
 }
 
+bool HTMLMediaElement::IsBeingDestroyed()
+{
+  nsIDocument* ownerDoc = OwnerDoc();
+  nsIDocShell* docShell = ownerDoc ? ownerDoc->GetDocShell() : nullptr;
+  bool isBeingDestroyed = false;
+  if (docShell) {
+    docShell->IsBeingDestroyed(&isBeingDestroyed);
+  }
+  return isBeingDestroyed;
+}
+
 void HTMLMediaElement::NotifyOwnerDocumentActivityChanged()
 {
   nsIDocument* ownerDoc = OwnerDoc();
-
-  if (mDecoder) {
+  if (mDecoder && !IsBeingDestroyed()) {
     mDecoder->SetElementVisibility(!ownerDoc->Hidden());
     mDecoder->NotifyOwnerActivityChanged();
   }
 
   // SetVisibilityState will update mMuted with MUTED_BY_AUDIO_CHANNEL via the
   // CanPlayChanged callback.
   if (UseAudioChannelService() && mPlayingThroughTheAudioChannel &&
       mAudioChannelAgent) {
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -615,24 +615,29 @@ public:
 
   /**
    * A public wrapper for FinishDecoderSetup()
    */
   nsresult FinishDecoderSetup(MediaDecoder* aDecoder, MediaResource* aStream) {
     return FinishDecoderSetup(aDecoder, aStream, nullptr, nullptr);
   }
 
+  // Returns true if the media element is being destroyed. Used in
+  // dormancy checks to prevent dormant processing for an element
+  // that will soon be gone.
+  bool IsBeingDestroyed();
+
 protected:
   virtual ~HTMLMediaElement();
 
   class MediaLoadListener;
   class MediaStreamTracksAvailableCallback;
   class StreamListener;
 
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
 
   class WakeLockBoolWrapper {
   public:
     explicit WakeLockBoolWrapper(bool val = false)
       : mValue(val), mCanPlay(true), mOuter(nullptr) {}
 
     ~WakeLockBoolWrapper();
@@ -958,16 +963,18 @@ protected:
   // Return true if decoding should be paused
   virtual bool GetPaused() MOZ_FINAL MOZ_OVERRIDE
   {
     bool isPaused = false;
     GetPaused(&isPaused);
     return isPaused;
   }
 
+  void ReportMSETelemetry();
+
   // Check the permissions for audiochannel.
   bool CheckAudioChannelPermissions(const nsAString& aType);
 
   // This method does the check for muting/fading/unmuting the audio channel.
   nsresult UpdateChannelMuteState(mozilla::dom::AudioChannelState aCanPlay);
 
   // Seeks to aTime seconds. aSeekType can be Exact to seek to exactly the
   // seek target, or PrevSyncPoint if a quicker but less precise seek is
--- a/dom/html/HTMLMetaElement.cpp
+++ b/dom/html/HTMLMetaElement.cpp
@@ -31,17 +31,17 @@ NS_IMPL_ELEMENT_CLONE(HTMLMetaElement)
 
 
 NS_IMPL_STRING_ATTR(HTMLMetaElement, Content, content)
 NS_IMPL_STRING_ATTR(HTMLMetaElement, HttpEquiv, httpEquiv)
 NS_IMPL_STRING_ATTR(HTMLMetaElement, Name, name)
 NS_IMPL_STRING_ATTR(HTMLMetaElement, Scheme, scheme)
 
 void
-HTMLMetaElement::GetItemValueText(nsAString& aValue)
+HTMLMetaElement::GetItemValueText(DOMString& aValue)
 {
   GetContent(aValue);
 }
 
 void
 HTMLMetaElement::SetItemValueText(const nsAString& aValue)
 {
   SetContent(aValue);
--- a/dom/html/HTMLMetaElement.h
+++ b/dom/html/HTMLMetaElement.h
@@ -59,16 +59,16 @@ public:
     SetHTMLAttr(nsGkAtoms::scheme, aScheme, aRv);
   }
 
   virtual JSObject* WrapNode(JSContext* aCx) MOZ_OVERRIDE;
 
 protected:
   virtual ~HTMLMetaElement();
 
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLMetaElement_h
--- a/dom/html/HTMLModElement.h
+++ b/dom/html/HTMLModElement.h
@@ -23,17 +23,17 @@ public:
   void GetCite(nsString& aCite)
   {
     GetHTMLURIAttr(nsGkAtoms::cite, aCite);
   }
   void SetCite(const nsAString& aCite, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::cite, aCite, aRv);
   }
-  void GetDateTime(nsAString& aDateTime)
+  void GetDateTime(DOMString& aDateTime)
   {
     GetHTMLAttr(nsGkAtoms::datetime, aDateTime);
   }
   void SetDateTime(const nsAString& aDateTime, ErrorResult& aRv)
   {
     SetHTMLAttr(nsGkAtoms::datetime, aDateTime, aRv);
   }
 
--- a/dom/html/HTMLObjectElement.cpp
+++ b/dom/html/HTMLObjectElement.cpp
@@ -106,17 +106,17 @@ NS_IMPL_NSICONSTRAINTVALIDATION(HTMLObje
 
 NS_IMETHODIMP
 HTMLObjectElement::GetForm(nsIDOMHTMLFormElement **aForm)
 {
   return nsGenericHTMLFormElement::GetForm(aForm);
 }
 
 void
-HTMLObjectElement::GetItemValueText(nsAString& aValue)
+HTMLObjectElement::GetItemValueText(DOMString& aValue)
 {
   GetData(aValue);
 }
 
 void
 HTMLObjectElement::SetItemValueText(const nsAString& aValue)
 {
   SetData(aValue);
--- a/dom/html/HTMLObjectElement.h
+++ b/dom/html/HTMLObjectElement.h
@@ -230,17 +230,17 @@ private:
   void StartObjectLoad(bool aNotify);
 
   /**
    * Returns if the element is currently focusable regardless of it's tabindex
    * value. This is used to know the default tabindex value.
    */
   bool IsFocusableForTabIndex();
   
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
 
   virtual ~HTMLObjectElement();
 
   virtual JSObject* WrapNode(JSContext *aCx) MOZ_OVERRIDE;
 
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
                                     nsRuleData* aData);
--- a/dom/html/HTMLSharedListElement.h
+++ b/dom/html/HTMLSharedListElement.h
@@ -53,17 +53,17 @@ public:
   int32_t Start() const
   {
     return GetIntAttr(nsGkAtoms::start, 1);
   }
   void SetStart(int32_t aStart, mozilla::ErrorResult& rv)
   {
     SetHTMLIntAttr(nsGkAtoms::start, aStart, rv);
   }
-  void GetType(nsString& aType)
+  void GetType(DOMString& aType)
   {
     GetHTMLAttr(nsGkAtoms::type, aType);
   }
   void SetType(const nsAString& aType, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::type, aType, rv);
   }
   bool Compact() const
--- a/dom/html/HTMLSharedObjectElement.cpp
+++ b/dom/html/HTMLSharedObjectElement.cpp
@@ -31,17 +31,17 @@ HTMLSharedObjectElement::HTMLSharedObjec
   RegisterActivityObserver();
   SetIsNetworkCreated(aFromParser == FROM_PARSER_NETWORK);
 
   // By default we're in the loading state
   AddStatesSilently(NS_EVENT_STATE_LOADING);
 }
 
 void
-HTMLSharedObjectElement::GetItemValueText(nsAString& aValue)
+HTMLSharedObjectElement::GetItemValueText(DOMString& aValue)
 {
   if (mNodeInfo->Equals(nsGkAtoms::applet)) {
     nsGenericHTMLElement::GetItemValueText(aValue);
   } else {
     GetSrc(aValue);
   }
 }
 
--- a/dom/html/HTMLSharedObjectElement.h
+++ b/dom/html/HTMLSharedObjectElement.h
@@ -201,17 +201,17 @@ private:
            nsGkAtoms::code :
            nsGkAtoms::src;
   }
 
   // mIsDoneAddingChildren is only really used for <applet>.  This boolean is
   // always true for <embed>, per the documentation in nsIContent.h.
   bool mIsDoneAddingChildren;
 
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
 
   virtual JSObject* WrapNode(JSContext *aCx) MOZ_OVERRIDE;
 
   static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
                                     nsRuleData* aData);
 };
 
--- a/dom/html/HTMLSourceElement.cpp
+++ b/dom/html/HTMLSourceElement.cpp
@@ -116,17 +116,17 @@ HTMLSourceElement::AfterSetAttr(int32_t 
     }
   }
 
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
                                             aValue, aNotify);
 }
 
 void
-HTMLSourceElement::GetItemValueText(nsAString& aValue)
+HTMLSourceElement::GetItemValueText(DOMString& aValue)
 {
   GetSrc(aValue);
 }
 
 void
 HTMLSourceElement::SetItemValueText(const nsAString& aValue)
 {
   SetSrc(aValue);
--- a/dom/html/HTMLSourceElement.h
+++ b/dom/html/HTMLSourceElement.h
@@ -55,59 +55,59 @@ public:
   {
     GetURIAttr(nsGkAtoms::src, nullptr, aSrc);
   }
   void SetSrc(const nsAString& aSrc, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::src, aSrc, rv);
   }
 
-  void GetType(nsString& aType)
+  void GetType(DOMString& aType)
   {
     GetHTMLAttr(nsGkAtoms::type, aType);
   }
   void SetType(const nsAString& aType, ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::type, aType, rv);
   }
 
-  void GetSrcset(nsString& aSrcset)
+  void GetSrcset(DOMString& aSrcset)
   {
     GetHTMLAttr(nsGkAtoms::srcset, aSrcset);
   }
   void SetSrcset(const nsAString& aSrcset, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::srcset, aSrcset, rv);
   }
 
-  void GetSizes(nsString& aSizes)
+  void GetSizes(DOMString& aSizes)
   {
     GetHTMLAttr(nsGkAtoms::sizes, aSizes);
   }
   void SetSizes(const nsAString& aSizes, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::sizes, aSizes, rv);
   }
 
-  void GetMedia(nsString& aMedia)
+  void GetMedia(DOMString& aMedia)
   {
     GetHTMLAttr(nsGkAtoms::media, aMedia);
   }
   void SetMedia(const nsAString& aMedia, mozilla::ErrorResult& rv)
   {
     SetHTMLAttr(nsGkAtoms::media, aMedia, rv);
   }
 
 protected:
   virtual ~HTMLSourceElement();
 
   virtual JSObject* WrapNode(JSContext* aCx) MOZ_OVERRIDE;
 
 protected:
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
 
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue,
                                 bool aNotify) MOZ_OVERRIDE;
 
 
 private:
--- a/dom/html/HTMLTableCaptionElement.h
+++ b/dom/html/HTMLTableCaptionElement.h
@@ -23,17 +23,17 @@ public:
   }
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMHTMLTableCaptionElement
   NS_DECL_NSIDOMHTMLTABLECAPTIONELEMENT
 
-  void GetAlign(nsString& aAlign)
+  void GetAlign(DOMString& aAlign)
   {
     GetHTMLAttr(nsGkAtoms::align, aAlign);
   }
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
 
--- a/dom/html/HTMLTableCellElement.cpp
+++ b/dom/html/HTMLTableCellElement.cpp
@@ -122,155 +122,155 @@ HTMLTableCellElement::SetAbbr(const nsAS
   ErrorResult rv;
   SetAbbr(aAbbr, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::GetAbbr(nsAString& aAbbr)
 {
-  nsString abbr;
+  DOMString abbr;
   GetAbbr(abbr);
-  aAbbr = abbr;
+  abbr.ToString(aAbbr);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::SetAxis(const nsAString& aAxis)
 {
   ErrorResult rv;
   SetAxis(aAxis, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::GetAxis(nsAString& aAxis)
 {
-  nsString axis;
+  DOMString axis;
   GetAxis(axis);
-  aAxis = axis;
+  axis.ToString(aAxis);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::SetAlign(const nsAString& aAlign)
 {
   ErrorResult rv;
   SetAlign(aAlign, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::GetAlign(nsAString& aAlign)
 {
-  nsString align;
+  DOMString align;
   GetAlign(align);
-  aAlign = align;
+  align.ToString(aAlign);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::SetVAlign(const nsAString& aVAlign)
 {
   ErrorResult rv;
   SetVAlign(aVAlign, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::GetVAlign(nsAString& aVAlign)
 {
-  nsString vAlign;
+  DOMString vAlign;
   GetVAlign(vAlign);
-  aVAlign = vAlign;
+  vAlign.ToString(aVAlign);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::SetCh(const nsAString& aCh)
 {
   ErrorResult rv;
   SetCh(aCh, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::GetCh(nsAString& aCh)
 {
-  nsString ch;
+  DOMString ch;
   GetCh(ch);
-  aCh = ch;
+  ch.ToString(aCh);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::SetChOff(const nsAString& aChOff)
 {
   ErrorResult rv;
   SetChOff(aChOff, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::GetChOff(nsAString& aChOff)
 {
-  nsString chOff;
+  DOMString chOff;
   GetChOff(chOff);
-  aChOff = chOff;
+  chOff.ToString(aChOff);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::SetBgColor(const nsAString& aBgColor)
 {
   ErrorResult rv;
   SetBgColor(aBgColor, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::GetBgColor(nsAString& aBgColor)
 {
-  nsString bgColor;
+  DOMString bgColor;
   GetBgColor(bgColor);
-  aBgColor = bgColor;
+  bgColor.ToString(aBgColor);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::SetHeight(const nsAString& aHeight)
 {
   ErrorResult rv;
   SetHeight(aHeight, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::GetHeight(nsAString& aHeight)
 {
-  nsString height;
+  DOMString height;
   GetHeight(height);
-  aHeight = height;
+  height.ToString(aHeight);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::SetWidth(const nsAString& aWidth)
 {
   ErrorResult rv;
   SetWidth(aWidth, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::GetWidth(nsAString& aWidth)
 {
-  nsString width;
+  DOMString width;
   GetWidth(width);
-  aWidth = width;
+  width.ToString(aWidth);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::SetNoWrap(bool aNoWrap)
 {
   ErrorResult rv;
   SetNoWrap(aNoWrap, rv);
@@ -290,36 +290,36 @@ HTMLTableCellElement::SetScope(const nsA
   ErrorResult rv;
   SetScope(aScope, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::GetScope(nsAString& aScope)
 {
-  nsString scope;
+  DOMString scope;
   GetScope(scope);
-  aScope = scope;
+  scope.ToString(aScope);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::SetHeaders(const nsAString& aHeaders)
 {
   ErrorResult rv;
   SetHeaders(aHeaders, rv);
   return rv.ErrorCode();
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::GetHeaders(nsAString& aHeaders)
 {
-  nsString headers;
+  DOMString headers;
   GetHeaders(headers);
-  aHeaders = headers;
+  headers.ToString(aHeaders);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLTableCellElement::SetColSpan(int32_t aColSpan)
 {
   ErrorResult rv;
   SetColSpan(aColSpan, rv);
@@ -344,17 +344,17 @@ HTMLTableCellElement::SetRowSpan(int32_t
 NS_IMETHODIMP
 HTMLTableCellElement::GetRowSpan(int32_t* aRowSpan)
 {
   *aRowSpan = RowSpan();
   return NS_OK;
 }
 
 void
-HTMLTableCellElement::GetAlign(nsString& aValue)
+HTMLTableCellElement::GetAlign(DOMString& aValue)
 {
   if (!GetAttr(kNameSpaceID_None, nsGkAtoms::align, aValue)) {
     // There's no align attribute, ask the row for the alignment.
     HTMLTableRowElement* row = GetRow();
     if (row) {
       row->GetAlign(aValue);
     }
   }
--- a/dom/html/HTMLTableCellElement.h
+++ b/dom/html/HTMLTableCellElement.h
@@ -44,104 +44,104 @@ public:
   {
     return GetIntAttr(nsGkAtoms::rowspan, 1);
   }
   void SetRowSpan(uint32_t aRowSpan, ErrorResult& aError)
   {
     SetHTMLIntAttr(nsGkAtoms::rowspan, aRowSpan, aError);
   }
   //already_AddRefed<nsDOMSettableTokenList> Headers() const;
-  void GetHeaders(nsString& aHeaders)
+  void GetHeaders(DOMString& aHeaders)
   {
     GetHTMLAttr(nsGkAtoms::headers, aHeaders);
   }
   void SetHeaders(const nsAString& aHeaders, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::headers, aHeaders, aError);
   }
   int32_t CellIndex() const;
 
-  void GetAbbr(nsString& aAbbr)
+  void GetAbbr(DOMString& aAbbr)
   {
     GetHTMLAttr(nsGkAtoms::abbr, aAbbr);
   }
   void SetAbbr(const nsAString& aAbbr, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::abbr, aAbbr, aError);
   }
-  void GetScope(nsString& aScope)
+  void GetScope(DOMString& aScope)
   {
     GetHTMLAttr(nsGkAtoms::scope, aScope);
   }
   void SetScope(const nsAString& aScope, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::scope, aScope, aError);
   }
-  void GetAlign(nsString& aAlign);
+  void GetAlign(DOMString& aAlign);
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
-  void GetAxis(nsString& aAxis)
+  void GetAxis(DOMString& aAxis)
   {
     GetHTMLAttr(nsGkAtoms::axis, aAxis);
   }
   void SetAxis(const nsAString& aAxis, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::axis, aAxis, aError);
   }
-  void GetHeight(nsString& aHeight)
+  void GetHeight(DOMString& aHeight)
   {
     GetHTMLAttr(nsGkAtoms::height, aHeight);
   }
   void SetHeight(const nsAString& aHeight, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::height, aHeight, aError);
   }
-  void GetWidth(nsString& aWidth)
+  void GetWidth(DOMString& aWidth)
   {
     GetHTMLAttr(nsGkAtoms::width, aWidth);
   }
   void SetWidth(const nsAString& aWidth, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::width, aWidth, aError);
   }
-  void GetCh(nsString& aCh)
+  void GetCh(DOMString& aCh)
   {
     GetHTMLAttr(nsGkAtoms::_char, aCh);
   }
   void SetCh(const nsAString& aCh, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::_char, aCh, aError);
   }
-  void GetChOff(nsString& aChOff)
+  void GetChOff(DOMString& aChOff)
   {
     GetHTMLAttr(nsGkAtoms::charoff, aChOff);
   }
   void SetChOff(const nsAString& aChOff, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::charoff, aChOff, aError);
   }
   bool NoWrap()
   {
     return GetBoolAttr(nsGkAtoms::nowrap);
   }
   void SetNoWrap(bool aNoWrap, ErrorResult& aError)
   {
     SetHTMLBoolAttr(nsGkAtoms::nowrap, aNoWrap, aError);
   }
-  void GetVAlign(nsString& aVAlign)
+  void GetVAlign(DOMString& aVAlign)
   {
     GetHTMLAttr(nsGkAtoms::valign, aVAlign);
   }
   void SetVAlign(const nsAString& aVAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::valign, aVAlign, aError);
   }
-  void GetBgColor(nsString& aBgColor)
+  void GetBgColor(DOMString& aBgColor)
   {
     GetHTMLAttr(nsGkAtoms::bgcolor, aBgColor);
   }
   void SetBgColor(const nsAString& aBgColor, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::bgcolor, aBgColor, aError);
   }
 
--- a/dom/html/HTMLTableColElement.h
+++ b/dom/html/HTMLTableColElement.h
@@ -24,49 +24,49 @@ public:
   {
     return GetIntAttr(nsGkAtoms::span, 1);
   }
   void SetSpan(uint32_t aSpan, ErrorResult& aError)
   {
     SetHTMLIntAttr(nsGkAtoms::span, aSpan, aError);
   }
 
-  void GetAlign(nsString& aAlign)
+  void GetAlign(DOMString& aAlign)
   {
     GetHTMLAttr(nsGkAtoms::align, aAlign);
   }
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
-  void GetCh(nsString& aCh)
+  void GetCh(DOMString& aCh)
   {
     GetHTMLAttr(nsGkAtoms::_char, aCh);
   }
   void SetCh(const nsAString& aCh, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::_char, aCh, aError);
   }
-  void GetChOff(nsString& aChOff)
+  void GetChOff(DOMString& aChOff)
   {
     GetHTMLAttr(nsGkAtoms::charoff, aChOff);
   }
   void SetChOff(const nsAString& aChOff, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::charoff, aChOff, aError);
   }
-  void GetVAlign(nsString& aVAlign)
+  void GetVAlign(DOMString& aVAlign)
   {
     GetHTMLAttr(nsGkAtoms::valign, aVAlign);
   }
   void SetVAlign(const nsAString& aVAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::valign, aVAlign, aError);
   }
-  void GetWidth(nsString& aWidth)
+  void GetWidth(DOMString& aWidth)
   {
     GetHTMLAttr(nsGkAtoms::width, aWidth);
   }
   void SetWidth(const nsAString& aWidth, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::width, aWidth, aError);
   }
 
--- a/dom/html/HTMLTableElement.h
+++ b/dom/html/HTMLTableElement.h
@@ -91,81 +91,85 @@ public:
   already_AddRefed<nsGenericHTMLElement> CreateTBody();
 
   nsIHTMLCollection* Rows();
 
   already_AddRefed<nsGenericHTMLElement> InsertRow(int32_t aIndex,
                                                    ErrorResult& aError);
   void DeleteRow(int32_t aIndex, ErrorResult& aError);
 
-  void GetAlign(nsString& aAlign)
+  void GetAlign(DOMString& aAlign)
   {
     GetHTMLAttr(nsGkAtoms::align, aAlign);
   }
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
-  void GetBorder(nsString& aBorder)
+  void GetBorder(DOMString& aBorder)
   {
     GetHTMLAttr(nsGkAtoms::border, aBorder);
   }
   void SetBorder(const nsAString& aBorder, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::border, aBorder, aError);
   }
-  void GetFrame(nsString& aFrame)
+  void GetFrame(DOMString& aFrame)
   {
     GetHTMLAttr(nsGkAtoms::frame, aFrame);
   }
   void SetFrame(const nsAString& aFrame, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::frame, aFrame, aError);
   }
-  void GetRules(nsString& aRules)
+  void GetRules(DOMString& aRules)
   {
     GetHTMLAttr(nsGkAtoms::rules, aRules);
   }
   void SetRules(const nsAString& aRules, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::rules, aRules, aError);
   }
   void GetSummary(nsString& aSummary)
   {
     GetHTMLAttr(nsGkAtoms::summary, aSummary);
   }
+  void GetSummary(DOMString& aSummary)
+  {
+    GetHTMLAttr(nsGkAtoms::summary, aSummary);
+  }
   void SetSummary(const nsAString& aSummary, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::summary, aSummary, aError);
   }
-  void GetWidth(nsString& aWidth)
+  void GetWidth(DOMString& aWidth)
   {
     GetHTMLAttr(nsGkAtoms::width, aWidth);
   }
   void SetWidth(const nsAString& aWidth, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::width, aWidth, aError);
   }
-  void GetBgColor(nsString& aBgColor)
+  void GetBgColor(DOMString& aBgColor)
   {
     GetHTMLAttr(nsGkAtoms::bgcolor, aBgColor);
   }
   void SetBgColor(const nsAString& aBgColor, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::bgcolor, aBgColor, aError);
   }
-  void GetCellPadding(nsString& aCellPadding)
+  void GetCellPadding(DOMString& aCellPadding)
   {
     GetHTMLAttr(nsGkAtoms::cellpadding, aCellPadding);
   }
   void SetCellPadding(const nsAString& aCellPadding, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::cellpadding, aCellPadding, aError);
   }
-  void GetCellSpacing(nsString& aCellSpacing)
+  void GetCellSpacing(DOMString& aCellSpacing)
   {
     GetHTMLAttr(nsGkAtoms::cellspacing, aCellSpacing);
   }
   void SetCellSpacing(const nsAString& aCellSpacing, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::cellspacing, aCellSpacing, aError);
   }
 
--- a/dom/html/HTMLTableRowElement.h
+++ b/dom/html/HTMLTableRowElement.h
@@ -32,49 +32,49 @@ public:
 
   int32_t RowIndex() const;
   int32_t SectionRowIndex() const;
   nsIHTMLCollection* Cells();
   already_AddRefed<nsGenericHTMLElement>
     InsertCell(int32_t aIndex, ErrorResult& aError);
   void DeleteCell(int32_t aValue, ErrorResult& aError);
 
-  void GetAlign(nsString& aAlign)
+  void GetAlign(DOMString& aAlign)
   {
     GetHTMLAttr(nsGkAtoms::align, aAlign);
   }
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
-  void GetCh(nsString& aCh)
+  void GetCh(DOMString& aCh)
   {
     GetHTMLAttr(nsGkAtoms::_char, aCh);
   }
   void SetCh(const nsAString& aCh, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::_char, aCh, aError);
   }
-  void GetChOff(nsString& aChOff)
+  void GetChOff(DOMString& aChOff)
   {
     GetHTMLAttr(nsGkAtoms::charoff, aChOff);
   }
   void SetChOff(const nsAString& aChOff, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::charoff, aChOff, aError);
   }
-  void GetVAlign(nsString& aVAlign)
+  void GetVAlign(DOMString& aVAlign)
   {
     GetHTMLAttr(nsGkAtoms::valign, aVAlign);
   }
   void SetVAlign(const nsAString& aVAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::valign, aVAlign, aError);
   }
-  void GetBgColor(nsString& aBgColor)
+  void GetBgColor(DOMString& aBgColor)
   {
     GetHTMLAttr(nsGkAtoms::bgcolor, aBgColor);
   }
   void SetBgColor(const nsAString& aBgColor, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::bgcolor, aBgColor, aError);
   }
 
--- a/dom/html/HTMLTableSectionElement.h
+++ b/dom/html/HTMLTableSectionElement.h
@@ -24,41 +24,41 @@ public:
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   nsIHTMLCollection* Rows();
   already_AddRefed<nsGenericHTMLElement>
     InsertRow(int32_t aIndex, ErrorResult& aError);
   void DeleteRow(int32_t aValue, ErrorResult& aError);
 
-  void GetAlign(nsString& aAlign)
+  void GetAlign(DOMString& aAlign)
   {
     GetHTMLAttr(nsGkAtoms::align, aAlign);
   }
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
-  void GetCh(nsString& aCh)
+  void GetCh(DOMString& aCh)
   {
     GetHTMLAttr(nsGkAtoms::_char, aCh);
   }
   void SetCh(const nsAString& aCh, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::_char, aCh, aError);
   }
-  void GetChOff(nsString& aChOff)
+  void GetChOff(DOMString& aChOff)
   {
     GetHTMLAttr(nsGkAtoms::charoff, aChOff);
   }
   void SetChOff(const nsAString& aChOff, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::charoff, aChOff, aError);
   }
-  void GetVAlign(nsString& aVAlign)
+  void GetVAlign(DOMString& aVAlign)
   {
     GetHTMLAttr(nsGkAtoms::valign, aVAlign);
   }
   void SetVAlign(const nsAString& aVAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::valign, aVAlign, aError);
   }
 
--- a/dom/html/HTMLTimeElement.cpp
+++ b/dom/html/HTMLTimeElement.cpp
@@ -27,17 +27,17 @@ NS_IMPL_ELEMENT_CLONE(HTMLTimeElement)
 
 JSObject*
 HTMLTimeElement::WrapNode(JSContext* cx)
 {
   return HTMLTimeElementBinding::Wrap(cx, this);
 }
 
 void
-HTMLTimeElement::GetItemValueText(nsAString& text)
+HTMLTimeElement::GetItemValueText(DOMString& text)
 {
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::datetime)) {
     GetDateTime(text);
   } else {
     ErrorResult rv;
     GetTextContentInternal(text, rv);
   }
 }
--- a/dom/html/HTMLTimeElement.h
+++ b/dom/html/HTMLTimeElement.h
@@ -16,27 +16,27 @@ namespace dom {
 
 class HTMLTimeElement MOZ_FINAL : public nsGenericHTMLElement
 {
 public:
   explicit HTMLTimeElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
   virtual ~HTMLTimeElement();
 
   // HTMLTimeElement WebIDL
-  void GetDateTime(nsAString& aDateTime)
+  void GetDateTime(DOMString& aDateTime)
   {
     GetHTMLAttr(nsGkAtoms::datetime, aDateTime);
   }
 
   void SetDateTime(const nsAString& aDateTime, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::datetime, aDateTime, aError);
   }
 
-  virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
+  virtual void GetItemValueText(DOMString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
   virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const MOZ_OVERRIDE;
 
 protected:
   virtual JSObject* WrapNode(JSContext* aCx) MOZ_OVERRIDE;
 };
 
 } // namespace dom
--- a/dom/html/HTMLTrackElement.h
+++ b/dom/html/HTMLTrackElement.h
@@ -88,21 +88,19 @@ public:
   uint16_t ReadyState() const;
   void SetReadyState(uint16_t aReadyState);
 
   TextTrack* GetTrack();
 
   virtual nsresult Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult) const MOZ_OVERRIDE;
 
   // For Track, ItemValue reflects the src attribute
-  virtual void GetItemValueText(nsAString& aText) MOZ_OVERRIDE
+  virtual void GetItemValueText(DOMString& aText) MOZ_OVERRIDE
   {
-    DOMString value;
-    GetSrc(value);
-    value.ToString(aText);
+    GetSrc(aText);
   }
   virtual void SetItemValueText(const nsAString& aText) MOZ_OVERRIDE
   {
     ErrorResult rv;
     SetSrc(aText, rv);
   }
 
   // Override ParseAttribute() to convert kind strings to enum values.
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -3029,17 +3029,17 @@ nsGenericHTMLElement::GetItemValue(JSCon
     JS::Rooted<JS::Value> v(aCx);
     JSAutoCompartment ac(aCx, scope);
     if (!mozilla::dom::WrapObject(aCx, this, aRetval)) {
       aError.Throw(NS_ERROR_FAILURE);
     }
     return;
   }
 
-  nsString string;
+  DOMString string;
   GetItemValueText(string);
   if (!xpc::NonVoidStringToJsval(aCx, string, aRetval)) {
     aError.Throw(NS_ERROR_FAILURE);
   }
 }
 
 NS_IMETHODIMP
 nsGenericHTMLElement::GetItemValue(nsIVariant** aValue)
@@ -3050,19 +3050,21 @@ nsGenericHTMLElement::GetItemValue(nsIVa
     out->SetAsEmpty();
     out.forget(aValue);
     return NS_OK;
   }
 
   if (ItemScope()) {
     out->SetAsISupports(static_cast<nsIContent*>(this));
   } else {
-    nsAutoString string;
+    DOMString string;
     GetItemValueText(string);
-    out->SetAsAString(string);
+    nsString xpcomString;
+    string.ToString(xpcomString);
+    out->SetAsAString(xpcomString);
   }
 
   out.forget(aValue);
   return NS_OK;
 }
 
 void
 nsGenericHTMLElement::SetItemValue(JSContext* aCx, JS::Value aValue,
@@ -3093,17 +3095,17 @@ nsGenericHTMLElement::SetItemValue(nsIVa
 
   nsAutoString string;
   aValue->GetAsAString(string);
   SetItemValueText(string);
   return NS_OK;
 }
 
 void
-nsGenericHTMLElement::GetItemValueText(nsAString& text)
+nsGenericHTMLElement::GetItemValueText(DOMString& text)
 {
   ErrorResult rv;
   GetTextContentInternal(text, rv);
 }
 
 void
 nsGenericHTMLElement::SetItemValueText(const nsAString& text)
 {
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -63,35 +63,35 @@ public:
 
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_IMPL_FROMCONTENT(nsGenericHTMLElement, kNameSpaceID_XHTML)
 
   // From Element
   nsresult CopyInnerTo(mozilla::dom::Element* aDest);
 
-  void GetTitle(nsString& aTitle)
+  void GetTitle(mozilla::dom::DOMString& aTitle)
   {
     GetHTMLAttr(nsGkAtoms::title, aTitle);
   }
   NS_IMETHODIMP SetTitle(const nsAString& aTitle) MOZ_OVERRIDE
   {
     SetHTMLAttr(nsGkAtoms::title, aTitle);
     return NS_OK;
   }
-  void GetLang(nsString& aLang)
+  void GetLang(mozilla::dom::DOMString& aLang)
   {
     GetHTMLAttr(nsGkAtoms::lang, aLang);
   }
   NS_IMETHODIMP SetLang(const nsAString& aLang) MOZ_OVERRIDE
   {
     SetHTMLAttr(nsGkAtoms::lang, aLang);
     return NS_OK;
   }
-  void GetDir(nsString& aDir)
+  void GetDir(mozilla::dom::DOMString& aDir)
   {
     GetHTMLEnumAttr(nsGkAtoms::dir, aDir);
   }
   void SetDir(const nsAString& aDir, mozilla::ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::dir, aDir, aError);
   }
   already_AddRefed<nsDOMStringMap> Dataset();
@@ -291,17 +291,17 @@ public:
     return rcFrame.height;
   }
 
 protected:
   virtual ~nsGenericHTMLElement() {}
 
   // These methods are used to implement element-specific behavior of Get/SetItemValue
   // when an element has @itemprop but no @itemscope.
-  virtual void GetItemValueText(nsAString& text);
+  virtual void GetItemValueText(mozilla::dom::DOMString& text);
   virtual void SetItemValueText(const nsAString& text);
 public:
   virtual already_AddRefed<mozilla::dom::UndoManager> GetUndoManager() MOZ_OVERRIDE;
   virtual bool UndoScope() MOZ_OVERRIDE;
   virtual void SetUndoScope(bool aUndoScope, mozilla::ErrorResult& aError) MOZ_OVERRIDE;
   // Callback for destructor of of dataset to ensure to null out weak pointer.
   nsresult ClearDataset();
 
@@ -313,31 +313,31 @@ public:
   nsSize GetWidthHeightForImage(nsRefPtr<imgRequestProxy>& aImageRequest);
 
   // XPIDL methods
   NS_FORWARD_NSIDOMNODE_TO_NSINODE
 
   NS_FORWARD_NSIDOMELEMENT_TO_GENERIC
 
   NS_IMETHOD GetTitle(nsAString& aTitle) MOZ_FINAL MOZ_OVERRIDE {
-    nsString title;
+    mozilla::dom::DOMString title;
     GetTitle(title);
-    aTitle.Assign(title);
+    title.ToString(aTitle);
     return NS_OK;
   }
   NS_IMETHOD GetLang(nsAString& aLang) MOZ_FINAL MOZ_OVERRIDE {
-    nsString lang;
+    mozilla::dom::DOMString lang;
     GetLang(lang);
-    aLang.Assign(lang);
+    lang.ToString(aLang);
     return NS_OK;
   }
   NS_IMETHOD GetDir(nsAString& aDir) MOZ_FINAL MOZ_OVERRIDE {
-    nsString dir;
+    mozilla::dom::DOMString dir;
     GetDir(dir);
-    aDir.Assign(dir);
+    dir.ToString(aDir);
     return NS_OK;
   }
   NS_IMETHOD SetDir(const nsAString& aDir) MOZ_FINAL MOZ_OVERRIDE {
     mozilla::ErrorResult rv;
     SetDir(aDir, rv);
     return rv.ErrorCode();
   }
   NS_IMETHOD GetDOMClassName(nsAString& aClassName) MOZ_FINAL {
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -26,16 +26,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
 #include "mozilla/docshell/OfflineCacheUpdateChild.h"
 #include "mozilla/dom/ContentBridgeChild.h"
 #include "mozilla/dom/ContentBridgeParent.h"
 #include "mozilla/dom/DOMStorageIPC.h"
 #include "mozilla/dom/ExternalHelperAppChild.h"
 #include "mozilla/dom/PCrashReporterChild.h"
+#include "mozilla/dom/ProcessGlobal.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/asmjscache/PAsmJSCacheEntryChild.h"
 #include "mozilla/dom/nsIContentChild.h"
 #include "mozilla/hal_sandbox/PHalChild.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
@@ -1909,22 +1910,30 @@ ContentChild::RecvNotifyVisited(const UR
     nsCOMPtr<IHistory> history = services::GetHistoryService();
     if (history) {
         history->NotifyVisited(newURI);
     }
     return true;
 }
 
 bool
+ContentChild::RecvLoadProcessScript(const nsString& aURL)
+{
+    ProcessGlobal* global = ProcessGlobal::Get();
+    global->LoadScript(aURL);
+    return true;
+}
+
+bool
 ContentChild::RecvAsyncMessage(const nsString& aMsg,
                                const ClonedMessageData& aData,
                                InfallibleTArray<CpowEntry>&& aCpows,
                                const IPC::Principal& aPrincipal)
 {
-    nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
+    nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::GetChildProcessManager();
     if (cpm) {
         StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
         CrossProcessCpowHolder cpows(this, aCpows);
         cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
                             aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
     }
     return true;
 }
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -299,16 +299,18 @@ public:
     virtual bool RecvSystemMemoryAvailable(const uint64_t& aGetterId,
                                            const uint32_t& aMemoryAvailable) MOZ_OVERRIDE;
 
     virtual bool RecvPreferenceUpdate(const PrefSetting& aPref) MOZ_OVERRIDE;
 
     virtual bool RecvNotifyAlertsObserver(const nsCString& aType,
                                           const nsString& aData) MOZ_OVERRIDE;
 
+    virtual bool RecvLoadProcessScript(const nsString& aURL) MOZ_OVERRIDE;
+
     virtual bool RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
                                   InfallibleTArray<CpowEntry>&& aCpows,
                                   const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
 
     virtual bool RecvGeolocationUpdate(const GeoPosition& somewhere) MOZ_OVERRIDE;
 
     virtual bool RecvGeolocationError(const uint16_t& errorCode) MOZ_OVERRIDE;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4175,16 +4175,24 @@ ContentParent::RecvPrivateDocShellsExist
             delete sPrivateContent;
             sPrivateContent = nullptr;
         }
     }
     return true;
 }
 
 bool
+ContentParent::DoLoadMessageManagerScript(const nsAString& aURL,
+                                          bool aRunInGlobalScope)
+{
+    MOZ_ASSERT(!aRunInGlobalScope);
+    return SendLoadProcessScript(nsString(aURL));
+}
+
+bool
 ContentParent::DoSendAsyncMessage(JSContext* aCx,
                                   const nsAString& aMessage,
                                   const mozilla::dom::StructuredCloneData& aData,
                                   JS::Handle<JSObject *> aCpows,
                                   nsIPrincipal* aPrincipal)
 {
     ClonedMessageData data;
     if (!BuildClonedMessageDataForParent(this, aData, data)) {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -164,16 +164,18 @@ public:
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIOBSERVER
     NS_DECL_NSIDOMGEOPOSITIONCALLBACK
     NS_DECL_NSIDOMGEOPOSITIONERRORCALLBACK
 
     /**
      * MessageManagerCallback methods that we override.
      */
+    virtual bool DoLoadMessageManagerScript(const nsAString& aURL,
+                                            bool aRunInGlobalScope) MOZ_OVERRIDE;
     virtual bool DoSendAsyncMessage(JSContext* aCx,
                                     const nsAString& aMessage,
                                     const mozilla::dom::StructuredCloneData& aData,
                                     JS::Handle<JSObject *> aCpows,
                                     nsIPrincipal* aPrincipal) MOZ_OVERRIDE;
     virtual bool CheckPermission(const nsAString& aPermission) MOZ_OVERRIDE;
     virtual bool CheckManifestURL(const nsAString& aManifestURL) MOZ_OVERRIDE;
     virtual bool CheckAppHasPermission(const nsAString& aPermission) MOZ_OVERRIDE;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -548,16 +548,18 @@ child:
     NuwaFreeze();
 
     /**
      * Notify the child to shutdown. The child will in turn call FinishShutdown
      * and let the parent close the channel.
      */
     async Shutdown();
 
+    async LoadProcessScript(nsString url);
+
 parent:
     /**
      * Tell the parent process a new accessible document has been created.
      * aParentDoc is the accessible document it was created in if any, and
      * aParentAcc is the id of the accessible in that document the new document
      * is a child of.
      */
     PDocAccessible(nullable PDocAccessible aParentDoc, uint64_t aParentAcc);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -9,17 +9,16 @@
 #include "TabChild.h"
 
 #include "Layers.h"
 #include "ContentChild.h"
 #include "TabParent.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/EventListenerManager.h"
-#include "mozilla/IntentionalCrash.h"
 #include "mozilla/dom/workers/ServiceWorkerManager.h"
 #include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
 #include "mozilla/plugins/PluginWidgetChild.h"
 #include "mozilla/ipc/DocumentRendererChild.h"
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/APZEventState.h"
@@ -2613,17 +2612,17 @@ TabChild::RecvActivateFrameEvent(const n
 bool
 TabChild::RecvLoadRemoteScript(const nsString& aURL, const bool& aRunInGlobalScope)
 {
   if (!mGlobal && !InitTabChildGlobal())
     // This can happen if we're half-destroyed.  It's not a fatal
     // error.
     return true;
 
-  LoadFrameScriptInternal(aURL, aRunInGlobalScope);
+  LoadScriptInternal(aURL, aRunInGlobalScope);
   return true;
 }
 
 bool
 TabChild::RecvAsyncMessage(const nsString& aMessage,
                            const ClonedMessageData& aData,
                            InfallibleTArray<CpowEntry>&& aCpows,
                            const IPC::Principal& aPrincipal)
@@ -2764,17 +2763,17 @@ TabChild::InitTabChildGlobal(FrameScript
     NS_ENSURE_TRUE(chromeHandler, false);
 
     nsRefPtr<TabChildGlobal> scope = new TabChildGlobal(this);
     mTabChildGlobal = scope;
 
     nsISupports* scopeSupports = NS_ISUPPORTS_CAST(EventTarget*, scope);
 
     NS_NAMED_LITERAL_CSTRING(globalId, "outOfProcessTabChildGlobal");
-    NS_ENSURE_TRUE(InitTabChildGlobalInternal(scopeSupports, globalId), false);
+    NS_ENSURE_TRUE(InitChildGlobalInternal(scopeSupports, globalId), false);
 
     scope->Init();
 
     nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(chromeHandler);
     NS_ENSURE_TRUE(root, false);
     root->SetParentTarget(scope);
 
     chromeHandler->AddEventListener(NS_LITERAL_STRING("DOMMetaAdded"), this, false);
@@ -3213,47 +3212,26 @@ TabChildGlobal::GetContent(nsIDOMWindow*
   if (!mTabChild)
     return NS_ERROR_NULL_POINTER;
   nsCOMPtr<nsIDOMWindow> window = do_GetInterface(mTabChild->WebNavigation());
   window.swap(*aContent);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TabChildGlobal::PrivateNoteIntentionalCrash()
-{
-    mozilla::NoteIntentionalCrash("tab");
-    return NS_OK;
-}
-
-NS_IMETHODIMP
 TabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
 {
   *aDocShell = nullptr;
   if (!mTabChild)
     return NS_ERROR_NULL_POINTER;
   nsCOMPtr<nsIDocShell> docShell = do_GetInterface(mTabChild->WebNavigation());
   docShell.swap(*aDocShell);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-TabChildGlobal::Btoa(const nsAString& aBinaryData,
-                     nsAString& aAsciiBase64String)
-{
-  return nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
-}
-
-NS_IMETHODIMP
-TabChildGlobal::Atob(const nsAString& aAsciiString,
-                     nsAString& aBinaryData)
-{
-  return nsContentUtils::Atob(aAsciiString, aBinaryData);
-}
-
 JSContext*
 TabChildGlobal::GetJSContextForEventHandlers()
 {
   return nsContentUtils::GetSafeJSContext();
 }
 
 nsIPrincipal*
 TabChildGlobal::GetPrincipal()
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -71,16 +71,17 @@ class TabChildGlobal : public DOMEventTa
 {
 public:
   explicit TabChildGlobal(TabChildBase* aTabChild);
   void Init();
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TabChildGlobal, DOMEventTargetHelper)
   NS_FORWARD_SAFE_NSIMESSAGELISTENERMANAGER(mMessageManager)
   NS_FORWARD_SAFE_NSIMESSAGESENDER(mMessageManager)
+  NS_FORWARD_SAFE_NSIMESSAGEMANAGERGLOBAL(mMessageManager)
   NS_IMETHOD SendSyncMessage(const nsAString& aMessageName,
                              JS::Handle<JS::Value> aObject,
                              JS::Handle<JS::Value> aRemote,
                              nsIPrincipal* aPrincipal,
                              JSContext* aCx,
                              uint8_t aArgc,
                              JS::MutableHandle<JS::Value> aRetval) MOZ_OVERRIDE
   {
@@ -99,25 +100,16 @@ public:
   {
     return mMessageManager
       ? mMessageManager->SendRpcMessage(aMessageName, aObject, aRemote,
                                         aPrincipal, aCx, aArgc, aRetval)
       : NS_ERROR_NULL_POINTER;
   }
   NS_IMETHOD GetContent(nsIDOMWindow** aContent) MOZ_OVERRIDE;
   NS_IMETHOD GetDocShell(nsIDocShell** aDocShell) MOZ_OVERRIDE;
-  NS_IMETHOD Dump(const nsAString& aStr) MOZ_OVERRIDE
-  {
-    return mMessageManager ? mMessageManager->Dump(aStr) : NS_OK;
-  }
-  NS_IMETHOD PrivateNoteIntentionalCrash() MOZ_OVERRIDE;
-  NS_IMETHOD Btoa(const nsAString& aBinaryData,
-                  nsAString& aAsciiBase64String) MOZ_OVERRIDE;
-  NS_IMETHOD Atob(const nsAString& aAsciiString,
-                  nsAString& aBinaryData) MOZ_OVERRIDE;
 
   nsresult AddEventListener(const nsAString& aType,
                             nsIDOMEventListener* aListener,
                             bool aUseCapture)
   {
     // By default add listeners only for trusted events!
     return DOMEventTargetHelper::AddEventListener(aType, aListener,
                                                   aUseCapture, false, 2);
@@ -168,17 +160,17 @@ protected:
   TabChild* mTabChild;
 };
 
 // This is base clase which helps to share Viewport and touch related functionality
 // between b2g/android FF/embedlite clients implementation.
 // It make sense to place in this class all helper functions, and functionality which could be shared between
 // Cross-process/Cross-thread implmentations.
 class TabChildBase : public nsISupports,
-                     public nsFrameScriptExecutor,
+                     public nsMessageManagerScriptExecutor,
                      public ipc::MessageManagerCallback
 {
 public:
     TabChildBase();
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TabChildBase)
 
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -108,17 +108,17 @@ nsIContentChild::GetOrCreateActorForBlob
 }
 
 bool
 nsIContentChild::RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
                                   InfallibleTArray<CpowEntry>&& aCpows,
                                   const IPC::Principal& aPrincipal)
 {
-  nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::sChildProcessManager;
+  nsRefPtr<nsFrameMessageManager> cpm = nsFrameMessageManager::GetChildProcessManager();
   if (cpm) {
     StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForChild(aData);
     CrossProcessCpowHolder cpows(this, aCpows);
     cpm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(cpm.get()),
                         aMsg, false, &cloneData, &cpows, aPrincipal, nullptr);
   }
   return true;
 }
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -139,16 +139,17 @@ void MediaDecoder::NotifyOwnerActivityCh
 void MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity)
 {
   MOZ_ASSERT(NS_IsMainThread());
   GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (!mDecoderStateMachine ||
       mPlayState == PLAY_STATE_SHUTDOWN ||
       !mOwner->GetVideoFrameContainer() ||
+      (mOwner->GetMediaElement() && mOwner->GetMediaElement()->IsBeingDestroyed()) ||
       !mDecoderStateMachine->IsDormantNeeded())
   {
     return;
   }
 
   bool prevDormant = mIsDormant;
   mIsDormant = false;
   if (!mOwner->IsActive()) {
@@ -979,18 +980,18 @@ bool MediaDecoder::IsSameOriginMedia()
 {
   GetReentrantMonitor().AssertCurrentThreadIn();
   return mSameOriginMedia;
 }
 
 bool MediaDecoder::IsSeeking() const
 {
   MOZ_ASSERT(NS_IsMainThread());
-  return mPlayState == PLAY_STATE_SEEKING ||
-    (mPlayState == PLAY_STATE_LOADING && mRequestedSeekTarget.IsValid());
+  return !mIsDormant && (mPlayState == PLAY_STATE_SEEKING ||
+    (mPlayState == PLAY_STATE_LOADING && mRequestedSeekTarget.IsValid()));
 }
 
 bool MediaDecoder::IsEnded() const
 {
   MOZ_ASSERT(NS_IsMainThread());
   return mPlayState == PLAY_STATE_ENDED || mPlayState == PLAY_STATE_SHUTDOWN;
 }
 
--- a/dom/media/eme/CDMCallbackProxy.cpp
+++ b/dom/media/eme/CDMCallbackProxy.cpp
@@ -8,17 +8,17 @@
 #include "mozilla/CDMProxy.h"
 #include "nsString.h"
 #include "mozilla/dom/MediaKeys.h"
 #include "mozilla/dom/MediaKeySession.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "nsContentCID.h"
 #include "nsServiceManagerUtils.h"
 #include "MainThreadUtils.h"
-#include "EMELog.h"
+#include "mozilla/EMEUtils.h"
 
 namespace mozilla {
 
 CDMCallbackProxy::CDMCallbackProxy(CDMProxy* aProxy)
   : mProxy(aProxy)
 {
 
 }
--- a/dom/media/eme/CDMCaps.cpp
+++ b/dom/media/eme/CDMCaps.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=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/. */
 
-#include "CDMCaps.h"
-#include "EMELog.h"
+#include "mozilla/CDMCaps.h"
+#include "mozilla/EMEUtils.h"
 #include "nsThreadUtils.h"
 #include "SamplesWaitingForKey.h"
 
 namespace mozilla {
 
 CDMCaps::CDMCaps()
   : mMonitor("CDMCaps")
   , mCaps(0)
--- a/dom/media/eme/CDMProxy.cpp
+++ b/dom/media/eme/CDMProxy.cpp
@@ -7,17 +7,17 @@
 #include "mozilla/CDMProxy.h"
 #include "nsString.h"
 #include "mozilla/dom/MediaKeys.h"
 #include "mozilla/dom/MediaKeySession.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "nsContentCID.h"
 #include "nsServiceManagerUtils.h"
 #include "MainThreadUtils.h"
-#include "mozilla/EMELog.h"
+#include "mozilla/EMEUtils.h"
 #include "nsIConsoleService.h"
 #include "prenv.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/CDMCallbackProxy.h"
 
 namespace mozilla {
 
 CDMProxy::CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem)
rename from dom/media/eme/EMELog.cpp
rename to dom/media/eme/EMEUtils.cpp
--- a/dom/media/eme/EMELog.cpp
+++ b/dom/media/eme/EMEUtils.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=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/. */
 
-#include "EMELog.h"
+#include "mozilla/EMEUtils.h"
 
 namespace mozilla {
 
 #ifdef PR_LOGGING
 
 PRLogModuleInfo* GetEMELog() {
   static PRLogModuleInfo* log = nullptr;
   if (!log) {
@@ -23,9 +23,94 @@ PRLogModuleInfo* GetEMEVerboseLog() {
   if (!log) {
     log = PR_NewLogModule("EMEV");
   }
   return log;
 }
 
 #endif
 
+static bool
+ContainsOnlyDigits(const nsAString& aString)
+{
+  nsAString::const_iterator iter, end;
+  aString.BeginReading(iter);
+  aString.EndReading(end);
+  while (iter != end) {
+    char16_t ch = *iter;
+    if (ch < '0' || ch > '9') {
+      return false;
+    }
+    iter++;
+  }
+  return true;
+}
+
+static bool
+ParseKeySystem(const nsAString& aExpectedKeySystem,
+               const nsAString& aInputKeySystem,
+               int32_t& aOutCDMVersion)
+{
+  if (!StringBeginsWith(aInputKeySystem, aExpectedKeySystem)) {
+    return false;
+  }
+
+  if (aInputKeySystem.Length() > aExpectedKeySystem.Length() + 8) {
+    // Allow up to 8 bytes for the ".version" field. 8 bytes should
+    // be enough for any versioning scheme...
+    NS_WARNING("Input KeySystem including was suspiciously long");
+    return false;
+  }
+
+  const char16_t* versionStart = aInputKeySystem.BeginReading() + aExpectedKeySystem.Length();
+  const char16_t* end = aInputKeySystem.EndReading();
+  if (versionStart == end) {
+    // No version supplied with keysystem.
+    aOutCDMVersion = NO_CDM_VERSION;
+    return true;
+  }
+  if (*versionStart != '.') {
+    // version not in correct format.
+    NS_WARNING("EME keySystem version string not prefixed by '.'");
+    return false;
+  }
+  versionStart++;
+  const nsAutoString versionStr(Substring(versionStart, end));
+  if (!ContainsOnlyDigits(versionStr)) {
+    NS_WARNING("Non-digit character in EME keySystem string's version suffix");
+    return false;
+  }
+  nsresult rv;
+  int32_t version = versionStr.ToInteger(&rv);
+  if (NS_FAILED(rv) || version < 0) {
+    NS_WARNING("Invalid version in EME keySystem string");
+    return false;
+  }
+  aOutCDMVersion = version;
+
+  return true;
+}
+
+static const char16_t* sKeySystems[] = {
+  MOZ_UTF16("org.w3.clearkey"),
+  MOZ_UTF16("com.adobe.access"),
+  MOZ_UTF16("com.adobe.primetime"),
+};
+
+bool
+ParseKeySystem(const nsAString& aInputKeySystem,
+               nsAString& aOutKeySystem,
+               int32_t& aOutCDMVersion)
+{
+  for (const char16_t* keySystem : sKeySystems) {
+    int32_t minCDMVersion = NO_CDM_VERSION;
+    if (ParseKeySystem(nsDependentString(keySystem),
+                       aInputKeySystem,
+                       minCDMVersion)) {
+      aOutKeySystem = keySystem;
+      aOutCDMVersion = minCDMVersion;
+      return true;
+    }
+  }
+  return false;
+}
+
 } // namespace mozilla
rename from dom/media/eme/EMELog.h
rename to dom/media/eme/EMEUtils.h
--- a/dom/media/eme/EMELog.h
+++ b/dom/media/eme/EMEUtils.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef EME_LOG_H_
 #define EME_LOG_H_
 
 #include "prlog.h"
+#include "nsString.h"
 
 namespace mozilla {
 
 #ifdef PR_LOGGING
 
   #ifndef EME_LOG
     PRLogModuleInfo* GetEMELog();
     #define EME_LOG(...) PR_LOG(GetEMELog(), PR_LOG_DEBUG, (__VA_ARGS__))
@@ -38,11 +39,31 @@ namespace mozilla {
   #endif
 
   #ifndef EME_VERBOSE_LOG
     #define EME_VERBOSE_LOG(...)
   #endif
 
 #endif // PR_LOGGING
 
+#define NO_CDM_VERSION -1
+
+// Checks a keySystem string against a whitelist, and determines whether
+// the keySystem is in the whitelist, and extracts the requested minimum
+// CDM version.
+//
+// Format of EME keysystems:
+// com.domain.keysystem[.minVersionAsInt]
+// i.e. org.w3.clearkey, com.adobe.primetime.7
+//
+// Returns true if aKeySystem contains a valid keySystem which we support,
+// false otherwise.
+//
+// On success, aOutKeySystem contains the keySystem string stripped of the
+// min version number, and aOutMinCDMVersion contains the min version number
+// if present. If it was not present, aOutMinCDMVersion is NO_CDM_VERSION.
+bool ParseKeySystem(const nsAString& aKeySystem,
+                    nsAString& aOutKeySystem,
+                    int32_t& aOutMinCDMVersion);
+
 } // namespace mozilla
 
 #endif // EME_LOG_H_
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/WindowsVersion.h"
 #endif
 #include "nsContentCID.h"
 #include "nsServiceManagerUtils.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "VideoUtils.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
+#include "mozilla/EMEUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeySystemAccess,
                                       mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeySystemAccess)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeySystemAccess)
@@ -75,30 +76,56 @@ HaveGMPFor(mozIGeckoMediaPluginService* 
            const nsCString& aAPI,
            const nsCString& aTag = EmptyCString())
 {
   nsTArray<nsCString> tags;
   tags.AppendElement(aKeySystem);
   if (!aTag.IsEmpty()) {
     tags.AppendElement(aTag);
   }
-  // Note: EME plugins need a non-null nodeId here, as they must
-  // not be shared across origins.
   bool hasPlugin = false;
   if (NS_FAILED(aGMPService->HasPluginForAPI(aAPI,
                                              &tags,
                                              &hasPlugin))) {
     return false;
   }
   return hasPlugin;
 }
 
+static MediaKeySystemStatus
+EnsureMinCDMVersion(mozIGeckoMediaPluginService* aGMPService,
+                    const nsAString& aKeySystem,
+                    int32_t aMinCdmVersion)
+{
+  if (aMinCdmVersion == NO_CDM_VERSION) {
+    return MediaKeySystemStatus::Available;
+  }
+
+  nsTArray<nsCString> tags;
+  tags.AppendElement(NS_ConvertUTF16toUTF8(aKeySystem));
+  nsAutoCString versionStr;
+  if (NS_FAILED(aGMPService->GetPluginVersionForAPI(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
+                                                    &tags,
+                                                    versionStr))) {
+    return MediaKeySystemStatus::Error;
+  }
+
+  nsresult rv;
+  int32_t version = versionStr.ToInteger(&rv);
+  if (NS_FAILED(rv) || version < 0 || aMinCdmVersion > version) {
+    return MediaKeySystemStatus::Cdm_insufficient_version;
+  }
+
+  return MediaKeySystemStatus::Available;
+}
+
 /* static */
 MediaKeySystemStatus
-MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem)
+MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem,
+                                         int32_t aMinCdmVersion)
 {
   MOZ_ASSERT(Preferences::GetBool("media.eme.enabled", false));
   nsCOMPtr<mozIGeckoMediaPluginService> mps =
     do_GetService("@mozilla.org/gecko-media-plugin-service;1");
   if (NS_WARN_IF(!mps)) {
     return MediaKeySystemStatus::Error;
   }
 
@@ -106,17 +133,17 @@ MediaKeySystemAccess::GetKeySystemStatus
     if (!Preferences::GetBool("media.eme.clearkey.enabled", true)) {
       return MediaKeySystemStatus::Cdm_disabled;
     }
     if (!HaveGMPFor(mps,
                     NS_LITERAL_CSTRING("org.w3.clearkey"),
                     NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))) {
       return MediaKeySystemStatus::Cdm_not_installed;
     }
-    return MediaKeySystemStatus::Available;
+    return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion);
   }
 
 #ifdef XP_WIN
   if ((aKeySystem.EqualsLiteral("com.adobe.access") ||
        aKeySystem.EqualsLiteral("com.adobe.primetime"))) {
     // Win Vista and later only.
     if (!IsVistaOrLater()) {
       return MediaKeySystemStatus::Cdm_not_supported;
@@ -124,17 +151,17 @@ MediaKeySystemAccess::GetKeySystemStatus
     if (!Preferences::GetBool("media.gmp-eme-adobe.enabled", false)) {
       return MediaKeySystemStatus::Cdm_disabled;
     }
     if (!HaveGMPFor(mps,
                     NS_ConvertUTF16toUTF8(aKeySystem),
                     NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))) {
       return MediaKeySystemStatus::Cdm_not_installed;
     }
-    return MediaKeySystemStatus::Available;
+    return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion);
   }
 #endif
 
   return MediaKeySystemStatus::Cdm_not_supported;
 }
 
 static bool
 IsPlayableWithGMP(mozIGeckoMediaPluginService* aGMPS,
--- a/dom/media/eme/MediaKeySystemAccess.h
+++ b/dom/media/eme/MediaKeySystemAccess.h
@@ -39,17 +39,18 @@ public:
   nsPIDOMWindow* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   void GetKeySystem(nsString& aRetVal) const;
 
   already_AddRefed<Promise> CreateMediaKeys(ErrorResult& aRv);
 
-  static MediaKeySystemStatus GetKeySystemStatus(const nsAString& aKeySystem);
+  static MediaKeySystemStatus GetKeySystemStatus(const nsAString& aKeySystem,
+                                                 int32_t aMinCdmVersion);
 
   static bool IsSupported(const nsAString& aKeySystem,
                           const Sequence<MediaKeySystemOptions>& aOptions);
 
   static void NotifyObservers(nsIDOMWindow* aWindow,
                               const nsAString& aKeySystem,
                               MediaKeySystemStatus aStatus);
 
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -8,17 +8,17 @@
 #include "mozilla/dom/MediaKeys.h"
 #include "mozilla/dom/MediaKeysBinding.h"
 #include "mozilla/dom/MediaKeyMessageEvent.h"
 #include "mozilla/dom/MediaKeyError.h"
 #include "mozilla/dom/MediaKeySession.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "mozilla/CDMProxy.h"
-#include "mozilla/EMELog.h"
+#include "mozilla/EMEUtils.h"
 #include "nsContentUtils.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "mozilla/Preferences.h"
 #include "nsContentTypeParser.h"
 #ifdef MOZ_FMP4
 #include "MP4Decoder.h"
 #endif
 #ifdef XP_WIN
--- a/dom/media/eme/moz.build
+++ b/dom/media/eme/moz.build
@@ -13,24 +13,24 @@ EXPORTS.mozilla.dom += [
     'MediaKeyStatusMap.h',
     'MediaKeySystemAccess.h',
 ]
 
 EXPORTS.mozilla += [
     'CDMCallbackProxy.h',
     'CDMCaps.h',
     'CDMProxy.h',
-    'EMELog.h'
+    'EMEUtils.h'
 ]
 
 UNIFIED_SOURCES += [
     'CDMCallbackProxy.cpp',
     'CDMCaps.cpp',
     'CDMProxy.cpp',
-    'EMELog.cpp',
+    'EMEUtils.cpp',
     'MediaEncryptedEvent.cpp',
     'MediaKeyError.cpp',
     'MediaKeyMessageEvent.cpp',
     'MediaKeys.cpp',
     'MediaKeySession.cpp',
     'MediaKeyStatusMap.cpp',
     'MediaKeySystemAccess.cpp',
 ]
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -997,16 +997,22 @@ GMPParent::CanBeUsedFrom(const nsACStrin
 void
 GMPParent::SetNodeId(const nsACString& aNodeId)
 {
   MOZ_ASSERT(!aNodeId.IsEmpty());
   MOZ_ASSERT(CanBeUsedFrom(aNodeId));
   mNodeId = aNodeId;
 }
 
+const nsCString&
+GMPParent::GetVersion() const
+{
+  return mVersion;
+}
+
 bool
 GMPParent::RecvAsyncShutdownRequired()
 {
   LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
   if (mAsyncShutdownRequired) {
     NS_WARNING("Received AsyncShutdownRequired message more than once!");
     return true;
   }
--- a/dom/media/gmp/GMPParent.h
+++ b/dom/media/gmp/GMPParent.h
@@ -110,16 +110,18 @@ public:
   //
   // If a plugin has no NodeId specified and it is loaded, it is assumed to
   // be shared across NodeIds.
 
   // Specifies that a GMP can only work with the specified NodeIds.
   void SetNodeId(const nsACString& aNodeId);
   const nsACString& GetNodeId() const { return mNodeId; }
 
+  const nsCString& GetVersion() const;
+
   // Returns true if a plugin can be or is being used across multiple NodeIds.
   bool CanBeSharedCrossNodeIds() const;
 
   // A GMP can be used from a NodeId if it's already been set to work with
   // that NodeId, or if it's not been set to work with any NodeId and has
   // not yet been loaded (i.e. it's not shared across NodeIds).
   bool CanBeUsedFrom(const nsACString& aNodeId) const;
 
--- a/dom/media/gmp/GMPService.cpp
+++ b/dom/media/gmp/GMPService.cpp
@@ -668,41 +668,79 @@ GeckoMediaPluginService::RemovePluginDir
 }
 
 class DummyRunnable : public nsRunnable {
 public:
   NS_IMETHOD Run() { return NS_OK; }
 };
 
 NS_IMETHODIMP
-GeckoMediaPluginService::HasPluginForAPI(const nsACString& aAPI,
-                                         nsTArray<nsCString>* aTags,
-                                         bool* aResult)
+GeckoMediaPluginService::GetPluginVersionForAPI(const nsACString& aAPI,
+                                                nsTArray<nsCString>* aTags,
+                                                nsACString& aOutVersion)
 {
   NS_ENSURE_ARG(aTags && aTags->Length() > 0);
-  NS_ENSURE_ARG(aResult);
+
+  nsresult rv = EnsurePluginsOnDiskScanned();
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Failed to load GMPs from disk.");
+    return rv;
+  }
 
+  {
+    MutexAutoLock lock(mMutex);
+    nsCString api(aAPI);
+    GMPParent* gmp = FindPluginForAPIFrom(0, api, *aTags, nullptr);
+    if (!gmp) {
+      return NS_ERROR_FAILURE;
+    }
+    aOutVersion = gmp->GetVersion();
+  }
+
+  return NS_OK;
+}
+
+nsresult
+GeckoMediaPluginService::EnsurePluginsOnDiskScanned()
+{
   const char* env = nullptr;
   if (!mScannedPluginOnDisk && (env = PR_GetEnv("MOZ_GMP_PATH")) && *env) {
     // We have a MOZ_GMP_PATH environment variable which may specify the
     // location of plugins to load, and we haven't yet scanned the disk to
     // see if there are plugins there. Get the GMP thread, which will
     // cause an event to be dispatched to which scans for plugins. We
     // dispatch a sync event to the GMP thread here in order to wait until
     // after the GMP thread has scanned any paths in MOZ_GMP_PATH.
     nsresult rv = GMPDispatch(new DummyRunnable(), NS_DISPATCH_SYNC);
     NS_ENSURE_SUCCESS(rv, rv);
     MOZ_ASSERT(mScannedPluginOnDisk, "Should have scanned MOZ_GMP_PATH by now");
   }
 
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+GeckoMediaPluginService::HasPluginForAPI(const nsACString& aAPI,
+                                         nsTArray<nsCString>* aTags,
+                                         bool* aOutHavePlugin)
+{
+  NS_ENSURE_ARG(aTags && aTags->Length() > 0);
+  NS_ENSURE_ARG(aOutHavePlugin);
+
+  nsresult rv = EnsurePluginsOnDiskScanned();
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Failed to load GMPs from disk.");
+    return rv;
+  }
+
   {
     MutexAutoLock lock(mMutex);
     nsCString api(aAPI);
     GMPParent* gmp = FindPluginForAPIFrom(0, api, *aTags, nullptr);
-    *aResult = (gmp != nullptr);
+    *aOutHavePlugin = (gmp != nullptr);
   }
 
   return NS_OK;
 }
 
 GMPParent*
 GeckoMediaPluginService::FindPluginForAPIFrom(size_t aSearchStartIndex,
                                               const nsCString& aAPI,
--- a/dom/media/gmp/GMPService.h
+++ b/dom/media/gmp/GMPService.h
@@ -85,16 +85,17 @@ private:
   void ForgetThisSiteOnGMPThread(const nsACString& aOrigin);
   void ClearRecentHistoryOnGMPThread(PRTime aSince);
 
 protected:
   friend class GMPParent;
   void ReAddOnGMPThread(nsRefPtr<GMPParent>& aOld);
 private:
   GMPParent* ClonePlugin(const GMPParent* aOriginal);
+  nsresult EnsurePluginsOnDiskScanned();
 
   class PathRunnable : public nsRunnable
   {
   public:
     PathRunnable(GeckoMediaPluginService* service, const nsAString& path,
                  bool add)
       : mService(service)
       , mPath(path)
--- a/dom/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/dom/media/gmp/mozIGeckoMediaPluginService.idl
@@ -21,33 +21,41 @@ class GMPVideoHost;
 [ptr] native GMPVideoDecoderProxy(GMPVideoDecoderProxy);
 [ptr] native GMPVideoEncoderProxy(GMPVideoEncoderProxy);
 [ptr] native GMPVideoHost(GMPVideoHost);
 [ptr] native MessageLoop(MessageLoop);
 [ptr] native TagArray(nsTArray<nsCString>);
 [ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
 [ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
 
-[scriptable, uuid(4aaf58d3-181f-4325-9a2f-41172d995a70)]
+[scriptable, uuid(56cc105f-dd27-4752-83e0-371908edba04)]
 interface mozIGeckoMediaPluginService : nsISupports
 {
 
   /**
    * The GMP thread. Callable from any thread.
    */
   readonly attribute nsIThread thread;
 
   /**
    * Get a plugin that supports the specified tags.
    * Callable on any thread
    */
   [noscript]
   boolean hasPluginForAPI(in ACString api, in TagArray tags);
 
   /**
+   * Get the version of the plugin that supports the specified tags.
+   * Callable on any thread
+   */
+  [noscript]
+  ACString getPluginVersionForAPI(in ACString api,
+                                  in TagArray tags);
+
+  /**
    * Get a video decoder that supports the specified tags.
    * The array of tags should at least contain a codec tag, and optionally
    * other tags such as for EME keysystem.
    * Callable only on GMP thread.
    */
   [noscript]
   GMPVideoDecoderProxy getGMPVideoDecoder(in TagArray tags,
                                           [optional] in ACString nodeId,
new file mode 100644
--- /dev/null
+++ b/dom/media/gtest/TestEME.cpp
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/EMEUtils.h"
+
+using namespace std;
+using namespace mozilla;
+
+struct ParseKeySystemTestCase {
+  const char16_t* mInputKeySystemString;
+  int32_t mOutCDMVersion;
+  bool mShouldPass;
+};
+
+const ParseKeySystemTestCase ParseKeySystemTests[] = {
+  {
+    MOZ_UTF16("org.w3.clearkey"),
+    NO_CDM_VERSION,
+    true,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.123"),
+    123,
+    true,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.-1"),
+    NO_CDM_VERSION,
+    false,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.NaN"),
+    NO_CDM_VERSION,
+    false,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.0"),
+    0,
+    true,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.123567890123567890123567890123567890123567890"),
+    NO_CDM_VERSION,
+    false,
+  }, {
+    MOZ_UTF16("org.w3.clearkey.0.1"),
+    NO_CDM_VERSION,
+    false,
+  }
+};
+
+TEST(EME, EMEParseKeySystem) {
+  const nsAutoString clearkey(MOZ_UTF16("org.w3.clearkey"));
+  for (const ParseKeySystemTestCase& test : ParseKeySystemTests) {
+    nsAutoString keySystem;
+    int32_t version;
+    bool rv = ParseKeySystem(nsDependentString(test.mInputKeySystemString),
+                             keySystem,
+                             version);
+    EXPECT_EQ(rv, test.mShouldPass) << "parse should succeed if expected to";
+    if (!test.mShouldPass) {
+      continue;
+    }
+    EXPECT_TRUE(keySystem.Equals(clearkey)) << NS_ConvertUTF16toUTF8(keySystem).get(); //"should extract expected keysystem" << ;
+    EXPECT_EQ(test.mOutCDMVersion, version) << "should extract expected version";
+  }
+}
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -10,16 +10,21 @@ SOURCES += [
     'TestGMPCrossOrigin.cpp',
     'TestMP4Demuxer.cpp',
     'TestMP4Reader.cpp',
     'TestTrackEncoder.cpp',
     'TestVideoSegment.cpp',
     'TestWebMBuffered.cpp',
 ]
 
+if CONFIG['MOZ_EME']:
+    SOURCES += [
+        'TestEME.cpp',
+    ]
+
 if CONFIG['MOZ_WEBM_ENCODER']:
     SOURCES += [
         'TestVideoTrackEncoder.cpp',
         'TestVorbisTrackEncoder.cpp',
         'TestWebMWriter.cpp',
     ]
 
 TEST_HARNESS_FILES.gtest += [
@@ -29,16 +34,17 @@ TEST_HARNESS_FILES.gtest += [
     'mediasource_test.mp4',
     'test.webm',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/dom/media',
+    '/dom/media/eme',
     '/dom/media/encoder',
     '/dom/media/fmp4',
     '/dom/media/gmp',
     '/security/certverifier',
     '/security/pkix/include',
 ]
 
 FINAL_LIBRARY = 'xul-gtest'
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -554,16 +554,26 @@ SourceBuffer::PrepareAppend(const uint8_
     MSE_DEBUG("AppendData Evict; current buffered start=%f",
               GetBufferedStart());
 
     // We notify that we've evicted from the time range 0 through to
     // the current start point.
     mMediaSource->NotifyEvicted(0.0, newBufferStartTime);
   }
 
+  // See if we have enough free space to append our new data.
+  // As we can only evict once we have playable data, we must give a chance
+  // to the DASH player to provide a complete media segment.
+  if (aLength > mEvictionThreshold ||
+      ((mTrackBuffer->GetSize() > mEvictionThreshold - aLength) &&
+       !mTrackBuffer->HasOnlyIncompleteMedia())) {
+    aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
+    return nullptr;
+  }
+
   nsRefPtr<LargeDataBuffer> data = new LargeDataBuffer();
   if (!data->AppendElements(aData, aLength)) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
   }
   // TODO: Test buffer full flag.
   return data.forget();
 }
--- a/dom/media/mediasource/TrackBuffer.cpp
+++ b/dom/media/mediasource/TrackBuffer.cpp
@@ -301,20 +301,17 @@ TrackBuffer::EvictData(double aPlaybackT
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
 
   if (!mCurrentDecoder) {
     return false;
   }
 
-  int64_t totalSize = 0;
-  for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
-    totalSize += mDecoders[i]->GetResource()->GetSize();
-  }
+  int64_t totalSize = GetSize();
 
   int64_t toEvict = totalSize - aThreshold;
   if (toEvict <= 0 || mInitializedDecoders.IsEmpty()) {
     return false;
   }
 
   // Get a list of initialized decoders.
   nsTArray<SourceBufferDecoder*> decoders;
@@ -444,16 +441,37 @@ TrackBuffer::RemoveEmptyDecoders(nsTArra
         buffered->GetStartTime() < 0.0 ||
         buffered->GetEndTime() < 0.0) {
       MSE_DEBUG("remove empty decoders=%d", i);
       RemoveDecoder(aDecoders[i]);
     }
   }
 }
 
+int64_t
+TrackBuffer::GetSize()
+{
+  int64_t totalSize = 0;
+  for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) {
+    totalSize += mInitializedDecoders[i]->GetResource()->GetSize();
+  }
+  return totalSize;
+}
+
+bool
+TrackBuffer::HasOnlyIncompleteMedia()
+{
+  if (!mCurrentDecoder) {
+    return false;
+  }
+  nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
+  mCurrentDecoder->GetBuffered(buffered);
+  return mCurrentDecoder->GetResource()->GetSize() && !buffered->Length();
+}
+
 void
 TrackBuffer::EvictBefore(double aTime)
 {
   MOZ_ASSERT(NS_IsMainThread());
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) {
     int64_t endOffset = mInitializedDecoders[i]->ConvertToByteOffset(aTime);
     if (endOffset > 0) {
--- a/dom/media/mediasource/TrackBuffer.h
+++ b/dom/media/mediasource/TrackBuffer.h
@@ -99,16 +99,23 @@ public:
   // Implementation is only partial, we can only trim a buffer.
   // Returns true if data was evicted.
   // Times are in microseconds.
   bool RangeRemoval(int64_t aStart, int64_t aEnd);
 
   // Abort any pending appendBuffer by rejecting any pending promises.
   void AbortAppendData();
 
+  // Return the size used by all decoders managed by this TrackBuffer.
+  int64_t GetSize();
+
+  // Return true if we have a partial media segment being appended that is
+  // currently not playable.
+  bool HasOnlyIncompleteMedia();
+
 #ifdef MOZ_EME
   nsresult SetCDMProxy(CDMProxy* aProxy);
 #endif
 
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif
 
--- a/dom/media/mediasource/test/test_SeekableBeforeEndOfStreamSplit.html
+++ b/dom/media/mediasource/test/test_SeekableBeforeEndOfStreamSplit.html
@@ -14,16 +14,17 @@ SimpleTest.waitForExplicitFinish();
 
 runWithMSE(function (ms, v) {
   ms.addEventListener("sourceopen", function () {
     var sb = ms.addSourceBuffer("video/webm");
 
     fetchWithXHR("seek.webm", function (arrayBuffer) {
       sb.appendBuffer(new Uint8Array(arrayBuffer, 0, 25223));
       sb.addEventListener("updateend", function () {
+        sb.removeEventListener('updateend', arguments.callee);
         sb.appendBuffer(new Uint8Array(arrayBuffer, 25223));
       });
     });
 
     var target = 2;
 
     v.addEventListener("loadedmetadata", function () {
       ok(v.seekable.length, "Resource is seekable");
--- a/dom/media/test/test_eme_requestKeySystemAccess.html
+++ b/dom/media/test/test_eme_requestKeySystemAccess.html
@@ -261,16 +261,36 @@ var tests = [
     options: [
       {
         initDataType: 'webm',
         videoType: 'video/webm',
       }
     ],
     shouldPass: false,
   },
+  {
+    name: "CDM version less than",
+    keySystem: CLEARKEY_ID + ".0",
+    shouldPass: true
+  },
+  {
+    name: "CDM version equal to",
+    keySystem: CLEARKEY_ID + ".1",
+    shouldPass: true
+  },
+  {
+    name: "CDM version greater than",
+    keySystem: CLEARKEY_ID + ".2",
+    shouldPass: false
+  },
+  {
+    name: "Non-whole number CDM version",
+    keySystem: CLEARKEY_ID + ".0.1",
+    shouldPass: false
+  },
 ];
 
 function beginTest() {
   Promise.all(tests.map(Test)).then(function() { SimpleTest.finish(); });
 }
 
 var prefs = [
   [ "media.mediasource.enabled", true ],
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -14,16 +14,17 @@
 #include "nsIWebProgressListener.h"
 #include "nsContentUtils.h"
 #include "nsNetUtil.h"
 #include "nsIRequest.h"
 #include "nsIDocument.h"
 #include "nsIContentViewer.h"
 #include "nsIChannel.h"
 #include "nsIHttpChannel.h"
+#include "nsIParentChannel.h"
 #include "mozilla/Preferences.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsISecureBrowserUI.h"
 #include "nsIDocumentLoader.h"
 #include "nsIWebNavigation.h"
 #include "nsLoadGroup.h"
 #include "nsIScriptError.h"
 #include "nsIURI.h"
@@ -209,16 +210,26 @@ nsMixedContentBlocker::AsyncOnChannelRed
 {
   nsAsyncRedirectAutoCallback autoCallback(aCallback);
 
   if (!aOldChannel) {
     NS_ERROR("No channel when evaluating mixed content!");
     return NS_ERROR_FAILURE;
   }
 
+  // If we are in the parent process in e10s, we don't have access to the
+  // document node, and hence ShouldLoad will fail when we try to get
+  // the docShell.  If that's the case, ignore mixed content checks
+  // on redirects in the parent.  Let the child check for mixed content.
+  nsCOMPtr<nsIParentChannel> is_ipc_channel;
+  NS_QueryNotificationCallbacks(aNewChannel, is_ipc_channel);
+  if (is_ipc_channel) {
+    return NS_OK;
+  }
+
   nsresult rv;
   nsCOMPtr<nsIURI> oldUri;
   rv = aOldChannel->GetURI(getter_AddRefs(oldUri));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIURI> newUri;
   rv = aNewChannel->GetURI(getter_AddRefs(newUri));
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/webidl/Apps.webidl
+++ b/dom/webidl/Apps.webidl
@@ -6,17 +6,17 @@
 
 dictionary InstallParameters {
   sequence<DOMString> receipts = [];
   sequence<DOMString> categories = [];
 };
 
 dictionary LanguageDesc {
   DOMString target;
-  DOMString version;
+  long revision;
   DOMString name;
 };
 
 enum LocaleResourceType {
   "binary",
   "json",
   "text"
 };
--- a/dom/webidl/MediaKeysRequestStatus.webidl
+++ b/dom/webidl/MediaKeysRequestStatus.webidl
@@ -5,16 +5,17 @@
  */
 
 enum MediaKeySystemStatus {
   "available",
   "api-disabled",
   "cdm-disabled",
   "cdm-not-supported",
   "cdm-not-installed",
+  "cdm-insufficient-version",
   "cdm-created",
   "error"
 };
 
 dictionary RequestMediaKeySystemAccessNotification {
   required DOMString keySystem;
   required MediaKeySystemStatus status;
 };
--- a/dom/webidl/Request.webidl
+++ b/dom/webidl/Request.webidl
@@ -18,17 +18,18 @@ interface Request {
   [SameObject] readonly attribute Headers headers;
 
   readonly attribute RequestContext context;
   readonly attribute DOMString referrer;
   readonly attribute RequestMode mode;
   readonly attribute RequestCredentials credentials;
   readonly attribute RequestCache cache;
 
-  [NewObject] Request clone();
+  [Throws,
+   NewObject] Request clone();
 
   // Bug 1124638 - Allow chrome callers to set the context.
   [ChromeOnly]
   void setContext(RequestContext context);
 };
 Request implements Body;
 
 dictionary RequestInit {
--- a/dom/webidl/Response.webidl
+++ b/dom/webidl/Response.webidl
@@ -20,17 +20,18 @@ interface Response {
   readonly attribute USVString url;
   [Throws]
            attribute boolean finalURL;
   readonly attribute unsigned short status;
   readonly attribute boolean ok;
   readonly attribute ByteString statusText;
   [SameObject] readonly attribute Headers headers;
 
-  [NewObject] Response clone();
+  [Throws,
+   NewObject] Response clone();
 };
 Response implements Body;
 
 dictionary ResponseInit {
   unsigned short status = 200;
   // WebIDL spec doesn't allow default values for ByteString.
   ByteString statusText;
   HeadersInit headers;
--- a/dom/workers/test/fetch/worker_test_request.js
+++ b/dom/workers/test/fetch/worker_test_request.js
@@ -22,31 +22,80 @@ function testDefaultCtor() {
   is(req.url, self.location.href, "URL should be resolved with entry settings object's API base URL");
   is(req.context, "fetch", "Default context is fetch.");
   is(req.referrer, "about:client", "Default referrer is `client` which serializes to about:client.");
   is(req.mode, "cors", "Request mode string input is cors");
   is(req.credentials, "omit", "Default Request credentials is omit");
 }
 
 function testClone() {
-  var req = (new Request("./cloned_request.txt", {
+  var orig = new Request("./cloned_request.txt", {
               method: 'POST',
               headers: { "Content-Length": 5 },
               body: "Sample body",
               mode: "same-origin",
               credentials: "same-origin",
-            })).clone();
-  ok(req.method === "POST", "Request method is POST");
-  ok(req.headers instanceof Headers, "Request should have non-null Headers object");
-  is(req.headers.get('content-length'), "5", "Request content-length should be 5.");
-  ok(req.url === (new URL("./cloned_request.txt", self.location.href)).href,
+            });
+  var clone = orig.clone();
+  ok(clone.method === "POST", "Request method is POST");
+  ok(clone.headers instanceof Headers, "Request should have non-null Headers object");
+
+  is(clone.headers.get('content-length'), "5", "Response content-length should be 5.");
+  orig.headers.set('content-length', 6);
+  is(clone.headers.get('content-length'), "5", "Request content-length should be 5.");
+
+  ok(clone.url === (new URL("./cloned_request.txt", self.location.href)).href,
        "URL should be resolved with entry settings object's API base URL");
-  ok(req.referrer === "about:client", "Default referrer is `client` which serializes to about:client.");
-  ok(req.mode === "same-origin", "Request mode is same-origin");
-  ok(req.credentials === "same-origin", "Default credentials is same-origin");
+  ok(clone.referrer === "about:client", "Default referrer is `client` which serializes to about:client.");
+  ok(clone.mode === "same-origin", "Request mode is same-origin");
+  ok(clone.credentials === "same-origin", "Default credentials is same-origin");
+
+  ok(!orig.bodyUsed, "Original body is not consumed.");
+  ok(!clone.bodyUsed, "Clone body is not consumed.");
+
+  var origBody = null;
+  var clone2 = null;
+  return orig.text().then(function (body) {
+    origBody = body;
+    is(origBody, "Sample body", "Original body string matches");
+    ok(orig.bodyUsed, "Original body is consumed.");
+    ok(!clone.bodyUsed, "Clone body is not consumed.");
+
+    try {
+      orig.clone()
+      ok(false, "Cannot clone Request whose body is already consumed");
+    } catch (e) {
+      is(e.name, "TypeError", "clone() of consumed body should throw TypeError");
+    }
+
+    clone2 = clone.clone();
+    return clone.text();
+  }).then(function (body) {
+    is(body, origBody, "Clone body matches original body.");
+    ok(clone.bodyUsed, "Clone body is consumed.");
+
+    try {
+      clone.clone()
+      ok(false, "Cannot clone Request whose body is already consumed");
+    } catch (e) {
+      is(e.name, "TypeError", "clone() of consumed body should throw TypeError");
+    }
+
+    return clone2.text();
+  }).then(function (body) {
+    is(body, origBody, "Clone body matches original body.");
+    ok(clone2.bodyUsed, "Clone body is consumed.");
+
+    try {
+      clone2.clone()
+      ok(false, "Cannot clone Request whose body is already consumed");
+    } catch (e) {
+      is(e.name, "TypeError", "clone() of consumed body should throw TypeError");
+    }
+  });
 }
 
 function testUsedRequest() {
   // Passing a used request should fail.
   var req = new Request("", { method: 'post', body: "This is foo" });
   var p1 = req.text().then(function(v) {
     try {
       var req2 = new Request(req);
@@ -261,27 +310,27 @@ function testModeCorsPreflightEnumValue(
        "mode cors-with-forced-preflight should throw same error as invalid RequestMode strings.");
   }
 }
 
 onmessage = function() {
   var done = function() { postMessage({ type: 'finish' }) }
 
   testDefaultCtor();
-  testClone();
   testSimpleUrlParse();
   testUrlFragment();
   testMethod();
   testBug1109574();
   testModeCorsPreflightEnumValue();
 
   Promise.resolve()
     .then(testBodyCreation)
     .then(testBodyUsed)
     .then(testBodyExtraction)
     .then(testUsedRequest)
+    .then(testClone())
     // Put more promise based tests here.
     .then(done)
     .catch(function(e) {
       ok(false, "Some Request tests failed " + e);
       done();
     })
 }
--- a/dom/workers/test/fetch/worker_test_response.js
+++ b/dom/workers/test/fetch/worker_test_response.js
@@ -13,25 +13,73 @@ function testDefaultCtor() {
   is(res.type, "default", "Default Response type is default");
   ok(res.headers instanceof Headers, "Response should have non-null Headers object");
   is(res.url, "", "URL should be empty string");
   is(res.status, 200, "Default status is 200");
   is(res.statusText, "OK", "Default statusText is OK");
 }
 
 function testClone() {
-  var res = (new Response("This is a body", {
+  var orig = new Response("This is a body", {
               status: 404,
               statusText: "Not Found",
               headers: { "Content-Length": 5 },
-            })).clone();
-  is(res.status, 404, "Response status is 404");
-  is(res.statusText, "Not Found", "Response statusText is POST");
-  ok(res.headers instanceof Headers, "Response should have non-null Headers object");
-  is(res.headers.get('content-length'), "5", "Response content-length should be 5.");
+            });
+  var clone = orig.clone();
+  is(clone.status, 404, "Response status is 404");
+  is(clone.statusText, "Not Found", "Response statusText is POST");
+  ok(clone.headers instanceof Headers, "Response should have non-null Headers object");
+
+  is(clone.headers.get('content-length'), "5", "Response content-length should be 5.");
+  orig.headers.set('content-length', 6);
+  is(clone.headers.get('content-length'), "5", "Response content-length should be 5.");
+
+  ok(!orig.bodyUsed, "Original body is not consumed.");
+  ok(!clone.bodyUsed, "Clone body is not consumed.");
+
+  var origBody = null;
+  var clone2 = null;
+  return orig.text().then(function (body) {
+    origBody = body;
+    is(origBody, "This is a body", "Original body string matches");
+    ok(orig.bodyUsed, "Original body is consumed.");
+    ok(!clone.bodyUsed, "Clone body is not consumed.");
+
+    try {
+      orig.clone()
+      ok(false, "Cannot clone Response whose body is already consumed");
+    } catch (e) {
+      is(e.name, "TypeError", "clone() of consumed body should throw TypeError");
+    }
+
+    clone2 = clone.clone();
+    return clone.text();
+  }).then(function (body) {
+    is(body, origBody, "Clone body matches original body.");
+    ok(clone.bodyUsed, "Clone body is consumed.");
+
+    try {
+      clone.clone()
+      ok(false, "Cannot clone Response whose body is already consumed");
+    } catch (e) {
+      is(e.name, "TypeError", "clone() of consumed body should throw TypeError");
+    }
+
+    return clone2.text();
+  }).then(function (body) {
+    is(body, origBody, "Clone body matches original body.");
+    ok(clone2.bodyUsed, "Clone body is consumed.");
+
+    try {
+      clone2.clone()
+      ok(false, "Cannot clone Response whose body is already consumed");
+    } catch (e) {
+      is(e.name, "TypeError", "clone() of consumed body should throw TypeError");
+    }
+  });
 }
 
 function testRedirect() {
   var res = Response.redirect("./redirect.response");
   is(res.status, 302, "Default redirect has status code 302");
   var h = res.headers.get("location");
   ok(h === (new URL("./redirect.response", self.location.href)).href, "Location header should be correct absolute URL");
 
@@ -164,24 +212,24 @@ function testBodyExtraction() {
     });
   })
 }
 
 onmessage = function() {
   var done = function() { postMessage({ type: 'finish' }) }
 
   testDefaultCtor();
-  testClone();
   testRedirect();
   testOk();
   testFinalURL();
 
   Promise.resolve()
     .then(testBodyCreation)
     .then(testBodyUsed)
     .then(testBodyExtraction)
+    .then(testClone)
     // Put more promise based tests here.
     .then(done)
     .catch(function(e) {
       ok(false, "Some Response tests failed " + e);
       done();
     })
 }
--- a/extensions/gio/nsGIOProtocolHandler.cpp
+++ b/extensions/gio/nsGIOProtocolHandler.cpp
@@ -1058,43 +1058,22 @@ nsGIOProtocolHandler::NewChannel2(nsIURI
   if (NS_FAILED(rv))
     return rv;
 
   nsRefPtr<nsGIOInputStream> stream = new nsGIOInputStream(spec);
   if (!stream) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  // Bug 1087720 (and Bug 1099296):
-  // Once all callsites have been updated to call NewChannel2() instead of NewChannel()
-  // we should have a non-null loadInfo consistently. Until then we have to brach on the
-  // loadInfo and provide default arguments to create a NewInputStreamChannel.
-  if (aLoadInfo) {
-    rv = NS_NewInputStreamChannelInternal(aResult,
-                                          aURI,
-                                          stream,
-                                          NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE),
-                                          EmptyCString(), // aContentCharset
-                                          aLoadInfo);
-  }
-  else {
-    nsCOMPtr<nsIPrincipal> nullPrincipal =
-      do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // start out assuming an unknown content-type.  we'll set the content-type
-    // to something better once we open the URI.
-    rv = NS_NewInputStreamChannel(aResult,
-                                  aURI,
-                                  stream,
-                                  nullPrincipal,
-                                  nsILoadInfo::SEC_NORMAL,
-                                  nsIContentPolicy::TYPE_OTHER,
-                                  NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE));
-  }
+  rv = NS_NewInputStreamChannelInternal(aResult,
+                                        aURI,
+                                        stream,
+                                        NS_LITERAL_CSTRING(UNKNOWN_CONTENT_TYPE),
+                                        EmptyCString(), // aContentCharset
+                                        aLoadInfo);
   if (NS_SUCCEEDED(rv)) {
     stream->SetChannel(*aResult);
   }
   return rv;
 }
 
 NS_IMETHODIMP
 nsGIOProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **aResult)
--- a/gfx/src/FilterSupport.cpp
+++ b/gfx/src/FilterSupport.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FilterSupport.h"
 
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Filters.h"
+#include "mozilla/gfx/Logging.h"
 #include "mozilla/PodOperations.h"
 
 #include "gfxContext.h"
 #include "gfxPattern.h"
 #include "gfxPlatform.h"
 #include "gfx2DGlue.h"
 
 #include "nsMargin.h"
@@ -394,18 +395,19 @@ ComputeColorMatrix(uint32_t aColorMatrix
   static const float hueRotateR = 0.143f;
   static const float hueRotateG = 0.140f;
   static const float hueRotateB = 0.283f;
 
   switch (aColorMatrixType) {
 
     case SVG_FECOLORMATRIX_TYPE_MATRIX:
     {
-      if (aValues.Length() != 20)
+      if (aValues.Length() != 20) {
         return NS_ERROR_FAILURE;
+      }
 
       PodCopy(aOutMatrix, aValues.Elements(), 20);
       break;
     }
 
     case SVG_FECOLORMATRIX_TYPE_SATURATE:
     {
       if (aValues.Length() != 1)
@@ -1474,17 +1476,17 @@ FilterSupport::PostFilterExtentsForPrimi
       }
       return ThebesIntRect(aDescription.PrimitiveSubregion());
     }
 
     case PrimitiveType::ColorMatrix:
     {
       if (atts.GetUint(eColorMatrixType) == (uint32_t)SVG_FECOLORMATRIX_TYPE_MATRIX) {
         const nsTArray<float>& values = atts.GetFloats(eColorMatrixValues);
-        if (values[19] > 0.0f) {
+        if (values.Length() == 20 && values[19] > 0.0f) {
           return ThebesIntRect(aDescription.PrimitiveSubregion());
         }
       }
       return aInputExtents[0];
     }
 
     case PrimitiveType::ComponentTransfer:
     {
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2955,25 +2955,31 @@ nsDisplayThemedBackground::GetBoundsInte
 #ifdef XP_MACOSX
   // Bug 748219
   r.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel());
 #endif
 
   return r + ToReferenceFrame();
 }
 
-bool
+void
 nsDisplayBackgroundColor::ApplyOpacity(nsDisplayListBuilder* aBuilder,
                                        float aOpacity,
                                        const DisplayItemClip* aClip)
 {
+  NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
   mColor.a = mColor.a * aOpacity;
   if (aClip) {
     IntersectClip(aBuilder, *aClip);
   }
+}
+
+bool
+nsDisplayBackgroundColor::CanApplyOpacity() const
+{
   return true;
 }
 
 void
 nsDisplayBackgroundColor::Paint(nsDisplayListBuilder* aBuilder,
                                 nsRenderingContext* aCtx)
 {
   DrawTarget& aDrawTarget = *aCtx->GetDrawTarget();
@@ -3817,43 +3823,76 @@ nsDisplayOpacity::NeedsActiveLayer(nsDis
     if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(),
                                                   eCSSProperty_opacity)) {
       return true;
     }
   }
   return false;
 }
 
-bool
+void
 nsDisplayOpacity::ApplyOpacity(nsDisplayListBuilder* aBuilder,
                              float aOpacity,
                              const DisplayItemClip* aClip)
 {
+  NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
   mOpacity = mOpacity * aOpacity;
   if (aClip) {
     IntersectClip(aBuilder, *aClip);
   }
+}
+
+bool
+nsDisplayOpacity::CanApplyOpacity() const
+{
   return true;
 }
 
 bool
 nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
 {
   if (NeedsActiveLayer(aBuilder))
     return false;
 
   nsDisplayItem* child = mList.GetBottom();
-  // Only try folding our opacity down if we have a single
-  // child. We could potentially do this also if we had multiple
-  // children as long as they don't overlap.
-  if (!child || child->GetAbove()) {
+  // Only try folding our opacity down if we have at most three children
+  // that don't overlap and can all apply the opacity to themselves.
+  if (!child) {
     return false;
   }
-
-  return child->ApplyOpacity(aBuilder, mOpacity, mClip);
+  struct {
+    nsDisplayItem* item;
+    nsRect bounds;
+  } children[3];
+  bool snap;
+  uint32_t numChildren = 0;
+  for (; numChildren < ArrayLength(children) && child; numChildren++, child = child->GetAbove()) {
+    if (!child->CanApplyOpacity()) {
+      return false;
+    }
+    children[numChildren].item = child;
+    children[numChildren].bounds = child->GetBounds(aBuilder, &snap);
+  }
+  if (child) {
+    // we have a fourth (or more) child
+    return false;
+  }
+
+  for (uint32_t i = 0; i < numChildren; i++) {
+    for (uint32_t j = i+1; j < numChildren; j++) {
+      if (children[i].bounds.Intersects(children[j].bounds)) {
+        return false;
+      }
+    }
+  }
+
+  for (uint32_t i = 0; i < numChildren; i++) {
+    children[i].item->ApplyOpacity(aBuilder, mOpacity, mClip);
+  }
+  return true;
 }
 
 nsDisplayItem::LayerState
 nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
                                 LayerManager* aManager,
                                 const ContainerLayerParameters& aParameters) {
   if (NeedsActiveLayer(aBuilder))
     return LAYER_ACTIVE;
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1362,22 +1362,29 @@ public:
    * Returns the visible rect for the children, relative to their
    * reference frame. Can be different from mVisibleRect for nsDisplayTransform,
    * since the reference frame for the children is different from the reference
    * frame for the item itself.
    */
   virtual const nsRect& GetVisibleRectForChildren() const { return mVisibleRect; }
 
   /**
-   * Stores the given opacity value to be applied when drawing. Returns
-   * false if this isn't supported for this display item.
+   * Stores the given opacity value to be applied when drawing. It is an error to
+   * call this if CanApplyOpacity returned false.
    */
-  virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder,
+  virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
                             float aOpacity,
                             const DisplayItemClip* aClip) {
+    NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity not supported on this type");
+  }
+  /**
+   * Returns true if this display item would return true from ApplyOpacity without
+   * actually applying the opacity. Otherwise returns false.
+   */
+  virtual bool CanApplyOpacity() const {
     return false;
   }
 
   /**
    * For debugging and stuff
    */
   virtual const char* Name() = 0;
 
@@ -2372,19 +2379,20 @@ public:
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
 
   virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                    bool* aSnap) MOZ_OVERRIDE;
   virtual bool IsUniform(nsDisplayListBuilder* aBuilder, nscolor* aColor) MOZ_OVERRIDE;
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE;
 
-  virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder,
+  virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
                             float aOpacity,
                             const DisplayItemClip* aClip) MOZ_OVERRIDE;
+  virtual bool CanApplyOpacity() const MOZ_OVERRIDE;
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE
   {
     *aSnap = true;
     return nsRect(ToReferenceFrame(), Frame()->GetSize());
   }
 
   virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
@@ -2481,24 +2489,28 @@ public:
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                  nsRegion* aVisibleRegion) MOZ_OVERRIDE;
   NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER)
   
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion* aInvalidRegion) MOZ_OVERRIDE;
   
-  virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder,
+  virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
                             float aOpacity,
                             const DisplayItemClip* aClip) MOZ_OVERRIDE
   {
+    NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
     mOpacity = aOpacity;
     if (aClip) {
       IntersectClip(aBuilder, *aClip);
     }
+  }
+  virtual bool CanApplyOpacity() const MOZ_OVERRIDE
+  {
     return true;
   }
 
   virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
   {
     return new nsDisplayBoxShadowOuterGeometry(this, aBuilder, mOpacity);
   }
 
@@ -2631,16 +2643,27 @@ public:
     return nsRect();
   }
   nsRect GetHitRegionBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
   {
     *aSnap = false;
     return mHitRegion.GetBounds().Union(mMaybeHitRegion.GetBounds());
   }
 
+  virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
+                            float aOpacity,
+                            const DisplayItemClip* aClip) MOZ_OVERRIDE
+  {
+    NS_ASSERTION(CanApplyOpacity(), "ApplyOpacity should be allowed");
+  }
+  virtual bool CanApplyOpacity() const MOZ_OVERRIDE
+  {
+    return true;
+  }
+
   NS_DISPLAY_DECL_NAME("LayerEventRegions", TYPE_LAYER_EVENT_REGIONS)
 
   // Indicate that aFrame's border-box contributes to the event regions for
   // this layer. aFrame must have the same reference frame as mFrame.
   void AddFrame(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
 
   // Indicate that an inactive scrollframe's scrollport should be added to the
   // dispatch-to-content region, to ensure that APZ lets content create a
@@ -2860,19 +2883,20 @@ public:
                                  nsRegion* aVisibleRegion) MOZ_OVERRIDE;
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) MOZ_OVERRIDE;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion* aInvalidRegion) MOZ_OVERRIDE
   {
     // We don't need to compute an invalidation region since we have LayerTreeInvalidation
   }
-  virtual bool ApplyOpacity(nsDisplayListBuilder* aBuilder,
+  virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder,
                             float aOpacity,
                             const DisplayItemClip* aClip) MOZ_OVERRIDE;
+  virtual bool CanApplyOpacity() const MOZ_OVERRIDE;
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
   bool NeedsActiveLayer(nsDisplayListBuilder* aBuilder);
   NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
   virtual void WriteDebugInfo(std::stringstream& aStream) MOZ_OVERRIDE;
 
   bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
 
 private:
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -311,17 +311,17 @@ nsLayoutStatics::Initialize()
 }
 
 void
 nsLayoutStatics::Shutdown()
 {
   // Don't need to shutdown nsWindowMemoryReporter, that will be done by the
   // memory reporter manager.
 
-  nsFrameScriptExecutor::Shutdown();
+  nsMessageManagerScriptExecutor::Shutdown();
   nsFocusManager::Shutdown();
 #ifdef MOZ_XUL
   nsXULPopupManager::Shutdown();
 #endif
   DOMStorageObserver::Shutdown();
   txMozillaXSLTProcessor::Shutdown();
   Attr::Shutdown();
   EventListenerManager::Shutdown();
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -2966,17 +2966,17 @@ nsLineLayout::ExpandRubyBoxWithAnnotatio
     }
 
     MOZ_ASSERT(annotation->mSpan);
     JustificationComputationState computeState;
     ComputeFrameJustification(annotation->mSpan, computeState);
     if (!computeState.mFirstParticipant) {
       continue;
     }
-    if (IsRubyAlignSpaceAround(aFrame->mFrame)) {
+    if (IsRubyAlignSpaceAround(annotation->mFrame)) {
       // Add one gap at each side of this annotation.
       computeState.mFirstParticipant->mJustificationAssignment.mGapsAtStart = 1;
       computeState.mLastParticipant->mJustificationAssignment.mGapsAtEnd = 1;
     }
     nsIFrame* parentFrame = annotation->mFrame->GetParent();
     nscoord containerWidth = parentFrame->GetRect().Width();
     MOZ_ASSERT(containerWidth == aContainerWidth ||
                parentFrame->GetType() == nsGkAtoms::rubyTextContainerFrame,
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -618,16 +618,20 @@ LineBreakBefore(const nsHTMLReflowState&
     gfxSkipCharsIterator iter =
       textFrame->EnsureTextRun(nsTextFrame::eInflated,
                                aReflowState.rendContext->ThebesContext(),
                                aReflowState.mLineLayout->LineContainerFrame(),
                                aReflowState.mLineLayout->GetLine());
     iter.SetOriginalOffset(textFrame->GetContentOffset());
     uint32_t pos = iter.GetSkippedOffset();
     gfxTextRun* textRun = textFrame->GetTextRun(nsTextFrame::eInflated);
+    if (pos >= textRun->GetLength()) {
+      // The text frame contains no character at all.
+      return gfxBreakPriority::eNoBreak;
+    }
     // Return whether we can break before the first character.
     if (textRun->CanBreakLineBefore(pos)) {
       return gfxBreakPriority::eNormalBreak;
     }
     // Check whether we can wrap word here.
     const nsStyleText* textStyle = textFrame->StyleText();
     if (textStyle->WordCanWrap(textFrame) && textRun->IsClusterStart(pos)) {
       return gfxBreakPriority::eWordWrapBreak;
--- a/layout/reftests/bugs/1119117-1-ref.html
+++ b/layout/reftests/bugs/1119117-1-ref.html
@@ -1,15 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <style>
 #image {
   position:fixed;
-  opacity:0.5;
+  opacity:0.50196078431;
   left:0;
   top:0;
   width:100%;
   height:100%;
   background:blue;
 }
 </style>
 </head>
--- a/layout/reftests/bugs/1119117-1a.html
+++ b/layout/reftests/bugs/1119117-1a.html
@@ -2,17 +2,17 @@
 <html>
 <head>
 <style>
 #d1 {
   overflow:hidden;
   height:0;
 }
 #d2 {
-  opacity:0.5;
+  opacity:0.50196078431;
 }
 #d3 {
   position:absolute;
   left:0;
   top:0;
   width:100%;
   height:100%;
   background:blue;
--- a/layout/reftests/bugs/1119117-1b.html
+++ b/layout/reftests/bugs/1119117-1b.html
@@ -2,17 +2,17 @@
 <html>
 <head>
 <style>
 #d1 {
   overflow:hidden;
   height:0;
 }
 #d2 {
-  opacity:0.5;
+  opacity:0.50196078431;
 }
 #image {
   position:fixed;
   left:0;
   top:0;
   width:100%;
   height:100%;
   background:blue;
--- a/layout/reftests/css-ruby/reftest.list
+++ b/layout/reftests/css-ruby/reftest.list
@@ -26,17 +26,19 @@ default-preferences pref(layout.css.ruby
 == line-height-2.html line-height-2-ref.html
 == line-height-3.html line-height-3-ref.html
 == line-height-4.html line-height-4-ref.html
 load nested-ruby-1.html
 == no-transform.html no-transform-ref.html
 == relative-positioning-1.html relative-positioning-1-ref.html
 == relative-positioning-2.html relative-positioning-2-ref.html
 == ruby-align-1.html ruby-align-1-ref.html
+== ruby-align-1a.html ruby-align-1-ref.html
 == ruby-align-2.html ruby-align-2-ref.html
+== ruby-align-2a.html ruby-align-2-ref.html
 == ruby-position-horizontal.html ruby-position-horizontal-ref.html
 pref(layout.css.vertical-text.enabled,true) fails == ruby-position-vertical-lr.html ruby-position-vertical-lr-ref.html # bug 1112474
 pref(layout.css.vertical-text.enabled,true) fails == ruby-position-vertical-rl.html ruby-position-vertical-rl-ref.html # bug 1112474
 != ruby-reflow-1-opaqueruby.html ruby-reflow-1-noruby.html
 == ruby-reflow-1-transparentruby.html ruby-reflow-1-noruby.html
 == ruby-span-1.html ruby-span-1-ref.html
 == ruby-whitespace-1.html ruby-whitespace-1-ref.html
 == ruby-whitespace-2.html ruby-whitespace-2-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/ruby-align-1a.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 1055676 - Tests for ruby-align</title>
+  <link rel="stylesheet" href="common.css">
+  <style>
+    ruby { line-height: 0; }
+    rt > div { width: 160px; }
+  </style>
+</head>
+<body style="font: 16px/3 Ahem">
+  <ruby>
+    <rb style="ruby-align: start">X X X<rt><div></div></rt>
+  </ruby><br>
+  <ruby>
+    <rb style="ruby-align: center">X X X<rt><div></div></rt>
+  </ruby><br>
+  <ruby>
+    <rb style="ruby-align: space-between">X X X<rt><div></div></rt>
+  </ruby><br>
+  <ruby>
+    <rb style="ruby-align: space-around">X X X<rt><div></div></rt>
+  </ruby>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ruby/ruby-align-2a.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>Bug 1055676 - Tests for ruby-align</title>
+  <link rel="stylesheet" href="common.css">
+  <style>
+    ruby { line-height: 0; }
+    rt { font-size: 100%; }
+    rb > div { width: 160px; }
+  </style>
+</head>
+<body style="font: 16px/3 Ahem">
+  <ruby>
+    <rb><div></div><rt style="ruby-align: start">X X X</rt>
+  </ruby><br>
+  <ruby>
+    <rb><div></div><rt style="ruby-align: center">X X X</rt>
+  </ruby><br>
+  <ruby>
+    <rb><div></div><rt style="ruby-align: space-between">X X X</rt>
+  </ruby><br>
+  <ruby>
+    <rb><div></div><rt style="ruby-align: space-around">X X X</rt>
+  </ruby>
+</body>
+</html>
--- a/media/gmp-clearkey/0.1/clearkey.info.in
+++ b/media/gmp-clearkey/0.1/clearkey.info.in
@@ -1,10 +1,10 @@
 Name: clearkey
-Description: ClearKey decrypt-only GMP plugin
-Version: 0.1
+Description: ClearKey Gecko Media Plugin
+Version: 1
 #ifdef ENABLE_WMF
 APIs: eme-decrypt-v6[org.w3.clearkey], decode-audio[aac:org.w3.clearkey], decode-video[h264:org.w3.clearkey]
 Libraries: dxva2.dll, d3d9.dll, msmpeg2vdec.dll, msmpeg2adec.dll, MSAudDecMFT.dll
 #else
 APIs: eme-decrypt-v6[org.w3.clearkey]
 Libraries:
 #endif
--- a/media/libcubeb/README_MOZILLA
+++ b/media/libcubeb/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb 
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
 
-The git commit ID used was 699aadf4d5e4c14a7e87b4f4add9cbc938feecc2.
+The git commit ID used was cacaae79dd8b7220202d0dfe3f889d55e23a77a5.
--- a/media/libcubeb/src/cubeb-internal.h
+++ b/media/libcubeb/src/cubeb-internal.h
@@ -34,10 +34,17 @@ struct cubeb_ops {
                                     cubeb_device ** const device);
   int (* stream_device_destroy)(cubeb_stream * stream,
                                 cubeb_device * device);
   int (* stream_register_device_changed_callback)(cubeb_stream * stream,
                                                   cubeb_device_changed_callback device_changed_callback);
 
 };
 
+#define XASSERT(expr) do {                                              \
+    if (!(expr)) {                                                      \
+      fprintf(stderr, "%s:%d - fatal error: %s\n", __FILE__, __LINE__, #expr); \
+      *((volatile int *) NULL) = 0;                                     \
+      abort();                                                          \
+    }                                                                   \
+  } while (0)
+
 #endif /* CUBEB_INTERNAL_0eb56756_4e20_4404_a76d_42bf88cd15a5 */
-
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@@ -1,35 +1,30 @@
 /*
  * Copyright  2013 Mozilla Foundation
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 // This enables assert in release, and lets us have debug-only code
-#ifdef NDEBUG
-#define DEBUG
-#undef NDEBUG
-#endif // #ifdef NDEBUG
-
 #if defined(HAVE_CONFIG_H)
 #include "config.h"
 #endif
-#include <assert.h>
 #include <windows.h>
 #include <mmdeviceapi.h>
 #include <windef.h>
 #include <audioclient.h>
 #include <process.h>
 #include <avrt.h>
 #include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
 #include "cubeb/cubeb-stdint.h"
 #include "cubeb_resampler.h"
 #include <stdio.h>
+#include <stdlib.h>
 #include <cmath>
 
 /**Taken from winbase.h, Not in MinGW.*/
 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
 #define STACK_SIZE_PARAM_IS_A_RESERVATION   0x00010000    // Threads only
 #endif
 
 // #define LOGGING_ENABLED
@@ -97,17 +92,17 @@ public:
   {
     DeleteCriticalSection(&critical_section);
   }
 
   void enter()
   {
     EnterCriticalSection(&critical_section);
 #ifdef DEBUG
-    assert(owner != GetCurrentThreadId() && "recursive locking");
+    XASSERT(owner != GetCurrentThreadId() && "recursive locking");
     owner = GetCurrentThreadId();
 #endif
   }
 
   void leave()
   {
 #ifdef DEBUG
     /* GetCurrentThreadId cannot return 0: it is not a the valid thread id */
@@ -117,17 +112,17 @@ public:
   }
 
   /* This is guaranteed to have the good behaviour if it succeeds. The behaviour
    * is undefined otherwise. */
   void assert_current_thread_owns()
   {
 #ifdef DEBUG
     /* This implies owner != 0, because GetCurrentThreadId cannot return 0. */
-    assert(owner == GetCurrentThreadId());
+    XASSERT(owner == GetCurrentThreadId());
 #endif
   }
 
 private:
   CRITICAL_SECTION critical_section;
 #ifdef DEBUG
   DWORD owner;
 #endif
@@ -384,17 +379,17 @@ mono_to_stereo(T * in, long insamples, T
     out[j] = out[j + 1] = in[i];
   }
 }
 
 template<typename T>
 void
 upmix(T * in, long inframes, T * out, int32_t in_channels, int32_t out_channels)
 {
-  assert(out_channels >= in_channels);
+  XASSERT(out_channels >= in_channels);
   /* If we are playing a mono stream over stereo speakers, copy the data over. */
   if (in_channels == 1 && out_channels == 2) {
     mono_to_stereo(in, inframes, out);
     return;
   }
   /* Otherwise, put silence in other channels. */
   long out_index = 0;
   for (long i = 0; i < inframes * in_channels; i += in_channels) {
@@ -407,17 +402,17 @@ upmix(T * in, long inframes, T * out, in
     out_index += out_channels;
   }
 }
 
 template<typename T>
 void
 downmix(T * in, long inframes, T * out, int32_t in_channels, int32_t out_channels)
 {
-  assert(in_channels >= out_channels);
+  XASSERT(in_channels >= out_channels);
   /* We could use a downmix matrix here, applying mixing weight based on the
    * channel, but directsound and winmm simply drop the channels that cannot be
    * rendered by the hardware, so we do the same for consistency. */
   long out_index = 0;
   for (long i = 0; i < inframes * in_channels; i += in_channels) {
     for (int j = 0; j < out_channels; ++j) {
       out[out_index + j] = in[i + j];
     }
@@ -447,28 +442,28 @@ refill(cubeb_stream * stm, float * data,
   }
 
   long out_frames = cubeb_resampler_fill(stm->resampler, dest, frames_needed);
 
   clock_add(stm, roundf(frames_needed * stream_to_mix_samplerate_ratio(stm)));
 
   /* XXX: Handle this error. */
   if (out_frames < 0) {
-    assert(false);
+    XASSERT(false);
   }
 
   /* Go in draining mode if we got fewer frames than requested. */
   if (out_frames < frames_needed) {
     LOG("draining.\n");
     stm->draining = true;
   }
 
   /* If this is not true, there will be glitches.
    * It is alright to have produced less frames if we are draining, though. */
-  assert(out_frames == frames_needed || stm->draining);
+  XASSERT(out_frames == frames_needed || stm->draining);
 
   if (should_upmix(stm)) {
     upmix(dest, out_frames, data,
           stm->stream_params.channels, stm->mix_params.channels);
   } else if (should_downmix(stm)) {
     downmix(dest, out_frames, data,
             stm->stream_params.channels, stm->mix_params.channels);
   }
@@ -534,17 +529,17 @@ wasapi_stream_render_loop(LPVOID stream)
       UINT32 padding;
 
       hr = stm->client->GetCurrentPadding(&padding);
       if (FAILED(hr)) {
         LOG("Failed to get padding\n");
         is_playing = false;
         continue;
       }
-      assert(padding <= stm->buffer_frame_count);
+      XASSERT(padding <= stm->buffer_frame_count);
 
       if (stm->draining) {
         if (padding == 0) {
           stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
           is_playing = false;
         }
         continue;
       }
@@ -567,17 +562,17 @@ wasapi_stream_render_loop(LPVOID stream)
         }
       } else {
         LOG("failed to get buffer.\n");
         is_playing = false;
       }
     }
       break;
     case WAIT_TIMEOUT:
-      assert(stm->shutdown_event == wait_array[0]);
+      XASSERT(stm->shutdown_event == wait_array[0]);
       is_playing = false;
       hr = -1;
       break;
     default:
       LOG("case %d not handled in render loop.", waitResult);
       abort();
     }
   }
@@ -623,17 +618,17 @@ HRESULT register_notification_client(cub
     return hr;
   }
 
   return hr;
 }
 
 HRESULT unregister_notification_client(cubeb_stream * stm)
 {
-  assert(stm);
+  XASSERT(stm);
 
   if (!stm->device_enumerator) {
     return S_OK;
   }
 
   stm->device_enumerator->UnregisterEndpointNotificationCallback(stm->notification_client);
 
   SafeRelease(stm->notification_client);
@@ -763,17 +758,17 @@ wasapi_get_max_channel_count(cubeb * ctx
   HRESULT hr;
   IAudioClient * client;
   WAVEFORMATEX * mix_format;
   auto_com com;
   if (!com.ok()) {
     return CUBEB_ERROR;
   }
 
-  assert(ctx && max_channels);
+  XASSERT(ctx && max_channels);
 
   IMMDevice * device;
   hr = get_default_endpoint(&device);
   if (FAILED(hr)) {
     return CUBEB_ERROR;
   }
 
   hr = device->Activate(__uuidof(IAudioClient),
@@ -915,17 +910,17 @@ handle_channel_layout(cubeb_stream * stm
   switch (stream_params->channels) {
     case 1: /* Mono */
       format_pcm->dwChannelMask = KSAUDIO_SPEAKER_MONO;
       break;
     case 2: /* Stereo */
       format_pcm->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
       break;
     default:
-      assert(false && "Channel layout not supported.");
+      XASSERT(false && "Channel layout not supported.");
       break;
   }
   (*mix_format)->nChannels = stream_params->channels;
   (*mix_format)->nBlockAlign = ((*mix_format)->wBitsPerSample * (*mix_format)->nChannels) / 8;
   (*mix_format)->nAvgBytesPerSec = (*mix_format)->nSamplesPerSec * (*mix_format)->nBlockAlign;
   format_pcm->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
   (*mix_format)->wBitsPerSample = 32;
   format_pcm->Samples.wValidBitsPerSample = (*mix_format)->wBitsPerSample;
@@ -936,17 +931,17 @@ handle_channel_layout(cubeb_stream * stm
                                               *mix_format,
                                               &closest);
 
   if (hr == S_FALSE) {
     /* Not supported, but WASAPI gives us a suggestion. Use it, and handle the
      * eventual upmix/downmix ourselves */
     LOG("Using WASAPI suggested format: channels: %d\n", closest->nChannels);
     WAVEFORMATEXTENSIBLE * closest_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(closest);
-    assert(closest_pcm->SubFormat == format_pcm->SubFormat);
+    XASSERT(closest_pcm->SubFormat == format_pcm->SubFormat);
     CoTaskMemFree(*mix_format);
     *mix_format = closest;
   } else if (hr == AUDCLNT_E_UNSUPPORTED_FORMAT) {
     /* Not supported, no suggestion. This should not happen, but it does in the
      * field with some sound cards. We restore the mix format, and let the rest
      * of the code figure out the right conversion path. */
     **mix_format = hw_mixformat;
   } else if (hr == S_OK) {
@@ -962,17 +957,17 @@ int setup_wasapi_stream(cubeb_stream * s
 
   stm->stream_reset_lock->assert_current_thread_owns();
 
   auto_com com;
   if (!com.ok()) {
     return CUBEB_ERROR;
   }
 
-  assert(!stm->client && "WASAPI stream already setup, close it first.");
+  XASSERT(!stm->client && "WASAPI stream already setup, close it first.");
 
   hr = get_default_endpoint(&device);
   if (FAILED(hr)) {
     LOG("Could not get default endpoint, error: %x\n", hr);
     stm->stream_reset_lock->leave();
     wasapi_stream_destroy(stm);
     return CUBEB_ERROR;
   }
@@ -1091,21 +1086,21 @@ wasapi_stream_init(cubeb * context, cube
 {
   HRESULT hr;
   int rv;
   auto_com com;
   if (!com.ok()) {
     return CUBEB_ERROR;
   }
 
-  assert(context && stream);
+  XASSERT(context && stream);
 
   cubeb_stream * stm = (cubeb_stream *)calloc(1, sizeof(cubeb_stream));
 
-  assert(stm);
+  XASSERT(stm);
 
   stm->context = context;
   stm->data_callback = data_callback;
   stm->state_callback = state_callback;
   stm->user_ptr = user_ptr;
   stm->stream_params = stream_params;
   stm->draining = false;
   stm->latency = latency;
@@ -1155,17 +1150,17 @@ wasapi_stream_init(cubeb * context, cube
 
   *stream = stm;
 
   return CUBEB_OK;
 }
 
 void close_wasapi_stream(cubeb_stream * stm)
 {
-  assert(stm);
+  XASSERT(stm);
 
   stm->stream_reset_lock->assert_current_thread_owns();
 
   SafeRelease(stm->client);
   stm->client = NULL;
 
   SafeRelease(stm->render_client);
   stm->render_client = NULL;
@@ -1176,17 +1171,17 @@ void close_wasapi_stream(cubeb_stream * 
   }
 
   free(stm->mix_buffer);
   stm->mix_buffer = NULL;
 }
 
 void wasapi_stream_destroy(cubeb_stream * stm)
 {
-  assert(stm);
+  XASSERT(stm);
 
   unregister_notification_client(stm);
 
   stop_and_join_render_thread(stm);
 
   SafeRelease(stm->reconfigure_event);
   SafeRelease(stm->refill_event);
 
@@ -1199,17 +1194,17 @@ void wasapi_stream_destroy(cubeb_stream 
 
   free(stm);
 }
 
 int wasapi_stream_start(cubeb_stream * stm)
 {
   auto_lock lock(stm->stream_reset_lock);
 
-  assert(stm && !stm->thread && !stm->shutdown_event);
+  XASSERT(stm && !stm->thread && !stm->shutdown_event);
 
   stm->shutdown_event = CreateEvent(NULL, 0, 0, NULL);
   if (!stm->shutdown_event) {
     LOG("Can't create the shutdown event, error: %x\n", GetLastError());
     return CUBEB_ERROR;
   }
 
   stm->thread = (HANDLE) _beginthreadex(NULL, 256 * 1024, wasapi_stream_render_loop, stm, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
@@ -1226,17 +1221,17 @@ int wasapi_stream_start(cubeb_stream * s
     stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED);
   }
 
   return FAILED(hr) ? CUBEB_ERROR : CUBEB_OK;
 }
 
 int wasapi_stream_stop(cubeb_stream * stm)
 {
-  assert(stm);
+  XASSERT(stm);
 
   auto_lock lock(stm->stream_reset_lock);
 
   HRESULT hr = stm->client->Stop();
   if (FAILED(hr)) {
     LOG("could not stop AudioClient\n");
   }
 
@@ -1248,26 +1243,26 @@ int wasapi_stream_stop(cubeb_stream * st
     stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
   }
 
   return FAILED(hr) ? CUBEB_ERROR : CUBEB_OK;
 }
 
 int wasapi_stream_get_position(cubeb_stream * stm, uint64_t * position)
 {
-  assert(stm && position);
+  XASSERT(stm && position);
 
   *position = clock_get(stm);
 
   return CUBEB_OK;
 }
 
 int wasapi_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
 {
-  assert(stm && latency);
+  XASSERT(stm && latency);
 
   auto_lock lock(stm->stream_reset_lock);
 
   /* The GetStreamLatency method only works if the
    * AudioClient has been initialized. */
   if (!stm->client) {
     return CUBEB_ERROR;
   }
@@ -1290,17 +1285,17 @@ int wasapi_stream_set_volume(cubeb_strea
   auto_lock lock(stm->stream_reset_lock);
 
   hr = stm->audio_stream_volume->GetChannelCount(&channels);
   if (hr != S_OK) {
     LOG("could not get the channel count: %x\n", hr);
     return CUBEB_ERROR;
   }
 
-  assert(channels <= 10 && "bump the array size");
+  XASSERT(channels <= 10 && "bump the array size");
 
   for (uint32_t i = 0; i < channels; i++) {
     volumes[i] = volume;
   }
 
   hr = stm->audio_stream_volume->SetAllVolumes(channels,  volumes);
   if (hr != S_OK) {
     LOG("could not set the channels volume: %x\n", hr);
--- a/media/libcubeb/src/cubeb_winmm.c
+++ b/media/libcubeb/src/cubeb_winmm.c
@@ -1,27 +1,26 @@
 /*
  * Copyright © 2011 Mozilla Foundation
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
-#undef NDEBUG
 #define __MSVCRT_VERSION__ 0x0700
 #undef WINVER
 #define WINVER 0x0501
 #undef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN
 
 #include <malloc.h>
-#include <assert.h>
 #include <windows.h>
 #include <mmreg.h>
 #include <mmsystem.h>
 #include <process.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
 #include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
 
 /* This is missing from the MinGW headers. Use a safe fallback. */
 #if !defined(MEMORY_ALLOCATION_ALIGNMENT)
 #define MEMORY_ALLOCATION_ALIGNMENT 16
@@ -90,48 +89,48 @@ bytes_per_frame(cubeb_stream_params para
   switch (params.format) {
   case CUBEB_SAMPLE_S16LE:
     bytes = sizeof(signed short);
     break;
   case CUBEB_SAMPLE_FLOAT32LE:
     bytes = sizeof(float);
     break;
   default:
-    assert(0);
+    XASSERT(0);
   }
 
   return bytes * params.channels;
 }
 
 static WAVEHDR *
 winmm_get_next_buffer(cubeb_stream * stm)
 {
   WAVEHDR * hdr = NULL;
 
-  assert(stm->free_buffers > 0 && stm->free_buffers <= NBUFS);
+  XASSERT(stm->free_buffers > 0 && stm->free_buffers <= NBUFS);
   hdr = &stm->buffers[stm->next_buffer];
-  assert(hdr->dwFlags & WHDR_PREPARED ||
-         (hdr->dwFlags & WHDR_DONE && !(hdr->dwFlags & WHDR_INQUEUE)));
+  XASSERT(hdr->dwFlags & WHDR_PREPARED ||
+          (hdr->dwFlags & WHDR_DONE && !(hdr->dwFlags & WHDR_INQUEUE)));
   stm->next_buffer = (stm->next_buffer + 1) % NBUFS;
   stm->free_buffers -= 1;
 
   return hdr;
 }
 
 static void
 winmm_refill_stream(cubeb_stream * stm)
 {
   WAVEHDR * hdr;
   long got;
   long wanted;
   MMRESULT r;
 
   EnterCriticalSection(&stm->lock);
   stm->free_buffers += 1;
-  assert(stm->free_buffers > 0 && stm->free_buffers <= NBUFS);
+  XASSERT(stm->free_buffers > 0 && stm->free_buffers <= NBUFS);
 
   if (stm->draining) {
     LeaveCriticalSection(&stm->lock);
     if (stm->free_buffers == NBUFS) {
       stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
     }
     SetEvent(stm->event);
     return;
@@ -150,27 +149,27 @@ winmm_refill_stream(cubeb_stream * stm)
   /* It is assumed that the caller is holding this lock.  It must be dropped
      during the callback to avoid deadlocks. */
   LeaveCriticalSection(&stm->lock);
   got = stm->data_callback(stm, stm->user_ptr, hdr->lpData, wanted);
   EnterCriticalSection(&stm->lock);
   if (got < 0) {
     LeaveCriticalSection(&stm->lock);
     /* XXX handle this case */
-    assert(0);
+    XASSERT(0);
     return;
   } else if (got < wanted) {
     stm->draining = 1;
   }
   stm->written += got;
 
-  assert(hdr->dwFlags & WHDR_PREPARED);
+  XASSERT(hdr->dwFlags & WHDR_PREPARED);
 
   hdr->dwBufferLength = got * bytes_per_frame(stm->params);
-  assert(hdr->dwBufferLength <= stm->buffer_size);
+  XASSERT(hdr->dwBufferLength <= stm->buffer_size);
 
   if (stm->soft_volume != -1.0) {
     if (stm->params.format == CUBEB_SAMPLE_FLOAT32NE) {
       float * b = (float *) hdr->lpData;
       uint32_t i;
       for (i = 0; i < got * stm->params.channels; i++) {
         b[i] *= stm->soft_volume;
       }
@@ -192,24 +191,24 @@ winmm_refill_stream(cubeb_stream * stm)
 
   LeaveCriticalSection(&stm->lock);
 }
 
 static unsigned __stdcall
 winmm_buffer_thread(void * user_ptr)
 {
   cubeb * ctx = (cubeb *) user_ptr;
-  assert(ctx);
+  XASSERT(ctx);
 
   for (;;) {
     DWORD r;
     PSLIST_ENTRY item;
 
     r = WaitForSingleObject(ctx->event, INFINITE);
-    assert(r == WAIT_OBJECT_0);
+    XASSERT(r == WAIT_OBJECT_0);
 
     /* Process work items in batches so that a single stream can't
        starve the others by continuously adding new work to the top of
        the work item stack. */
     item = InterlockedFlushSList(ctx->work);
     while (item != NULL) {
       PSLIST_ENTRY tmp = item;
       winmm_refill_stream(((struct cubeb_stream_item *) tmp)->stream);
@@ -231,17 +230,17 @@ winmm_buffer_callback(HWAVEOUT waveout, 
   cubeb_stream * stm = (cubeb_stream *) user_ptr;
   struct cubeb_stream_item * item;
 
   if (msg != WOM_DONE) {
     return;
   }
 
   item = _aligned_malloc(sizeof(struct cubeb_stream_item), MEMORY_ALLOCATION_ALIGNMENT);
-  assert(item);
+  XASSERT(item);
   item->stream = stm;
   InterlockedPushEntrySList(stm->context->work, &item->head);
 
   SetEvent(stm->context->event);
 }
 
 static unsigned int
 calculate_minimum_latency(void)
@@ -273,26 +272,26 @@ calculate_minimum_latency(void)
 
 static void winmm_destroy(cubeb * ctx);
 
 /*static*/ int
 winmm_init(cubeb ** context, char const * context_name)
 {
   cubeb * ctx;
 
-  assert(context);
+  XASSERT(context);
   *context = NULL;
 
   ctx = calloc(1, sizeof(*ctx));
-  assert(ctx);
+  XASSERT(ctx);
 
   ctx->ops = &winmm_ops;
 
   ctx->work = _aligned_malloc(sizeof(*ctx->work), MEMORY_ALLOCATION_ALIGNMENT);
-  assert(ctx->work);
+  XASSERT(ctx->work);
   InitializeSListHead(ctx->work);
 
   ctx->event = CreateEvent(NULL, FALSE, FALSE, NULL);
   if (!ctx->event) {
     winmm_destroy(ctx);
     return CUBEB_ERROR;
   }
 
@@ -320,26 +319,26 @@ winmm_get_backend_id(cubeb * ctx)
   return "winmm";
 }
 
 static void
 winmm_destroy(cubeb * ctx)
 {
   DWORD r;
 
-  assert(ctx->active_streams == 0);
-  assert(!InterlockedPopEntrySList(ctx->work));
+  XASSERT(ctx->active_streams == 0);
+  XASSERT(!InterlockedPopEntrySList(ctx->work));
 
   DeleteCriticalSection(&ctx->lock);
 
   if (ctx->thread) {
     ctx->shutdown = 1;
     SetEvent(ctx->event);
     r = WaitForSingleObject(ctx->thread, INFINITE);
-    assert(r == WAIT_OBJECT_0);
+    XASSERT(r == WAIT_OBJECT_0);
     CloseHandle(ctx->thread);
   }
 
   if (ctx->event) {
     CloseHandle(ctx->event);
   }
 
   _aligned_free(ctx->work);
@@ -357,18 +356,18 @@ winmm_stream_init(cubeb * context, cubeb
                   void * user_ptr)
 {
   MMRESULT r;
   WAVEFORMATEXTENSIBLE wfx;
   cubeb_stream * stm;
   int i;
   size_t bufsz;
 
-  assert(context);
-  assert(stream);
+  XASSERT(context);
+  XASSERT(stream);
 
   *stream = NULL;
 
   memset(&wfx, 0, sizeof(wfx));
   if (stream_params.channels > 2) {
     wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
     wfx.Format.cbSize = sizeof(wfx) - sizeof(wfx.Format);
   } else {
@@ -408,17 +407,17 @@ winmm_stream_init(cubeb * context, cubeb
   if (context->active_streams >= CUBEB_STREAM_MAX) {
     LeaveCriticalSection(&context->lock);
     return CUBEB_ERROR;
   }
   context->active_streams += 1;
   LeaveCriticalSection(&context->lock);
 
   stm = calloc(1, sizeof(*stm));
-  assert(stm);
+  XASSERT(stm);
 
   stm->context = context;
 
   stm->params = stream_params;
 
   stm->data_callback = data_callback;
   stm->state_callback = state_callback;
   stm->user_ptr = user_ptr;
@@ -427,17 +426,17 @@ winmm_stream_init(cubeb * context, cubeb
   if (latency < context->minimum_latency) {
     latency = context->minimum_latency;
   }
 
   bufsz = (size_t) (stm->params.rate / 1000.0 * latency * bytes_per_frame(stm->params) / NBUFS);
   if (bufsz % bytes_per_frame(stm->params) != 0) {
     bufsz += bytes_per_frame(stm->params) - (bufsz % bytes_per_frame(stm->params));
   }
-  assert(bufsz % bytes_per_frame(stm->params) == 0);
+  XASSERT(bufsz % bytes_per_frame(stm->params) == 0);
 
   stm->buffer_size = bufsz;
 
   InitializeCriticalSection(&stm->lock);
 
   stm->event = CreateEvent(NULL, FALSE, FALSE, NULL);
   if (!stm->event) {
     winmm_stream_destroy(stm);
@@ -462,17 +461,17 @@ winmm_stream_init(cubeb * context, cubeb
     return CUBEB_ERROR;
   }
 
 
   for (i = 0; i < NBUFS; ++i) {
     WAVEHDR * hdr = &stm->buffers[i];
 
     hdr->lpData = calloc(1, bufsz);
-    assert(hdr->lpData);
+    XASSERT(hdr->lpData);
     hdr->dwBufferLength = bufsz;
     hdr->dwFlags = 0;
 
     r = waveOutPrepareHeader(stm->waveout, hdr, sizeof(*hdr));
     if (r != MMSYSERR_NOERROR) {
       winmm_stream_destroy(stm);
       return CUBEB_ERROR;
     }
@@ -499,17 +498,17 @@ winmm_stream_destroy(cubeb_stream * stm)
     waveOutReset(stm->waveout);
 
     enqueued = NBUFS - stm->free_buffers;
     LeaveCriticalSection(&stm->lock);
 
     /* Wait for all blocks to complete. */
     while (enqueued > 0) {
       r = WaitForSingleObject(stm->event, INFINITE);
-      assert(r == WAIT_OBJECT_0);
+      XASSERT(r == WAIT_OBJECT_0);
 
       EnterCriticalSection(&stm->lock);
       enqueued = NBUFS - stm->free_buffers;
       LeaveCriticalSection(&stm->lock);
     }
 
     EnterCriticalSection(&stm->lock);
 
@@ -530,27 +529,27 @@ winmm_stream_destroy(cubeb_stream * stm)
 
   DeleteCriticalSection(&stm->lock);
 
   for (i = 0; i < NBUFS; ++i) {
     free(stm->buffers[i].lpData);
   }
 
   EnterCriticalSection(&stm->context->lock);
-  assert(stm->context->active_streams >= 1);
+  XASSERT(stm->context->active_streams >= 1);
   stm->context->active_streams -= 1;
   LeaveCriticalSection(&stm->context->lock);
 
   free(stm);
 }
 
 static int
 winmm_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
 {
-  assert(ctx && max_channels);
+  XASSERT(ctx && max_channels);
 
   /* We don't support more than two channels in this backend. */
   *max_channels = 2;
 
   return CUBEB_OK;
 }
 
 static int
--- a/media/libstagefright/binding/mp4_demuxer.cpp
+++ b/media/libstagefright/binding/mp4_demuxer.cpp
@@ -326,17 +326,17 @@ MP4Demuxer::GetEvictionOffset(Microsecon
   if (mPrivate->mIndexes.IsEmpty()) {
     return 0;
   }
 
   uint64_t offset = std::numeric_limits<uint64_t>::max();
   for (int i = 0; i < mPrivate->mIndexes.Length(); i++) {
     offset = std::min(offset, mPrivate->mIndexes[i]->GetEvictionOffset(aTime));
   }
-  return offset == std::numeric_limits<uint64_t>::max() ? -1 : offset;
+  return offset == std::numeric_limits<uint64_t>::max() ? 0 : offset;
 }
 
 Microseconds
 MP4Demuxer::GetNextKeyframeTime()
 {
   mMonitor->AssertCurrentThreadOwns();
   if (!mPrivate->mVideoIterator) {
     return -1;
--- a/mobile/android/chrome/content/Reader.js
+++ b/mobile/android/chrome/content/Reader.js
@@ -154,34 +154,34 @@ let Reader = {
     if (this.pageAction.id) {
       PageActions.remove(this.pageAction.id);
       delete this.pageAction.id;
     }
 
     let browser = tab.browser;
     if (browser.currentURI.spec.startsWith("about:reader")) {
       this.pageAction.id = PageActions.add({
-        title: Strings.browser.GetStringFromName("readerMode.exit"),
+        title: Strings.browser.GetStringFromName("readerView.exit"),
         icon: "drawable://reader_active",
         clickCallback: () => this.pageAction.readerModeCallback(tab.id),
         important: true
       });
 
       // Only start a reader session if the viewer is in the foreground. We do
       // not track background reader viewers.
       UITelemetry.startSession("reader.1", null);
       return;
     }
 
     // Only stop a reader session if the foreground viewer is not visible.
     UITelemetry.stopSession("reader.1", "", null);
 
     if (browser.isArticle) {
       this.pageAction.id = PageActions.add({
-        title: Strings.browser.GetStringFromName("readerMode.enter"),
+        title: Strings.browser.GetStringFromName("readerView.enter"),
         icon: "drawable://reader",
         clickCallback: () => this.pageAction.readerModeCallback(tab.id),
         longClickCallback: () => this.pageAction.readerModeActiveCallback(tab.id),
         important: true
       });
     }
   },
 
--- a/mobile/android/locales/en-US/chrome/browser.properties
+++ b/mobile/android/locales/en-US/chrome/browser.properties
@@ -356,19 +356,19 @@ getUserMedia.videoSource.tabShare = Choo
 getUserMedia.videoSource.prompt = Video source
 getUserMedia.audioDevice.default = Microphone %S
 getUserMedia.audioDevice.none = No Audio
 getUserMedia.audioDevice.prompt = Microphone to use
 getUserMedia.sharingCamera.message2 = Camera is on
 getUserMedia.sharingMicrophone.message2 = Microphone is on
 getUserMedia.sharingCameraAndMicrophone.message2 = Camera and microphone are on
 
-#Reader mode
-readerMode.enter = Enter Reader Mode
-readerMode.exit = Exit Reader Mode
+#Reader view
+readerView.enter = Enter Reader View
+readerView.exit = Exit Reader View
 
 # LOCALIZATION NOTE (readerMode.toolbarTip):
 # Tip shown to users the first time we hide the reader mode toolbar.
 readerMode.toolbarTip=Tap the screen to show reader options
 
 #Open in App
 openInApp.pageAction = Open in App
 openInApp.ok = OK
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -867,33 +867,22 @@ nsJARChannel::AsyncOpen(nsIStreamListene
         // Not a local file...
         // kick off an async download of the base URI...
         rv = NS_NewDownloader(getter_AddRefs(mDownloader), this);
         if (NS_SUCCEEDED(rv)) {
             // Since we might not have a loadinfo on all channels yet
             // we have to provide default arguments in case mLoadInfo is null;
             uint32_t loadFlags =
               mLoadFlags & ~(LOAD_DOCUMENT_URI | LOAD_CALL_CONTENT_SNIFFERS);
-            if (mLoadInfo) {
-              rv = NS_NewChannelInternal(getter_AddRefs(channel),
-                                         mJarBaseURI,
-                                         mLoadInfo,
-                                         mLoadGroup,
-                                         mCallbacks,
-                                         loadFlags);
-            } else {
-              rv = NS_NewChannel(getter_AddRefs(channel),
-                                 mJarBaseURI,
-                                 nsContentUtils::GetSystemPrincipal(),
-                                 nsILoadInfo::SEC_NORMAL,
-                                 nsIContentPolicy::TYPE_OTHER,
-                                 mLoadGroup,
-                                 mCallbacks,
-                                 loadFlags);
-            }
+            rv = NS_NewChannelInternal(getter_AddRefs(channel),
+                                       mJarBaseURI,
+                                       mLoadInfo,
+                                       mLoadGroup,
+                                       mCallbacks,
+                                       loadFlags);
             if (NS_FAILED(rv)) {
               mIsPending = false;
               mListenerContext = nullptr;
               mListener = nullptr;
               return rv;
             }
             channel->AsyncOpen(mDownloader, nullptr);
         }
--- a/netwerk/base/nsNetUtil.h
+++ b/netwerk/base/nsNetUtil.h
@@ -591,17 +591,16 @@ NS_GetRealPort(nsIURI* aURI)
 inline nsresult /* NS_NewInputStreamChannelWithLoadInfo */
 NS_NewInputStreamChannelInternal(nsIChannel**        outChannel,
                                  nsIURI*             aUri,
                                  nsIInputStream*     aStream,
                                  const nsACString&   aContentType,
                                  const nsACString&   aContentCharset,
                                  nsILoadInfo*        aLoadInfo)
 {
-  MOZ_ASSERT(aLoadInfo, "can not create channel without a loadinfo");
   nsresult rv;
   nsCOMPtr<nsIInputStreamChannel> isc =
     do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = isc->SetURI(aUri);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = isc->SetContentStream(aStream);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -618,17 +617,17 @@ NS_NewInputStreamChannelInternal(nsIChan
     rv = channel->SetContentCharset(aContentCharset);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   channel->SetLoadInfo(aLoadInfo);
 
   // If we're sandboxed, make sure to clear any owner the channel
   // might already have.
-  if (aLoadInfo->GetLoadingSandboxed()) {
+  if (aLoadInfo && aLoadInfo->GetLoadingSandboxed()) {
     channel->SetOwner(nullptr);
   }
 
   channel.forget(outChannel);
   return NS_OK;
 }
 
 inline nsresult
--- a/netwerk/protocol/about/nsAboutBlank.cpp
+++ b/netwerk/protocol/about/nsAboutBlank.cpp
@@ -18,38 +18,22 @@ nsAboutBlank::NewChannel(nsIURI* aURI,
 {
     NS_ENSURE_ARG_POINTER(aURI);
 
     nsCOMPtr<nsIInputStream> in;
     nsresult rv = NS_NewCStringInputStream(getter_AddRefs(in), EmptyCString());
     if (NS_FAILED(rv)) return rv;
 
     nsCOMPtr<nsIChannel> channel;
-    // Bug 1087720 (and Bug 1099296):
-    // Once all callsites have been updated to call NewChannel2()
-    // instead of NewChannel() we should have a non-null loadInfo
-    // consistently. Until then we have to branch on the loadInfo.
-    if (aLoadInfo) {
-      rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
-                                            aURI,
-                                            in,
-                                            NS_LITERAL_CSTRING("text/html"),
-                                            NS_LITERAL_CSTRING("utf-8"),
-                                            aLoadInfo);
-    }
-    else {
-      rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
-                                    aURI,
-                                    in,
-                                    nsContentUtils::GetSystemPrincipal(),
-                                    nsILoadInfo::SEC_NORMAL,
-                                    nsIContentPolicy::TYPE_OTHER,
-                                    NS_LITERAL_CSTRING("text/html"),
-                                    NS_LITERAL_CSTRING("utf-8"));
-    }
+    rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
+                                          aURI,
+                                          in,
+                                          NS_LITERAL_CSTRING("text/html"),
+                                          NS_LITERAL_CSTRING("utf-8"),
+                                          aLoadInfo);
     if (NS_FAILED(rv)) return rv;
 
     channel.forget(result);
     return rv;
 }
 
 NS_IMETHODIMP
 nsAboutBlank::GetURIFlags(nsIURI *aURI, uint32_t *result)
--- a/netwerk/protocol/about/nsAboutBloat.cpp
+++ b/netwerk/protocol/about/nsAboutBloat.cpp
@@ -107,38 +107,22 @@ nsAboutBloat::NewChannel(nsIURI* aURI,
         ::fclose(out);
         if (NS_FAILED(rv)) return rv;
 
         rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), file);
         if (NS_FAILED(rv)) return rv;
     }
 
     nsIChannel* channel = nullptr;
-    // Bug 1087720 (and Bug 1099296):
-    // Once all callsites have been updated to call NewChannel2()
-    // instead of NewChannel() we should have a non-null loadInfo
-    // consistently. Until then we have to branch on the loadInfo.
-    if (aLoadInfo) {
-      rv = NS_NewInputStreamChannelInternal(&channel,
-                                            aURI,
-                                            inStr,
-                                            NS_LITERAL_CSTRING("text/plain"),
-                                            NS_LITERAL_CSTRING("utf-8"),
-                                            aLoadInfo);
-    }
-    else {
-      rv = NS_NewInputStreamChannel(&channel,
-                                    aURI,
-                                    inStr,
-                                    nsContentUtils::GetSystemPrincipal(),
-                                    nsILoadInfo::SEC_NORMAL,
-                                    nsIContentPolicy::TYPE_OTHER,
-                                    NS_LITERAL_CSTRING("text/plain"),
-                                    NS_LITERAL_CSTRING("utf-8"));
-    }
+    rv = NS_NewInputStreamChannelInternal(&channel,
+                                          aURI,
+                                          inStr,
+                                          NS_LITERAL_CSTRING("text/plain"),
+                                          NS_LITERAL_CSTRING("utf-8"),
+                                          aLoadInfo);
     if (NS_FAILED(rv)) return rv;
 
     *result = channel;
     return rv;
 }
 
 NS_IMETHODIMP
 nsAboutBloat::GetURIFlags(nsIURI *aURI, uint32_t *result)
--- a/netwerk/protocol/about/nsAboutCache.cpp
+++ b/netwerk/protocol/about/nsAboutCache.cpp
@@ -59,38 +59,22 @@ nsAboutCache::NewChannel(nsIURI* aURI,
         // ...and visit just the specified storage, entries will output too
         mStorageList.AppendElement(storageName);
     }
 
     // The entries header is added on encounter of the first entry
     mEntriesHeaderAdded = false;
 
     nsCOMPtr<nsIChannel> channel;
-    // Bug 1087720 (and Bug 1099296):
-    // Once all callsites have been updated to call NewChannel2()
-    // instead of NewChannel() we should have a non-null loadInfo
-    // consistently. Until then we have to branch on the loadInfo.
-    if (aLoadInfo) {
-      rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
-                                            aURI,
-                                            inputStream,
-                                            NS_LITERAL_CSTRING("text/html"),
-                                            NS_LITERAL_CSTRING("utf-8"),
-                                            aLoadInfo);
-    }
-    else {
-      rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
-                            aURI,
-                            inputStream,
-                            nsContentUtils::GetSystemPrincipal(),
-                            nsILoadInfo::SEC_NORMAL,
-                            nsIContentPolicy::TYPE_OTHER,
-                            NS_LITERAL_CSTRING("text/html"),
-                            NS_LITERAL_CSTRING("utf-8"));
-    }
+    rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
+                                          aURI,
+                                          inputStream,
+                                          NS_LITERAL_CSTRING("text/html"),
+                                          NS_LITERAL_CSTRING("utf-8"),
+                                          aLoadInfo);
     if (NS_FAILED(rv)) return rv;
 
     mBuffer.AssignLiteral(
         "<!DOCTYPE html>\n"
         "<html>\n"
         "<head>\n"
         "  <title>Network Cache Storage Information</title>\n"
         "  <meta charset=\"utf-8\">\n"
--- a/netwerk/protocol/about/nsAboutCacheEntry.cpp
+++ b/netwerk/protocol/about/nsAboutCacheEntry.cpp
@@ -94,36 +94,22 @@ nsAboutCacheEntry::NewChannel(nsIURI* ur
                               nsIChannel** result)
 {
     NS_ENSURE_ARG_POINTER(uri);
     nsresult rv;
 
     nsCOMPtr<nsIInputStream> stream;
     rv = GetContentStream(uri, getter_AddRefs(stream));
     if (NS_FAILED(rv)) return rv;
-    // Bug 1087720 (and Bug 1099296):
-    // Once all callsites have been updated to call NewChannel2()
-    // instead of NewChannel() we should have a non-null loadInfo
-    // consistently. Until then we have to branch on the loadInfo.
-    if (aLoadInfo) {
-      return NS_NewInputStreamChannelInternal(result,
-                                              uri,
-                                              stream,
-                                              NS_LITERAL_CSTRING("text/html"),
-                                              NS_LITERAL_CSTRING("utf-8"),
-                                              aLoadInfo);
-    }
-    return NS_NewInputStreamChannel(result,
-                                    uri,
-                                    stream,
-                                    nsContentUtils::GetSystemPrincipal(),
-                                    nsILoadInfo::SEC_NORMAL,
-                                    nsIContentPolicy::TYPE_OTHER,
-                                    NS_LITERAL_CSTRING("text/html"),
-                                    NS_LITERAL_CSTRING("utf-8"));
+    return NS_NewInputStreamChannelInternal(result,
+                                            uri,
+                                            stream,
+                                            NS_LITERAL_CSTRING("text/html"),
+                                            NS_LITERAL_CSTRING("utf-8"),
+                                            aLoadInfo);
 }
 
 NS_IMETHODIMP
 nsAboutCacheEntry::GetURIFlags(nsIURI *aURI, uint32_t *result)
 {
     *result = nsIAboutModule::HIDE_FROM_ABOUTABOUT;
     return NS_OK;
 }
--- a/netwerk/protocol/res/nsResProtocolHandler.cpp
+++ b/netwerk/protocol/res/nsResProtocolHandler.cpp
@@ -283,32 +283,23 @@ nsResProtocolHandler::NewChannel2(nsIURI
                                   nsILoadInfo* aLoadInfo,
                                   nsIChannel** result)
 {
     NS_ENSURE_ARG_POINTER(uri);
     nsAutoCString spec;
     nsresult rv = ResolveURI(uri, spec);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    // Bug 1087720 (and Bug 1099296):
-    // Once all callsites have been updated to call NewChannel2() instead of NewChannel()
-    // we should have a non-null loadInfo consistently. Until then we have to branch on the
-    // loadInfo.
     nsCOMPtr<nsIURI> newURI;
     rv = NS_NewURI(getter_AddRefs(newURI), spec);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    if (aLoadInfo) {
-        rv = NS_NewChannelInternal(result,
-                                   newURI,
-                                   aLoadInfo);
-    }
-    else {
-        rv = mIOService->NewChannelFromURI(newURI, result);
-    }
+    rv = NS_NewChannelInternal(result,
+                               newURI,
+                               aLoadInfo);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsLoadFlags loadFlags = 0;
     (*result)->GetLoadFlags(&loadFlags);
     (*result)->SetLoadFlags(loadFlags & ~nsIChannel::LOAD_REPLACE);
     return (*result)->SetOriginalURI(uri);
 }
 
--- a/python/mozbuild/mozbuild/mozinfo.py
+++ b/python/mozbuild/mozbuild/mozinfo.py
@@ -78,16 +78,17 @@ def build_dict(config, env=os.environ):
     # other CPUs will wind up with unknown bits
 
     d['debug'] = substs.get('MOZ_DEBUG') == '1'
     d['crashreporter'] = bool(substs.get('MOZ_CRASHREPORTER'))
     d['datareporting'] = bool(substs.get('MOZ_DATA_REPORTING'))
     d['healthreport'] = substs.get('MOZ_SERVICES_HEALTHREPORT') == '1'
     d['asan'] = substs.get('MOZ_ASAN') == '1'
     d['tsan'] = substs.get('MOZ_TSAN') == '1'
+    d['telemetry'] = substs.get('MOZ_TELEMETRY_REPORTING') == '1'
     d['tests_enabled'] = substs.get('ENABLE_TESTS') == "1"
     d['bin_suffix'] = substs.get('BIN_SUFFIX', '')
 
     d['webm'] = bool(substs.get('MOZ_WEBM'))
     d['wave'] = bool(substs.get('MOZ_WAVE'))
 
     d['official'] = bool(substs.get('MOZILLA_OFFICIAL'))
 
--- a/testing/marionette/client/marionette/runner/base.py
+++ b/testing/marionette/client/marionette/runner/base.py
@@ -237,16 +237,18 @@ class MarionetteTextTestRunner(Structure
             pre_run_func()
 
         result = super(MarionetteTextTestRunner, self).run(test)
         result.printLogs(test)
         return result
 
 
 class BaseMarionetteOptions(OptionParser):
+    socket_timeout_default = 360.0
+
     def __init__(self, **kwargs):
         OptionParser.__init__(self, **kwargs)
         self.parse_args_handlers = [] # Used by mixins
         self.verify_usage_handlers = [] # Used by mixins
         self.add_option('--emulator',
                         action='store',
                         dest='emulator',
                         choices=['x86', 'arm'],
@@ -396,16 +398,21 @@ class BaseMarionetteOptions(OptionParser
                         action='store',
                         default='Marionette-based Tests',
                         help='Define the name to associate with the logger used')
         self.add_option('--jsdebugger',
                         dest='jsdebugger',
                         action='store_true',
                         default=False,
                         help='Enable the jsdebugger for marionette javascript.')
+        self.add_option('--socket-timeout',
+                        dest='socket_timeout',
+                        action='store',
+                        default=self.socket_timeout_default,
+                        help='Set the global timeout for marionette socket operations.')
         self.add_option('--e10s',
                         dest='e10s',
                         action='store_true',
                         default=False,
                         help='Enable e10s when running marionette tests.')
 
     def parse_args(self, args=None, values=None):
         options, tests = OptionParser.parse_args(self, args, values)
@@ -452,16 +459,17 @@ class BaseMarionetteOptions(OptionParser
         if options.total_chunks is not None:
             if not 1 <= options.total_chunks:
                 self.error('Total chunks must be greater than 1.')
             if not 1 <= options.this_chunk <= options.total_chunks:
                 self.error('Chunk to run must be between 1 and %s.' % options.total_chunks)
 
         if options.jsdebugger:
             options.app_args.append('-jsdebugger')
+            options.socket_timeout = None
 
         if options.e10s:
             options.prefs = {
                 'browser.tabs.remote.autostart': True
             }
 
         for handler in self.verify_usage_handlers:
             handler(options, tests)
@@ -477,17 +485,19 @@ class BaseMarionetteTestRunner(object):
                  emulator_img=None, emulator_res='480x800', homedir=None,
                  app=None, app_args=None, binary=None, profile=None,
                  logger=None, no_window=False, logdir=None, logcat_stdout=False,
                  xml_output=None, repeat=0, testvars=None, tree=None, type=None,
                  device_serial=None, symbols_path=None, timeout=None,
                  shuffle=False, shuffle_seed=random.randint(0, sys.maxint),
                  sdcard=None, this_chunk=1, total_chunks=1, sources=None,
                  server_root=None, gecko_log=None, result_callbacks=None,
-                 adb_host=None, adb_port=None, prefs=None, **kwargs):
+                 adb_host=None, adb_port=None, prefs=None,
+                 socket_timeout=BaseMarionetteOptions.socket_timeout_default,
+                 **kwargs):
         self.address = address
         self.emulator = emulator
         self.emulator_binary = emulator_binary
         self.emulator_img = emulator_img
         self.emulator_res = emulator_res
         self.homedir = homedir
         self.app = app
         self.app_args = app_args or []
@@ -502,16 +512,17 @@ class BaseMarionetteTestRunner(object):
         self.xml_output = xml_output
         self.repeat = repeat
         self.test_kwargs = kwargs
         self.tree = tree
         self.type = type
         self.device_serial = device_serial
         self.symbols_path = symbols_path
         self.timeout = timeout
+        self.socket_timeout = socket_timeout
         self._device = None
         self._capabilities = None
         self._appName = None
         self.shuffle = shuffle
         self.shuffle_seed = shuffle_seed
         self.sdcard = sdcard
         self.sources = sources
         self.server_root = server_root
@@ -633,16 +644,17 @@ class BaseMarionetteTestRunner(object):
             self.marionette.baseurl = self.server_root
             self.logger.info('using content from %s' % self.marionette.baseurl)
 
     def _build_kwargs(self):
         kwargs = {
             'device_serial': self.device_serial,
             'symbols_path': self.symbols_path,
             'timeout': self.timeout,
+            'socket_timeout': self.socket_timeout,
             'adb_host': self._adb_host,
             'adb_port': self._adb_port,
             'prefs': self.prefs,
         }
         if self.bin:
             kwargs.update({
                 'host': 'localhost',
                 'port': 2828,
--- a/testing/marionette/client/marionette/tests/unit/test_modal_dialogs.py
+++ b/testing/marionette/client/marionette/tests/unit/test_modal_dialogs.py
@@ -147,17 +147,17 @@ class TestTabModals(MarionetteTestCase):
             lambda mn: mn.execute_script("""
               return window.onbeforeunload !== null;
             """))
         self.marionette.navigate("about:blank")
         self.wait_for_alert()
         alert = self.marionette.switch_to_alert()
         self.assertTrue(alert.text.startswith("This page is asking you to confirm"))
         alert.accept()
-        self.assertEqual(self.marionette.get_url(), "about:blank")
+        self.wait_for_condition(lambda mn: mn.get_url() == "about:blank")
 
     @skip_if_e10s
     def test_unrelated_command_when_alert_present(self):
         click_handler = self.marionette.find_element('id', 'click-handler')
         text = self.marionette.find_element('id', 'click-result').text
         self.assertEqual(text, '')
 
         self.marionette.find_element('id', 'modal-alert').click()
--- a/toolkit/components/places/nsAnnoProtocolHandler.cpp
+++ b/toolkit/components/places/nsAnnoProtocolHandler.cpp
@@ -338,36 +338,22 @@ nsAnnoProtocolHandler::NewFaviconChannel
                            getter_AddRefs(outputStream),
                            MAX_FAVICON_SIZE, MAX_FAVICON_SIZE, true,
                            true);
   NS_ENSURE_SUCCESS(rv, GetDefaultIcon(_channel));
 
   // Create our channel.  We'll call SetContentType with the right type when
   // we know what it actually is.
   nsCOMPtr<nsIChannel> channel;
-  // Bug 1087720 (and Bug 1099296):
-  // Once all callsites have been updated to call NewChannel2() instead of NewChannel()
-  // we should have a non-null loadInfo consistently. Until then we have to brach on the
-  // loadInfo and provide default arguments to create a NewInputStreamChannel.
-  if (aLoadInfo) {
-    rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
-                                          aURI,
-                                          inputStream,
-                                          EmptyCString(), // aContentType
-                                          EmptyCString(), // aContentCharset
-                                          aLoadInfo);
-  }
-  else {
-    rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
-                                  aURI,
-                                  inputStream,
-                                  nsContentUtils::GetSystemPrincipal(),
-                                  nsILoadInfo::SEC_NORMAL,
-                                  nsIContentPolicy::TYPE_IMAGE);
-  }
+  rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
+                                        aURI,
+                                        inputStream,
+                                        EmptyCString(), // aContentType
+                                        EmptyCString(), // aContentCharset
+                                        aLoadInfo);
   NS_ENSURE_SUCCESS(rv, GetDefaultIcon(_channel));
 
   // Now we go ahead and get our data asynchronously for the favicon.
   nsCOMPtr<mozIStorageStatementCallback> callback =
     new faviconAsyncLoader(channel, outputStream);
   NS_ENSURE_TRUE(callback, GetDefaultIcon(_channel));
   nsFaviconService* faviconService = nsFaviconService::GetFaviconService();
   NS_ENSURE_TRUE(faviconService, GetDefaultIcon(_channel));
--- a/toolkit/components/reader/AboutReader.jsm
+++ b/toolkit/components/reader/AboutReader.jsm
@@ -51,19 +51,20 @@ let AboutReader = function(mm, win) {
 
   win.addEventListener("unload", this, false);
   win.addEventListener("scroll", this, false);
   win.addEventListener("resize", this, false);
 
   doc.addEventListener("visibilitychange", this, false);
 
   this._setupStyleDropdown();
-  this._setupButton("close-button", this._onReaderClose.bind(this));
-  this._setupButton("toggle-button", this._onReaderToggle.bind(this));
-  this._setupButton("share-button", this._onShare.bind(this));
+  this._setupButton("close-button", this._onReaderClose.bind(this), "aboutReader.toolbar.close");
+  this._setupButton("toggle-button", this._onReaderToggle.bind(this), "aboutReader.toolbar.addToReadingList");
+  this._setupButton("share-button", this._onShare.bind(this), "aboutReader.toolbar.share");
+  this._setupButton("list-button", this._onList.bind(this), "aboutReader.toolbar.openReadingList");
 
   let colorSchemeValues = JSON.parse(Services.prefs.getCharPref("reader.color_scheme.values"));
   let colorSchemeOptions = colorSchemeValues.map((value) => {
     return { name: gStrings.GetStringFromName("aboutReader.colorScheme." + value),
              value: value,
              itemClass: value + "-button" };
   });
 
@@ -216,22 +217,24 @@ AboutReader.prototype = {
       case "unload":
         this._mm.removeMessageListener("Reader:Added", this);
         this._mm.removeMessageListener("Reader:Removed", this);
         break;
     }
   },
 
   _updateToggleButton: function Reader_updateToggleButton() {
-    let classes = this._doc.getElementById("toggle-button").classList;
+    let button = this._doc.getElementById("toggle-button");
 
     if (this._isReadingListItem == 1) {
-      classes.add("on");
+      button.classList.add("on");
+      button.setAttribute("title", gStrings.GetStringFromName("aboutReader.toolbar.removeFromReadingList"));
     } else {
-      classes.remove("on");
+      button.classList.remove("on");
+      button.setAttribute("title", gStrings.GetStringFromName("aboutReader.toolbar.addToReadingList"));
     }
   },
 
   _requestReadingListStatus: function Reader_requestReadingListStatus() {
     let handleListStatusData = (message) => {
       this._mm.removeMessageListener("Reader:ListStatusData", handleListStatusData);
 
       let args = message.data;
@@ -276,16 +279,20 @@ AboutReader.prototype = {
 
     this._mm.sendAsyncMessage("Reader:Share", {
       url: this._article.url,
       title: this._article.title
     });
     UITelemetry.addEvent("share.1", "list", null);
   },
 
+  _onList: function() {
+    // To be implemented (bug 1132665)
+  },
+
   _setFontSize: function Reader_setFontSize(newFontSize) {
     let htmlClasses = this._doc.documentElement.classList;
 
     if (this._fontSize > 0)
       htmlClasses.remove("font-size" + this._fontSize);
 
     this._fontSize = newFontSize;
     htmlClasses.add("font-size" + this._fontSize);
@@ -672,18 +679,19 @@ AboutReader.prototype = {
         callback(option.value);
       }.bind(this), true);
 
       if (option.value === initialValue)
         item.classList.add("selected");
     }
   },
 
-  _setupButton: function Reader_setupButton(id, callback) {
+  _setupButton: function Reader_setupButton(id, callback, titleEntity) {
     let button = this._doc.getElementById(id);
+    button.setAttribute("title", gStrings.GetStringFromName(titleEntity));
 
     button.addEventListener("click", function(aEvent) {
       if (!aEvent.isTrusted)
         return;
 
       aEvent.stopPropagation();
       callback();
     }, true);
@@ -723,16 +731,17 @@ AboutReader.prototype = {
     win.addEventListener("resize", event => {
       if (!event.isTrusted)
         return;
 
       // Wait for reflow before calculating the new position of the popup.
       win.setTimeout(updatePopupPosition, 0);
     }, true);
 
+    dropdownToggle.setAttribute("title", gStrings.GetStringFromName("aboutReader.toolbar.typeControls"));
     dropdownToggle.addEventListener("click", event => {
       if (!event.isTrusted)
         return;
 
       event.stopPropagation();
 
       if (dropdown.classList.contains("open")) {
         dropdown.classList.remove("open");
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -7251,16 +7251,22 @@
   },
   "DATA_STORAGE_ENTRIES": {
     "expires_in_version": "default",
     "kind": "linear",
     "high": "1024",
     "n_buckets": 16,
     "description": "The number of entries in persistent DataStorage (HSTS and HPKP data, basically)"
   },
+  "VIDEO_MSE_UNLOAD_STATE": {
+    "expires_in_version": "45",
+    "kind": "enumerated",
+    "n_values": 5,
+    "description": "MSE video state when unloading. ended = 0, paused = 1, stalled = 2, seeking = 3, other = 4"
+  },
   "FX_SANITIZE_TOTAL": {
     "alert_emails": ["firefox-dev@mozilla.org", "gavin@mozilla.com"],
     "expires_in_version": "40",
     "kind": "exponential",
     "high": "30000",
     "n_buckets": 20,
     "extended_statistics_ok": true,
     "description": "Sanitize: Total time it takes to sanitize (ms)"
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -16,17 +16,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 window.addEventListener("load", function onload(event) {
   try {
   window.removeEventListener("load", onload, false);
   Troubleshoot.snapshot(function (snapshot) {
     for (let prop in snapshotFormatters)
       snapshotFormatters[prop](snapshot[prop]);
   });
-  populateResetBox();
+  populateActionBox();
   setupEventListeners();
   } catch (e) {
     Cu.reportError("stack of load error for about:support: " + e + ": " + e.stack);
   }
 }, false);
 
 // Each property in this object corresponds to a property in Troubleshoot.jsm's
 // snapshot data.  Each function is passed its property's corresponding data,
@@ -679,21 +679,37 @@ function openProfileDirectory() {
   let nsLocalFile = Components.Constructor("@mozilla.org/file/local;1",
                                            "nsILocalFile", "initWithPath");
   new nsLocalFile(profileDir).reveal();
 }
 
 /**
  * Profile reset is only supported for the default profile if the appropriate migrator exists.
  */
-function populateResetBox() {
-  if (ResetProfile.resetSupported())
-    $("reset-box").style.visibility = "visible";
+function populateActionBox() {
+  if (ResetProfile.resetSupported()) {
+    $("reset-box").style.display = "block";
+    $("action-box").style.display = "block";
+  }
+  if (!Services.appinfo.inSafeMode) {
+    $("safe-mode-box").style.display = "block";
+    $("action-box").style.display = "block";
+  }
 }
 
+// Prompt user to restart the browser in safe mode
+function safeModeRestart() {
+  let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
+                     .createInstance(Ci.nsISupportsPRBool);
+  Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
+
+  if (!cancelQuit.data) {
+    Services.startup.restartInSafeMode(Ci.nsIAppStartup.eAttemptQuit);
+  }
+}
 /**
  * Set up event listeners for buttons.
  */
 function setupEventListeners(){
   $("show-update-history-button").addEventListener("click", function (event) {
     var prompter = Cc["@mozilla.org/updates/update-prompt;1"].createInstance(Ci.nsIUpdatePrompt);
       prompter.showUpdateHistory(window);
   });
@@ -704,9 +720,17 @@ function setupEventListeners(){
     copyRawDataToClipboard(this);
   });
   $("copy-to-clipboard").addEventListener("click", function (event){
     copyContentsToClipboard();
   });
   $("profile-dir-button").addEventListener("click", function (event){
     openProfileDirectory();
   });
+  $("restart-in-safe-mode-button").addEventListener("click", function (event) {
+    if (Services.obs.enumerateObservers("restart-in-safe-mode").hasMoreElements()) {
+      Services.obs.notifyObservers(null, "restart-in-safe-mode", "");
+    }
+    else {
+      safeModeRestart();
+    }
+  });
 }
--- a/toolkit/content/aboutSupport.xhtml
+++ b/toolkit/content/aboutSupport.xhtml
@@ -24,23 +24,31 @@
     <script type="application/javascript;version=1.7"
             src="chrome://global/content/aboutSupport.js"/>
     <script type="application/javascript;version=1.7"
             src="chrome://global/content/resetProfile.js"/>
   </head>
 
   <body dir="&locale.dir;">
 
-    <div id="reset-box">
-      <h3>&refreshProfile.title;</h3>
-      <button id="reset-box-button">
-        &refreshProfile.button.label;
-      </button>
+    <div id="action-box">
+      <div id="reset-box">
+        <h3>&refreshProfile.title;</h3>
+        <button id="reset-box-button">
+          &refreshProfile.button.label;
+        </button>
+      </div>
+      <div id="safe-mode-box">
+        <h3>&aboutSupport.safeModeTitle;</h3>
+        <button id="restart-in-safe-mode-button">
+          &aboutSupport.restartInSafeMode.label;
+        </button>
+      </div>
+
     </div>
-
     <h1>
       &aboutSupport.pageTitle;
     </h1>
 
     <div class="page-subtitle">
         &aboutSupport.pageSubtitle;
     </div>
 
--- a/toolkit/content/widgets/notification.xml
+++ b/toolkit/content/widgets/notification.xml
@@ -96,17 +96,21 @@
             for (var n = notifications.length - 1; n >= 0; n--) {
               if (notifications[n].priority < aPriority)
                 break;
               insertPos = notifications[n];
             }
 
             const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
             var newitem = document.createElementNS(XULNS, "notification");
-            newitem.setAttribute("label", aLabel);
+            // Can't use instanceof in case this was created from a different document:
+            let labelIsDocFragment = aLabel && typeof aLabel == "object" && aLabel.nodeType &&
+                                     aLabel.nodeType == aLabel.DOCUMENT_FRAGMENT_NODE;
+            if (!labelIsDocFragment)
+              newitem.setAttribute("label", aLabel);
             newitem.setAttribute("value", aValue);
             if (aImage)
               newitem.setAttribute("image", aImage);
             newitem.eventCallback = aEventCallback;
 
             if (aButtons) {
               // The notification-button-default class is added to the button
               // with isDefault set to true. If there is no such button, it is
@@ -143,16 +147,23 @@
 
             if (!insertPos) {
               newitem.style.position = "fixed";
               newitem.style.top = "100%";
               newitem.style.marginTop = "-15px";
               newitem.style.opacity = "0";
             }
             this.insertBefore(newitem, insertPos);
+            // Can only insert the document fragment after the item has been created because
+            // otherwise the XBL structure isn't there yet:
+            if (labelIsDocFragment) {
+              document.getAnonymousElementByAttribute(newitem, "anonid", "messageText")
+                .appendChild(aLabel);
+            }
+
             if (!insertPos)
               this._showNotification(newitem, true);
 
             // Fire event for accessibility APIs
             var event = document.createEvent("Events");
             event.initEvent("AlertActive", true, true);
             newitem.dispatchEvent(event);
 
--- a/toolkit/locales/en-US/chrome/global/aboutReader.properties
+++ b/toolkit/locales/en-US/chrome/global/aboutReader.properties
@@ -21,8 +21,18 @@ aboutReader.fontType.charis-sil=Charis S
 aboutReader.fontType.clear-sans=Clear Sans
 
 # LOCALIZATION NOTE (aboutReader.fontTypeSample): String used to sample font types.
 aboutReader.fontTypeSample=Aa
 
 # LOCALIZATION NOTE (aboutReader.fontSizeSample): String used to sample a relative font size
 # for the font size setting. Tapping different samples will change the font size.
 aboutReader.fontSizeSample=A
+
+aboutReader.toolbar.close=Close Reader View
+aboutReader.toolbar.typeControls=Type controls
+aboutReader.toolbar.addToReadingList=Add to Reading List
+aboutReader.toolbar.removeFromReadingList=Remove from Reading List
+aboutReader.toolbar.openReadingList=Open Reading List
+aboutReader.toolbar.closeReadingList=Close Reading List
+aboutReader.toolbar.share=Share
+
+aboutReader.footer.deleteThisArticle=Delete this article
--- a/toolkit/locales/en-US/chrome/global/aboutSupport.dtd
+++ b/toolkit/locales/en-US/chrome/global/aboutSupport.dtd
@@ -92,8 +92,11 @@ variant of aboutSupport.showDir.label. -
 
 <!ENTITY aboutSupport.installationHistoryTitle "Installation History">
 <!ENTITY aboutSupport.updateHistoryTitle "Update History">
 
 <!ENTITY aboutSupport.copyTextToClipboard.label "Copy text to clipboard">
 <!ENTITY aboutSupport.copyRawDataToClipboard.label "Copy raw data to clipboard">
 
 <!ENTITY aboutSupport.sandboxTitle "Sandbox">
+
+<!ENTITY aboutSupport.safeModeTitle "Try Safe Mode">
+<!ENTITY aboutSupport.restartInSafeMode.label "Restart with Add-ons Disabled…">
--- a/toolkit/modules/RemoteWebNavigation.jsm
+++ b/toolkit/modules/RemoteWebNavigation.jsm
@@ -56,17 +56,16 @@ RemoteWebNavigation.prototype = {
   },
   gotoIndex: function(aIndex) {
     this._sendMessage("WebNavigation:GotoIndex", {index: aIndex});
   },
   loadURI: function(aURI, aLoadFlags, aReferrer, aPostData, aHeaders) {
     if (aPostData || aHeaders)
       throw Components.Exception("RemoteWebNavigation doesn't accept postdata or headers.", Cr.NS_ERROR_INVALID_ARGS);
 
-    this._browser._contentTitle = "";
     this._sendMessage("WebNavigation:LoadURI", {
       uri: aURI,
       flags: aLoadFlags,
       referrer: aReferrer ? aReferrer.spec : null
     });
   },
   reload: function(aReloadFlags) {
     this._sendMessage("WebNavigation:Reload", {flags: aReloadFlags});
--- a/toolkit/modules/RemoteWebProgress.jsm
+++ b/toolkit/modules/RemoteWebProgress.jsm
@@ -174,16 +174,17 @@ RemoteWebProgressManager.prototype = {
       // These properties can change even for a sub-frame navigation.
       this._browser.webNavigation.canGoBack = json.canGoBack;
       this._browser.webNavigation.canGoForward = json.canGoForward;
 
       if (isTopLevel) {
         this._browser.webNavigation._currentURI = location;
         this._browser._characterSet = json.charset;
         this._browser._documentURI = newURI(json.documentURI);
+        this._browser._contentTitle = "";
         this._browser._imageDocument = null;
         this._browser._mayEnableCharacterEncodingMenu = json.mayEnableCharacterEncodingMenu;
         this._browser._contentPrincipal = json.principal;
       }
 
       this._callProgressListeners("onLocationChange", webProgress, request, location, flags);
       break;
 
--- a/toolkit/themes/shared/in-content/common.inc.css
+++ b/toolkit/themes/shared/in-content/common.inc.css
@@ -35,16 +35,17 @@ html|hr {
   border-color: #c1c1c1;
 }
 
 xul|caption {
   -moz-appearance: none;
   margin: 0;
 }
 
+xul|caption > xul|checkbox,
 xul|caption > xul|label {
   font-size: 1.3rem;
   font-weight: bold;
   line-height: 22px;
   margin: 0 !important;
 }
 
 xul|description {
--- a/toolkit/themes/windows/global/aboutSupport.css
+++ b/toolkit/themes/windows/global/aboutSupport.css
@@ -73,39 +73,44 @@ td {
 }
 
 .pref-value {
   width: 30%;
   white-space: nowrap;
   overflow: hidden;
 }
 
-#reset-box {
+#action-box {
   background-color: -moz-Dialog;
   border: 1px solid ThreeDShadow;
   color: -moz-DialogText;
   float: right;
   margin-top: 2em;
   margin-bottom: 20px;
   -moz-margin-start: 20px;
   -moz-margin-end: 0;
   padding: 16px;
   width: 30%;
-  visibility: hidden;
 }
 
-#reset-box:-moz-dir(rtl) {
+#action-box,
+#reset-box,
+#safe-mode-box {
+  display: none;
+}
+
+#action-box:-moz-dir(rtl) {
   float: left;
 }
 
 #reset-box > h3 {
   margin-top: 0;
 }
 
-#reset-box > button {
+#action-box button {
   display: block;
 }
 
 .block {
   display: block;
 }
 
 .hidden {