Merge mozilla-central and fx-team
authorEd Morley <emorley@mozilla.com>
Fri, 15 Aug 2014 17:37:16 +0100
changeset 199841 4f430621992c83787aed08ffe8411841bb82d760
parent 199785 e05ba2d89374f1807f805915b86e1e14b0094044 (current diff)
parent 199840 abd2919b124b47afd188ffe709517835811150a6 (diff)
child 199842 54179c9a121a3d23d3dbc5167fa6b1bcbf65ed52
push id47750
push userryanvm@gmail.com
push dateFri, 15 Aug 2014 21:04:12 +0000
treeherdermozilla-inbound@baea646f5a80 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central and fx-team
browser/components/loop/test/mochitest/browser_mozLoop_charPref.js
browser/components/loop/test/xpcshell/test_loopservice_get_loop_char_pref.js
browser/components/loop/test/xpcshell/test_loopservice_set_loop_char_pref.js
browser/themes/linux/in-content/common.css
browser/themes/osx/in-content/common.css
browser/themes/shared/in-content/check.png
browser/themes/shared/in-content/check@2x.png
browser/themes/shared/in-content/common.inc.css
browser/themes/shared/in-content/dropdown-disabled.png
browser/themes/shared/in-content/dropdown-disabled@2x.png
browser/themes/shared/in-content/dropdown.png
browser/themes/shared/in-content/dropdown@2x.png
browser/themes/shared/in-content/help-glyph.png
browser/themes/shared/in-content/help-glyph@2x.png
browser/themes/shared/in-content/sorter.png
browser/themes/shared/in-content/sorter@2x.png
browser/themes/windows/in-content/common.css
mobile/android/base/home/SuggestClient.java
mobile/android/search/java/org/mozilla/search/autocomplete/SuggestClient.java
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1275,18 +1275,18 @@ pref("devtools.toolbar.enabled", true);
 pref("devtools.toolbar.visible", false);
 pref("devtools.commands.dir", "");
 
 // Enable the app manager
 pref("devtools.appmanager.enabled", true);
 pref("devtools.appmanager.lastTab", "help");
 pref("devtools.appmanager.manifestEditor.enabled", true);
 
-// Disable devtools webide until bug 1007059
-pref("devtools.webide.enabled", false);
+// Enable DevTools WebIDE by default
+pref("devtools.webide.enabled", true);
 
 // Toolbox preferences
 pref("devtools.toolbox.footer.height", 250);
 pref("devtools.toolbox.sidebar.width", 500);
 pref("devtools.toolbox.host", "bottom");
 pref("devtools.toolbox.selectedTool", "webconsole");
 pref("devtools.toolbox.toolbarSpec", '["splitconsole", "paintflashing toggle","tilt toggle","scratchpad","resize toggle","eyedropper","screenshot --fullpage"]');
 pref("devtools.toolbox.sideEnabled", true);
--- a/browser/base/content/aboutneterror/netError.css
+++ b/browser/base/content/aboutneterror/netError.css
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-@import url("chrome://browser/skin/in-content/common.css");
+@import url("chrome://global/skin/in-content/common.css");
 
 body {
   display: flex;
   box-sizing: padding-box;
   min-height: 100vh;
   padding: 0 48px;
   align-items: center;
   justify-content: center;
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -18,16 +18,20 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
                                   "resource://gre/modules/CharsetMenu.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
                                   "resource://gre/modules/ShortcutUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "GMPInstallManager",
                                   "resource://gre/modules/GMPInstallManager.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
+                                  "resource:///modules/ContentSearch.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AboutHome",
+                                  "resource:///modules/AboutHome.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
                                    "@mozilla.org/network/dns-service;1",
                                    "nsIDNSService");
 
 const nsIWebNavigation = Ci.nsIWebNavigation;
 
 var gLastBrowserCharset = null;
 var gPrevCharset = null;
@@ -3090,18 +3094,27 @@ const BrowserSearch = {
         win = window.openDialog(getBrowserURL(), "_blank",
                                 "chrome,all,dialog=no", "about:blank");
         Services.obs.addObserver(observer, "browser-delayed-startup-finished", false);
       }
       return;
     }
 #endif
     let openSearchPageIfFieldIsNotActive = function(aSearchBar) {
-      if (!aSearchBar || document.activeElement != aSearchBar.textbox.inputField)
+      let doc = gBrowser.selectedBrowser.contentDocument;
+      let url = doc.documentURI.toLowerCase();
+      let mm = gBrowser.selectedBrowser.messageManager;
+
+      if (url === "about:home") {
+        AboutHome.focusInput(mm);
+      } else if (url === "about:newtab") {
+        ContentSearch.focusInput(mm);
+      } else if (!aSearchBar || document.activeElement != aSearchBar.textbox.inputField) {
         openUILinkIn("about:home", "current");
+      }
     };
 
     let searchBar = this.searchBar;
     let placement = CustomizableUI.getPlacementOfWidget("search-container");
     let focusSearchBar = () => {
       searchBar = this.searchBar;
       searchBar.select();
       openSearchPageIfFieldIsNotActive(searchBar);
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -101,16 +101,19 @@ let AboutHomeListener = {
     }
   },
 
   receiveMessage: function(aMessage) {
     switch (aMessage.name) {
       case "AboutHome:Update":
         this.onUpdate(aMessage.data);
         break;
+      case "AboutHome:FocusInput":
+        this.onFocusInput();
+        break;
     }
   },
 
   onUpdate: function(aData) {
     let doc = content.document;
     if (doc.documentURI.toLowerCase() != "about:home")
       return;
 
@@ -133,16 +136,17 @@ let AboutHomeListener = {
     if (doc.documentURI.toLowerCase() != "about:home" ||
         doc.documentElement.hasAttribute("hasBrowserHandlers")) {
       return;
     }
 
     doc.documentElement.setAttribute("hasBrowserHandlers", "true");
     let self = this;
     addMessageListener("AboutHome:Update", self);
+    addMessageListener("AboutHome:FocusInput", self);
     addEventListener("click", this.onClick, true);
     addEventListener("pagehide", function onPageHide(event) {
       if (event.target.defaultView.frameElement)
         return;
       removeMessageListener("AboutHome:Update", self);
       removeEventListener("click", self.onClick, true);
       removeEventListener("pagehide", onPageHide, true);
       if (event.target.documentElement)
@@ -207,16 +211,20 @@ let AboutHomeListener = {
         sendAsyncMessage("AboutHome:Sync");
         break;
 
       case "settings":
         sendAsyncMessage("AboutHome:Settings");
         break;
     }
   },
+
+  onFocusInput: function () {
+    content.document.getElementById("searchText").focus();
+  },
 };
 AboutHomeListener.init(this);
 
 
 // An event listener for custom "WebChannelMessageToChrome" events on pages
 addEventListener("WebChannelMessageToChrome", function (e) {
   // if target is window then we want the document principal, otherwise fallback to target itself.
   let principal = e.target.nodePrincipal ? e.target.nodePrincipal : e.target.document.nodePrincipal;
--- a/browser/base/content/newtab/search.js
+++ b/browser/base/content/newtab/search.js
@@ -71,16 +71,20 @@ let gSearch = {
 
   onCurrentEngine: function (engineName) {
     if (this._initialStateReceived) {
       this._nodes.panel.hidePopup();
       this._setCurrentEngine(engineName);
     }
   },
 
+  onFocusInput: function () {
+    this._nodes.text.focus();
+  },
+
   _nodeIDSuffixes: [
     "form",
     "logo",
     "manage",
     "panel",
     "text",
   ],
 
--- a/browser/base/content/test/general/browser_aboutHome.js
+++ b/browser/base/content/test/general/browser_aboutHome.js
@@ -414,16 +414,32 @@ let gTests = [
 
       // Empty the search input, causing the suggestions to be hidden.
       EventUtils.synthesizeKey("a", { accelKey: true });
       EventUtils.synthesizeKey("VK_DELETE", {});
       ok(table.hidden, "Search suggestion table hidden");
     });
   }
 },
+{
+  desc: "Cmd+k should focus the search bar element",
+  setup: function () {},
+  run: Task.async(function* () {
+    let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
+    let logo = doc.getElementById("brandLogo");
+    let searchInput = doc.getElementById("searchText");
+
+    EventUtils.synthesizeMouseAtCenter(logo, {});
+    isnot(searchInput, doc.activeElement, "Search input should not be the active element.");
+
+    EventUtils.synthesizeKey("k", { accelKey: true });
+    yield promiseWaitForCondition(() => doc.activeElement === searchInput);
+    is(searchInput, doc.activeElement, "Search input should be the active element.");
+  })
+},
 
 ];
 
 function test()
 {
   waitForExplicitFinish();
   requestLongerTimeout(2);
   ignoreAllUncaughtExceptions();
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -77,16 +77,22 @@ function waitForCondition(condition, nex
     if (conditionPassed) {
       moveOn();
     }
     tries++;
   }, 100);
   var moveOn = function() { clearInterval(interval); nextTest(); };
 }
 
+function promiseWaitForCondition(aConditionFn) {
+  let deferred = Promise.defer();
+  waitForCondition(aConditionFn, deferred.resolve, "Condition didn't pass.");
+  return deferred.promise;
+}
+
 function getTestPlugin(aName) {
   var pluginName = aName || "Test Plug-in";
   var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
   var tags = ph.getPluginTags();
 
   // Find the test plugin
   for (var i = 0; i < tags.length; i++) {
     if (tags[i].name == pluginName)
--- a/browser/base/content/test/newtab/browser_newtab_search.js
+++ b/browser/base/content/test/newtab/browser_newtab_search.js
@@ -181,16 +181,26 @@ function runTests() {
   yield undefined;
   yield suggestionsPromise.then(TestRunner.next);
 
   // Empty the search input, causing the suggestions to be hidden.
   EventUtils.synthesizeKey("a", { accelKey: true });
   EventUtils.synthesizeKey("VK_DELETE", {});
   ok(table.hidden, "Search suggestion table hidden");
 
+  // Focus a different element than the search input.
+  let btn = getContentDocument().getElementById("newtab-customize-button");
+  yield promiseClick(btn).then(TestRunner.next);
+
+  isnot(input, getContentDocument().activeElement, "Search input should not be focused");
+  // Test that Ctrl/Cmd + K will focus the input field.
+  EventUtils.synthesizeKey("k", { accelKey: true });
+  yield promiseSearchEvents(["FocusInput"]).then(TestRunner.next);
+  is(input, getContentDocument().activeElement, "Search input should be focused");
+
   // Done.  Revert the current engine and remove the new engines.
   Services.search.currentEngine = oldCurrentEngine;
   yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
 
   let events = [];
   for (let engine of gNewEngines) {
     Services.search.removeEngine(engine);
     events.push("CurrentState");
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -304,16 +304,18 @@ function openLinkIn(url, where, params) 
       loadInBackground = false;
     }
   }
 
   // Raise the target window before loading the URI, since loading it may
   // result in a new frontmost window (e.g. "javascript:window.open('');").
   w.focus();
 
+  let newTab;
+
   switch (where) {
   case "current":
     let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
 
     if (aAllowThirdPartyFixup) {
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
       flags |= Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
     }
@@ -327,32 +329,39 @@ function openLinkIn(url, where, params) 
 
     w.gBrowser.loadURIWithFlags(url, flags, aReferrerURI, null, aPostData);
     break;
   case "tabshifted":
     loadInBackground = !loadInBackground;
     // fall through
   case "tab":
     let browser = w.gBrowser;
-    browser.loadOneTab(url, {
-                       referrerURI: aReferrerURI,
-                       charset: aCharset,
-                       postData: aPostData,
-                       inBackground: loadInBackground,
-                       allowThirdPartyFixup: aAllowThirdPartyFixup,
-                       relatedToCurrent: aRelatedToCurrent,
-                       skipAnimation: aSkipTabAnimation,
-                       allowMixedContent: aAllowMixedContent });
+    newTab = browser.loadOneTab(url, {
+                                referrerURI: aReferrerURI,
+                                charset: aCharset,
+                                postData: aPostData,
+                                inBackground: loadInBackground,
+                                allowThirdPartyFixup: aAllowThirdPartyFixup,
+                                relatedToCurrent: aRelatedToCurrent,
+                                skipAnimation: aSkipTabAnimation,
+                                allowMixedContent: aAllowMixedContent });
     break;
   }
 
   w.gBrowser.selectedBrowser.focus();
 
-  if (!loadInBackground && w.isBlankPageURL(url))
+  if (!loadInBackground && w.isBlankPageURL(url)) {
+    if (newTab) {
+      // Remote tab content does not focus synchronously, so we set the flag
+      // on this tab to skip focusing the content if we want to focus the URL
+      // bar instead.
+      newTab._urlbarFocused = true;
+    }
     w.focusAndSelectUrlBar();
+  }
 }
 
 // Used as an onclick handler for UI elements with link-like behavior.
 // e.g. onclick="checkForMiddleClick(this, event);"
 function checkForMiddleClick(node, event) {
   // We should be using the disabled property here instead of the attribute,
   // but some elements that this function is used with don't support it (e.g.
   // menuitem).
--- a/browser/components/loop/MozLoopAPI.jsm
+++ b/browser/components/loop/MozLoopAPI.jsm
@@ -156,16 +156,37 @@ function injectLoopAPI(targetWindow) {
       enumerable: true,
       writable: true,
       value: function(prefName) {
         return MozLoopService.getLoopCharPref(prefName);
       }
     },
 
     /**
+     * Return any preference under "loop." that's coercible to a boolean
+     * preference.
+     *
+     * @param {String} prefName The name of the pref without the preceding
+     * "loop."
+     *
+     * Any errors thrown by the Mozilla pref API are logged to the console
+     * and cause null to be returned. This includes the case of the preference
+     * not being found.
+     *
+     * @return {String} on success, null on error
+     */
+    getLoopBoolPref: {
+      enumerable: true,
+      writable: true,
+      value: function(prefName) {
+        return MozLoopService.getLoopBoolPref(prefName);
+      }
+    },
+
+    /**
      * Starts alerting the user about an incoming call
      */
     startAlerting: {
       enumerable: true,
       writable: true,
       value: function() {
         let chromeWindow = getChromeWindow(targetWindow);
         chromeWindow.getAttention();
--- a/browser/components/loop/MozLoopService.jsm
+++ b/browser/components/loop/MozLoopService.jsm
@@ -609,16 +609,39 @@ this.MozLoopService = {
     } catch (ex) {
       console.log("getLoopCharPref had trouble getting " + prefName +
         "; exception: " + ex);
       return null;
     }
   },
 
   /**
+   * Return any preference under "loop." that's coercible to a character
+   * preference.
+   *
+   * @param {String} prefName The name of the pref without the preceding
+   * "loop."
+   *
+   * Any errors thrown by the Mozilla pref API are logged to the console
+   * and cause null to be returned. This includes the case of the preference
+   * not being found.
+   *
+   * @return {String} on success, null on error
+   */
+  getLoopBoolPref: function(prefName) {
+    try {
+      return Services.prefs.getBoolPref("loop." + prefName);
+    } catch (ex) {
+      console.log("getLoopBoolPref had trouble getting " + prefName +
+        "; exception: " + ex);
+      return null;
+    }
+  },
+
+  /**
    * Performs a hawk based request to the loop server.
    *
    * @param {String} path The path to make the request to.
    * @param {String} method The request method, e.g. 'POST', 'GET'.
    * @param {Object} payloadObj An object which is converted to JSON and
    *                            transmitted with the request.
    * @returns {Promise}
    *        Returns a promise that resolves to the response of the API call,
--- a/browser/components/loop/test/mochitest/browser.ini
+++ b/browser/components/loop/test/mochitest/browser.ini
@@ -1,8 +1,8 @@
 [DEFAULT]
 support-files =
     head.js
 
 [browser_mozLoop_appVersionInfo.js]
-[browser_mozLoop_charPref.js]
+[browser_mozLoop_prefs.js]
 [browser_mozLoop_doNotDisturb.js]
 skip-if = buildapp == 'mulet'
rename from browser/components/loop/test/mochitest/browser_mozLoop_charPref.js
rename to browser/components/loop/test/mochitest/browser_mozLoop_prefs.js
--- a/browser/components/loop/test/mochitest/browser_mozLoop_charPref.js
+++ b/browser/components/loop/test/mochitest/browser_mozLoop_prefs.js
@@ -19,8 +19,22 @@ add_task(function* test_mozLoop_charPref
   gMozLoopAPI.setLoopCharPref("test", "foo");
   Assert.equal(Services.prefs.getCharPref("loop.test"), "foo",
                "should set loop pref value correctly");
 
   // Test getLoopCharPref
   Assert.equal(gMozLoopAPI.getLoopCharPref("test"), "foo",
                "should get loop pref value correctly");
 });
+
+add_task(function* test_mozLoop_boolPref() {
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("loop.testBool");
+  });
+
+  Assert.ok(gMozLoopAPI, "mozLoop should exist");
+
+  Services.prefs.setBoolPref("loop.testBool", true);
+
+  // Test getLoopCharPref
+  Assert.equal(gMozLoopAPI.getLoopBoolPref("testBool"), true,
+               "should get loop pref value correctly");
+});
rename from browser/components/loop/test/xpcshell/test_loopservice_get_loop_char_pref.js
rename to browser/components/loop/test/xpcshell/test_loopservice_loop_prefs.js
--- a/browser/components/loop/test/xpcshell/test_loopservice_get_loop_char_pref.js
+++ b/browser/components/loop/test/xpcshell/test_loopservice_loop_prefs.js
@@ -1,47 +1,106 @@
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 /*global XPCOMUtils, Services, Assert */
 
-var fakePrefName = "color";
+var fakeCharPrefName = "color";
+var fakeBoolPrefName = "boolean";
 var fakePrefValue = "green";
 
 function test_getLoopCharPref()
 {
-  Services.prefs.setCharPref("loop." + fakePrefName, fakePrefValue);
+  Services.prefs.setCharPref("loop." + fakeCharPrefName, fakePrefValue);
 
-  var returnedPref = MozLoopService.getLoopCharPref(fakePrefName);
+  var returnedPref = MozLoopService.getLoopCharPref(fakeCharPrefName);
 
   Assert.equal(returnedPref, fakePrefValue,
     "Should return a char pref under the loop. branch");
-  Services.prefs.clearUserPref("loop." + fakePrefName);
+  Services.prefs.clearUserPref("loop." + fakeCharPrefName);
 }
 
 function test_getLoopCharPref_not_found()
 {
-  var returnedPref = MozLoopService.getLoopCharPref(fakePrefName);
+  var returnedPref = MozLoopService.getLoopCharPref(fakeCharPrefName);
 
   Assert.equal(returnedPref, null,
     "Should return null if a preference is not found");
 }
 
 function test_getLoopCharPref_non_coercible_type()
 {
-  Services.prefs.setBoolPref("loop." + fakePrefName, false );
+  Services.prefs.setBoolPref("loop." + fakeCharPrefName, false);
 
-  var returnedPref = MozLoopService.getLoopCharPref(fakePrefName);
+  var returnedPref = MozLoopService.getLoopCharPref(fakeCharPrefName);
 
   Assert.equal(returnedPref, null,
     "Should return null if the preference exists & is of a non-coercible type");
 }
 
+function test_setLoopCharPref()
+{
+  Services.prefs.setCharPref("loop." + fakeCharPrefName, "red");
+  MozLoopService.setLoopCharPref(fakeCharPrefName, fakePrefValue);
+
+  var returnedPref = Services.prefs.getCharPref("loop." + fakeCharPrefName);
+
+  Assert.equal(returnedPref, fakePrefValue,
+    "Should set a char pref under the loop. branch");
+  Services.prefs.clearUserPref("loop." + fakeCharPrefName);
+}
+
+function test_setLoopCharPref_new()
+{
+  Services.prefs.clearUserPref("loop." + fakeCharPrefName);
+  MozLoopService.setLoopCharPref(fakeCharPrefName, fakePrefValue);
+
+  var returnedPref = Services.prefs.getCharPref("loop." + fakeCharPrefName);
+
+  Assert.equal(returnedPref, fakePrefValue,
+               "Should set a new char pref under the loop. branch");
+  Services.prefs.clearUserPref("loop." + fakeCharPrefName);
+}
+
+function test_setLoopCharPref_non_coercible_type()
+{
+  MozLoopService.setLoopCharPref(fakeCharPrefName, true);
+
+  ok(true, "Setting non-coercible type should not fail");
+}
+
+
+function test_getLoopBoolPref()
+{
+  Services.prefs.setBoolPref("loop." + fakeBoolPrefName, true);
+
+  var returnedPref = MozLoopService.getLoopBoolPref(fakeBoolPrefName);
+
+  Assert.equal(returnedPref, true,
+    "Should return a bool pref under the loop. branch");
+  Services.prefs.clearUserPref("loop." + fakeBoolPrefName);
+}
+
+function test_getLoopBoolPref_not_found()
+{
+  var returnedPref = MozLoopService.getLoopBoolPref(fakeBoolPrefName);
+
+  Assert.equal(returnedPref, null,
+    "Should return null if a preference is not found");
+}
+
 
 function run_test()
 {
   test_getLoopCharPref();
   test_getLoopCharPref_not_found();
   test_getLoopCharPref_non_coercible_type();
+  test_setLoopCharPref();
+  test_setLoopCharPref_new();
+  test_setLoopCharPref_non_coercible_type();
+
+  test_getLoopBoolPref();
+  test_getLoopBoolPref_not_found();
 
   do_register_cleanup(function() {
-    Services.prefs.clearUserPref("loop." + fakePrefName);
+    Services.prefs.clearUserPref("loop." + fakeCharPrefName);
+    Services.prefs.clearUserPref("loop." + fakeBoolPrefName);
   });
 }
deleted file mode 100644
--- a/browser/components/loop/test/xpcshell/test_loopservice_set_loop_char_pref.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-/*global XPCOMUtils, Services, Assert */
-
-var fakePrefName = "color";
-var fakePrefValue = "green";
-
-function test_setLoopCharPref()
-{
-  Services.prefs.setCharPref("loop." + fakePrefName, "red");
-  MozLoopService.setLoopCharPref(fakePrefName, fakePrefValue);
-
-  var returnedPref = Services.prefs.getCharPref("loop." + fakePrefName);
-
-  Assert.equal(returnedPref, fakePrefValue,
-    "Should set a char pref under the loop. branch");
-  Services.prefs.clearUserPref("loop." + fakePrefName);
-}
-
-function test_setLoopCharPref_new()
-{
-  Services.prefs.clearUserPref("loop." + fakePrefName);
-  MozLoopService.setLoopCharPref(fakePrefName, fakePrefValue);
-
-  var returnedPref = Services.prefs.getCharPref("loop." + fakePrefName);
-
-  Assert.equal(returnedPref, fakePrefValue,
-               "Should set a new char pref under the loop. branch");
-  Services.prefs.clearUserPref("loop." + fakePrefName);
-}
-
-function test_setLoopCharPref_non_coercible_type()
-{
-  MozLoopService.setLoopCharPref(fakePrefName, true);
-
-  ok(true, "Setting non-coercible type should not fail");
-}
-
-
-function run_test()
-{
-  test_setLoopCharPref();
-  test_setLoopCharPref_new();
-  test_setLoopCharPref_non_coercible_type();
-
-  do_register_cleanup(function() {
-    Services.prefs.clearUserPref("loop." + fakePrefName);
-  });
-}
--- a/browser/components/loop/test/xpcshell/xpcshell.ini
+++ b/browser/components/loop/test/xpcshell/xpcshell.ini
@@ -1,17 +1,16 @@
 [DEFAULT]
 head = head.js
 tail =
 firefox-appdir = browser
 
 [test_looppush_initialize.js]
 [test_loopservice_dnd.js]
 [test_loopservice_expiry.js]
-[test_loopservice_get_loop_char_pref.js]
-[test_loopservice_set_loop_char_pref.js]
+[test_loopservice_loop_prefs.js]
 [test_loopservice_initialize.js]
 [test_loopservice_locales.js]
 [test_loopservice_registration.js]
 [test_loopservice_token_invalid.js]
 [test_loopservice_token_save.js]
 [test_loopservice_token_send.js]
 [test_loopservice_token_validation.js]
--- a/browser/components/preferences/in-content/preferences.xul
+++ b/browser/components/preferences/in-content/preferences.xul
@@ -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/. -->
 
 <?xml-stylesheet href="chrome://global/skin/global.css"?>
 
 <?xml-stylesheet href="chrome://mozapps/content/preferences/preferences.css"?>
 
 <?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css"?>
-<?xml-stylesheet href="chrome://browser/skin/in-content/common.css"?>
+<?xml-stylesheet href="chrome://global/skin/in-content/common.css"?>
 <?xml-stylesheet
   href="chrome://browser/skin/preferences/in-content/preferences.css"?>
 <?xml-stylesheet
   href="chrome://browser/content/preferences/handlers.css"?>
 <?xml-stylesheet href="chrome://browser/skin/preferences/applications.css"?>
 
 <!DOCTYPE page [
 <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
--- a/browser/components/preferences/in-content/subdialogs.js
+++ b/browser/components/preferences/in-content/subdialogs.js
@@ -6,17 +6,17 @@
 
 let gSubDialog = {
   _closingCallback: null,
   _frame: null,
   _overlay: null,
   _box: null,
   _injectedStyleSheets: ["chrome://mozapps/content/preferences/preferences.css",
                          "chrome://browser/skin/preferences/preferences.css",
-                         "chrome://browser/skin/in-content/common.css",
+                         "chrome://global/skin/in-content/common.css",
                          "chrome://browser/skin/preferences/in-content/preferences.css"],
 
   init: function() {
     this._frame = document.getElementById("dialogFrame");
     this._overlay = document.getElementById("dialogOverlay");
     this._box = document.getElementById("dialogBox");
 
     // Make the close button work.
--- a/browser/devtools/framework/test/browser_dynamic_tool_enabling.js
+++ b/browser/devtools/framework/test/browser_dynamic_tool_enabling.js
@@ -1,16 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that toggling prefs immediately (de)activates the relevant menuitem
 
 let gItemsToTest = {
   "menu_devToolbar": "devtools.toolbar.enabled",
-  "menu_devAppMgr": "devtools.appmanager.enabled",
   "menu_browserToolbox": ["devtools.chrome.enabled", "devtools.debugger.remote-enabled", "devtools.debugger.chrome-enabled"],
   "javascriptConsole": "devtools.errorconsole.enabled",
   "menu_devtools_connect": "devtools.debugger.remote-enabled",
 };
 
 function expectedAttributeValueFromPrefs(prefs) {
   return prefs.every((pref) => Services.prefs.getBoolPref(pref)) ?
          "" : "true";
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -71,16 +71,17 @@ function Toolbox(target, selectedTool, h
   this._refreshHostTitle = this._refreshHostTitle.bind(this);
   this._splitConsoleOnKeypress = this._splitConsoleOnKeypress.bind(this);
   this.destroy = this.destroy.bind(this);
   this.highlighterUtils = getHighlighterUtils(this);
   this._highlighterReady = this._highlighterReady.bind(this);
   this._highlighterHidden = this._highlighterHidden.bind(this);
   this._prefChanged = this._prefChanged.bind(this);
   this._saveSplitConsoleHeight = this._saveSplitConsoleHeight.bind(this);
+  this._onFocus = this._onFocus.bind(this);
 
   this._target.on("close", this.destroy);
 
   if (!hostType) {
     hostType = Services.prefs.getCharPref(this._prefs.LAST_HOST);
   }
   if (!selectedTool) {
     selectedTool = Services.prefs.getCharPref(this._prefs.LAST_TOOL);
@@ -248,36 +249,39 @@ Toolbox.prototype = {
         gDevTools.on("pref-changed", this._prefChanged);
 
         this._buildDockButtons();
         this._buildOptions();
         this._buildTabs();
         this._applyCacheSettings();
         this._addKeysToWindow();
         this._addReloadKeys();
-        this._addToolSwitchingKeys();
+        this._addHostListeners();
         this._addZoomKeys();
         this._loadInitialZoom();
 
         this.webconsolePanel = this.doc.querySelector("#toolbox-panel-webconsole");
         this.webconsolePanel.height =
           Services.prefs.getIntPref(SPLITCONSOLE_HEIGHT_PREF);
         this.webconsolePanel.addEventListener("resize",
           this._saveSplitConsoleHeight);
 
-        let splitConsolePromise = promise.resolve();
-        if (Services.prefs.getBoolPref(SPLITCONSOLE_ENABLED_PREF)) {
-          splitConsolePromise = this.openSplitConsole();
-        }
-
         let buttonsPromise = this._buildButtons();
 
         this._telemetry.toolOpened("toolbox");
 
         this.selectTool(this._defaultToolId).then(panel => {
+
+          // Wait until the original tool is selected so that the split
+          // console input will receive focus.
+          let splitConsolePromise = promise.resolve();
+          if (Services.prefs.getBoolPref(SPLITCONSOLE_ENABLED_PREF)) {
+            splitConsolePromise = this.openSplitConsole();
+          }
+
           promise.all([
             splitConsolePromise,
             buttonsPromise
           ]).then(() => {
             this.emit("ready");
             deferred.resolve();
           }, deferred.reject);
         });
@@ -340,25 +344,27 @@ Toolbox.prototype = {
       ["toolbox-force-reload-key2", true]
     ].forEach(([id, force]) => {
       this.doc.getElementById(id).addEventListener("command", (event) => {
         this.reloadTarget(force);
       }, true);
     });
   },
 
-  _addToolSwitchingKeys: function() {
+  _addHostListeners: function() {
     let nextKey = this.doc.getElementById("toolbox-next-tool-key");
     nextKey.addEventListener("command", this.selectNextTool.bind(this), true);
     let prevKey = this.doc.getElementById("toolbox-previous-tool-key");
     prevKey.addEventListener("command", this.selectPreviousTool.bind(this), true);
 
     // Split console uses keypress instead of command so the event can be
     // cancelled with stopPropagation on the keypress, and not preventDefault.
     this.doc.addEventListener("keypress", this._splitConsoleOnKeypress, false);
+
+    this.doc.addEventListener("focus", this._onFocus, true);
   },
 
   _saveSplitConsoleHeight: function() {
     Services.prefs.setIntPref(SPLITCONSOLE_HEIGHT_PREF,
       this.webconsolePanel.height);
   },
 
   /**
@@ -971,49 +977,71 @@ Toolbox.prototype = {
     let iframe = this.doc.getElementById("toolbox-panel-iframe-" + id);
     iframe.focus();
   },
 
   /**
    * Focus split console's input line
    */
   focusConsoleInput: function() {
-    let hud = this.getPanel("webconsole").hud;
-    if (hud && hud.jsterm) {
-      hud.jsterm.inputNode.focus();
+    let consolePanel = this.getPanel("webconsole");
+    if (consolePanel) {
+      consolePanel.focusInput();
     }
   },
 
   /**
+   * If the console is split and we are focusing an element outside
+   * of the console, then store the newly focused element, so that
+   * it can be restored once the split console closes.
+   */
+  _onFocus: function({originalTarget}) {
+    // Ignore any non element nodes, or any elements contained
+    // within the webconsole frame.
+    let webconsoleURL = gDevTools.getToolDefinition("webconsole").url;
+    if (originalTarget.nodeType !== 1 ||
+        originalTarget.baseURI === webconsoleURL) {
+      return;
+    }
+
+    this._lastFocusedElement = originalTarget;
+  },
+
+  /**
    * Opens the split console.
    *
    * @returns {Promise} a promise that resolves once the tool has been
    *          loaded and focused.
    */
   openSplitConsole: function() {
     this._splitConsole = true;
     Services.prefs.setBoolPref(SPLITCONSOLE_ENABLED_PREF, true);
     this._refreshConsoleDisplay();
     this.emit("split-console");
+
     return this.loadTool("webconsole").then(() => {
       this.focusConsoleInput();
     });
   },
 
   /**
    * Closes the split console.
    *
    * @returns {Promise} a promise that resolves once the tool has been
    *          closed.
    */
   closeSplitConsole: function() {
     this._splitConsole = false;
     Services.prefs.setBoolPref(SPLITCONSOLE_ENABLED_PREF, false);
     this._refreshConsoleDisplay();
     this.emit("split-console");
+
+    if (this._lastFocusedElement) {
+      this._lastFocusedElement.focus();
+    }
     return promise.resolve();
   },
 
   /**
    * Toggles the split state of the webconsole.  If the webconsole panel
    * is already selected then this command is ignored.
    *
    * @returns {Promise} a promise that resolves once the tool has been
@@ -1307,16 +1335,17 @@ Toolbox.prototype = {
   /**
    * Destroy the current host, and remove event listeners from its frame.
    *
    * @return {promise} to be resolved when the host is destroyed.
    */
   destroyHost: function() {
     this.doc.removeEventListener("keypress",
       this._splitConsoleOnKeypress, false);
+    this.doc.removeEventListener("focus", this._onFocus, true);
     return this._host.destroy();
   },
 
   /**
    * Remove all UI elements, detach from target and clear up
    */
   destroy: function() {
     // If several things call destroy then we give them all the same
@@ -1329,16 +1358,17 @@ Toolbox.prototype = {
     this.off("select", this._refreshHostTitle);
     this.off("host-changed", this._refreshHostTitle);
 
     gDevTools.off("tool-registered", this._toolRegistered);
     gDevTools.off("tool-unregistered", this._toolUnregistered);
 
     gDevTools.off("pref-changed", this._prefChanged);
 
+    this._lastFocusedElement = null;
     this._saveSplitConsoleHeight();
     this.webconsolePanel.removeEventListener("resize",
       this._saveSplitConsoleHeight);
     this.closeButton.removeEventListener("command", this.destroy, true);
 
     let outstanding = [];
     for (let [id, panel] of this._toolPanels) {
       try {
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -1609,18 +1609,21 @@ var Scratchpad = {
     };
 
     this.editor = new Editor(config);
     let editorElement = document.querySelector("#scratchpad-editor");
     this.editor.appendTo(editorElement).then(() => {
       var lines = initialText.split("\n");
 
       this.editor.on("change", this._onChanged);
+      let okstring = this.strings.GetStringFromName("selfxss.okstring");
+      let msg = this.strings.formatStringFromName("selfxss.msg", [okstring], 1);
       this._onPaste = WebConsoleUtils.pasteHandlerGen(this.editor.container.contentDocument.body,
-                                                      document.querySelector('#scratchpad-notificationbox'));
+                                                      document.querySelector('#scratchpad-notificationbox'),
+                                                      msg, okstring);
       editorElement.addEventListener("paste", this._onPaste);
       editorElement.addEventListener("drop", this._onPaste);
       this.editor.on("save", () => this.saveFile());
       this.editor.focus();
       this.editor.setCursor({ line: lines.length, ch: lines.pop().length });
 
       if (state)
         this.dirty = !state.saved;
--- a/browser/devtools/webaudioeditor/test/browser_wa_inspector-toggle.js
+++ b/browser/devtools/webaudioeditor/test/browser_wa_inspector-toggle.js
@@ -53,14 +53,14 @@ function spawnTest() {
 
   click(panelWin, findGraphNode(panelWin, nodeIds[1]));
   yield once(panelWin, EVENTS.UI_INSPECTOR_NODE_SET);
 
   ok(!isVisible($("#web-audio-editor-details-pane-empty")),
     "Empty message hides even when loading node while open.");
   ok(isVisible($("#web-audio-editor-tabs")),
     "Switches to tab view when loading node while open.");
-  is($("#web-audio-inspector-title").value, "OscillatorNode (" + nodeIds[1] + ")",
+  is($("#web-audio-inspector-title").value, "Oscillator",
     "Inspector title updates when loading node while open.");
 
   yield teardown(panel);
   finish();
 }
--- a/browser/devtools/webaudioeditor/test/browser_wa_inspector.js
+++ b/browser/devtools/webaudioeditor/test/browser_wa_inspector.js
@@ -38,23 +38,23 @@ function spawnTest() {
   ]);
 
   ok(WebAudioInspectorView.isVisible(), "InspectorView shown once node selected.");
   ok(!isVisible($("#web-audio-editor-details-pane-empty")),
     "InspectorView empty message hidden when node selected.");
   ok(isVisible($("#web-audio-editor-tabs")),
     "InspectorView tabs view visible when node selected.");
 
-  is($("#web-audio-inspector-title").value, "OscillatorNode (" + nodeIds[1] + ")",
+  is($("#web-audio-inspector-title").value, "Oscillator",
     "Inspector should have the node title when a node is selected.");
 
   is($("#web-audio-editor-tabs").selectedIndex, 0,
     "default tab selected should be the parameters tab.");
 
   click(panelWin, findGraphNode(panelWin, nodeIds[2]));
   yield once(panelWin, EVENTS.UI_INSPECTOR_NODE_SET);
 
-  is($("#web-audio-inspector-title").value, "GainNode (" + nodeIds[2] + ")",
+  is($("#web-audio-inspector-title").value, "Gain",
     "Inspector title updates when a new node is selected.");
 
   yield teardown(panel);
   finish();
 }
--- a/browser/devtools/webaudioeditor/webaudioeditor-view.js
+++ b/browser/devtools/webaudioeditor/webaudioeditor-view.js
@@ -151,17 +151,21 @@ let WebAudioGraphView = {
     // Clear out previous SVG information
     this.clearGraph();
 
     let graph = new dagreD3.Digraph();
     let edges = [];
 
     AudioNodes.forEach(node => {
       // Add node to graph
-      graph.addNode(node.id, { label: node.type, id: node.id });
+      graph.addNode(node.id, {
+        type: node.type,                        // Just for storing type data
+        label: node.type.replace(/Node$/, ""),  // Displayed in SVG node
+        id: node.id                             // Identification
+      });
 
       // Add all of the connections from this node to the edge array to be added
       // after all the nodes are added, otherwise edges will attempted to be created
       // for nodes that have not yet been added
       AudioNodeConnections.get(node, new Set()).forEach(dest => edges.push([node, dest]));
     });
 
     edges.forEach(([node, dest]) => graph.addEdge(null, node.id, dest.id, {
@@ -172,17 +176,17 @@ let WebAudioGraphView = {
     let renderer = new dagreD3.Renderer();
 
     // Post-render manipulation of the nodes
     let oldDrawNodes = renderer.drawNodes();
     renderer.drawNodes(function(graph, root) {
       let svgNodes = oldDrawNodes(graph, root);
       svgNodes.attr("class", (n) => {
         let node = graph.node(n);
-        return "audionode type-" + node.label;
+        return "audionode type-" + node.type;
       });
       svgNodes.attr("data-id", (n) => {
         let node = graph.node(n);
         return node.id;
       });
       return svgNodes;
     });
 
@@ -447,17 +451,17 @@ let WebAudioInspectorView = {
     this.toggleInspector({ visible: false, animated: false, delayed: false });
   },
 
   /**
    * Sets the title of the Inspector view
    */
   _setTitle: function () {
     let node = this._currentNode;
-    let title = node.type + " (" + node.id + ")";
+    let title = node.type.replace(/Node$/, "");
     $("#web-audio-inspector-title").setAttribute("value", title);
   },
 
   /**
    * Reconstructs the `Properties` tab in the inspector
    * with the `this._currentNode` as it's source.
    */
   _buildPropertiesView: Task.async(function* () {
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -276,16 +276,17 @@ skip-if = buildapp == 'mulet'
 [browser_webconsole_notifications.js]
 [browser_webconsole_open-links-without-callback.js]
 [browser_webconsole_output_copy_newlines.js]
 [browser_webconsole_output_order.js]
 [browser_webconsole_property_provider.js]
 [browser_webconsole_scratchpad_panel_link.js]
 [browser_webconsole_split.js]
 [browser_webconsole_split_escape_key.js]
+[browser_webconsole_split_focus.js]
 [browser_webconsole_split_persist.js]
 [browser_webconsole_view_source.js]
 [browser_webconsole_reflow.js]
 [browser_webconsole_log_file_filter.js]
 [browser_webconsole_expandable_timestamps.js]
 [browser_webconsole_autocomplete_in_debugger_stackframe.js]
 [browser_webconsole_autocomplete_popup_close_on_tab_switch.js]
 [browser_webconsole_autocomplete-properties-with-non-alphanumeric-names.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_split_focus.js
@@ -0,0 +1,74 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+function test() {
+  info("Test that the split console state is persisted");
+
+  let toolbox;
+  let TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for splitting</p>";
+
+  Task.spawn(runner).then(finish);
+
+  function* runner() {
+    info("Opening a tab while there is no user setting on split console pref");
+    let {tab} = yield loadTab(TEST_URI);
+    let target = TargetFactory.forTab(tab);
+    toolbox = yield gDevTools.showToolbox(target, "inspector");
+
+    ok(!toolbox.splitConsole, "Split console is hidden by default");
+
+    info ("Focusing the search box before opening the split console");
+    let inspector = toolbox.getPanel("inspector");
+    inspector.searchBox.focus();
+
+    // Use the binding element since inspector.searchBox is a XUL element.
+    let activeElement = getActiveElement(inspector.panelDoc);
+    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+    is (activeElement, inspector.searchBox, "Search box is focused");
+
+    yield toolbox.openSplitConsole();
+
+    ok(toolbox.splitConsole, "Split console is now visible");
+
+    // Use the binding element since jsterm.inputNode is a XUL textarea element.
+    let activeElement = getActiveElement(toolbox.doc);
+    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+    let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
+    is(activeElement, inputNode, "Split console input is focused by default");
+
+    yield toolbox.closeSplitConsole();
+
+    info ("Making sure that the search box is refocused after closing the split console");
+    // Use the binding element since inspector.searchBox is a XUL element.
+    let activeElement = getActiveElement(inspector.panelDoc);
+    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+    is (activeElement, inspector.searchBox, "Search box is focused");
+
+    yield toolbox.destroy();
+  }
+
+  function getActiveElement(doc) {
+    let activeElement = doc.activeElement;
+    while (activeElement && activeElement.contentDocument) {
+      activeElement = activeElement.contentDocument.activeElement;
+    }
+    return activeElement;
+  }
+
+  function toggleSplitConsoleWithEscape() {
+    let onceSplitConsole = toolbox.once("split-console");
+    let contentWindow = toolbox.frame.contentWindow;
+    contentWindow.focus();
+    EventUtils.sendKey("ESCAPE", contentWindow);
+    return onceSplitConsole;
+  }
+
+  function finish() {
+    toolbox = TEST_URI = null;
+    Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
+    Services.prefs.clearUserPref("devtools.toolbox.splitconsoleHeight");
+    finishTest();
+  }
+}
--- a/browser/devtools/webconsole/test/browser_webconsole_split_persist.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_split_persist.js
@@ -30,16 +30,22 @@ function test() {
     info("Opening a tab while there is a true user setting on split console pref");
     let {tab} = yield loadTab(TEST_URI);
     let target = TargetFactory.forTab(tab);
     toolbox = yield gDevTools.showToolbox(target, "inspector");
 
     ok(toolbox.splitConsole, "Split console is visible by default.");
     is(getHeightPrefValue(), 200, "Height is set based on panel height after closing");
 
+    // Use the binding element since jsterm.inputNode is a XUL textarea element.
+    let activeElement = getActiveElement(toolbox.doc);
+    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
+    let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
+    is(activeElement, inputNode, "Split console input is focused by default");
+
     toolbox.webconsolePanel.height = 1;
     ok (toolbox.webconsolePanel.clientHeight > 1,
         "The actual height of the console is bound with a min height");
 
     toolbox.webconsolePanel.height = 10000;
     ok (toolbox.webconsolePanel.clientHeight < 10000,
         "The actual height of the console is bound with a max height");
 
@@ -58,16 +64,24 @@ function test() {
     toolbox = yield gDevTools.showToolbox(target, "inspector");
 
     ok(!toolbox.splitConsole, "Split console is hidden by default.");
     ok(!getVisiblePrefValue(), "Visibility pref is false");
 
     yield toolbox.destroy();
   }
 
+  function getActiveElement(doc) {
+    let activeElement = doc.activeElement;
+    while (activeElement && activeElement.contentDocument) {
+      activeElement = activeElement.contentDocument.activeElement;
+    }
+    return activeElement;
+  }
+
   function getVisiblePrefValue() {
     return Services.prefs.getBoolPref("devtools.toolbox.splitconsoleEnabled");
   }
 
   function getHeightPrefValue() {
     return Services.prefs.getIntPref("devtools.toolbox.splitconsoleHeight");
   }
 
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -3132,17 +3132,21 @@ JSTerm.prototype = {
     this.completeNode = doc.querySelector(".jsterm-complete-node");
     this.inputNode = doc.querySelector(".jsterm-input-node");
 
     if (this.hud.owner._browserConsole &&
         !Services.prefs.getBoolPref("devtools.chrome.enabled")) {
       inputContainer.style.display = "none";
     }
     else {
-      this._onPaste = WebConsoleUtils.pasteHandlerGen(this.inputNode, doc.getElementById("webconsole-notificationbox"));
+      let okstring = l10n.getStr("selfxss.okstring");
+      let msg = l10n.getFormatStr("selfxss.msg", [okstring]);
+      this._onPaste = WebConsoleUtils.pasteHandlerGen(this.inputNode,
+                                                      doc.getElementById("webconsole-notificationbox"),
+                                                      msg, okstring);
       this.inputNode.addEventListener("keypress", this._keyPress, false);
       this.inputNode.addEventListener("paste", this._onPaste);
       this.inputNode.addEventListener("drop", this._onPaste);
       this.inputNode.addEventListener("input", this._inputEventHandler, false);
       this.inputNode.addEventListener("keyup", this._inputEventHandler, false);
       this.inputNode.addEventListener("focus", this._focusEventHandler, false);
     }
 
--- a/browser/locales/en-US/chrome/browser/devtools/scratchpad.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/scratchpad.properties
@@ -98,8 +98,18 @@ scratchpad.label=Scratchpad
 # LOCALIZATION NOTE (scratchpad.panelLabel): this is used as the
 # label for the toolbox panel.
 scratchpad.panelLabel=Scratchpad Panel
 
 # LOCALIZATION NOTE (scratchpad.tooltip):  This string is displayed in the
 # tooltip of the tab when the Scratchpad is displayed inside the developer tools
 # window.
 scratchpad.tooltip=Scratchpad
+
+# LOCALIZATION NOTE (selfxss.msg): the text that is displayed when
+# a new user of the developer tools pastes code into the console
+# %1 is the text of selfxss.okstring
+selfxss.msg=Scam Warning: Take care when pasting things you don't understand. This could allow attackers to steal your identity or take control of your computer. Please type '%S' in the scratchpad below to allow pasting.
+
+# LOCALIZATION NOTE (selfxss.msg): the string to be typed
+# in by a new user of the developer tools when they receive the sefxss.msg prompt.
+# Please avoid using non-keyboard characters here
+selfxss.okstring=allow pasting
--- a/browser/modules/AboutHome.jsm
+++ b/browser/modules/AboutHome.jsm
@@ -246,9 +246,18 @@ let AboutHome = {
       } else {
         let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
         mm.broadcastAsyncMessage("AboutHome:Update", data);
       }
     }).then(null, function onError(x) {
       Cu.reportError("Error in AboutHome.sendAboutHomeData: " + x);
     });
   },
+
+  /**
+   * Focuses the search input in the page with the given message manager.
+   * @param  messageManager
+   *         The MessageManager object of the selected browser.
+   */
+  focusInput: function (messageManager) {
+    messageManager.sendAsyncMessage("AboutHome:FocusInput");
+  }
 };
--- a/browser/modules/ContentSearch.jsm
+++ b/browser/modules/ContentSearch.jsm
@@ -89,16 +89,27 @@ this.ContentSearch = {
 
   init: function () {
     Cc["@mozilla.org/globalmessagemanager;1"].
       getService(Ci.nsIMessageListenerManager).
       addMessageListener(INBOUND_MESSAGE, this);
     Services.obs.addObserver(this, "browser-search-engine-modified", false);
   },
 
+  /**
+   * Focuses the search input in the page with the given message manager.
+   * @param  messageManager
+   *         The MessageManager object of the selected browser.
+   */
+  focusInput: function (messageManager) {
+    messageManager.sendAsyncMessage(OUTBOUND_MESSAGE, {
+      type: "FocusInput"
+    });
+  },
+
   receiveMessage: function (msg) {
     // Add a temporary event handler that exists only while the message is in
     // the event queue.  If the message's source docshell changes browsers in
     // the meantime, then we need to update msg.target.  event.detail will be
     // the docshell's new parent <xul:browser> element.
     msg.handleEvent = event => {
       let browserData = this._suggestionMap.get(msg.target);
       if (browserData) {
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -876,17 +876,16 @@ toolbarbutton[sdk-button="true"][cui-are
   -moz-box-direction: reverse;
 }
 
 #urlbar-icons {
   -moz-box-align: center;
 }
 
 .urlbar-icon {
-  cursor: pointer;
   padding: 0 3px;
 }
 
 #urlbar-search-splitter {
   -moz-appearance: none;
   width: 8px;
   -moz-margin-start: -4px;
 }
@@ -1519,17 +1518,16 @@ richlistitem[type~="action"][actiontype=
   border-top: 1px solid GrayText;
 }
 
 /* Combined go/reload/stop button in location bar */
 
 #urlbar > toolbarbutton {
   -moz-appearance: none;
   padding: 0 2px;
-  cursor: pointer;
   list-style-image: url("chrome://browser/skin/reload-stop-go.png");
 }
 
 #urlbar-reload-button {
   -moz-image-region: rect(0, 14px, 14px, 0);
 }
 
 #urlbar-reload-button:not([disabled]):hover {
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -30,27 +30,16 @@ browser.jar:
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity-icons-generic.png
   skin/classic/browser/identity-icons-https.png
   skin/classic/browser/identity-icons-https-ev.png
   skin/classic/browser/identity-icons-https-mixed-active.png
   skin/classic/browser/identity-icons-https-mixed-display.png
   skin/classic/browser/Info.png
-* skin/classic/browser/in-content/common.css                    (in-content/common.css)
-  skin/classic/browser/in-content/check.png                 (../shared/in-content/check.png)
-  skin/classic/browser/in-content/check@2x.png              (../shared/in-content/check@2x.png)
-  skin/classic/browser/in-content/dropdown.png              (../shared/in-content/dropdown.png)
-  skin/classic/browser/in-content/dropdown@2x.png           (../shared/in-content/dropdown@2x.png)
-  skin/classic/browser/in-content/dropdown-disabled.png     (../shared/in-content/dropdown-disabled.png)
-  skin/classic/browser/in-content/dropdown-disabled@2x.png  (../shared/in-content/dropdown-disabled@2x.png)
-  skin/classic/browser/in-content/help-glyph.png            (../shared/in-content/help-glyph.png)
-  skin/classic/browser/in-content/help-glyph@2x.png         (../shared/in-content/help-glyph@2x.png)
-  skin/classic/browser/in-content/sorter.png                (../shared/in-content/sorter.png)
-  skin/classic/browser/in-content/sorter@2x.png             (../shared/in-content/sorter@2x.png)
   skin/classic/browser/menuPanel.png
   skin/classic/browser/menuPanel-customize.png
   skin/classic/browser/menuPanel-exit.png
   skin/classic/browser/menuPanel-help.png
   skin/classic/browser/menuPanel-small.png
   skin/classic/browser/mixed-content-blocked-16.png
   skin/classic/browser/mixed-content-blocked-64.png
   skin/classic/browser/monitor.png
--- a/browser/themes/linux/searchbar.css
+++ b/browser/themes/linux/searchbar.css
@@ -52,17 +52,16 @@
 /* Search go button */
 .search-go-container {
   -moz-box-align: center;
 }
 
 .search-go-button {
   padding: 1px;
   list-style-image: url(moz-icon://stock/gtk-find?size=menu);
-  cursor: pointer;
 }
 
 menuitem[cmd="cmd_clearhistory"] {
   list-style-image: url("moz-icon://stock/gtk-clear?size=menu");
 }
 
 menuitem[cmd="cmd_clearhistory"][disabled] {
   list-style-image: url("moz-icon://stock/gtk-clear?size=menu&state=disabled");
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -38,27 +38,16 @@ browser.jar:
   skin/classic/browser/identity-icons-https@2x.png
   skin/classic/browser/identity-icons-https-ev.png
   skin/classic/browser/identity-icons-https-ev@2x.png
   skin/classic/browser/identity-icons-https-mixed-active.png
   skin/classic/browser/identity-icons-https-mixed-active@2x.png
   skin/classic/browser/identity-icons-https-mixed-display.png
   skin/classic/browser/identity-icons-https-mixed-display@2x.png
   skin/classic/browser/Info.png
-* skin/classic/browser/in-content/common.css                (in-content/common.css)
-  skin/classic/browser/in-content/check.png                 (../shared/in-content/check.png)
-  skin/classic/browser/in-content/check@2x.png              (../shared/in-content/check@2x.png)
-  skin/classic/browser/in-content/dropdown.png              (../shared/in-content/dropdown.png)
-  skin/classic/browser/in-content/dropdown@2x.png           (../shared/in-content/dropdown@2x.png)
-  skin/classic/browser/in-content/dropdown-disabled.png     (../shared/in-content/dropdown-disabled.png)
-  skin/classic/browser/in-content/dropdown-disabled@2x.png  (../shared/in-content/dropdown-disabled@2x.png)
-  skin/classic/browser/in-content/help-glyph.png            (../shared/in-content/help-glyph.png)
-  skin/classic/browser/in-content/help-glyph@2x.png         (../shared/in-content/help-glyph@2x.png)
-  skin/classic/browser/in-content/sorter.png                (../shared/in-content/sorter.png)
-  skin/classic/browser/in-content/sorter@2x.png             (../shared/in-content/sorter@2x.png)
   skin/classic/browser/keyhole-circle.png
   skin/classic/browser/keyhole-circle@2x.png
   skin/classic/browser/KUI-background.png
   skin/classic/browser/subtle-pattern.png
   skin/classic/browser/menu-back.png
   skin/classic/browser/menu-forward.png
   skin/classic/browser/notification-16.png
   skin/classic/browser/notification-16@2x.png
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -892,24 +892,24 @@ toolbarbutton[panel-multiview-anchor="tr
   background-repeat: no-repeat;
   background-color: Highlight;
   background-position: left 10px center, 0; /* this doesn't need to be changed for RTL */
 }
 
 toolbarbutton[panel-multiview-anchor="true"] {
   background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted.png),
                     linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
-  background-position: right 5px center;
+  background-position: right calc(@menuPanelButtonWidth@ / 2 - @exitSubviewGutterWidth@ + 2px) center;
   background-repeat: no-repeat, repeat;
 }
 
 toolbarbutton[panel-multiview-anchor="true"]:-moz-locale-dir(rtl) {
   background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted-rtl.png),
                     linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
-  background-position: left 5px center;
+  background-position: left calc(@menuPanelButtonWidth@ / 2 - @exitSubviewGutterWidth@ + 2px) center;
 }
 
 toolbarpaletteitem[place="palette"] > .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
 #bookmarks-menu-button[cui-areatype="menu-panel"] > .toolbarbutton-menubutton-dropmarker {
   display: none;
 }
 
 #search-container[cui-areatype="menu-panel"],
--- a/browser/themes/shared/devtools/webaudioeditor.inc.css
+++ b/browser/themes/shared/devtools/webaudioeditor.inc.css
@@ -94,16 +94,20 @@ text {
 .theme-light g.selected text {
   fill: #f0f1f2; /* Toolbars */
 }
 
 /**
  * Inspector Styles
  */
 
+#web-audio-inspector-title {
+  margin: 6px;
+}
+
 .web-audio-inspector .error {
   background-image: url(alerticon-warning.png);
   background-size: 13px 12px;
   -moz-appearance: none;
   opacity: 0;
   transition: opacity .5s ease-out 0s;
 }
 
--- a/browser/themes/shared/incontentprefs/preferences.css
+++ b/browser/themes/shared/incontentprefs/preferences.css
@@ -162,32 +162,32 @@ prefpane {
   padding: 0 10px;
 }
 
 #typeColumn > .treecol-sortdirection[sortDirection=ascending],
 #actionColumn > .treecol-sortdirection[sortDirection=ascending],
 #typeColumn > .treecol-sortdirection[sortDirection=descending],
 #actionColumn > .treecol-sortdirection[sortDirection=descending] {
   -moz-appearance: none;
-  list-style-image: url("chrome://browser/skin/in-content/sorter.png");
+  list-style-image: url("chrome://global/skin/in-content/sorter.png");
 }
 
 #typeColumn > .treecol-sortdirection[sortDirection=descending],
 #actionColumn > .treecol-sortdirection[sortDirection=descending] {
   transform: scaleY(-1);
 }
 
 @media (min-resolution: 2dppx) {
   #typeColumn > .treecol-sortdirection[sortDirection=ascending],
   #actionColumn > .treecol-sortdirection[sortDirection=ascending],
   #typeColumn > .treecol-sortdirection[sortDirection=descending],
   #actionColumn > .treecol-sortdirection[sortDirection=descending] {
     width: 12px;
     height: 8px;
-    list-style-image: url("chrome://browser/skin/in-content/sorter@2x.png");
+    list-style-image: url("chrome://global/skin/in-content/sorter@2x.png");
   }
 }
 
 #handlersView > richlistitem {
   min-height: 40px !important;
 }
 
 .typeIcon {
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -32,27 +32,16 @@ browser.jar:
         skin/classic/browser/Geolocation-64.png
         skin/classic/browser/Info.png
         skin/classic/browser/identity.png
         skin/classic/browser/identity-icons-generic.png
         skin/classic/browser/identity-icons-https.png
         skin/classic/browser/identity-icons-https-ev.png
         skin/classic/browser/identity-icons-https-mixed-active.png
         skin/classic/browser/identity-icons-https-mixed-display.png
-*       skin/classic/browser/in-content/common.css                  (in-content/common.css)
-        skin/classic/browser/in-content/check.png                   (../shared/in-content/check.png)
-        skin/classic/browser/in-content/check@2x.png                (../shared/in-content/check@2x.png)
-        skin/classic/browser/in-content/dropdown.png                (../shared/in-content/dropdown.png)
-        skin/classic/browser/in-content/dropdown@2x.png             (../shared/in-content/dropdown@2x.png)
-        skin/classic/browser/in-content/dropdown-disabled.png       (../shared/in-content/dropdown-disabled.png)
-        skin/classic/browser/in-content/dropdown-disabled@2x.png    (../shared/in-content/dropdown-disabled@2x.png)
-        skin/classic/browser/in-content/help-glyph.png              (../shared/in-content/help-glyph.png)
-        skin/classic/browser/in-content/help-glyph@2x.png           (../shared/in-content/help-glyph@2x.png)
-        skin/classic/browser/in-content/sorter.png                  (../shared/in-content/sorter.png)
-        skin/classic/browser/in-content/sorter@2x.png               (../shared/in-content/sorter@2x.png)
         skin/classic/browser/keyhole-forward-mask.svg
         skin/classic/browser/KUI-background.png
         skin/classic/browser/livemark-folder.png
         skin/classic/browser/menu-back.png
         skin/classic/browser/menu-forward.png
         skin/classic/browser/menuPanel.png
         skin/classic/browser/menuPanel-customize.png
         skin/classic/browser/menuPanel-exit.png
@@ -452,27 +441,16 @@ browser.jar:
         skin/classic/aero/browser/Geolocation-64.png
         skin/classic/aero/browser/Info.png                           (Info-aero.png)
         skin/classic/aero/browser/identity.png                       (identity-aero.png)
         skin/classic/aero/browser/identity-icons-generic.png
         skin/classic/aero/browser/identity-icons-https.png
         skin/classic/aero/browser/identity-icons-https-ev.png
         skin/classic/aero/browser/identity-icons-https-mixed-active.png
         skin/classic/aero/browser/identity-icons-https-mixed-display.png
-*       skin/classic/aero/browser/in-content/common.css               (in-content/common.css)
-        skin/classic/aero/browser/in-content/check.png                (../shared/in-content/check.png)
-        skin/classic/aero/browser/in-content/check@2x.png             (../shared/in-content/check@2x.png)
-        skin/classic/aero/browser/in-content/dropdown.png             (../shared/in-content/dropdown.png)
-        skin/classic/aero/browser/in-content/dropdown@2x.png          (../shared/in-content/dropdown@2x.png)
-        skin/classic/aero/browser/in-content/dropdown-disabled.png    (../shared/in-content/dropdown-disabled.png)
-        skin/classic/aero/browser/in-content/dropdown-disabled@2x.png (../shared/in-content/dropdown-disabled@2x.png)
-        skin/classic/aero/browser/in-content/help-glyph.png           (../shared/in-content/help-glyph.png)
-        skin/classic/aero/browser/in-content/help-glyph@2x.png        (../shared/in-content/help-glyph@2x.png)
-        skin/classic/aero/browser/in-content/sorter.png               (../shared/in-content/sorter.png)
-        skin/classic/aero/browser/in-content/sorter@2x.png            (../shared/in-content/sorter@2x.png)
         skin/classic/aero/browser/keyhole-forward-mask.svg
         skin/classic/aero/browser/KUI-background.png
         skin/classic/aero/browser/livemark-folder.png                (livemark-folder-aero.png)
         skin/classic/aero/browser/menu-back.png                      (menu-back-aero.png)
         skin/classic/aero/browser/menu-forward.png                   (menu-forward-aero.png)
         skin/classic/aero/browser/menuPanel.png
         skin/classic/aero/browser/menuPanel-aero.png
         skin/classic/aero/browser/menuPanel-customize.png
--- a/dom/plugins/base/nsIPluginTag.idl
+++ b/dom/plugins/base/nsIPluginTag.idl
@@ -1,16 +1,16 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(0e56f04d-cda4-4a55-ab83-e5e29ddd370e)]
+[scriptable, uuid(231df043-3a32-43c4-aaac-7ad2da81e84f)]
 interface nsIPluginTag : nsISupports
 {
   // enabledState is stored as one of the following as an integer in prefs,
   // so if new states are added, they must not renumber the existing states.
   const unsigned long STATE_DISABLED = 0;
   const unsigned long STATE_CLICKTOPLAY = 1;
   const unsigned long STATE_ENABLED = 2;
 
@@ -20,16 +20,21 @@ interface nsIPluginTag : nsISupports
   readonly attribute AUTF8String version;
   readonly attribute AUTF8String name;
 
   /**
    * true only if this plugin is "hardblocked" and cannot be enabled.
    */
   readonly attribute boolean blocklisted;
 
+  /**
+   * true if the state is non-default and locked, false otherwise.
+   */
+  readonly attribute boolean isEnabledStateLocked;
+
   readonly attribute boolean disabled;
   readonly attribute boolean clicktoplay;
            attribute unsigned long enabledState;
 
   readonly attribute PRTime lastModifiedTime;
 
   void getMimeTypes([optional] out unsigned long aCount,
                     [retval, array, size_is(aCount)] out wstring aResults);
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -11,16 +11,17 @@
 #include "nsPluginsDir.h"
 #include "nsPluginHost.h"
 #include "nsIBlocklistService.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsIPlatformCharset.h"
 #include "nsPluginLogging.h"
 #include "nsNPAPIPlugin.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/unused.h"
 #include <cctype>
 #include "mozilla/dom/EncodingUtils.h"
 
 using mozilla::dom::EncodingUtils;
 using namespace mozilla;
 
 // These legacy flags are used in the plugin registry. The states are now
 // stored in prefs, but we still need to be able to import them.
@@ -335,16 +336,32 @@ nsPluginTag::IsBlocklisted()
 
 NS_IMETHODIMP
 nsPluginTag::GetBlocklisted(bool* aBlocklisted)
 {
   *aBlocklisted = IsBlocklisted();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsPluginTag::GetIsEnabledStateLocked(bool* aIsEnabledStateLocked)
+{
+  *aIsEnabledStateLocked = false;
+  nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
+
+  if (NS_WARN_IF(!prefs)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  unused << prefs->PrefIsLocked(GetStatePrefNameForPlugin(this).get(),
+                                aIsEnabledStateLocked);
+
+  return NS_OK;
+}
+
 bool
 nsPluginTag::IsClicktoplay()
 {
   const PluginState state = GetPluginState();
   return (state == ePluginState_Clicktoplay);
 }
 
 NS_IMETHODIMP
rename from mobile/android/base/home/SuggestClient.java
rename to mobile/android/base/SuggestClient.java
--- a/mobile/android/base/home/SuggestClient.java
+++ b/mobile/android/base/SuggestClient.java
@@ -1,16 +1,18 @@
 /* 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/. */
 
-package org.mozilla.gecko.home;
+package org.mozilla.gecko;
 
+import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.mozglue.RobocopTarget;
+import org.mozilla.gecko.util.HardwareUtils;
 
 import org.json.JSONArray;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.text.TextUtils;
 import android.util.Log;
@@ -23,17 +25,21 @@ import java.net.URL;
 import java.net.URLEncoder;
 import java.util.ArrayList;
 
 /**
  * Use network-based search suggestions.
  */
 public class SuggestClient {
     private static final String LOGTAG = "GeckoSuggestClient";
-    private static final String USER_AGENT = GeckoAppShell.getGeckoInterface().getDefaultUAString();
+
+    // This should go through GeckoInterface to get the UA, but the search activity
+    // doesn't use a GeckoView yet. Until it does, get the UA directly.
+    private static final String USER_AGENT = HardwareUtils.isTablet() ?
+        AppConstants.USER_AGENT_FENNEC_TABLET : AppConstants.USER_AGENT_FENNEC_MOBILE;
 
     private final Context mContext;
     private final int mTimeout;
 
     // should contain the string "__searchTerms__", which is replaced with the query
     private final String mSuggestTemplate;
 
     // the maximum number of suggestions to return
@@ -107,17 +113,17 @@ public class SuggestClient {
 
             if (json != null) {
                 /*
                  * Sample result:
                  * ["foo",["food network","foothill college","foot locker",...]]
                  */
                 JSONArray results = new JSONArray(json);
                 JSONArray jsonSuggestions = results.getJSONArray(1);
-                
+
                 int added = 0;
                 for (int i = 0; (i < jsonSuggestions.length()) && (added < mMaxResults); i++) {
                     String suggestion = jsonSuggestions.getString(i);
                     if (!suggestion.equalsIgnoreCase(query)) {
                         suggestions.add(suggestion);
                         added++;
                     }
                 }
--- a/mobile/android/base/home/BrowserSearch.java
+++ b/mobile/android/base/home/BrowserSearch.java
@@ -14,16 +14,17 @@ import java.util.Locale;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.PrefsHelper;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.SuggestClient;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.db.BrowserContract.History;
 import org.mozilla.gecko.db.BrowserContract.URLColumns;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
 import org.mozilla.gecko.home.SearchLoader.SearchCursorLoader;
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -297,17 +297,16 @@ gbjar.sources += [
     'home/PinSiteDialog.java',
     'home/ReadingListPanel.java',
     'home/ReadingListRow.java',
     'home/RecentTabsPanel.java',
     'home/SearchEngine.java',
     'home/SearchEngineRow.java',
     'home/SearchLoader.java',
     'home/SimpleCursorLoader.java',
-    'home/SuggestClient.java',
     'home/TabMenuStrip.java',
     'home/TabMenuStripLayout.java',
     'home/TopSitesGridItemView.java',
     'home/TopSitesGridView.java',
     'home/TopSitesPanel.java',
     'home/TopSitesThumbnailView.java',
     'home/TwoLinePageRow.java',
     'InputMethods.java',
@@ -374,16 +373,17 @@ gbjar.sources += [
     'SessionParser.java',
     'SharedPreferencesHelper.java',
     'SiteIdentity.java',
     'SmsManager.java',
     'sqlite/ByteBufferInputStream.java',
     'sqlite/MatrixBlobCursor.java',
     'sqlite/SQLiteBridge.java',
     'sqlite/SQLiteBridgeException.java',
+    'SuggestClient.java',
     'SurfaceBits.java',
     'Tab.java',
     'Tabs.java',
     'tabs/PrivateTabsPanel.java',
     'tabs/RemoteTabsContainerPanel.java',
     'tabs/RemoteTabsList.java',
     'tabs/RemoteTabsPanel.java',
     'tabs/RemoteTabsSetupPanel.java',
--- a/mobile/android/base/resources/layout-large-land-v11/tabs_panel.xml
+++ b/mobile/android/base/resources/layout-large-land-v11/tabs_panel.xml
@@ -41,21 +41,20 @@
                                          gecko:tabs="tabs_normal"/>
 
         <org.mozilla.gecko.tabs.PrivateTabsPanel
                 android:id="@+id/private_tabs_panel"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:visibility="gone"/>
 
-        <org.mozilla.gecko.tabs.RemoteTabsPanel
-                android:id="@+id/remote_tabs"
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:visibility="gone"/>
+        <ViewStub android:id="@+id/remote_tabs_panel_stub"
+                  android:layout="@layout/remote_tabs_panel_view"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent"/>
 
     </view>
 
     <RelativeLayout android:id="@+id/tabs_panel_footer"
                     android:layout_width="match_parent"
                     android:layout_height="@dimen/browser_toolbar_height">
 
         <view class="org.mozilla.gecko.tabs.TabsPanel$TabsPanelToolbar"
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/layout/remote_tabs_panel_view.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<org.mozilla.gecko.tabs.RemoteTabsPanel xmlns:android="http://schemas.android.com/apk/res/android"
+                                        android:id="@+id/remote_tabs_panel"
+                                        android:layout_width="match_parent"
+                                        android:layout_height="match_parent"/>
--- a/mobile/android/base/resources/layout/tabs_panel.xml
+++ b/mobile/android/base/resources/layout/tabs_panel.xml
@@ -40,17 +40,16 @@
                                          gecko:tabs="tabs_normal"/>
 
         <org.mozilla.gecko.tabs.PrivateTabsPanel
                 android:id="@+id/private_tabs_panel"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:visibility="gone"/>
 
-        <org.mozilla.gecko.tabs.RemoteTabsPanel
-                android:id="@+id/remote_tabs"
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"
-                android:visibility="gone"/>
+        <ViewStub android:id="@+id/remote_tabs_panel_stub"
+                  android:layout="@layout/remote_tabs_panel_view"
+                  android:layout_width="match_parent"
+                  android:layout_height="match_parent"/>
 
     </view>
 
 </merge>
--- a/mobile/android/base/tabs/TabsPanel.java
+++ b/mobile/android/base/tabs/TabsPanel.java
@@ -27,16 +27,17 @@ import android.content.res.Resources;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewStub;
 import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.RelativeLayout;
 
 public class TabsPanel extends LinearLayout
                        implements GeckoPopupMenu.OnMenuItemClickListener,
@@ -108,43 +109,56 @@ public class TabsPanel extends LinearLay
         LayoutInflater.from(context).inflate(R.layout.tabs_panel, this);
         initialize();
 
         mAppStateListener = new AppStateListener() {
             @Override
             public void onResume() {
                 if (mPanel == mPanelRemote) {
                     // Refresh the remote panel.
-                    mPanelRemote.show();
+                    getRemotePanelView().show();
                 }
             }
 
             @Override
             public void onOrientationChanged() {
                 // Remote panel is already refreshed by chrome refresh.
             }
 
             @Override
             public void onPause() {}
         };
     }
 
+    /**
+     * Initializes views in tabs_panel layout
+     *
+     * @throws IllegalStateException
+     *             mCurrentPanel must have a non-null value
+     */
     private void initialize() {
+        if (mCurrentPanel == null) {
+            throw new IllegalStateException(
+                    "mCurrentPanel cannot be null in order for RemotePanelView to be initialized");
+        }
+
+        if (mCurrentPanel == Panel.REMOTE_TABS) {
+            // Initializes mPanelRemote
+            getRemotePanelView();
+        }
+
         mHeader = (RelativeLayout) findViewById(R.id.tabs_panel_header);
         mTabsContainer = (TabsListContainer) findViewById(R.id.tabs_container);
 
         mPanelNormal = (PanelView) findViewById(R.id.normal_tabs);
         mPanelNormal.setTabsPanel(this);
 
         mPanelPrivate = (PanelView) findViewById(R.id.private_tabs_panel);
         mPanelPrivate.setTabsPanel(this);
 
-        mPanelRemote = (PanelView) findViewById(R.id.remote_tabs);
-        mPanelRemote.setTabsPanel(this);
-
         mFooter = (RelativeLayout) findViewById(R.id.tabs_panel_footer);
 
         mAddTab = (ImageButton) findViewById(R.id.add_tab);
         mAddTab.setOnClickListener(new Button.OnClickListener() {
             @Override
             public void onClick(View v) {
                 TabsPanel.this.addTab();
             }
@@ -411,17 +425,17 @@ public class TabsPanel extends LinearLay
         switch (panelToShow) {
             case NORMAL_TABS:
                 mPanel = mPanelNormal;
                 break;
             case PRIVATE_TABS:
                 mPanel = mPanelPrivate;
                 break;
             case REMOTE_TABS:
-                mPanel = mPanelRemote;
+                mPanel = getRemotePanelView();
                 break;
 
             default:
                 throw new IllegalArgumentException("Unknown panel type " + panelToShow);
         }
         mPanel.show();
 
         if (mCurrentPanel == Panel.REMOTE_TABS) {
@@ -467,16 +481,19 @@ public class TabsPanel extends LinearLay
             mPopupMenu.dismiss();
             dispatchLayoutChange(0, 0);
         }
     }
 
     public void refresh() {
         removeAllViews();
 
+        // The View that mPanelRemote points to is invalidated because the layout is invalidated.
+        // mPanelRemote must be null in order to properly initialize RemotePanelView.
+        mPanelRemote = null;
         LayoutInflater.from(mContext).inflate(R.layout.tabs_panel, this);
         initialize();
 
         if (mVisible)
             show(mCurrentPanel);
     }
 
     public void autoHidePanel() {
@@ -565,9 +582,23 @@ public class TabsPanel extends LinearLay
      */
     public Drawable getIconDrawable(Panel panel) {
         return mTabWidget.getIconDrawable(panel.ordinal());
     }
 
     public void setIconDrawable(Panel panel, int resource) {
         mTabWidget.setIconDrawable(panel.ordinal(), resource);
     }
+
+    /**
+     * Initializes mPanelRemote if necessary and provides getter because you
+     * should probably not access mPanelRemote directly
+     *
+     * @return PanelView
+     */
+    private PanelView getRemotePanelView() {
+        if (mPanelRemote == null) {
+            mPanelRemote = (PanelView) ((ViewStub) findViewById(R.id.remote_tabs_panel_stub)).inflate();
+            mPanelRemote.setTabsPanel(TabsPanel.this);
+        }
+        return mPanelRemote;
+    }
 }
--- a/mobile/android/base/tests/testSearchSuggestions.java
+++ b/mobile/android/base/tests/testSearchSuggestions.java
@@ -1,17 +1,17 @@
 package org.mozilla.gecko.tests;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 
 import org.mozilla.gecko.Actions;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.SuggestClient;
 import org.mozilla.gecko.home.BrowserSearch;
-import org.mozilla.gecko.home.SuggestClient;
 
 import android.app.Activity;
 import android.support.v4.app.Fragment;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
 /**
deleted file mode 100644
--- a/mobile/android/search/java/org/mozilla/search/autocomplete/SuggestClient.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/* 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/. */
-
-package org.mozilla.search.autocomplete;
-
-import org.json.JSONArray;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-
-/**
- * Use network-based search suggestions.
- */
-public class SuggestClient {
-    private static final String LOGTAG = "GeckoSuggestClient";
-    private static final String USER_AGENT = "";
-
-    private final Context mContext;
-    private final int mTimeout;
-
-    // should contain the string "__searchTerms__", which is replaced with the query
-    private final String mSuggestTemplate;
-
-    // the maximum number of suggestions to return
-    private final int mMaxResults;
-
-    // used by robocop for testing
-    private boolean mCheckNetwork;
-
-    // used to make suggestions appear instantly after opt-in
-    private String mPrevQuery;
-    private ArrayList<String> mPrevResults;
-
-    public SuggestClient(Context context, String suggestTemplate, int timeout, int maxResults) {
-        mContext = context;
-        mMaxResults = maxResults;
-        mSuggestTemplate = suggestTemplate;
-        mTimeout = timeout;
-        mCheckNetwork = true;
-    }
-
-    /**
-     * Queries for a given search term and returns an ArrayList of suggestions.
-     */
-    public ArrayList<String> query(String query) {
-        if (query.equals(mPrevQuery))
-            return mPrevResults;
-
-        ArrayList<String> suggestions = new ArrayList<String>();
-        if (TextUtils.isEmpty(mSuggestTemplate) || TextUtils.isEmpty(query)) {
-            return suggestions;
-        }
-
-        if (!isNetworkConnected() && mCheckNetwork) {
-            Log.i(LOGTAG, "Not connected to network");
-            return suggestions;
-        }
-
-        try {
-            String encoded = URLEncoder.encode(query, "UTF-8");
-            String suggestUri = mSuggestTemplate.replace("__searchTerms__", encoded);
-
-            URL url = new URL(suggestUri);
-            String json = null;
-            HttpURLConnection urlConnection = null;
-            InputStream in = null;
-            try {
-                urlConnection = (HttpURLConnection) url.openConnection();
-                urlConnection.setConnectTimeout(mTimeout);
-                urlConnection.setRequestProperty("User-Agent", USER_AGENT);
-                in = new BufferedInputStream(urlConnection.getInputStream());
-                json = convertStreamToString(in);
-            } finally {
-                if (urlConnection != null)
-                    urlConnection.disconnect();
-                if (in != null) {
-                    try {
-                        in.close();
-                    } catch (IOException e) {
-                        Log.e(LOGTAG, "error", e);
-                    }
-                }
-            }
-
-            if (json != null) {
-                /*
-                 * Sample result:
-                 * ["foo",["food network","foothill college","foot locker",...]]
-                 */
-                JSONArray results = new JSONArray(json);
-                JSONArray jsonSuggestions = results.getJSONArray(1);
-
-                int added = 0;
-                for (int i = 0; (i < jsonSuggestions.length()) && (added < mMaxResults); i++) {
-                    String suggestion = jsonSuggestions.getString(i);
-                    if (!suggestion.equalsIgnoreCase(query)) {
-                        suggestions.add(suggestion);
-                        added++;
-                    }
-                }
-            } else {
-                Log.e(LOGTAG, "Suggestion query failed");
-            }
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Error", e);
-        }
-
-        mPrevQuery = query;
-        mPrevResults = suggestions;
-        return suggestions;
-    }
-
-    private boolean isNetworkConnected() {
-        NetworkInfo networkInfo = getActiveNetworkInfo();
-        return networkInfo != null && networkInfo.isConnected();
-    }
-
-    private NetworkInfo getActiveNetworkInfo() {
-        ConnectivityManager connectivity = (ConnectivityManager) mContext
-                .getSystemService(Context.CONNECTIVITY_SERVICE);
-        if (connectivity == null)
-            return null;
-        return connectivity.getActiveNetworkInfo();
-    }
-
-    private String convertStreamToString(java.io.InputStream is) {
-        try {
-            return new java.util.Scanner(is).useDelimiter("\\A").next();
-        } catch (java.util.NoSuchElementException e) {
-            return "";
-        }
-    }
-}
--- a/mobile/android/search/java/org/mozilla/search/autocomplete/SuggestionsFragment.java
+++ b/mobile/android/search/java/org/mozilla/search/autocomplete/SuggestionsFragment.java
@@ -16,16 +16,17 @@ import android.text.SpannableString;
 import android.text.style.ForegroundColorSpan;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.ListView;
 
+import org.mozilla.gecko.SuggestClient;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.search.AcceptsSearchQuery;
 import org.mozilla.search.AcceptsSearchQuery.SuggestionAnimation;
 import org.mozilla.search.Constants;
 import org.mozilla.search.R;
 import org.mozilla.search.providers.SearchEngine;
 import org.mozilla.search.providers.SearchEngineManager;
--- a/mobile/android/search/search_activity_sources.mozbuild
+++ b/mobile/android/search/search_activity_sources.mozbuild
@@ -3,17 +3,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 search_activity_sources = [
     'java/org/mozilla/search/AcceptsSearchQuery.java',
     'java/org/mozilla/search/autocomplete/AutoCompleteAdapter.java',
     'java/org/mozilla/search/autocomplete/ClearableEditText.java',
-    'java/org/mozilla/search/autocomplete/SuggestClient.java',
     'java/org/mozilla/search/autocomplete/SuggestionsFragment.java',
     'java/org/mozilla/search/Constants.java',
     'java/org/mozilla/search/MainActivity.java',
     'java/org/mozilla/search/PostSearchFragment.java',
     'java/org/mozilla/search/PreSearchFragment.java',
     'java/org/mozilla/search/providers/BingSearchEngine.java',
     'java/org/mozilla/search/providers/GoogleSearchEngine.java',
     'java/org/mozilla/search/providers/SearchEngine.java',
--- a/toolkit/devtools/webconsole/utils.js
+++ b/toolkit/devtools/webconsole/utils.js
@@ -565,31 +565,29 @@ let WebConsoleUtils = {
   },
   /**
    * The inputNode "paste" event handler generator. Helps prevent self-xss attacks
    *
    * @param nsIDOMElement inputField
    * @param nsIDOMElement notificationBox
    * @returns A function to be added as a handler to 'paste' and 'drop' events on the input field
    */
-  pasteHandlerGen: function WCU_pasteHandlerGen(inputField, notificationBox){
+  pasteHandlerGen: function WCU_pasteHandlerGen(inputField, notificationBox, msg, okstring) {
     let handler = function WCU_pasteHandler(aEvent) {
       if (WebConsoleUtils.usageCount >= CONSOLE_ENTRY_THRESHOLD) {
         inputField.removeEventListener("paste", handler);
         inputField.removeEventListener("drop", handler);
         return true;
       }
       if (notificationBox.getNotificationWithValue("selfxss-notification")) {
         aEvent.preventDefault();
         aEvent.stopPropagation();
         return false;
       }
-      let l10n = new WebConsoleUtils.l10n("chrome://browser/locale/devtools/webconsole.properties");
-      let okstring = l10n.getStr("selfxss.okstring");
-      let msg = l10n.getFormatStr("selfxss.msg", [okstring]);
+
 
       let notification = notificationBox.appendNotification(msg,
         "selfxss-notification", null, notificationBox.PRIORITY_WARNING_HIGH, null,
         function(eventType) {
           // Cleanup function if notification is dismissed
           if (eventType == "removed") {
             inputField.removeEventListener("keyup", pasteKeyUpHandler);
           }
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -3101,31 +3101,34 @@ var gDetailView = {
         warning.textContent = gStrings.ext.GetStringFromName("details.notification.openH264Pending");
       } else {
         this.node.removeAttribute("notification");
       }
     }
 
     let menulist = document.getElementById("detail-state-menulist");
     let addonType = AddonManager.addonTypes[this._addon.type];
-    if (addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE &&
-        (hasPermission(this._addon, "ask_to_activate") ||
-         hasPermission(this._addon, "enable") ||
-         hasPermission(this._addon, "disable"))) {
+    if (addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) {
       let askItem = document.getElementById("detail-ask-to-activate-menuitem");
       let alwaysItem = document.getElementById("detail-always-activate-menuitem");
       let neverItem = document.getElementById("detail-never-activate-menuitem");
+      let hasActivatePermission =
+        ["ask_to_activate", "enable", "disable"].some(perm => hasPermission(this._addon, perm));
+
       if (this._addon.userDisabled === true) {
         menulist.selectedItem = neverItem;
       } else if (this._addon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE) {
         menulist.selectedItem = askItem;
       } else {
         menulist.selectedItem = alwaysItem;
       }
+
+      menulist.disabled = !hasActivatePermission;
       menulist.hidden = false;
+      menulist.classList.add('no-auto-hide');
     } else {
       menulist.hidden = true;
     }
 
     this.node.setAttribute("active", this._addon.isActive);
   },
 
   clearLoading: function gDetailView_clearLoading() {
--- a/toolkit/mozapps/extensions/content/extensions.xml
+++ b/toolkit/mozapps/extensions/content/extensions.xml
@@ -1301,36 +1301,36 @@
               this.removeAttribute("notification");
             }
           }
 
           this._preferencesBtn.hidden = (!this.mAddon.optionsURL) ||
                                         this.mAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO;
 
           let addonType = AddonManager.addonTypes[this.mAddon.type];
-          if (addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE &&
-              (this.hasPermission("ask_to_activate") ||
-               this.hasPermission("enable") ||
-               this.hasPermission("disable"))) {
+          if (addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) {
             this._enableBtn.disabled = true;
             this._disableBtn.disabled = true;
             this._askToActivateMenuitem.disabled = !this.hasPermission("ask_to_activate");
             this._alwaysActivateMenuitem.disabled = !this.hasPermission("enable");
             this._neverActivateMenuitem.disabled = !this.hasPermission("disable");
             if (this.mAddon.userDisabled === true) {
               this._stateMenulist.selectedItem = this._neverActivateMenuitem;
             } else if (this.mAddon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE) {
               this._stateMenulist.selectedItem = this._askToActivateMenuitem;
             } else {
               this._stateMenulist.selectedItem = this._alwaysActivateMenuitem;
             }
-            this._stateMenulist.selectedItem.disabled = false;
-            this._stateMenulist.disabled = false;
+            let hasActivatePermission =
+              ["ask_to_activate", "enable", "disable"].some(perm => this.hasPermission(perm));
+            this._stateMenulist.disabled = !hasActivatePermission;
+            this._stateMenulist.hidden = false;
+            this._stateMenulist.classList.add('no-auto-hide');
           } else {
-            this._stateMenulist.disabled = true;
+            this._stateMenulist.hidden = true;
             if (this.hasPermission("enable")) {
               this._enableBtn.hidden = false;
               let tooltip = gViewController.commands["cmd_enableItem"]
                                            .getTooltip(this.mAddon);
               this._enableBtn.setAttribute("tooltiptext", tooltip);
             } else {
               this._enableBtn.hidden = true;
             }
--- a/toolkit/mozapps/extensions/internal/PluginProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/PluginProvider.jsm
@@ -456,16 +456,19 @@ function PluginWrapper(aId, aName, aDesc
   });
 
   this.__defineGetter__("operationsRequiringRestart", function() {
     return AddonManager.OP_NEEDS_RESTART_NONE;
   });
 
   this.__defineGetter__("permissions", function() {
     let permissions = 0;
+    if (aTags[0].isEnabledStateLocked) {
+      return permissions;
+    }
     if (!this.appDisabled) {
 
       if (this.userDisabled !== true)
         permissions |= AddonManager.PERM_CAN_DISABLE;
 
       let blocklistState = this.blocklistState;
       let isCTPBlocklisted =
         (blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE ||
--- a/toolkit/mozapps/extensions/test/browser/browser-common.ini
+++ b/toolkit/mozapps/extensions/test/browser/browser-common.ini
@@ -39,16 +39,17 @@ skip-if = e10s # Bug ?????? - test times
 [browser_dragdrop.js]
 skip-if = buildapp == 'mulet'
 [browser_experiments.js]
 [browser_list.js]
 [browser_metadataTimeout.js]
 [browser_searching.js]
 [browser_sorting.js]
 [browser_sorting_plugins.js]
+[browser_plugin_enabled_state_locked.js]
 skip-if = e10s # Bug ?????? - leaked until shutdown [nsGlobalWindow #1760 about:blank]
 [browser_uninstalling.js]
 skip-if = e10s # Bug ?????? - leaked until shutdown [nsGlobalWindow #1760 about:blank]
 [browser_install.js]
 [browser_recentupdates.js]
 [browser_manualupdates.js]
 [browser_globalwarnings.js]
 [browser_globalinformations.js]
--- a/toolkit/mozapps/extensions/test/browser/browser_CTP_plugins.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_CTP_plugins.js
@@ -195,26 +195,26 @@ function part11() {
   });
 }
 
 function part12(aWindow) {
   gManagerWindow = aWindow;
   let pluginEl = get_addon_element(gManagerWindow, gTestPluginId);
   pluginEl.parentNode.ensureElementIsVisible(pluginEl);
   let menu = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "state-menulist");
-  is_element_hidden(menu, "part12: state menu should be hidden");
+  is(menu.disabled, true, "part12: state menu should be disabled");
 
   let details = gManagerWindow.document.getAnonymousElementByAttribute(pluginEl, "anonid", "details-btn");
   EventUtils.synthesizeMouseAtCenter(details, {}, gManagerWindow);
   wait_for_view_load(gManagerWindow, part13);
 }
 
 function part13() {
   let menu = gManagerWindow.document.getElementById("detail-state-menulist");
-  is_element_hidden(menu, "part13: detail state menu should be hidden");
+  is(menu.disabled, true, "part13: detail state menu should be disabled");
 
   setAndUpdateBlocklist(gHttpTestRoot + "blockNoPlugins.xml", function() {
     run_next_test();
   });
 }
 
 function end_test() {
   Services.prefs.clearUserPref("plugins.click_to_play");
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/browser_plugin_enabled_state_locked.js
@@ -0,0 +1,121 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that state menu is displayed correctly (enabled or disabled) in the add-on manager
+// when the preference is unlocked / locked
+const {classes: Cc, interfaces: Ci} = Components;
+const gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
+const gIsOSX = ("nsILocalFileMac" in Ci);
+const gIsLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc) ||
+  ("@mozilla.org/gio-service;1" in Cc);
+
+let gManagerWindow;
+let gCategoryUtilities;
+let gPluginElement;
+
+function getTestPluginPref() {
+  let prefix = "plugin.state.";
+  if (gIsWindows)
+    return prefix + "nptest";
+  else if (gIsLinux)
+    return prefix + "libnptest";
+  else
+    return prefix + "test";
+}
+
+registerCleanupFunction(() => {
+  Services.prefs.unlockPref(getTestPluginPref());
+  Services.prefs.clearUserPref(getTestPluginPref());
+});
+
+function getPlugins() {
+  let deferred = Promise.defer();
+  AddonManager.getAddonsByTypes(["plugin"], plugins => deferred.resolve(plugins));
+  return deferred.promise;
+}
+
+function getTestPlugin(aPlugins) {
+  let testPluginId;
+
+  for (let plugin of aPlugins) {
+    if (plugin.name == "Test Plug-in") {
+      testPluginId = plugin.id;
+      break;
+    }
+  }
+
+  Assert.ok(testPluginId, "Test Plug-in should exist");
+
+  let pluginElement = get_addon_element(gManagerWindow, testPluginId);
+  pluginElement.parentNode.ensureElementIsVisible(pluginElement);
+
+  return pluginElement;
+}
+
+function checkStateMenu(locked) {
+  Assert.equal(Services.prefs.prefIsLocked(getTestPluginPref()), locked,
+    "Preference lock state should be correct.");
+  let menuList = gManagerWindow.document.getAnonymousElementByAttribute(gPluginElement, "anonid", "state-menulist");
+
+  is_element_visible(menuList, "State menu should be visible.");
+  Assert.equal(menuList.disabled, locked,
+    "State menu should" + (locked === true ? "" : " not") + " be disabled.");
+}
+
+function checkStateMenuDetail(locked) {
+  Assert.equal(Services.prefs.prefIsLocked(getTestPluginPref()), locked,
+    "Preference should be " + (locked === true ? "" : "un") + "locked.");
+
+  // open details menu
+  let details = gManagerWindow.document.getAnonymousElementByAttribute(gPluginElement, "anonid", "details-btn");
+  is_element_visible(details, "Details link should be visible.");
+  EventUtils.synthesizeMouseAtCenter(details, {}, gManagerWindow);
+
+  let deferred = Promise.defer();
+  wait_for_view_load(gManagerWindow, function() {
+    let menuList = gManagerWindow.document.getElementById("detail-state-menulist");
+    is_element_visible(menuList, "Details state menu should be visible.");
+    Assert.equal(menuList.disabled, locked,
+      "Details state menu enabled state should be correct.");
+    deferred.resolve();
+  });
+  return deferred.promise;
+}
+
+add_task(function* initializeState() {
+  Services.prefs.setIntPref(getTestPluginPref(), Ci.nsIPluginTag.STATE_ENABLED);
+  Services.prefs.unlockPref(getTestPluginPref());
+  gManagerWindow = yield open_manager();
+  gCategoryUtilities = new CategoryUtilities(gManagerWindow);
+  yield gCategoryUtilities.openType("plugin");
+
+  let plugins = yield getPlugins();
+  gPluginElement = getTestPlugin(plugins);
+});
+
+// Tests that plugin state menu is enabled if the preference is unlocked
+add_task(function* taskCheckStateMenuIsEnabled() {
+  checkStateMenu(false);
+  yield checkStateMenuDetail(false);
+});
+
+// Lock the preference and then reload the plugin category
+add_task(function* reinitializeState() {
+  // lock the preference
+  Services.prefs.lockPref(getTestPluginPref());
+  yield gCategoryUtilities.openType("plugin");
+  // Retrieve the test plugin element
+  let plugins = yield getPlugins();
+  gPluginElement = getTestPlugin(plugins);
+});
+
+// Tests that plugin state menu is disabled if the preference is locked
+add_task(function* taskCheckStateMenuIsDisabled() {
+  checkStateMenu(true);
+  yield checkStateMenuDetail(true);
+});
+
+add_task(function* testCleanup() {
+  yield close_manager(gManagerWindow);
+});
rename from browser/themes/linux/in-content/common.css
rename to toolkit/themes/linux/global/in-content/common.css
--- a/browser/themes/linux/in-content/common.css
+++ b/toolkit/themes/linux/global/in-content/common.css
@@ -1,13 +1,13 @@
 /* - 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 ../../shared/in-content/common.inc.css
+%include ../../../shared/in-content/common.inc.css
 
 xul|tab[selected] {
   /* Override styles for tab[selected] from
      toolkit/themes/linux/global/tabbox.css */
   margin-bottom: 0;
   border-bottom-left-radius: 0;
   border-bottom-right-radius: 0;
 }
--- a/toolkit/themes/linux/global/jar.mn
+++ b/toolkit/themes/linux/global/jar.mn
@@ -49,9 +49,20 @@ toolkit.jar:
 +  skin/classic/global/icons/panelarrow-horizontal.svg         (icons/panelarrow-horizontal.svg)
 +  skin/classic/global/icons/panelarrow-vertical.svg           (icons/panelarrow-vertical.svg)
 +  skin/classic/global/icons/resizer.png                       (icons/resizer.png)
 +  skin/classic/global/icons/sslWarning.png                    (icons/sslWarning.png)
 +  skin/classic/global/icons/wrap.png                          (icons/wrap.png)
 +  skin/classic/global/icons/webapps-16.png                    (icons/webapps-16.png)
 +  skin/classic/global/icons/webapps-64.png                    (icons/webapps-64.png)
    skin/classic/global/menu/shared-menu-check.png              (../../shared/menu-check.png)
+*  skin/classic/global/in-content/common.css                   (in-content/common.css)
+   skin/classic/global/in-content/check.png                    (../../shared/in-content/check.png)
+   skin/classic/global/in-content/check@2x.png                 (../../shared/in-content/check@2x.png)
+   skin/classic/global/in-content/dropdown.png                 (../../shared/in-content/dropdown.png)
+   skin/classic/global/in-content/dropdown@2x.png              (../../shared/in-content/dropdown@2x.png)
+   skin/classic/global/in-content/dropdown-disabled.png        (../../shared/in-content/dropdown-disabled.png)
+   skin/classic/global/in-content/dropdown-disabled@2x.png     (../../shared/in-content/dropdown-disabled@2x.png)
+   skin/classic/global/in-content/help-glyph.png               (../../shared/in-content/help-glyph.png)
+   skin/classic/global/in-content/help-glyph@2x.png            (../../shared/in-content/help-glyph@2x.png)
+   skin/classic/global/in-content/sorter.png                   (../../shared/in-content/sorter.png)
+   skin/classic/global/in-content/sorter@2x.png                (../../shared/in-content/sorter@2x.png)
 +  skin/classic/global/toolbar/spring.png                      (toolbar/spring.png)
--- a/toolkit/themes/linux/mozapps/extensions/extensions.css
+++ b/toolkit/themes/linux/mozapps/extensions/extensions.css
@@ -879,16 +879,20 @@ setting[type="radio"] > radiogroup {
 
 
 /*** buttons ***/
 
 .addon-control[disabled="true"] {
   display: none;
 }
 
+.addon-control.no-auto-hide {
+  display: block;
+}
+
 .addon-control.enable {
   list-style-image: url("moz-icon://stock/gtk-yes?size=button");
 }
 
 .addon-control.disable {
   list-style-image: url("moz-icon://stock/gtk-no?size=button");
 }
 
rename from browser/themes/osx/in-content/common.css
rename to toolkit/themes/osx/global/in-content/common.css
--- a/browser/themes/osx/in-content/common.css
+++ b/toolkit/themes/osx/global/in-content/common.css
@@ -1,13 +1,13 @@
 /* - 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 ../../shared/in-content/common.inc.css
+%include ../../../shared/in-content/common.inc.css
 
 xul|tabs {
   padding-right: 0;
   padding-left: 0;
 }
 
 xul|tab[selected] {
   text-shadow: none;
--- a/toolkit/themes/osx/global/jar.mn
+++ b/toolkit/themes/osx/global/jar.mn
@@ -179,16 +179,27 @@ toolkit.jar:
   skin/classic/global/media/volume-full.png                          (media/volume-full.png)
   skin/classic/global/media/volume-full@2x.png                       (media/volume-full@2x.png)
   skin/classic/global/media/clicktoplay-bgtexture.png                (media/clicktoplay-bgtexture.png)
   skin/classic/global/media/videoClickToPlayButton.svg               (media/videoClickToPlayButton.svg)
   skin/classic/global/menu/menu-arrow.png                            (menu/menu-arrow.png)
   skin/classic/global/menu/menu-arrow@2x.png                         (menu/menu-arrow@2x.png)
   skin/classic/global/menu/shared-menu-check.png                     (../../shared/menu-check.png)
   skin/classic/global/menu/shared-menu-check@2x.png                  (../../shared/menu-check@2x.png)
+* skin/classic/global/in-content/common.css                          (in-content/common.css)
+  skin/classic/global/in-content/check.png                           (../../shared/in-content/check.png)
+  skin/classic/global/in-content/check@2x.png                        (../../shared/in-content/check@2x.png)
+  skin/classic/global/in-content/dropdown.png                        (../../shared/in-content/dropdown.png)
+  skin/classic/global/in-content/dropdown@2x.png                     (../../shared/in-content/dropdown@2x.png)
+  skin/classic/global/in-content/dropdown-disabled.png               (../../shared/in-content/dropdown-disabled.png)
+  skin/classic/global/in-content/dropdown-disabled@2x.png            (../../shared/in-content/dropdown-disabled@2x.png)
+  skin/classic/global/in-content/help-glyph.png                      (../../shared/in-content/help-glyph.png)
+  skin/classic/global/in-content/help-glyph@2x.png                   (../../shared/in-content/help-glyph@2x.png)
+  skin/classic/global/in-content/sorter.png                          (../../shared/in-content/sorter.png)
+  skin/classic/global/in-content/sorter@2x.png                       (../../shared/in-content/sorter@2x.png)
   skin/classic/global/scale/scale-tray-horiz.gif                     (scale/scale-tray-horiz.gif)
   skin/classic/global/scale/scale-tray-vert.gif                      (scale/scale-tray-vert.gif)
   skin/classic/global/splitter/dimple.png                            (splitter/dimple.png)
   skin/classic/global/splitter/grip-bottom.gif                       (splitter/grip-bottom.gif)
   skin/classic/global/splitter/grip-top.gif                          (splitter/grip-top.gif)
   skin/classic/global/splitter/grip-left.gif                         (splitter/grip-left.gif)
   skin/classic/global/splitter/grip-right.gif                        (splitter/grip-right.gif)
   skin/classic/global/toolbar/spring.png                             (toolbar/spring.png)
--- a/toolkit/themes/osx/mozapps/extensions/extensions.css
+++ b/toolkit/themes/osx/mozapps/extensions/extensions.css
@@ -1103,16 +1103,20 @@ setting[type="radio"] > radiogroup {
 
 
 /*** buttons ***/
 
 .addon-control[disabled="true"] {
   display: none;
 }
 
+.addon-control.no-auto-hide {
+  display: block;
+}
+
 button.button-link {
   -moz-appearance: none;
   background: transparent;
   border: none;
   box-shadow: none;
   text-decoration: underline;
   color: #0066CC;
   cursor: pointer;
rename from browser/themes/shared/in-content/check.png
rename to toolkit/themes/shared/in-content/check.png
rename from browser/themes/shared/in-content/check@2x.png
rename to toolkit/themes/shared/in-content/check@2x.png
rename from browser/themes/shared/in-content/common.inc.css
rename to toolkit/themes/shared/in-content/common.inc.css
--- a/browser/themes/shared/in-content/common.inc.css
+++ b/toolkit/themes/shared/in-content/common.inc.css
@@ -189,17 +189,17 @@ xul|button[type="menu"] > xul|*.button-b
   -moz-appearance: none;
   margin: 1px 0;
   -moz-margin-start: 10px;
   padding: 0;
   width: 10px;
   height: 16px;
   border: none;
   background-color: transparent;
-  list-style-image: url("chrome://browser/skin/in-content/dropdown.png");
+  list-style-image: url("chrome://global/skin/in-content/dropdown.png");
 }
 
 xul|*.help-button {
   min-width: 30px;
   border-radius: 2px;
   border: 1px solid #c1c1c1;
   background-color: #ffcb00;
   background-image: none;
@@ -222,24 +222,24 @@ xul|*.help-button > xul|*.button-box {
   padding-bottom: 0;
   padding-right: 0 !important;
   padding-left: 0 !important;
 }
 
 xul|*.help-button > xul|*.button-box > xul|*.button-icon {
   width: 26px;
   height: 26px;
-  background-image: url("chrome://browser/skin/in-content/help-glyph.png");
+  background-image: url("chrome://global/skin/in-content/help-glyph.png");
   background-position: center;
 }
 
 @media (min-resolution: 2dppx) {
   xul|*.help-button > xul|*.button-box > xul|*.button-icon {
     background-size: 26px 26px;
-    background-image: url("chrome://browser/skin/in-content/help-glyph@2x.png");
+    background-image: url("chrome://global/skin/in-content/help-glyph@2x.png");
   }
 }
 
 xul|*.help-button > xul|*.button-box > xul|*.button-text {
   display: none;
 }
 
 xul|*.spinbuttons-button {
@@ -278,31 +278,31 @@ xul|*.spinbuttons-down[disabled="true"] 
 }
 
 xul|menulist:not([editable="true"]) > xul|*.menulist-dropmarker {
   -moz-appearance: none;
   -moz-margin-end: 10px;
   padding: 0;
   border: none;
   background-color: transparent;
-  list-style-image: url("chrome://browser/skin/in-content/dropdown.png");
+  list-style-image: url("chrome://global/skin/in-content/dropdown.png");
 }
 
 xul|menulist[disabled="true"]:not([editable="true"]) > xul|*.menulist-dropmarker {
-  list-style-image: url("chrome://browser/skin/in-content/dropdown-disabled.png")
+  list-style-image: url("chrome://global/skin/in-content/dropdown-disabled.png")
 }
 
 @media (min-resolution: 2dppx) {
   xul|menulist:not([editable="true"]) > xul|*.menulist-dropmarker,
   xul|button[type="menu"] > xul|*.button-box > xul|*.button-menu-dropmarker {
-    list-style-image: url("chrome://browser/skin/in-content/dropdown@2x.png");
+    list-style-image: url("chrome://global/skin/in-content/dropdown@2x.png");
   }
 
   xul|menulist[disabled="true"]:not([editable="true"]) > xul|*.menulist-dropmarker {
-    list-style-image: url("chrome://browser/skin/in-content/dropdown-disabled@2x.png")
+    list-style-image: url("chrome://global/skin/in-content/dropdown-disabled@2x.png")
   }
 
   xul|menulist:not([editable="true"]) > xul|*.menulist-dropmarker > xul|*.dropmarker-icon,
   xul|button[type="menu"] > xul|*.button-box > xul|*.button-menu-dropmarker > xul|*.dropmarker-icon {
     width: 10px;
     height: 16px;
   }
 }
@@ -426,34 +426,34 @@ xul|*.checkbox-check {
   box-shadow: 0 1px 1px 0 #fff, inset 0 2px 0 0 rgba(0,0,0,0.03);
 }
 
 xul|checkbox:not([disabled="true"]):hover > xul|*.checkbox-check {
   border-color: #0095dd;
 }
 
 xul|*.checkbox-check[checked] {
-  background-image: url("chrome://browser/skin/in-content/check.png"),
+  background-image: url("chrome://global/skin/in-content/check.png"),
                     /* !important needed to override toolkit !important rule */
                     linear-gradient(#fff, rgba(255,255,255,0.8)) !important;
 }
 
 xul|checkbox[disabled="true"] > xul|*.checkbox-check {
   opacity: 0.5;
 }
 
 xul|*.checkbox-label-box {
   -moz-margin-start: -1px; /* negative margin for the transparent border */
   -moz-padding-start: 0;
 }
 
 @media (min-resolution: 2dppx) {
   xul|*.checkbox-check[checked] {
     background-size: 12px 12px, auto;
-    background-image: url("chrome://browser/skin/in-content/check@2x.png"),
+    background-image: url("chrome://global/skin/in-content/check@2x.png"),
                       linear-gradient(#fff, rgba(255,255,255,0.8)) !important;
   }
 }
 
 xul|*.radio-check {
   -moz-appearance: none;
   width: 23px;
   height: 23px;
rename from browser/themes/shared/in-content/dropdown-disabled.png
rename to toolkit/themes/shared/in-content/dropdown-disabled.png
rename from browser/themes/shared/in-content/dropdown-disabled@2x.png
rename to toolkit/themes/shared/in-content/dropdown-disabled@2x.png
rename from browser/themes/shared/in-content/dropdown.png
rename to toolkit/themes/shared/in-content/dropdown.png
rename from browser/themes/shared/in-content/dropdown@2x.png
rename to toolkit/themes/shared/in-content/dropdown@2x.png
rename from browser/themes/shared/in-content/help-glyph.png
rename to toolkit/themes/shared/in-content/help-glyph.png
rename from browser/themes/shared/in-content/help-glyph@2x.png
rename to toolkit/themes/shared/in-content/help-glyph@2x.png
rename from browser/themes/shared/in-content/sorter.png
rename to toolkit/themes/shared/in-content/sorter.png
rename from browser/themes/shared/in-content/sorter@2x.png
rename to toolkit/themes/shared/in-content/sorter@2x.png
rename from browser/themes/windows/in-content/common.css
rename to toolkit/themes/windows/global/in-content/common.css
--- a/browser/themes/windows/in-content/common.css
+++ b/toolkit/themes/windows/global/in-content/common.css
@@ -1,13 +1,13 @@
 /* - 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 ../../shared/in-content/common.inc.css
+%include ../../../shared/in-content/common.inc.css
 
 xul|caption {
   background-color: transparent;
 }
 
 xul|button,
 xul|colorpicker[type="button"],
 xul|menulist {
--- a/toolkit/themes/windows/global/jar.mn
+++ b/toolkit/themes/windows/global/jar.mn
@@ -164,16 +164,27 @@ toolkit.jar:
         skin/classic/global/media/throbber.png                   (media/throbber.png)
         skin/classic/global/media/stalled.png                    (media/stalled.png)
         skin/classic/global/media/volume-empty.png               (media/volume-empty.png)
         skin/classic/global/media/volume-full.png                (media/volume-full.png)
         skin/classic/global/media/error.png                      (media/error.png)
         skin/classic/global/media/clicktoplay-bgtexture.png      (media/clicktoplay-bgtexture.png)
         skin/classic/global/media/videoClickToPlayButton.svg     (media/videoClickToPlayButton.svg)
         skin/classic/global/menu/shared-menu-check.png           (../../shared/menu-check.png)
+*       skin/classic/global/in-content/common.css                (in-content/common.css)
+        skin/classic/global/in-content/check.png                 (../../shared/in-content/check.png)
+        skin/classic/global/in-content/check@2x.png              (../../shared/in-content/check@2x.png)
+        skin/classic/global/in-content/dropdown.png              (../../shared/in-content/dropdown.png)
+        skin/classic/global/in-content/dropdown@2x.png           (../../shared/in-content/dropdown@2x.png)
+        skin/classic/global/in-content/dropdown-disabled.png     (../../shared/in-content/dropdown-disabled.png)
+        skin/classic/global/in-content/dropdown-disabled@2x.png  (../../shared/in-content/dropdown-disabled@2x.png)
+        skin/classic/global/in-content/help-glyph.png            (../../shared/in-content/help-glyph.png)
+        skin/classic/global/in-content/help-glyph@2x.png         (../../shared/in-content/help-glyph@2x.png)
+        skin/classic/global/in-content/sorter.png                (../../shared/in-content/sorter.png)
+        skin/classic/global/in-content/sorter@2x.png             (../../shared/in-content/sorter@2x.png)
         skin/classic/global/printpreview/arrow-left.png          (printpreview/arrow-left.png)
         skin/classic/global/printpreview/arrow-left-end.png      (printpreview/arrow-left-end.png)
         skin/classic/global/printpreview/arrow-right.png         (printpreview/arrow-right.png)
         skin/classic/global/printpreview/arrow-right-end.png     (printpreview/arrow-right-end.png)
         skin/classic/global/radio/radio-check.gif                (radio/radio-check.gif)
         skin/classic/global/radio/radio-check-dis.gif            (radio/radio-check-dis.gif)
         skin/classic/global/scrollbar/slider.gif                 (scrollbar/slider.gif)
         skin/classic/global/splitter/grip-bottom.gif             (splitter/grip-bottom.gif)
@@ -347,16 +358,27 @@ toolkit.jar:
         skin/classic/aero/global/media/throbber.png                      (media/throbber.png)
         skin/classic/aero/global/media/stalled.png                       (media/stalled.png)
         skin/classic/aero/global/media/volume-empty.png                  (media/volume-empty.png)
         skin/classic/aero/global/media/volume-full.png                   (media/volume-full.png)
         skin/classic/aero/global/media/error.png                         (media/error.png)
         skin/classic/aero/global/media/clicktoplay-bgtexture.png         (media/clicktoplay-bgtexture.png)
         skin/classic/aero/global/media/videoClickToPlayButton.svg        (media/videoClickToPlayButton.svg)
         skin/classic/aero/global/menu/shared-menu-check.png              (../../shared/menu-check.png)
+*       skin/classic/aero/global/in-content/common.css                   (in-content/common.css)
+        skin/classic/aero/global/in-content/check.png                    (../../shared/in-content/check.png)
+        skin/classic/aero/global/in-content/check@2x.png                 (../../shared/in-content/check@2x.png)
+        skin/classic/aero/global/in-content/dropdown.png                 (../../shared/in-content/dropdown.png)
+        skin/classic/aero/global/in-content/dropdown@2x.png              (../../shared/in-content/dropdown@2x.png)
+        skin/classic/aero/global/in-content/dropdown-disabled.png        (../../shared/in-content/dropdown-disabled.png)
+        skin/classic/aero/global/in-content/dropdown-disabled@2x.png     (../../shared/in-content/dropdown-disabled@2x.png)
+        skin/classic/aero/global/in-content/help-glyph.png               (../../shared/in-content/help-glyph.png)
+        skin/classic/aero/global/in-content/help-glyph@2x.png            (../../shared/in-content/help-glyph@2x.png)
+        skin/classic/aero/global/in-content/sorter.png                   (../../shared/in-content/sorter.png)
+        skin/classic/aero/global/in-content/sorter@2x.png                (../../shared/in-content/sorter@2x.png)
         skin/classic/aero/global/printpreview/arrow-left.png             (printpreview/arrow-left-aero.png)
         skin/classic/aero/global/printpreview/arrow-left-end.png         (printpreview/arrow-left-end-aero.png)
         skin/classic/aero/global/printpreview/arrow-right.png            (printpreview/arrow-right-aero.png)
         skin/classic/aero/global/printpreview/arrow-right-end.png        (printpreview/arrow-right-end-aero.png)
         skin/classic/aero/global/radio/radio-check.gif                   (radio/radio-check.gif)
         skin/classic/aero/global/radio/radio-check-dis.gif               (radio/radio-check-dis.gif)
         skin/classic/aero/global/scrollbar/slider.gif                    (scrollbar/slider.gif)
         skin/classic/aero/global/splitter/grip-bottom.gif                (splitter/grip-bottom.gif)
--- a/toolkit/themes/windows/mozapps/extensions/extensions.css
+++ b/toolkit/themes/windows/mozapps/extensions/extensions.css
@@ -1119,16 +1119,20 @@ menulist { /* Fixes some styling inconsi
 
 
 /*** buttons ***/
 
 .addon-control[disabled="true"] {
   display: none;
 }
 
+.addon-control.no-auto-hide {
+  display: block;
+}
+
 button.button-link {
   -moz-appearance: none;
   background: transparent;
   border: none;
   box-shadow: none;
   text-decoration: underline;
   color: #0066CC;
   cursor: pointer;