Merge m-c to b-i
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 08 Aug 2015 19:41:01 -0700
changeset 288663 2b91beb0fdace8590e07a1f59803464bb6e39b36
parent 288662 931cffa0dfe67eaf3ba40a61eef88dc465056187 (current diff)
parent 288608 24f4d8e5e24b2d93d96f4dd9db0bb0153e31ca6a (diff)
child 288664 8dd1fecccd22cd099b18552e74d55ef84a9d5ecd
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to b-i
browser/themes/shared/bad-content-blocked-16.png
browser/themes/shared/bad-content-blocked-16@2x.png
browser/themes/shared/bad-content-blocked-64.png
browser/themes/shared/bad-content-blocked-64@2x.png
browser/themes/shared/bad-content-unblocked-16.png
browser/themes/shared/bad-content-unblocked-16@2x.png
browser/themes/shared/bad-content-unblocked-64.png
browser/themes/shared/bad-content-unblocked-64@2x.png
browser/themes/shared/badcontent-doorhanger.inc.css
dom/media/AbstractThread.cpp
dom/media/AbstractThread.h
dom/media/TaskDispatcher.h
mobile/android/base/resources/drawable-hdpi/ic_tracking_protection.png
mobile/android/base/resources/drawable-xhdpi/ic_tracking_protection.png
mobile/android/base/resources/drawable-xxhdpi/ic_tracking_protection.png
toolkit/components/passwordmgr/test/browser/browser_passwordmgrcopypwd.js
--- a/browser/base/content/aboutDialog.js
+++ b/browser/base/content/aboutDialog.js
@@ -2,16 +2,22 @@
 # 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/.
 
 // Services = object with smart getters for common XPCOM services
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 const PREF_EM_HOTFIX_ID = "extensions.hotfix.id";
 
+let gMenuButton = null;
+try {
+  gMenuButton = Services.wm.getMostRecentWindow("navigator:browser")
+                        .document.getElementById("PanelUI-menu-button");
+} catch (ex) { };
+
 function init(aEvent)
 {
   if (aEvent.target != document)
     return;
 
   try {
     var distroId = Services.prefs.getCharPref("distribution.id");
     if (distroId) {
@@ -44,16 +50,27 @@ function init(aEvent)
   if (/a\d+$/.test(version)) {
     let buildID = Services.appinfo.appBuildID;
     let buildDate = buildID.slice(0,4) + "-" + buildID.slice(4,6) + "-" + buildID.slice(6,8);
     document.getElementById("version").textContent += " (" + buildDate + ")";
     document.getElementById("experimental").hidden = false;
     document.getElementById("communityDesc").hidden = true;
   }
 
+  if (/^42/.test(version)) {
+    document.getElementById("version").addEventListener("click", event => {
+      if (gMenuButton) {
+        gMenuButton.classList.add("thumburger");
+        if (event.shiftKey) {
+          gMenuButton = null;
+        }
+      }
+    });
+  }
+
 #ifdef MOZ_UPDATER
   gAppUpdater = new appUpdater();
 
   let defaults = Services.prefs.getDefaultBranch("");
   let channelLabel = document.getElementById("currentChannel");
   let currentChannelText = document.getElementById("currentChannelText");
   channelLabel.value = UpdateChannel.get();
   if (/^release($|\-)/.test(channelLabel.value))
@@ -78,16 +95,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 var gAppUpdater;
 
 function onUnload(aEvent) {
   if (gAppUpdater.isChecking)
     gAppUpdater.checker.stopChecking(Components.interfaces.nsIUpdateChecker.CURRENT_CHECK);
   // Safe to call even when there isn't a download in progress.
   gAppUpdater.removeDownloadListener();
   gAppUpdater = null;
+  if (gMenuButton) {
+    gMenuButton.classList.remove("thumburger");
+  }
 }
 
 
 function appUpdater()
 {
   this.updateDeck = document.getElementById("updateDeck");
 
   // Hide the update deck when there is already an update window open to avoid
--- a/browser/base/content/aboutaccounts/main.css
+++ b/browser/base/content/aboutaccounts/main.css
@@ -61,16 +61,19 @@ header h1
 #manage header h1 {
   margin: 0 0 12px 0;
 }
 
 #manage header #email {
   margin-bottom: 23px;
   color: rgb(138, 155, 168);
   font-size: 19px;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
 }
 
 .description {
   font-size: 18px;
 }
 
 .button-row {
   margin-top: 45px;
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -762,20 +762,16 @@ window[chromehidden~="toolbar"] toolbar:
 #addon-progress-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#addon-progress-notification");
 }
 
 #identity-request-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#identity-request-notification");
 }
 
-#bad-content-notification {
-  -moz-binding: url("chrome://browser/content/urlbarBindings.xml#bad-content-notification");
-}
-
 #click-to-play-plugins-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#click-to-play-plugins-notification");
 }
 
 #login-fill-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#login-fill-notification");
 }
 
@@ -1328,26 +1324,16 @@ toolbarpaletteitem[place="palette"][hidd
 }
 
 /* Combined context-menu items */
 #context-navigation > .menuitem-iconic > .menu-iconic-text,
 #context-navigation > .menuitem-iconic > .menu-accel-container {
   display: none;
 }
 
-/* Tracking protection doorhanger */
-.popup-notification-footer[popupid="bad-content"] {
-  display: none;
-}
-
-.popup-notification-footer[popupid="bad-content"][mixedblockdisabled],
-.popup-notification-footer[popupid="bad-content"][trackingblockdisabled] {
-  display: block;
-}
-
 #login-fill-doorhanger:not([inDetailView]) > #login-fill-clickcapturer {
   pointer-events: none;
 }
 
 .popup-notification-invalid-input {
   box-shadow: 0 0 1.5px 1px red;
 }
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -6912,57 +6912,16 @@ var gIdentityHandler = {
       this._identityBox.className = mode;
       this.refreshIdentityBlock(mode);
     }
 
     // NOTE: We do NOT update the identity popup (the control center) when
     // we receive a new security state. If the user opened the popup and looks
     // at the provided information we don't want to suddenly change the panel
     // contents.
-
-    // Show the doorhanger when:
-    // - mixed active content is blocked
-    // - mixed active content is loaded (detected but not blocked)
-    // - tracking content is blocked
-    // - tracking content is not blocked
-    if (state &
-        (nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT |
-         nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT  |
-         nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT     |
-         nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT)) {
-      this.showBadContentDoorhanger(state);
-    }
-  },
-
-  showBadContentDoorhanger : function(state) {
-    var currentNotification =
-      PopupNotifications.getNotification("bad-content",
-        gBrowser.selectedBrowser);
-
-    // Avoid showing the same notification (same state) repeatedly.
-    if (currentNotification && currentNotification.options.state == state)
-      return;
-
-    let options = {
-      /* keep doorhanger collapsed */
-      dismissed: true,
-      state: state
-    };
-
-    // default
-    let iconState = "bad-content-blocked-notification-icon";
-
-    if (state &
-        (Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT |
-         Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT)) {
-      iconState = "bad-content-unblocked-notification-icon";
-    }
-
-    PopupNotifications.show(gBrowser.selectedBrowser, "bad-content",
-                            "", iconState, null, null, options);
   },
 
   /**
    * Return the eTLD+1 version of the current hostname
    */
   getEffectiveHost : function() {
     if (!this._IDNService)
       this._IDNService = Cc["@mozilla.org/network/idn-service;1"]
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -737,18 +737,16 @@
                 <image id="push-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="login-fill-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="password-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="webapps-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="plugins-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="web-notifications-notification-icon" class="notification-anchor-icon" role="button"/>
-                <image id="bad-content-blocked-notification-icon" class="notification-anchor-icon" role="button"/>
-                <image id="bad-content-unblocked-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="webRTC-shareMicrophone-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="webRTC-sharingMicrophone-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="webRTC-shareScreen-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="webRTC-sharingScreen-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="pointerLock-notification-icon" class="notification-anchor-icon" role="button"/>
                 <image id="servicesInstall-notification-icon" class="notification-anchor-icon" role="button"/>
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -254,22 +254,25 @@ skip-if = os == "mac" # Bug 1102331 - do
 [browser_bug734076.js]
 [browser_bug735471.js]
 [browser_bug749738.js]
 [browser_bug763468_perwindowpb.js]
 [browser_bug767836_perwindowpb.js]
 [browser_bug783614.js]
 [browser_bug817947.js]
 [browser_bug822367.js]
+tags = mcb
 [browser_bug832435.js]
 [browser_bug839103.js]
 [browser_bug880101.js]
 [browser_bug882977.js]
 [browser_bug902156.js]
+tags = mcb
 [browser_bug906190.js]
+tags = mcb
 skip-if = buildapp == "mulet" || e10s # Bug 1093642 - test manipulates content and relies on content focus
 [browser_mixedContentFromOnunload.js]
 [browser_bug970746.js]
 [browser_bug1015721.js]
 skip-if = os == 'win' || e10s # Bug 1159268 - Need a content-process safe version of synthesizeWheel
 [browser_bug1064280_changeUrlInPinnedTab.js]
 [browser_bug1070778.js]
 [browser_canonizeURL.js]
@@ -325,16 +328,17 @@ skip-if = toolkit == "windows" # Disable
 skip-if = os == "linux" # Linux: Intermittent failures, bug 917535
 [browser_locationBarExternalLoad.js]
 [browser_menuButtonFitts.js]
 skip-if = os != "win" # The Fitts Law menu button is only supported on Windows (bug 969376)
 [browser_middleMouse_noJSPaste.js]
 [browser_minimize.js]
 skip-if = e10s # Bug 1100664 - test directly access content docShells (TypeError: gBrowser.docShell is null)
 [browser_mixedcontent_securityflags.js]
+tags = mcb
 [browser_notification_tab_switching.js]
 skip-if = buildapp == 'mulet' || e10s # Bug 1100662 - content access causing uncaught exception - Error: cannot ipc non-cpow object at chrome://mochitests/content/browser/browser/base/content/test/general/browser_notification_tab_switching.js:32 (or in RemoteAddonsChild.jsm)
 [browser_offlineQuotaNotification.js]
 skip-if = buildapp == 'mulet' || e10s # Bug 1093603 - test breaks with PopupNotifications.panel.firstElementChild is null
 [browser_overflowScroll.js]
 [browser_pageInfo.js]
 skip-if = buildapp == 'mulet'
 [browser_page_style_menu.js]
@@ -484,24 +488,26 @@ skip-if = e10s # Bug 1094240 - has findb
 [browser_no_mcb_on_http_site.js]
 [browser_bug1104165-switchtab-decodeuri.js]
 [browser_bug1003461-switchtab-override.js]
 [browser_bug1024133-switchtab-override-keynav.js]
 [browser_bug1025195_switchToTabHavingURI_aOpenParams.js]
 [browser_addCertException.js]
 skip-if = e10s # Bug 1100687 - test directly manipulates content (content.document.getElementById)
 [browser_bug1045809.js]
+tags = mcb
 [browser_e10s_switchbrowser.js]
 [browser_e10s_about_process.js]
 [browser_e10s_chrome_process.js]
 [browser_e10s_javascript.js]
 [browser_blockHPKP.js]
 tags = psm
 skip-if = e10s # bug 1100687 - test directly manipulates content (content.document.getElementById)
 [browser_mcb_redirect.js]
+tags = mcb
 [browser_windowactivation.js]
 [browser_contextmenu_childprocess.js]
 [browser_bug963945.js]
 [browser_readerMode.js]
 support-files =
   readerModeArticle.html
 [browser_readerMode_hidden_nodes.js]
 support-files =
--- a/browser/base/content/test/general/browser_action_keyword.js
+++ b/browser/base/content/test/general/browser_action_keyword.js
@@ -33,17 +33,19 @@ add_task(function*() {
                                                 url: "http://example.com/?q=%s",
                                                 title: "test" });
   yield PlacesUtils.keywords.insert({ keyword: "keyword",
                                       url: "http://example.com/?q=%s" });
 
   let result = yield promise_first_result("keyword something");
   isnot(result, null, "Expect a keyword result");
 
-  is(result.getAttribute("type"), "action keyword", "Expect correct  `type` attribute");
+  let types = new Set(result.getAttribute("type").split(/\s+/));
+  Assert.ok(types.has("action"));
+  Assert.ok(types.has("keyword"));
   is(result.getAttribute("actiontype"), "keyword", "Expect correct `actiontype` attribute");
   is(result.getAttribute("title"), "example.com", "Expect correct title");
 
   // We need to make a real URI out of this to ensure it's normalised for
   // comparison.
   let uri = NetUtil.newURI(result.getAttribute("url"));
   is(uri.spec, makeActionURI("keyword", {url: "http://example.com/?q=something", input: "keyword something"}).spec, "Expect correct url");
 
--- a/browser/base/content/test/general/browser_autocomplete_a11y_label.js
+++ b/browser/base/content/test/general/browser_autocomplete_a11y_label.js
@@ -1,26 +1,68 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-add_task(function*() {
+const UNIFIEDCOMPLETE_PREF = "browser.urlbar.unifiedcomplete";
+const SUGGEST_ALL_PREF = "browser.search.suggest.enabled";
+const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
+const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
+
+add_task(function* prepare() {
   // This test is only relevant if UnifiedComplete is enabled.
-  let ucpref = Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete");
-  Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
+  Services.prefs.setBoolPref(UNIFIEDCOMPLETE_PREF, true);
   registerCleanupFunction(() => {
-    Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", ucpref);
+    Services.prefs.clearUserPref(UNIFIEDCOMPLETE_PREF);
   });
+});
 
+add_task(function* switchToTab() {
   let tab = gBrowser.addTab("about:about");
   yield promiseTabLoaded(tab);
 
   let actionURL = makeActionURI("switchtab", {url: "about:about"}).spec;
   yield promiseAutocompleteResultPopup("% about");
 
   ok(gURLBar.popup.richlistbox.children.length > 1, "Should get at least 2 results");
   let result = gURLBar.popup.richlistbox.children[1];
   is(result.getAttribute("type"), "action switchtab", "Expect right type attribute");
-  is(result.label, "about:about " + actionURL + " Tab", "Result a11y label should be as expected");
+  is(result.label, "about:about about:about Tab", "Result a11y label should be: <title> <url> Tab");
 
   gURLBar.popup.hidePopup();
   yield promisePopupHidden(gURLBar.popup);
   gBrowser.removeTab(tab);
 });
+
+add_task(function* searchSuggestions() {
+  let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
+  let oldCurrentEngine = Services.search.currentEngine;
+  Services.search.currentEngine = engine;
+  Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
+  Services.prefs.setBoolPref(SUGGEST_URLBAR_PREF, true);
+  registerCleanupFunction(function () {
+    Services.search.currentEngine = oldCurrentEngine;
+    Services.prefs.clearUserPref(SUGGEST_ALL_PREF);
+    Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
+  });
+
+  yield promiseAutocompleteResultPopup("foo");
+  // Don't assume that the search doesn't match history or bookmarks left around
+  // by earlier tests.
+  Assert.ok(gURLBar.popup.richlistbox.children.length >= 3,
+            "Should get at least heuristic result + two search suggestions");
+  // The first expected search is the search term itself since the heuristic
+  // result will come before the search suggestions.
+  let expectedSearches = [
+    "foo",
+    "foofoo",
+    "foobar",
+  ];
+  for (let child of gURLBar.popup.richlistbox.children) {
+    if (child.getAttribute("type").split(/\s+/).indexOf("searchengine") >= 0) {
+      Assert.ok(expectedSearches.length > 0);
+      let suggestion = expectedSearches.shift();
+      Assert.equal(child.label, suggestion + " browser_searchSuggestionEngine searchSuggestionEngine.xml Search",
+                   "Result label should be: <search term> <engine name> Search");
+    }
+  }
+  Assert.ok(expectedSearches.length == 0);
+  gURLBar.closePopup();
+});
--- a/browser/base/content/test/general/browser_bug1045809.js
+++ b/browser/base/content/test/general/browser_bug1045809.js
@@ -30,48 +30,33 @@ add_task(function* () {
   yield* test2(gBrowser.getBrowserForTab(tab));
 
   // Test 3: mixed content must be blocked again
   yield promiseTabLoadEvent(tab);
   yield* test3(gBrowser.getBrowserForTab(tab));
 });
 
 function* test1(gTestBrowser) {
-  var notification =
-    PopupNotifications.getNotification("bad-content", gTestBrowser);
-  isnot(notification, null, "Mixed Content Doorhanger did appear in Test1");
-  yield promiseNotificationShown(notification);
-  isnot(PopupNotifications.panel.firstChild.isMixedContentBlocked, 0,
-    "Mixed Content is being blocked in Test1");
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
   var x = content.document.getElementsByTagName('iframe')[0].contentDocument.getElementById('mixedContentContainer');
   is(x, null, "Mixed Content is NOT to be found in Test1");
 
   // Disable Mixed Content Protection for the page (and reload)
-  PopupNotifications.panel.firstChild.disableMixedContentProtection();
+  gIdentityHandler.disableMixedContentProtection();
 }
 
 function* test2(gTestBrowser) {
-  var notification =
-    PopupNotifications.getNotification("bad-content", gTestBrowser);
-  isnot(notification, null, "Mixed Content Doorhanger did appear in Test2");
-  yield promiseNotificationShown(notification);
-  is(PopupNotifications.panel.firstChild.isMixedContentBlocked, 0,
-    "Mixed Content is NOT being blocked in Test2");
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: true, activeBlocked: false, passiveLoaded: false});
 
   var x = content.document.getElementsByTagName('iframe')[0].contentDocument.getElementById('mixedContentContainer');
   isnot(x, null, "Mixed Content is to be found in Test2");
 
   // Re-enable Mixed Content Protection for the page (and reload)
-  PopupNotifications.panel.firstChild.enableMixedContentProtection();
+  gIdentityHandler.enableMixedContentProtection();
 }
 
 function* test3(gTestBrowser) {
-  var notification =
-    PopupNotifications.getNotification("bad-content", gTestBrowser);
-  isnot(notification, null, "Mixed Content Doorhanger did appear in Test3");
-  yield promiseNotificationShown(notification);
-  isnot(PopupNotifications.panel.firstChild.isMixedContentBlocked, 0,
-    "Mixed Content is being blocked in Test3");
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
   var x = content.document.getElementsByTagName('iframe')[0].contentDocument.getElementById('mixedContentContainer');
   is(x, null, "Mixed Content is NOT to be found in Test3");
 }
--- a/browser/base/content/test/general/browser_bug822367.js
+++ b/browser/base/content/test/general/browser_bug822367.js
@@ -45,21 +45,21 @@ function test() {
   var url = gHttpTestRoot + "file_bug822367_1.html";
   gTestBrowser.contentWindow.location = url;
 }
 
 // Mixed Script Test
 function MixedTest1A() {
   gTestBrowser.removeEventListener("load", MixedTest1A, true);
   gTestBrowser.addEventListener("load", MixedTest1B, true);
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "Mixed Content Doorhanger did appear");
-  notification.reshow();
-  ok(PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked");
-  PopupNotifications.panel.firstChild.disableMixedContentProtection();
+
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
+
+  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
+  gIdentityHandler.disableMixedContentProtection();
 }
 function MixedTest1B() {
   waitForCondition(function() content.document.getElementById('p1').innerHTML == "hello", MixedTest1C, "Waited too long for mixed script to run in Test 1");
 }
 function MixedTest1C() {
   ok(content.document.getElementById('p1').innerHTML == "hello","Mixed script didn't load in Test 1");
   gTestBrowser.removeEventListener("load", MixedTest1B, true);
   MixedTest2();
@@ -68,75 +68,74 @@ function MixedTest1C() {
 //Mixed Display Test - Doorhanger should not appear
 function MixedTest2() {
   gTestBrowser.addEventListener("load", MixedTest2A, true);
   var url = gHttpTestRoot2 + "file_bug822367_2.html";
   gTestBrowser.contentWindow.location = url;
 }
 
 function MixedTest2A() {
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(!notification, "Mixed Content Doorhanger did not appear for mixed display content!");
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: false, passiveLoaded: false});
   MixedTest3();
 }
 
 // Mixed Script and Display Test - User Override should cause both the script and the image to load.
 function MixedTest3() {
   gTestBrowser.removeEventListener("load", MixedTest2A, true);
   gTestBrowser.addEventListener("load", MixedTest3A, true);
   var url = gHttpTestRoot + "file_bug822367_3.html";
   gTestBrowser.contentWindow.location = url;
 }
 function MixedTest3A() {
   gTestBrowser.removeEventListener("load", MixedTest3A, true);
   gTestBrowser.addEventListener("load", MixedTest3B, true);
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "Mixed Content Doorhanger did appear for test 3");
-  notification.reshow();
-  ok(PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in test 3");
-  PopupNotifications.panel.firstChild.disableMixedContentProtection();
+
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
+
+  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
+  gIdentityHandler.disableMixedContentProtection();
 }
 function MixedTest3B() {
   waitForCondition(function() content.document.getElementById('p1').innerHTML == "hello", MixedTest3C, "Waited too long for mixed script to run in Test 3");
 }
 function MixedTest3C() {
   waitForCondition(function() content.document.getElementById('p2').innerHTML == "bye", MixedTest3D, "Waited too long for mixed image to load in Test 3");
 }
 function MixedTest3D() {
   ok(content.document.getElementById('p1').innerHTML == "hello","Mixed script didn't load in Test 3");
   ok(content.document.getElementById('p2').innerHTML == "bye","Mixed image didn't load in Test 3");
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: true, activeBlocked: false, passiveLoaded: true});
   MixedTest4();
 }
 
 // Location change - User override on one page doesn't propogate to another page after location change.
 function MixedTest4() {
   gTestBrowser.removeEventListener("load", MixedTest3B, true);
   gTestBrowser.addEventListener("load", MixedTest4A, true);
   var url = gHttpTestRoot2 + "file_bug822367_4.html";
   gTestBrowser.contentWindow.location = url;
 }
 function MixedTest4A() {
   gTestBrowser.removeEventListener("load", MixedTest4A, true);
   gTestBrowser.addEventListener("load", MixedTest4B, true);
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "Mixed Content Doorhanger did appear for Test 4");
-  notification.reshow();
-  ok(PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test 4");
-  PopupNotifications.panel.firstChild.disableMixedContentProtection();
+
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
+
+  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
+  gIdentityHandler.disableMixedContentProtection();
 }
 function MixedTest4B() {
   waitForCondition(function() content.document.location == gHttpTestRoot + "file_bug822367_4B.html", MixedTest4C, "Waited too long for mixed script to run in Test 4");
 }
 function MixedTest4C() {
   ok(content.document.location == gHttpTestRoot + "file_bug822367_4B.html", "Location didn't change in test 4");
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "Mixed Content Doorhanger did appear after location change in Test 4");
-  notification.reshow();
-  ok(PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in test 4");
-  notification.remove();
+
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
+
+  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
   waitForCondition(function() content.document.getElementById('p1').innerHTML == "", MixedTest4D, "Mixed script loaded in test 4 after location change!");
 }
 function MixedTest4D() {
   ok(content.document.getElementById('p1').innerHTML == "","p1.innerHTML changed; mixed script loaded after location change in Test 4");
   MixedTest5();
 }
 
 // Mixed script attempts to load in a document.open()
@@ -144,21 +143,21 @@ function MixedTest5() {
   gTestBrowser.removeEventListener("load", MixedTest4B, true);
   gTestBrowser.addEventListener("load", MixedTest5A, true);
   var url = gHttpTestRoot + "file_bug822367_5.html";
   gTestBrowser.contentWindow.location = url;
 }
 function MixedTest5A() {
   gTestBrowser.removeEventListener("load", MixedTest5A, true);
   gTestBrowser.addEventListener("load", MixedTest5B, true);
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "Mixed Content Doorhanger did appear for Test 5");
-  notification.reshow();
-  ok(PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test 5");
-  PopupNotifications.panel.firstChild.disableMixedContentProtection();
+
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
+
+  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
+  gIdentityHandler.disableMixedContentProtection();
 }
 function MixedTest5B() {
   waitForCondition(function() content.document.getElementById('p1').innerHTML == "hello", MixedTest5C, "Waited too long for mixed script to run in Test 5");
 }
 function MixedTest5C() {
   ok(content.document.getElementById('p1').innerHTML == "hello","Mixed script didn't load in Test 5");
   MixedTest6();
 }
@@ -167,34 +166,36 @@ function MixedTest5C() {
 function MixedTest6() {
   gTestBrowser.removeEventListener("load", MixedTest5B, true);
   gTestBrowser.addEventListener("load", MixedTest6A, true);
   var url = gHttpTestRoot2 + "file_bug822367_6.html";
   gTestBrowser.contentWindow.location = url;
 }
 function MixedTest6A() {
   gTestBrowser.removeEventListener("load", MixedTest6A, true);
-  waitForCondition(function() PopupNotifications.getNotification("bad-content", gTestBrowser), MixedTest6B, "waited too long for doorhanger");
+  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
+  waitForCondition(() => gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"), MixedTest6B, "Waited too long for control center to get mixed active blocked state");
 }
 
 function MixedTest6B() {
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "Mixed Content Doorhanger did appear for Test 6");
   gTestBrowser.addEventListener("load", MixedTest6C, true);
-  notification.reshow();
-  ok(PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test 6");
-  PopupNotifications.panel.firstChild.disableMixedContentProtection();
+
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
+
+  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
+  gIdentityHandler.disableMixedContentProtection();
 }
 
 function MixedTest6C() {
   gTestBrowser.removeEventListener("load", MixedTest6C, true);
   waitForCondition(function() {
     try {
       return content.document.getElementById('f1').contentDocument.getElementById('p1').innerHTML == "hello";
     } catch (e) {
       return false;
     }
   }, MixedTest6D, "Waited too long for mixed script to run in Test 6");
 }
 function MixedTest6D() {
   ok(content.document.getElementById('f1').contentDocument.getElementById('p1').innerHTML == "hello","Mixed script didn't load in Test 6");
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: true, activeBlocked: false, passiveLoaded: false});
   MixedTestsCompleted();
 }
--- a/browser/base/content/test/general/browser_bug902156.js
+++ b/browser/base/content/test/general/browser_bug902156.js
@@ -1,27 +1,27 @@
 /*
  * Description of the Tests for
  *  - Bug 902156: Persist "disable protection" option for Mixed Content Blocker
  *
  * 1. Navigate to the same domain via document.location
  *    - Load a html page which has mixed content
- *    - Doorhanger to disable protection appears - we disable it
+ *    - Control Center button to disable protection appears - we disable it
  *    - Load a new page from the same origin using document.location
- *    - Doorhanger should not appear anymore!
+ *    - Control Center button should not appear anymore!
  *
  * 2. Navigate to the same domain via simulateclick for a link on the page
  *    - Load a html page which has mixed content
- *    - Doorhanger to disable protection appears - we disable it
+ *    - Control Center button to disable protection appears - we disable it
  *    - Load a new page from the same origin simulating a click
- *    - Doorhanger should not appear anymore!
+ *    - Control Center button should not appear anymore!
  *
  * 3. Navigate to a differnet domain and show the content is still blocked
  *    - Load a different html page which has mixed content
- *    - Doorhanger to disable protection should appear again because
+ *    - Control Center button to disable protection should appear again because
  *      we navigated away from html page where we disabled the protection.
  *
  * Note, for all tests we set gHttpTestRoot to use 'https'.
  */
 
 const PREF_ACTIVE = "security.mixed_content.block_active_content";
 
 // We alternate for even and odd test cases to simulate different hosts
@@ -45,24 +45,21 @@ function cleanUpAfterTests() {
 //------------------------ Test 1 ------------------------------
 
 function test1A() {
   // Removing EventListener because we have to register a new
   // one once the page is loaded with mixed content blocker disabled
   gTestBrowser.removeEventListener("load", test1A, true);
   gTestBrowser.addEventListener("load", test1B, true);
 
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test1A!");
-  notification.reshow();
-  ok(PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test1A!");
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
   // Disable Mixed Content Protection for the page (and reload)
-  PopupNotifications.panel.firstChild.disableMixedContentProtection();
-  notification.remove();
+  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
+  gIdentityHandler.disableMixedContentProtection();
 }
 
 function test1B() {
   var expected = "Mixed Content Blocker disabled";
   waitForCondition(
     function() content.document.getElementById('mctestdiv').innerHTML == expected,
     test1C, "Error: Waited too long for mixed script to run in Test 1B");
 }
@@ -78,23 +75,19 @@ function test1C() {
 
   var url = gHttpTestRoot1 + "file_bug902156_2.html";
   gTestBrowser.contentWindow.location = url;
 }
 
 function test1D() {
   gTestBrowser.removeEventListener("load", test1D, true);
 
-  // The Doorhanger should appear but isMixedContentBlocked should be NOT true,
+  // The Control Center button should appear but isMixedContentBlocked should be NOT true,
   // because our decision of disabling the mixed content blocker is persistent.
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test1D!");
-  notification.reshow();
-  ok(!PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is NOT being blocked in Test1D!");
-  notification.remove();
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: true, activeBlocked: false, passiveLoaded: false});
 
   var actual = content.document.getElementById('mctestdiv').innerHTML;
   is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 1D");
 
   // move on to Test 2
   test2();
 }
 
@@ -107,24 +100,21 @@ function test2() {
 }
 
 function test2A() {
   // Removing EventListener because we have to register a new
   // one once the page is loaded with mixed content blocker disabled
   gTestBrowser.removeEventListener("load", test2A, true);
   gTestBrowser.addEventListener("load", test2B, true);
 
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 2A!");
-  notification.reshow();
-  ok(PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test 2A!");
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
   // Disable Mixed Content Protection for the page (and reload)
-  PopupNotifications.panel.firstChild.disableMixedContentProtection();
-  notification.remove();
+  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
+  gIdentityHandler.disableMixedContentProtection();
 }
 
 function test2B() {
   var expected = "Mixed Content Blocker disabled";
   waitForCondition(
     function() content.document.getElementById('mctestdiv').innerHTML == expected,
     test2C, "Error: Waited too long for mixed script to run in Test 2B");
 }
@@ -141,23 +131,19 @@ function test2C() {
   // reload the page using the provided link in the html file
   var mctestlink = content.document.getElementById("mctestlink");
   mctestlink.click();
 }
 
 function test2D() {
   gTestBrowser.removeEventListener("load", test2D, true);
 
-  // The Doorhanger should appear but isMixedContentBlocked should be NOT true,
+  // The Control Center button should appear but isMixedContentBlocked should be NOT true,
   // because our decision of disabling the mixed content blocker is persistent.
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test2D!");
-  notification.reshow();
-  ok(!PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is NOT being blocked");
-  notification.remove();
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: true, activeBlocked: false, passiveLoaded: false});
 
   var actual = content.document.getElementById('mctestdiv').innerHTML;
   is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 2D");
 
   // move on to Test 3
   test3();
 }
 
@@ -169,21 +155,17 @@ function test3() {
   gTestBrowser.contentWindow.location = url;
 }
 
 function test3A() {
   // Removing EventListener because we have to register a new
   // one once the page is loaded with mixed content blocker disabled
   gTestBrowser.removeEventListener("load", test3A, true);
 
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 3A!");
-  notification.reshow();
-  ok(PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test 3A");
-  notification.remove();
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
   // We are done with tests, clean up
   cleanUpAfterTests();
 }
 
 //------------------------------------------------------
 
 function test() {
--- a/browser/base/content/test/general/browser_bug906190.js
+++ b/browser/base/content/test/general/browser_bug906190.js
@@ -138,25 +138,21 @@ function waitForSomeTabToLoad(callback) 
       callback();
     }
   }, true);
 }
 
 function checkPopUpNotification() {
   waitForSomeTabToLoad(reloadedTabAfterDisablingMCB);
 
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in " + curTestName + "!");
-  promiseNotificationShown(notification).then(function() {
-    ok(gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in " + curTestName + "!");
+  assertMixedContentBlockingState(gTestWin.gBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
-    // Disable Mixed Content Protection for the page (and reload page)
-    gTestWin.PopupNotifications.panel.firstChild.disableMixedContentProtection();
-    notification.remove();
-  });
+  // Disable Mixed Content Protection for the page (which reloads the page)
+  let {gIdentityHandler} = gTestWin.gBrowser.ownerGlobal;
+  gIdentityHandler.disableMixedContentProtection();
 }
 
 function reloadedTabAfterDisablingMCB() {
   var expected = "Mixed Content Blocker disabled";
   waitForCondition(
     function() gTestWin.content.document.getElementById('mctestdiv').innerHTML == expected,
     makeSureMCBisDisabled, "Error: Waited too long for mixed script to run in " + curTestName + "!");
 }
@@ -187,28 +183,23 @@ function test1() {
   EventUtils.synthesizeMouseAtCenter(targetElt, { button: 1 }, gTestWin.content);
 }
 
 function test1A() {
   gTestWin.gBrowser.selectTabAtIndex(2);
 
   // The Doorhanger should appear but isMixedContentBlocked should be >> NOT << true,
   // because our decision of disabling the mixed content blocker is persistent across tabs.
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 1A!");
-  promiseNotificationShown(notification).then(function() {
-    ok(!gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is NOT being blocked in Test 1A!");
-    notification.remove();
+  assertMixedContentBlockingState(gTestWin.gBrowser, {activeLoaded: true, activeBlocked: false, passiveLoaded: false});
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 1A");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 1A");
 
-    gTestWin.gBrowser.removeCurrentTab();
-    test1B();
-  });
+  gTestWin.gBrowser.removeCurrentTab();
+  test1B();
 }
 
 function test1B() {
   curContextMenu = function (e) { contextMenuOpenHandler(e, test1C) };
   gTestWin.document.addEventListener("popupshown", curContextMenu, false);
 
   // simulating |RIGHT-CLICK -> OPEN LINK IN TAB|
   let targetElt = gTestWin.content.document.getElementById("Test1");
@@ -216,33 +207,28 @@ function test1B() {
   EventUtils.synthesizeMouseAtCenter(targetElt, { type : "contextmenu", button : 2 } , gTestWin.content);
 }
 
 function test1C() {
   gTestWin.gBrowser.selectTabAtIndex(2);
 
   // The Doorhanger should appear but isMixedContentBlocked should be >> NOT << true,
   // because our decision of disabling the mixed content blocker is persistent across tabs.
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 1C!");
-  promiseNotificationShown(notification).then(function() {
-    ok(!gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is NOT being blocked in Test 1C!");
-    notification.remove();
+  assertMixedContentBlockingState(gTestWin.gBrowser, {activeLoaded: true, activeBlocked: false, passiveLoaded: false});
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 1C");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 1C");
 
-    // remove tabs
-    gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
-    gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
-    gTestWin.gBrowser.selectTabAtIndex(0);
+  // remove tabs
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
+  gTestWin.gBrowser.selectTabAtIndex(0);
 
-    var childTabLink = gHttpTestRoot2 + "file_bug906190_2.html";
-    setUpTest("Test2", "linkForTest2", test2, childTabLink);
-  });
+  var childTabLink = gHttpTestRoot2 + "file_bug906190_2.html";
+  setUpTest("Test2", "linkForTest2", test2, childTabLink);
 }
 
 //------------------------ Test 2 ------------------------------
 
 function test2() {
   curClickHandler = function (e) { clickHandler(e, test2A) };
   gTestWin.gBrowser.addEventListener("click", curClickHandler, true);
 
@@ -251,28 +237,23 @@ function test2() {
   EventUtils.synthesizeMouseAtCenter(targetElt, { button: 1 }, gTestWin.content);
 }
 
 function test2A() {
   gTestWin.gBrowser.selectTabAtIndex(2);
 
   // The Doorhanger should appear and isMixedContentBlocked should be >> TRUE <<,
   // because our decision of disabling the mixed content blocker should only persist if pages are from the same domain.
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 2A!");
-  promiseNotificationShown(notification).then(function() {
-    ok(gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test 2A!");
-    notification.remove();
+  assertMixedContentBlockingState(gTestWin.gBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 2A");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 2A");
 
-    gTestWin.gBrowser.removeCurrentTab();
-    test2B();
-  });
+  gTestWin.gBrowser.removeCurrentTab();
+  test2B();
 }
 
 function test2B() {
   curContextMenu = function (e) { contextMenuOpenHandler(e, test2C) };
   gTestWin.document.addEventListener("popupshown", curContextMenu, false);
 
   // simulating |RIGHT-CLICK -> OPEN LINK IN TAB|
   let targetElt = gTestWin.content.document.getElementById("Test2");
@@ -280,34 +261,29 @@ function test2B() {
   EventUtils.synthesizeMouseAtCenter(targetElt, { type : "contextmenu", button : 2 } , gTestWin.content);
 }
 
 function test2C() {
   gTestWin.gBrowser.selectTabAtIndex(2);
 
   // The Doorhanger should appear and isMixedContentBlocked should be >> TRUE <<,
   // because our decision of disabling the mixed content blocker should only persist if pages are from the same domain.
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 2C!");
-  promiseNotificationShown(notification).then(function() {
-    ok(gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test 2C!");
-    notification.remove();
+  assertMixedContentBlockingState(gTestWin.gBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 2C");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 2C");
 
-    // remove tabs
-    gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
-    gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
-    gTestWin.gBrowser.selectTabAtIndex(0);
+  // remove tabs
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
+  gTestWin.gBrowser.selectTabAtIndex(0);
 
-    // file_bug906190_3_4.html redirects to page test1.example.com/* using meta-refresh
-    var childTabLink = gHttpTestRoot1 + "file_bug906190_3_4.html";
-    setUpTest("Test3", "linkForTest3", test3, childTabLink);
-  });
+  // file_bug906190_3_4.html redirects to page test1.example.com/* using meta-refresh
+  var childTabLink = gHttpTestRoot1 + "file_bug906190_3_4.html";
+  setUpTest("Test3", "linkForTest3", test3, childTabLink);
 }
 
 //------------------------ Test 3 ------------------------------
 
 function test3() {
   curClickHandler = function (e) { clickHandler(e, test3A) };
   gTestWin.gBrowser.addEventListener("click", curClickHandler, true);
   // simulating |CTRL-CLICK|
@@ -319,29 +295,24 @@ function test3A() {
   // we need this indirection because the page is reloaded caused by meta-refresh
   waitForSomeTabToLoad(test3B);
 }
 
 function test3B() {
   gTestWin.gBrowser.selectTabAtIndex(2);
 
   // The Doorhanger should appear but isMixedContentBlocked should be >> NOT << true!
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 3B!");
-  promiseNotificationShown(notification).then(function() {
-    ok(!gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is NOT being blocked in Test 3B!");
-    notification.remove();
+  assertMixedContentBlockingState(gTestWin.gBrowser, {activeLoaded: true, activeBlocked: false, passiveLoaded: false});
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 3B");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 3B");
 
-    // remove tabs
-    gTestWin.gBrowser.removeCurrentTab();
-    test3C();
-  });
+  // remove tabs
+  gTestWin.gBrowser.removeCurrentTab();
+  test3C();
 }
 
 function test3C() {
   curContextMenu = function (e) { contextMenuOpenHandler(e, test3D) };
   gTestWin.document.addEventListener("popupshown", curContextMenu, false);
 
   // simulating |RIGHT-CLICK -> OPEN LINK IN TAB|
   let targetElt = gTestWin.content.document.getElementById("Test3");
@@ -352,33 +323,28 @@ function test3D() {
   // we need this indirection because the page is reloaded caused by meta-refresh
   waitForSomeTabToLoad(test3E);
 }
 
 function test3E() {
   gTestWin.gBrowser.selectTabAtIndex(2);
 
   // The Doorhanger should appear but isMixedContentBlocked should be >> NOT << true!
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 3E!");
-  promiseNotificationShown(notification).then(function() {
-    ok(!gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is NOT being blocked in Test 3E!");
-    notification.remove();
+  assertMixedContentBlockingState(gTestWin.gBrowser, {activeLoaded: true, activeBlocked: false, passiveLoaded: false});
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 3E");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 3E");
 
-    // remove tabs
-    gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
-    gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
-    gTestWin.gBrowser.selectTabAtIndex(0);
+  // remove tabs
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
+  gTestWin.gBrowser.selectTabAtIndex(0);
 
-    var childTabLink = gHttpTestRoot1 + "file_bug906190_3_4.html";
-    setUpTest("Test4", "linkForTest4", test4, childTabLink);
-  });
+  var childTabLink = gHttpTestRoot1 + "file_bug906190_3_4.html";
+  setUpTest("Test4", "linkForTest4", test4, childTabLink);
 }
 
 //------------------------ Test 4 ------------------------------
 
 function test4() {
   curClickHandler = function (e) { clickHandler(e, test4A) };
   gTestWin.gBrowser.addEventListener("click", curClickHandler, true);
 
@@ -391,29 +357,24 @@ function test4A() {
   // we need this indirection because the page is reloaded caused by meta-refresh
   waitForSomeTabToLoad(test4B);
 }
 
 function test4B() {
   gTestWin.gBrowser.selectTabAtIndex(2);
 
   // The Doorhanger should appear and isMixedContentBlocked should be >> TRUE <<
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 4B!");
-  promiseNotificationShown(notification).then(function() {
-    ok(gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test 4B!");
-    notification.remove();
+  assertMixedContentBlockingState(gTestWin.gBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 4B");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 4B");
 
-    // remove tabs
-    gTestWin.gBrowser.removeCurrentTab();
-    test4C();
-  });
+  // remove tabs
+  gTestWin.gBrowser.removeCurrentTab();
+  test4C();
 }
 
 function test4C() {
   curContextMenu = function (e) { contextMenuOpenHandler(e, test4D) };
   gTestWin.document.addEventListener("popupshown", curContextMenu, false);
 
   // simulating |RIGHT-CLICK -> OPEN LINK IN TAB|
   let targetElt = gTestWin.content.document.getElementById("Test4");
@@ -424,34 +385,29 @@ function test4D() {
   // we need this indirection because the page is reloaded caused by meta-refresh
   waitForSomeTabToLoad(test4E);
 }
 
 function test4E() {
   gTestWin.gBrowser.selectTabAtIndex(2);
 
   // The Doorhanger should appear and isMixedContentBlocked should be >> TRUE <<
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 4E!");
-  promiseNotificationShown(notification).then(function() {
-    ok(gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test 4E!");
-    notification.remove();
+  assertMixedContentBlockingState(gTestWin.gBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 4E");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 4E");
 
-    // remove tabs
-    gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
-    gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
-    gTestWin.gBrowser.selectTabAtIndex(0);
+  // remove tabs
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
+  gTestWin.gBrowser.selectTabAtIndex(0);
 
-    // the sjs files returns a 302 redirect- note, same origins
-    var childTabLink = gHttpTestRoot1 + "file_bug906190.sjs";
-    setUpTest("Test5", "linkForTest5", test5, childTabLink);
-  });
+  // the sjs files returns a 302 redirect- note, same origins
+  var childTabLink = gHttpTestRoot1 + "file_bug906190.sjs";
+  setUpTest("Test5", "linkForTest5", test5, childTabLink);
 }
 
 //------------------------ Test 5 ------------------------------
 
 function test5() {
   curClickHandler = function (e) { clickHandler(e, test5A) };
   gTestWin.gBrowser.addEventListener("click", curClickHandler, true);
 
@@ -460,64 +416,57 @@ function test5() {
   EventUtils.synthesizeMouseAtCenter(targetElt, { button: 1 }, gTestWin.content);
 }
 
 function test5A() {
   gTestWin.gBrowser.selectTabAtIndex(2);
 
   // The Doorhanger should appear but isMixedContentBlocked should be >> NOT << true
   // Currently it is >> TRUE << - see follow up bug 914860
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 5A!");
-  promiseNotificationShown(notification).then(function() {
-    todo(!gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is NOT being blocked in Test 5A!");
-    notification.remove();
+  let {gIdentityHandler} = gTestWin.gBrowser.ownerGlobal;
+  todo(!gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"), "OK: Mixed Content is NOT being blocked in Test 5A!");
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    todo_is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 5A!");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  todo_is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 5A!");
 
-    // remove tabs
-    gTestWin.gBrowser.removeCurrentTab();
-    test5B();
-  });
+  // remove tabs
+  gTestWin.gBrowser.removeCurrentTab();
+  test5B();
 }
 
 function test5B() {
   curContextMenu = function (e) { contextMenuOpenHandler(e, test5C) };
   gTestWin.document.addEventListener("popupshown", curContextMenu, false);
 
   // simulating |RIGHT-CLICK -> OPEN LINK IN TAB|
   let targetElt = gTestWin.content.document.getElementById("Test5");
   EventUtils.synthesizeMouseAtCenter(targetElt, { type : "contextmenu", button : 2 } , gTestWin.content);
 }
 
 function test5C() {
   // move the tab again
   gTestWin.gBrowser.selectTabAtIndex(2);
 
+  let {gIdentityHandler} = gTestWin.gBrowser.ownerGlobal;
+
   // The Doorhanger should appear but isMixedContentBlocked should be >> NOT << true
   // Currently it is >> TRUE << - see follow up bug 914860
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 5C!");
-  promiseNotificationShown(notification).then(function() {
-    todo(!gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is NOT being blocked in Test 5C!");
-    notification.remove();
+  todo(!gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"), "OK: Mixed Content is NOT being blocked in Test 5C!");
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    todo_is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 5C!");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  todo_is(actual, "Mixed Content Blocker disabled", "OK: Executed mixed script in Test 5C!");
 
-    // remove tabs
-    gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
-    gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
-    gTestWin.gBrowser.selectTabAtIndex(0);
+  // remove tabs
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[2], {animate: false});
+  gTestWin.gBrowser.removeTab(gTestWin.gBrowser.tabs[1], {animate: false});
+  gTestWin.gBrowser.selectTabAtIndex(0);
 
-    // the sjs files returns a 302 redirect - note, different origins
-    var childTabLink = gHttpTestRoot2 + "file_bug906190.sjs";
-    setUpTest("Test6", "linkForTest6", test6, childTabLink);
-  });
+  // the sjs files returns a 302 redirect - note, different origins
+  var childTabLink = gHttpTestRoot2 + "file_bug906190.sjs";
+  setUpTest("Test6", "linkForTest6", test6, childTabLink);
 }
 
 //------------------------ Test 6 ------------------------------
 
 function test6() {
   curClickHandler = function (e) { clickHandler(e, test6A) };
   gTestWin.gBrowser.addEventListener("click", curClickHandler, true);
 
@@ -525,56 +474,46 @@ function test6() {
   let targetElt = gTestWin.content.document.getElementById("Test6");
   EventUtils.synthesizeMouseAtCenter(targetElt, { button: 1 }, gTestWin.content);
 }
 
 function test6A() {
   gTestWin.gBrowser.selectTabAtIndex(2);
 
   // The Doorhanger should appear and isMixedContentBlocked should be >> TRUE <<
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 6A!");
-  promiseNotificationShown(notification).then(function() {
-    ok(gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test 6A!");
-    notification.remove();
+  assertMixedContentBlockingState(gTestWin.gBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 6A");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 6A");
 
-    // done
-    gTestWin.gBrowser.removeCurrentTab();
-    test6B();
-  });
+  // done
+  gTestWin.gBrowser.removeCurrentTab();
+  test6B();
 }
 
 function test6B() {
   curContextMenu = function (e) { contextMenuOpenHandler(e, test6C) };
   gTestWin.document.addEventListener("popupshown", curContextMenu, false);
 
   // simulating |RIGHT-CLICK -> OPEN LINK IN TAB|
   let targetElt = gTestWin.content.document.getElementById("Test6");
   EventUtils.synthesizeMouseAtCenter(targetElt, { type : "contextmenu", button : 2 } , gTestWin.content);
 }
 
 function test6C() {
   gTestWin.gBrowser.selectTabAtIndex(2);
 
   // The Doorhanger should appear and isMixedContentBlocked should be >> TRUE <<
-  var notification = PopupNotifications.getNotification("bad-content", gTestWin.gBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger did appear in Test 6C!");
-  promiseNotificationShown(notification).then(function() {
-    ok(gTestWin.PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked in Test 6C!");
-    notification.remove();
+  assertMixedContentBlockingState(gTestWin.gBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
-    var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
-    is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 6C");
+  var actual = gTestWin.content.document.getElementById('mctestdiv').innerHTML;
+  is(actual, "Mixed Content Blocker enabled", "OK: Blocked mixed script in Test 6C");
 
-    gTestWin.close();
-    finish();
-  });
+  gTestWin.close();
+  finish();
 }
 
 //------------------------ SETUP ------------------------------
 
 function setupTestBrowserWindow() {
   // Inject links in content.
   let doc = gTestWin.content.document;
   let mainDiv = doc.createElement("div");
--- a/browser/base/content/test/general/browser_mcb_redirect.js
+++ b/browser/base/content/test/general/browser_mcb_redirect.js
@@ -95,47 +95,45 @@ function waitForCondition(condition, nex
   var moveOn = function() {
     clearInterval(interval); nextTest();
   };
 }
 
 //------------------------ Test 1 ------------------------------
 
 function test1() {
-  gTestBrowser.addEventListener("load", checkPopUpNotificationsForTest1, true);
+  gTestBrowser.addEventListener("load", checkUIForTest1, true);
   var url = gHttpsTestRoot + "test_mcb_redirect.html"
   gTestBrowser.contentWindow.location = url;
 }
 
-function checkPopUpNotificationsForTest1() {
-  gTestBrowser.removeEventListener("load", checkPopUpNotificationsForTest1, true);
+function checkUIForTest1() {
+  gTestBrowser.removeEventListener("load", checkUIForTest1, true);
 
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser.selectedBrowser);
-  ok(notification, "OK: Mixed Content Doorhanger appeared in Test1!");
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
   var expected = "script blocked";
   waitForCondition(
     function() content.document.getElementById('mctestdiv').innerHTML == expected,
     test2, "Error: Waited too long for status in Test 1!",
     "OK: Expected result in innerHTML for Test1!");
 }
 
 //------------------------ Test 2 ------------------------------
 
 function test2() {
-  gTestBrowser.addEventListener("load", checkPopUpNotificationsForTest2, true);
+  gTestBrowser.addEventListener("load", checkUIForTest2, true);
   var url = gHttpTestRoot + "test_mcb_redirect.html"
   gTestBrowser.contentWindow.location = url;
 }
 
-function checkPopUpNotificationsForTest2() {
-  gTestBrowser.removeEventListener("load", checkPopUpNotificationsForTest2, true);
+function checkUIForTest2() {
+  gTestBrowser.removeEventListener("load", checkUIForTest2, true);
 
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser.selectedBrowser);
-  ok(!notification, "OK: Mixed Content Doorhanger did not appear in 2!");
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: false, passiveLoaded: false});
 
   var expected = "script executed";
   waitForCondition(
     function() content.document.getElementById('mctestdiv').innerHTML == expected,
     test3, "Error: Waited too long for status in Test 2!",
     "OK: Expected result in innerHTML for Test2!");
 }
 
--- a/browser/base/content/test/general/browser_mixedcontent_securityflags.js
+++ b/browser/base/content/test/general/browser_mixedcontent_securityflags.js
@@ -34,41 +34,32 @@ function blockMixedContentTest()
     overrideMCB();
   }, true);
 }
 
 function overrideMCB()
 {
   // test mixed content flags on load (reload)
   gTestBrowser.addEventListener("load", mixedContentOverrideTest, true);
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "Mixed Content Doorhanger should appear");
-  notification.reshow();
-  ok(PopupNotifications.panel.firstChild.isMixedContentBlocked, "OK: Mixed Content is being blocked");
+
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: false, activeBlocked: true, passiveLoaded: false});
 
-  // Make sure the notification has no mixedblockdisabled attribute
-  ok(!PopupNotifications.panel.firstChild.hasAttribute("mixedblockdisabled"),
-    "Doorhanger must have no mixedblockdisabled attribute");
   // Click on the doorhanger to allow mixed content (and reload page)
-  PopupNotifications.panel.firstChild.disableMixedContentProtection();
+  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
+  gIdentityHandler.disableMixedContentProtection();
+
   notification.remove();
 }
 
 function mixedContentOverrideTest()
 {
   gTestBrowser.removeEventListener("load", mixedContentOverrideTest, true);
 
   is(gTestBrowser.docShell.hasMixedDisplayContentLoaded, true, "hasMixedDisplayContentLoaded flag has not been set");
   is(gTestBrowser.docShell.hasMixedActiveContentLoaded, true, "hasMixedActiveContentLoaded flag has not been set");
   is(gTestBrowser.docShell.hasMixedDisplayContentBlocked, false, "second hasMixedDisplayContentBlocked flag has been set");
   is(gTestBrowser.docShell.hasMixedActiveContentBlocked, false, "second hasMixedActiveContentBlocked flag has been set");
 
-  let notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(notification, "Mixed Content Doorhanger should appear");
-  notification.reshow();
-
-  // Make sure the notification has the mixedblockdisabled attribute set to true
-  is(PopupNotifications.panel.firstChild.getAttribute("mixedblockdisabled"), "true",
-    "Doorhanger must have [mixedblockdisabled='true'] attribute");
+  assertMixedContentBlockingState(gTestBrowser, {activeLoaded: true, activeBlocked: false, passiveLoaded: true});
 
   gBrowser.removeCurrentTab();
   finish();
 }
--- a/browser/base/content/test/general/browser_urlbarSearchSuggestionsNotification.js
+++ b/browser/base/content/test/general/browser_urlbarSearchSuggestionsNotification.js
@@ -1,16 +1,16 @@
 const SUGGEST_ALL_PREF = "browser.search.suggest.enabled";
 const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
 const CHOICE_PREF = "browser.urlbar.userMadeSearchSuggestionsChoice";
 const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
 
 // Must run first.
 add_task(function* prepare() {
-  let engine = yield promiseNewEngine(TEST_ENGINE_BASENAME);
+  let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
   let oldCurrentEngine = Services.search.currentEngine;
   Services.search.currentEngine = engine;
   registerCleanupFunction(function () {
     Services.search.currentEngine = oldCurrentEngine;
     Services.prefs.clearUserPref(SUGGEST_ALL_PREF);
     Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
 
     // Disable the notification for future tests so it doesn't interfere with
@@ -18,46 +18,34 @@ add_task(function* prepare() {
     Services.prefs.setBoolPref(CHOICE_PREF, true);
 
     // Make sure the popup is closed for the next test.
     gURLBar.blur();
     Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
   });
 });
 
-add_task(function* focus_allSuggestionsDisabled() {
-  Services.prefs.setBoolPref(SUGGEST_ALL_PREF, false);
-  Services.prefs.setBoolPref(CHOICE_PREF, false);
-  gURLBar.blur();
-  gURLBar.focus();
-  Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
-  yield promiseAutocompleteResultPopup("foo");
-  Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
-  assertVisible(false);
-});
-
-add_task(function* focus_noChoiceMade() {
+add_task(function* focus() {
+  // Focusing the urlbar used to open the popup in order to show the
+  // notification, but it doesn't anymore.  Make sure it does not.
   Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
   Services.prefs.setBoolPref(CHOICE_PREF, false);
   gURLBar.blur();
   gURLBar.focus();
-  Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
-  assertVisible(true);
-  gURLBar.blur();
-  Assert.ok(!gURLBar.popup.popupOpen, "popup should be closed");
-  gURLBar.focus();
-  Assert.ok(gURLBar.popup.popupOpen, "popup should be open again");
-  assertVisible(true);
+  Assert.ok(!gURLBar.popup.popupOpen, "popup should remain closed");
 });
 
 add_task(function* dismissWithoutResults() {
   Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
   Services.prefs.setBoolPref(CHOICE_PREF, false);
   gURLBar.blur();
   gURLBar.focus();
+  let popupPromise = promisePopupShown(gURLBar.popup);
+  gURLBar.openPopup();
+  yield popupPromise;
   Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
   assertVisible(true);
   Assert.equal(gURLBar.popup._matchCount, 0, "popup should have no results");
   let disableButton = document.getAnonymousElementByAttribute(
     gURLBar.popup, "anonid", "search-suggestions-notification-disable"
   );
   let transitionPromise = promiseTransition();
   disableButton.click();
@@ -71,19 +59,19 @@ add_task(function* dismissWithoutResults
   assertVisible(false);
 });
 
 add_task(function* dismissWithResults() {
   Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
   Services.prefs.setBoolPref(CHOICE_PREF, false);
   gURLBar.blur();
   gURLBar.focus();
+  yield promiseAutocompleteResultPopup("foo");
   Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
   assertVisible(true);
-  yield promiseAutocompleteResultPopup("foo");
   Assert.ok(gURLBar.popup._matchCount > 0, "popup should have results");
   let disableButton = document.getAnonymousElementByAttribute(
     gURLBar.popup, "anonid", "search-suggestions-notification-disable"
   );
   let transitionPromise = promiseTransition();
   disableButton.click();
   yield transitionPromise;
   Assert.ok(gURLBar.popup.popupOpen, "popup should remain open");
@@ -95,16 +83,17 @@ add_task(function* dismissWithResults() 
   assertVisible(false);
 });
 
 add_task(function* disable() {
   Services.prefs.setBoolPref(SUGGEST_ALL_PREF, true);
   Services.prefs.setBoolPref(CHOICE_PREF, false);
   gURLBar.blur();
   gURLBar.focus();
+  yield promiseAutocompleteResultPopup("foo");
   Assert.ok(gURLBar.popup.popupOpen, "popup should be open");
   assertVisible(true);
   let disableButton = document.getAnonymousElementByAttribute(
     gURLBar.popup, "anonid", "search-suggestions-notification-disable"
   );
   let transitionPromise = promiseTransition();
   disableButton.click();
   yield transitionPromise;
@@ -156,35 +145,16 @@ function assertSuggestionsPresent(expect
 }
 
 function assertVisible(visible) {
   let style =
     window.getComputedStyle(gURLBar.popup.searchSuggestionsNotification);
   Assert.equal(style.visibility, visible ? "visible" : "collapse");
 }
 
-function promiseNewEngine(basename) {
-  return new Promise((resolve, reject) => {
-    info("Waiting for engine to be added: " + basename);
-    let url = getRootDirectory(gTestPath) + basename;
-    Services.search.addEngine(url, Ci.nsISearchEngine.TYPE_MOZSEARCH, "",
-                              false, {
-      onSuccess: function (engine) {
-        info("Search engine added: " + basename);
-        registerCleanupFunction(() => Services.search.removeEngine(engine));
-        resolve(engine);
-      },
-      onError: function (errCode) {
-        Assert.ok(false, "addEngine failed with error code " + errCode);
-        reject();
-      },
-    });
-  });
-}
-
 function promiseTransition() {
   return new Promise(resolve => {
     gURLBar.popup.addEventListener("transitionend", function onEnd() {
       gURLBar.popup.removeEventListener("transitionend", onEnd, true);
       // The urlbar needs to handle the transitionend first, but that happens
       // naturally since promises are resolved at the end of the current tick.
       resolve();
     }, true);
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -753,16 +753,76 @@ function assertWebRTCIndicatorStatus(exp
            item + " global indicator attribute as expected");
       }
 
       ok(!indicator.hasMoreElements(), "only one global indicator window");
     }
   }
 }
 
+/**
+ * Test the state of the identity box and control center to make
+ * sure they are correctly showing the expected mixed content states.
+ *
+ * @param tabbrowser
+ * @param Object states
+ *        MUST include the following properties:
+ *        {
+ *           activeLoaded: true|false,
+ *           activeBlocked: true|false,
+ *           passiveLoaded: true|false,
+ *        }
+ */
+function assertMixedContentBlockingState(tabbrowser, states = {}) {
+  if (!tabbrowser || !("activeLoaded" in states) ||
+      !("activeBlocked" in states) || !("passiveLoaded" in states))  {
+    throw new Error("assertMixedContentBlockingState requires a browser and a states object");
+  }
+
+  let {passiveLoaded,activeLoaded,activeBlocked} = states;
+  let {gIdentityHandler} = tabbrowser.ownerGlobal;
+  let doc = tabbrowser.ownerDocument;
+  let identityBox = gIdentityHandler._identityBox;
+  let classList = identityBox.classList;
+
+  // Make sure the identity box UI has the correct mixedcontent states
+  is(classList.contains("mixedActiveContent"), activeLoaded,
+      "identityBox has expected class for activeLoaded");
+  is(classList.contains("mixedActiveBlocked"), activeBlocked && !passiveLoaded,
+      "identityBox has expected class for activeBlocked && !passiveLoaded");
+  is(classList.contains("mixedDisplayContent"), passiveLoaded && !activeLoaded,
+     "identityBox has expected class for passiveLoaded && activeLoaded");
+  is(classList.contains("mixedDisplayContentLoadedActiveBlocked"), passiveLoaded && activeBlocked,
+     "identityBox has expected class for passiveLoaded && activeBlocked");
+  is (classList.contains("mixedContent"), activeBlocked || activeLoaded || passiveLoaded,
+     "identityBox is showing no mixed content");
+
+  // Make sure the identity popup has the correct mixedcontent states
+  gIdentityHandler._identityBox.click();
+  let popupAttr = doc.getElementById("identity-popup").getAttribute("mixedcontent");
+  let bodyAttr = doc.getElementById("identity-popup-securityView-body").getAttribute("mixedcontent");
+
+  is(popupAttr.contains("active-loaded"), activeLoaded,
+      "identity-popup has expected attr for activeLoaded");
+  is(bodyAttr.contains("active-loaded"), activeLoaded,
+      "securityView-body has expected attr for activeLoaded");
+
+  is(popupAttr.contains("active-blocked"), activeBlocked,
+      "identity-popup has expected attr for activeBlocked");
+  is(bodyAttr.contains("active-blocked"), activeBlocked,
+      "securityView-body has expected attr for activeBlocked");
+
+  is(popupAttr.contains("passive-loaded"), passiveLoaded,
+      "identity-popup has expected attr for passiveLoaded");
+  is(bodyAttr.contains("passive-loaded"), passiveLoaded,
+      "securityView-body has expected attr for passiveLoaded");
+
+  gIdentityHandler._identityPopup.hidden = true;
+}
+
 function makeActionURI(action, params) {
   let url = "moz-action:" + action + "," + JSON.stringify(params);
   return NetUtil.newURI(url);
 }
 
 function is_hidden(element) {
   var style = element.ownerDocument.defaultView.getComputedStyle(element, "");
   if (style.display == "none")
@@ -877,8 +937,27 @@ function promiseTopicObserved(aTopic)
   return new Promise((resolve) => {
     Services.obs.addObserver(
       function PTO_observe(aSubject, aTopic, aData) {
         Services.obs.removeObserver(PTO_observe, aTopic);
         resolve({subject: aSubject, data: aData});
       }, aTopic, false);
   });
 }
+
+function promiseNewSearchEngine(basename) {
+  return new Promise((resolve, reject) => {
+    info("Waiting for engine to be added: " + basename);
+    let url = getRootDirectory(gTestPath) + basename;
+    Services.search.addEngine(url, Ci.nsISearchEngine.TYPE_MOZSEARCH, "",
+                              false, {
+      onSuccess: function (engine) {
+        info("Search engine added: " + basename);
+        registerCleanupFunction(() => Services.search.removeEngine(engine));
+        resolve(engine);
+      },
+      onError: function (errCode) {
+        Assert.ok(false, "addEngine failed with error code " + errCode);
+        reject();
+      },
+    });
+  });
+}
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -763,18 +763,24 @@ file, You can obtain one at http://mozil
               }
             } else {
               val = losslessDecodeURI(uri);
             }
           }
 
           // Trim popup selected values, but never trim results coming from
           // autofill.
+          let styles = new Set(
+            this.popup.selectedIndex == -1 ? [] :
+            this.mController.getStyleAt(this.popup.selectedIndex).split(/\s+/)
+          );
           if (this.popup.selectedIndex == -1 ||
-              this.mController.getStyleAt(this.popup.selectedIndex) == "autofill") {
+              this.mController
+                  .getStyleAt(this.popup.selectedIndex)
+                  .split(/\s+/).indexOf("autofill") >= 0) {
             this._disableTrim = true;
           }
           this.value = val;
           this._disableTrim = false;
 
           // Completing a result should simulate the user typing the result, so
           // fire an input event.
           let evt = document.createEvent("UIEvents");
@@ -918,30 +924,26 @@ file, You can obtain one at http://mozil
           return this.mController.handleDelete();
         ]]></body>
       </method>
 
       <field name="_userMadeSearchSuggestionsChoice"><![CDATA[
         false
       ]]></field>
 
-      <method name="_maybeShowSearchSuggestionsNotification">
-        <body><![CDATA[
-          let showNotification =
-            !this._userMadeSearchSuggestionsChoice &&
-            // When _urlbarFocused is true, tabbrowser would close the popup if
-            // it's opened here, so don't show the notification.
-            !gBrowser.selectedBrowser._urlbarFocused &&
-            Services.prefs.getBoolPref("browser.search.suggest.enabled") &&
-            this._prefs.getBoolPref("unifiedcomplete");
-          if (showNotification) {
-            this.popup.showSearchSuggestionsNotification(this, this);
-          }
-        ]]></body>
-      </method>
+      <property name="shouldShowSearchSuggestionsNotification" readonly="true">
+        <getter><![CDATA[
+          return !this._userMadeSearchSuggestionsChoice &&
+                 // When _urlbarFocused is true, tabbrowser would close the
+                 // popup if it's opened here, so don't show the notification.
+                 !gBrowser.selectedBrowser._urlbarFocused &&
+                 Services.prefs.getBoolPref("browser.search.suggest.enabled") &&
+                 this._prefs.getBoolPref("unifiedcomplete");
+        ]]></getter>
+      </property>
 
     </implementation>
 
     <handlers>
       <handler event="keydown"><![CDATA[
         if ((event.keyCode === KeyEvent.DOM_VK_ALT ||
              event.keyCode === KeyEvent.DOM_VK_SHIFT) &&
             this.popup.selectedIndex >= 0 &&
@@ -963,17 +965,16 @@ file, You can obtain one at http://mozil
             this._clearNoActions();
         }
       ]]></handler>
 
       <handler event="focus"><![CDATA[
         if (event.originalTarget == this.inputField) {
           this._hideURLTooltip();
           this.formatValue();
-          this._maybeShowSearchSuggestionsNotification();
         }
       ]]></handler>
 
       <handler event="blur"><![CDATA[
         if (event.originalTarget == this.inputField) {
           this._clearNoActions();
           this.formatValue();
         }
@@ -1581,17 +1582,23 @@ file, You can obtain one at http://mozil
 
           let newIndex = index + (reverse ? -1 : 1) * amount;
 
           // We only want to wrap if navigation is in any direction by one item,
           // otherwise we clamp to one end of the list.
           // ie, hitting page-down will only cause is to wrap if we're already
           // at one end of the list.
 
-          if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete")) {
+          // Do not allow the selection to be removed if UnifiedComplete is
+          // enabled and the popup's first result is a heuristic result.
+          if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete") ||
+              (this.input.mController.matchCount > 0 &&
+               this.input.mController
+                         .getStyleAt(0)
+                         .split(/\s+/).indexOf("heuristic") == -1)) {
             if (reverse && index == -1 || newIndex > maxRow && index != maxRow)
               newIndex = maxRow;
             else if (!reverse && index == -1 || newIndex < 0 && index != 0)
               newIndex = 0;
 
             if (newIndex < 0 && index == 0 || newIndex > maxRow && index == maxRow)
               newIndex = -1;
 
@@ -1626,37 +1633,34 @@ file, You can obtain one at http://mozil
         <parameter name="aInput"/>
         <parameter name="aElement"/>
         <body>
           <![CDATA[
           // initially the panel is hidden
           // to avoid impacting startup / new window performance
           aInput.popup.hidden = false;
 
-          // The popup may already be open if it's showing the search
-          // suggestions notification.  In that case, its footer visibility
-          // needs to be updated.
-          if (this.popupOpen) {
-            this._updateFooterVisibility();
+          if (aInput.shouldShowSearchSuggestionsNotification) {
+            this._showSearchSuggestionsNotification();
           }
 
           this._openAutocompletePopup(aInput, aElement);
           ]]>
         </body>
       </method>
 
       <method name="_updateFooterVisibility">
         <body>
           <![CDATA[
           this.footer.collapsed = this._matchCount == 0;
           ]]>
         </body>
       </method>
 
-      <method name="showSearchSuggestionsNotification">
+      <method name="_showSearchSuggestionsNotification">
         <parameter name="aInput"/>
         <parameter name="aElement"/>
         <body>
           <![CDATA[
           // Set the learn-more link href.
           let link = this.searchSuggestionsNotificationLearnMoreLink;
           if (!link.hasAttribute("href")) {
             let url = Services.urlFormatter.formatURL(
@@ -1674,17 +1678,16 @@ file, You can obtain one at http://mozil
           // But without flexing the listbox, the listbox's height animation
           // sometimes fails to complete, leaving the popup too tall.  Work
           // around that problem by disabling the listbox animation.
           this.richlistbox.flex = 0;
           this.setAttribute("dontanimate", "true");
 
           this.classList.add("showSearchSuggestionsNotification");
           this._updateFooterVisibility();
-          this.openAutocompletePopup(aInput, aElement);
           ]]>
         </body>
       </method>
 
       <method name="_hideSearchSuggestionsNotification">
         <parameter name="animate"/>
         <body>
           <![CDATA[
@@ -1785,47 +1788,69 @@ file, You can obtain one at http://mozil
             // respect the usual clicking subtleties
             openUILink(url, aEvent, options);
           }
         ]]>
         </body>
       </method>
 
       <method name="createResultLabel">
-        <parameter name="aTitle"/>
-        <parameter name="aUrl"/>
-        <parameter name="aType"/>
+        <parameter name="item"/>
+        <parameter name="proposedLabel"/>
         <body>
           <![CDATA[
-            let label = aTitle + " " + aUrl;
-            // convert aType (ex: "ac-result-type-<aType>") to text to be spoke aloud
-            // by screen readers.  convert "tag" and "bookmark" to the localized versions,
-            // but don't do anything for "favicon" (the default)
+            let parts = [proposedLabel];
+
+            let action = this.mInput._parseActionUrl(item.getAttribute("url"));
+            if (action) {
+              switch (action.type) {
+              case "searchengine":
+                parts = [
+                  action.params.searchSuggestion || action.params.searchQuery,
+                  action.params.engineName,
+                ];
+                break;
+              case "switchtab":
+                parts = [
+                  item.getAttribute("title"),
+                  action.params.url,
+                ];
+                break;
+              }
+            }
+
+            let types = item.getAttribute("type").split(/\s+/);
+            let type = types.find(type => type != "action" && type != "heuristic");
             try {
-              label += " " + this._bundle.GetStringFromName(aType + "ResultLabel");
-            } catch (e) {
-              // Undefined result label, do nothing.
-            }
-
-            return label;
+              // Some types intentionally do not map to strings, which is not
+              // an error.
+              parts.push(this._bundle.GetStringFromName(type + "ResultLabel"));
+            } catch (e) {}
+
+            return parts.filter(str => str).join(" ");
           ]]>
         </body>
       </method>
 
       <method name="onResultsAdded">
         <body>
           <![CDATA[
             if (!Services.prefs.getBoolPref("browser.urlbar.unifiedcomplete"))
               return;
 
+            // If nothing is selected yet, select the first result if it is a
+            // pre-selected "heuristic" result.  (See UnifiedComplete.js.)
             if (this._matchCount > 0 && this.selectedIndex == -1) {
-              // Don't handle this as a user-initiated action.
-              this._ignoreNextSelect = true;
-              this.selectedIndex = 0;
-              this._ignoreNextSelect = false;
+              let styles = this.input.mController.getStyleAt(0).split(/\s+/);
+              if (styles.indexOf("heuristic") >= 0) {
+                // Don't handle this as a user-initiated action.
+                this._ignoreNextSelect = true;
+                this.selectedIndex = 0;
+                this._ignoreNextSelect = false;
+              }
             }
 
             this.input.gotResultForCurrentQuery = true;
             if (this.input.handleEnterWhenGotResult) {
               this.input.handleEnterWhenGotResult = false;
               this.input.mController.handleEnter(false);
             }
           ]]>
@@ -2382,269 +2407,16 @@ file, You can obtain one at http://mozil
         <setter><!-- This should be used only in automated tests -->
           document.getAnonymousElementByAttribute(this, "anonid",
                     "center-item-menulist").value = val;
         </setter>
       </property>
     </implementation>
   </binding>
 
-  <binding id="bad-content-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
-    <content>
-      <xul:hbox align="start">
-        <xul:image class="popup-notification-icon" xbl:inherits="popupid,mixedblockdisabled,trackingblockdisabled"/>
-        <xul:vbox>
-          <!-- header -->
-          <xul:vbox>
-            <xul:description anonid="badContentBlocked.title"
-              class="popup-notification-item-title" xbl:inherits="popupid">
-            </xul:description>
-            <xul:description class="popup-notification-item-message"
-              xbl:inherits="popupid">
-              &badContentBlocked.moreinfo;
-            </xul:description>
-          </xul:vbox>
-          <!-- mixed content -->
-          <xul:vbox anonid="mixedContent" hidden="true">
-            <xul:separator class="groove"/>
-            <xul:hbox align="start">
-              <xul:vbox>
-                <xul:description class="popup-notification-item-title"
-                  xbl:inherits="popupid">
-                  &mixedContentBlocked2.message;
-                </xul:description>
-                <xul:description class="popup-notification-item-message"
-                  xbl:inherits="popupid,mixedblockdisabled">
-                  &mixedContentBlocked2.moreinfo;
-                </xul:description>
-                <xul:label anonid="mixedContent.helplink"
-                  class="text-link" href=""
-                  value="&mixedContentBlocked2.learnMore;"/>
-              </xul:vbox>
-              <xul:button
-                type="menu" label="&mixedContentBlocked2.options;"
-                sizetopopup="none">
-                <xul:menupopup>
-                  <xul:menuitem anonid="mixedContentAction.unblock"
-                    hidden="true" label="&mixedContentBlocked2.unblock.label;"
-                    accesskey="&mixedContentBlocked2.unblock.accesskey;"
-                    oncommand="document.getBindingParent(this).disableMixedContentProtection();"/>
-                  <xul:menuitem anonid="mixedContentAction.block"
-                    hidden="true" label="&mixedContentBlocked2.block.label;"
-                    accesskey="&mixedContentBlocked2.block.accesskey;"
-                    oncommand="document.getBindingParent(this).enableMixedContentProtection();"/>
-                </xul:menupopup>
-              </xul:button>
-            </xul:hbox>
-            <xul:hbox class="popup-notification-footer" xbl:inherits="popupid,mixedblockdisabled">
-              <xul:description class="popup-notification-item-message popup-notification-item-message-critical" xbl:inherits="popupid">
-                  &mixedContentBlocked2.disabled.message;
-              </xul:description>
-            </xul:hbox>
-          </xul:vbox>
-          <!-- tracking content -->
-          <xul:vbox anonid="trackingContent" hidden="true">
-            <xul:separator class="groove"/>
-            <xul:hbox align="start">
-              <xul:vbox>
-                <xul:description class="popup-notification-item-title"
-                  xbl:inherits="popupid">
-                  &trackingContentBlocked.message;
-                </xul:description>
-                <xul:description class="popup-notification-item-message"
-                  xbl:inherits="popupid,trackingblockdisabled">
-                  &trackingContentBlocked.moreinfo;
-                </xul:description>
-                <xul:label anonid="trackingContent.helplink"
-                  class="text-link" href=""
-                  value="&trackingContentBlocked.learnMore;"/>
-              </xul:vbox>
-              <xul:button
-                type="menu" label="&trackingContentBlocked.options;"
-                sizetopopup="none">
-                <xul:menupopup>
-                  <xul:menuitem anonid="trackingContentAction.unblock"
-                    hidden="true" label="&trackingContentBlocked.unblock2.label;"
-                    accesskey="&trackingContentBlocked.unblock2.accesskey;"
-                    oncommand="document.getBindingParent(this).disableTrackingContentProtection();"/>
-                  <xul:menuitem anonid="trackingContentAction.block"
-                    hidden="true" label="&trackingContentBlocked.block.label;"
-                    accesskey="&trackingContentBlocked.block.accesskey;"
-                    oncommand="document.getBindingParent(this).enableTrackingContentProtection();"/>
-                </xul:menupopup>
-              </xul:button>
-            </xul:hbox>
-            <xul:hbox class="popup-notification-footer" xbl:inherits="popupid,trackingblockdisabled">
-              <xul:description class="popup-notification-item-message popup-notification-item-message-critical" xbl:inherits="popupid">
-                &trackingContentBlocked.disabled.message;
-                </xul:description>
-            </xul:hbox>
-          </xul:vbox>
-        </xul:vbox>
-        <xul:vbox pack="start">
-          <xul:toolbarbutton anonid="closebutton"
-                             class="messageCloseButton popup-notification-closebutton tabbable close-icon"
-                             xbl:inherits="oncommand=closebuttoncommand"
-                             tooltiptext="&closeNotification.tooltip;"/>
-        </xul:vbox>
-      </xul:hbox>
-    </content>
-    <resources>
-      <stylesheet src="chrome://global/skin/notification.css"/>
-    </resources>
-    <implementation>
-      <field name="_brandShortName">
-        document.getElementById("bundle_brand").getString("brandShortName")
-      </field>
-      <field name="_doorhangerTitle">
-        document.getAnonymousElementByAttribute(this, "anonid",
-          "badContentBlocked.title")
-      </field>
-      <field name="_mixedContent">
-        document.getAnonymousElementByAttribute(this, "anonid",
-            "mixedContent")
-      </field>
-      <field name="_mixedContentUnblock">
-        document.getAnonymousElementByAttribute(this, "anonid",
-          "mixedContentAction.unblock")
-      </field>
-      <field name="_mixedContentBlock">
-        document.getAnonymousElementByAttribute(this, "anonid",
-          "mixedContentAction.block");
-      </field>
-      <field name="_mixedContentHelpLink">
-        document.getAnonymousElementByAttribute(this, "anonid",
-          "mixedContent.helplink")
-      </field>
-      <property name="isMixedContentBlocked" readonly="true">
-        <getter><![CDATA[
-          return this.notification.options.state &
-            Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT;
-        ]]></getter>
-      </property>
-      <field name="_trackingContent">
-        document.getAnonymousElementByAttribute(this, "anonid",
-          "trackingContent")
-      </field>
-      <field name="_trackingContentUnblock">
-        document.getAnonymousElementByAttribute(this, "anonid",
-          "trackingContentAction.unblock")
-      </field>
-      <field name="_trackingContentBlock">
-        document.getAnonymousElementByAttribute(this, "anonid",
-          "trackingContentAction.block");
-      </field>
-      <field name="_trackingContentHelpLink">
-        document.getAnonymousElementByAttribute(this, "anonid",
-          "trackingContent.helplink")
-      </field>
-      <property name="isTrackingContentBlocked" readonly="true">
-        <getter><![CDATA[
-          return !!(this.notification.options.state &
-            Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT);
-        ]]></getter>
-      </property>
-      <constructor><![CDATA[
-        // default title
-        _doorhangerTitle.value =
-          gNavigatorBundle.getFormattedString(
-            "badContentBlocked.notblocked.message", [this._brandShortName]);
-        if (this.notification.options.state &
-            Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT) {
-          _doorhangerTitle.value =
-            gNavigatorBundle.getFormattedString(
-              "badContentBlocked.blocked.message", [this._brandShortName]);
-          _mixedContent.hidden = false;
-          _mixedContentUnblock.hidden = false;
-          _mixedContentHelpLink.href =
-            Services.urlFormatter.formatURLPref("app.support.baseURL")
-              + "mixed-content";
-        }
-        if (this.notification.options.state &
-            Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT) {
-          this.setAttribute("mixedblockdisabled", true);
-          _mixedContent.hidden = false;
-          _mixedContentBlock.hidden = false;
-          _mixedContentHelpLink.href =
-            Services.urlFormatter.formatURLPref("app.support.baseURL")
-              + "mixed-content";
-        }
-        if (this.notification.options.state &
-            Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT) {
-          _doorhangerTitle.value =
-            gNavigatorBundle.getFormattedString(
-              "badContentBlocked.blocked.message", [this._brandShortName]);
-          _trackingContent.hidden = false;
-          _trackingContentUnblock.hidden = false;
-          _trackingContentHelpLink.href =
-            Services.urlFormatter.formatURLPref("app.support.baseURL")
-              + "tracking-protection";
-        }
-        if (this.notification.options.state &
-            Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT) {
-          this.setAttribute("trackingblockdisabled", true);
-          _trackingContent.hidden = false;
-          _trackingContentBlock.hidden = false;
-          _trackingContentHelpLink.href =
-            Services.urlFormatter.formatURLPref("app.support.baseURL")
-              + "tracking-protection";
-        }
-      ]]></constructor>
-      <method name="disableMixedContentProtection">
-        <body><![CDATA[
-          // Use telemetry to measure how often unblocking happens
-          const kMIXED_CONTENT_UNBLOCK_EVENT = 2;
-          let histogram =
-            Services.telemetry.getHistogramById(
-              "MIXED_CONTENT_UNBLOCK_COUNTER");
-          histogram.add(kMIXED_CONTENT_UNBLOCK_EVENT);
-          // Reload the page with the content unblocked
-          BrowserReloadWithFlags(
-            nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT);
-        ]]></body>
-      </method>
-      <method name="enableMixedContentProtection">
-        <body><![CDATA[
-          gBrowser.selectedBrowser.messageManager.sendAsyncMessage(
-            "MixedContent:ReenableProtection", {});
-          BrowserReload();
-        ]]></body>
-      </method>
-      <method name="disableTrackingContentProtection">
-        <body><![CDATA[
-          // convert document URI into the format used by
-          // nsChannelClassifier::ShouldEnableTrackingProtection
-          // (any scheme turned into https is correct)
-          let normalizedUrl = Services.io.newURI(
-            "https://" + gBrowser.selectedBrowser.currentURI.hostPort,
-            null, null);
-          // Add the current host/port combination in the 'trackingprotection' consumer of
-          // the permission manager using a normalized URI. This effectively
-          // places this host/port combination on the tracking protection allowlist.
-          Services.perms.add(normalizedUrl,
-            "trackingprotection", Services.perms.ALLOW_ACTION);
-          BrowserReload();
-        ]]></body>
-      </method>
-      <method name="enableTrackingContentProtection">
-        <body><![CDATA[
-          // Remove the current host/port combination from the 'trackingprotection' consumer
-          // of the permission manager. This effectively removes this host/port combination
-          // from the tracking protection allowlist.
-          let normalizedUrl = Services.io.newURI(
-            "https://" + gBrowser.selectedBrowser.currentURI.hostPort,
-            null, null);
-          Services.perms.remove(normalizedUrl,
-            "trackingprotection");
-          BrowserReload();
-        ]]></body>
-      </method>
-    </implementation>
-  </binding>
-
   <binding id="click-to-play-plugins-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
     <content align="start" style="width: &pluginNotification.width;;">
       <xul:vbox flex="1" align="stretch" class="popup-notification-main-box"
                 xbl:inherits="popupid">
         <xul:hbox class="click-to-play-plugins-notification-description-box" flex="1" align="start">
           <xul:description class="click-to-play-plugins-outer-description" flex="1">
             <html:span anonid="click-to-play-plugins-notification-description" />
             <xul:label class="text-link click-to-play-plugins-notification-link" anonid="click-to-play-plugins-notification-link" />
--- a/browser/components/downloads/DownloadsCommon.jsm
+++ b/browser/components/downloads/DownloadsCommon.jsm
@@ -223,17 +223,17 @@ this.DownloadsCommon = {
   /**
    * Get access to one of the DownloadsData or PrivateDownloadsData objects,
    * depending on the privacy status of the window in question.
    *
    * @param aWindow
    *        The browser window which owns the download button.
    */
   getData(aWindow) {
-    if (PrivateBrowsingUtils.isWindowPrivate(aWindow)) {
+    if (PrivateBrowsingUtils.isContentWindowPrivate(aWindow)) {
       return PrivateDownloadsData;
     } else {
       return DownloadsData;
     }
   },
 
   /**
    * Initializes the Downloads back-end and starts receiving events for both the
@@ -245,17 +245,17 @@ this.DownloadsCommon = {
   },
 
   /**
    * Get access to one of the DownloadsIndicatorData or
    * PrivateDownloadsIndicatorData objects, depending on the privacy status of
    * the window in question.
    */
   getIndicatorData(aWindow) {
-    if (PrivateBrowsingUtils.isWindowPrivate(aWindow)) {
+    if (PrivateBrowsingUtils.isContentWindowPrivate(aWindow)) {
       return PrivateDownloadsIndicatorData;
     } else {
       return DownloadsIndicatorData;
     }
   },
 
   /**
    * Returns a reference to the DownloadsSummaryData singleton - creating one
@@ -263,17 +263,17 @@ this.DownloadsCommon = {
    *
    * @param aWindow
    *        The browser window which owns the download button.
    * @param aNumToExclude
    *        The number of items on the top of the downloads list to exclude
    *        from the summary.
    */
   getSummary(aWindow, aNumToExclude) {
-    if (PrivateBrowsingUtils.isWindowPrivate(aWindow)) {
+    if (PrivateBrowsingUtils.isContentWindowPrivate(aWindow)) {
       if (this._privateSummary) {
         return this._privateSummary;
       }
       return this._privateSummary = new DownloadsSummaryData(true, aNumToExclude);
     } else {
       if (this._summary) {
         return this._summary;
       }
--- a/browser/components/downloads/content/contentAreaDownloadsView.js
+++ b/browser/components/downloads/content/contentAreaDownloadsView.js
@@ -3,13 +3,13 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 let ContentAreaDownloadsView = {
   init() {
     let view = new DownloadsPlacesView(document.getElementById("downloadsRichListBox"));
     // Do not display the Places downloads in private windows
-    if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
+    if (!PrivateBrowsingUtils.isContentWindowPrivate(window)) {
       view.place = "place:transition=7&sort=4";
     }
   },
 };
--- a/browser/components/migration/ChromeProfileMigrator.js
+++ b/browser/components/migration/ChromeProfileMigrator.js
@@ -179,16 +179,23 @@ Object.defineProperty(ChromeProfileMigra
       catch(e) {
         Cu.reportError("Error parsing Chrome's preferences file: " + e);
       }
     }
     return "";
   }
 });
 
+Object.defineProperty(ChromeProfileMigrator.prototype, "sourceLocked", {
+  get: function Chrome_sourceLocked() {
+    // There is an exclusive lock on some SQLite databases. Assume they are locked for now.
+    return true;
+  },
+});
+
 function GetBookmarksResource(aProfileFolder) {
   let bookmarksFile = aProfileFolder.clone();
   bookmarksFile.append("Bookmarks");
   if (!bookmarksFile.exists())
     return null;
 
   return {
     type: MigrationUtils.resourceTypes.BOOKMARKS,
--- a/browser/components/migration/MigrationUtils.jsm
+++ b/browser/components/migration/MigrationUtils.jsm
@@ -163,16 +163,22 @@ this.MigratorPrototype = {
 
   /**
    * OVERRIDE IF AND ONLY IF your migrator supports importing the homepage.
    * @see nsIBrowserProfileMigrator
    */
   get sourceHomePageURL() "",
 
   /**
+   * Override if the data to migrate is locked/in-use and the user should
+   * probably shutdown the source browser.
+   */
+  get sourceLocked() false,
+
+  /**
    * DO NOT OVERRIDE - After deCOMing migration, the UI will just call
    * getResources.
    *
    * @see nsIBrowserProfileMigrator
    */
   getMigrateData: function MP_getMigrateData(aProfile) {
     let types = [r.type for each (r in this._getMaybeCachedResources(aProfile))];
     return types.reduce(function(a, b) a |= b, 0);
--- a/browser/components/migration/content/migration.js
+++ b/browser/components/migration/content/migration.js
@@ -59,16 +59,25 @@ var MigrationWizard = {
     os.removeObserver(this, "Migration:ItemError");
     os.removeObserver(this, "Migration:Ended");
     MigrationUtils.finishMigration();
   },
 
   // 1 - Import Source
   onImportSourcePageShow: function ()
   {
+    // Show warning message to close the selected browser when needed
+    function toggleCloseBrowserWarning() {
+      let visibility = "hidden";
+      if (group.selectedItem.id != "nothing") {
+        let migrator = MigrationUtils.getMigrator(group.selectedItem.id);
+        visibility = migrator.sourceLocked ? "visible" : "hidden";
+      }
+      document.getElementById("closeSourceBrowser").style.visibility = visibility;
+    }
     this._wiz.canRewind = false;
 
     var selectedMigrator = null;
 
     // Figure out what source apps are are available to import from:
     var group = document.getElementById("importSourceGroup");
     for (var i = 0; i < group.childNodes.length; ++i) {
       var migratorKey = group.childNodes[i].id;
@@ -81,19 +90,22 @@ var MigrationWizard = {
             selectedMigrator = group.childNodes[i];
         } else {
           // Hide this option
           group.childNodes[i].hidden = true;
         }
       }
     }
 
-    if (selectedMigrator)
+    group.addEventListener("command", toggleCloseBrowserWarning);
+
+    if (selectedMigrator) {
       group.selectedItem = selectedMigrator;
-    else {
+      toggleCloseBrowserWarning();
+    } else {
       // We didn't find a migrator, notify the user
       document.getElementById("noSources").hidden = false;
 
       this._wiz.canAdvance = false;
 
       document.getElementById("importBookmarks").hidden = true;
       document.getElementById("importAll").hidden = true;
     }
--- a/browser/components/migration/content/migration.xul
+++ b/browser/components/migration/content/migration.xul
@@ -47,16 +47,18 @@
       <radio id="canary"    label="&importFromCanary.label;"    accesskey="&importFromCanary.accesskey;"/>
 #elifdef XP_UNIX
       <radio id="chrome"    label="&importFromChrome.label;"    accesskey="&importFromChrome.accesskey;"/>
       <radio id="chromium"  label="&importFromChromium.label;"  accesskey="&importFromChromium.accesskey;"/>
 #endif
       <radio id="nothing"   label="&importFromNothing.label;"   accesskey="&importFromNothing.accesskey;" hidden="true"/>
     </radiogroup>
     <label id="noSources" hidden="true">&noMigrationSources.label;</label>
+    <spacer flex="1"/>
+    <description class="header" id="closeSourceBrowser" style="visibility:hidden">&closeSourceBrowser.label;</description>
   </wizardpage>
 
   <wizardpage id="selectProfile" pageid="selectProfile" label="&selectProfile.title;"
               next="importItems"
               onpageshow="return MigrationWizard.onSelectProfilePageShow();"
               onpagerewound="return MigrationWizard.onSelectProfilePageRewound();"
               onpageadvanced="return MigrationWizard.onSelectProfilePageAdvanced();">
     <description control="profiles">&selectProfile.label;</description>
--- a/browser/components/migration/nsIBrowserProfileMigrator.idl
+++ b/browser/components/migration/nsIBrowserProfileMigrator.idl
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIArray;
 interface nsIProfileStartup;
 
-[scriptable, uuid(30e5a7ec-f71e-4f41-9dbd-7429c02132ec)]
+[scriptable, uuid(22b56ffc-3149-43c5-b5a9-b3a6b678de93)]
 interface nsIBrowserProfileMigrator : nsISupports
 {
   /**
    * profile items to migrate. use with migrate().
    */
   const unsigned short ALL         = 0x0000;
   const unsigned short SETTINGS    = 0x0001;
   const unsigned short COOKIES     = 0x0002;
@@ -38,27 +38,34 @@ interface nsIBrowserProfileMigrator : ns
    * @param   aProfile the profile that we are looking for available data
    *          to import
    * @param   aDoingStartup "true" if the profile is not currently being used.
    * @return  bit field containing profile items (see above)
    * @note    a return value of 0 represents no items rather than ALL.
    */
   unsigned short getMigrateData(in jsval aProfile, in boolean aDoingStartup);
 
-  /** 
-   * Whether or not there is any data that can be imported from this 
+  /**
+   * Whether or not there is any data that can be imported from this
    * browser (i.e. whether or not it is installed, and there exists
    * a user profile)
    */
   readonly attribute boolean          sourceExists;
 
 
-  /** 
-   * An enumeration of available profiles. If the import source does 
+  /**
+   * An enumeration of available profiles. If the import source does
    * not support profiles, this attribute is null.
    */
   readonly attribute jsval            sourceProfiles;
 
   /**
    * The import source homepage.  Returns null if not present/available
    */
   readonly attribute AUTF8String      sourceHomePageURL;
+
+
+  /**
+   * Whether the source browser data is locked/in-use meaning migration likely
+   * won't succeed and the user should be warned.
+   */
+  readonly attribute boolean          sourceLocked;
 };
--- a/browser/components/preferences/privacy.xul
+++ b/browser/components/preferences/privacy.xul
@@ -94,17 +94,17 @@
       <caption label="&tracking.label;"/>
       <vbox id="trackingprotectionbox" hidden="true">
         <hbox align="center">
           <checkbox id="trackingProtection"
                     preference="privacy.trackingprotection.enabled"
                     accesskey="&trackingProtection5.accesskey;"
                     label="&trackingProtection5.label;" />
           <image id="trackingProtectionImage"
-                 src="chrome://browser/skin/bad-content-blocked-16.png"/>
+                 src="chrome://browser/skin/tracking-protection-16.svg"/>
         </hbox>
         <hbox align="center"
               class="indent">
           <label id="trackingProtectionLearnMore"
                  class="text-link"
                  value="&trackingProtectionLearnMore.label;"/>
         </hbox>
       </vbox>
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
@@ -64,18 +64,17 @@
           <span id="tpEnabled"
                 style="width: &trackingProtection.state.width;"
                 class="showTpEnabled">&trackingProtection.state.enabled;</span>
           <span id="tpDisabled"
                 style="width: &trackingProtection.state.width;"
                 class="showTpDisabled">&trackingProtection.state.disabled;</span>
         </div>
         <p id="tpDiagram"/>
-        <p class="showTpEnabled">&trackingProtection.description.enabled;</p>
-        <p class="showTpDisabled">&trackingProtection.description.disabled;</p>
+        <p>&trackingProtection.description;</p>
         <!-- Use text links to implement plain styled buttons without an href. -->
         <label xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
                id="disableTrackingProtection"
                class="text-link showTpEnabled"
                value="&trackingProtection.disable;"/>
         <label xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
                id="enableTrackingProtection"
                class="text-link showTpDisabled"
--- a/browser/devtools/performance/modules/logic/frame-utils.js
+++ b/browser/devtools/performance/modules/logic/frame-utils.js
@@ -237,49 +237,46 @@ function getInflatedFrameCache(frameTabl
 
 /**
  * Get or add an inflated frame to a cache.
  *
  * @param object cache
  * @param number index
  * @param object frameTable
  * @param object stringTable
- * @param object allocationsTable
  */
-function getOrAddInflatedFrame(cache, index, frameTable, stringTable, allocationsTable) {
+function getOrAddInflatedFrame(cache, index, frameTable, stringTable) {
   let inflatedFrame = cache[index];
   if (inflatedFrame === null) {
-    inflatedFrame = cache[index] = new InflatedFrame(index, frameTable, stringTable, allocationsTable);
+    inflatedFrame = cache[index] = new InflatedFrame(index, frameTable, stringTable);
   }
   return inflatedFrame;
 };
 
 /**
  * An intermediate data structured used to hold inflated frames.
  *
  * @param number index
  * @param object frameTable
  * @param object stringTable
- * @param object allocationsTable
  */
-function InflatedFrame(index, frameTable, stringTable, allocationsTable) {
+function InflatedFrame(index, frameTable, stringTable) {
   const LOCATION_SLOT = frameTable.schema.location;
   const IMPLEMENTATION_SLOT = frameTable.schema.implementation;
   const OPTIMIZATIONS_SLOT = frameTable.schema.optimizations;
   const LINE_SLOT = frameTable.schema.line;
   const CATEGORY_SLOT = frameTable.schema.category;
 
   let frame = frameTable.data[index];
   let category = frame[CATEGORY_SLOT];
   this.location = stringTable[frame[LOCATION_SLOT]];
   this.implementation = frame[IMPLEMENTATION_SLOT];
   this.optimizations = frame[OPTIMIZATIONS_SLOT];
   this.line = frame[LINE_SLOT];
   this.column = undefined;
-  this.allocations = allocationsTable ? allocationsTable[index] : 0;
   this.category = category;
   this.isContent = false;
 
   // Attempt to compute if this frame is a content frame, and if not,
   // its category.
   //
   // Since only C++ stack frames have associated category information,
   // attempt to generate a useful category, fallback to the one provided
@@ -500,20 +497,20 @@ function getFrameInfo (node, options) {
 
     data.selfDuration = node.youngestFrameSamples / totalSamples * totalDuration;
     data.selfPercentage = node.youngestFrameSamples / totalSamples * 100;
     data.totalDuration = node.samples / totalSamples * totalDuration;
     data.totalPercentage = node.samples / totalSamples * 100;
     data.COSTS_CALCULATED = true;
   }
 
-  if (options && options.allocations && !data.ALLOCATIONS_CALCULATED) {
-    data.totalAllocations = node.allocations + node.calls.reduce((acc, node) => acc + node.allocations, 0);
-    data.selfAllocations = node.allocations;
-    data.ALLOCATIONS_CALCULATED = true;
+  if (options && options.allocations && !data.ALLOCATION_DATA_CALCULATED) {
+    data.selfCount = node.youngestFrameSamples;
+    data.totalCount = node.samples;
+    data.ALLOCATION_DATA_CALCULATED = true;
   }
 
   return data;
 }
 
 exports.getFrameInfo = getFrameInfo;
 exports.computeIsContentAndCategory = computeIsContentAndCategory;
 exports.parseLocation = parseLocation;
--- a/browser/devtools/performance/modules/logic/tree-model.js
+++ b/browser/devtools/performance/modules/logic/tree-model.js
@@ -32,24 +32,24 @@ function ThreadNode(thread, options = {}
   }
   this.samples = 0;
   this.sampleTimes = [];
   this.youngestFrameSamples = 0;
   this.calls = [];
   this.duration = options.endTime - options.startTime;
   this.nodeType = "Thread";
 
-  let { samples, stackTable, frameTable, stringTable, allocationsTable } = thread;
+  let { samples, stackTable, frameTable, stringTable } = thread;
 
   // Nothing to do if there are no samples.
   if (samples.data.length === 0) {
     return;
   }
 
-  this._buildInverted(samples, stackTable, frameTable, stringTable, allocationsTable, options);
+  this._buildInverted(samples, stackTable, frameTable, stringTable, options);
   if (!options.invertTree) {
     this._uninvert();
   }
 }
 
 ThreadNode.prototype = {
   /**
    * Build an inverted call tree from profile samples. The format of the
@@ -62,27 +62,24 @@ ThreadNode.prototype = {
    * @param object samples
    *        The raw samples array received from the backend.
    * @param object stackTable
    *        The table of deduplicated stacks from the backend.
    * @param object frameTable
    *        The table of deduplicated frames from the backend.
    * @param object stringTable
    *        The table of deduplicated strings from the backend.
-   * @param object allocationsTable
-   *        The table of allocation counts from the backend. Indexed by frame
-   *        index.
    * @param object options
    *        Additional supported options
    *          - number startTime
    *          - number endTime
    *          - boolean contentOnly [optional]
    *          - boolean invertTree [optional]
    */
-  _buildInverted: function buildInverted(samples, stackTable, frameTable, stringTable, allocationsTable, options) {
+  _buildInverted: function buildInverted(samples, stackTable, frameTable, stringTable, options) {
     function getOrAddFrameNode(calls, isLeaf, frameKey, inflatedFrame, isMetaCategory, leafTable) {
       // Insert the inflated frame into the call tree at the current level.
       let frameNode;
 
       // Leaf nodes have fan out much greater than non-leaf nodes, thus the
       // use of a hash table. Otherwise, do linear search.
       //
       // Note that this method is very hot, thus the manual looping over
@@ -198,17 +195,17 @@ ThreadNode.prototype = {
         // will make it clear to differentiate (root)->B vs (root)->A->B
         // when a tree is inverted, a revert of bug 1147604
         if (stackIndex === null && skipRoot) {
           break;
         }
 
         // Inflate the frame.
         let inflatedFrame = getOrAddInflatedFrame(inflatedFrameCache, frameIndex, frameTable,
-                                                  stringTable, allocationsTable);
+                                                  stringTable);
 
         // Compute the frame key.
         mutableFrameKeyOptions.isRoot = stackIndex === null;
         let frameKey = inflatedFrame.getFrameKey(mutableFrameKeyOptions);
 
         // An empty frame key means this frame should be skipped.
         if (frameKey === "") {
           continue;
@@ -377,21 +374,20 @@ ThreadNode.prototype = {
  * @param number allocations
  *        The number of memory allocations performed in this frame.
  * @param number isContent
  *        Whether this frame is content.
  * @param boolean isMetaCategory
  *        Whether or not this is a platform node that should appear as a
  *        generalized meta category or not.
  */
-function FrameNode(frameKey, { location, line, category, allocations, isContent }, isMetaCategory) {
+function FrameNode(frameKey, { location, line, category, isContent }, isMetaCategory) {
   this.key = frameKey;
   this.location = location;
   this.line = line;
-  this.allocations = allocations;
   this.youngestFrameSamples = 0;
   this.samples = 0;
   this.calls = [];
   this.isContent = !!isContent;
   this._optimizations = null;
   this._tierData = null;
   this._stringTable = null;
   this.isMetaCategory = !!isMetaCategory;
--- a/browser/devtools/performance/modules/widgets/tree-view.js
+++ b/browser/devtools/performance/modules/widgets/tree-view.js
@@ -32,20 +32,20 @@ const DEFAULT_SORTING_PREDICATE = (frame
   }
   return dataA.totalPercentage < dataB.totalPercentage ? 1 : -1;
 };
 
 const DEFAULT_AUTO_EXPAND_DEPTH = 3; // depth
 const DEFAULT_VISIBLE_CELLS = {
   duration: true,
   percentage: true,
-  allocations: false,
+  count: false,
   selfDuration: true,
   selfPercentage: true,
-  selfAllocations: false,
+  selfCount: false,
   samples: true,
   function: true
 };
 
 const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
 const sum = vals => vals.reduce((a, b) => a + b, 0);
 
 /**
@@ -129,74 +129,55 @@ CallView.prototype = Heritage.extend(Abs
   /**
    * Creates the view for this tree node.
    * @param nsIDOMNode document
    * @param nsIDOMNode arrowNode
    * @return nsIDOMNode
    */
   _displaySelf: function(document, arrowNode) {
     let frameInfo = this.getDisplayedData();
+    let cells = [];
 
     if (this.visibleCells.duration) {
-      var durationCell = this._createTimeCell(document, frameInfo.totalDuration);
+      cells.push(this._createTimeCell(document, frameInfo.totalDuration));
+    }
+    if (this.visibleCells.percentage) {
+      cells.push(this._createExecutionCell(document, frameInfo.totalPercentage));
+    }
+    if (this.visibleCells.count) {
+      cells.push(this._createCountCell(document, frameInfo.totalCount));
     }
     if (this.visibleCells.selfDuration) {
-      var selfDurationCell = this._createTimeCell(document, frameInfo.selfDuration, true);
-    }
-    if (this.visibleCells.percentage) {
-      var percentageCell = this._createExecutionCell(document, frameInfo.totalPercentage);
+      cells.push(this._createTimeCell(document, frameInfo.selfDuration, true));
     }
     if (this.visibleCells.selfPercentage) {
-      var selfPercentageCell = this._createExecutionCell(document, frameInfo.selfPercentage, true);
+      cells.push(this._createExecutionCell(document, frameInfo.selfPercentage, true));
     }
-    if (this.visibleCells.allocations) {
-      var allocationsCell = this._createAllocationsCell(document, frameInfo.totalAllocations);
-    }
-    if (this.visibleCells.selfAllocations) {
-      var selfAllocationsCell = this._createAllocationsCell(document, frameInfo.selfAllocations, true);
+    if (this.visibleCells.selfCount) {
+      cells.push(this._createCountCell(document, frameInfo.selfCount, true));
     }
     if (this.visibleCells.samples) {
-      var samplesCell = this._createSamplesCell(document, frameInfo.samples);
+      cells.push(this._createSamplesCell(document, frameInfo.samples));
     }
     if (this.visibleCells.function) {
-      var functionCell = this._createFunctionCell(document, arrowNode, frameInfo.name, frameInfo, this.level);
+      cells.push(this._createFunctionCell(document, arrowNode, frameInfo.name, frameInfo, this.level));
     }
 
     let targetNode = document.createElement("hbox");
     targetNode.className = "call-tree-item";
     targetNode.setAttribute("origin", frameInfo.isContent ? "content" : "chrome");
     targetNode.setAttribute("category", frameInfo.categoryData.abbrev || "");
     targetNode.setAttribute("tooltiptext", frameInfo.tooltiptext);
 
     if (this.hidden) {
       targetNode.style.display = "none";
     }
-    if (this.visibleCells.duration) {
-      targetNode.appendChild(durationCell);
-    }
-    if (this.visibleCells.percentage) {
-      targetNode.appendChild(percentageCell);
-    }
-    if (this.visibleCells.allocations) {
-      targetNode.appendChild(allocationsCell);
-    }
-    if (this.visibleCells.selfDuration) {
-      targetNode.appendChild(selfDurationCell);
-    }
-    if (this.visibleCells.selfPercentage) {
-      targetNode.appendChild(selfPercentageCell);
-    }
-    if (this.visibleCells.selfAllocations) {
-      targetNode.appendChild(selfAllocationsCell);
-    }
-    if (this.visibleCells.samples) {
-      targetNode.appendChild(samplesCell);
-    }
-    if (this.visibleCells.function) {
-      targetNode.appendChild(functionCell);
+
+    for (let i = 0; i < cells.length; i++) {
+      targetNode.appendChild(cells[i]);
     }
 
     return targetNode;
   },
 
   /**
    * Populates this node in the call tree with the corresponding "callees".
    * These are defined in the `frame` data source for this call view.
@@ -234,20 +215,20 @@ CallView.prototype = Heritage.extend(Abs
   _createExecutionCell: function(doc, percentage, isSelf = false) {
     let cell = doc.createElement("description");
     cell.className = "plain call-tree-cell";
     cell.setAttribute("type", isSelf ? "self-percentage" : "percentage");
     cell.setAttribute("crop", "end");
     cell.setAttribute("value", L10N.numberWithDecimals(percentage, 2) + PERCENTAGE_UNITS);
     return cell;
   },
-  _createAllocationsCell: function(doc, count, isSelf = false) {
+  _createCountCell: function(doc, count, isSelf = false) {
     let cell = doc.createElement("description");
     cell.className = "plain call-tree-cell";
-    cell.setAttribute("type", isSelf ? "self-allocations" : "allocations");
+    cell.setAttribute("type", isSelf ? "self-count" : "count");
     cell.setAttribute("crop", "end");
     cell.setAttribute("value", count || 0);
     return cell;
   },
   _createSamplesCell: function(doc, count) {
     let cell = doc.createElement("description");
     cell.className = "plain call-tree-cell";
     cell.setAttribute("type", "samples");
@@ -351,17 +332,17 @@ CallView.prototype = Heritage.extend(Abs
    */
   getDisplayedData: function() {
     if (this._cachedDisplayedData) {
       return this._cachedDisplayedData;
     }
 
     return this._cachedDisplayedData = this.frame.getInfo({
       root: this.root.frame,
-      allocations: (this.visibleCells.allocations || this.visibleCells.selfAllocations)
+      allocations: (this.visibleCells.count || this.visibleCells.selfCount)
     });
 
     /**
      * When inverting call tree, the costs and times are dependent on position
      * in the tree. We must only count leaf nodes with self cost, and total costs
      * dependent on how many times the leaf node was found with a full stack path.
      *
      *   Total |  Self | Calls | Function
--- a/browser/devtools/performance/performance.xul
+++ b/browser/devtools/performance/performance.xul
@@ -300,22 +300,22 @@
               <!-- JS FlameChart -->
               <hbox id="js-flamegraph-view" flex="1">
               </hbox>
 
               <!-- Memory Tree -->
               <vbox id="memory-calltree-view" flex="1">
                 <hbox class="call-tree-headers-container">
                   <label class="plain call-tree-header"
-                         type="allocations"
+                         type="count"
                          crop="end"
                          value="&performanceUI.table.totalAlloc;"
                          tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
                   <label class="plain call-tree-header"
-                         type="self-allocations"
+                         type="self-count"
                          crop="end"
                          value="&performanceUI.table.selfAlloc;"
                          tooltiptext="&performanceUI.table.selfAlloc.tooltip;"/>
                   <label class="plain call-tree-header"
                          type="function"
                          crop="end"
                          value="&performanceUI.table.function;"/>
                 </hbox>
--- a/browser/devtools/performance/test/browser_perf-columns-memory-calltree.js
+++ b/browser/devtools/performance/test/browser_perf-columns-memory-calltree.js
@@ -7,31 +7,31 @@
 function* spawnTest() {
   let { panel } = yield initPerformance(SIMPLE_URL);
   let { EVENTS, $, $$, DetailsView, MemoryCallTreeView } = panel.panelWin;
 
   // Enable memory to test.
   Services.prefs.setBoolPref(MEMORY_PREF, true);
 
   yield startRecording(panel);
-  yield busyWait(1000);
+  yield busyWait(100);
 
   let rendered = once(MemoryCallTreeView, EVENTS.MEMORY_CALL_TREE_RENDERED);
   yield stopRecording(panel);
   yield DetailsView.selectView("memory-calltree");
   ok(DetailsView.isViewSelected(MemoryCallTreeView), "The call tree is now selected.");
   yield rendered;
 
   testCells($, $$, {
     "duration": false,
     "percentage": false,
-    "allocations": true,
+    "count": true,
     "self-duration": false,
     "self-percentage": false,
-    "self-allocations": true,
+    "self-count": true,
     "samples": false,
     "function": true
   });
 
   yield teardown(panel);
   finish();
 }
 
--- a/browser/devtools/performance/views/details-memory-call-tree.js
+++ b/browser/devtools/performance/views/details-memory-call-tree.js
@@ -91,18 +91,18 @@ let MemoryCallTreeView = Heritage.extend
       // Memory call trees should be sorted by allocations.
       sortingPredicate: (a, b) => a.frame.allocations < b.frame.allocations ? 1 : -1,
       // Call trees should only auto-expand when not inverted. Passing undefined
       // will default to the CALL_TREE_AUTO_EXPAND depth.
       autoExpandDepth: inverted ? 0 : undefined,
       // Some cells like the time duration and cost percentage don't make sense
       // for a memory allocations call tree.
       visibleCells: {
-        allocations: true,
-        selfAllocations: true,
+        selfCount: true,
+        count: true,
         function: true
       }
     });
 
     // Bind events.
     root.on("link", this._onLink);
 
     // Pipe "focus" events to the view, mostly for tests
--- a/browser/devtools/performance/views/frames-list.js
+++ b/browser/devtools/performance/views/frames-list.js
@@ -96,17 +96,16 @@ let FramesListView = {
       if (frame.location === location) {
         // If found, set the selected class on element, remove it
         // from previous element, and emit event "select"
         if (this._selectedItem) {
           this._selectedItem.classList.remove("selected");
         }
         this._selectedItem = target;
         target.classList.add("selected");
-        console.log("Emitting select on", this, frame);
         this.emit("select", frame);
         break;
       }
     }
   },
 
   toString: () => "[object FramesListView]"
 };
--- a/browser/devtools/styleinspector/rule-view.js
+++ b/browser/devtools/styleinspector/rule-view.js
@@ -1701,16 +1701,20 @@ CssRuleView.prototype = {
    * @param {NodeActor} aElement
    *        The node whose style rules we'll inspect.
    */
   selectElement: function(aElement) {
     if (this._viewedElement === aElement) {
       return promise.resolve(undefined);
     }
 
+    if (this.popup.isOpen) {
+      this.popup.hidePopup();
+    }
+
     this.clear();
     this.clearPseudoClassPanel();
 
     this._viewedElement = aElement;
     this.refreshAddRuleButtonState();
 
     if (!this._viewedElement) {
       this._showEmpty();
@@ -2203,16 +2207,17 @@ CssRuleView.prototype = {
    *         The rule property TextPropertyEditor object.
    * @return {bool} true if the computed property was highlighted, false
    *         otherwise.
    */
   _highlightComputedProperty: function(editor) {
     let isComputedHighlighted = false;
 
     // Highlight search matches in the computed list of properties
+    editor._populateComputed();
     for (let computed of editor.prop.computed) {
       if (computed.element) {
         // Get the actual property value displayed in the computed list
         let computedName = computed.name.toLowerCase();
         let computedValue = computed.parsedValue.toLowerCase();
 
         isComputedHighlighted = this._highlightMatches(computed.element, {
           searchName: this.searchPropertyName,
@@ -2832,16 +2837,17 @@ RuleEditor.prototype = {
 function TextPropertyEditor(aRuleEditor, aProperty) {
   this.ruleEditor = aRuleEditor;
   this.ruleView = this.ruleEditor.ruleView;
   this.doc = this.ruleEditor.doc;
   this.popup = this.ruleView.popup;
   this.prop = aProperty;
   this.prop.editor = this;
   this.browserWindow = this.doc.defaultView.top;
+  this._populatedComputed = false;
 
   this._onEnableClicked = this._onEnableClicked.bind(this);
   this._onExpandClicked = this._onExpandClicked.bind(this);
   this._onStartEditing = this._onStartEditing.bind(this);
   this._onNameDone = this._onNameDone.bind(this);
   this._onValueDone = this._onValueDone.bind(this);
   this._onSwatchCommit = this._onSwatchCommit.bind(this);
   this._onSwatchPreview = this._onSwatchPreview.bind(this);
@@ -3174,34 +3180,47 @@ TextPropertyEditor.prototype = {
   },
 
   _onStartEditing: function() {
     this.element.classList.remove("ruleview-overridden");
     this.enable.style.visibility = "hidden";
   },
 
   /**
-   * Populate the list of computed styles.
+   * Update the indicator for computed styles. The computed styles themselves
+   * are populated on demand, when they become visible.
    */
   _updateComputed: function() {
-    // Clear out existing viewers.
-    while (this.computed.hasChildNodes()) {
-      this.computed.removeChild(this.computed.lastChild);
+    this.computed.innerHTML = "";
+
+    let showExpander = this.prop.computed.some(c => c.name !== this.prop.name);
+    this.expander.style.visibility = showExpander ? "visible" : "hidden";
+
+    this._populatedComputed = false;
+    if (this.expander.hasAttribute("open")) {
+      this._populateComputed();
     }
-
-    let showExpander = false;
+  },
+
+  /**
+   * Populate the list of computed styles.
+   */
+  _populateComputed: function() {
+    if (this._populatedComputed) {
+      return;
+    }
+    this._populatedComputed = true;
+
     for (let computed of this.prop.computed) {
       // Don't bother to duplicate information already
       // shown in the text property.
       if (computed.name === this.prop.name) {
         continue;
       }
 
-      showExpander = true;
-
       let li = createChild(this.computed, "li", {
         class: "ruleview-computed"
       });
 
       if (computed.overridden) {
         li.classList.add("ruleview-overridden");
       }
 
@@ -3229,23 +3248,16 @@ TextPropertyEditor.prototype = {
       });
 
       appendText(li, ";");
 
       // Store the computed style element for easy access when highlighting
       // styles
       computed.element = li;
     }
-
-    // Show or hide the expander as needed.
-    if (showExpander) {
-      this.expander.style.visibility = "visible";
-    } else {
-      this.expander.style.visibility = "hidden";
-    }
   },
 
   /**
    * Handles clicks on the disabled property.
    */
   _onEnableClicked: function(aEvent) {
     let checked = this.enable.hasAttribute("checked");
     if (checked) {
@@ -3268,30 +3280,32 @@ TextPropertyEditor.prototype = {
     if (this.computed.hasAttribute("filter-open") ||
         this.computed.hasAttribute("user-open")) {
       this.expander.removeAttribute("open");
       this.computed.removeAttribute("filter-open");
       this.computed.removeAttribute("user-open");
     } else {
       this.expander.setAttribute("open", "true");
       this.computed.setAttribute("user-open", "");
+      this._populateComputed();
     }
 
     aEvent.stopPropagation();
   },
 
   /**
    * Expands the computed list when a computed property is matched by the style
    * filtering. The filter-open attribute is used to track whether or not the
    * computed list was toggled opened by the filter.
    */
   expandForFilter: function() {
     if (!this.computed.hasAttribute("user-open")) {
       this.expander.setAttribute("open", "true");
       this.computed.setAttribute("filter-open", "");
+      this._populateComputed();
     }
   },
 
   /**
    * Collapses the computed list that was expanded by style filtering.
    */
   collapseForFilter: function() {
     this.computed.removeAttribute("filter-open");
--- a/browser/devtools/styleinspector/style-inspector-menu.js
+++ b/browser/devtools/styleinspector/style-inspector-menu.js
@@ -1,539 +1,539 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* globals overlays, Services, clipboardHelper, _strings */
-
-"use strict";
-
-const {Cc, Ci, Cu} = require("chrome");
-const {PREF_ORIG_SOURCES} = require("devtools/styleeditor/utils");
-
-loader.lazyRequireGetter(this, "overlays", "devtools/styleinspector/style-inspector-overlays");
-loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
-loader.lazyServiceGetter(this, "clipboardHelper", "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
-loader.lazyGetter(this, "_strings", () => {
-  return Services.strings
-  .createBundle("chrome://global/locale/devtools/styleinspector.properties");
-});
-
-const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-const PREF_ENABLE_MDN_DOCS_TOOLTIP = "devtools.inspector.mdnDocsTooltip.enabled";
-
-/**
- * Style inspector context menu
- * @param {RuleView|ComputedView} view RuleView or ComputedView instance controlling this menu
- * @param {Object} options menu configuration
- */
-function StyleInspectorMenu(view, options) {
-  this.view = view;
-  this.inspector = this.view.inspector;
-  this.styleDocument = this.view.styleDocument;
-  this.styleWindow = this.view.styleWindow;
-
-  this.isRuleView = options.isRuleView;
-
-  this._onAddNewRule = this._onAddNewRule.bind(this);
-  this._onCopy = this._onCopy.bind(this);
-  this._onCopyColor = this._onCopyColor.bind(this);
-  this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
-  this._onCopyLocation = this._onCopyLocation.bind(this);
-  this._onCopyPropertyDeclaration = this._onCopyPropertyDeclaration.bind(this);
-  this._onCopyPropertyName = this._onCopyPropertyName.bind(this);
-  this._onCopyPropertyValue = this._onCopyPropertyValue.bind(this);
-  this._onCopyRule = this._onCopyRule.bind(this);
-  this._onCopySelector = this._onCopySelector.bind(this);
-  this._onCopyUrl = this._onCopyUrl.bind(this);
-  this._onSelectAll = this._onSelectAll.bind(this);
-  this._onShowMdnDocs = this._onShowMdnDocs.bind(this);
-  this._onToggleOrigSources = this._onToggleOrigSources.bind(this);
-  this._updateMenuItems = this._updateMenuItems.bind(this);
-
-  this._createContextMenu();
-}
-
-module.exports = StyleInspectorMenu;
-
-StyleInspectorMenu.prototype = {
-  /**
-   * Display the style inspector context menu
-   */
-  show: function(event) {
-    try {
-      // In the sidebar we do not have this.styleDocument.popupNode
-      // so we need to save the node ourselves.
-      this.styleDocument.popupNode = event.explicitOriginalTarget;
-      this.styleWindow.focus();
-      this._menupopup.openPopupAtScreen(event.screenX, event.screenY, true);
-    } catch(e) {
-      console.error(e);
-    }
-  },
-
-  _createContextMenu: function() {
-    this._menupopup = this.styleDocument.createElementNS(XUL_NS, "menupopup");
-    this._menupopup.addEventListener("popupshowing", this._updateMenuItems);
-    this._menupopup.id = "computed-view-context-menu";
-
-    let parentDocument = this.styleWindow.parent.document;
-    let popupset = parentDocument.documentElement.querySelector("popupset");
-    if (!popupset) {
-      popupset = parentDocument.createElementNS(XUL_NS, "popupset");
-      parentDocument.documentElement.appendChild(popupset);
-    }
-    popupset.appendChild(this._menupopup);
-
-    this._createContextMenuItems();
-  },
-  /**
-   * Create all context menu items
-   */
-  _createContextMenuItems: function() {
-    this.menuitemCopy = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.copy",
-      accesskey: "styleinspector.contextmenu.copy.accessKey",
-      command: this._onCopy
-    });
-
-    this.menuitemCopyLocation = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.copyLocation",
-      command: this._onCopyLocation
-    });
-
-    this.menuitemCopyRule = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.copyRule",
-      command: this._onCopyRule
-    });
-
-    this.menuitemCopyColor = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.copyColor",
-      accesskey: "styleinspector.contextmenu.copyColor.accessKey",
-      command: this._onCopyColor
-    });
-
-    this.menuitemCopyUrl = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.copyUrl",
-      accesskey: "styleinspector.contextmenu.copyUrl.accessKey",
-      command: this._onCopyUrl
-    });
-
-    this.menuitemCopyImageDataUrl = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.copyImageDataUrl",
-      accesskey: "styleinspector.contextmenu.copyImageDataUrl.accessKey",
-      command: this._onCopyImageDataUrl
-    });
-
-    this.menuitemCopyPropertyDeclaration = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.copyPropertyDeclaration",
-      command: this._onCopyPropertyDeclaration
-    });
-
-    this.menuitemCopyPropertyName = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.copyPropertyName",
-      command: this._onCopyPropertyName
-    });
-
-    this.menuitemCopyPropertyValue = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.copyPropertyValue",
-      command: this._onCopyPropertyValue
-    });
-
-    this.menuitemCopySelector = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.copySelector",
-      command: this._onCopySelector
-    });
-
-    this._createMenuSeparator();
-
-    // Select All
-    this.menuitemSelectAll = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.selectAll",
-      accesskey: "styleinspector.contextmenu.selectAll.accessKey",
-      command: this._onSelectAll
-    });
-
-    this._createMenuSeparator();
-
-    // Add new rule
-    this.menuitemAddRule = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.addNewRule",
-      accesskey: "styleinspector.contextmenu.addNewRule.accessKey",
-      command: this._onAddNewRule
-    });
-
-    // Show MDN Docs
-    this.menuitemShowMdnDocs = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.showMdnDocs",
-      accesskey: "styleinspector.contextmenu.showMdnDocs.accessKey",
-      command: this._onShowMdnDocs
-    });
-
-    // Show Original Sources
-    this.menuitemSources = this._createContextMenuItem({
-      label: "styleinspector.contextmenu.toggleOrigSources",
-      accesskey: "styleinspector.contextmenu.toggleOrigSources.accessKey",
-      command: this._onToggleOrigSources,
-      type: "checkbox"
-    });
-  },
-
-  /**
-   * Create a single context menu item based on the provided configuration
-   * Returns the created menu item element
-   */
-  _createContextMenuItem: function(attributes) {
-    let ownerDocument = this._menupopup.ownerDocument;
-    let item = ownerDocument.createElementNS(XUL_NS, "menuitem");
-
-    item.setAttribute("label", _strings.GetStringFromName(attributes.label));
-    if (attributes.accesskey) {
-      item.setAttribute("accesskey", _strings.GetStringFromName(attributes.accesskey));
-    }
-    item.addEventListener("command", attributes.command);
-
-    if (attributes.type) {
-      item.setAttribute("type", attributes.type);
-    }
-
-    this._menupopup.appendChild(item);
-    return item;
-  },
-
-  _createMenuSeparator: function() {
-    let ownerDocument = this._menupopup.ownerDocument;
-    let separator = ownerDocument.createElementNS(XUL_NS, "menuseparator");
-    this._menupopup.appendChild(separator);
-  },
-
-  /**
-   * Update the context menu. This means enabling or disabling menuitems as
-   * appropriate.
-   */
-  _updateMenuItems: function() {
-    this._updateCopyMenuItems();
-
-    let showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
-    this.menuitemSources.setAttribute("checked", showOrig);
-
-    let enableMdnDocsTooltip = Services.prefs.getBoolPref(PREF_ENABLE_MDN_DOCS_TOOLTIP);
-    this.menuitemShowMdnDocs.hidden = !(enableMdnDocsTooltip && this._isPropertyName());
-
-    this.menuitemAddRule.disabled = !(this.isRuleView && !this.inspector.selection.isAnonymousNode());
-  },
-
-  /**
-   * Display the necessary copy context menu items depending on the clicked
-   * node and selection in the rule view.
-   */
-  _updateCopyMenuItems: function() {
-    this.menuitemCopy.hidden = !this._hasTextSelected();
-    this.menuitemCopyColor.hidden = !this._isColorPopup();
-    this.menuitemCopyImageDataUrl.hidden = !this._isImageUrl();
-    this.menuitemCopyUrl.hidden = !this._isImageUrl();
-
-    this.menuitemCopyRule.hidden = true;
-    this.menuitemCopyLocation.hidden = true;
-    this.menuitemCopyPropertyDeclaration.hidden = true;
-    this.menuitemCopyPropertyName.hidden = true;
-    this.menuitemCopyPropertyValue.hidden = true;
-    this.menuitemCopySelector.hidden = true;
-
-    this._clickedNodeInfo = this._getClickedNodeInfo();
-    if (this.isRuleView && this._clickedNodeInfo) {
-      this.menuitemCopyRule.hidden = false;
-
-      switch (this._clickedNodeInfo.type) {
-        case overlays.VIEW_NODE_PROPERTY_TYPE :
-          this.menuitemCopyPropertyDeclaration.hidden = false;
-          this.menuitemCopyPropertyName.hidden = false;
-          break;
-        case overlays.VIEW_NODE_VALUE_TYPE :
-          this.menuitemCopyPropertyDeclaration.hidden = false;
-          this.menuitemCopyPropertyValue.hidden = false;
-          break;
-        case overlays.VIEW_NODE_SELECTOR_TYPE :
-          this.menuitemCopySelector.hidden = false;
-          break;
-        case overlays.VIEW_NODE_LOCATION_TYPE :
-          this.menuitemCopyLocation.hidden = false;
-          break;
-      }
-    }
-  },
-
-  _hasTextSelected: function() {
-    let hasTextSelected;
-    let selection = this.styleWindow.getSelection();
-
-    let node = this._getClickedNode();
-    if (node.nodeName == "input") {
-       // input type="text"
-      let { selectionStart, selectionEnd } = node;
-      hasTextSelected = isFinite(selectionStart) && isFinite(selectionEnd)
-        && selectionStart !== selectionEnd;
-    } else {
-      hasTextSelected = selection.toString() && !selection.isCollapsed;
-    }
-
-    return hasTextSelected;
-  },
-
-  /**
-   * Get the type of the currently clicked node
-   */
-  _getClickedNodeInfo: function() {
-    let node = this._getClickedNode();
-    return this.view.getNodeInfo(node);
-  },
-
-  /**
-   * A helper that determines if the popup was opened with a click to a color
-   * value and saves the color to this._colorToCopy.
-   *
-   * @return {Boolean}
-   *         true if click on color opened the popup, false otherwise.
-   */
-  _isColorPopup: function() {
-    this._colorToCopy = "";
-
-    let container = this._getClickedNode();
-    if (!container) {
-      return false;
-    }
-
-    let isColorNode = el => el.dataset && "color" in el.dataset;
-
-    while (!isColorNode(container)) {
-      container = container.parentNode;
-      if (!container) {
-        return false;
-      }
-    }
-
-    this._colorToCopy = container.dataset.color;
-    return true;
-  },
-
-  _isPropertyName: function() {
-    let nodeInfo = this._getClickedNodeInfo();
-    if (!nodeInfo) {
-      return false;
-    }
-    return nodeInfo.type == overlays.VIEW_NODE_PROPERTY_TYPE;
-  },
-
-  /**
-   * Check if the current node (clicked node) is an image URL
-   * @return {Boolean} true if the node is an image url
-   */
-  _isImageUrl: function() {
-    let nodeInfo = this._getClickedNodeInfo();
-    if (!nodeInfo) {
-      return false;
-    }
-    return nodeInfo.type == overlays.VIEW_NODE_IMAGE_URL_TYPE;
-  },
-
-  /**
-   * Get the DOM Node container for the current popupNode.
-   * If popupNode is a textNode, return the parent node, otherwise return popupNode itself.
-   * @return {DOMNode}
-   */
-  _getClickedNode: function() {
-    let container = null;
-    let node = this.styleDocument.popupNode;
-
-    if (node) {
-      let isTextNode = node.nodeType == node.TEXT_NODE;
-      container = isTextNode ? node.parentElement : node;
-    }
-
-    return container;
-  },
-
-  /**
-   * Select all text.
-   */
-  _onSelectAll: function() {
-    let selection = this.styleWindow.getSelection();
-    selection.selectAllChildren(this.styleDocument.documentElement);
-  },
-
-  /**
-   * Copy the most recently selected color value to clipboard.
-   */
-  _onCopy: function(event) {
-    this.view.copySelection(this.styleDocument.popupNode);
-  },
-
-  /**
-   * Copy the most recently selected color value to clipboard.
-   */
-  _onCopyColor: function() {
-    clipboardHelper.copyString(this._colorToCopy);
-  },
-
-  /*
-   * Retrieve the url for the selected image and copy it to the clipboard
-   */
-  _onCopyUrl: function() {
-    if (!this._clickedNodeInfo) {
-      return;
-    }
-
-    clipboardHelper.copyString(this._clickedNodeInfo.value.url);
-  },
-
-  /**
-   * Retrieve the image data for the selected image url and copy it to the clipboard
-   */
-  _onCopyImageDataUrl: Task.async(function*() {
-    if (!this._clickedNodeInfo) {
-      return;
-    }
-
-    let message;
-    try {
-      let inspectorFront = this.inspector.inspector;
-      let imageUrl = this._clickedNodeInfo.value.url;
-      let data = yield inspectorFront.getImageDataFromURL(imageUrl);
-      message = yield data.data.string();
-    } catch (e) {
-      message = _strings.GetStringFromName("styleinspector.copyImageDataUrlError");
-    }
-
-    clipboardHelper.copyString(message);
-  }),
-
-  /**
-   *  Show docs from MDN for a CSS property.
-   */
-  _onShowMdnDocs: function() {
-    let cssPropertyName = this.styleDocument.popupNode.textContent;
-    let anchor = this.styleDocument.popupNode.parentNode;
-    let cssDocsTooltip = this.view.tooltips.cssDocs;
-    cssDocsTooltip.show(anchor, cssPropertyName);
-  },
-
-  /**
-   * Add a new rule to the current element.
-   */
-  _onAddNewRule: function() {
-    this.view._onAddRule();
-  },
-
-  /**
-   * Copy the rule source location of the current clicked node.
-   */
-  _onCopyLocation: function() {
-    if (!this._clickedNodeInfo) {
-      return;
-    }
-
-    clipboardHelper.copyString(this._clickedNodeInfo.value);
-  },
-
-  /**
-   * Copy the rule property declaration of the current clicked node.
-   */
-  _onCopyPropertyDeclaration: function() {
-    if (!this._clickedNodeInfo) {
-      return;
-    }
-
-    let textProp = this._clickedNodeInfo.value.textProperty;
-    clipboardHelper.copyString(textProp.stringifyProperty());
-  },
-
-  /**
-   * Copy the rule property name of the current clicked node.
-   */
-  _onCopyPropertyName: function() {
-    if (!this._clickedNodeInfo) {
-      return;
-    }
-
-    clipboardHelper.copyString(this._clickedNodeInfo.value.property);
-  },
-
-  /**
-   * Copy the rule property value of the current clicked node.
-   */
-  _onCopyPropertyValue: function() {
-    if (!this._clickedNodeInfo) {
-      return;
-    }
-
-    clipboardHelper.copyString(this._clickedNodeInfo.value.value);
-  },
-
-  /**
-   * Copy the rule of the current clicked node.
-   */
-  _onCopyRule: function() {
-    let ruleEditor = this.styleDocument.popupNode.parentNode.offsetParent._ruleEditor;
-    let rule = ruleEditor.rule;
-    clipboardHelper.copyString(rule.stringifyRule());
-  },
-
-  /**
-   * Copy the rule selector of the current clicked node.
-   */
-  _onCopySelector: function() {
-    if (!this._clickedNodeInfo) {
-      return;
-    }
-
-    clipboardHelper.copyString(this._clickedNodeInfo.value);
-  },
-
-  /**
-   *  Toggle the original sources pref.
-   */
-  _onToggleOrigSources: function() {
-    let isEnabled = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
-    Services.prefs.setBoolPref(PREF_ORIG_SOURCES, !isEnabled);
-  },
-
-  destroy: function() {
-    this._removeContextMenuItems();
-
-    // Destroy the context menu.
-    this._menupopup.removeEventListener("popupshowing", this._updateMenuItems);
-    this._menupopup.parentNode.removeChild(this._menupopup);
-    this._menupopup = null;
-
-    this.popupNode = null;
-    this.styleDocument.popupNode = null;
-    this.view = null;
-    this.inspector = null;
-    this.styleDocument = null;
-    this.styleWindow = null;
-  },
-
-  _removeContextMenuItems: function() {
-    this._removeContextMenuItem("menuitemAddRule", this._onAddNewRule);
-    this._removeContextMenuItem("menuitemCopy", this._onCopy);
-    this._removeContextMenuItem("menuitemCopyColor", this._onCopyColor);
-    this._removeContextMenuItem("menuitemCopyImageDataUrl", this._onCopyImageDataUrl);
-    this._removeContextMenuItem("menuitemCopyLocation", this._onCopyLocation);
-    this._removeContextMenuItem("menuitemCopyPropertyDeclaration", this._onCopyPropertyDeclaration);
-    this._removeContextMenuItem("menuitemCopyPropertyName", this._onCopyPropertyName);
-    this._removeContextMenuItem("menuitemCopyPropertyValue", this._onCopyPropertyValue);
-    this._removeContextMenuItem("menuitemCopyRule", this._onCopyRule);
-    this._removeContextMenuItem("menuitemCopySelector", this._onCopySelector);
-    this._removeContextMenuItem("menuitemCopyUrl", this._onCopyUrl);
-    this._removeContextMenuItem("menuitemSelectAll", this._onSelectAll);
-    this._removeContextMenuItem("menuitemShowMdnDocs", this._onShowMdnDocs);
-    this._removeContextMenuItem("menuitemSources", this._onToggleOrigSources);
-  },
-
-  _removeContextMenuItem: function(itemName, callback) {
-    if (this[itemName]) {
-      this[itemName].removeEventListener("command", callback);
-      this[itemName] = null;
-    }
-  }
-};
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* globals overlays, Services, clipboardHelper, _strings */
+
+"use strict";
+
+const {Cc, Ci, Cu} = require("chrome");
+const {PREF_ORIG_SOURCES} = require("devtools/styleeditor/utils");
+
+loader.lazyRequireGetter(this, "overlays", "devtools/styleinspector/style-inspector-overlays");
+loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
+loader.lazyServiceGetter(this, "clipboardHelper", "@mozilla.org/widget/clipboardhelper;1", "nsIClipboardHelper");
+loader.lazyGetter(this, "_strings", () => {
+  return Services.strings
+  .createBundle("chrome://global/locale/devtools/styleinspector.properties");
+});
+
+const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+const PREF_ENABLE_MDN_DOCS_TOOLTIP = "devtools.inspector.mdnDocsTooltip.enabled";
+
+/**
+ * Style inspector context menu
+ * @param {RuleView|ComputedView} view RuleView or ComputedView instance controlling this menu
+ * @param {Object} options menu configuration
+ */
+function StyleInspectorMenu(view, options) {
+  this.view = view;
+  this.inspector = this.view.inspector;
+  this.styleDocument = this.view.styleDocument;
+  this.styleWindow = this.view.styleWindow;
+
+  this.isRuleView = options.isRuleView;
+
+  this._onAddNewRule = this._onAddNewRule.bind(this);
+  this._onCopy = this._onCopy.bind(this);
+  this._onCopyColor = this._onCopyColor.bind(this);
+  this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
+  this._onCopyLocation = this._onCopyLocation.bind(this);
+  this._onCopyPropertyDeclaration = this._onCopyPropertyDeclaration.bind(this);
+  this._onCopyPropertyName = this._onCopyPropertyName.bind(this);
+  this._onCopyPropertyValue = this._onCopyPropertyValue.bind(this);
+  this._onCopyRule = this._onCopyRule.bind(this);
+  this._onCopySelector = this._onCopySelector.bind(this);
+  this._onCopyUrl = this._onCopyUrl.bind(this);
+  this._onSelectAll = this._onSelectAll.bind(this);
+  this._onShowMdnDocs = this._onShowMdnDocs.bind(this);
+  this._onToggleOrigSources = this._onToggleOrigSources.bind(this);
+  this._updateMenuItems = this._updateMenuItems.bind(this);
+
+  this._createContextMenu();
+}
+
+module.exports = StyleInspectorMenu;
+
+StyleInspectorMenu.prototype = {
+  /**
+   * Display the style inspector context menu
+   */
+  show: function(event) {
+    try {
+      // In the sidebar we do not have this.styleDocument.popupNode
+      // so we need to save the node ourselves.
+      this.styleDocument.popupNode = event.explicitOriginalTarget;
+      this.styleWindow.focus();
+      this._menupopup.openPopupAtScreen(event.screenX, event.screenY, true);
+    } catch(e) {
+      console.error(e);
+    }
+  },
+
+  _createContextMenu: function() {
+    this._menupopup = this.styleDocument.createElementNS(XUL_NS, "menupopup");
+    this._menupopup.addEventListener("popupshowing", this._updateMenuItems);
+    this._menupopup.id = "computed-view-context-menu";
+
+    let parentDocument = this.styleWindow.parent.document;
+    let popupset = parentDocument.documentElement.querySelector("popupset");
+    if (!popupset) {
+      popupset = parentDocument.createElementNS(XUL_NS, "popupset");
+      parentDocument.documentElement.appendChild(popupset);
+    }
+    popupset.appendChild(this._menupopup);
+
+    this._createContextMenuItems();
+  },
+  /**
+   * Create all context menu items
+   */
+  _createContextMenuItems: function() {
+    this.menuitemCopy = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.copy",
+      accesskey: "styleinspector.contextmenu.copy.accessKey",
+      command: this._onCopy
+    });
+
+    this.menuitemCopyLocation = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.copyLocation",
+      command: this._onCopyLocation
+    });
+
+    this.menuitemCopyRule = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.copyRule",
+      command: this._onCopyRule
+    });
+
+    this.menuitemCopyColor = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.copyColor",
+      accesskey: "styleinspector.contextmenu.copyColor.accessKey",
+      command: this._onCopyColor
+    });
+
+    this.menuitemCopyUrl = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.copyUrl",
+      accesskey: "styleinspector.contextmenu.copyUrl.accessKey",
+      command: this._onCopyUrl
+    });
+
+    this.menuitemCopyImageDataUrl = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.copyImageDataUrl",
+      accesskey: "styleinspector.contextmenu.copyImageDataUrl.accessKey",
+      command: this._onCopyImageDataUrl
+    });
+
+    this.menuitemCopyPropertyDeclaration = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.copyPropertyDeclaration",
+      command: this._onCopyPropertyDeclaration
+    });
+
+    this.menuitemCopyPropertyName = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.copyPropertyName",
+      command: this._onCopyPropertyName
+    });
+
+    this.menuitemCopyPropertyValue = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.copyPropertyValue",
+      command: this._onCopyPropertyValue
+    });
+
+    this.menuitemCopySelector = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.copySelector",
+      command: this._onCopySelector
+    });
+
+    this._createMenuSeparator();
+
+    // Select All
+    this.menuitemSelectAll = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.selectAll",
+      accesskey: "styleinspector.contextmenu.selectAll.accessKey",
+      command: this._onSelectAll
+    });
+
+    this._createMenuSeparator();
+
+    // Add new rule
+    this.menuitemAddRule = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.addNewRule",
+      accesskey: "styleinspector.contextmenu.addNewRule.accessKey",
+      command: this._onAddNewRule
+    });
+
+    // Show MDN Docs
+    this.menuitemShowMdnDocs = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.showMdnDocs",
+      accesskey: "styleinspector.contextmenu.showMdnDocs.accessKey",
+      command: this._onShowMdnDocs
+    });
+
+    // Show Original Sources
+    this.menuitemSources = this._createContextMenuItem({
+      label: "styleinspector.contextmenu.toggleOrigSources",
+      accesskey: "styleinspector.contextmenu.toggleOrigSources.accessKey",
+      command: this._onToggleOrigSources,
+      type: "checkbox"
+    });
+  },
+
+  /**
+   * Create a single context menu item based on the provided configuration
+   * Returns the created menu item element
+   */
+  _createContextMenuItem: function(attributes) {
+    let ownerDocument = this._menupopup.ownerDocument;
+    let item = ownerDocument.createElementNS(XUL_NS, "menuitem");
+
+    item.setAttribute("label", _strings.GetStringFromName(attributes.label));
+    if (attributes.accesskey) {
+      item.setAttribute("accesskey", _strings.GetStringFromName(attributes.accesskey));
+    }
+    item.addEventListener("command", attributes.command);
+
+    if (attributes.type) {
+      item.setAttribute("type", attributes.type);
+    }
+
+    this._menupopup.appendChild(item);
+    return item;
+  },
+
+  _createMenuSeparator: function() {
+    let ownerDocument = this._menupopup.ownerDocument;
+    let separator = ownerDocument.createElementNS(XUL_NS, "menuseparator");
+    this._menupopup.appendChild(separator);
+  },
+
+  /**
+   * Update the context menu. This means enabling or disabling menuitems as
+   * appropriate.
+   */
+  _updateMenuItems: function() {
+    this._updateCopyMenuItems();
+
+    let showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
+    this.menuitemSources.setAttribute("checked", showOrig);
+
+    let enableMdnDocsTooltip = Services.prefs.getBoolPref(PREF_ENABLE_MDN_DOCS_TOOLTIP);
+    this.menuitemShowMdnDocs.hidden = !(enableMdnDocsTooltip && this._isPropertyName());
+
+    this.menuitemAddRule.hidden = !this.isRuleView;
+    this.menuitemAddRule.disabled = !(this.isRuleView && !this.inspector.selection.isAnonymousNode());
+  },
+
+  /**
+   * Display the necessary copy context menu items depending on the clicked
+   * node and selection in the rule view.
+   */
+  _updateCopyMenuItems: function() {
+    this.menuitemCopy.disabled = !this._hasTextSelected();
+
+    this.menuitemCopyColor.hidden = !this._isColorPopup();
+    this.menuitemCopyImageDataUrl.hidden = !this._isImageUrl();
+    this.menuitemCopyUrl.hidden = !this._isImageUrl();
+    this.menuitemCopyRule.hidden = !this.isRuleView;
+
+    this.menuitemCopyLocation.hidden = true;
+    this.menuitemCopyPropertyDeclaration.hidden = true;
+    this.menuitemCopyPropertyName.hidden = true;
+    this.menuitemCopyPropertyValue.hidden = true;
+    this.menuitemCopySelector.hidden = true;
+
+    this._clickedNodeInfo = this._getClickedNodeInfo();
+    if (this.isRuleView && this._clickedNodeInfo) {
+      switch (this._clickedNodeInfo.type) {
+        case overlays.VIEW_NODE_PROPERTY_TYPE :
+          this.menuitemCopyPropertyDeclaration.hidden = false;
+          this.menuitemCopyPropertyName.hidden = false;
+          break;
+        case overlays.VIEW_NODE_VALUE_TYPE :
+          this.menuitemCopyPropertyDeclaration.hidden = false;
+          this.menuitemCopyPropertyValue.hidden = false;
+          break;
+        case overlays.VIEW_NODE_SELECTOR_TYPE :
+          this.menuitemCopySelector.hidden = false;
+          break;
+        case overlays.VIEW_NODE_LOCATION_TYPE :
+          this.menuitemCopyLocation.hidden = false;
+          break;
+      }
+    }
+  },
+
+  _hasTextSelected: function() {
+    let hasTextSelected;
+    let selection = this.styleWindow.getSelection();
+
+    let node = this._getClickedNode();
+    if (node.nodeName == "input") {
+       // input type="text"
+      let { selectionStart, selectionEnd } = node;
+      hasTextSelected = isFinite(selectionStart) && isFinite(selectionEnd)
+        && selectionStart !== selectionEnd;
+    } else {
+      hasTextSelected = selection.toString() && !selection.isCollapsed;
+    }
+
+    return hasTextSelected;
+  },
+
+  /**
+   * Get the type of the currently clicked node
+   */
+  _getClickedNodeInfo: function() {
+    let node = this._getClickedNode();
+    return this.view.getNodeInfo(node);
+  },
+
+  /**
+   * A helper that determines if the popup was opened with a click to a color
+   * value and saves the color to this._colorToCopy.
+   *
+   * @return {Boolean}
+   *         true if click on color opened the popup, false otherwise.
+   */
+  _isColorPopup: function() {
+    this._colorToCopy = "";
+
+    let container = this._getClickedNode();
+    if (!container) {
+      return false;
+    }
+
+    let isColorNode = el => el.dataset && "color" in el.dataset;
+
+    while (!isColorNode(container)) {
+      container = container.parentNode;
+      if (!container) {
+        return false;
+      }
+    }
+
+    this._colorToCopy = container.dataset.color;
+    return true;
+  },
+
+  _isPropertyName: function() {
+    let nodeInfo = this._getClickedNodeInfo();
+    if (!nodeInfo) {
+      return false;
+    }
+    return nodeInfo.type == overlays.VIEW_NODE_PROPERTY_TYPE;
+  },
+
+  /**
+   * Check if the current node (clicked node) is an image URL
+   * @return {Boolean} true if the node is an image url
+   */
+  _isImageUrl: function() {
+    let nodeInfo = this._getClickedNodeInfo();
+    if (!nodeInfo) {
+      return false;
+    }
+    return nodeInfo.type == overlays.VIEW_NODE_IMAGE_URL_TYPE;
+  },
+
+  /**
+   * Get the DOM Node container for the current popupNode.
+   * If popupNode is a textNode, return the parent node, otherwise return popupNode itself.
+   * @return {DOMNode}
+   */
+  _getClickedNode: function() {
+    let container = null;
+    let node = this.styleDocument.popupNode;
+
+    if (node) {
+      let isTextNode = node.nodeType == node.TEXT_NODE;
+      container = isTextNode ? node.parentElement : node;
+    }
+
+    return container;
+  },
+
+  /**
+   * Select all text.
+   */
+  _onSelectAll: function() {
+    let selection = this.styleWindow.getSelection();
+    selection.selectAllChildren(this.styleDocument.documentElement);
+  },
+
+  /**
+   * Copy the most recently selected color value to clipboard.
+   */
+  _onCopy: function(event) {
+    this.view.copySelection(this.styleDocument.popupNode);
+  },
+
+  /**
+   * Copy the most recently selected color value to clipboard.
+   */
+  _onCopyColor: function() {
+    clipboardHelper.copyString(this._colorToCopy);
+  },
+
+  /*
+   * Retrieve the url for the selected image and copy it to the clipboard
+   */
+  _onCopyUrl: function() {
+    if (!this._clickedNodeInfo) {
+      return;
+    }
+
+    clipboardHelper.copyString(this._clickedNodeInfo.value.url);
+  },
+
+  /**
+   * Retrieve the image data for the selected image url and copy it to the clipboard
+   */
+  _onCopyImageDataUrl: Task.async(function*() {
+    if (!this._clickedNodeInfo) {
+      return;
+    }
+
+    let message;
+    try {
+      let inspectorFront = this.inspector.inspector;
+      let imageUrl = this._clickedNodeInfo.value.url;
+      let data = yield inspectorFront.getImageDataFromURL(imageUrl);
+      message = yield data.data.string();
+    } catch (e) {
+      message = _strings.GetStringFromName("styleinspector.copyImageDataUrlError");
+    }
+
+    clipboardHelper.copyString(message);
+  }),
+
+  /**
+   *  Show docs from MDN for a CSS property.
+   */
+  _onShowMdnDocs: function() {
+    let cssPropertyName = this.styleDocument.popupNode.textContent;
+    let anchor = this.styleDocument.popupNode.parentNode;
+    let cssDocsTooltip = this.view.tooltips.cssDocs;
+    cssDocsTooltip.show(anchor, cssPropertyName);
+  },
+
+  /**
+   * Add a new rule to the current element.
+   */
+  _onAddNewRule: function() {
+    this.view._onAddRule();
+  },
+
+  /**
+   * Copy the rule source location of the current clicked node.
+   */
+  _onCopyLocation: function() {
+    if (!this._clickedNodeInfo) {
+      return;
+    }
+
+    clipboardHelper.copyString(this._clickedNodeInfo.value);
+  },
+
+  /**
+   * Copy the rule property declaration of the current clicked node.
+   */
+  _onCopyPropertyDeclaration: function() {
+    if (!this._clickedNodeInfo) {
+      return;
+    }
+
+    let textProp = this._clickedNodeInfo.value.textProperty;
+    clipboardHelper.copyString(textProp.stringifyProperty());
+  },
+
+  /**
+   * Copy the rule property name of the current clicked node.
+   */
+  _onCopyPropertyName: function() {
+    if (!this._clickedNodeInfo) {
+      return;
+    }
+
+    clipboardHelper.copyString(this._clickedNodeInfo.value.property);
+  },
+
+  /**
+   * Copy the rule property value of the current clicked node.
+   */
+  _onCopyPropertyValue: function() {
+    if (!this._clickedNodeInfo) {
+      return;
+    }
+
+    clipboardHelper.copyString(this._clickedNodeInfo.value.value);
+  },
+
+  /**
+   * Copy the rule of the current clicked node.
+   */
+  _onCopyRule: function() {
+    let ruleEditor = this.styleDocument.popupNode.parentNode.offsetParent._ruleEditor;
+    let rule = ruleEditor.rule;
+    clipboardHelper.copyString(rule.stringifyRule());
+  },
+
+  /**
+   * Copy the rule selector of the current clicked node.
+   */
+  _onCopySelector: function() {
+    if (!this._clickedNodeInfo) {
+      return;
+    }
+
+    clipboardHelper.copyString(this._clickedNodeInfo.value);
+  },
+
+  /**
+   *  Toggle the original sources pref.
+   */
+  _onToggleOrigSources: function() {
+    let isEnabled = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
+    Services.prefs.setBoolPref(PREF_ORIG_SOURCES, !isEnabled);
+  },
+
+  destroy: function() {
+    this._removeContextMenuItems();
+
+    // Destroy the context menu.
+    this._menupopup.removeEventListener("popupshowing", this._updateMenuItems);
+    this._menupopup.parentNode.removeChild(this._menupopup);
+    this._menupopup = null;
+
+    this.popupNode = null;
+    this.styleDocument.popupNode = null;
+    this.view = null;
+    this.inspector = null;
+    this.styleDocument = null;
+    this.styleWindow = null;
+  },
+
+  _removeContextMenuItems: function() {
+    this._removeContextMenuItem("menuitemAddRule", this._onAddNewRule);
+    this._removeContextMenuItem("menuitemCopy", this._onCopy);
+    this._removeContextMenuItem("menuitemCopyColor", this._onCopyColor);
+    this._removeContextMenuItem("menuitemCopyImageDataUrl", this._onCopyImageDataUrl);
+    this._removeContextMenuItem("menuitemCopyLocation", this._onCopyLocation);
+    this._removeContextMenuItem("menuitemCopyPropertyDeclaration", this._onCopyPropertyDeclaration);
+    this._removeContextMenuItem("menuitemCopyPropertyName", this._onCopyPropertyName);
+    this._removeContextMenuItem("menuitemCopyPropertyValue", this._onCopyPropertyValue);
+    this._removeContextMenuItem("menuitemCopyRule", this._onCopyRule);
+    this._removeContextMenuItem("menuitemCopySelector", this._onCopySelector);
+    this._removeContextMenuItem("menuitemCopyUrl", this._onCopyUrl);
+    this._removeContextMenuItem("menuitemSelectAll", this._onSelectAll);
+    this._removeContextMenuItem("menuitemShowMdnDocs", this._onShowMdnDocs);
+    this._removeContextMenuItem("menuitemSources", this._onToggleOrigSources);
+  },
+
+  _removeContextMenuItem: function(itemName, callback) {
+    if (this[itemName]) {
+      this[itemName].removeEventListener("command", callback);
+      this[itemName] = null;
+    }
+  }
+};
--- a/browser/devtools/styleinspector/test/browser.ini
+++ b/browser/devtools/styleinspector/test/browser.ini
@@ -69,16 +69,19 @@ support-files =
 [browser_ruleview_colorpicker-multiple-changes.js]
 [browser_ruleview_colorpicker-release-outside-frame.js]
 [browser_ruleview_colorpicker-revert-on-ESC.js]
 [browser_ruleview_colorpicker-swatch-displayed.js]
 [browser_ruleview_completion-existing-property_01.js]
 [browser_ruleview_completion-existing-property_02.js]
 [browser_ruleview_completion-new-property_01.js]
 [browser_ruleview_completion-new-property_02.js]
+[browser_ruleview_computed_01.js]
+[browser_ruleview_computed_02.js]
+[browser_ruleview_completion-popup-hidden-after-navigation.js]
 [browser_ruleview_content_01.js]
 [browser_ruleview_content_02.js]
 skip-if = e10s # Bug 1039528: "inspect element" contextual-menu doesn't work with e10s
 [browser_ruleview_context-menu-show-mdn-docs-01.js]
 [browser_ruleview_context-menu-show-mdn-docs-02.js]
 [browser_ruleview_context-menu-show-mdn-docs-03.js]
 [browser_ruleview_copy_styles.js]
 [browser_ruleview_cubicbezier-appears-on-swatch-click.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_ruleview_completion-popup-hidden-after-navigation.js
@@ -0,0 +1,38 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the ruleview autocomplete popup is hidden after page navigation
+
+let TEST_URL = "data:text/html;charset=utf-8,<h1 style='font: 24px serif'></h1>";
+
+add_task(function*() {
+  yield addTab(TEST_URL);
+  let {inspector, view} = yield openRuleView();
+
+  info("Test autocompletion popup is hidden after page navigation");
+
+  info("Selecting the test node");
+  yield selectNode("h1", inspector);
+
+  info("Focusing the css property editable field");
+  let propertyName = view.styleDocument.querySelectorAll(".ruleview-propertyname")[0];
+  let editor = yield focusEditableField(view, propertyName);
+
+  info("Pressing key VK_DOWN");
+  let onSuggest = once(editor.input, "keypress");
+  EventUtils.synthesizeKey("VK_DOWN", {}, view.styleWindow);
+
+  info("Waiting for autocomplete popup to be displayed");
+  yield onSuggest;
+  yield wait(1);
+
+  ok(view.popup && view.popup.isOpen, "Popup should be opened");
+
+  info("Reloading the page");
+  yield reloadPage(inspector);
+
+  ok(!(view.popup && view.popup.isOpen), "Popup should be closed");
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_ruleview_computed_01.js
@@ -0,0 +1,47 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the rule view shows expanders for properties with computed lists.
+
+let TEST_URI = `
+  <style type="text/css">
+    #testid {
+      margin: 4px;
+      top: 0px;
+    }
+  </style>
+  <h1 id="testid">Styled Node</h1>
+`;
+
+add_task(function*() {
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+  let {inspector, view} = yield openRuleView();
+  yield selectNode("#testid", inspector);
+  yield testExpandersShown(inspector, view);
+});
+
+function* testExpandersShown(inspector, view) {
+  let rule = getRuleViewRuleEditor(view, 1).rule;
+
+  info("Check that the correct rules are visible");
+  is(rule.selectorText, "#testid", "Second rule is #testid.");
+  is(rule.textProps[0].name, "margin", "First property is margin.");
+  is(rule.textProps[1].name, "top", "Second property is top.");
+
+  info("Check that the expanders are shown correctly");
+  is(rule.textProps[0].editor.expander.style.visibility, "visible",
+      "margin expander is visible.");
+  is(rule.textProps[1].editor.expander.style.visibility, "hidden",
+      "top expander is hidden.");
+  ok(!rule.textProps[0].editor.expander.hasAttribute("open"),
+      "margin computed list is closed.");
+  ok(!rule.textProps[1].editor.expander.hasAttribute("open"),
+      "top computed list is closed.");
+  ok(!rule.textProps[0].editor.computed.hasChildNodes(),
+      "margin computed list is empty before opening.");
+  ok(!rule.textProps[1].editor.computed.hasChildNodes(),
+      "top computed list is empty.");
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_ruleview_computed_02.js
@@ -0,0 +1,68 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the rule view computed lists can be expanded/collapsed,
+// and contain the right subproperties.
+
+let TEST_URI = `
+  <style type="text/css">
+    #testid {
+      margin: 0px 1px 2px 3px;
+      top: 0px;
+    }
+  </style>
+  <h1 id="testid">Styled Node</h1>
+`;
+
+add_task(function*() {
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+  let {inspector, view} = yield openRuleView();
+  yield selectNode("#testid", inspector);
+  yield testComputedList(inspector, view);
+});
+
+function* testComputedList(inspector, view) {
+  let rule = getRuleViewRuleEditor(view, 1).rule;
+  let propEditor = rule.textProps[0].editor;
+  let expander = propEditor.expander;
+
+  ok(!expander.hasAttribute("open"), "margin computed list is closed");
+
+  info("Opening the computed list of margin property")
+  expander.click();
+  ok(expander.hasAttribute("open"), "margin computed list is open");
+
+  let computed = propEditor.prop.computed;
+  let computedDom = propEditor.computed;
+  let propNames = [
+    "margin-top",
+    "margin-right",
+    "margin-bottom",
+    "margin-left"
+  ];
+
+  is(computed.length, propNames.length, "There should be 4 computed values");
+  is(computedDom.children.length, propNames.length, "There should be 4 nodes in the DOM");
+  propNames.forEach((propName, i) => {
+    let propValue = i + "px";
+    is(computed[i].name, propName, "Computed property #" + i + " has name " + propName);
+    is(computed[i].value, propValue, "Computed property #" + i + " has value " + propValue);
+    is(computedDom.getElementsByClassName("ruleview-propertyname")[i].textContent, propName,
+        "Computed property #" + i + " in DOM has correct name");
+    is(computedDom.getElementsByClassName("ruleview-propertyvalue")[i].textContent, propValue,
+        "Computed property #" + i + " in DOM has correct value");
+  });
+
+  info("Closing the computed list of margin property")
+  expander.click();
+  ok(!expander.hasAttribute("open"), "margin computed list is closed");
+
+  info("Opening the computed list of margin property")
+  expander.click();
+  ok(expander.hasAttribute("open"), "margin computed list is open");
+  is(computed.length, propNames.length, "Still 4 computed values");
+  is(computedDom.children.length, propNames.length, "Still 4 nodes in the DOM");
+}
--- a/browser/devtools/styleinspector/test/browser_ruleview_copy_styles.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_copy_styles.js
@@ -191,17 +191,20 @@ add_task(function*() {
 });
 
 function* checkCopyStyle(view, node, menuItem, expectedPattern, hidden) {
   let onPopup = once(view._contextmenu._menupopup, "popupshown");
   EventUtils.synthesizeMouseAtCenter(node,
     {button: 2, type: "contextmenu"}, view.styleWindow);
   yield onPopup;
 
-  is(view._contextmenu.menuitemCopy.hidden, true, "Copy hidden is as expected: true");
+  ok(view._contextmenu.menuitemCopy.disabled,
+    "Copy disabled is as expected: true");
+  ok(!view._contextmenu.menuitemCopy.hidden,
+    "Copy hidden is as expected: false");
 
   is(view._contextmenu.menuitemCopyLocation.hidden,
      hidden.copyLocation,
      "Copy Location hidden attribute is as expected: " +
      hidden.copyLocation);
 
   is(view._contextmenu.menuitemCopyPropertyDeclaration.hidden,
      hidden.copyPropertyDeclaration,
--- a/browser/devtools/styleinspector/test/browser_ruleview_edit-property-computed.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-property-computed.js
@@ -59,9 +59,17 @@ function* editAndCheck(view) {
     "padding-left"
   ];
 
   is(computed.length, propNames.length, "There should be 4 computed values");
   propNames.forEach((propName, i) => {
     is(computed[i].name, propName, "Computed property #" + i + " has name " + propName);
     is(computed[i].value, newPaddingValue, "Computed value of " + propName + " is as expected");
   });
+
+  propEditor.expander.click();
+  let computedDom = propEditor.computed;
+  is(computedDom.children.length, propNames.length, "There should be 4 nodes in the DOM");
+  propNames.forEach((propName, i) => {
+    is(computedDom.getElementsByClassName("ruleview-propertyvalue")[i].textContent,
+        newPaddingValue, "Computed value of " + propName + " in DOM is as expected");
+  });
 }
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -192,20 +192,22 @@ skip-if = e10s # Bug 1042253 - webconsol
 [browser_output_breaks_after_console_dir_uninspectable.js]
 [browser_output_longstring_expand.js]
 [browser_repeated_messages_accuracy.js]
 skip-if = buildapp == 'mulet'
 [browser_result_format_as_string.js]
 [browser_warn_user_about_replaced_api.js]
 [browser_webconsole_abbreviate_source_url.js]
 [browser_webconsole_allow_mixedcontent_securityerrors.js]
+tags = mcb
 skip-if = buildapp == 'mulet'
 [browser_webconsole_assert.js]
 [browser_webconsole_basic_net_logging.js]
 [browser_webconsole_block_mixedcontent_securityerrors.js]
+tags = mcb
 skip-if = buildapp == 'mulet'
 [browser_webconsole_bug_579412_input_focus.js]
 [browser_webconsole_bug_580001_closing_after_completion.js]
 [browser_webconsole_bug_580030_errors_after_page_reload.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
 [browser_webconsole_bug_580454_timestamp_l10n.js]
 [browser_webconsole_bug_582201_duplicate_errors.js]
 skip-if = e10s # Bug 1042253 - webconsole tests disabled with e10s (expectUncaughtException)
--- a/browser/devtools/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_block_mixedcontent_securityerrors.js
@@ -58,44 +58,22 @@ function pushPrefEnv() {
   let options = {"set": [
                   ["security.mixed_content.block_active_content", true],
                   ["security.mixed_content.block_display_content", true]
                 ]};
   SpecialPowers.pushPrefEnv(options, deferred.resolve);
   return deferred.promise;
 }
 
-function waitForNotificationShown(notification, callback) {
-  if (PopupNotifications.panel.state == "open") {
-    executeSoon(callback);
-    return;
-  }
-  PopupNotifications.panel.addEventListener("popupshown", function onShown() {
-    PopupNotifications.panel.removeEventListener("popupshown", onShown);
-    callback();
-  }, false);
-  notification.reshow();
-}
-
 function mixedContentOverrideTest2(hud, browser) {
-  let notification = PopupNotifications.getNotification("bad-content", browser);
-  ok(notification, "Mixed Content Doorhanger did appear");
   let deferred = promise.defer();
-  waitForNotificationShown(notification, () => {
-    afterNotificationShown(hud, notification, deferred);
-  });
-  return deferred.promise;
-}
-
-function afterNotificationShown(hud, notification, deferred) {
-  ok(PopupNotifications.panel.firstChild.isMixedContentBlocked,
-     "OK: Mixed Content is being blocked");
-  // Click on the doorhanger.
-  PopupNotifications.panel.firstChild.disableMixedContentProtection();
-  notification.remove();
+  let {gIdentityHandler} = browser.ownerGlobal;
+  ok(gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"),
+    "Mixed Active Content state appeared on identity box");
+  gIdentityHandler.disableMixedContentProtection();
 
   waitForMessages({
     webconsole: hud,
     messages: [
       {
         name: "Logged blocking mixed active content",
         text: "Loading mixed (insecure) active content " +
               "\"http://example.com/\" on a secure page",
@@ -109,16 +87,18 @@ function afterNotificationShown(hud, not
           " \"http://example.com/tests/image/test/mochitest/blue.png\"" +
           " on a secure page",
         category: CATEGORY_SECURITY,
         severity: SEVERITY_WARNING,
         objects: true,
       },
     ],
   }).then(msgs => deferred.resolve(msgs), Cu.reportError);
+
+  return deferred.promise;
 }
 
 function testClickOpenNewTab(hud, match) {
   let warningNode = match.clickableElements[0];
   ok(warningNode, "link element");
   ok(warningNode.classList.contains("learn-more-link"), "link class name");
   return simulateMessageLinkClick(warningNode, LEARN_MORE_URI);
 }
--- a/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
@@ -8,43 +8,44 @@
 
 <!ENTITY privateBrowsing.title                 "Private Browsing">
 
 <!-- LOCALIZATION NOTE (aboutPrivateBrowsing.width):
      Width of the Private Browsing section.
      -->
 <!ENTITY aboutPrivateBrowsing.width            "25em">
 <!ENTITY aboutPrivateBrowsing.title            "You're browsing privately">
-<!ENTITY aboutPrivateBrowsing.subtitle         "&brandShortName; won't remember any history for this window.">
+<!ENTITY aboutPrivateBrowsing.subtitle         "In this window, &brandShortName; will not remember any history.">
 
+<!ENTITY aboutPrivateBrowsing.forgotten        "In this window, &brandShortName; will not remember:">
 <!ENTITY aboutPrivateBrowsing.info.forgotten   "Forgotten">
 <!ENTITY aboutPrivateBrowsing.info.history     "History">
-<!ENTITY aboutPrivateBrowsing.info.search      "Search">
+<!ENTITY aboutPrivateBrowsing.info.search      "Searches">
 <!ENTITY aboutPrivateBrowsing.info.cookies     "Cookies">
 <!ENTITY aboutPrivateBrowsing.info.temporaryFiles "Temporary Files">
 
+<!ENTITY aboutPrivateBrowsing.kept             "&brandShortName; will keep:">
 <!ENTITY aboutPrivateBrowsing.info.kept        "Kept">
 <!ENTITY aboutPrivateBrowsing.info.downloads   "Downloads">
 <!ENTITY aboutPrivateBrowsing.info.bookmarks   "Bookmarks">
 
-<!ENTITY aboutPrivateBrowsing.note             "Your employer or Internet service provider can still track the pages you visit.">
+<!ENTITY aboutPrivateBrowsing.note             "Please note that your employer or Internet service provider can still track the pages you visit.">
 <!ENTITY aboutPrivateBrowsing.learnMore        "Learn More.">
 
 <!-- LOCALIZATION NOTE (trackingProtection.width):
      Width of the Tracking Protection section. This should be enough to
      accommodate the title as well as the enabled or disabled indicator.
      -->
 <!ENTITY trackingProtection.width              "22em">
 <!ENTITY trackingProtection.title              "Tracking Protection">
 
 <!-- LOCALIZATION NOTE (trackingProtection.state.width):
      Width of the element representing the enabled or disabled indicator.
      -->
 <!ENTITY trackingProtection.state.width        "6ch">
 <!ENTITY trackingProtection.state.enabled      "ON">
 <!ENTITY trackingProtection.state.disabled     "OFF">
 
-<!ENTITY trackingProtection.description.enabled "Private Windows now block content that tracks your browsing activity.">
-<!ENTITY trackingProtection.description.disabled "Private Windows will not block content that tracks your browsing activity.">
+<!ENTITY trackingProtection.description        "Private Windows now block parts of the page that may track your browsing activity.">
 
 <!ENTITY trackingProtection.disable            "Turn Tracking Protection Off">
 <!ENTITY trackingProtection.enable             "Turn Tracking Protection On">
 <!ENTITY trackingProtection.startTour          "See how this works">
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -787,29 +787,16 @@ you can use these alternative items. Oth
 
 <!ENTITY getUserMedia.selectCamera.label "Camera to share:">
 <!ENTITY getUserMedia.selectCamera.accesskey "C">
 <!ENTITY getUserMedia.selectMicrophone.label "Microphone to share:">
 <!ENTITY getUserMedia.selectMicrophone.accesskey "M">
 <!ENTITY getUserMedia.audioCapture.label "Audio from the tab will be shared.">
 <!ENTITY getUserMedia.allWindowsShared.message "All visible windows on your screen will be shared.">
 
-<!-- Bad Content Blocker Doorhanger Notification -->
-<!ENTITY badContentBlocked.moreinfo "Most websites will work properly even if content is blocked.">
-
-<!ENTITY mixedContentBlocked2.message "Insecure content">
-<!ENTITY mixedContentBlocked2.moreinfo "Some unencrypted elements on this website have been blocked.">
-<!ENTITY mixedContentBlocked2.learnMore "Learn More">
-<!ENTITY mixedContentBlocked2.options "Options">
-<!ENTITY mixedContentBlocked2.unblock.label "Disable protection for now">
-<!ENTITY mixedContentBlocked2.unblock.accesskey "D">
-<!ENTITY mixedContentBlocked2.block.label "Enable protection">
-<!ENTITY mixedContentBlocked2.block.accesskey "E">
-<!ENTITY mixedContentBlocked2.disabled.message "Protection is disabled">
-
 <!ENTITY trackingProtection.title "Tracking Protection">
 <!ENTITY trackingProtection.detectedBlocked3 "&brandShortName; is blocking parts of the page that may track your browsing.">
 <!ENTITY trackingProtection.detectedNotBlocked3 "This site includes elements that may track your browsing. You have disabled protection.">
 <!ENTITY trackingProtection.notDetected3 "No tracking elements detected on this page.">
 <!-- LOCALIZATION NOTE (trackingProtection.unblock.label, trackingProtection.unblock.accesskey):
      The associated button with this label and accesskey is only shown when opening the control
      center while looking at a site with trackers in NON-private browsing mode. -->
 <!ENTITY trackingProtection.unblock.label "Disable protection for this site">
--- a/browser/locales/en-US/chrome/browser/migration/migration.dtd
+++ b/browser/locales/en-US/chrome/browser/migration/migration.dtd
@@ -38,8 +38,9 @@
 <!ENTITY migrating.label                "The following items are currently being imported…">
 
 <!ENTITY selectProfile.title            "Select Profile">
 <!ENTITY selectProfile.label            "The following profiles are available to import from:">
 
 <!ENTITY done.title                     "Import Complete">
 <!ENTITY done.label                     "The following items were successfully imported:">
 
+<!ENTITY closeSourceBrowser.label       "Please ensure the selected browser is closed before continuing.">
--- a/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
@@ -3,20 +3,20 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <!ENTITY tracking.label                 "Tracking">
 
 <!ENTITY dntTrackingNotOkay4.label     "Request that sites not track you">
 <!ENTITY dntTrackingNotOkay4.accesskey "n">
 <!ENTITY doNotTrackInfo.label          "Learn More">
 <!ENTITY trackingProtection5.label     "Use Tracking Protection">
-<!ENTITY trackingProtection5.accesskey "m">
+<!ENTITY trackingProtection5.accesskey "i">
 <!ENTITY trackingProtectionLearnMore.label "Learn more">
 <!ENTITY trackingProtectionPBM5.label         "Use Tracking Protection in Private Windows">
-<!ENTITY trackingProtectionPBM5.accesskey     "y">
+<!ENTITY trackingProtectionPBM5.accesskey     "v">
 <!ENTITY trackingProtectionPBMLearnMore.label "Learn more">
 
 <!ENTITY  history.label                 "History">
 
 <!ENTITY  locationBar.label             "Location Bar">
 
 <!ENTITY  locbar.suggest.label          "When using the location bar, suggest:">
 <!ENTITY  locbar.history.label          "History">
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1740,17 +1740,16 @@ toolbarbutton.chevron > .toolbarbutton-i
 
 #full-screen-domain-text {
   font-size: 300%;
 }
 
 %include ../shared/devtools/responsivedesign.inc.css
 %include ../shared/devtools/commandline.inc.css
 %include ../shared/plugin-doorhanger.inc.css
-%include ../shared/badcontent-doorhanger.inc.css
 %include ../shared/login-doorhanger.inc.css
 
 %include downloads/indicator.css
 
 .gcli-panel {
   padding: 0;
 }
 
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5bd63855384b43f126f39b8de28d2562ca4d6fb4
GIT binary patch
literal 411
zc$@*70c8G(P)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B0004ENkl<ZcmbV~
z1899=7{>Q^T9|EQYgse1Yx~d2%{J0avu$r-Hp6Ti@%m`*sr%N|cTe4?o`Vm+`hMq_
z=!>bjT`;sjt@b7cLW2CWv~w*wI6OX6D3r>viK!(XW(+7ix1gklQw3nOv7mzOoxMv0
zZEf#<AqeijutE?Yzu*WFP17ub(zElo(G{VN`alJ%>l+6Md3}46TRFJbPE5@#(-2NA
z{5wCcer$xq$0VdSvMkGCN-L_5V7!o`D2CG$nOsgG2qD(yw$6nQk5BKo=>Gme0$;C@
zU)b2veydbctU3hXY*TB;jW(!YaCmG%ePL8gBJZY9<)IBa4_#F2ylUK010<D76$lv}
zpL~Haksdc>M+mBGY`KOrGwT~$U-quv{rniojUh+2&{pUibO;(ja%0GmI?$1yz!Kb$
z9jPCY<VD?y@Slxdgq#S4>_xx{!4b&|!HF>RmwJWPe*-|9;An^MDJlQ}002ovPDHLk
FV1graw~_z=
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bd75b4432b79e2ce46383ab7a998a34e5883f3ca
GIT binary patch
literal 453
zc$@*n0XqJPP)<h;3K|Lk000e1NJLTq000sI000sQ1ONa4{KrPz0004uNkl<ZcmZ{h
zGoT$o6o&uVz4ndmG_jhfifyNh*+*Tfpowj}OclQOnrFqfo%QZ4XKwhNX2;*2pMXQN
zNW$d<(eN7r-$I^dJ8x}Q+-o@+0sq;A?DE0!-py5Y7XBgxM&k3-yc98;fAQ~y1EIfd
zqN#PQes*v2T?r4UbVe<L*}#z9l)1btsR;<v`4@Vv_%>JYG%PE1tY#}-g}f7uXZO$s
z=D#cA@cP^xd2jP?5fct-=+ks;^~7oTO{{)(P9j#+Sa}@g*gF&kaSIr8k2y6SJ3rDm
z_Cty;DNa@an-8ELM7WqJ!-qgzn$bkkgsvZEAL+H^`|L0kE&soC8rQ3e@X8Y$b6<@#
zk=LKZQ+Y<SugyO-`P}%6Q(qfO%2f8;`;CXu4=->D;jwp1TIhrX8BmOQ00#npA`*l#
zi1~1*ONBl)>b~^*OcA0bngkY2oU7P{*R130rWT#AHvSSZ;7&V7Kc?>vC9nPpc*1?J
vJAzY$l5r2g_|0h|x8W{@O$?qrPoHB0`Kp^Hw(n{|00000NkvXXu0mjfhl<k^
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -61,21 +61,16 @@ browser.jar:
   skin/classic/browser/menuPanel-customize.png
   skin/classic/browser/menuPanel-customize@2x.png
   skin/classic/browser/menuPanel-exit.png
   skin/classic/browser/menuPanel-exit@2x.png
   skin/classic/browser/menuPanel-help.png
   skin/classic/browser/menuPanel-help@2x.png
   skin/classic/browser/menuPanel-small.png
   skin/classic/browser/menuPanel-small@2x.png
-  skin/classic/browser/bad-content-blocked-16.png           (../shared/bad-content-blocked-16.png)
-  skin/classic/browser/bad-content-blocked-16@2x.png        (../shared/bad-content-blocked-16@2x.png)
-  skin/classic/browser/bad-content-blocked-64.png           (../shared/bad-content-blocked-64.png)
-  skin/classic/browser/bad-content-unblocked-16.png         (../shared/bad-content-unblocked-16.png)
-  skin/classic/browser/bad-content-unblocked-64.png         (../shared/bad-content-unblocked-64.png)
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
   skin/classic/browser/notification-16.png
   skin/classic/browser/notification-64.png
 * skin/classic/browser/pageInfo.css
   skin/classic/browser/pageInfo.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/pointerLock-16.png
@@ -159,16 +154,18 @@ browser.jar:
   skin/classic/browser/customizableui/customizeFavicon.ico  (../shared/customizableui/customizeFavicon.ico)
   skin/classic/browser/customizableui/info-icon-customizeTip.png  (../shared/customizableui/info-icon-customizeTip.png)
   skin/classic/browser/customizableui/menuPanel-customizeFinish.png  (../shared/customizableui/menuPanel-customizeFinish.png)
   skin/classic/browser/customizableui/menuPanel-customizeFinish@2x.png  (../shared/customizableui/menuPanel-customizeFinish@2x.png)
   skin/classic/browser/customizableui/panelarrow-customizeTip.png  (../shared/customizableui/panelarrow-customizeTip.png)
 * skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
   skin/classic/browser/customizableui/subView-arrow-back-inverted.png  (../shared/customizableui/subView-arrow-back-inverted.png)
   skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png  (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
+  skin/classic/browser/customizableui/thumburger.png  (customizableui/thumburger.png)
+  skin/classic/browser/customizableui/thumburger-inverted.png  (customizableui/thumburger-inverted.png)
   skin/classic/browser/customizableui/whimsy.png  (../shared/customizableui/whimsy.png)
   skin/classic/browser/customizableui/whimsy@2x.png  (../shared/customizableui/whimsy@2x.png)
   skin/classic/browser/customizableui/whimsy-bw.png  (../shared/customizableui/whimsy-bw.png)
   skin/classic/browser/customizableui/whimsy-bw@2x.png  (../shared/customizableui/whimsy-bw@2x.png)
   skin/classic/browser/downloads/allDownloadsViewOverlay.css   (downloads/allDownloadsViewOverlay.css)
   skin/classic/browser/downloads/buttons.png          (downloads/buttons.png)
   skin/classic/browser/downloads/contentAreaDownloadsView.css  (../shared/downloads/contentAreaDownloadsView.css)
   skin/classic/browser/downloads/download-glow-menuPanel.png (downloads/download-glow-menuPanel.png)
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -1656,16 +1656,21 @@ toolbarbutton[constrain-size="true"][cui
 }
 
 @conditionalForwardWithUrlbar@:-moz-locale-dir(rtl) {
   -moz-box-direction: reverse;
 }
 
 %include ../shared/identity-block/identity-block.inc.css
 
+#identity-box {
+  padding-top: 2px;
+  padding-bottom: 2px;
+}
+
 #urlbar:not([focused="true"]) > #identity-box {
   margin-top: -1px;
   margin-bottom: -1px;
   padding-top: 3px;
   padding-bottom: 3px;
 }
 
 @media (-moz-mac-yosemite-theme) {
@@ -3357,17 +3362,16 @@ notification[value="loop-sharing-notific
 
 #full-screen-domain-text {
   font-size: 300%;
 }
 
 %include ../shared/devtools/responsivedesign.inc.css
 %include ../shared/devtools/commandline.inc.css
 %include ../shared/plugin-doorhanger.inc.css
-%include ../shared/badcontent-doorhanger.inc.css
 %include ../shared/login-doorhanger.inc.css
 
 %include downloads/indicator.css
 
 /* On mac, the popup notification contents are indented by default and so
   the default closebutton margins from notification.css require adjustment */
 
 .click-to-play-plugins-notification-description-box > .popup-notification-closebutton {
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..43f4d3661d9c44e7a519de83c9808a81c6714ed4
GIT binary patch
literal 427
zc$@*N0aX5pP)<h;3K|Lk000e1NJLTq000sI000sQ1ONa4{KrPz0004UNkl<ZcmZ|J
zL%<e60LJnE&b!&Reap7ZYrN#TWZRdlOT1*;cAt6qY$G>2FLoyP+p+fH7bU4i9V%n<
zU!F!y;-7uXe|?nd{8xp;D^;;7{8m6K{$QTAsNQ1)5@Hi5$sYu+QqwxOZi9l$L3pT7
z<G@$nO(^uy8uMoeP&psAK7O)9MyS9iBi`(yGFtg{b5y>{Re5{PGUmH)WWKLCv~)As
zRU6HmkA&2sm8VI+_I!93TL4Js#w)bycTf6mWvkrzhv-T>Cb60=Z1vR@jH8zOQq>-V
zaNtht?t4$?bsH``XpVewz2^%Z{Q9de>RtNe17vm`DkNXbCuHYARCHg;ov@or<Pl2g
zt1m`$u`M*IuD?dJsZ0Z!(UcB4&n8y0n1#$@Al1R#s{VRMhtVdDbROLuu$5fCQ|$Y`
zn?o(-Q{kX+S>Gtxn^-h~cKOwJ5LmuXNOkQE|4^NQ%wnPbbQZ(LmCswE%}i&(@B+tT
Vnp=?T#LfT!002ovPDHLkV1i-;&mRB)
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..51b10235542e6acc6516882383ea73ccb190d8ac
GIT binary patch
literal 809
zc$@(#1J?YBP)<h;3K|Lk000e1NJLTq001Na001Ni1ONa4O9@aD0008;Nkl<ZcmdUv
z1FZB290%vww*AhwZQHgT96#IN*|u%lwr_3oa{tFwyWMOW-f!YGQ%#G;3Mi+UZaS!=
z7~LzNYSG@Nx8sh`pP%12)I$k6S91Cm5vznHG*0;2`)NSu>fXF=T;Ug=_$3f?(x>;v
zdM)3IH$l+K+UQ!@c?XL>De}GZA?xY8p5~99Ocz~t8^h>W$?jW39pXvgFjt*Ko1W`w
zeB(~>Cq>>n-e5=SXrPNe`qSv6iw5m5N_N>SVi$LUxND=US##Z??;nU+C74Ov`osMj
z^<`HT(DdFt;!BD=&waxF^ndf91SOD#;1_pMpY?s6z5BmzaV3bmwwT9yj6|&B5my#G
z5i7l@R!GOMuZcH#nEQ#3Ig}RG30cLJosgBaP_6p5^TaRC1VQ_nGuePL)_(pCafvev
zt|wnni%NIgFz}bSQwLr9ItS810e!XSKJuyGChko9wnsmyJzM$t6w&d^^Wqi9G)}|c
zRTr~1r9cBaa|sJs&Wbdavye;JN%^pAp1MkW;!KGCa~^dkyU|J`T@0}$hjT8MaA_JB
za~Aucdi`C2KgKooX&euK%t?%_GyMJiQM3566S02r$ht#H(P-G3(){^n(-mw^*EbJ{
zPrNzseQ~Gq*4BLCb#Y8-f|l)XU~gI&h*-oW_8hn(7G+0$wP)Y^zQY)|ef9HxcXAAa
zl(2TlB(~gy%*xk4{${v{1uWqjj%Ph8DPZmAUK4vxk^PC6m7)?l*_OjNntfP@8VZ2%
zejfhVZ`Qgozxk1m)Ez+y^>oogD-{%iW<S~;sf3At&u~URmv9m1a0(|*a{@=OJzbP&
zXg2Ks?!Kr|JZd85kDln<mSOs*>CW|IYxw$p@rX+U&lh)4PhRVb7{w-L4Qvr3z2vpE
zLk2Nx6Ed(?o}y=86^ocOusrc%UZUxCKJpvHDi#G+zu}P&mECAhyB+OrG%D(1dye3Q
nL@#-EqY-2`{b~~3{9iT(%A8ljb+}Oe00000NkvXXu0mjf>+q4_
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ca66dcbb431e796cdc5fdc630765760baa951a32
GIT binary patch
literal 263
zc$@(T0r>ujP)<h;3K|Lk000e1NJLTq000sI000sQ1ONa4{KrPz0002aNkl<ZcmZP|
z5%{wBZu0%&+l*I{zn|}a-~WE!@hS@51X2`p5}##Cet$rUs><;w3RnzM68!SIv~R2L
zPaqozfpjafITpVEK*AMW|C#)LL6m@9_!XgqIp7jVDD>e&IR=Kj#eTn`N`B`qf-CZ?
zhY0rO{%2%h_^<fi?!N;V+W%KXDEbIelDhT35ZpbOZpxqU|0C|iO??IixO*_&^k3n>
z?SI|>%n0{jx(NXg?m@T-8NgkGa0@2z`-SEfOn`6=!Y#O6gK!I}005_2ui)Uw1Ni^|
N002ovPDHLkV1nNdcn<&o
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..348ccd0339d9c2f4e85669753c9f54be8aa13a43
GIT binary patch
literal 477
zc$@*<0V4j1P)<h;3K|Lk000e1NJLTq001Na001Ni1ONa4O9@aD0004`Nkl<ZcmdUu
z1B_f@6ot3871XwE`@Y(3P}|*LZ7bSfZ5!bR>tMGVYi-wVZ^!cwPVpw1bHnrBd{5uA
zv7XQp%BMF}PmVO$63jH}BGycxC7>6?y6Lw7BvtA`Cwk=H&wTo&2i+)?4+<jIkN-=#
zm~qk@J?2bj-!i!%d+~mrNAM(>_d|VpjP$MKI1iwq6hghkM$@NghhmVMxO^vvXDPa1
zVldtaGm}0G_w&8z91m5ry%5xkKq=zdy$oKcY)`yFAj!O}bWmJ6`LSB!;mZDQ3Ig4a
zGlv;XjpCARC@)Z-^zFW%e)63$<m9{i>3zG+fnvqAbB%9z^APn3&*$A>=9*%zh#2Wt
z_#>X7J>!82)OHidc11hT6x1Ms?x*oa=+B=$5`T;Hb!~@u9Q5bU9^FpTy~GcB*Lc37
zLjL^OqrN?l63%o>->=jp+~y5D2>XLQGX65#d8DEM{$P*vUuG_E;hnsi$EX|N5AX;C
z_yatG0sa7wK!7{I8yMgY@CF9BgS^23?f`FKpgY(b9PAGE2D>A}8|)7D#%l5#g&4LJ
TjgE|J00000NkvXXu0mjfl0@XX
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ddd22f5220d60e808f7c484a0eaac19cd8da4f3e
GIT binary patch
literal 388
zc$@)*0ek+5P)<h;3K|Lk000e1NJLTq000sI000sQ1ONa4{KrPz0003?Nkl<ZcmZP|
z1~4I*(k!wIRIkaF;Z?-$Bxx-Fg+C6jBHmEZPdq=wZ{krTFUMuX{o^OI;yz48EHDOF
zzR)+Oe?NZ~uHRG2nZUxt@SlP4_rGroA9cYM$r}pU@xJ@UrnFn@1#gVp8_wS#(eJE}
zBY}z_*2yvpG>Cp=`uqJ`?PA7%ntOjRe`N*1@677^;MTEaiwg37c*kSCSnde}!^+7F
zvJlNcD<3feDG+ARKc@N~DDrqsm0}`K6#IXczhGg8p9~*X-tU8&q;=?p8Q0Uksf_RR
zBNSe8{epSs8{5Ay2AHB{GZ?lqd|<f7z@WMRo#8*Y*MG2R9J~m#4gvlv!rTLQ(|sgG
z3WYooZ2y`60^Rff7sID@w<f}5po$=lS9#9;6T<$=epmE@9hPX(KJ=CSGbaRoVbeN_
i><C5-*C5<N8UO$n$9DDrgApqL0000<MNUMnLSTYLJF_wX
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8a90a8238c9ab9ff6efc4ffcc8418a898816de3f
GIT binary patch
literal 891
zc$@)y1BCpEP)<h;3K|Lk000e1NJLTq001Na001Ni1ONa4O9@aD0009*Nkl<ZcwW_%
zO=uit9LAsbW2T$#%w~7<(KMMYX^m8J5*05(JxEd8grvlaB8VqNv8V;LqM#HN?LjDb
zQM90-LZ#Y5wSo#B#4nP9CMJG#v$P4Vrn~88cW2+(nfHA?3}ng9E)09??>g|~dH(b8
z;>Kb4=G;fS7e;>^J~GVFJtG5qF5J3!=lmTD<A0C5iWpF|h0J8k!HvQ4V0mC8IfWQ>
zh;7~5S54QM0=TO1u0^>~dn{El0{~!ZXsPRJ{1MwVd?+Zb1-t#{E=7)=ny>{^L=&yh
z5J$f6vKoCfMS2=k0f6Anuf6|vC35WEhtoAf5)DXNHJ<(sCCAV&Cni}68cm3-h_g7h
z>UR*)$1<=4lK|lH^zZu?iFRJf&LllnB50x^nfpLV;Ptj5XC(7bx@-nvo{IVG*SG@M
z_wTrFd0b%&0j(q&(;Y<S(X6oRVV=5?{%!vsqyZ#@Of}h{8e34r@Yn6OH_GkH-j!Vo
z^8~cQUptRW0N~7e<J%jgMWl(xM}L}&ikzhNN`E=Lk0w=f^oQI2A_4$D`0UA<tG7_2
zC6S+9c<0RNsK_|h-;-Gn|Ch(=;;nB{2)|@jKR%82T#i)BO=s^OSnCl~0Rb)dOnzeL
ziI0#xfT74#0$fEQBHI4c;CjmC0f8npBQ^i{JXRb7FD4E$Yg|*sB*E4l`EKpJdIPFe
zWb~G|1w?BIqw2l)CH^EjcQiX~xvWSLML|;IP|3raEuvksVs8=*f?wPA#L1n@qzu^m
zcNSAFQ)r8%<+?u^5uH5q%z-O=b;4YG@biNOECYZg`zp3*?kBP%S=<al5CT00XY+`2
z#07vuZ_}Ils$3C7(FkbKqD!ZqYu!;E3Oit60~bRL@ctKvr&h)oC%TP@$RPXAiF2o#
ziK0YOcIFbvM<2E*d8{BnCjzXXfKG{W23|<q$1MOLnn@<ZVjw}){RYP``Y|6i@_he<
zRbwuR99J?vRrGN@rpUf$=)bhfB_agudd)i!TVyo`HhM+75lU(V*GwR$XxF@#(;g75
zrin23T=*rf=-so2Ckne6L+f^kl<DOYUws-^lwSSt96ECu9iTC{)7;Gs!~dBrM>u2~
Rmi+(#002ovPDHLkV1l$Apl$#F
--- a/browser/themes/osx/devedition.css
+++ b/browser/themes/osx/devedition.css
@@ -92,16 +92,18 @@
   -moz-appearance: none !important;
 }
 
 /* Prevent the hover styling from on the identity icon from overlapping the
    urlbar border. */
 #identity-box {
   margin-top: -1px !important;
   margin-bottom: -1px !important;
+  padding-top: 3px !important;
+  padding-bottom: 3px !important;
 }
 
 /* Tab styling - make sure to use an inverted icon for the selected tab
    (brighttext only covers the unselected tabs) */
 .tab-close-button[visuallyselected=true]:not(:hover) {
   -moz-image-region: rect(0, 64px, 16px, 48px);
 }
 @media (min-resolution: 2dppx) {
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -75,24 +75,16 @@ browser.jar:
   skin/classic/browser/menuPanel-customize.png
   skin/classic/browser/menuPanel-customize@2x.png
   skin/classic/browser/menuPanel-exit.png
   skin/classic/browser/menuPanel-exit@2x.png
   skin/classic/browser/menuPanel-help.png
   skin/classic/browser/menuPanel-help@2x.png
   skin/classic/browser/menuPanel-small.png
   skin/classic/browser/menuPanel-small@2x.png
-  skin/classic/browser/bad-content-blocked-16.png           (../shared/bad-content-blocked-16.png)
-  skin/classic/browser/bad-content-blocked-16@2x.png        (../shared/bad-content-blocked-16@2x.png)
-  skin/classic/browser/bad-content-blocked-64.png           (../shared/bad-content-blocked-64.png)
-  skin/classic/browser/bad-content-blocked-64@2x.png        (../shared/bad-content-blocked-64@2x.png)
-  skin/classic/browser/bad-content-unblocked-16.png         (../shared/bad-content-unblocked-16.png)
-  skin/classic/browser/bad-content-unblocked-16@2x.png      (../shared/bad-content-unblocked-16@2x.png)
-  skin/classic/browser/bad-content-unblocked-64.png         (../shared/bad-content-unblocked-64.png)
-  skin/classic/browser/bad-content-unblocked-64@2x.png      (../shared/bad-content-unblocked-64@2x.png)
   skin/classic/browser/panel-expander-closed.png
   skin/classic/browser/panel-expander-closed@2x.png
   skin/classic/browser/panel-expander-open.png
   skin/classic/browser/panel-expander-open@2x.png
   skin/classic/browser/panel-plus-sign.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/page-livemarks@2x.png
   skin/classic/browser/pageInfo.css
@@ -213,16 +205,20 @@ browser.jar:
   skin/classic/browser/customizableui/menuPanel-customizeFinish@2x.png  (../shared/customizableui/menuPanel-customizeFinish@2x.png)
   skin/classic/browser/customizableui/panelarrow-customizeTip.png  (../shared/customizableui/panelarrow-customizeTip.png)
   skin/classic/browser/customizableui/panelarrow-customizeTip@2x.png  (../shared/customizableui/panelarrow-customizeTip@2x.png)
   skin/classic/browser/customizableui/subView-arrow-back-inverted.png  (../shared/customizableui/subView-arrow-back-inverted.png)
   skin/classic/browser/customizableui/subView-arrow-back-inverted@2x.png  (../shared/customizableui/subView-arrow-back-inverted@2x.png)
   skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png  (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
   skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl@2x.png  (../shared/customizableui/subView-arrow-back-inverted-rtl@2x.png)
 * skin/classic/browser/customizableui/panelUIOverlay.css    (customizableui/panelUIOverlay.css)
+  skin/classic/browser/customizableui/thumburger-inverted.png  (customizableui/thumburger-inverted.png)
+  skin/classic/browser/customizableui/thumburger-inverted@2x.png  (customizableui/thumburger-inverted@2x.png)
+  skin/classic/browser/customizableui/thumburger.png  (customizableui/thumburger.png)
+  skin/classic/browser/customizableui/thumburger@2x.png  (customizableui/thumburger@2x.png)
   skin/classic/browser/customizableui/whimsy.png          (../shared/customizableui/whimsy.png)
   skin/classic/browser/customizableui/whimsy@2x.png       (../shared/customizableui/whimsy@2x.png)
   skin/classic/browser/customizableui/whimsy-bw.png       (../shared/customizableui/whimsy-bw.png)
   skin/classic/browser/customizableui/whimsy-bw@2x.png    (../shared/customizableui/whimsy-bw@2x.png)
   skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
   skin/classic/browser/downloads/buttons.png                (downloads/buttons.png)
   skin/classic/browser/downloads/buttons@2x.png             (downloads/buttons@2x.png)
   skin/classic/browser/downloads/contentAreaDownloadsView.css (../shared/downloads/contentAreaDownloadsView.css)
@@ -614,16 +610,18 @@ browser.jar:
   skin/classic/browser/yosemite/menuPanel-help.png          (menuPanel-help-yosemite.png)
   skin/classic/browser/yosemite/menuPanel-help@2x.png       (menuPanel-help-yosemite@2x.png)
   skin/classic/browser/yosemite/menuPanel-small.png         (menuPanel-small-yosemite.png)
   skin/classic/browser/yosemite/menuPanel-small@2x.png      (menuPanel-small-yosemite@2x.png)
   skin/classic/browser/yosemite/reload-stop-go.png          (reload-stop-go-yosemite.png)
   skin/classic/browser/yosemite/reload-stop-go@2x.png       (reload-stop-go-yosemite@2x.png)
   skin/classic/browser/yosemite/sync-horizontalbar.png      (sync-horizontalbar-yosemite.png)
   skin/classic/browser/yosemite/sync-horizontalbar@2x.png   (sync-horizontalbar-yosemite@2x.png)
+  skin/classic/browser/yosemite/thumburger.png              (customizableui/thumburger-yosemite.png)
+  skin/classic/browser/yosemite/thumburger@2x.png           (customizableui/thumburger-yosemite@2x.png)
   skin/classic/browser/notification-pluginNormal.png  (../shared/plugins/notification-pluginNormal.png)
   skin/classic/browser/notification-pluginAlert.png   (../shared/plugins/notification-pluginAlert.png)
   skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png)
   skin/classic/browser/notification-pluginNormal@2x.png  (../shared/plugins/notification-pluginNormal@2x.png)
   skin/classic/browser/notification-pluginAlert@2x.png   (../shared/plugins/notification-pluginAlert@2x.png)
   skin/classic/browser/notification-pluginBlocked@2x.png (../shared/plugins/notification-pluginBlocked@2x.png)
   skin/classic/browser/devtools/tooltip/arrow-horizontal-dark.png   (../shared/devtools/tooltip/arrow-horizontal-dark.png)
   skin/classic/browser/devtools/tooltip/arrow-horizontal-dark@2x.png   (../shared/devtools/tooltip/arrow-horizontal-dark@2x.png)
@@ -644,16 +642,18 @@ browser.jar:
 % override chrome://browser/skin/feeds/videoFeedIcon.png                   chrome://browser/skin/feeds/feedIcon.png
 % override chrome://browser/skin/feeds/videoFeedIcon16.png                 chrome://browser/skin/feeds/feedIcon16.png
 % override chrome://browser/skin/toolbarbutton-dropmarker.png              chrome://browser/skin/lion/toolbarbutton-dropmarker.png                 os=Darwin osversion>=10.7
 % override chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon.png     chrome://browser/skin/lion/tabbrowser/alltabs-box-bkgnd-icon.png        os=Darwin osversion>=10.7
 % override chrome://browser/skin/tabview/tabview.png                       chrome://browser/skin/lion/tabview/tabview.png                          os=Darwin osversion>=10.7
 % override chrome://browser/skin/places/toolbar.png                        chrome://browser/skin/lion/places/toolbar.png                           os=Darwin osversion>=10.7
 % override chrome://browser/skin/Toolbar.png                               chrome://browser/skin/yosemite/Toolbar.png                              os=Darwin osversion>=10.10
 % override chrome://browser/skin/Toolbar@2x.png                            chrome://browser/skin/yosemite/Toolbar@2x.png                           os=Darwin osversion>=10.10
+% override chrome://browser/skin/customizableui/thumburger.png             chrome://browser/skin/yosemite/thumburger.png                           os=Darwin osversion>=10.10
+% override chrome://browser/skin/customizableui/thumburger@2x.png          chrome://browser/skin/yosemite/thumburger@2x.png                        os=Darwin osversion>=10.10
 % override chrome://browser/skin/menuPanel.png                             chrome://browser/skin/yosemite/menuPanel.png                            os=Darwin osversion>=10.10
 % override chrome://browser/skin/menuPanel@2x.png                          chrome://browser/skin/yosemite/menuPanel@2x.png                         os=Darwin osversion>=10.10
 % override chrome://browser/skin/loop/menuPanel.png                        chrome://browser/skin/yosemite/loop/menuPanel.png                       os=Darwin osversion>=10.10
 % override chrome://browser/skin/loop/menuPanel@2x.png                     chrome://browser/skin/yosemite/loop/menuPanel@2x.png                    os=Darwin osversion>=10.10
 % override chrome://browser/skin/loop/toolbar.png                          chrome://browser/skin/yosemite/loop/toolbar.png                         os=Darwin osversion>=10.10
 % override chrome://browser/skin/loop/toolbar@2x.png                       chrome://browser/skin/yosemite/loop/toolbar@2x.png                      os=Darwin osversion>=10.10
 % override chrome://browser/skin/menuPanel-customize.png                   chrome://browser/skin/yosemite/menuPanel-customize.png                  os=Darwin osversion>=10.10
 % override chrome://browser/skin/menuPanel-customize@2x.png                chrome://browser/skin/yosemite/menuPanel-customize@2x.png               os=Darwin osversion>=10.10
deleted file mode 100644
index 7cf33ec4c5acc81330208f5f5ac45fa5435c3d1a..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index c2e49b3a7fb616bf5b84f1e99575e8d1658d2321..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 75cf7f9faa547f9a632b4b95674ddbbb15852083..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 4ef0a5cb1a2a7eaad57d78d2a7015d0c4a9c9711..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 2bf0868ab1d28c333dfc06248f6c44a441f5822c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index faa2a785688c29af52639cab9f0401d2b685e91b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 54eb9f365f75d3870858cd7d7ac3544c176a642e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index e147189c4b3df0ecb0d3cb7914e1f69b17f16050..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/browser/themes/shared/badcontent-doorhanger.inc.css
+++ /dev/null
@@ -1,21 +0,0 @@
-.popup-notification-item-title[popupid="bad-content"] {
-  font-weight: bold;
-}
-
-.popup-notification-item-message[popupid="bad-content"] {
-  width: 17em;
-}
-
-.popup-notification-item-message[popupid="bad-content"][mixedblockdisabled]:not(.popup-notification-item-message-critical),
-.popup-notification-item-message[popupid="bad-content"][trackingblockdisabled]:not(.popup-notification-item-message-critical) {
-  color: GrayText;
-}
-
-.popup-notification-item-message-critical[popupid="bad-content"] {
-  color: #d74345;
-  font-style: italic;
-}
-
-.popup-notification-footer[popupid="bad-content"] {
-  padding-top: 1em;
-}
--- a/browser/themes/shared/devedition.inc.css
+++ b/browser/themes/shared/devedition.inc.css
@@ -5,16 +5,17 @@
 /* devedition.css is loaded in browser.xul after browser.css when it is
    preffed on.  The bulk of the styling is here in the shared file, but
    there are overrides for each platform in their devedition.css files. */
 
 :root {
   --tab-toolbar-navbar-overlap: 0px;
   --space-above-tabbar: 0px;
   --toolbarbutton-text-shadow: none;
+  --backbutton-urlbar-overlap: 0px;
 }
 
 :root[devtoolstheme="dark"] {
   /* Chrome */
   --chrome-background-color: #1C2126;
   --chrome-color: #F5F7FA;
   --chrome-secondary-background-color: #39424D;
   --chrome-navigator-toolbox-separator-color: rgba(0,0,0,.2);
--- a/browser/themes/shared/devtools/performance.css
+++ b/browser/themes/shared/devtools/performance.css
@@ -216,20 +216,20 @@
   width: 5vw;
 }
 
 .call-tree-header[type="samples"],
 .call-tree-cell[type="samples"] {
   width: 4.5vw;
 }
 
-.call-tree-header[type="allocations"],
-.call-tree-cell[type="allocations"],
-.call-tree-header[type="self-allocations"],
-.call-tree-cell[type="self-allocations"] {
+.call-tree-header[type="count"],
+.call-tree-cell[type="count"],
+.call-tree-header[type="self-count"],
+.call-tree-cell[type="self-count"] {
   width: 9vw;
 }
 
 .call-tree-header[type="function"],
 .call-tree-cell[type="function"] {
   -moz-box-flex: 1;
 }
 
--- a/browser/themes/shared/identity-block/identity-block.inc.css
+++ b/browser/themes/shared/identity-block/identity-block.inc.css
@@ -20,17 +20,17 @@
 
   border-inline-end: 1px solid var(--identity-box-border-color);
   border-image: linear-gradient(transparent 15%,
                                 var(--identity-box-border-color) 15%,
                                 var(--identity-box-border-color) 85%,
                                 transparent 85%);
   border-image-slice: 1;
   font-size: .9em;
-  padding: 2px 5px;
+  padding: 3px 5px;
   margin-inline-end: 4px;
   overflow: hidden;
 }
 
 #identity-box:hover,
 #identity-box[open=true] {
   background-color: var(--identity-box-selected-background-color);
   border-image-source: none;
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -65,25 +65,16 @@
   list-style-image: url(chrome://mozapps/skin/passwordmgr/key-64.png);
 }
 
 .popup-notification-icon[popupid="webapps-install-progress"],
 .popup-notification-icon[popupid="webapps-install"] {
   list-style-image: url(chrome://global/skin/icons/webapps-64.png);
 }
 
-.popup-notification-icon[popupid="bad-content"] {
-  list-style-image: url(chrome://browser/skin/bad-content-blocked-64.png);
-}
-
-.popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
-.popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
-  list-style-image: url(chrome://browser/skin/bad-content-unblocked-64.png);
-}
-
 .popup-notification-icon[popupid="webRTC-sharingDevices"],
 .popup-notification-icon[popupid="webRTC-shareDevices"] {
   list-style-image: url(chrome://browser/skin/webRTC-shareDevice-64.png);
 }
 
 .popup-notification-icon[popupid="webRTC-sharingMicrophone"],
 .popup-notification-icon[popupid="webRTC-shareMicrophone"] {
   list-style-image: url(chrome://browser/skin/webRTC-shareMicrophone-64.png);
@@ -216,26 +207,16 @@
   from {
     opacity: 0;
   }
   to {
     opacity: 1;
   }
 }
 
-.bad-content-blocked-notification-icon,
-#bad-content-blocked-notification-icon {
-  list-style-image: url(chrome://browser/skin/bad-content-blocked-16.png);
-}
-
-.bad-content-unblocked-notification-icon,
-#bad-content-unblocked-notification-icon {
-  list-style-image: url(chrome://browser/skin/bad-content-unblocked-16.png);
-}
-
 .webRTC-shareDevices-notification-icon,
 #webRTC-shareDevices-notification-icon {
   list-style-image: url(chrome://browser/skin/webRTC-shareDevice-16.png);
 }
 
 .webRTC-sharingDevices-notification-icon,
 #webRTC-sharingDevices-notification-icon {
   list-style-image: url(chrome://browser/skin/webRTC-sharingDevice-16.png);
@@ -416,24 +397,16 @@
   #plugins-notification-icon:hover {
     -moz-image-region: rect(0, 64px, 32px, 32px);
   }
 
   #plugins-notification-icon:active {
     -moz-image-region: rect(0, 96px, 32px, 64px);
   }
 
-  #bad-content-blocked-notification-icon {
-    list-style-image: url(chrome://browser/skin/bad-content-blocked-16@2x.png);
-  }
-
-  #bad-content-unblocked-notification-icon {
-    list-style-image: url(chrome://browser/skin/bad-content-unblocked-16@2x.png);
-  }
-
   .web-notifications-notification-icon,
   #web-notifications-notification-icon {
     list-style-image: url(chrome://browser/skin/notification-16@2x.png);
   }
 
   .pointerLock-notification-icon,
   #pointerLock-notification-icon {
     list-style-image: url(chrome://browser/skin/pointerLock-16@2x.png);
@@ -458,25 +431,16 @@
   .popup-notification-icon[popupid="push"] {
     list-style-image: url(chrome://browser/skin/Push-64@2x.png);
   }
 
   .popup-notification-icon[popupid="web-notifications"] {
     list-style-image: url(chrome://browser/skin/notification-64@2x.png);
   }
 
-  .popup-notification-icon[popupid="bad-content"] {
-    list-style-image: url(chrome://browser/skin/bad-content-blocked-64@2x.png);
-  }
-
-  .popup-notification-icon[popupid="bad-content"][mixedblockdisabled],
-  .popup-notification-icon[popupid="bad-content"][trackingblockdisabled] {
-    list-style-image: url(chrome://browser/skin/bad-content-unblocked-64@2x.png);
-  }
-
   .popup-notification-icon[popupid="pointerLock"] {
     list-style-image: url(chrome://browser/skin/pointerLock-64@2x.png);
   }
 
   .popup-notification-icon[popupid="servicesInstall"] {
     list-style-image: url(chrome://browser/skin/social/services-64@2x.png);
   }
 
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -7,16 +7,17 @@
 :root {
   --tab-toolbar-navbar-overlap: 1px;
   --tab-min-height: 31px;
 }
 #TabsToolbar {
   --tab-separator-image: url(chrome://browser/skin/tabbrowser/tab-separator.png);
   --tab-separator-size: 3px 100%;
   --tab-separator-opacity: 1;
+  --tab-stroke-background-size: auto 100%;
 }
 
 %define tabCurveWidth 30px
 %define tabCurveHalfWidth 15px
 
 /* image preloading hack */
 #tabbrowser-tabs::before {
   /* Because of bug 853415, we need to ordinal this to the first position: */
@@ -371,31 +372,31 @@
 
 .tab-background-middle[visuallyselected=true] {
   background-clip: padding-box, padding-box, content-box;
   background-color: @fgTabBackgroundColor@;
   background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
                     @fgTabTexture@,
                     none;
   background-repeat: repeat-x;
-  background-size: auto 100%;
+  background-size: var(--tab-stroke-background-size), auto 100%;
   /* The padding-top combined with background-clip: content-box (the bottom-most) ensure the
      background-color doesn't extend above the top border. */
   padding-top: 2px;
 }
 
 /* Selected tab lightweight theme styles.
    See browser-lightweightTheme.css for information about run-time changes to LWT styles. */
 .tab-background-middle[visuallyselected=true]:-moz-lwtheme {
   background-color: transparent;
   background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
                     @fgTabTextureLWT@;/*,
                     lwtHeader;*/
   /* Don't stretch the LWT header images */
-  background-size: auto 100%, auto 100%, auto auto;
+  background-size: var(--tab-stroke-background-size), auto 100%, auto auto;
 }
 
 /* These LWT styles are normally overridden by browser-lightweightTheme.css */
 .tab-background-start[visuallyselected=true]:-moz-lwtheme::before,
 .tab-background-end[visuallyselected=true]:-moz-lwtheme::before {
   background-image: @fgTabTextureLWT@;
 }
 
--- a/browser/themes/shared/toolbarbuttons.inc.css
+++ b/browser/themes/shared/toolbarbuttons.inc.css
@@ -119,16 +119,25 @@ toolbar[brighttext] #sync-button[status=
 #preferences-button[cui-areatype="toolbar"] {
   -moz-image-region: rect(0, 468px, 18px, 450px);
 }
 
 #PanelUI-menu-button {
   -moz-image-region: rect(0, 486px, 18px, 468px);
 }
 
+#PanelUI-menu-button.thumburger {
+  list-style-image: url("chrome://browser/skin/customizableui/thumburger.png") !important;
+  -moz-image-region: auto !important;
+}
+
+toolbar[brighttext] #PanelUI-menu-button.thumburger {
+  list-style-image: url("chrome://browser/skin/customizableui/thumburger-inverted.png") !important;
+}
+
 #edit-controls:not(@inAnyPanel@) > #cut-button {
   -moz-image-region: rect(0, 504px, 18px, 486px);
 }
 
 #edit-controls:not(@inAnyPanel@) > #copy-button {
   -moz-image-region: rect(0, 522px, 18px, 504px);
 }
 
@@ -425,16 +434,24 @@ toolbar[brighttext] #loop-button {
   #pocket-button[cui-areatype="toolbar"][open] {
 %ifdef XP_MACOSX
     -moz-image-region: rect(72px, 1548px, 108px, 1512px);
 %else
     -moz-image-region: rect(36px, 1548px, 72px, 1512px);
 %endif
   }
 
+  #PanelUI-menu-button.thumburger {
+    list-style-image: url("chrome://browser/skin/customizableui/thumburger@2x.png") !important;
+  }
+
+  toolbar[brighttext] #PanelUI-menu-button.thumburger {
+    list-style-image: url("chrome://browser/skin/customizableui/thumburger-inverted@2x.png") !important;
+  }
+
   #loop-button {
     list-style-image: url("chrome://browser/skin/loop/toolbar@2x.png");
     -moz-image-region: rect(0, 36px, 36px, 0);
   }
 
   toolbar[brighttext] #loop-button {
     list-style-image: url("chrome://browser/skin/loop/toolbar-inverted@2x.png");
   }
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -312,25 +312,25 @@
   /* Position the toolbar above the bottom of background tabs */
   position: relative;
   z-index: 1;
 }
 
 #nav-bar {
   background-clip: padding-box;
   background-image: linear-gradient(@toolbarHighlight@, transparent);
-  box-shadow: 0 1px 0 @toolbarHighlight@ inset;
 }
 
 @media (-moz-os-version: windows-xp),
        (-moz-os-version: windows-vista),
        (-moz-os-version: windows-win7),
        (-moz-os-version: windows-win8) {
   #nav-bar {
     border-top: 1px solid @toolbarShadowColor@ !important;
+    box-shadow: 0 1px 0 @toolbarHighlight@ inset;
   }
   @media not all and (-moz-windows-compositor) {
     #TabsToolbar[collapsed="true"] + #nav-bar {
       border-top-style: none !important;
     }
   }
 }
 
@@ -604,22 +604,30 @@ menuitem.bookmark-item {
   :-moz-any(@primaryToolbarButtons@),
   #bookmarks-menu-button.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
     list-style-image: url("chrome://browser/skin/Toolbar-lunaSilver.png");
   }
 
   #loop-button {
     list-style-image: url(chrome://browser/skin/loop/toolbar-lunaSilver.png)
   }
+
+  #PanelUI-menu-button.thumburger {
+    list-style-image: url("chrome://browser/skin/customizableui/thumburger-lunaSilver.png") !important;
+  }
 }
 
 @media (-moz-windows-theme: luna-silver) and (min-resolution: 1.1dppx) {
   #loop-button {
     list-style-image: url(chrome://browser/skin/loop/toolbar-lunaSilver@2x.png)
   }
+
+  #PanelUI-menu-button.thumburger {
+    list-style-image: url("chrome://browser/skin/customizableui/thumburger-lunaSilver@2x.png") !important;
+  }
 }
 
 #main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon,
 #main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker,
 #main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-dropmarker,
 #main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 #main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled=true] > .toolbarbutton-icon {
   opacity: .4;
@@ -2045,20 +2053,18 @@ richlistitem[type~="action"][actiontype=
   @media not all and (-moz-os-version: windows-vista) {
     @media not all and (-moz-os-version: windows-win7) {
       @media not all and (-moz-os-version: windows-win8) {
         .tab-background-end[visuallyselected=true]::after,
         .tab-background-start[visuallyselected=true]::after {
           content: none;
         }
 
-        .tab-background-middle[visuallyselected=true] {
-          /* Setting background-size to "0 0" for the first
-             background-image to remove the stroke. */
-          background-size: 0 0, auto 100%, auto 100%;
+        #TabsToolbar {
+          --tab-stroke-background-size: 0 0;
         }
 
         :root {
           --tab-toolbar-navbar-overlap: 0;
         }
       }
     }
   }
@@ -2584,17 +2590,16 @@ notification[value="loop-sharing-notific
 
 #full-screen-domain-text {
   font-size: 300%;
 }
 
 %include ../shared/devtools/responsivedesign.inc.css
 %include ../shared/devtools/commandline.inc.css
 %include ../shared/plugin-doorhanger.inc.css
-%include ../shared/badcontent-doorhanger.inc.css
 %include ../shared/login-doorhanger.inc.css
 
 %include downloads/indicator.css
 
 /* Error counter */
 
 #developer-toolbar-toolbox-button[error-count]:before {
   color: #FDF3DE;
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6e83c40f310af3f6a852834d42de2a662ad1a7e2
GIT binary patch
literal 610
zc$@)Z0-gPdP)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B0006hNkl<Zc-ozm
z-*3`T6vyX-Jeg>g_=3?V6K9r4U_(Y_?SNXK5I{hx@?#WAC{kc_j$x)T#3vIIt^b0_
zc<~QV{{(&a)r_cd+ndRfr5KO*EX-B9jBPjh<o2H2esc2dNhc0l0C1jQHDH-I;X=uo
zet+YN(?0dlapUR^O*vkp>@=baLMl>V7n~4}c!8#DyQdXdgY2yj57J>M=93^KL!Ys>
z-|ar*B<G%Y*WBTN=Xa%)hC((5kK2uBC^`bmq1|vk_q*)92q<y}NLQObzJIg%Xs70y
zxvsmN(?H#v2HagUQ##{uX!y>k<YGn2MWQ_ON0GB2O9FIO8W{8?KQpVNTq-09sl7cT
zM8L<)?x4shIlHy_^D^gieJP76SZ<0S<`Vtw?JYZARH}uZn2QfkUM&lNJDzLu;`*q_
z%5$EV8G(nkDnYGsAKturv4Y(Ub8rv>grI@Iux=R<QNNayJUnU^p;;5(liIa_->or}
zO%M9#AR3y7c$oPIf7`8-udA6lTB?`dR*LD}nw<O8-}p)o<+?1Tp`|Q>T0a2KSP!w3
zIU@q*!4W9JBwkP(<zC}qX3%bxU{yT;&scBO%l~C$6k3ckV$Q~#(Ghbrr+Me?dcg03
zC{M%PJ1htZ4iZtXo`|t~nH*=btuda~F^8uenNS@flWg)t%os8mBU)Xq_Bv{5&|OoY
w`(y}t##&pgt{+!qG3R2=<i!6aBjfJ>1*8Z7gEeRF#{d8T07*qoM6N<$f~6%M_5c6?
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..726537f3ced8569131b7f58b143ee362463c1ed0
GIT binary patch
literal 1443
zc$@*F1zh@xP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ000GQNkl<ZcmdUy
z18_8X5XHavvu!JOvPNv%TpO`-wr$(C3uoKL?w;M(JvB9Tw{@A!R_$%orRo>H-g)Wn
z|C`wbfqVc!7!rvrLY5$lk!U0wSr7~Y5r-oSk+sNXKb9j=NLVNh#ULAPX01FaZtwlE
z2eyA3cX0a$qRhl&KltFi?EtU>i3pXUaJt~>r=E})e`x1d>B;*cJ3SV%(hfm#{2u&1
z?i{vLF`+UPP2Ew-GA1Qi@laMIhuX?KsHw<-e04UYCGGdIhL(iFP#Alm&Em}XXR6B7
z(A{1Q{oVD@*Hs5C4JDwGrF|VrLlMa8ks*gjEl>Zmv$YEJ{mmRb9W~I}SaA<)XkjP}
z(M2}P#i{31ma0J0(*Ood3rBl%1sr$G%rI)!A(8*Jp>Sm7_19f>KqgA`wKbK2QQHD0
zT`PedYQm9~e&O?ZMWkcRFF}^g18HKA2>+-M)E$*9{pgYcDbpRZzMZ4Ly8&!w%_XQg
zfUGBNfUHEKgc{<yBgsnewl<cci8inrI|%xo#`Wt{Pd-+Qx-GA~{Nj$x)Y$Xl5AE<^
zJ^>%7@sgHm{PT<NWG!O5a}sq&*VhDga~Fp}(+oyk$L**|A{}PYx#`IV07nZ-X$mi-
zA+01U@iZ>K<}nnBtT}RKJROUF?r5oCOgODQ4D@|(XYFr~Jp4c_>b4_j=&+}vM2TH1
z$CFo$)XYIOqp2uS0M+=%#ayFeatB9sD_z8-YXP^tmxCFdsrzQsqyu|zE65S~XvZ9u
zZqo2V8qyZzWc%hb6vi&{rpCImMzuT@!><-xwq6)?_7n6y1>z4czW7`n>Nc=<{LPx)
z<{R+T(FIAz3u$l#kk+f_8(Ac>`kuRQ--kQ#QDbc({x@AP?A9_2xiq-Y?Jz!KKNodr
ztoaCJrPu2za9aCs()84Sr|WCLi#5(c1CWNaRKvH_;eWeDTvu8srK~|CIv5?)GYmNT
zLD%2(!FS(%TgV>sMaWWQHEXaSK;n?-xsE+^11&378C0@VT-q8mqk-{Z1A&HgxI3+X
zUUAv^cGM;QOYUr8P2~zOlFMq>@)=@wL6i~qVQWJ%3_AK?YShFqIbwtXW;gUVqDDy<
zfAy7@c8D_K&r6Ei?MaN?1t|%8n8y)mb^^%7NuZbmIf5FmLXvtOy$0XNm~j>5iNCes
zo{*85aSOv3b;r>D?&qI>T8^4Mq{9q3SCkP8xr%f=Em=?~5Ykc&)yl-lyg3wuY}RYq
zu6LL_VS3EWm>C~3fJNW-{e$=4)dK)2$ZFEbvJ*W`b%kKSlVvrugUu)m(ozl8;%o5c
z5OZ35UQgk~i1iw~sq-s*f!~~#o)>Su<ys>E$l1cB$mYrth0ks4hS>=V95rnZ2&$pl
z$`Uzm4uv66$YG?w4<)h+2?w^5W_{-kgU&uUa>@?J%sK-CYj8(<F+#fM%ONg{b|IOF
z1W9BUFU+r#1!F_zn_Ske@7(qtjD%i6kd|tw);C8E@e#&~WBi_T_;W`%hXQ!~;6}L8
zFK+_P9VH_5Bbz;~k-{I)*wIi{;1NGBHF2*eHDNE{R|a}3MDIXUvJ}WwrvC%ABF$Tr
zCpqtp*I(swCK!*f%<{@b$>+*NiBOy;g7PAnAV^C!N=Yi0Gr=&#1f^1z;^}UyV2<hN
zfCkadgND&|VGY)DITJKP_0@U4=}{w`di)5SaniUTNJ};KRk>Ww1Z`vvOYaS{<7PPR
zgi$#2<OxBLb_Q!)w*ISvI5IYGeBOeY3Fl4YgSzh~M+|t6Gx9<j(oT;%Z=%{DE;V=T
xV}qG9{0IxiNH#OF5h*|XIV03i2>2fx`U^8ElquT~$|?W=002ovPDHLkV1oRyuNMFS
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0d4b56a4a9ec8e262635f4deea1d4a762cdad8d2
GIT binary patch
literal 565
zc$@(>0?Pe~P)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B0005}Nkl<Zc-pm)
zOKcKR6oxgra@)GnM69&bN?T|<4Uc3<d4y^y(3F`0rr=D0!7>7+(1eIZ8$;^Cor&z-
zx-sreYGdNgsC$?0T@cMc;_tnY+Ql`dnWQKAbLO0re7W<TJJY&)<JLusZT5}T&h@TM
z%sep-8n@3!T}vwnMpJOO13yiJ=DdN|v2-5dW*LD<;>Z+aY-(<d53dbmZ3l_$7KBV*
zHwBtm^u3JB8kBMqD}wUv?cvdgb(-tkbb1Us$76bt2kmseKI!QE6JoV55H-TDyZ4)r
zi#tfEr9A-WIeyuQr3;WYE0A&|q({lj@!=i=vDh3J$l<e;ucA<EBfg=1{rKt2WqOMz
z)$Y2Y_tV8XWD?rRJcvum3kEdlbhjhP9E!X9*x1^I-e_g$Yv>KYD9Jd<#Bql6C<F3@
zqTkg@3tIgVM5Xi!z$F6jINW~29bAR)P6A62@ozlAs4+F~WgQ8b;&U;#{X<ms!*}mL
zSm@3hiWy0*2DSPS>h?+KoGjERjCBNHWcb`G$G;?I?{%}KW?!rCLu;Ib&SXCjvPISr
zTdbS^IAY5->*_eYLBr*bfO-k7$q27!;a`=E1%8=0Ic527Ck*O9e{ewZbeIF;rA5KL
zQ-jj^a<|ZU+^_6CL$&=U^qcGksa%<HV!{jK<ZS9U7hgUF%ElUq00000NkvXXu0mjf
D-pLg9
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..061ff53c4ca6d5f58fbc4c98992693f249f5037e
GIT binary patch
literal 1270
zc$@+D1PS|zP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ000ENNkl<Zc-rlj
z>rb0y7{+H*qS3?{r%N1%0R_sT&@#?AV3xxG3k-o43X~owEiG*+g${<C3WLpU&~0jF
z4A|i*Gtp0)_{Hz~7nnt(j>D#=-OvxlC3<<^Z-C%|mL?5+*^~Sd;JvP=7x(kr_uE4c
zSESdA@u{gt6Vg755vAXcPE7xvejg(qJE$;6;*v9e7E22u$t^)f&IyPzazFtuA4s6s
zB*}oZ;3VV<C2E>9IMvvJ;);4CN%HO;NT5_%(N|RsYN!l$w3`N??s4LDyAio1mA~wJ
z7&<CZep&TjEm|wOtnO_%Tvfg5lYI{)O3#_EsBc4uc@WyZ;cc2U7MLAw!@h=z5oJ7+
zRdDiNV~0ryp|gz$Xe@3hRJ!%sE347_8Yn(hHd<QUMEAx8y<>D6HQgg+muUgOQ~O$-
z%)HV7UtYcaEV`Xzj1cJ6&fY&h`1sQT0FOkA(xZ+hrg>wNGyQQXSqKJc0<0yX!VZ*>
zD)Vr4I(mm-9GKWfV>yFnjp;)G&us=@;Q1sgk|XCtB~i5tm4b$~<e3YvI!TgPX~E0C
zQzc+@j>9xK#R!2^di#TS-@jP~K$y~L*~NajLWRaoGn6_Tl=@wuXRKi@d%_AtQ~0L5
zt`%K<BQU$Cx6#tkskD}507tg8g>prpt!Ds6*CcC#!Wz~V%3leDGj}R;OHXknU>fqk
zGJK8^epVXnzkUA2m-zr5-_k3TT}z#oA^Jc;8x+>G)A(pmX|M0~sGg>B{#dKj3dhrT
zc22-LGAmqWopta$fERXpZm+C~)kcS}&Dg&|-N+yKzwk5Gu$Dc03Y3_3e3>t@hGveH
zg4kZWAYeW-gVt`xcX#goBnI&4P7i?RiR3Uj95M{Gr8=ji3N3oOP!Y%YMTP@$z(1!h
zcv}HH`)?n&K39!M+(VE=*0LvLptR#J{ZQ9tplVFRIeA&2f8r8MbnaS<%Lm{XZ$!bP
z=<V-~7t8z!Y1t5E<bu4Qu0(cm`L1xwOK7f<-phN03`Aci?(3+FIEc%$AYdCkPjkq1
z>ziBOW&wDTb;nY&7BX^6KrdVrl`Dw4J)#gi?4><I&!PHO{i4A+MuFxr;PJvX_Bu4y
z;a}gm@lh4ulPz6lewn{ksY5#rOs#zsTF2gCEqiKPbl^Qg23lELPwlo3zpd>XxvR5}
zKG0a*U(dg}cp5<5&NDBoX$}}&Q&hn#aG!f4EZD=|((2|Qb0~PXh=_ljcT-2tlG#0j
zp_ywKo_i}S*kc-+Mzh8oY7T98%V8pcNFrj0C;n5()pfDnHsUk%k8c?1b<#8F*%Pc~
zkKQ)y<2??AwZgAt<mXW66?*Q3HHX4m+}_eC!kd_$;}=PCk+eyQw1B%r_)3viR!!7w
zQq6x0&@(R)btuw{hTej-P>$lt29(w`fx0UwtYIyC$U7JDK(gX;f1{=s-L6SkMrMh*
z5X=hN#?D@_H{yXR8q@*D*hP%bFJkJ74^vlf1cf!MWe<BJ9!RC@TXIe=V8ZKz=jt*%
z*WL>XYgpSqF^@Kb?Rvxmt*+e>n+7L*bQBwQ`mgQdmx96?)|y=7KK4dD5YL-~n=_&3
gP55)>;fnD38`U2W56Hvl>;M1&07*qoM6N<$f{6%VUH||9
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5bd63855384b43f126f39b8de28d2562ca4d6fb4
GIT binary patch
literal 411
zc$@*70c8G(P)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B0004ENkl<ZcmbV~
z1899=7{>Q^T9|EQYgse1Yx~d2%{J0avu$r-Hp6Ti@%m`*sr%N|cTe4?o`Vm+`hMq_
z=!>bjT`;sjt@b7cLW2CWv~w*wI6OX6D3r>viK!(XW(+7ix1gklQw3nOv7mzOoxMv0
zZEf#<AqeijutE?Yzu*WFP17ub(zElo(G{VN`alJ%>l+6Md3}46TRFJbPE5@#(-2NA
z{5wCcer$xq$0VdSvMkGCN-L_5V7!o`D2CG$nOsgG2qD(yw$6nQk5BKo=>Gme0$;C@
zU)b2veydbctU3hXY*TB;jW(!YaCmG%ePL8gBJZY9<)IBa4_#F2ylUK010<D76$lv}
zpL~Haksdc>M+mBGY`KOrGwT~$U-quv{rniojUh+2&{pUibO;(ja%0GmI?$1yz!Kb$
z9jPCY<VD?y@Slxdgq#S4>_xx{!4b&|!HF>RmwJWPe*-|9;An^MDJlQ}002ovPDHLk
FV1graw~_z=
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..072821422c3c8c42ec2e77e9ce190f61bbe23105
GIT binary patch
literal 754
zc$@+90uB9%P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ0008HNkl<ZcmeH}
z1F#-T5QT49FSc#lc3y0iV-{lDww-I+wr$(CCf!v#;m+OLu})S0nzJ+K@0$5`Rj6vv
ztnDGF<Db-2l^-k&(vAlZ)ejBC7hSY`&F#>z@W`_A^76dA{5)-41G^S&yPTB9m;I<P
zV{pL{V<%rK0kKbHX=UTa1OL$OyjIn)U^0SkmHm`J2?>cQOh$!;g+DG3?h9OK&ith}
zYinznoXjk&Qh!(=zL1r*ts4_)!<L=Cl5gYp4l@-O>OElCxze(-awemU%*^s;Z8~Z2
z;KW+_McvWT(X(X&-MRNL4m`K$VTk+!<LnQ*Q^sUeSy@%nf9PmC@SSMgvBxPJTYGo#
zmNEt5eCWk%q)-d$-5moX69*=cj-DZI=4a@$wy|?(M46abIM=I7VAzGGNz><Es{#qS
zQ#)+*L|5>gMKA9RMR<*3AQ)`KO@96XAxt0*EuCcWsB&*{ad8DB3ZP%E7>FD8960i-
zj)|&!^&jd4zVqC#uBn~Ch<fo#HC_~mhuMOI-Fgo?o1b5h&jh-B?Pd)4-teP~?{I^)
zQPa>$E-EUjVhTbJdhr_3rp7Q`cv?>{p8zIMVq#KB^ERDvqBEZy-`7y~#Cj?04xbqQ
zy$%zorly81UAfK=d{1O}azYAaRgWN6lJ|sSAb7^fX9B6JYvD#VC2)tpAweL~Eg~*H
zzPL@No{r$TM&J&CLxMnXoa1FqRn_>(Gd;1*+(+yTokJg-7Tc#UUL|H_XO|=V`~w2>
z;nBkf#!R42(z){$9IE5ASVLWe>O$rYfkUEDi=^Xd0c8uN4|Ro))44<Ckb-ysUUcrz
zIV6-I2%S4(4y`74hRz$>^A5Q?G~N(6LlvDjM9xq}=M9}RB++?8=L|`7-q1Ni7M(YA
k&X9$yp!0^vnSUbaEvU<0PSGiBbpQYW07*qoM6N<$f@^?e7ytkO
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..198a6934815c0df410c7e92600232127aabe60ba
GIT binary patch
literal 619
zc$@)i0+juUP)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B0006qNkl<Zc-pm-
z-D}fO7{=!m>-Wc>;DrdXtKp4<U2Lo-*rw}ZSwdUVrnYIKwpnJfYO>N{x5+4sD7ZVt
zJ7L9tV0gO=FT^`91~QO>jNJ*!NQ<xUJ5sl{1Gj+(e&oDQ;5qMk&N+Pt4FKpz&LHQI
z(^U5zagfQ0_4SXJhKISep`q~4v9Z`PnH|UI)Z}C?$uMz<MsqMS!tYRL$1yq^3MJPB
z;SnSf1_*-snY5#toGg{9gB+J`$#Mxqu>j@r(md+teJ-}~>j34~lMSuRank!_atah>
z7LBy+M&tVc%Zl#kXv_-+1!zMx!w4?r*OQH+JZ5=b`K@Uc$Ye_3IL}|9eiifb(rFXT
z9a>=bOEt^Je|6+X?QLv)y%LF}zNo4Lx?Y7;YO1ldwSAMWfv%V9iA1p}%NDf3x>YDR
zs~sItF)@*@$+8KSwFLS6Q&?GfYomU_&tnjYBKO+(^#JACaZ=H!{KGI7z%b^aSe*TU
z+O<eTa>HTCi^XzydKzZ-;4eI%^~T3jZcj(1`RrXLWA3QxlTVwQ-)>VkJb&LKW7}TF
zy!N1)bo}3&5po>~BDcsG3Czq?>zd{?r>7U78`N94ct=Lvh5`SMT<*$-M<PfFxr;E!
zjRW5ynee>qVkTZZ{tzTd2iz`Xvlh)gQOvuCdUv#6H1Ou;UP7(*8hJzP&Pl_6ekT7m
z3g9KITh?N;Qh5RUL9J!mi>rt2sNdiB9m=6iPbU9!`~g|n{q5IvW7z-z002ovPDHLk
FV1m23GiLw*
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..96cd8912db8d3b3990afbcf52d616d1a647102d4
GIT binary patch
literal 1345
zc$@)21-|-;P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ000FDNkl<ZcmeH~
z1#lZ@5QS57!x=0yGjk1Nv00HKFrQ3fHk>$Mc9=P3W@cvQ;WD>^GH!P@7fudlG#YAV
zzL?(rdiU?{vph}8KL9ucDMZSU8OU^`1SvqK<pQY%#TJX_lB=$&d;IdtHJQsUQ-3Ox
z%^!d6xtC{?seBtM2!}^by5b7W_f=IokjqUVlNq7Bya_5R8#e$zX}%4WsMW@}Ty6xd
zwg(n0uz_B0g}S;<xcch)G_^3_hGtY(>)zCA`=GTo0PXGl(AE|NqtOLu^2dA|D)e~5
z7b=y_|F*RFfnkPr(cJ7sW6mdN(DP}iOsO<%q*gJ^Aar%HSuB<zFc=&#HMK5=nxcFe
zDp<RA+tG5lA>G>Qh3@VU^z?)YGK8~a{Vtu(TtbnMFGHmojd@I~?arF9T4THD=m>((
z7rzlTha&}~<z{J?05dpkfmA~U>(*_j+ex*x`N3w3f!&@U$Pf;+^Us%Ge#1cd^w2|3
z%&V@Rzq!1;K3QJg2>jHiNJ};Qni9O7ni}(Rovs%RM8V}+w2Ph|7L5%(f|^rECztCt
zDHKL%XkdVDlMm967Uyy`)rvJ#$g)e$R;!zTXP5zSyBCAUGn|DC;XM8I+;gvVqV7;+
zhD^2~X*RoX*oV+8H)jVVl+}<{CetUWR*WGU(CI3b@m`b3fd&?W-#@wwn~iQO@&Ibi
z-kDML^&M%eH3DAmFll%p4QZ)HtfAu8R-3+|p)=d6Kwu2|`zHt-;t}ZV4E*}udmov|
z^v>4WY=igo_OkSXq~nD&-Q7draD;9b)3SnVuf6pMmCE$F#S(;Ia1@4yrm_qUPU0ak
zh(^bEpzh2)Ym&*d((8@g&oKU<EtY<4%YmVvk%qKXBQVsvT6LS*?95&*%PxaZXgPuA
z#_-7oKL6>bpEdhF88_T=M1^PsP;uImgx0=TukW&IwOuqfWCCwvRhDpgInB<$H{5XN
zAnJ}kK<>;z&P5a=49So)kRl;N)75J8XMKGv8dwI2#F{Me_-dS^QM{o=_o3!$I_Qx{
zo|=ch{WsI5C=>?37DH`q3$AoKG&Xh~6q?JLnwC^;ZS!V2L#Smlbh_@$z`!^xTC@%p
zFJ4b@w-f&4n{U2rM9n-dpEfl$F}VINOl+SdsD^6m>RJSIsMO^O-R<)&*<~miU5REQ
zzdZ58bA14C>Q3Wzb!|!fK9G5qU5f1$2WhE>YUvE2wJ%7eGOAE$^bVIR`h(LM{mbo+
zzJJd>k9Yy#@;!P!!(_6hBavk=I=TtQ$G1p=YN*y^vWm(f+7=nN32H=%RP0k&ifen%
z;NS!vz8NMbw@ZR*=#~P3gt#0+PT+2&9668MqJ3^MtsEK}x!>bS{OtEH!NZ3|L0YPz
zS~^2$sD+W9JCbvV7oPVyyK;x;1*?$C18@~*M*91q#~yon9<JwR%#LJzeH+x*w`ZYD
z!H58(u@7*-cVRSIL9g#gVZd(2&E#?>ckdWW8yea+nawt!uyi=0q985RXtf<&&g9O}
z41C(;;NUonjBJ33i7m)hUPwb)s?qDaxtz(NA%^j#r>3^T#*MeZ=FNAAg0xh_Fy3^o
z4V4ZIEWT%WczyOowr;&k6r>#<UI#2Ya(k{@R)BxvDC6;|`&oA4=U8kx#N#V?Aq{D%
zhH51bwe-A^o-?^NRKOj4)qyfaYR*VElz;v=B#Hk3kBsHsMe9dx00000NkvXXu0mjf
D6D5#?
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..01290ee6df68d9603bc4a845c8f153e0d084b0c2
GIT binary patch
literal 220
zc%17D@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rhe#hxyXAr*|t3p7`($xL8;<m>Q<
zwPUuX;R*4M|IQ!Hy?COUQ!elo@dh$Iy6?f}Iw|`ClZvw(lcBW0cBYU1Dj)v`)M@KE
z>ook3pY+IQg2f#HpFfhb70)=-$a!8YRY+q!`LN)k{sarN=2sU)c1@Hvdq0t9X7gdy
zmctwxH#m;OH&$p16bo`lyGRH!vBb1+D0?w1UH8Lt4>w2q>2$By7LLh^%nUvg_(XEH
S9Ipa8m%-E3&t;ucLK6UyYD+)>
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8bbad792cc4adbc603fc9ed095d52b9f0e470236
GIT binary patch
literal 379
zc$@)y0fhdEP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ0003(Nkl<ZcmeH|
zwNeC85Jhp91b3I1lobC2{sMP*cL<S;oDU!)Ml;-DEx}>9!TRp&wXRw1s*~O7InR26
zxGPYdJp<)n52(Qf=mTNyl1T;6Kr&;_T|&*~GFnvb5;_nFJ-I`s2>c0zw%j2!4<rE%
za?2zFl|beigvl+`10(^x?${lrK;{FaYjY7`5h#FU1En?_;f&BQ(Rjlsw*VvunQ&Al
z2fPcKeS%!0tilN)g`+~dM6+dWOdcVGtBFP$kgScma%7YC%EW;yqEU-+-t1B<*)KJM
zJ4CZH5H9C4ZzN=XL8aVt=aLXw(8lPw!+B)HFX9NqP?wl@4$&V{gHi{cIp4F_9>oN>
z1)pFaRG8;@g&2zI$R^o@=()pisRPAuGzzyL3B%=`U{GLv-U`1ETHu&7?w&V+ITI+i
Z)ju0I6$?kh1GNAE002ovPDHLkV1hD@oCg2^
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9b54a9de246e1a96f5703239a9fdd606fc2ccb6f
GIT binary patch
literal 201
zc$@*r05<=LP)<h;3K|Lk000e1NJLTq000sI000sQ1ONa4{KrPz0001xNkl<ZcmZP|
z5%{q9Z1VZy(~Mt{ug`xV{DxoA8nB`r_>?I5{01wE#HVNhSjj^lHlJ3XpJ4WXAl-_r
z#KPwvSU3~N1}cHW&j=;VKIg$g*L_%lJcLQVkWBKag9^IgbI*IQk~s)du(-*m(dVnr
zRv#{edobOE00@&1Zo&@;neh{=2^g;VjL#&5TWA6Rp23A5(5B?-00000NkvXXu0mjf
D92iv~
new file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..69381715451cbdb2c9d497c854978b66a352a477
GIT binary patch
literal 343
zc$@)O0jU0oP)<h;3K|Lk000e1NJLTq001Na001Ni1ONa4O9@aD0003VNkl<ZcmeH`
zB~Zpe5XEtqg1bwmQt{Udy$5KxyK6)mojx=&+HiLYZl8a*Gwd9*hr@2VH}C&D+4uMO
zIfY!z;sWcag^vj)8b^3`bgv1h0?)2KHv!EnphGz(15XNQQV#0Fv(jZ!OgPRJ%$9g+
zs3zyBk)P*G!Q3F$qWNI}r<N7%GmGlSgPMqW+@|&8ndx>8lZ0!<c8g@2ddh-MInWHT
z4Ot`!2!+ISiAaaeU#;UcOb9lKsnV`H9{cRgkBw<!TZOM|?BxXWh<s^&HVCNSA~E^V
zT#ft|iwNQ#S(793(FL;kv1`W<KeS^9x0pkoWhnvi1^v}J^b|fn^s#?Nk?fdW1^xQm
p=u1EH(=Pz^o99NC9mCxG*9+@@4p!6jl!E{O002ovPDHLkV1nFnn)v_#
--- a/browser/themes/windows/devedition.css
+++ b/browser/themes/windows/devedition.css
@@ -50,16 +50,22 @@
 
 /* Force 1x image for back/forward button for now, otherwise it breaks the
    layout - Bug 1165360. */
 @media (min-resolution: 1.1dppx) {
   #back-button,
   #forward-button {
     list-style-image: url("chrome://browser/skin/Toolbar.png");
   }
+
+  toolbar[brighttext] #back-button,
+  toolbar[brighttext] #forward-button {
+    list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
+  }
+
   /* The back button region is already set in devedition.inc.css */
   #forward-button {
     -moz-image-region: rect(0px, 72px, 18px, 54px);
   }
 }
 
 #forward-button > .toolbarbutton-icon {
   -moz-border-start: none !important;
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -76,21 +76,16 @@ browser.jar:
         skin/classic/browser/menuPanel-exit.png
         skin/classic/browser/menuPanel-exit@2x.png
         skin/classic/browser/menuPanel-help.png
         skin/classic/browser/menuPanel-help@2x.png
         skin/classic/browser/menuPanel-small.png
         skin/classic/browser/menuPanel-small@2x.png
         skin/classic/browser/menuPanel-small-aero.png
         skin/classic/browser/menuPanel-small-aero@2x.png
-        skin/classic/browser/bad-content-blocked-16.png             (../shared/bad-content-blocked-16.png)
-        skin/classic/browser/bad-content-blocked-16@2x.png          (../shared/bad-content-blocked-16@2x.png)
-        skin/classic/browser/bad-content-blocked-64.png             (../shared/bad-content-blocked-64.png)
-        skin/classic/browser/bad-content-unblocked-16.png           (../shared/bad-content-unblocked-16.png)
-        skin/classic/browser/bad-content-unblocked-64.png           (../shared/bad-content-unblocked-64.png)
         skin/classic/browser/monitor.png
         skin/classic/browser/monitor_16-10.png
         skin/classic/browser/notification-16.png
         skin/classic/browser/notification-64.png
         skin/classic/browser/pageInfo.css
         skin/classic/browser/pageInfo.png
         skin/classic/browser/pageInfo-XP.png
         skin/classic/browser/pointerLock-16.png
@@ -219,16 +214,28 @@ browser.jar:
         skin/classic/browser/customizableui/menu-arrow.svg           (customizableui/menu-arrow.svg)
         skin/classic/browser/customizableui/menuPanel-customizeFinish.png  (../shared/customizableui/menuPanel-customizeFinish.png)
         skin/classic/browser/customizableui/menuPanel-customizeFinish@2x.png  (../shared/customizableui/menuPanel-customizeFinish@2x.png)
         skin/classic/browser/customizableui/panelarrow-customizeTip.png  (../shared/customizableui/panelarrow-customizeTip.png)
 *       skin/classic/browser/customizableui/panelUIOverlay.css       (customizableui/panelUIOverlay.css)
         skin/classic/browser/customizableui/subView-arrow-back-inverted.png  (../shared/customizableui/subView-arrow-back-inverted.png)
         skin/classic/browser/customizableui/subView-arrow-back-inverted@2x.png  (../shared/customizableui/subView-arrow-back-inverted@2x.png)
         skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png  (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
+        skin/classic/browser/customizableui/thumburger-XP.png             (customizableui/thumburger-XP.png)
+        skin/classic/browser/customizableui/thumburger-XP@2x.png          (customizableui/thumburger-XP@2x.png)
+        skin/classic/browser/customizableui/thumburger-aero.png           (customizableui/thumburger-aero.png)
+        skin/classic/browser/customizableui/thumburger-aero@2x.png        (customizableui/thumburger-aero@2x.png)
+        skin/classic/browser/customizableui/thumburger-inverted.png       (customizableui/thumburger-inverted.png)
+        skin/classic/browser/customizableui/thumburger-inverted@2x.png    (customizableui/thumburger-inverted@2x.png)
+        skin/classic/browser/customizableui/thumburger-lunaSilver.png     (customizableui/thumburger-lunaSilver.png)
+        skin/classic/browser/customizableui/thumburger-lunaSilver@2x.png  (customizableui/thumburger-lunaSilver@2x.png)
+        skin/classic/browser/customizableui/thumburger-win8.png           (customizableui/thumburger-win8.png)
+        skin/classic/browser/customizableui/thumburger-win8@2x.png        (customizableui/thumburger-win8@2x.png)
+        skin/classic/browser/customizableui/thumburger.png                (customizableui/thumburger.png)
+        skin/classic/browser/customizableui/thumburger@2x.png             (customizableui/thumburger@2x.png)
         skin/classic/browser/customizableui/whimsy.png  (../shared/customizableui/whimsy.png)
         skin/classic/browser/customizableui/whimsy@2x.png  (../shared/customizableui/whimsy@2x.png)
         skin/classic/browser/customizableui/whimsy-bw.png  (../shared/customizableui/whimsy-bw.png)
         skin/classic/browser/customizableui/whimsy-bw@2x.png  (../shared/customizableui/whimsy-bw@2x.png)
         skin/classic/browser/downloads/allDownloadsViewOverlay.css   (downloads/allDownloadsViewOverlay.css)
         skin/classic/browser/downloads/buttons.png                   (downloads/buttons.png)
         skin/classic/browser/downloads/buttons-XP.png                (downloads/buttons-XP.png)
         skin/classic/browser/downloads/contentAreaDownloadsView.css  (../shared/downloads/contentAreaDownloadsView.css)
@@ -697,16 +704,26 @@ browser.jar:
 % override chrome://browser/skin/loop/menuPanel@2x.png                chrome://browser/skin/loop/menuPanel-aero@2x.png                  os=WINNT osversion=6
 % override chrome://browser/skin/loop/menuPanel@2x.png                chrome://browser/skin/loop/menuPanel-aero@2x.png                  os=WINNT osversion=6.1
 
 % override chrome://browser/skin/Toolbar.png                          chrome://browser/skin/Toolbar-XP.png                              os=WINNT osversion<6
 % override chrome://browser/skin/Toolbar.png                          chrome://browser/skin/Toolbar-aero.png                            os=WINNT osversion=6
 % override chrome://browser/skin/Toolbar.png                          chrome://browser/skin/Toolbar-aero.png                            os=WINNT osversion=6.1
 % override chrome://browser/skin/Toolbar.png                          chrome://browser/skin/Toolbar-win8.png                            os=WINNT osversion=6.2
 % override chrome://browser/skin/Toolbar.png                          chrome://browser/skin/Toolbar-win8.png                            os=WINNT osversion=6.3
+% override chrome://browser/skin/customizableui/thumburger.png        chrome://browser/skin/customizableui/thumburger-XP.png            os=WINNT osversion<6
+% override chrome://browser/skin/customizableui/thumburger.png        chrome://browser/skin/customizableui/thumburger-aero.png          os=WINNT osversion=6
+% override chrome://browser/skin/customizableui/thumburger.png        chrome://browser/skin/customizableui/thumburger-aero.png          os=WINNT osversion=6.1
+% override chrome://browser/skin/customizableui/thumburger.png        chrome://browser/skin/customizableui/thumburger-win8.png          os=WINNT osversion=6.2
+% override chrome://browser/skin/customizableui/thumburger.png        chrome://browser/skin/customizableui/thumburger-win8.png          os=WINNT osversion=6.3
+% override chrome://browser/skin/customizableui/thumburger@2x.png     chrome://browser/skin/customizableui/thumburger-XP@2x.png         os=WINNT osversion<6
+% override chrome://browser/skin/customizableui/thumburger@2x.png     chrome://browser/skin/customizableui/thumburger-aero@2x.png       os=WINNT osversion=6
+% override chrome://browser/skin/customizableui/thumburger@2x.png     chrome://browser/skin/customizableui/thumburger-aero@2x.png       os=WINNT osversion=6.1
+% override chrome://browser/skin/customizableui/thumburger@2x.png     chrome://browser/skin/customizableui/thumburger-win8@2x.png       os=WINNT osversion=6.2
+% override chrome://browser/skin/customizableui/thumburger@2x.png     chrome://browser/skin/customizableui/thumburger-win8@2x.png       os=WINNT osversion=6.3
 % override chrome://browser/skin/loop/toolbar.png                     chrome://browser/skin/loop/toolbar-XP.png                         os=WINNT osversion<6
 % override chrome://browser/skin/loop/toolbar.png                     chrome://browser/skin/loop/toolbar-aero.png                       os=WINNT osversion=6
 % override chrome://browser/skin/loop/toolbar.png                     chrome://browser/skin/loop/toolbar-aero.png                       os=WINNT osversion=6.1
 % override chrome://browser/skin/loop/toolbar.png                     chrome://browser/skin/loop/toolbar-win8.png                       os=WINNT osversion=6.2
 % override chrome://browser/skin/loop/toolbar.png                     chrome://browser/skin/loop/toolbar-win8.png                       os=WINNT osversion=6.3
 % override chrome://browser/skin/loop/toolbar@2x.png                  chrome://browser/skin/loop/toolbar-XP@2x.png                      os=WINNT osversion<6
 % override chrome://browser/skin/loop/toolbar@2x.png                  chrome://browser/skin/loop/toolbar-aero@2x.png                    os=WINNT osversion=6
 % override chrome://browser/skin/loop/toolbar@2x.png                  chrome://browser/skin/loop/toolbar-aero@2x.png                    os=WINNT osversion=6.1
--- a/dom/base/test/browser.ini
+++ b/dom/base/test/browser.ini
@@ -1,15 +1,16 @@
 [DEFAULT]
 support-files =
   file_messagemanager_unload.html
 
 [browser_bug593387.js]
 skip-if = e10s # Bug ?????? - test directly touches content (contentWindow.iframe.addEventListener)
 [browser_bug902350.js]
+tags = mcb
 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_messagemanager_targetframeloader.js]
 [browser_pagehide_on_tab_close.js]
 skip-if = e10s # this tests non-e10s behavior. it's not expected to work in e10s.
 [browser_messagemanager_unload.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.
--- a/dom/base/test/browser_bug902350.js
+++ b/dom/base/test/browser_bug902350.js
@@ -46,18 +46,19 @@ function MixedTest1A() {
 function MixedTest1B() {
   gTestBrowser.removeEventListener("load", MixedTest1B, true);
   gTestBrowser.addEventListener("load", MixedTest1C, true);
   var frame = content.document.getElementById("testing_frame");
   var topTarget = frame.contentWindow.document.getElementById("topTarget");
   topTarget.click();
 
   // The link click should have caused a load and should not invoke the Mixed Content Blocker
-  var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
-  ok(!notification, "Mixed Content Doorhanger did not appear when trying to navigate top");
+  let {gIdentityHandler} = gTestBrowser.ownerGlobal;
+  ok (!gIdentityHandler._identityBox.classList.contains("mixedActiveBlocked"),
+      "Mixed Content Doorhanger did not appear when trying to navigate top");
 }
 
 function MixedTest1C() {
   gTestBrowser.removeEventListener("load", MixedTest1C, true);
   ok(gTestBrowser.contentWindow.location == "http://example.com/", "Navigating to insecure domain through target='_top' failed.")
   MixedTestsCompleted();
 }
 
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -124,17 +124,16 @@ PRLogModuleInfo* gStateWatchingLog;
 PRLogModuleInfo* gMozPromiseLog;
 PRLogModuleInfo* gMediaTimerLog;
 PRLogModuleInfo* gMediaSampleLog;
 
 void
 MediaDecoder::InitStatics()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  AbstractThread::InitStatics();
 
   // Log modules.
   gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
   gMozPromiseLog = PR_NewLogModule("MozPromise");
   gStateWatchingLog = PR_NewLogModule("StateWatching");
   gMediaTimerLog = PR_NewLogModule("MediaTimer");
   gMediaSampleLog = PR_NewLogModule("MediaSample");
 }
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -619,23 +619,26 @@ RTCPeerConnection.prototype = {
   makeGetterSetterEH: function(name) {
     Object.defineProperty(this, name,
                           {
                             get:function()  { return this.getEH(name); },
                             set:function(h) { return this.setEH(name, h); }
                           });
   },
 
-  _addIdentityAssertion: function(p, origin) {
-    if (this._localIdp.enabled) {
-      return this._localIdp.getIdentityAssertion(this._impl.fingerprint, origin)
-        .then(() => p)
-        .then(sdp => this._localIdp.addIdentityAttribute(sdp));
+  _addIdentityAssertion: function(sdpPromise, origin) {
+    if (!this._localIdp.enabled) {
+      return sdpPromise;
     }
-    return p;
+    return Promise.all([
+      this._certificateReady
+        .then(() => this._localIdp.getIdentityAssertion(this._impl.fingerprint,
+                                                        origin)),
+      sdpPromise
+    ]).then(([,sdp]) => this._localIdp.addIdentityAttribute(sdp));
   },
 
   createOffer: function(optionsOrOnSuccess, onError, options) {
     // This entry-point handles both new and legacy call sig. Decipher which one
     let onSuccess;
     if (typeof optionsOrOnSuccess == "function") {
       onSuccess = optionsOrOnSuccess;
     } else {
@@ -756,16 +759,23 @@ RTCPeerConnection.prototype = {
         case "rollback":
           type = Ci.IPeerConnection.kActionRollback;
           break;
         default:
           throw new this._win.DOMException(
               "Invalid type " + desc.type + " provided to setLocalDescription",
               "InvalidParameterError");
       }
+
+      if (desc.type !== "rollback" && !desc.sdp) {
+        throw new this._win.DOMException(
+            "Empty or null SDP provided to setLocalDescription",
+            "InvalidParameterError");
+      }
+
       return this._chain(() => new this._win.Promise((resolve, reject) => {
         this._onSetLocalDescriptionSuccess = resolve;
         this._onSetLocalDescriptionFailure = reject;
         this._impl.setLocalDescription(type, desc.sdp);
       }));
     });
   },
 
@@ -830,31 +840,44 @@ RTCPeerConnection.prototype = {
           throw new this._win.DOMException("pranswer not yet implemented",
                                            "NotSupportedError");
         case "rollback":
           type = Ci.IPeerConnection.kActionRollback;
           break;
         default:
           throw new this._win.DOMException(
               "Invalid type " + desc.type + " provided to setRemoteDescription",
+              "InvalidParameterError");
+      }
+
+      if (!desc.sdp && desc.type !== "rollback") {
+        throw new this._win.DOMException(
+            "Empty or null SDP provided to setRemoteDescription",
             "InvalidParameterError");
       }
 
       // Get caller's origin before hitting the promise chain
       let origin = Cu.getWebIDLCallerPrincipal().origin;
 
-      // Do setRemoteDescription and identity validation in parallel
-      return this._chain(() => this._win.Promise.all([
-        new this._win.Promise((resolve, reject) => {
+      return this._chain(() => {
+        let setRem = new this._win.Promise((resolve, reject) => {
           this._onSetRemoteDescriptionSuccess = resolve;
           this._onSetRemoteDescriptionFailure = reject;
           this._impl.setRemoteDescription(type, desc.sdp);
-        }),
-        this._validateIdentity(desc.sdp, origin)
-      ])).then(() => {}); // must return undefined
+        });
+
+        if (desc.type === "rollback") {
+          return setRem;
+        }
+
+        // Do setRemoteDescription and identity validation in parallel
+        let validId = this._validateIdentity(desc.sdp, origin);
+        return this._win.Promise.all([setRem, validId])
+          .then(() => {}); // must return undefined
+      });
     });
   },
 
   setIdentityProvider: function(provider, protocol, username) {
     this._checkClosed();
     this._localIdp.setIdentityProvider(provider, protocol, username);
   },
 
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -145,22 +145,20 @@ EXPORTS += [
     'TrackUnionStream.h',
     'VideoFrameContainer.h',
     'VideoSegment.h',
     'VideoUtils.h',
     'VorbisUtils.h',
 ]
 
 EXPORTS.mozilla += [
-    'AbstractThread.h',
     'MediaManager.h',
     'MozPromise.h',
     'StateMirroring.h',
     'StateWatching.h',
-    'TaskDispatcher.h',
     'TaskQueue.h',
 ]
 
 EXPORTS.mozilla.media.webrtc += [
     'webrtc/WebrtcGlobal.h',
 ]
 
 IPDL_SOURCES += [
@@ -189,17 +187,16 @@ EXPORTS.mozilla.dom += [
     'TextTrackRegion.h',
     'VideoPlaybackQuality.h',
     'VideoStreamTrack.h',
     'VideoTrack.h',
     'VideoTrackList.h',
 ]
 
 UNIFIED_SOURCES += [
-    'AbstractThread.cpp',
     'AudioCaptureStream.cpp',
     'AudioChannelFormat.cpp',
     'AudioCompactor.cpp',
     'AudioSegment.cpp',
     'AudioSink.cpp',
     'AudioStream.cpp',
     'AudioStreamTrack.cpp',
     'AudioTrack.cpp',
--- a/editor/libeditor/nsEditorEventListener.cpp
+++ b/editor/libeditor/nsEditorEventListener.cpp
@@ -778,16 +778,18 @@ nsEditorEventListener::NotifyIMEOfMouseB
   return IMEStateManager::OnMouseButtonEventInEditor(presContext,
                                                      GetFocusedRootContent(),
                                                      aMouseEvent);
 }
 
 nsresult
 nsEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
 {
+  // FYI: This may be called by nsHTMLEditorEventListener::MouseDown() even
+  //      when the event is not acceptable for committing composition.
   mEditor->ForceCompositionEnd();
   return NS_OK;
 }
 
 nsresult
 nsEditorEventListener::HandleText(nsIDOMEvent* aTextEvent)
 {
   if (!mEditor->IsAcceptableInputEvent(aTextEvent)) {
--- a/editor/libeditor/nsHTMLEditorEventListener.cpp
+++ b/editor/libeditor/nsHTMLEditorEventListener.cpp
@@ -76,17 +76,21 @@ nsHTMLEditorEventListener::MouseUp(nsIDO
 
 nsresult
 nsHTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
 {
   nsHTMLEditor* htmlEditor = GetHTMLEditor();
   // Contenteditable should disregard mousedowns outside it.
   // IsAcceptableInputEvent() checks it for a mouse event.
   if (!htmlEditor->IsAcceptableInputEvent(aMouseEvent)) {
-    return NS_OK;
+    // If it's not acceptable mousedown event (including when mousedown event
+    // is fired outside of the active editing host), we need to commit
+    // composition because it will be change the selection to the clicked
+    // point.  Then, we won't be able to commit the composition.
+    return nsEditorEventListener::MouseDown(aMouseEvent);
   }
 
   // Detect only "context menu" click
   // XXX This should be easier to do!
   // But eDOMEvents_contextmenu and NS_CONTEXTMENU is not exposed in any event
   // interface :-(
   int16_t buttonNumber;
   nsresult rv = aMouseEvent->GetButton(&buttonNumber);
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -159,8 +159,9 @@ skip-if = toolkit == 'android' # bug 105
 [test_root_element_replacement.html]
 [test_select_all_without_body.html]
 skip-if = e10s
 [test_spellcheck_pref.html]
 skip-if = toolkit == 'android'
 [test_bug1068979.html]
 [test_bug1109465.html]
 [test_bug1162952.html]
+[test_bug1186799.html]
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_bug1186799.html
@@ -0,0 +1,81 @@
+<!DOCTYPE>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1186799
+-->
+<head>
+  <title>Test for Bug 1186799</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<div id="content">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1186799">Mozilla Bug 1186799</a>
+<p id="display"></p>
+<div id="content">
+  <span id="span">span</span>
+  <div id="editor" contenteditable></div>
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1186799 **/
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  var span = document.getElementById("span");
+  var editor = document.getElementById("editor");
+  editor.focus();
+
+  synthesizeCompositionChange(
+    { "composition":
+      { "string": "\u3042",
+        "clauses":
+        [
+          { "length": 1, "attr": COMPOSITION_ATTR_RAW_CLAUSE }
+        ]
+      },
+      "caret": { "start": 1, "length": 0 }
+    });
+
+  ok(isThereIMESelection(), "There should be IME selection");
+
+  var compositionEnd = false;
+  editor.addEventListener("compositionend", function () { compositionEnd = true; }, true);
+
+  synthesizeMouseAtCenter(span, {});
+
+  ok(compositionEnd, "composition end should be fired at clicking outside of the editor");
+  ok(!isThereIMESelection(), "There should be no IME selection");
+
+  SimpleTest.finish();
+});
+
+function isThereIMESelection()
+{
+  var selCon = SpecialPowers.wrap(window).
+        QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
+        getInterface(SpecialPowers.Ci.nsIWebNavigation).
+        QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
+        getInterface(SpecialPowers.Ci.nsIEditingSession).
+        getEditorForWindow(window).
+        selectionController;
+  const kIMESelections = [
+    SpecialPowers.Ci.nsISelectionController.SELECTION_IME_RAWINPUT,
+    SpecialPowers.Ci.nsISelectionController.SELECTION_IME_SELECTEDRAWTEXT,
+    SpecialPowers.Ci.nsISelectionController.SELECTION_IME_CONVERTEDTEXT,
+    SpecialPowers.Ci.nsISelectionController.SELECTION_IME_SELECTEDCONVERTEDTEXT
+  ];
+  for (var i = 0; i < kIMESelections.length; i++) {
+    var sel = selCon.getSelection(kIMESelections[i]);
+    if (sel && sel.rangeCount) {
+      return true;
+    }
+  }
+  return false;
+}
+
+</script>
+</pre>
+</body>
+</html>
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -677,18 +677,16 @@ CompositorParent::CompositorParent(nsIWi
 
   if (UseVsyncComposition()) {
     gfxDebugOnce() << "Enabling vsync compositor";
     mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget);
   } else {
     mCompositorScheduler = new CompositorSoftwareTimerScheduler(this);
   }
 
-  gfxPlatform::GetPlatform()->ComputeTileSize();
-
   LayerScope::SetPixelScale(mWidget->GetDefaultScale().scale);
 }
 
 bool
 CompositorParent::IsInCompositorThread()
 {
   return CompositorThread() && CompositorThread()->thread_id() == PlatformThread::CurrentId();
 }
@@ -1730,17 +1728,16 @@ class CrossProcessCompositorParent final
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CrossProcessCompositorParent)
 public:
   explicit CrossProcessCompositorParent(Transport* aTransport)
     : mTransport(aTransport)
     , mCompositorThreadHolder(sCompositorThreadHolder)
     , mNotifyAfterRemotePaint(false)
   {
     MOZ_ASSERT(NS_IsMainThread());
-    gfxPlatform::GetPlatform()->ComputeTileSize();
   }
 
   // IToplevelProtocol::CloneToplevel()
   virtual IToplevelProtocol*
   CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds,
                 base::ProcessHandle aPeerProcess,
                 mozilla::ipc::ProtocolCloneContext* aCtx) override;
 
--- a/gfx/tests/gtest/TestTiledLayerBuffer.cpp
+++ b/gfx/tests/gtest/TestTiledLayerBuffer.cpp
@@ -6,18 +6,16 @@
 #include "TiledLayerBuffer.h"
 
 #include "gtest/gtest.h"
 
 namespace mozilla {
 namespace layers {
 
 TEST(TiledLayerBuffer, TileStart) {
-  gfxPlatform::GetPlatform()->ComputeTileSize();
-
   ASSERT_EQ(RoundDownToTileEdge(10, 256), 0);
   ASSERT_EQ(RoundDownToTileEdge(-10, 256), -256);
 }
 
 TEST(TiledLayerBuffer, TilesPlacement) {
   for (int firstY = -10; firstY < 10; ++firstY) {
     for (int firstX = -10; firstX < 10; ++firstX) {
       for (int height = 1; height < 10; ++height) {
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -499,16 +499,18 @@ gfxPlatform::Init()
 
 #ifdef MOZ_GL_DEBUG
     GLContext::StaticInit();
 #endif
 
     InitLayersAccelerationPrefs();
     InitLayersIPC();
 
+    gPlatform->ComputeTileSize();
+
     nsresult rv;
 
     bool usePlatformFontList = true;
 #if defined(MOZ_WIDGET_GTK)
     usePlatformFontList = gfxPlatformGtk::UseFcFontList();
 #elif defined(MOZ_WIDGET_QT)
     usePlatformFontList = false;
 #endif
@@ -997,17 +999,17 @@ gfxPlatform::SetTileSize(int aWidth, int
 }
 
 void
 gfxPlatform::ComputeTileSize()
 {
   // The tile size should be picked in the parent processes
   // and sent to the child processes over IPDL GetTileSize.
   if (!XRE_IsParentProcess()) {
-    NS_RUNTIMEABORT("wrong process.");
+    return;
   }
 
   int32_t w = gfxPrefs::LayersTileWidth();
   int32_t h = gfxPrefs::LayersTileHeight();
 
   // TODO We may want to take the screen size into consideration here.
   if (gfxPrefs::LayersTilesAdjust()) {
 #ifdef MOZ_WIDGET_GONK
@@ -1021,31 +1023,33 @@ gfxPlatform::ComputeTileSize()
 
     if (alloc.get()) {
       w = alloc->getStride(); // We want the tiles to be gralloc stride aligned.
       // No need to adjust the height here.
     }
 #endif
   }
 
+#ifdef XP_MACOSX
   // Use double sized tiles for HiDPI screens.
   nsCOMPtr<nsIScreenManager> screenManager =
     do_GetService("@mozilla.org/gfx/screenmanager;1");
   if (screenManager) {
     nsCOMPtr<nsIScreen> primaryScreen;
     screenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
     double scaleFactor = 1.0;
     if (primaryScreen) {
       primaryScreen->GetContentsScaleFactor(&scaleFactor);
     }
     if (scaleFactor > 1.0) {
       w *= 2;
       h *= 2;
     }
   }
+#endif
 
   SetTileSize(w, h);
 }
 
 bool
 gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
 {
   if (!aTarget) {
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -302,22 +302,16 @@ public:
      */
     virtual nsresult GetFontList(nsIAtom *aLangGroup,
                                  const nsACString& aGenericFamily,
                                  nsTArray<nsString>& aListOfFonts);
 
     int GetTileWidth();
     int GetTileHeight();
     void SetTileSize(int aWidth, int aHeight);
-    /**
-     * Calling this function will compute and set the ideal tile size for the
-     * platform. This should only be called in the parent process; child processes
-     * should be updated via SetTileSize to match the value computed in the parent.
-     */
-    void ComputeTileSize();
 
     /**
      * Rebuilds the any cached system font lists
      */
     virtual nsresult UpdateFontList();
 
     /**
      * Create the platform font-list object (gfxPlatformFontList concrete subclass).
@@ -755,16 +749,23 @@ private:
     static void CreateCMSOutputProfile();
 
     static void GetCMSOutputProfileData(void *&mem, size_t &size);
 
     friend void RecordingPrefChanged(const char *aPrefName, void *aClosure);
 
     virtual void GetPlatformCMSOutputProfile(void *&mem, size_t &size);
 
+    /**
+     * Calling this function will compute and set the ideal tile size for the
+     * platform. This will only have an effect in the parent process; child processes
+     * should be updated via SetTileSize to match the value computed in the parent.
+     */
+    void ComputeTileSize();
+
     nsRefPtr<gfxASurface> mScreenReferenceSurface;
     nsTArray<uint32_t> mCJKPrefLangs;
     nsCOMPtr<nsIObserver> mSRGBOverrideObserver;
     nsCOMPtr<nsIObserver> mFontPrefsObserver;
     nsCOMPtr<nsIObserver> mMemoryPressureObserver;
 
     // The preferred draw target backend to use for canvas
     mozilla::gfx::BackendType mPreferredCanvasBackend;
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -1271,16 +1271,128 @@ FoldExponentiation(ExclusiveContext* cx,
     parser.prepareNodeForMutation(node);
     node->setKind(PNK_NUMBER);
     node->setArity(PN_NULLARY);
     node->setOp(JSOP_DOUBLE);
     node->pn_dval = ecmaPow(d1, d2);
     return true;
 }
 
+static bool
+FoldList(ExclusiveContext* cx, ParseNode* list, Parser<FullParseHandler>& parser,
+         bool inGenexpLambda)
+{
+    MOZ_ASSERT(list->isArity(PN_LIST));
+
+    ParseNode** elem = &list->pn_head;
+    for (; *elem; elem = &(*elem)->pn_next) {
+        if (!Fold(cx, elem, parser, inGenexpLambda, SyntacticContext::Other))
+            return false;
+    }
+
+    // Repoint the list's tail pointer if the final element was replaced.
+    list->pn_tail = elem;
+
+    list->checkListConsistency();
+
+    return true;
+}
+
+static bool
+FoldReturn(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
+           bool inGenexpLambda)
+{
+    MOZ_ASSERT(node->isKind(PNK_RETURN));
+    MOZ_ASSERT(node->isArity(PN_BINARY));
+
+    if (ParseNode*& expr = node->pn_left) {
+        if (!Fold(cx, &expr, parser, inGenexpLambda, SyntacticContext::Other))
+            return false;
+    }
+
+#ifdef DEBUG
+    if (ParseNode* generatorSpecific = node->pn_right) {
+        MOZ_ASSERT(generatorSpecific->isKind(PNK_NAME));
+        MOZ_ASSERT(generatorSpecific->pn_atom->equals(".genrval"));
+        MOZ_ASSERT(generatorSpecific->isAssigned());
+    }
+#endif
+
+    return true;
+}
+
+static bool
+FoldTry(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
+        bool inGenexpLambda)
+{
+    MOZ_ASSERT(node->isKind(PNK_TRY));
+    MOZ_ASSERT(node->isArity(PN_TERNARY));
+
+    ParseNode*& statements = node->pn_kid1;
+    if (!Fold(cx, &statements, parser, inGenexpLambda, SyntacticContext::Other))
+        return false;
+
+    if (ParseNode*& catchList = node->pn_kid2) {
+        if (!Fold(cx, &catchList, parser, inGenexpLambda, SyntacticContext::Other))
+            return false;
+    }
+
+    if (ParseNode*& finally = node->pn_kid3) {
+        if (!Fold(cx, &finally, parser, inGenexpLambda, SyntacticContext::Other))
+            return false;
+    }
+
+    return true;
+}
+
+static bool
+FoldCatch(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
+          bool inGenexpLambda)
+{
+    MOZ_ASSERT(node->isKind(PNK_CATCH));
+    MOZ_ASSERT(node->isArity(PN_TERNARY));
+
+    ParseNode*& declPattern = node->pn_kid1;
+    if (!Fold(cx, &declPattern, parser, inGenexpLambda, SyntacticContext::Other))
+        return false;
+
+    if (ParseNode*& cond = node->pn_kid2) {
+        if (!Fold(cx, &cond, parser, inGenexpLambda, SyntacticContext::Condition))
+            return false;
+    }
+
+    if (ParseNode*& statements = node->pn_kid3) {
+        if (!Fold(cx, &statements, parser, inGenexpLambda, SyntacticContext::Other))
+            return false;
+    }
+
+    return true;
+}
+
+static bool
+FoldClass(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
+          bool inGenexpLambda)
+{
+    MOZ_ASSERT(node->isKind(PNK_CLASS));
+    MOZ_ASSERT(node->isArity(PN_TERNARY));
+
+    if (ParseNode*& classNames = node->pn_kid1) {
+        if (!Fold(cx, &classNames, parser, inGenexpLambda, SyntacticContext::Other))
+            return false;
+    }
+
+    if (ParseNode*& heritage = node->pn_kid2) {
+        if (!Fold(cx, &heritage, parser, inGenexpLambda, SyntacticContext::Other))
+            return false;
+    }
+
+    ParseNode*& body = node->pn_kid3;
+    return Fold(cx, &body, parser, inGenexpLambda, SyntacticContext::Other);
+}
+
 bool
 Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bool inGenexpLambda,
      SyntacticContext sc)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     ParseNode* pn = *pnp;
     ParseNode* pn1 = nullptr;
@@ -1387,16 +1499,77 @@ Fold(ExclusiveContext* cx, ParseNode** p
       case PNK_URSH:
       case PNK_DIV:
       case PNK_MOD:
         return FoldBinaryArithmetic(cx, pn, parser, inGenexpLambda);
 
       case PNK_POW:
         return FoldExponentiation(cx, pn, parser, inGenexpLambda);
 
+      // Various list nodes not requiring care to minimally fold.  Some of
+      // these could be further folded/optimized, but we don't make the effort.
+      case PNK_BITOR:
+      case PNK_BITXOR:
+      case PNK_BITAND:
+      case PNK_STRICTEQ:
+      case PNK_EQ:
+      case PNK_STRICTNE:
+      case PNK_NE:
+      case PNK_LT:
+      case PNK_LE:
+      case PNK_GT:
+      case PNK_GE:
+      case PNK_INSTANCEOF:
+      case PNK_IN:
+      case PNK_COMMA:
+      case PNK_ARRAY:
+      case PNK_OBJECT:
+      case PNK_ARRAYCOMP:
+      case PNK_STATEMENTLIST:
+      case PNK_CLASSMETHODLIST:
+      case PNK_CATCHLIST:
+      case PNK_TEMPLATE_STRING_LIST:
+      case PNK_VAR:
+      case PNK_CONST:
+      case PNK_GLOBALCONST:
+      case PNK_LET:
+      case PNK_ARGSBODY:
+      case PNK_CALLSITEOBJ:
+      case PNK_EXPORT_SPEC_LIST:
+      case PNK_IMPORT_SPEC_LIST:
+        return FoldList(cx, pn, parser, inGenexpLambda);
+
+      case PNK_YIELD_STAR:
+        MOZ_ASSERT(pn->isArity(PN_BINARY));
+        MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME));
+        MOZ_ASSERT(!pn->pn_right->isAssigned());
+        return Fold(cx, &pn->pn_left, parser, inGenexpLambda, SyntacticContext::Other);
+
+      case PNK_YIELD:
+        MOZ_ASSERT(pn->isArity(PN_BINARY));
+        MOZ_ASSERT((pn->pn_right->isKind(PNK_NAME) && !pn->pn_right->isAssigned()) ||
+                   (pn->pn_right->isKind(PNK_ASSIGN) &&
+                    pn->pn_right->pn_left->isKind(PNK_NAME) &&
+                    pn->pn_right->pn_right->isKind(PNK_GENERATOR)));
+        if (!pn->pn_left)
+            return true;
+        return Fold(cx, &pn->pn_left, parser, inGenexpLambda, SyntacticContext::Other);
+
+      case PNK_RETURN:
+        return FoldReturn(cx, pn, parser, inGenexpLambda);
+
+      case PNK_TRY:
+        return FoldTry(cx, pn, parser, inGenexpLambda);
+
+      case PNK_CATCH:
+        return FoldCatch(cx, pn, parser, inGenexpLambda);
+
+      case PNK_CLASS:
+        return FoldClass(cx, pn, parser, inGenexpLambda);
+
       case PNK_EXPORT:
       case PNK_ASSIGN:
       case PNK_ADDASSIGN:
       case PNK_SUBASSIGN:
       case PNK_BITORASSIGN:
       case PNK_BITXORASSIGN:
       case PNK_BITANDASSIGN:
       case PNK_LSHASSIGN:
@@ -1414,68 +1587,33 @@ Fold(ExclusiveContext* cx, ParseNode** p
       case PNK_WHILE:
       case PNK_SWITCH:
       case PNK_LETBLOCK:
       case PNK_FOR:
       case PNK_CLASSMETHOD:
       case PNK_WITH:
       case PNK_CLASSNAMES:
       case PNK_DEFAULT:
-      case PNK_YIELD_STAR:
-      case PNK_YIELD:
-      case PNK_RETURN:
       case PNK_IMPORT:
       case PNK_EXPORT_FROM:
       case PNK_EXPORT_DEFAULT:
       case PNK_FORIN:
       case PNK_FOROF:
       case PNK_FORHEAD:
-      case PNK_CLASS:
-      case PNK_TRY:
-      case PNK_BITOR:
-      case PNK_BITXOR:
-      case PNK_BITAND:
-      case PNK_STRICTEQ:
-      case PNK_EQ:
-      case PNK_STRICTNE:
-      case PNK_NE:
-      case PNK_LT:
-      case PNK_LE:
-      case PNK_GT:
-      case PNK_GE:
-      case PNK_INSTANCEOF:
-      case PNK_IN:
       case PNK_ADD:
-      case PNK_COMMA:
       case PNK_NEW:
       case PNK_CALL:
       case PNK_GENEXP:
-      case PNK_ARRAY:
-      case PNK_STATEMENTLIST:
-      case PNK_ARGSBODY:
-      case PNK_ARRAYCOMP:
-      case PNK_VAR:
-      case PNK_CONST:
-      case PNK_LET:
-      case PNK_GLOBALCONST:
-      case PNK_OBJECT:
-      case PNK_CLASSMETHODLIST:
-      case PNK_TEMPLATE_STRING_LIST:
       case PNK_TAGGED_TEMPLATE:
-      case PNK_EXPORT_SPEC_LIST:
-      case PNK_IMPORT_SPEC_LIST:
-      case PNK_CATCHLIST:
       case PNK_LABEL:
       case PNK_DOT:
       case PNK_LEXICALSCOPE:
       case PNK_NAME:
-      case PNK_CATCH:
       case PNK_EXPORT_SPEC:
       case PNK_IMPORT_SPEC:
-      case PNK_CALLSITEOBJ:
         MOZ_ASSERT(!pn->isArity(PN_CODE), "only functions are code nodes");
         break; // for now
 
       case PNK_LIMIT: // invalid sentinel value
         MOZ_CRASH("invalid node kind");
     }
 
     // First, recursively fold constants on the children of this node.
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -6567,30 +6567,18 @@ TryAttachMagicArgumentsGetPropStub(JSCon
     if (name == cx->names().callee) {
         MOZ_ASSERT(!script->strict());
 
         JitSpew(JitSpew_BaselineIC, "  Generating GetProp(MagicArgs.callee) stub");
 
         // Unlike ICGetProp_ArgumentsLength, only magic argument stubs are
         // supported at the moment.
         ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
-
-        // XXXshu the compiler really should be stack allocated, but stack
-        // allocating it causes the test_temporary_storage indexedDB test to
-        // fail on GCC 4.7-compiled ARMv6 optimized builds on Android 2.3 and
-        // below with a NotFoundError, despite that test never exercising this
-        // code.
-        //
-        // Instead of tracking down the GCC bug, I've opted to heap allocate
-        // instead.
-        ScopedJSDeletePtr<ICGetProp_ArgumentsCallee::Compiler> compiler;
-        compiler = js_new<ICGetProp_ArgumentsCallee::Compiler>(cx, monitorStub);
-        if (!compiler)
-            return false;
-        ICStub* newStub = compiler->getStub(compiler->getStubSpace(script));
+        ICGetProp_ArgumentsCallee::Compiler compiler(cx, monitorStub);
+        ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
         stub->addNewStub(newStub);
 
         *attached = true;
         return true;
     }
 
new file mode 100644
--- /dev/null
+++ b/layout/svg/crashtests/1149542-1.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <style>
+    text { white-space: pre }
+    text::first-letter { color: red; }
+    tspan { display: none }
+  </style>
+  <text textLength="64">
+<tspan>a</tspan>b</text>
+</svg>
--- a/layout/svg/crashtests/crashtests.list
+++ b/layout/svg/crashtests/crashtests.list
@@ -184,9 +184,10 @@ load 963086-1.svg
 load 975773-1.svg
 load 974746-1.svg
 load 979407-1.svg
 load 979407-2.svg
 load 993443.svg
 load 1016145.svg
 load 1028512.svg
 load 1140080-1.svg
+load 1149542-1.svg
 load 1182496-1.html
--- a/media/webrtc/signaling/src/common/browser_logging/WebRtcLog.cpp
+++ b/media/webrtc/signaling/src/common/browser_logging/WebRtcLog.cpp
@@ -14,22 +14,30 @@
 #include "nsXULAppAPI.h"
 #if !defined(MOZILLA_XPCOMRT_API)
 #include "mozilla/Preferences.h"
 #endif // !defined(MOZILLA_XPCOMRT_API)
 #else
 #include "nsStringAPI.h"
 #endif
 
+#include "nsIFile.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsDirectoryServiceDefs.h"
+
 using mozilla::LogLevel;
 
 static int gWebRtcTraceLoggingOn = 0;
 
-#ifndef ANDROID
-static const char *default_log = "WebRTC.log";
+
+#if defined(ANDROID)
+static const char *default_tmp_dir = "/dev/null";
+static const char *default_log_name = "nspr";
+#else // Assume a POSIX environment
+NS_NAMED_LITERAL_CSTRING(default_log_name, "WebRTC.log");
 #endif
 
 static PRLogModuleInfo* GetWebRtcTraceLog()
 {
   static PRLogModuleInfo *sLog;
   if (!sLog) {
     sLog = PR_NewLogModule("webrtc_trace");
   }
@@ -101,49 +109,44 @@ void CheckOverrides(uint32_t *aTraceMask
 }
 
 void ConfigWebRtcLog(uint32_t trace_mask, nsCString &aLogFile, nsCString &aAECLogDir, bool multi_log)
 {
   if (gWebRtcTraceLoggingOn) {
     return;
   }
 
-  nsCString logFile;
-  nsCString aecLogDir;
-#if defined(XP_WIN)
-  // Use the Windows TEMP environment variable as part of the default location.
-  const char *temp_dir = PR_GetEnv("TEMP");
-  if (!temp_dir) {
-    logFile.Assign(default_log);
-  } else {
-    logFile.Assign(temp_dir);
-    logFile.Append('/');
-    aecLogDir = logFile;
-    logFile.Append(default_log);
-  }
-#elif defined(ANDROID)
+#if defined(ANDROID)
   // Special case: use callback to pipe to NSPR logging.
-  logFile.Assign("nspr");
-  // for AEC, force the user to specify a directory
-  aecLogDir.Assign("/dev/null");
+  aLogFile.Assign(default_log_name);
+  // For AEC, do not use a default value: force the user to specify a directory.
+  if (aAECLogDir.IsEmpty()) {
+    aAECLogDir.Assign(default_tmp_dir);
+  }
 #else
-  // UNIX-like place for the others
-  logFile.Assign("/tmp/");
-  aecLogDir = logFile;
-  logFile.Append(default_log);
+  if (aLogFile.IsEmpty() || aAECLogDir.IsEmpty()) {
+    nsCOMPtr<nsIFile> tempDir;
+    nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tempDir));
+
+    if (NS_SUCCEEDED(rv)) {
+      if (aAECLogDir.IsEmpty()) {
+        tempDir->GetNativePath(aAECLogDir);
+      }
+
+      if (aLogFile.IsEmpty()) {
+        tempDir->AppendNative(default_log_name);
+        tempDir->GetNativePath(aLogFile);
+      }
+    }
+  }
 #endif
-  if (aLogFile.IsEmpty()) {
-    aLogFile = logFile;
-  }
-  if (aAECLogDir.IsEmpty()) {
-    aAECLogDir = aecLogDir;
-  }
 
   webrtc::Trace::set_level_filter(trace_mask);
   webrtc::Trace::set_aec_debug_filename(aAECLogDir.get());
+
   if (trace_mask != 0) {
     if (aLogFile.EqualsLiteral("nspr")) {
       webrtc::Trace::SetTraceCallback(&gWebRtcCallback);
     } else {
       webrtc::Trace::SetTraceFile(aLogFile.get(), multi_log);
     }
   }
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -2054,21 +2054,19 @@ public class BrowserApp extends GeckoApp
     @Override
     public void addTab() {
         Tabs.getInstance().addTab();
     }
 
     @Override
     public void addPrivateTab() {
         Tabs.getInstance().addPrivateTab();
-
-        showTrackingProtectionPromptIfApplicable();
     }
 
-    private void showTrackingProtectionPromptIfApplicable() {
+    public void showTrackingProtectionPromptIfApplicable() {
         final SharedPreferences prefs = getSharedPreferences();
 
         final boolean hasTrackingProtectionPromptBeShownBefore = prefs.getBoolean(GeckoPreferences.PREFS_TRACKING_PROTECTION_PROMPT_SHOWN, false);
 
         if (hasTrackingProtectionPromptBeShownBefore) {
             return;
         }
 
--- a/mobile/android/base/RestrictedProfiles.java
+++ b/mobile/android/base/RestrictedProfiles.java
@@ -50,17 +50,17 @@ public class RestrictedProfiles {
         }
     }
 
     private static boolean isGuestProfile() {
         return GeckoAppShell.getGeckoInterface().getProfile().inGuestMode();
     }
 
     @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
-    private static boolean isRestrictedProfile(Context context) {
+    public static boolean isRestrictedProfile(Context context) {
         if (Versions.preJBMR2) {
             // Early versions don't support restrictions at all
             return false;
         }
 
         final UserManager mgr = (UserManager) context.getSystemService(Context.USER_SERVICE);
         final Bundle restrictions = new Bundle();
         restrictions.putAll(mgr.getApplicationRestrictions(context.getPackageName()));
--- a/mobile/android/base/db/SuggestedSites.java
+++ b/mobile/android/base/db/SuggestedSites.java
@@ -35,16 +35,17 @@ import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.GeckoSharedPrefs;
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.Locales;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.distribution.Distribution;
 import org.mozilla.gecko.db.BrowserContract;
+import org.mozilla.gecko.RestrictedProfiles;
 import org.mozilla.gecko.mozglue.RobocopTarget;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.util.RawResource;
 import org.mozilla.gecko.util.ThreadUtils;
 
 /**
  * {@code SuggestedSites} provides API to get a list of locale-specific
  * suggested sites to be used in Fennec's top sites panel. It provides
@@ -85,40 +86,44 @@ public class SuggestedSites {
 
     public static final int TRACKING_ID_NONE = -1;
 
     private static final String JSON_KEY_TRACKING_ID = "trackingid";
     private static final String JSON_KEY_URL = "url";
     private static final String JSON_KEY_TITLE = "title";
     private static final String JSON_KEY_IMAGE_URL = "imageurl";
     private static final String JSON_KEY_BG_COLOR = "bgcolor";
+    private static final String JSON_KEY_RESTRICTED = "restricted";
 
     private static class Site {
         public final String url;
         public final String title;
         public final String imageUrl;
         public final String bgColor;
         public final int trackingId;
+        public final boolean restricted;
 
         public Site(JSONObject json) throws JSONException {
             this.trackingId = json.isNull(JSON_KEY_TRACKING_ID) ? TRACKING_ID_NONE : json.getInt(JSON_KEY_TRACKING_ID);
+            this.restricted =  !json.isNull(JSON_KEY_RESTRICTED);
             this.url = json.getString(JSON_KEY_URL);
             this.title = json.getString(JSON_KEY_TITLE);
             this.imageUrl = json.getString(JSON_KEY_IMAGE_URL);
             this.bgColor = json.getString(JSON_KEY_BG_COLOR);
 
             validate();
         }
 
         public Site(int trackingId, String url, String title, String imageUrl, String bgColor) {
             this.trackingId = trackingId;
             this.url = url;
             this.title = title;
             this.imageUrl = imageUrl;
             this.bgColor = bgColor;
+            this.restricted = false;
 
             validate();
         }
 
         private void validate() {
             // Site instances must have non-empty values for all properties except IDs.
             if (TextUtils.isEmpty(url) ||
                 TextUtils.isEmpty(title) ||
@@ -128,28 +133,33 @@ public class SuggestedSites {
                                                 "image URL, and background color.");
             }
         }
 
         @Override
         public String toString() {
             return "{ trackingId = " + trackingId + "\n" +
                      "url = " + url + "\n" +
+                     "restricted = " + restricted + "\n" +
                      "title = " + title + "\n" +
                      "imageUrl = " + imageUrl + "\n" +
                      "bgColor = " + bgColor + " }";
         }
 
         public JSONObject toJSON() throws JSONException {
             final JSONObject json = new JSONObject();
 
             if (trackingId >= 0) {
                 json.put(JSON_KEY_TRACKING_ID, trackingId);
             }
 
+            if (restricted) {
+                json.put(JSON_KEY_RESTRICTED, true);
+            }
+
             json.put(JSON_KEY_URL, url);
             json.put(JSON_KEY_TITLE, title);
             json.put(JSON_KEY_IMAGE_URL, imageUrl);
             json.put(JSON_KEY_BG_COLOR, bgColor);
 
             return json;
         }
     }
@@ -497,20 +507,24 @@ public class SuggestedSites {
             if (cursor.getCount() == maxCount) {
                 break;
             }
 
             if (excludeUrls != null && excludeUrls.contains(site.url)) {
                 continue;
             }
 
-            final RowBuilder row = cursor.newRow();
-            row.add(-1);
-            row.add(site.url);
-            row.add(site.title);
+            final boolean restrictedProfile =  RestrictedProfiles.isRestrictedProfile(context);
+
+            if (restrictedProfile == site.restricted) {
+                final RowBuilder row = cursor.newRow();
+                row.add(-1);
+                row.add(site.url);
+                row.add(site.title);
+            }
         }
 
         cursor.setNotificationUri(context.getContentResolver(),
                                   BrowserContract.SuggestedSites.CONTENT_URI);
 
         return cursor;
     }
 
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -5,17 +5,17 @@
 
 <!ENTITY  no_space_to_start_error "There is not enough space available for &brandShortName; to start.">
 <!ENTITY  error_loading_file "An error occurred when trying to load files required to run &brandShortName;">
 
 <!ENTITY  onboard_start_message3 "Browse with &brandShortName;">
 <!ENTITY  onboard_start_subtext3 "Make your mobile Web browsing experience truly your own.">
 <!ENTITY  onboard_start_button_account "Sign in to &brandShortName;">
 <!ENTITY  onboard_start_button_browser "Start Browsing">
-<!ENTITY  onboard_start_restricted "Stay safe and in control with this simplified version of Firefox.">
+<!ENTITY  onboard_start_restricted1 "Stay safe and in control with this simplified version of &brandShortName;.">
 
 <!-- Localization note: These are used as the titles of different pages on the home screen.
      They are automatically converted to all caps by the Android platform. -->
 <!ENTITY  bookmarks_title "Bookmarks">
 <!ENTITY  history_title "History">
 <!ENTITY  reading_list_title "Reading List">
 <!ENTITY  recent_tabs_title "Recent Tabs">
 
@@ -193,17 +193,17 @@
 <!ENTITY pref_header_devtools "Developer tools">
 
 <!ENTITY pref_cookies_menu "Cookies">
 <!ENTITY pref_cookies_accept_all "Enabled">
 <!ENTITY pref_cookies_not_accept_foreign "Enabled, excluding 3rd party">
 <!ENTITY pref_cookies_disabled "Disabled">
 
 <!ENTITY pref_tracking_protection_title "Tracking protection">
-<!ENTITY pref_tracking_protection_summary2 "Actively block tracking elements in Private Browsing">
+<!ENTITY pref_tracking_protection_summary3 "Enabled in Private Browsing">
 <!ENTITY pref_donottrack_title "Do not track">
 <!ENTITY pref_donottrack_summary "&brandShortName; will tell sites that you do not want to be tracked">
 
 <!ENTITY tracking_protection_prompt_title "Now with Tracking Protection">
 <!ENTITY tracking_protection_prompt_text "Actively block tracking elements so you don\'t have to worry.">
 <!ENTITY tracking_protection_prompt_tip_text "Visit Privacy settings to learn more">
 <!ENTITY tracking_protection_prompt_action_button "Got it!">
 
deleted file mode 100644
index ff6fb6d8078cd4f2930f6000644f3fa82045dd7a..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9984d7f3ecfc9ba314d078c723a7e75a4a8015cc
GIT binary patch
literal 2474
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
deleted file mode 100644
index c95a4876e1317196132a14cbf8277aba60764b0b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f28a62f53a7f896b9434df91d5fd62f4624468e8
GIT binary patch
literal 2643
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
B%yj?&
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3fabf236a680465186c9a9ce9cf4c83e734d8fee
GIT binary patch
literal 2751
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
FV1k}bR(1dY
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a2f92d2ec4a08015f959f3d975f6d9843ee5f7a5
GIT binary patch
literal 7869
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
b^Md{#GY@ffxhjwe00000NkvXXu0mjfa49ee
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..744d3573ca8b450dbf8063b843d322a83c3f80eb
GIT binary patch
literal 3450
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
deleted file mode 100644
index edf20af1178d65921e7ea29bc086cef5443d64d6..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2c86b5baae04eb8d83ff58dbad1d38e84d0df9c5
GIT binary patch
literal 5660
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
awB6ZzI1UqRe|!QDo?{BLGA0{czWsj(rdVPC
--- a/mobile/android/base/resources/layout/tracking_protection_prompt.xml
+++ b/mobile/android/base/resources/layout/tracking_protection_prompt.xml
@@ -18,17 +18,17 @@
             android:layout_width="@dimen/overlay_prompt_container_width"
             android:layout_height="wrap_content"
             android:layout_gravity="bottom|center"
             android:background="@android:color/white"
             android:orientation="vertical">
 
         <ImageView android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
-                   android:src="@drawable/ic_tracking_protection"
+                   android:src="@drawable/tracking_protection_toolbar_illustration"
                    android:layout_gravity="center"
                    android:layout_marginTop="40dp"
                    android:layout_marginBottom="20dp" />
 
         <TextView
                 android:id="@+id/title"
                 android:layout_width="@dimen/overlay_prompt_content_width"
                 android:layout_height="wrap_content"
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -38,17 +38,17 @@
   <string name="no_space_to_start_error">&no_space_to_start_error;</string>
   <string name="error_loading_file">&error_loading_file;</string>
 
   <string name="firstrun_welcome_message">&onboard_start_message3;</string>
   <string name="firstrun_welcome_subtext">&onboard_start_subtext3;</string>
   <string name="firstrun_welcome_button_account">&onboard_start_button_account;</string>
   <string name="firstrun_welcome_button_browser">&onboard_start_button_browser;</string>
   <string name="firstrun_empty_contentDescription"></string>
-  <string name="firstrun_welcome_restricted">&onboard_start_restricted;</string>
+  <string name="firstrun_welcome_restricted">&onboard_start_restricted1;</string>
 
   <string name="bookmarks_title">&bookmarks_title;</string>
   <string name="history_title">&history_title;</string>
   <string name="reading_list_title">&reading_list_title;</string>
   <string name="recent_tabs_title">&recent_tabs_title;</string>
 
   <string name="switch_to_tab">&switch_to_tab;</string>
 
@@ -189,17 +189,17 @@
   <string name="pref_manage_logins">&pref_manage_logins;</string>
 
   <string name="pref_cookies_menu">&pref_cookies_menu;</string>
   <string name="pref_cookies_accept_all">&pref_cookies_accept_all;</string>
   <string name="pref_cookies_not_accept_foreign">&pref_cookies_not_accept_foreign;</string>
   <string name="pref_cookies_disabled">&pref_cookies_disabled;</string>
 
   <string name="pref_tracking_protection_title">&pref_tracking_protection_title;</string>
-  <string name="pref_tracking_protection_summary">&pref_tracking_protection_summary2;</string>
+  <string name="pref_tracking_protection_summary">&pref_tracking_protection_summary3;</string>
   <string name="pref_donottrack_title">&pref_donottrack_title;</string>
   <string name="pref_donottrack_summary">&pref_donottrack_summary;</string>
 
   <string name="pref_char_encoding">&pref_char_encoding;</string>
   <string name="pref_char_encoding_on">&pref_char_encoding_on;</string>
   <string name="pref_char_encoding_off">&pref_char_encoding_off;</string>
   <string name="pref_clear_private_data">&pref_clear_private_data2;</string>
   <string name="pref_clear_private_data_category">&pref_clear_private_data_category;</string>
--- a/mobile/android/base/toolbar/ToolbarDisplayLayout.java
+++ b/mobile/android/base/toolbar/ToolbarDisplayLayout.java
@@ -60,16 +60,17 @@ import android.widget.ImageButton;
 *
 * {@code ToolbarDisplayLayout} is meant to be owned by {@code BrowserToolbar}
 * which is the main event bus for the toolbar subsystem.
 */
 public class ToolbarDisplayLayout extends ThemedLinearLayout
                                   implements Animation.AnimationListener {
 
     private static final String LOGTAG = "GeckoToolbarDisplayLayout";
+    private boolean mTrackingProtectionEnabled;
 
     // To be used with updateFromTab() to allow the caller
     // to give enough context for the requested state change.
     enum UpdateFlags {
         TITLE,
         FAVICON,
         PROGRESS,
         SITE_IDENTITY,
@@ -200,17 +201,17 @@ public class ToolbarDisplayLayout extend
         mStop.setOnClickListener(new Button.OnClickListener() {
             @Override
             public void onClick(View v) {
                 if (mStopListener != null) {
                     // Force toolbar to switch to Display mode
                     // immediately based on the stopped tab.
                     final Tab tab = mStopListener.onStop();
                     if (tab != null) {
-                        updateUiMode(tab, UIMode.DISPLAY, EnumSet.noneOf(UpdateFlags.class));
+                        updateUiMode(UIMode.DISPLAY, EnumSet.noneOf(UpdateFlags.class));
                     }
                 }
             }
         });
 
         float slideWidth = getResources().getDimension(R.dimen.browser_toolbar_site_security_width);
 
         LayoutParams siteSecParams = (LayoutParams) mSiteSecurity.getLayoutParams();
@@ -452,26 +453,32 @@ public class ToolbarDisplayLayout extend
             imageLevel = LEVEL_WARNING_MINOR;
         }
 
         if (mSecurityImageLevel != imageLevel) {
             mSecurityImageLevel = imageLevel;
             mSiteSecurity.setImageLevel(mSecurityImageLevel);
             updatePageActions(flags);
         }
+
+        mTrackingProtectionEnabled = trackingMode == TrackingMode.TRACKING_CONTENT_BLOCKED;
     }
 
     private void updateProgress(Tab tab, EnumSet<UpdateFlags> flags) {
         final boolean shouldShowThrobber = (tab != null &&
                                             tab.getState() == Tab.STATE_LOADING);
 
-        updateUiMode(tab, shouldShowThrobber ? UIMode.PROGRESS : UIMode.DISPLAY, flags);
+        updateUiMode(shouldShowThrobber ? UIMode.PROGRESS : UIMode.DISPLAY, flags);
+
+        if (Tab.STATE_SUCCESS == tab.getState() && mTrackingProtectionEnabled) {
+            mActivity.showTrackingProtectionPromptIfApplicable();
+        }
     }
 
-    private void updateUiMode(Tab tab, UIMode uiMode, EnumSet<UpdateFlags> flags) {
+    private void updateUiMode(UIMode uiMode, EnumSet<UpdateFlags> flags) {
         if (mUiMode == uiMode) {
             return;
         }
 
         mUiMode = uiMode;
 
         // The "Throbber start" and "Throbber stop" log messages in this method
         // are needed by S1/S2 tests (http://mrcote.info/phonedash/#).
--- a/mobile/android/base/widget/ContentSecurityDoorHanger.java
+++ b/mobile/android/base/widget/ContentSecurityDoorHanger.java
@@ -95,20 +95,16 @@ public class ContentSecurityDoorHanger e
     @Override
     protected OnClickListener makeOnButtonClickListener(final int id) {
         return new Button.OnClickListener() {
             @Override
             public void onClick(View v) {
                 final JSONObject response = new JSONObject();
                 try {
                     switch (mType) {
-                        case MIXED_CONTENT:
-                            response.put("allowContent", (id == SiteIdentityPopup.ButtonType.DISABLE.ordinal()));
-                            response.put("contentType", ("mixed"));
-                            break;
                         case TRACKING:
                             response.put("allowContent", (id == SiteIdentityPopup.ButtonType.DISABLE.ordinal()));
                             response.put("contentType", ("tracking"));
                             break;
                         default:
                             Log.w(LOGTAG, "Unknown doorhanger type " + mType.toString());
                     }
                 } catch (JSONException e) {
--- a/mobile/android/base/widget/DoorHanger.java
+++ b/mobile/android/base/widget/DoorHanger.java
@@ -23,23 +23,22 @@ import org.mozilla.gecko.Tabs;
 public abstract class DoorHanger extends LinearLayout {
 
     public static DoorHanger Get(Context context, DoorhangerConfig config) {
         final Type type = config.getType();
         switch (type) {
             case LOGIN:
                 return new LoginDoorHanger(context, config);
             case TRACKING:
-            case MIXED_CONTENT:
                 return new ContentSecurityDoorHanger(context, config, type);
         }
         return new DefaultDoorHanger(context, config, type);
     }
 
-    public static enum Type { DEFAULT, LOGIN, TRACKING, MIXED_CONTENT, GEOLOCATION }
+    public static enum Type { DEFAULT, LOGIN, TRACKING, GEOLOCATION }
 
     public interface OnButtonClickListener {
         public void onButtonClick(JSONObject response, DoorHanger doorhanger);
     }
 
     private static final String LOGTAG = "GeckoDoorHanger";
 
     // Divider between doorhangers.
--- a/mobile/android/chrome/content/aboutPrivateBrowsing.xhtml
+++ b/mobile/android/chrome/content/aboutPrivateBrowsing.xhtml
@@ -24,20 +24,20 @@
     <script type="application/javascript;version=1.8" src="chrome://browser/content/aboutPrivateBrowsing.js"></script>
   </head>
 
   <body class="private">
     <img class="showPrivate masq" src="chrome://browser/skin/images/privatebrowsing-mask-and-shield.svg" />
     <img class="showNormal masq" src="chrome://browser/skin/images/privatebrowsing-mask.png" />
 
     <h1 class="showPrivate">&privatebrowsingpage.title;<br />&privatebrowsingpage.title.private;</h1>
-    <h1 class="showNormal">&privatebrowsingpage.title.normal;</h1>
+    <h1 class="showNormal">&privatebrowsingpage.title.normal1;</h1>
 
     <div class="contentSection">
       <p class="showPrivate">&privatebrowsingpage.description.private3;</p>
-      <p class="showNormal">&privatebrowsingpage.description.normal1;</p>
+      <p class="showNormal">&privatebrowsingpage.description.normal2;</p>
 
       <p class="showPrivate"><a href="https://support.mozilla.org/kb/private-browsing-firefox-android">&privatebrowsingpage.link.private;</a></p>
       <p class="showNormal"><a href="#" id="newPrivateTabLink">&privatebrowsingpage.link.normal;</a></p>
     </div>
 
   </body>
 </html>
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1750,26 +1750,17 @@ var BrowserApp = {
           break;
 
       case "Session:Reload": {
         let flags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
 
         // Check to see if this is a message to enable/disable mixed content blocking.
         if (aData) {
           let data = JSON.parse(aData);
-          if (data.contentType === "mixed") {
-            if (data.allowContent) {
-              // Set a flag to disable mixed content blocking.
-              flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_MIXED_CONTENT;
-            } else {
-              // Set mixedContentChannel to null to re-enable mixed content blocking.
-              let docShell = browser.webNavigation.QueryInterface(Ci.nsIDocShell);
-              docShell.mixedContentChannel = null;
-            }
-          } else if (data.contentType === "tracking") {
+          if (data.contentType === "tracking") {
             // Convert document URI into the format used by
             // nsChannelClassifier::ShouldEnableTrackingProtection
             // (any scheme turned into https is correct)
             let normalizedUrl = Services.io.newURI("https://" + browser.currentURI.hostPort, null, null);
             if (data.allowContent) {
               // Add the current host in the 'trackingprotection' consumer of
               // the permission manager using a normalized URI. This effectively
               // places this host on the tracking protection white list.
--- a/mobile/android/locales/en-US/chrome/aboutPrivateBrowsing.dtd
+++ b/mobile/android/locales/en-US/chrome/aboutPrivateBrowsing.dtd
@@ -3,15 +3,15 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <!ENTITY privatebrowsingpage.title "Private Browsing">
 
 <!-- Localisation note: the plus sign here is a shorthand way of expressing the word "and". Contextually the privatebrowsingpage.title.private string
                         is used as a title, with the privatebrowsingpage.title string preceding it but on a separate line.
                         So the final line will say "Private Browsing + Tracking Protection". -->
 <!ENTITY privatebrowsingpage.title.private "+ Tracking Protection">
-<!ENTITY privatebrowsingpage.title.normal "You are not in private browsing">
+<!ENTITY privatebrowsingpage.title.normal1 "You are not in Private Browsing">
 
 <!ENTITY privatebrowsingpage.description.private3 "Firefox will prevent you from being tracked and won't remember any history, but downloaded files and new bookmarks will still be saved to your device.">
-<!ENTITY privatebrowsingpage.description.normal1 "In private browsing, we won't keep any of your browsing history or cookies. Bookmarks you add and files you download will still be saved on your device.">
+<!ENTITY privatebrowsingpage.description.normal2 "In Private Browsing, we won't keep any of your browsing history or cookies. Bookmarks you add and files you download will still be saved on your device.">
 
 <!ENTITY privatebrowsingpage.link.private "Want to learn more?">
 <!ENTITY privatebrowsingpage.link.normal "Open a new private tab">
--- a/mobile/android/tests/browser/robocop/PixelTest.java
+++ b/mobile/android/tests/browser/robocop/PixelTest.java
@@ -58,21 +58,16 @@ abstract class PixelTest extends BaseTes
         if (isPrivate) {
             selectMenuItem(mStringHelper.NEW_PRIVATE_TAB_LABEL);
         } else {
             selectMenuItem(mStringHelper.NEW_TAB_LABEL);
         }
         tabEventExpecter.blockForEvent();
         contentEventExpecter.blockForEvent();
 
-        if (isPrivate) {
-            waitForText(mStringHelper.TRACKING_PROTECTION_PROMPT_TITLE);
-            mSolo.clickOnText(mStringHelper.TRACKING_PROTECTION_PROMPT_BUTTON);
-        }
-
         waitForText(mStringHelper.TITLE_PLACE_HOLDER);
         loadAndPaint(url);
         tabEventExpecter.unregisterListener();
         contentEventExpecter.unregisterListener();
     }
 
     protected final PaintedSurface waitForPaint(Actions.RepeatedEventExpecter expecter) {
         expecter.blockUntilClear(PAINT_CLEAR_DELAY);
--- a/mobile/locales/en-US/chrome/region.properties
+++ b/mobile/locales/en-US/chrome/region.properties
@@ -65,8 +65,26 @@ browser.suggestedsites.fxaddons.title=Ad
 browser.suggestedsites.fxaddons.url=https://addons.mozilla.org/en-US/android/
 browser.suggestedsites.fxaddons.bgcolor=#62be06
 browser.suggestedsites.fxaddons.trackingid=630
 
 browser.suggestedsites.fxsupport.title=Firefox Help and Support
 browser.suggestedsites.fxsupport.url=https://support.mozilla.org/en-US/products/mobile
 browser.suggestedsites.fxsupport.bgcolor=#f37c00
 browser.suggestedsites.fxsupport.trackingid=631
+
+browser.suggestedsites.restricted.list.0=restricted_fxsupport
+browser.suggestedsites.restricted.list.1=webmaker
+browser.suggestedsites.restricted.list.2=restricted_mozilla
+
+browser.suggestedsites.restricted_fxsupport.title=Firefox Help and Support for a simplified kid-friendly version of Firefox
+browser.suggestedsites.restricted_fxsupport.url=https://support.mozilla.org/kb/kids
+browser.suggestedsites.restricted_fxsupport.bgcolor=#f37c00
+
+browser.suggestedsites.webmaker.title=Learn the Web: Mozilla Webmaker
+browser.suggestedsites.webmaker.url=https://webmaker.org/
+browser.suggestedsites.webmaker.bgcolor=#f37c00
+
+# LOCALIZATION NOTE: browser.suggestedsites.restricted_mozilla.url must be different from browser.suggestedsites.mozilla.url
+browser.suggestedsites.restricted_mozilla.title=The Mozilla Project
+browser.suggestedsites.restricted_mozilla.url=https://www.mozilla.org
+browser.suggestedsites.restricted_mozilla.bgcolor=#ce4e41
+browser.suggestedsites.restricted_mozilla.trackingid=632
--- a/mozglue/android/SQLiteBridge.cpp
+++ b/mozglue/android/SQLiteBridge.cpp
@@ -18,16 +18,17 @@
 #endif
 
 #define SQLITE_WRAPPER_INT(name) name ## _t f_ ## name;
 
 SQLITE_WRAPPER_INT(sqlite3_open)
 SQLITE_WRAPPER_INT(sqlite3_errmsg)
 SQLITE_WRAPPER_INT(sqlite3_prepare_v2)
 SQLITE_WRAPPER_INT(sqlite3_bind_parameter_count)
+SQLITE_WRAPPER_INT(sqlite3_bind_null)
 SQLITE_WRAPPER_INT(sqlite3_bind_text)
 SQLITE_WRAPPER_INT(sqlite3_step)
 SQLITE_WRAPPER_INT(sqlite3_column_count)
 SQLITE_WRAPPER_INT(sqlite3_finalize)
 SQLITE_WRAPPER_INT(sqlite3_close)
 SQLITE_WRAPPER_INT(sqlite3_column_name)
 SQLITE_WRAPPER_INT(sqlite3_column_type)
 SQLITE_WRAPPER_INT(sqlite3_column_blob)
@@ -38,16 +39,17 @@ SQLITE_WRAPPER_INT(sqlite3_last_insert_r
 
 void setup_sqlite_functions(void *sqlite_handle)
 {
 #define GETFUNC(name) f_ ## name = (name ## _t) (uintptr_t) __wrap_dlsym(sqlite_handle, #name)
   GETFUNC(sqlite3_open);
   GETFUNC(sqlite3_errmsg);
   GETFUNC(sqlite3_prepare_v2);
   GETFUNC(sqlite3_bind_parameter_count);
+  GETFUNC(sqlite3_bind_null);
   GETFUNC(sqlite3_bind_text);
   GETFUNC(sqlite3_step);
   GETFUNC(sqlite3_column_count);
   GETFUNC(sqlite3_finalize);
   GETFUNC(sqlite3_close);
   GETFUNC(sqlite3_column_name);
   GETFUNC(sqlite3_column_type);
   GETFUNC(sqlite3_column_blob);
@@ -258,21 +260,27 @@ sqliteInternalCall(JNIEnv* jenv,
                 // IsInstanceOf or isAssignableFrom? String is final, so IsInstanceOf
                 // should be OK.
                 jboolean isString = jenv->IsInstanceOf(jObjectParam, stringClass);
                 if (isString != JNI_TRUE) {
                     throwSqliteException(jenv,
                         "Parameter is not of String type");
                     return nullptr;
                 }
-                jstring jStringParam = (jstring)jObjectParam;
-                const char* paramStr = jenv->GetStringUTFChars(jStringParam, nullptr);
+
                 // SQLite parameters index from 1.
-                rc = f_sqlite3_bind_text(ppStmt, i + 1, paramStr, -1, SQLITE_TRANSIENT);
-                jenv->ReleaseStringUTFChars(jStringParam, paramStr);
+                if (jObjectParam == nullptr) {
+                  rc = f_sqlite3_bind_null(ppStmt, i + 1);
+                } else {
+                  jstring jStringParam = (jstring) jObjectParam;
+                  const char* paramStr = jenv->GetStringUTFChars(jStringParam, nullptr);
+                  rc = f_sqlite3_bind_text(ppStmt, i + 1, paramStr, -1, SQLITE_TRANSIENT);
+                  jenv->ReleaseStringUTFChars(jStringParam, paramStr);
+                }
+
                 if (rc != SQLITE_OK) {
                     throwSqliteException(jenv, "Error binding query parameter");
                     return nullptr;
                 }
             }
         }
     }
 
--- a/mozglue/android/SQLiteBridge.h
+++ b/mozglue/android/SQLiteBridge.h
@@ -13,16 +13,17 @@ void setup_sqlite_functions(void *sqlite
 typedef return_type (*name ## _t)(args);  \
 extern name ## _t f_ ## name;
 
 SQLITE_WRAPPER(sqlite3_open, int, const char*, sqlite3**)
 SQLITE_WRAPPER(sqlite3_errmsg, const char*, sqlite3*)
 SQLITE_WRAPPER(sqlite3_prepare_v2, int, sqlite3*, const char*, int, sqlite3_stmt**, const char**)
 SQLITE_WRAPPER(sqlite3_bind_parameter_count, int, sqlite3_stmt*)
 SQLITE_WRAPPER(sqlite3_bind_text, int, sqlite3_stmt*, int, const char*, int, void(*)(void*))
+SQLITE_WRAPPER(sqlite3_bind_null, int, sqlite3_stmt*, int)
 SQLITE_WRAPPER(sqlite3_step, int, sqlite3_stmt*)
 SQLITE_WRAPPER(sqlite3_column_count, int, sqlite3_stmt*)
 SQLITE_WRAPPER(sqlite3_finalize, int, sqlite3_stmt*)
 SQLITE_WRAPPER(sqlite3_close, int, sqlite3*)
 SQLITE_WRAPPER(sqlite3_column_name, const char*, sqlite3_stmt*, int)
 SQLITE_WRAPPER(sqlite3_column_type, int, sqlite3_stmt*, int)
 SQLITE_WRAPPER(sqlite3_column_blob, const void*, sqlite3_stmt*, int)
 SQLITE_WRAPPER(sqlite3_column_bytes, int, sqlite3_stmt*, int)
--- a/python/mozbuild/mozbuild/action/generate_suggestedsites.py
+++ b/python/mozbuild/mozbuild/action/generate_suggestedsites.py
@@ -6,33 +6,35 @@
 ''' Script to generate the suggestedsites.json file for Fennec.
 
 This script follows these steps:
 
 1. Read the region.properties file in all the given source directories
 (see srcdir option). Merge all properties into a single dict accounting for
 the priority of source directories.
 
-2. Read the list of sites from the 'browser.suggestedsites.list.INDEX'
-properties with value of these keys being an identifier for each suggested site
-e.g. browser.suggestedsites.list.0=mozilla, browser.suggestedsites.list.1=fxmarketplace.
+2. Read the list of sites from the list 'browser.suggestedsites.list.INDEX' and
+'browser.suggestedsites.restricted.list.INDEX' properties with value of these keys
+being an identifier for each suggested site e.g. browser.suggestedsites.list.0=mozilla,
+browser.suggestedsites.list.1=fxmarketplace.
 
 3. For each site identifier defined by the list keys, look for matching branches
 containing the respective properties i.e. url, title, etc. For example,
 for a 'mozilla' identifier, we'll look for keys like:
 browser.suggestedsites.mozilla.url, browser.suggestedsites.mozilla.title, etc.
 
 4. Generate a JSON representation of each site, join them in a JSON array, and
 write the result to suggestedsites.json on the locale-specific raw resource
 directory e.g. raw/suggestedsites.json, raw-pt-rBR/suggestedsites.json.
 '''
 
 from __future__ import absolute_import, print_function
 
 import argparse
+import copy
 import json
 import sys
 import os
 
 from mozbuild.dotproperties import (
     DotProperties,
 )
 from mozbuild.util import (
@@ -73,47 +75,63 @@ def main(args):
                         action='append', required=True,
                         help='directories to read inputs from, in order of priority')
     parser.add_argument('output', metavar='OUTPUT',
                         help='output')
     opts = parser.parse_args(args)
 
     # Use reversed order so that the first srcdir has higher priority to override keys.
     properties = merge_properties('region.properties', reversed(opts.srcdir))
-    names = properties.get_list('browser.suggestedsites.list')
-    if opts.verbose:
-        print('Reading {len} suggested sites: {names}'.format(len=len(names), names=names))
 
     # Keep these two in sync.
     image_url_template = 'android.resource://%s/drawable/suggestedsites_{name}' % opts.android_package_name
     drawables_template = 'drawable*/suggestedsites_{name}.*'
 
     # Load properties corresponding to each site name and define their
     # respective image URL.
     sites = []
-    for name in names:
-        site = properties.get_dict('browser.suggestedsites.{name}'.format(name=name), required_keys=('title', 'url', 'bgcolor'))
-        site['imageurl'] = image_url_template.format(name=name)
-        sites.append(site)
+
+    def add_names(names, defaults={}):
+        for name in names:
+            site = copy.deepcopy(defaults)
+            site.update(properties.get_dict('browser.suggestedsites.{name}'.format(name=name), required_keys=('title', 'url', 'bgcolor')))
+            site['imageurl'] = image_url_template.format(name=name)
+            sites.append(site)
 
-        # Now check for existence of an appropriately named drawable.  If none
-        # exists, throw.  This stops a locale discovering, at runtime, that the
-        # corresponding drawable was not added to en-US.
-        if not opts.resources:
-            continue
-        resources = os.path.abspath(opts.resources)
-        finder = FileFinder(resources)
-        matches = [p for p, _ in finder.find(drawables_template.format(name=name))]
-        if not matches:
-            raise Exception("Could not find drawable in '{resources}' for '{name}'"
-                .format(resources=resources, name=name))
-        else:
-            if opts.verbose:
-                print("Found {len} drawables in '{resources}' for '{name}': {matches}"
-                      .format(len=len(matches), resources=resources, name=name, matches=matches))
+            # Now check for existence of an appropriately named drawable.  If none
+            # exists, throw.  This stops a locale discovering, at runtime, that the
+            # corresponding drawable was not added to en-US.
+            if not opts.resources:
+                continue
+            resources = os.path.abspath(opts.resources)
+            finder = FileFinder(resources)
+            matches = [p for p, _ in finder.find(drawables_template.format(name=name))]
+            if not matches:
+                raise Exception("Could not find drawable in '{resources}' for '{name}'"
+                    .format(resources=resources, name=name))
+            else:
+                if opts.verbose:
+                    print("Found {len} drawables in '{resources}' for '{name}': {matches}"
+                          .format(len=len(matches), resources=resources, name=name, matches=matches))
+
+    # We want the lists to be ordered for reproducibility.  Each list has a
+    # "default" JSON list item which will be extended by the properties read.
+    lists = [
+        ('browser.suggestedsites.list', {}),
+        ('browser.suggestedsites.restricted.list', {'restricted': True}),
+    ]
+    if opts.verbose:
+        print('Reading {len} suggested site lists: {lists}'.format(len=len(lists), lists=[list_name for list_name, _ in lists]))
+
+    for (list_name, list_item_defaults) in lists:
+        names = properties.get_list(list_name)
+        if opts.verbose:
+            print('Reading {len} suggested sites from {list}: {names}'.format(len=len(names), list=list_name, names=names))
+        add_names(names, list_item_defaults)
+
 
     # FileAvoidWrite creates its parent directories.
     output = os.path.abspath(opts.output)
     fh = FileAvoidWrite(output)
     json.dump(sites, fh)
     existed, updated = fh.close()
 
     if not opts.silent:
--- a/toolkit/components/passwordmgr/content/passwordManager.js
+++ b/toolkit/components/passwordmgr/content/passwordManager.js
@@ -406,26 +406,54 @@ function CopyUsername() {
   var clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"].
                   getService(Components.interfaces.nsIClipboardHelper);
   var row = document.getElementById("signonsTree").currentIndex;
   var username = signonsTreeView.getCellText(row, {id : "userCol" });
   clipboard.copyString(username);
   Services.telemetry.getHistogramById("PWMGR_MANAGE_COPIED_USERNAME").add(1);
 }
 
-function UpdateCopyPassword() {
-  var singleSelection = (signonsTreeView.selection.count == 1);
-  var passwordMenuitem = document.getElementById("context-copypassword");
-  var usernameMenuitem = document.getElementById("context-copyusername");
-  if (singleSelection) {
-    usernameMenuitem.removeAttribute("disabled");
-    passwordMenuitem.removeAttribute("disabled");
+function EditCellInSelectedRow(columnName) {
+  let row = signonsTree.currentIndex;
+  let columnElement = getColumnByName(columnName);
+  signonsTree.startEditing(row, signonsTree.columns.getColumnFor(columnElement));
+}
+
+function UpdateContextMenu() {
+  let singleSelection = (signonsTreeView.selection.count == 1);
+  let menuItems = new Map();
+  let menupopup = document.getElementById("signonsTreeContextMenu");
+  for (let menuItem of menupopup.querySelectorAll("menuitem")) {
+    menuItems.set(menuItem.id, menuItem);
+  }
+
+  if (!singleSelection) {
+    for (let menuItem of menuItems.values()) {
+      menuItem.setAttribute("disabled", "true");
+    }
+    return;
+  }
+
+  let selectedRow = signonsTree.currentIndex;
+
+  // Disable "Copy Username" if the username is empty.
+  if (signonsTreeView.getCellText(selectedRow, { id: "userCol" }) != "") {
+    menuItems.get("context-copyusername").removeAttribute("disabled");
   } else {
-    usernameMenuitem.setAttribute("disabled", "true");
-    passwordMenuitem.setAttribute("disabled", "true");
+    menuItems.get("context-copyusername").setAttribute("disabled", "true");
+  }
+
+  menuItems.get("context-editusername").removeAttribute("disabled");
+  menuItems.get("context-copypassword").removeAttribute("disabled");
+
+  // Disable "Edit Password" if the password column isn't showing.
+  if (!document.getElementById("passwordCol").hidden) {
+    menuItems.get("context-editpassword").removeAttribute("disabled");
+  } else {
+    menuItems.get("context-editpassword").setAttribute("disabled", "true");
   }
 }
 
 function masterPasswordLogin(noPasswordCallback) {
   // This doesn't harm if passwords are not encrypted
   var tokendb = Components.classes["@mozilla.org/security/pk11tokendb;1"]
                     .createInstance(Components.interfaces.nsIPK11TokenDB);
   var token = tokendb.getInternalKeyToken();
--- a/toolkit/components/passwordmgr/content/passwordManager.xul
+++ b/toolkit/components/passwordmgr/content/passwordManager.xul
@@ -26,25 +26,34 @@
     <key keycode="VK_ESCAPE" oncommand="window.close();"/>
     <key key="&windowClose.key;" modifiers="accel" oncommand="escapeKeyHandler();"/>
     <key key="&focusSearch1.key;" modifiers="accel" oncommand="FocusFilterBox();"/>
     <key key="&focusSearch2.key;" modifiers="accel" oncommand="FocusFilterBox();"/>
   </keyset>
 
   <popupset id="signonsTreeContextSet">
     <menupopup id="signonsTreeContextMenu"
-           onpopupshowing="UpdateCopyPassword()">
+               onpopupshowing="UpdateContextMenu()">
       <menuitem id="context-copyusername"
                 label="&copyUsernameCmd.label;"
                 accesskey="&copyUsernameCmd.accesskey;"
                 oncommand="CopyUsername()"/>
+      <menuitem id="context-editusername"
+                label="&editUsernameCmd.label;"
+                accesskey="&editUsernameCmd.accesskey;"
+                oncommand="EditCellInSelectedRow('username')"/>
+      <menuseparator/>
       <menuitem id="context-copypassword"
                 label="&copyPasswordCmd.label;"
                 accesskey="&copyPasswordCmd.accesskey;"
                 oncommand="CopyPassword()"/>
+      <menuitem id="context-editpassword"
+                label="&editPasswordCmd.label;"
+                accesskey="&editPasswordCmd.accesskey;"
+                oncommand="EditCellInSelectedRow('password')"/>
     </menupopup>
   </popupset>
 
   <!-- saved signons -->
   <vbox id="savedsignons" class="contentPane" flex="1">
     <!-- filter -->
     <hbox align="center">
       <label accesskey="&filter.accesskey;" control="filter">&filter.label;</label>
--- a/toolkit/components/passwordmgr/test/browser/browser.ini
+++ b/toolkit/components/passwordmgr/test/browser/browser.ini
@@ -7,14 +7,14 @@ support-files =
 [browser_DOMFormHasPassword.js]
 [browser_DOMInputPasswordAdded.js]
 [browser_filldoorhanger.js]
 [browser_notifications.js]
 skip-if = true # Intermittent failures: Bug 1182296, bug 1148771
 [browser_passwordmgr_editing.js]
 skip-if = os == "linux"
 [browser_context_menu.js]
+[browser_passwordmgr_contextmenu.js]
 [browser_passwordmgr_fields.js]
 [browser_passwordmgr_observers.js]
 [browser_passwordmgr_sort.js]
 [browser_passwordmgr_switchtab.js]
-[browser_passwordmgrcopypwd.js]
 [browser_passwordmgrdlg.js]
rename from toolkit/components/passwordmgr/test/browser/browser_passwordmgrcopypwd.js
rename to toolkit/components/passwordmgr/test/browser/browser_passwordmgr_contextmenu.js
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgrcopypwd.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_contextmenu.js
@@ -1,80 +1,100 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 function test() {
     waitForExplicitFinish();
 
-    let pwmgr = Cc["@mozilla.org/login-manager;1"].
-                getService(Ci.nsILoginManager);
-    pwmgr.removeAllLogins();
+    Services.logins.removeAllLogins();
 
     // Add some initial logins
     let urls = [
         "http://example.com/",
         "http://mozilla.org/",
         "http://spreadfirefox.com/",
         "https://developer.mozilla.org/",
         "http://hg.mozilla.org/"
     ];
     let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1",
                                                  Ci.nsILoginInfo, "init");
     let logins = [
-        new nsLoginInfo(urls[0], urls[0], null, "o", "hai", "u1", "p1"),
+        new nsLoginInfo(urls[0], urls[0], null, "", "o hai", "u1", "p1"),
         new nsLoginInfo(urls[1], urls[1], null, "ehsan", "coded", "u2", "p2"),
         new nsLoginInfo(urls[2], urls[2], null, "this", "awesome", "u3", "p3"),
         new nsLoginInfo(urls[3], urls[3], null, "array of", "logins", "u4", "p4"),
         new nsLoginInfo(urls[4], urls[4], null, "then", "i wrote the test", "u5", "p5")
     ];
-    logins.forEach(function (login) pwmgr.addLogin(login));
+    logins.forEach(function (login) Services.logins.addLogin(login));
 
     // Open the password manager dialog
     const PWMGR_DLG = "chrome://passwordmgr/content/passwordManager.xul";
     let pwmgrdlg = window.openDialog(PWMGR_DLG, "Toolkit:PasswordManager", "");
     SimpleTest.waitForFocus(doTest, pwmgrdlg);
 
     // Test if "Copy Username" and "Copy Password" works
     function doTest() {
         let doc = pwmgrdlg.document;
         let selection = doc.getElementById("signonsTree").view.selection;
         let menuitem = doc.getElementById("context-copyusername");
 
         function copyField() {
+            info("Select all");
             selection.selectAll();
-            is(isMenuitemEnabled(), false, "Copy should be disabled");
+            assertMenuitemEnabled("copyusername", false);
+            assertMenuitemEnabled("editusername", false);
+            assertMenuitemEnabled("copypassword", false);
+            assertMenuitemEnabled("editpassword", false);
 
+            info("Select the first row (with an empty username)");
             selection.select(0);
-            is(isMenuitemEnabled(), true, "Copy should be enabled");
+            assertMenuitemEnabled("copyusername", false, "empty username");
+            assertMenuitemEnabled("editusername", true);
+            assertMenuitemEnabled("copypassword", true);
+            assertMenuitemEnabled("editpassword", false, "password column hidden");
 
+            info("Clear the selection");
             selection.clearSelection();
-            is(isMenuitemEnabled(), false, "Copy should be disabled");
+            assertMenuitemEnabled("copyusername", false);
+            assertMenuitemEnabled("editusername", false);
+            assertMenuitemEnabled("copypassword", false);
+            assertMenuitemEnabled("editpassword", false);
 
+            info("Select the third row and making the password column visible");
             selection.select(2);
-            is(isMenuitemEnabled(), true, "Copy should be enabled");
+            doc.getElementById("passwordCol").hidden = false;
+            assertMenuitemEnabled("copyusername", true);
+            assertMenuitemEnabled("editusername", true);
+            assertMenuitemEnabled("copypassword", true);
+            assertMenuitemEnabled("editpassword", true, "password column visible");
             menuitem.doCommand();
         }
 
-        function isMenuitemEnabled() {
-            doc.defaultView.UpdateCopyPassword();
-            return !menuitem.getAttribute("disabled");
+        function assertMenuitemEnabled(idSuffix, expected, reason = "") {
+            doc.defaultView.UpdateContextMenu();
+            let actual = !doc.getElementById("context-" + idSuffix).getAttribute("disabled");
+            is(actual, expected, idSuffix + " should be " + (expected ? "enabled" : "disabled") +
+               (reason ? ": " + reason : ""));
         }
 
         function cleanUp() {
             Services.ww.registerNotification(function (aSubject, aTopic, aData) {
                 Services.ww.unregisterNotification(arguments.callee);
-                pwmgr.removeAllLogins();
+                Services.logins.removeAllLogins();
+                doc.getElementById("passwordCol").hidden = true;
                 finish();
             });
             pwmgrdlg.close();
         }
-        
+
         function testPassword() {
-            menuitem = doc.getElementById("context-copypassword");
             info("Testing Copy Password");
-            waitForClipboard("coded", copyField, cleanUp, cleanUp);
+            waitForClipboard("coded", function copyPassword() {
+                menuitem = doc.getElementById("context-copypassword");
+                menuitem.doCommand();
+            }, cleanUp, cleanUp);
         }
-        
+
         info("Testing Copy Username");
         waitForClipboard("ehsan", copyField, testPassword, testPassword);
     }
 }
--- a/toolkit/components/places/UnifiedComplete.js
+++ b/toolkit/components/places/UnifiedComplete.js
@@ -842,62 +842,22 @@ Search.prototype = {
 
     // "openpage" behavior is supported by the default query.
     // _switchToTabQuery instead returns only pages not supported by history.
     if (this.hasBehavior("openpage")) {
       queries.push(this._switchToTabQuery);
     }
     queries.push(this._searchQuery);
 
-    // When actions are enabled, we run a series of heuristics to determine what
-    // the first result should be - which is always a special result.
-    // |hasFirstResult| is used to keep track of whether we've obtained such a
-    // result yet, so we can skip further heuristics and not add any additional
-    // special results.
-    let hasFirstResult = false;
-
-    if (this._searchTokens.length > 0) {
-      // This may be a Places keyword.
-      hasFirstResult = yield this._matchPlacesKeyword();
-    }
-
-    if (this.pending && this._enableActions && !hasFirstResult) {
-      // If it's not a Places keyword, then it may be a search engine
-      // with an alias - which works like a keyword.
-      hasFirstResult = yield this._matchSearchEngineAlias();
-    }
-
-    let shouldAutofill = this._shouldAutofill;
-    if (this.pending && !hasFirstResult && shouldAutofill) {
-      // It may also look like a URL we know from the database.
-      hasFirstResult = yield this._matchKnownUrl(conn);
-    }
-
-    if (this.pending && !hasFirstResult && shouldAutofill) {
-      // Or it may look like a URL we know about from search engines.
-      hasFirstResult = yield this._matchSearchEngineUrl();
-    }
-
-    if (this.pending && this._enableActions && !hasFirstResult) {
-      // If we don't have a result that matches what we know about, then
-      // we use a fallback for things we don't know about.
-
-      // We may not have auto-filled, but this may still look like a URL.
-      // However, even if the input is a valid URL, we may not want to use
-      // it as such. This can happen if the host would require whitelisting,
-      // but isn't in the whitelist.
-      hasFirstResult = yield this._matchUnknownUrl();
-    }
-
-    if (this.pending && this._enableActions && !hasFirstResult) {
-      // When all else fails, we search using the current search engine.
-      hasFirstResult = yield this._matchCurrentSearchEngine();
-    }
-
-    // IMPORTANT: No other first result heuristics should run after this point.
+    // Add the first heuristic result, if any.  Set _addingHeuristicFirstMatch
+    // to true so that when the result is added, "heuristic" can be included in
+    // its style.
+    this._addingHeuristicFirstMatch = true;
+    yield this._matchFirstHeuristicResult(conn);
+    this._addingHeuristicFirstMatch = false;
 
     yield this._sleep(Prefs.delay);
     if (!this.pending)
       return;
 
     yield this._matchSearchSuggestions();
     if (!this.pending)
       return;
@@ -921,16 +881,78 @@ Search.prototype = {
           return;
       }
     }
 
     // Ensure to fill any remaining space.
     yield Promise.all(this._remoteMatchesPromises);
   }),
 
+  *_matchFirstHeuristicResult(conn) {
+    // We always try to make the first result a special "heuristic" result.  The
+    // heuristics below determine what type of result it will be, if any.
+
+    if (this._searchTokens.length > 0) {
+      // This may be a Places keyword.
+      let matched = yield this._matchPlacesKeyword();
+      if (matched) {
+        return;
+      }
+    }
+
+    if (this.pending && this._enableActions) {
+      // If it's not a Places keyword, then it may be a search engine
+      // with an alias - which works like a keyword.
+      let matched = yield this._matchSearchEngineAlias();
+      if (matched) {
+        return;
+      }
+    }
+
+    let shouldAutofill = this._shouldAutofill;
+    if (this.pending && shouldAutofill) {
+      // It may also look like a URL we know from the database.
+      let matched = yield this._matchKnownUrl(conn);
+      if (matched) {
+        return;
+      }
+    }
+
+    if (this.pending && shouldAutofill) {
+      // Or it may look like a URL we know about from search engines.
+      let matched = yield this._matchSearchEngineUrl();
+      if (matched) {
+        return;
+      }
+    }
+
+    if (this.pending && this._enableActions) {
+      // If we don't have a result that matches what we know about, then
+      // we use a fallback for things we don't know about.
+
+      // We may not have auto-filled, but this may still look like a URL.
+      // However, even if the input is a valid URL, we may not want to use
+      // it as such. This can happen if the host would require whitelisting,
+      // but isn't in the whitelist.
+      let matched = yield this._matchUnknownUrl();
+      if (matched) {
+        return;
+      }
+    }
+
+    if (this.pending && this._enableActions && this._originalSearchString) {
+      // When all else fails, and the search string is non-empty, we search
+      // using the current search engine.
+      let matched = yield this._matchCurrentSearchEngine();
+      if (matched) {
+        return;
+      }
+    }
+  },
+
   *_matchSearchSuggestions() {
     // Limit the string sent for search suggestions to a maximum length.
     let searchString = this._searchTokens.join(" ")
                            .substr(0, Prefs.maxCharsForSearchSuggestions);
     // Avoid fetching suggestions if they are not required, private browsing
     // mode is enabled, or the search string may expose sensitive information.
     if (!this.hasBehavior("searches") || this._inPrivateWindow ||
         this._prohibitSearchSuggestionsFor(searchString)) {
@@ -1293,16 +1315,20 @@ Search.prototype = {
 
     match.style = match.style || "favicon";
 
     // Restyle past searches, unless they are bookmarks or special results.
     if (Prefs.restyleSearches && match.style == "favicon") {
       this._maybeRestyleSearchMatch(match);
     }
 
+    if (this._addingHeuristicFirstMatch) {
+      match.style += " heuristic";
+    }
+
     match.icon = match.icon || PlacesUtils.favicons.defaultFavicon.spec;
     match.finalCompleteValue = match.finalCompleteValue || "";
 
     this._result.insertMatchAt(this._getInsertIndexForMatch(match),
                                match.value,
                                match.comment,
                                match.icon,
                                match.style,
@@ -1571,17 +1597,17 @@ Search.prototype = {
   /**
    * Whether we should try to autoFill.
    */
   get _shouldAutofill() {
     // First of all, check for the autoFill pref.
     if (!Prefs.autofill)
       return false;
 
-    if (!this._searchTokens.length == 1)
+    if (this._searchTokens.length != 1)
       return false;
 
     // autoFill can only cope with history or bookmarks entries.
     if (!this.hasBehavior("history") &&
         !this.hasBehavior("bookmark"))
       return false;
 
     // autoFill doesn't search titles or tags.
--- a/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
+++ b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
@@ -357,37 +357,45 @@ function makeSearchMatch(input, extra = 
   // in the object passed to makeActionURI is important for check_autocomplete
   // to match them :(
   let params = {
     engineName: extra.engineName || "MozSearch",
     input,
     searchQuery: "searchQuery" in extra ? extra.searchQuery : input,
     alias: extra.alias, // may be undefined which is expected.
   }
+  let style = [ "action", "searchengine" ];
+  if (extra.heuristic) {
+    style.push("heuristic");
+  }
   return {
     uri: makeActionURI("searchengine", params),
     title: params.engineName,
-    style: [ "action", "searchengine" ],
+    style,
   }
 }
 
 // Creates a full "match" entry for a search result, suitable for passing as
 // an entry to check_autocomplete.
 function makeVisitMatch(input, url, extra = {}) {
   // Note that counter-intuitively, the order the object properties are defined
   // in the object passed to makeActionURI is important for check_autocomplete
   // to match them :(
   let params = {
     url,
     input,
   }
+  let style = [ "action", "visiturl" ];
+  if (extra.heuristic) {
+    style.push("heuristic");
+  }
   return {
     uri: makeActionURI("visiturl", params),
     title: extra.title || url,
-    style: [ "action", "visiturl" ],
+    style,
   }
 }
 
 function makeSwitchToTabMatch(url, extra = {}) {
   return {
     uri: makeActionURI("switchtab", {url}),
     title: extra.title || url,
     style: [ "action", "switchtab" ],
--- a/toolkit/components/places/tests/unifiedcomplete/test_autoFill_default_behavior.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_autoFill_default_behavior.js
@@ -36,17 +36,17 @@ add_task(function* test_default_behavior
     matches: [ { uri: uri2, title: "visited" } ],
     autofilled: "vi",
     completed: "vi"
   });
 
   do_print("Restrict history, typed visit, should autoFill");
   yield check_autocomplete({
     search: "ty",
-    matches: [ { uri: uri1, title: "typed", style: [ "autofill" ],
+    matches: [ { uri: uri1, title: "typed", style: [ "autofill", "heuristic" ],
                  icon: "chrome://global/skin/icons/information-16.png" } ],
     autofilled: "typed/",
     completed: "typed/"
   });
 
   // Don't autoFill this one cause it's not typed.
   do_print("Restrict history, bookmark, should not autoFill");
   yield check_autocomplete({
@@ -55,39 +55,39 @@ add_task(function* test_default_behavior
     autofilled: "bo",
     completed: "bo"
   });
 
   // Note we don't show this one cause it's not typed.
   do_print("Restrict history, typed bookmark, should autoFill");
   yield check_autocomplete({
     search: "tp",
-    matches: [ { uri: uri4, title: "tpbk", style: [ "autofill" ] } ],
+    matches: [ { uri: uri4, title: "tpbk", style: [ "autofill", "heuristic" ] } ],
     autofilled: "tpbk/",
     completed: "tpbk/"
   });
 
   Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
 
   // We are not restricting on typed, so we autoFill the bookmark even if we
   // are restricted to history.  We accept that cause not doing that
   // would be a perf hit and the privacy implications are very weak.
   do_print("Restrict history, bookmark, autoFill.typed = false, should autoFill");
   yield check_autocomplete({
     search: "bo",
-    matches: [ { uri: uri3, title: "bookmarked", style: [ "bookmark" ], style: [ "autofill" ],
+    matches: [ { uri: uri3, title: "bookmarked", style: [ "bookmark" ], style: [ "autofill", "heuristic" ],
                  icon: "chrome://global/skin/icons/error-16.png" } ],
     autofilled: "bookmarked/",
     completed: "bookmarked/"
   });
 
   do_print("Restrict history, common visit, autoFill.typed = false, should autoFill");
   yield check_autocomplete({
     search: "vi",
-    matches: [ { uri: uri2, title: "visited", style: [ "autofill" ] } ],
+    matches: [ { uri: uri2, title: "visited", style: [ "autofill", "heuristic" ] } ],
     autofilled: "visited/",
     completed: "visited/"
   });
 
   // RESTRICT TO TYPED.
   // This should basically ignore autoFill.typed and acts as if it would be set.
   Services.prefs.setBoolPref("browser.urlbar.suggest.history.onlyTyped", true);
 
@@ -98,34 +98,34 @@ add_task(function* test_default_behavior
     matches: [ ],
     autofilled: "vi",
     completed: "vi"
   });
 
   do_print("Restrict typed, typed visit, autofill.typed = false, should autoFill");
   yield check_autocomplete({
     search: "ty",
-    matches: [ { uri: uri1, title: "typed", style: [ "autofill" ],
+    matches: [ { uri: uri1, title: "typed", style: [ "autofill", "heuristic" ],
                  icon: "chrome://global/skin/icons/information-16.png"} ],
     autofilled: "typed/",
     completed: "typed/"
   });
 
   do_print("Restrict typed, bookmark, autofill.typed = false, should not autoFill");
   yield check_autocomplete({
     search: "bo",
     matches: [ ],
     autofilled: "bo",
     completed: "bo"
   });
 
   do_print("Restrict typed, typed bookmark, autofill.typed = false, should autoFill");
   yield check_autocomplete({
     search: "tp",
-    matches: [ { uri: uri4, title: "tpbk", style: [ "autofill" ] } ],
+    matches: [ { uri: uri4, title: "tpbk", style: [ "autofill", "heuristic" ] } ],
     autofilled: "tpbk/",
     completed: "tpbk/"
   });
 
   // RESTRICT BOOKMARKS.
   Services.prefs.setBoolPref("browser.urlbar.suggest.history", false);
   Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", true);
   Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", true);
@@ -155,27 +155,27 @@ add_task(function* test_default_behavior
     autofilled: "bo",
     completed: "bo"
   });
 
   // Note we don't show this one cause it's not typed.
   do_print("Restrict bookmarks, typed bookmark, should autoFill");
   yield check_autocomplete({
     search: "tp",
-    matches: [ { uri: uri4, title: "tpbk", style: [ "autofill" ] } ],
+    matches: [ { uri: uri4, title: "tpbk", style: [ "autofill", "heuristic" ] } ],
     autofilled: "tpbk/",
     completed: "tpbk/"
   });
 
   Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
 
   do_print("Restrict bookmarks, bookmark, autofill.typed = false, should autoFill");
   yield check_autocomplete({
     search: "bo",
-    matches: [ { uri: uri3, title: "bookmarked", style: [ "autofill" ],
+    matches: [ { uri: uri3, title: "bookmarked", style: [ "autofill", "heuristic" ],
                  icon: "chrome://global/skin/icons/error-16.png" } ],
     autofilled: "bookmarked/",
     completed: "bookmarked/"
   });
 
   // Don't autofill because it's a title.
   do_print("Restrict bookmarks, title, autofill.typed = false, should not autoFill");
   yield check_autocomplete({
@@ -227,17 +227,17 @@ add_task(function* test_default_behavior
     matches: [ { uri: uri2, title: "visited" } ],
     autofilled: "visited/v",
     completed: "visited/v"
   });
 
   do_print("URL: Restrict history, typed visit, should autoFill");
   yield check_autocomplete({
     search: "typed/t",
-    matches: [ { uri: uri1, title: "typed/ty/", style: [ "autofill" ],
+    matches: [ { uri: uri1, title: "typed/ty/", style: [ "autofill", "heuristic" ],
                  icon: "chrome://global/skin/icons/information-16.png"} ],
     autofilled: "typed/ty/",
     completed: "http://typed/ty/"
   });
 
   // Don't autoFill this one cause it's not typed.
   do_print("URL: Restrict history, bookmark, should not autoFill");
   yield check_autocomplete({
@@ -246,17 +246,17 @@ add_task(function* test_default_behavior
     autofilled: "bookmarked/b",
     completed: "bookmarked/b"
   });
 
   // Note we don't show this one cause it's not typed.
   do_print("URL: Restrict history, typed bookmark, should autoFill");
   yield check_autocomplete({
     search: "tpbk/t",
-    matches: [ { uri: uri4, title: "tpbk/tp/", style: [ "autofill" ] } ],
+    matches: [ { uri: uri4, title: "tpbk/tp/", style: [ "autofill", "heuristic" ] } ],
     autofilled: "tpbk/tp/",
     completed: "http://tpbk/tp/"
   });
 
   // RESTRICT BOOKMARKS.
   Services.prefs.setBoolPref("browser.urlbar.suggest.history", false);
   Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", true);
 
@@ -285,26 +285,26 @@ add_task(function* test_default_behavior
     autofilled: "bookmarked/b",
     completed: "bookmarked/b"
   });
 
   // Note we don't show this one cause it's not typed.
   do_print("URL: Restrict bookmarks, typed bookmark, should autoFill");
   yield check_autocomplete({
     search: "tpbk/t",
-    matches: [ { uri: uri4, title: "tpbk/tp/", style: [ "autofill" ] } ],
+    matches: [ { uri: uri4, title: "tpbk/tp/", style: [ "autofill", "heuristic" ] } ],
     autofilled: "tpbk/tp/",
     completed: "http://tpbk/tp/"
   });
 
   Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", false);
 
   do_print("URL: Restrict bookmarks, bookmark, autofill.typed = false, should autoFill");
   yield check_autocomplete({
     search: "bookmarked/b",
-    matches: [ { uri: uri3, title: "bookmarked/bo/", style: [ "autofill" ],
+    matches: [ { uri: uri3, title: "bookmarked/bo/", style: [ "autofill", "heuristic" ],
                  icon: "chrome://global/skin/icons/error-16.png" } ],
     autofilled: "bookmarked/bo/",
     completed: "http://bookmarked/bo/"
   });
 
   yield cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_dupe_urls.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_dupe_urls.js
@@ -12,12 +12,12 @@ add_task(function* test_dupe_urls() {
     uri: NetUtil.newURI("http://mozilla.org/?")
   });
   yield check_autocomplete({
     search: "moz",
     autofilled: "mozilla.org/",
     completed:  "mozilla.org/",
     matches: [ { uri: NetUtil.newURI("http://mozilla.org/"),
                  title: "mozilla.org",
-                 style: [ "autofill" ] } ]
+                 style: [ "autofill", "heuristic" ] } ]
   });
   yield cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_empty_search.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_empty_search.js
@@ -38,17 +38,17 @@ add_task(function* test_javascript_match
 
   // Now remove page 6 from history, so it is an unvisited bookmark.
   PlacesUtils.history.removePage(uri6);
 
   do_print("Match everything");
   yield check_autocomplete({
     search: "foo",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("foo"),
+    matches: [ makeSearchMatch("foo", { heuristic: true }),
                { uri: uri1, title: "title" },
                { uri: uri2, title: "title", style: ["bookmark"] },
                { uri: uri3, title: "title" },
                { uri: uri4, title: "title", style: ["bookmark"] },
                { uri: uri5, title: "title", style: ["bookmark"] },
                { uri: uri6, title: "title", style: ["bookmark"] },
                makeSwitchToTabMatch("http://t.foo/6", { title: "title" }),
              ]
@@ -82,17 +82,16 @@ add_task(function* test_javascript_match
   });
 
   do_print("Drop-down empty search matches only open tabs");
   Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", false);
   yield check_autocomplete({
     search: "",
     searchParam: "enable-actions",
     matches: [
-               makeSearchMatch(""),
                makeSwitchToTabMatch("http://t.foo/6", { title: "title" }),
              ]
   });
 
   Services.prefs.clearUserPref("browser.urlbar.suggest.history");
   Services.prefs.clearUserPref("browser.urlbar.suggest.bookmark");
 
   yield cleanup();
--- a/toolkit/components/places/tests/unifiedcomplete/test_keyword_search.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_keyword_search.js
@@ -19,49 +19,49 @@ add_task(function* test_keyword_searc() 
     { uri: uri1, title: "Generic page title" },
     { uri: uri2, title: "Generic page title" }
   ]);
   yield addBookmark({ uri: uri1, title: "Bookmark title", keyword: "key"});
 
   do_print("Plain keyword query");
   yield check_autocomplete({
     search: "key term",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search=term"), title: "abc", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search=term"), title: "abc", style: ["keyword", "heuristic"] } ]
   });
 
   do_print("Multi-word keyword query");
   yield check_autocomplete({
     search: "key multi word",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search=multi+word"), title: "abc", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search=multi+word"), title: "abc", style: ["keyword", "heuristic"] } ]
   });
 
   do_print("Keyword query with +");
   yield check_autocomplete({
     search: "key blocking+",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search=blocking%2B"), title: "abc", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search=blocking%2B"), title: "abc", style: ["keyword", "heuristic"] } ]
   });
 
   do_print("Unescaped term in query");
   yield check_autocomplete({
     search: "key ユニコード",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search=ユニコード"), title: "abc", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search=ユニコード"), title: "abc", style: ["keyword", "heuristic"] } ]
   });
 
   do_print("Keyword that happens to match a page");
   yield check_autocomplete({
     search: "key ThisPageIsInHistory",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search=ThisPageIsInHistory"), title: "abc", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search=ThisPageIsInHistory"), title: "abc", style: ["keyword", "heuristic"] } ]
   });
 
   do_print("Keyword without query (without space)");
   yield check_autocomplete({
     search: "key",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search="), title: "abc", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search="), title: "abc", style: ["keyword", "heuristic"] } ]
   });
 
   do_print("Keyword without query (with space)");
   yield check_autocomplete({
     search: "key ",
-    matches: [ { uri: NetUtil.newURI("http://abc/?search="), title: "abc", style: ["keyword"] } ]
+    matches: [ { uri: NetUtil.newURI("http://abc/?search="), title: "abc", style: ["keyword", "heuristic"] } ]
   });
 
   yield cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_keyword_search_actions.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_keyword_search_actions.js
@@ -20,55 +20,55 @@ add_task(function* test_keyword_search()
     { uri: uri2, title: "Generic page title" }
   ]);
   yield addBookmark({ uri: uri1, title: "Bookmark title", keyword: "key"});
 
   do_print("Plain keyword query");
   yield check_autocomplete({
     search: "key term",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=term", input: "key term"}), title: "abc", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=term", input: "key term"}), title: "abc", style: [ "action", "keyword", "heuristic" ] } ]
   });
 
   do_print("Multi-word keyword query");
   yield check_autocomplete({
     search: "key multi word",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=multi+word", input: "key multi word"}), title: "abc", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=multi+word", input: "key multi word"}), title: "abc", style: [ "action", "keyword", "heuristic" ] } ]
   });
 
   do_print("Keyword query with +");
   yield check_autocomplete({
     search: "key blocking+",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=blocking%2B", input: "key blocking+"}), title: "abc", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=blocking%2B", input: "key blocking+"}), title: "abc", style: [ "action", "keyword", "heuristic" ] } ]
   });
 
   do_print("Unescaped term in query");
   yield check_autocomplete({
     search: "key ユニコード",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=ユニコード", input: "key ユニコード"}), title: "abc", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=ユニコード", input: "key ユニコード"}), title: "abc", style: [ "action", "keyword", "heuristic" ] } ]
   });
 
   do_print("Keyword that happens to match a page");
   yield check_autocomplete({
     search: "key ThisPageIsInHistory",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=ThisPageIsInHistory", input: "key ThisPageIsInHistory"}), title: "abc", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=ThisPageIsInHistory", input: "key ThisPageIsInHistory"}), title: "abc", style: [ "action", "keyword", "heuristic" ] } ]
   });
 
   do_print("Keyword without query (without space)");
   yield check_autocomplete({
     search: "key",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=", input: "key"}), title: "abc", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=", input: "key"}), title: "abc", style: [ "action", "keyword", "heuristic" ] } ]
   });
 
   do_print("Keyword without query (with space)");
   yield check_autocomplete({
     search: "key ",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=", input: "key "}), title: "abc", style: [ "action", "keyword" ] } ]
+    matches: [ { uri: makeActionURI("keyword", {url: "http://abc/?search=", input: "key "}), title: "abc", style: [ "action", "keyword", "heuristic" ] } ]
   });
 
   yield cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_searchEngine_alias.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_searchEngine_alias.js
@@ -7,31 +7,31 @@ add_task(function*() {
   // Here we add another engine with a search alias.
   Services.search.addEngineWithDetails("AliasedMozSearch", "", "doit", "",
                                        "GET", "http://s.example.com/search");
 
 
   yield check_autocomplete({
     search: "doit",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("doit", { engineName: "AliasedMozSearch", searchQuery: "", alias: "doit" }) ]
+    matches: [ makeSearchMatch("doit", { engineName: "AliasedMozSearch", searchQuery: "", alias: "doit", heuristic: true }) ]
   });
 
   yield check_autocomplete({
     search: "doit ",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("doit ", { engineName: "AliasedMozSearch", searchQuery: "", alias: "doit" }) ]
+    matches: [ makeSearchMatch("doit ", { engineName: "AliasedMozSearch", searchQuery: "", alias: "doit", heuristic: true }) ]
   });
 
   yield check_autocomplete({
     search: "doit mozilla",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("doit mozilla", { engineName: "AliasedMozSearch", searchQuery: "mozilla", alias: "doit" }) ]
+        matches: [ makeSearchMatch("doit mozilla", { engineName: "AliasedMozSearch", searchQuery: "mozilla", alias: "doit", heuristic: true }) ]
   });
 
   yield check_autocomplete({
     search: "doit mozzarella mozilla",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("doit mozzarella mozilla", { engineName: "AliasedMozSearch", searchQuery: "mozzarella mozilla", alias: "doit" }) ]
+        matches: [ makeSearchMatch("doit mozzarella mozilla", { engineName: "AliasedMozSearch", searchQuery: "mozzarella mozilla", alias: "doit", heuristic: true }) ]
   });
 
   yield cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_searchEngine_current.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_searchEngine_current.js
@@ -7,39 +7,39 @@ add_task(function*() {
   // Here we add another engine with a search alias.
   Services.search.addEngineWithDetails("AliasedMozSearch", "", "doit", "",
                                        "GET", "http://s.example.com/search");
 
   do_print("search engine");
   yield check_autocomplete({
     search: "mozilla",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("mozilla") ]
+    matches: [ makeSearchMatch("mozilla", { heuristic: true }) ]
   });
 
   do_print("search engine, uri-like input");
   yield check_autocomplete({
     search: "http:///",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("http:///") ]
+    matches: [ makeSearchMatch("http:///", { heuristic: true }) ]
   });
 
   do_print("search engine, multiple words");
   yield check_autocomplete({
     search: "mozzarella cheese",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("mozzarella cheese") ]
+    matches: [ makeSearchMatch("mozzarella cheese", { heuristic: true }) ]
   });
 
   do_print("search engine, after current engine has changed");
   Services.search.addEngineWithDetails("MozSearch2", "", "", "", "GET",
                                        "http://s.example.com/search2");
   engine = Services.search.getEngineByName("MozSearch2");
   notEqual(Services.search.currentEngine, engine, "New engine shouldn't be the current engine yet");
   Services.search.currentEngine = engine;
   yield check_autocomplete({
     search: "mozilla",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("mozilla", { engineName: "MozSearch2" }) ]
+    matches: [ makeSearchMatch("mozilla", { engineName: "MozSearch2", heuristic: true }) ]
   });
 
   yield cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_tabmatches.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_tabmatches.js
@@ -19,54 +19,54 @@ add_task(function* test_tab_matches() {
   // Pages that cannot be registered in history.
   addOpenPages(uri3, 1);
   addOpenPages(uri4, 1);
 
   do_print("two results, normal result is a tab match");
   yield check_autocomplete({
     search: "abc.com",
     searchParam: "enable-actions",
-    matches: [ makeVisitMatch("abc.com", "http://abc.com/"),
+    matches: [ makeVisitMatch("abc.com", "http://abc.com/", { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }) ]
   });
 
   do_print("three results, one tab match");
   yield check_autocomplete({
     search: "abc",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("abc"),
+    matches: [ makeSearchMatch("abc", { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
                { uri: uri2, title: "xyz.net - we're better than ABC", style: [ "favicon" ] } ]
   });
 
   do_print("three results, both normal results are tab matches");
   addOpenPages(uri2, 1);
   yield check_autocomplete({
     search: "abc",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("abc"),
+    matches: [ makeSearchMatch("abc", { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
                makeSwitchToTabMatch("http://xyz.net/", { title: "xyz.net - we're better than ABC" }) ]
   });
 
   do_print("three results, both normal results are tab matches, one has multiple tabs");
   addOpenPages(uri2, 5);
   yield check_autocomplete({
     search: "abc",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("abc"),
+    matches: [ makeSearchMatch("abc", { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
                makeSwitchToTabMatch("http://xyz.net/", { title: "xyz.net - we're better than ABC" }) ]
   });
 
   do_print("three results, no tab matches (disable-private-actions)");
   yield check_autocomplete({
     search: "abc",
     searchParam: "enable-actions disable-private-actions",
-    matches: [ makeSearchMatch("abc"),
+    matches: [ makeSearchMatch("abc", { heuristic: true }),
                { uri: uri1, title: "ABC rocks", style: [ "favicon" ] },
                { uri: uri2, title: "xyz.net - we're better than ABC", style: [ "favicon" ] } ]
   });
 
   do_print("two results (actions disabled)");
   yield check_autocomplete({
     search: "abc",
     searchParam: "",
@@ -75,50 +75,50 @@ add_task(function* test_tab_matches() {
   });
 
   do_print("three results, no tab matches");
   removeOpenPages(uri1, 1);
   removeOpenPages(uri2, 6);
   yield check_autocomplete({
     search: "abc",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("abc"),
+    matches: [ makeSearchMatch("abc", { heuristic: true }),
                { uri: uri1, title: "ABC rocks", style: [ "favicon" ] },
                { uri: uri2, title: "xyz.net - we're better than ABC", style: [ "favicon" ] } ]
   });
 
   do_print("tab match search with restriction character");
   addOpenPages(uri1, 1);
   yield check_autocomplete({
     search: gTabRestrictChar + " abc",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch(gTabRestrictChar + " abc"),
+    matches: [ makeSearchMatch(gTabRestrictChar + " abc", { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }) ]
   });
 
   do_print("tab match with not-addable pages");
   yield check_autocomplete({
     search: "mozilla",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("mozilla"),
+    matches: [ makeSearchMatch("mozilla", { heuristic: true }),
                makeSwitchToTabMatch("about:mozilla") ]
   });
 
   do_print("tab match with not-addable pages and restriction character");
   yield check_autocomplete({
     search: gTabRestrictChar + " mozilla",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch(gTabRestrictChar + " mozilla"),
+    matches: [ makeSearchMatch(gTabRestrictChar + " mozilla", { heuristic: true }),
                makeSwitchToTabMatch("about:mozilla") ]
   });
 
   do_print("tab match with not-addable pages and only restriction character");
   yield check_autocomplete({
     search: gTabRestrictChar,
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch(gTabRestrictChar),
+    matches: [ makeSearchMatch(gTabRestrictChar, { heuristic: true }),
                makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
                makeSwitchToTabMatch("about:mozilla"),
                makeSwitchToTabMatch("data:text/html,test") ]
   });
 
   yield cleanup();
 });
--- a/toolkit/components/places/tests/unifiedcomplete/test_visiturl.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_visiturl.js
@@ -2,75 +2,75 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 
 add_task(function*() {
   do_print("visit url, no protocol");
   yield check_autocomplete({
     search: "mozilla.org",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("visiturl", {url: "http://mozilla.org/", input: "mozilla.org"}), title: "http://mozilla.org/", style: [ "action", "visiturl" ] } ]
+    matches: [ { uri: makeActionURI("visiturl", {url: "http://mozilla.org/", input: "mozilla.org"}), title: "http://mozilla.org/", style: [ "action", "visiturl", "heuristic" ] } ]
   });
 
   do_print("visit url, with protocol");
   yield check_autocomplete({
     search: "https://mozilla.org",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("visiturl", {url: "https://mozilla.org/", input: "https://mozilla.org"}), title: "https://mozilla.org/", style: [ "action", "visiturl" ] } ]
+    matches: [ { uri: makeActionURI("visiturl", {url: "https://mozilla.org/", input: "https://mozilla.org"}), title: "https://mozilla.org/", style: [ "action", "visiturl", "heuristic" ] } ]
   });
 
   do_print("visit url, about: protocol (no host)");
   yield check_autocomplete({
     search: "about:config",
     searchParam: "enable-actions",
-    matches: [ { uri: makeActionURI("visiturl", {url: "about:config", input: "about:config"}), title: "about:config", style: [ "action", "visiturl" ] } ]
+    matches: [ { uri: makeActionURI("visiturl", {url: "about:config", input: "about:config"}), title: "about:config", style: [ "action", "visiturl", "heuristic" ] } ]
   });
 
   // This is distinct because of how we predict being able to url autofill via
   // host lookups.
   do_print("visit url, host matching visited host but not visited url");
   yield PlacesTestUtils.addVisits([
     { uri: NetUtil.newURI("http://mozilla.org/wine/"), title: "Mozilla Wine", transition: TRANSITION_TYPED },
   ]);
   yield check_autocomplete({
     search: "mozilla.org/rum",
     searchParam: "enable-actions",
-    matches: [ makeVisitMatch("mozilla.org/rum", "http://mozilla.org/rum") ]
+    matches: [ makeVisitMatch("mozilla.org/rum", "http://mozilla.org/rum", { heuristic: true }) ]
   });
 
   // And hosts with no dot in them are special, due to requiring whitelisting.
   do_print("visit url, host matching visited host but not visited url, non-whitelisted host");
   yield PlacesTestUtils.addVisits([
     { uri: NetUtil.newURI("http://mozilla/bourbon/"), title: "Mozilla Bourbon", transition: TRANSITION_TYPED },
   ]);
   yield check_autocomplete({
     search: "mozilla/rum",
     searchParam: "enable-actions",
-    matches: [ makeSearchMatch("mozilla/rum") ]
+    matches: [ makeSearchMatch("mozilla/rum", { heuristic: true }) ]
   });
 
   // ipv4 and ipv6 literal addresses should offer to visit.
   do_print("visit url, ipv4 literal");
   yield check_autocomplete({
     search: "127.0.0.1",
     searchParam: "enable-actions",
-    matches: [ makeVisitMatch("127.0.0.1", "http://127.0.0.1/") ]
+    matches: [ makeVisitMatch("127.0.0.1", "http://127.0.0.1/", { heuristic: true }) ]
   });
 
   do_print("visit url, ipv6 literal");
   yield check_autocomplete({
     search: "[2001:db8::1]",
     searchParam: "enable-actions",
-    matches: [ makeVisitMatch("[2001:db8::1]", "http://[2001:db8::1]/") ]
+    matches: [ makeVisitMatch("[2001:db8::1]", "http://[2001:db8::1]/", { heuristic: true }) ]
   });
 
   // Setting keyword.enabled to false should always try to visit.
   Services.prefs.setBoolPref("keyword.enabled", false);
   do_register_cleanup(() => {
     Services.prefs.clearUserPref("keyword.enabled");
   });
   do_print("visit url, keyword.enabled = false");
   yield check_autocomplete({
     search: "bacon",
     searchParam: "enable-actions",
-    matches: [ makeVisitMatch("bacon", "http://bacon/") ]
+    matches: [ makeVisitMatch("bacon", "http://bacon/", { heuristic: true }) ]
   });
 });
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -1378,34 +1378,33 @@ extends="chrome://global/content/binding
 
             this._adjustAcItem();
           ]]>
       </constructor>
 
       <property name="label" readonly="true">
         <getter>
           <![CDATA[
-            var title = this.getAttribute("title");
-            var url = this.getAttribute("url");
-            var panel = this.parentNode.parentNode;
+            // This property is a string that is read aloud by screen readers,
+            // so it must not contain anything that should not be user-facing.
+
+            let parts = [
+              this.getAttribute("title"),
+              this.getAttribute("url"),
+            ];
+            let label = parts.filter(str => str).join(" ")
 
             // allow consumers that have extended popups to override
             // the label values for the richlistitems
+            let panel = this.parentNode.parentNode;
             if (panel.createResultLabel) {
-              let types = this.getAttribute("type").split(/\s+/);
-              // We only want one type for createResultLabel, so get the first
-              // that isn't "action".
-              let type = types.find(v => v != "action");
-
-              return panel.createResultLabel(title, url, type);
+              return panel.createResultLabel(this, label);
             }
 
-            // aType (ex: "ac-result-type-<aType>") is related to the class of the image,
-            // and is not "visible" text so don't use it for the label (for accessibility).
-            return title + " " + url;
+            return label;
           ]]>
         </getter>
       </property>
 
       <property name="_stringBundle">
         <getter><![CDATA[
           if (!this.__stringBundle) {
             this.__stringBundle = Services.strings.createBundle("chrome://global/locale/autocomplete.properties");
@@ -1686,20 +1685,28 @@ extends="chrome://global/content/binding
 
           // The ellipses are hidden via their visibility so that they always
           // take up space and don't pop in on top of text when shown.  For
           // keyword searches, however, the title ellipsis should not take up
           // space when hidden.  Setting the hidden property accomplishes that.
           this._titleOverflowEllipsis.hidden = false;
 
           let types = new Set(type.split(/\s+/));
+
+          // Remove types that should ultimately not be in the `type` string.
           let initialTypes = new Set(types);
+          types.delete("action");
+          types.delete("autofill");
+          types.delete("heuristic");
+          types.delete("search");
+
+          type = [...types][0] || "";
 
           // If the type includes an action, set up the item appropriately.
-          if (types.has("action")) {
+          if (initialTypes.has("action")) {
             let action = this._parseActionUrl(url);
             this.setAttribute("actiontype", action.type);
 
             if (action.type == "switchtab") {
               this.classList.add("overridable-action");
               displayUrl = action.params.url;
               let desc = this._stringBundle.GetStringFromName("switchToTab");
               this._setUpDescription(this._action, desc, true);
@@ -1759,50 +1766,39 @@ extends="chrome://global/content/binding
               displayUrl = action.params.url;
 
               let sourceStr = this._stringBundle.GetStringFromName("visitURL");
               title = this._generateEmphasisPairs(sourceStr, [
                                                     [displayUrl, "match"],
                                                   ]);
             }
 
-            // Remove the "action" substring so that the correct style, if any,
-            // is applied below.
-            types.delete("action");
           }
 
           // Check if we have a search engine name
-          if (types.has("search")) {
+          if (initialTypes.has("search")) {
             emphasiseUrl = false;
 
             const TITLE_SEARCH_ENGINE_SEPARATOR = " \u00B7\u2013\u00B7 ";
 
             let searchEngine = "";
             [title, searchEngine] = title.split(TITLE_SEARCH_ENGINE_SEPARATOR);
             displayUrl = this._stringBundle.formatStringFromName("searchWithEngine", [searchEngine], 1);
-
-            // Remove the "search" substring so that the correct style, if any,
-            // is applied below.
-            types.delete("search");
           }
 
           // Check if we have an auto-fill URL
-          if (types.has("autofill")) {
+          if (initialTypes.has("autofill")) {
             emphasiseUrl = false;
 
             let sourceStr = this._stringBundle.GetStringFromName("visitURL");
             title = this._generateEmphasisPairs(sourceStr, [
                                                  [displayUrl, "match"],
                                                 ]);
-
-            types.delete("autofill");
           }
 
-          type = [...types].join(" ");
-
           // If we have a tag match, show the tags and icon
           if (type == "tag" || type == "bookmark-tag") {
             // Configure the extra box for tags display
             this._extraBox.hidden = false;
             this._extraBox.childNodes[0].hidden = false;
             this._extraBox.childNodes[1].hidden = true;
             this._extraBox.pack = "end";
             this._titleBox.flex = 1;
--- a/toolkit/devtools/server/tests/mochitest/chrome.ini
+++ b/toolkit/devtools/server/tests/mochitest/chrome.ini
@@ -73,16 +73,17 @@ skip-if = buildapp == 'mulet'
 [test_makeGlobalObjectReference.html]
 [test_memory.html]
 [test_memory_allocations_01.html]
 [test_memory_allocations_02.html]
 [test_memory_allocations_03.html]
 [test_memory_allocations_04.html]
 [test_memory_allocations_05.html]
 [test_memory_allocations_06.html]
+[test_memory_allocations_07.html]
 [test_memory_attach_01.html]
 [test_memory_attach_02.html]
 [test_memory_census.html]
 [test_memory_gc_01.html]
 [test_memory_gc_events.html]
 [test_preference.html]
 [test_registerActor.html]
 [test_SaveHeapSnapshot.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/mochitest/test_memory_allocations_07.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Bug 1192335 - Test getting the byte sizes for allocations.
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Memory monitoring actor test</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="memory-helpers.js" type="application/javascript;version=1.8"></script>
+<script>
+window.onload = function() {
+  SimpleTest.waitForExplicitFinish();
+
+  Task.spawn(function* () {
+    var { memory, client } = yield startServerAndGetSelectedTabMemory();
+    yield memory.attach();
+
+    var allocs = [];
+    function allocator() {
+      allocs.push(new Object);
+    }
+
+    yield memory.startRecordingAllocations();
+
+    allocator();
+    allocator();
+    allocator();
+
+    var response = yield memory.getAllocations();
+    yield memory.stopRecordingAllocations();
+
+    ok(response.allocationSizes, "The response should have bytesizes.");
+    is(response.allocationSizes.length, response.allocations.length,
+       "There should be a bytesize for every allocation.");
+    ok(response.allocationSizes.length >= 3,
+       "There are atleast 3 allocations.");
+    ok(response.allocationSizes.every(isPositiveNumber), "every bytesize is a positive number");
+
+    yield memory.detach();
+    destroyServerAndFinish(client);
+  });
+};
+
+function isPositiveNumber (n) {
+  return typeof n === "number" && n > 0;
+}
+</script>
+</pre>
+</body>
+</html>
--- a/toolkit/devtools/shared/memory.js
+++ b/toolkit/devtools/shared/memory.js
@@ -221,16 +221,21 @@ let Memory = exports.Memory = Class({
    *
    *            {
    *              allocations: [<index into "frames" below>, ...],
    *              allocationsTimestamps: [
    *                <timestamp for allocations[0]>,
    *                <timestamp for allocations[1]>,
    *                ...
    *              ],
+   *              allocationSizes: [
+   *                <bytesize for allocations[0]>,
+   *                <bytesize for allocations[1]>,
+   *                ...
+   *              ],
    *              frames: [
    *                {
    *                  line: <line number for this frame>,
    *                  column: <column number for this frame>,
    *                  source: <filename string for this frame>,
    *                  functionDisplayName: <this frame's inferred function name function or null>,
    *                  parent: <index into "frames">
    *                },
@@ -270,33 +275,35 @@ let Memory = exports.Memory = Class({
       reportException("MemoryBridge.prototype.getAllocations",
                       "Warning: allocations log overflowed and lost some data.");
     }
 
     const allocations = this.dbg.memory.drainAllocationsLog()
     const packet = {
       allocations: [],
       allocationsTimestamps: [],
+      allocationSizes: [],
     };
-    for (let { frame: stack, timestamp } of allocations) {
+    for (let { frame: stack, timestamp, size } of allocations) {
       if (stack && Cu.isDeadWrapper(stack)) {
         continue;
       }
 
       // Safe because SavedFrames are frozen/immutable.
       let waived = Cu.waiveXrays(stack);
 
-      // Ensure that we have a form, count, and index for new allocations
+      // Ensure that we have a form, size, and index for new allocations
       // because we potentially haven't seen some or all of them yet. After this
       // loop, we can rely on the fact that every frame we deal with already has
       // its metadata stored.
       let index = this._frameCache.addFrame(waived);
 
       packet.allocations.push(index);
       packet.allocationsTimestamps.push(timestamp);
+      packet.allocationSizes.push(size);
     }
 
     return this._frameCache.updateFramePacket(packet);
   }, `getting allocations`),
 
   /*
    * Force a browser-wide GC.
    */
--- a/toolkit/devtools/sourcemap/source-map.js
+++ b/toolkit/devtools/sourcemap/source-map.js
@@ -843,17 +843,17 @@ define('source-map/util', ['require', 'e
     var path = aPath;
     var url = urlParse(aPath);
     if (url) {
       if (!url.path) {
         return aPath;
       }
       path = url.path;
     }
-    var isAbsolute = (path.charAt(0) === '/');
+    var isAbsolute = exports.isAbsolute(path);
 
     var parts = path.split(/\/+/);
     for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
       part = parts[i];
       if (part === '.') {
         parts.splice(i, 1);
       } else if (part === '..') {
         up++;
@@ -938,16 +938,20 @@ define('source-map/util', ['require', 'e
     if (aRootUrl) {
       aRootUrl.path = joined;
       return urlGenerate(aRootUrl);
     }
     return joined;
   }
   exports.join = join;
 
+  exports.isAbsolute = function (aPath) {
+    return aPath.charAt(0) === '/' || !!aPath.match(urlRegexp);
+  };
+
   /**
    * Make a path relative to a URL or another path.
    *
    * @param aRoot The root path or URL.
    * @param aPath The path or URL to be made relative to aRoot.
    */
   function relative(aRoot, aPath) {
     if (aRoot === "") {
@@ -1612,20 +1616,30 @@ define('source-map/source-map-consumer',
     var file = util.getArg(sourceMap, 'file', null);
 
     // Once again, Sass deviates from the spec and supplies the version as a
     // string rather than a number, so we use loose equality checking here.
     if (version != this._version) {
       throw new Error('Unsupported version: ' + version);
     }
 
-    // Some source maps produce relative source paths like "./foo.js" instead of
-    // "foo.js".  Normalize these first so that future comparisons will succeed.
-    // See bugzil.la/1090768.
-    sources = sources.map(util.normalize);
+    sources = sources
+      // Some source maps produce relative source paths like "./foo.js" instead of
+      // "foo.js".  Normalize these first so that future comparisons will succeed.
+      // See bugzil.la/1090768.
+      .map(util.normalize)
+      // Always ensure that absolute sources are internally stored relative to
+      // the source root, if the source root is absolute. Not doing this would
+      // be particularly problematic when the source root is a prefix of the
+      // source (valid, but why??). See github issue #199 and bugzil.la/1188982.
+      .map(function (source) {
+        return sourceRoot && util.isAbsolute(sourceRoot) && util.isAbsolute(source)
+          ? util.relative(sourceRoot, source)
+          : source;
+      });
 
     // Pass `true` below to allow duplicate names and sources. While source maps
     // are intended to be compressed and deduplicated, the TypeScript compiler
     // sometimes generates source maps with duplicates in them. See Github issue
     // #72 and bugzil.la/889492.
     this._names = ArraySet.fromArray(names, true);
     this._sources = ArraySet.fromArray(sources, true);
 
--- a/toolkit/devtools/sourcemap/tests/unit/Utils.jsm
+++ b/toolkit/devtools/sourcemap/tests/unit/Utils.jsm
@@ -461,17 +461,17 @@ define('lib/source-map/util', ['require'
     var path = aPath;
     var url = urlParse(aPath);
     if (url) {
       if (!url.path) {
         return aPath;
       }
       path = url.path;
     }
-    var isAbsolute = (path.charAt(0) === '/');
+    var isAbsolute = exports.isAbsolute(path);
 
     var parts = path.split(/\/+/);
     for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
       part = parts[i];
       if (part === '.') {
         parts.splice(i, 1);
       } else if (part === '..') {
         up++;
@@ -556,16 +556,20 @@ define('lib/source-map/util', ['require'
     if (aRootUrl) {
       aRootUrl.path = joined;
       return urlGenerate(aRootUrl);
     }
     return joined;
   }
   exports.join = join;
 
+  exports.isAbsolute = function (aPath) {
+    return aPath.charAt(0) === '/' || !!aPath.match(urlRegexp);
+  };
+
   /**
    * Make a path relative to a URL or another path.
    *
    * @param aRoot The root path or URL.
    * @param aPath The path or URL to be made relative to aRoot.
    */
   function relative(aRoot, aPath) {
     if (aRoot === "") {
--- a/toolkit/devtools/sourcemap/tests/unit/test_source_map_consumer.js
+++ b/toolkit/devtools/sourcemap/tests/unit/test_source_map_consumer.js
@@ -1081,12 +1081,53 @@ define("test/source-map/test-source-map-
     // ... and then try and use the SourceMapGenerator again. This should not
     // throw.
     generator.toJSON();
 
     assert.ok(true, "Using a SourceMapGenerator again after creating a " +
                     "SourceMapConsumer from it should not throw");
   };
 
+  exports['test sources where their prefix is the source root: issue #199'] = function (assert, util) {
+    var testSourceMap = {
+      "version": 3,
+      "sources": ["/source/app/app/app.js"],
+      "names": ["System"],
+      "mappings": "AAAAA",
+      "file": "app/app.js",
+      "sourcesContent": ["'use strict';"],
+      "sourceRoot":"/source/"
+    };
+
+    var consumer = new SourceMapConsumer(testSourceMap);
+
+    function consumerHasSource(s) {
+      assert.ok(consumer.sourceContentFor(s));
+    }
+
+    consumer.sources.forEach(consumerHasSource);
+    testSourceMap.sources.forEach(consumerHasSource);
+  };
+
+  exports['test sources where their prefix is the source root and the source root is a url: issue #199'] = function (assert, util) {
+    var testSourceMap = {
+      "version": 3,
+      "sources": ["http://example.com/source/app/app/app.js"],
+      "names": ["System"],
+      "mappings": "AAAAA",
+      "sourcesContent": ["'use strict';"],
+      "sourceRoot":"http://example.com/source/"
+    };
+
+    var consumer = new SourceMapConsumer(testSourceMap);
+
+    function consumerHasSource(s) {
+      assert.ok(consumer.sourceContentFor(s));
+    }
+
+    consumer.sources.forEach(consumerHasSource);
+    testSourceMap.sources.forEach(consumerHasSource);
+  };
+
 });
 function run_test() {
   runSourceMapTests('test/source-map/test-source-map-consumer', do_throw);
 }
--- a/toolkit/locales/en-US/chrome/passwordmgr/passwordManager.dtd
+++ b/toolkit/locales/en-US/chrome/passwordmgr/passwordManager.dtd
@@ -32,8 +32,14 @@
 <!ENTITY      focusSearch1.key                "f">
 <!ENTITY      focusSearch2.key                "k">
 
 <!ENTITY      copyPasswordCmd.label           "Copy Password">
 <!ENTITY      copyPasswordCmd.accesskey       "C">
 
 <!ENTITY      copyUsernameCmd.label           "Copy Username">
 <!ENTITY      copyUsernameCmd.accesskey       "U">
+
+<!ENTITY      editPasswordCmd.label           "Edit Password">
+<!ENTITY      editPasswordCmd.accesskey       "E">
+
+<!ENTITY      editUsernameCmd.label           "Edit Username">
+<!ENTITY      editUsernameCmd.accesskey       "d">
--- a/xpcom/build/XPCOMInit.cpp
+++ b/xpcom/build/XPCOMInit.cpp
@@ -1,16 +1,17 @@
 /* -*- 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 "base/basictypes.h"
 
+#include "mozilla/AbstractThread.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Poison.h"
 #include "mozilla/SharedThreadPool.h"
 #include "mozilla/XPCOM.h"
 #include "nsXULAppAPI.h"
 
 #include "nsXPCOMPrivate.h"
 #include "nsXPCOMCIDInternal.h"
@@ -713,16 +714,19 @@ NS_InitXPCOM2(nsIServiceManager** aResul
   // After autoreg, but before we actually instantiate any components,
   // add any services listed in the "xpcom-directory-providers" category
   // to the directory service.
   nsDirectoryService::gService->RegisterCategoryProviders();
 
   // Init SharedThreadPool (which needs the service manager).
   SharedThreadPool::InitStatics();
 
+  // Init AbstractThread.
+  AbstractThread::InitStatics();
+
   // Force layout to spin up so that nsContentUtils is available for cx stack
   // munging.
   nsCOMPtr<nsISupports> componentLoader =
     do_GetService("@mozilla.org/moz/jsloader;1");
 
   mozilla::scache::StartupCache::GetSingleton();
   mozilla::AvailableMemoryTracker::Activate();
 
rename from dom/media/AbstractThread.cpp
rename to xpcom/threads/AbstractThread.cpp
rename from dom/media/AbstractThread.h
rename to xpcom/threads/AbstractThread.h
rename from dom/media/TaskDispatcher.h
rename to xpcom/threads/TaskDispatcher.h
--- a/xpcom/threads/moz.build
+++ b/xpcom/threads/moz.build
@@ -23,25 +23,28 @@ XPIDL_MODULE = 'xpcom_threads'
 EXPORTS += [
     'nsEventQueue.h',
     'nsMemoryPressure.h',
     'nsProcess.h',
     'nsThread.h',
 ]
 
 EXPORTS.mozilla += [
+    'AbstractThread.h',
     'BackgroundHangMonitor.h',
     'HangAnnotations.h',
     'HangMonitor.h',
     'LazyIdleThread.h',
     'SharedThreadPool.h',
     'SyncRunnable.h',
+    'TaskDispatcher.h',
 ]
 
 UNIFIED_SOURCES += [
+    'AbstractThread.cpp',
     'BackgroundHangMonitor.cpp',
     'HangAnnotations.cpp',
     'HangMonitor.cpp',
     'LazyIdleThread.cpp',
     'nsEnvironment.cpp',
     'nsEventQueue.cpp',
     'nsMemoryPressure.cpp',
     'nsProcessCommon.cpp',