Merge mozilla-central to mozilla-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 20 Feb 2015 15:35:35 +0100
changeset 229987 71fff9b44fbe8ffe93d8d6c22f6e8a29153837c0
parent 229974 dbfe4013530a3fc3c0d3749443d6dfc142ab4ad7 (current diff)
parent 229986 5f1009731a977b83d2b177099c6ae3b12085ec7a (diff)
child 229988 62bc66380845b1886c58731943b8254c21fe75e7
push id55861
push usercbook@mozilla.com
push dateFri, 20 Feb 2015 14:35:53 +0000
treeherdermozilla-inbound@71fff9b44fbe [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 mozilla-inbound
--- 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
@@ -7637,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,16 +480,17 @@ 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]
 [browser_windowactivation.js]
 [browser_contextmenu_childprocess.js]
 [browser_bug963945.js]
 [browser_readerMode.js]
 support-files =
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/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/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/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/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/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 {