diff --git a/CLOBBER b/CLOBBER
index b02b8fc90d36aaa3867d9afd66d4d684ce4d04f9..cc2cb7ee4f26d5c50e570b7a16a1919ae390e00a 100644
--- a/CLOBBER
+++ b/CLOBBER
@@ -18,4 +18,4 @@
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-Bug 928390 requires a clobber because of bug 939416.
+Australis landing.
diff --git a/accessible/tests/mochitest/events/test_focus_general.html b/accessible/tests/mochitest/events/test_focus_general.html
index 55f71d5f7b55db95b297d8d5e4814d00accee3d8..e1a09c6149567e59491125bd4d997a22d0718b43 100644
--- a/accessible/tests/mochitest/events/test_focus_general.html
+++ b/accessible/tests/mochitest/events/test_focus_general.html
@@ -96,7 +96,7 @@
       gQueue.push(new focusElmWhileSubdocIsFocused("link"));
 
       gQueue.push(new synthTab(editableDoc, new focusChecker(editableDoc)));
-      if (WIN) {
+      if (WIN || LINUX) {
         // Alt key is used to active menubar and focus menu item on Windows,
         // other platforms requires setting a ui.key.menuAccessKeyFocuses
         // preference.
diff --git a/accessible/tests/mochitest/events/test_menu.xul b/accessible/tests/mochitest/events/test_menu.xul
index a286964a1fbb901ab86514baf68ce9d5c25c2d24..bae36fb7123934d74d4cdf930101a42c2ac61653 100644
--- a/accessible/tests/mochitest/events/test_menu.xul
+++ b/accessible/tests/mochitest/events/test_menu.xul
@@ -156,7 +156,7 @@
       // Alt key is used to active menubar and focus menu item on Windows,
       // other platforms requires setting a ui.key.menuAccessKeyFocuses
       // preference.
-      if (WIN) {
+      if (WIN || LINUX) {
         gQueue.push(new focusFileMenu());
         gQueue.push(new focusEditMenu());
         gQueue.push(new leaveMenubar());
diff --git a/addon-sdk/source/test/test-ui-button.js b/addon-sdk/source/test/test-ui-button.js
index f481fae29062ba429d0713c696b27acfa09aa740..3f05eeb774497ed7c4af35cb7d350289818bf8de 100644
--- a/addon-sdk/source/test/test-ui-button.js
+++ b/addon-sdk/source/test/test-ui-button.js
@@ -11,7 +11,7 @@ module.metadata = {
 
 const { Cu } = require('chrome');
 const { Loader } = require('sdk/test/loader');
-const data = require('./fixtures');
+const { data } = require('sdk/self');
 const { open, focus, close } = require('sdk/window/helpers');
 const { setTimeout } = require('sdk/timers');
 const { getMostRecentBrowserWindow } = require('sdk/window/utils');
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index bb29699a8f779c9168d238c3fc06b09e2e9aabd9..88dc128fb8129bce52f388a01376e450ed956671 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -444,11 +444,10 @@ pref("browser.tabs.loadDivertedInBackground", false);
 pref("browser.tabs.loadBookmarksInBackground", false);
 pref("browser.tabs.tabClipWidth", 140);
 pref("browser.tabs.animate", true);
-pref("browser.tabs.onTop", true);
-#ifdef XP_WIN
-pref("browser.tabs.drawInTitlebar", true);
-#else
+#ifdef UNIX_BUT_NOT_MAC
 pref("browser.tabs.drawInTitlebar", false);
+#else
+pref("browser.tabs.drawInTitlebar", true);
 #endif
 
 // Where to show tab close buttons:
@@ -1332,3 +1331,6 @@ pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%G
 // Necko IPC security checks only needed for app isolation for cookies/cache/etc:
 // currently irrelevant for desktop e10s
 pref("network.disable.ipc.security", true);
+
+// CustomizableUI debug logging.
+pref("browser.uiCustomization.debug", false);
diff --git a/browser/base/content/browser-addons.js b/browser/base/content/browser-addons.js
index b638f31f9ea2b717446586576803613fcd35287a..fe40e408a2a738deb5dfce9b0b2aae86abf02303 100644
--- a/browser/base/content/browser-addons.js
+++ b/browser/base/content/browser-addons.js
@@ -178,50 +178,6 @@ const gXPInstallObserver = {
   }
 };
 
-/*
- * When addons are installed/uninstalled, check and see if the number of items
- * on the add-on bar changed:
- * - If an add-on was installed, incrementing the count, show the bar.
- * - If an add-on was uninstalled, and no more items are left, hide the bar.
- */
-let AddonsMgrListener = {
-  get addonBar() document.getElementById("addon-bar"),
-  get statusBar() document.getElementById("status-bar"),
-  getAddonBarItemCount: function() {
-    // Take into account the contents of the status bar shim for the count.
-    var itemCount = this.statusBar.childNodes.length;
-
-    var defaultOrNoninteractive = this.addonBar.getAttribute("defaultset")
-                                      .split(",")
-                                      .concat(["separator", "spacer", "spring"]);
-    for (let item of this.addonBar.currentSet.split(",")) {
-      if (defaultOrNoninteractive.indexOf(item) == -1)
-        itemCount++;
-    }
-
-    return itemCount;
-  },
-  onInstalling: function(aAddon) {
-    this.lastAddonBarCount = this.getAddonBarItemCount();
-  },
-  onInstalled: function(aAddon) {
-    if (this.getAddonBarItemCount() > this.lastAddonBarCount)
-      setToolbarVisibility(this.addonBar, true);
-  },
-  onUninstalling: function(aAddon) {
-    this.lastAddonBarCount = this.getAddonBarItemCount();
-  },
-  onUninstalled: function(aAddon) {
-    if (this.getAddonBarItemCount() == 0)
-      setToolbarVisibility(this.addonBar, false);
-  },
-  onEnabling: function(aAddon) this.onInstalling(),
-  onEnabled: function(aAddon) this.onInstalled(),
-  onDisabling: function(aAddon) this.onUninstalling(),
-  onDisabled: function(aAddon) this.onUninstalled(),
-};
-
-
 var LightWeightThemeWebInstaller = {
   handleEvent: function (event) {
     switch (event.type) {
@@ -415,3 +371,60 @@ var LightWeightThemeWebInstaller = {
                                     node.baseURI);
   }
 }
+
+/*
+ * Listen for Lightweight Theme styling changes and update the browser's theme accordingly.
+ */
+let LightweightThemeListener = {
+  _modifiedStyles: [],
+
+  init: function () {
+    XPCOMUtils.defineLazyGetter(this, "styleSheet", function() {
+      for (let i = document.styleSheets.length - 1; i >= 0; i--) {
+        let sheet = document.styleSheets[i];
+        if (sheet.href == "chrome://browser/skin/browser-lightweightTheme.css")
+          return sheet;
+      }
+    });
+
+    Services.obs.addObserver(this, "lightweight-theme-styling-update", false);
+    if (document.documentElement.hasAttribute("lwtheme"))
+      this.updateStyleSheet(document.documentElement.style.backgroundImage);
+  },
+
+  uninit: function () {
+    Services.obs.removeObserver(this, "lightweight-theme-styling-update");
+  },
+
+  /**
+   * Append the headerImage to the background-image property of all rulesets in
+   * browser-lightweightTheme.css.
+   *
+   * @param headerImage - a string containing a CSS image for the lightweight theme header.
+   */
+  updateStyleSheet: function(headerImage) {
+    if (!this.styleSheet)
+      return;
+    for (let i = 0; i < this.styleSheet.cssRules.length; i++) {
+      let rule = this.styleSheet.cssRules[i];
+      if (!rule.style.backgroundImage)
+        continue;
+
+      if (!this._modifiedStyles[i])
+        this._modifiedStyles[i] = { backgroundImage: rule.style.backgroundImage };
+
+      rule.style.backgroundImage = this._modifiedStyles[i].backgroundImage + ", " + headerImage;
+    }
+  },
+
+  // nsIObserver
+  observe: function (aSubject, aTopic, aData) {
+    if (aTopic != "lightweight-theme-styling-update" || !this.styleSheet)
+      return;
+
+    let themeData = JSON.parse(aData);
+    if (!themeData)
+      return;
+    this.updateStyleSheet("url(" + themeData.headerURL + ")");
+  },
+};
diff --git a/browser/base/content/browser-appmenu.inc b/browser/base/content/browser-appmenu.inc
deleted file mode 100644
index 0cd58f2ecf49130ac60770fc6f3efb29855502e7..0000000000000000000000000000000000000000
--- a/browser/base/content/browser-appmenu.inc
+++ /dev/null
@@ -1,406 +0,0 @@
-# -*- Mode: HTML -*-
-# 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/.
-
-<menupopup id="appmenu-popup"
-           onpopupshowing="if (event.target == this) {
-                             updateEditUIVisibility();
-#ifdef MOZ_SERVICES_SYNC
-                             gSyncUI.updateUI();
-#endif
-                             return;
-                           }
-                           updateCharacterEncodingMenuState();
-                           if (event.target.parentNode.parentNode.parentNode.parentNode == this)
-                             this._currentPopup = event.target;">
-  <hbox>
-    <vbox id="appmenuPrimaryPane">
-      <splitmenu id="appmenu_newTab"
-                 label="&tabCmd.label;"
-                 command="cmd_newNavigatorTab">
-          <menupopup>
-            <menuitem id="appmenu_newTab_popup"
-                      label="&tabCmd.label;"
-                      command="cmd_newNavigatorTab"
-                      key="key_newNavigatorTab"/>
-            <menuitem id="appmenu_newNavigator"
-                      label="&newNavigatorCmd.label;"
-                      command="cmd_newNavigator"
-                      key="key_newNavigator"/>
-            <menuseparator/>
-            <menuitem id="appmenu_openFile"
-                      label="&openFileCmd.label;"
-                      command="Browser:OpenFile"
-                      key="openFileKb"/>
-          </menupopup>
-      </splitmenu>
-      <menuitem id="appmenu_newPrivateWindow"
-                class="menuitem-iconic menuitem-iconic-tooltip"
-                label="&newPrivateWindow.label;"
-                command="Tools:PrivateBrowsing"
-                key="key_privatebrowsing"/>
-      <menuitem label="&goOfflineCmd.label;"
-                id="appmenu_offlineModeRecovery"
-                type="checkbox"
-                observes="workOfflineMenuitemState"
-                oncommand="BrowserOffline.toggleOfflineStatus();"/>
-      <menuseparator class="appmenu-menuseparator"/>
-      <hbox>
-        <menuitem id="appmenu-edit-label"
-                  label="&appMenuEdit.label;"
-                  disabled="true"/>
-        <toolbarbutton id="appmenu-cut"
-                       class="appmenu-edit-button"
-                       command="cmd_cut"
-                       onclick="if (!this.disabled) hidePopup();"
-                       tooltiptext="&cutButton.tooltip;"/>
-        <toolbarbutton id="appmenu-copy"
-                       class="appmenu-edit-button"
-                       command="cmd_copy"
-                       onclick="if (!this.disabled) hidePopup();"
-                       tooltiptext="&copyButton.tooltip;"/>
-        <toolbarbutton id="appmenu-paste"
-                       class="appmenu-edit-button"
-                       command="cmd_paste"
-                       onclick="if (!this.disabled) hidePopup();"
-                       tooltiptext="&pasteButton.tooltip;"/>
-        <spacer flex="1"/>
-        <menu id="appmenu-editmenu">
-          <menupopup id="appmenu-editmenu-menupopup">
-            <menuitem id="appmenu-editmenu-cut"
-                      class="menuitem-iconic"
-                      label="&cutCmd.label;"
-                      key="key_cut"
-                      command="cmd_cut"/>
-            <menuitem id="appmenu-editmenu-copy"
-                      class="menuitem-iconic"
-                      label="&copyCmd.label;"
-                      key="key_copy"
-                      command="cmd_copy"/>
-            <menuitem id="appmenu-editmenu-paste"
-                      class="menuitem-iconic"
-                      label="&pasteCmd.label;"
-                      key="key_paste"
-                      command="cmd_paste"/>
-            <menuseparator/>
-            <menuitem id="appmenu-editmenu-undo"
-                      label="&undoCmd.label;"
-                      key="key_undo"
-                      command="cmd_undo"/>
-            <menuitem id="appmenu-editmenu-redo"
-                      label="&redoCmd.label;"
-                      key="key_redo"
-                      command="cmd_redo"/>
-            <menuseparator/>
-            <menuitem id="appmenu-editmenu-selectAll"
-                      label="&selectAllCmd.label;"
-                      key="key_selectAll"
-                      command="cmd_selectAll"/>
-            <menuseparator/>
-            <menuitem id="appmenu-editmenu-delete"
-                      label="&deleteCmd.label;"
-                      key="key_delete"
-                      command="cmd_delete"/>
-          </menupopup>
-        </menu>
-      </hbox>
-      <menuitem id="appmenu_find"
-                class="menuitem-tooltip"
-                label="&appMenuFind.label;"
-                command="cmd_find"
-                key="key_find"/>
-      <menuseparator class="appmenu-menuseparator"/>
-      <menuitem id="appmenu_savePage"
-                class="menuitem-tooltip"
-                label="&savePageCmd.label;"
-                command="Browser:SavePage"
-                key="key_savePage"/>
-      <menuitem id="appmenu_sendLink"
-                label="&emailPageCmd.label;"
-                command="Browser:SendLink"/>
-      <splitmenu id="appmenu_print"
-                 iconic="true"
-                 label="&printCmd.label;"
-                 command="cmd_print">
-          <menupopup>
-            <menuitem id="appmenu_print_popup"
-                      class="menuitem-iconic"
-                      label="&printCmd.label;"
-                      command="cmd_print"
-                      key="printKb"/>
-            <menuitem id="appmenu_printPreview"
-                      label="&printPreviewCmd.label;"
-                      command="cmd_printPreview"/>
-            <menuitem id="appmenu_printSetup"
-                      label="&printSetupCmd.label;"
-                      command="cmd_pageSetup"/>
-          </menupopup>
-      </splitmenu>
-      <menuseparator class="appmenu-menuseparator"/>
-      <splitmenu id="appmenu_webDeveloper"
-                 command="Tools:DevToolbox"
-                 label="&appMenuWebDeveloper.label;">
-        <menupopup id="appmenu_webDeveloper_popup">
-          <menuitem id="appmenu_devToolbox"
-                    observes="devtoolsMenuBroadcaster_DevToolbox"/>
-          <menuseparator id="appmenu_devtools_separator"/>
-          <menuitem id="appmenu_devToolbar"
-                    observes="devtoolsMenuBroadcaster_DevToolbar"/>
-          <menuitem id="appmenu_devAppMgr"
-                    observes="devtoolsMenuBroadcaster_DevAppMgr"/>
-          <menuitem id="appmenu_chromeDebugger"
-                    observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
-          <menuitem id="appmenu_browserConsole"
-                    observes="devtoolsMenuBroadcaster_BrowserConsole"/>
-          <menuitem id="appmenu_responsiveUI"
-                    observes="devtoolsMenuBroadcaster_ResponsiveUI"/>
-          <menuitem id="appmenu_scratchpad"
-                    observes="devtoolsMenuBroadcaster_Scratchpad"/>
-          <menuitem id="appmenu_pageSource"
-                    observes="devtoolsMenuBroadcaster_PageSource"/>
-          <menuitem id="appmenu_errorConsole"
-                    observes="devtoolsMenuBroadcaster_ErrorConsole"/>
-          <menuitem id="appmenu_devtools_connect"
-                    observes="devtoolsMenuBroadcaster_connect"/>
-          <menuseparator id="appmenu_devToolsEndSeparator"/>
-          <menuitem id="appmenu_getMoreDevtools"
-                    observes="devtoolsMenuBroadcaster_GetMoreTools"/>
-          <menuseparator/>
-#define ID_PREFIX appmenu_developer_
-#define OMIT_ACCESSKEYS
-#include browser-charsetmenu.inc
-#undef ID_PREFIX
-#undef OMIT_ACCESSKEYS
-          <menuitem label="&goOfflineCmd.label;"
-                    type="checkbox"
-                    observes="workOfflineMenuitemState"
-                    oncommand="BrowserOffline.toggleOfflineStatus();"/>
-        </menupopup>
-      </splitmenu>
-      <menuseparator class="appmenu-menuseparator"/>
-#define ID_PREFIX appmenu_
-#define OMIT_ACCESSKEYS
-#include browser-charsetmenu.inc
-#undef ID_PREFIX
-#undef OMIT_ACCESSKEYS
-      <menuitem id="appmenu_fullScreen"
-                class="menuitem-tooltip"
-                label="&fullScreenCmd.label;"
-                type="checkbox"
-                observes="View:FullScreen"
-                key="key_fullScreen"/>
-#ifdef MOZ_SERVICES_SYNC
-      <!-- only one of sync-setup or sync-syncnow will be showing at once -->
-      <menuitem id="sync-setup-appmenu"
-                label="&syncSetup.label;"
-                observes="sync-setup-state"
-                oncommand="gSyncUI.openSetup()"/>
-      <menuitem id="sync-syncnowitem-appmenu"
-                label="&syncSyncNowItem.label;"
-                observes="sync-syncnow-state"
-                oncommand="gSyncUI.doSync(event);"/>
-#endif
-      <menuitem id="appmenu-quit"
-                class="menuitem-iconic"
-#ifdef XP_WIN
-                label="&quitApplicationCmdWin.label;"
-#else
-                label="&quitApplicationCmd.label;"
-#endif
-                command="cmd_quitApplication"/>
-    </vbox>
-    <vbox id="appmenuSecondaryPane">
-      <splitmenu id="appmenu_bookmarks"
-                 iconic="true"
-                 label="&bookmarksMenu.label;"
-                 command="Browser:ShowAllBookmarks">
-          <menupopup id="appmenu_bookmarksPopup"
-                     placespopup="true"
-                     context="placesContext"
-                     openInTabs="children"
-                     oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
-                     onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
-                     onpopupshowing="BookmarkingUI.onPopupShowing(event);
-                                     if (!this.parentNode._placesView)
-                                       new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
-                     tooltip="bhTooltip"
-                     popupsinherittooltip="true">
-            <menuitem id="appmenu_showAllBookmarks"
-                      label="&showAllBookmarks2.label;"
-                      command="Browser:ShowAllBookmarks"
-                      context=""
-                      key="manBookmarkKb"/>
-            <menuseparator/>
-            <menuitem id="appmenu_bookmarkThisPage"
-                      class="menuitem-iconic"
-                      label="&bookmarkThisPageCmd.label;"
-                      command="Browser:AddBookmarkAs"
-                      key="addBookmarkAsKb"/>
-            <menuitem id="appmenu_subscribeToPage"
-                      class="menuitem-iconic"
-                      label="&subscribeToPageMenuitem.label;"
-                      oncommand="return FeedHandler.subscribeToFeed(null, event);"
-                      onclick="checkForMiddleClick(this, event);"
-                      observes="singleFeedMenuitemState"/>
-            <menu id="appmenu_subscribeToPageMenu"
-                  class="menu-iconic"
-                  label="&subscribeToPageMenupopup.label;"
-                  observes="multipleFeedsMenuState">
-              <menupopup id="appmenu_subscribeToPageMenupopup"
-                         onpopupshowing="return FeedHandler.buildFeedList(event.target);"
-                         oncommand="return FeedHandler.subscribeToFeed(null, event);"
-                         onclick="checkForMiddleClick(this, event);"/>
-            </menu>
-            <menuseparator/>
-            <menu id="appmenu_bookmarksToolbar"
-                  placesanonid="toolbar-autohide"
-                  class="menu-iconic bookmark-item"
-                  label="&personalbarCmd.label;"
-                  container="true">
-              <menupopup id="appmenu_bookmarksToolbarPopup"
-                         placespopup="true"
-                         context="placesContext"
-                         onpopupshowing="if (!this.parentNode._placesView)
-                                           new PlacesMenu(event, 'place:folder=TOOLBAR');"/>
-            </menu>
-            <menuseparator/>
-            <!-- Bookmarks menu items -->
-            <menuseparator builder="end"
-                           class="hide-if-empty-places-result"/>
-            <menuitem id="appmenu_unsortedBookmarks"
-                      label="&appMenuUnsorted.label;"
-                      oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"
-                      class="menuitem-iconic"/>
-          </menupopup>
-      </splitmenu>
-      <splitmenu id="appmenu_history"
-                 iconic="true"
-                 label="&historyMenu.label;"
-                 command="Browser:ShowAllHistory">
-          <menupopup id="appmenu_historyMenupopup"
-                     placespopup="true"
-                     oncommand="this.parentNode._placesView._onCommand(event);"
-                     onclick="checkForMiddleClick(this, event);"
-                     onpopupshowing="if (!this.parentNode._placesView)
-                                       new HistoryMenu(event);"
-                     tooltip="bhTooltip"
-                     popupsinherittooltip="true">
-            <menuitem id="appmenu_showAllHistory"
-                      label="&showAllHistoryCmd2.label;"
-                      command="Browser:ShowAllHistory"
-                      key="showAllHistoryKb"/>
-            <menuseparator/>
-            <menuitem id="appmenu_sanitizeHistory"
-                      label="&clearRecentHistory.label;"
-                      key="key_sanitize"
-                      command="Tools:Sanitize"/>
-            <menuseparator class="hide-if-empty-places-result"/>
-#ifdef MOZ_SERVICES_SYNC
-            <menuitem id="appmenu_sync-tabs"
-                      class="syncTabsMenuItem"
-                      label="&syncTabsMenu2.label;"
-                      oncommand="BrowserOpenSyncTabs();"
-                      disabled="true"/>
-#endif
-            <menuitem id="appmenu_restoreLastSession"
-                      label="&historyRestoreLastSession.label;"
-                      command="Browser:RestoreLastSession"/>
-            <menu id="appmenu_recentlyClosedTabsMenu"
-                  class="recentlyClosedTabsMenu"
-                  label="&historyUndoMenu.label;"
-                  disabled="true">
-              <menupopup id="appmenu_recentlyClosedTabsMenupopup"
-                         onpopupshowing="document.getElementById('appmenu_history')._placesView.populateUndoSubmenu();"/>
-            </menu>
-            <menu id="appmenu_recentlyClosedWindowsMenu"
-                  class="recentlyClosedWindowsMenu"
-                  label="&historyUndoWindowMenu.label;"
-                  disabled="true">
-              <menupopup id="appmenu_recentlyClosedWindowsMenupopup"
-                         onpopupshowing="document.getElementById('appmenu_history')._placesView.populateUndoWindowSubmenu();"/>
-            </menu>
-            <menuseparator/>
-          </menupopup>
-      </splitmenu>
-      <menuitem id="appmenu_downloads"
-                class="menuitem-tooltip"
-                label="&downloads.label;"
-                command="Tools:Downloads"
-                key="key_openDownloads"/>
-      <spacer id="appmenuSecondaryPane-spacer"/>
-      <menuitem id="appmenu_addons"
-                class="menuitem-iconic menuitem-iconic-tooltip"
-                label="&addons.label;"
-                command="Tools:Addons"
-                key="key_openAddons"/>
-      <splitmenu id="appmenu_customize"
-#ifdef XP_UNIX
-                 label="&preferencesCmdUnix.label;"
-#else
-                 label="&preferencesCmd2.label;"
-#endif
-                 oncommand="openPreferences();">
-          <menupopup id="appmenu_customizeMenu"
-                     onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('appmenu_toggleToolbarsSeparator'));">
-            <menuitem id="appmenu_preferences"
-#ifdef XP_UNIX
-                      label="&preferencesCmdUnix.label;"
-#else
-                      label="&preferencesCmd2.label;"
-#endif
-                      oncommand="openPreferences();"/>
-            <menuseparator/>
-            <menuseparator id="appmenu_toggleToolbarsSeparator"/>
-            <menuitem id="appmenu_toggleTabsOnTop"
-                      label="&viewTabsOnTop.label;"
-                      type="checkbox"
-                      command="cmd_ToggleTabsOnTop"/>
-            <menuitem id="appmenu_toolbarLayout"
-                      label="&appMenuToolbarLayout.label;"
-                      command="cmd_CustomizeToolbars"/>
-          </menupopup>
-      </splitmenu>
-      <splitmenu id="appmenu_help"
-                 label="&helpMenu.label;"
-                 oncommand="openHelpLink('firefox-help')">
-          <menupopup id="appmenu_helpMenupopup">
-            <menuitem id="appmenu_openHelp"
-                      label="&helpMenu.label;"
-                      oncommand="openHelpLink('firefox-help')"
-                      onclick="checkForMiddleClick(this, event);"/>
-            <menuitem id="appmenu_gettingStarted"
-                      label="&appMenuGettingStarted.label;"
-                      oncommand="gBrowser.loadOneTab('https://www.mozilla.org/firefox/central/', {inBackground: false});"
-                      onclick="checkForMiddleClick(this, event);"/>
-            <menuitem id="appmenu_keyboardShortcuts"
-                      label="&helpKeyboardShortcuts.label;"
-                      oncommand="openHelpLink('keyboard-shortcuts')"
-                      onclick="checkForMiddleClick(this, event);"/>
-#ifdef MOZ_SERVICES_HEALTHREPORT
-            <menuitem id="appmenu_healthReport"
-                      label="&healthReport.label;"
-                      oncommand="openHealthReport()"
-                      onclick="checkForMiddleClick(this, event);"/>
-#endif
-            <menuitem id="appmenu_troubleshootingInfo"
-                      label="&helpTroubleshootingInfo.label;"
-                      oncommand="openTroubleshootingPage()"
-                      onclick="checkForMiddleClick(this,event);"/>
-            <menuitem id="appmenu_feedbackPage"
-                      label="&helpFeedbackPage.label;"
-                      oncommand="openFeedbackPage()"
-                      onclick="checkForMiddleClick(this, event);"/>
-            <menuseparator/>
-            <menuitem id="appmenu_safeMode"
-                      label="&appMenuSafeMode.label;"
-                      oncommand="safeModeRestart();"/>
-            <menuseparator/>
-            <menuitem id="appmenu_about"
-                      label="&aboutProduct.label;"
-                      oncommand="openAboutDialog();"/>
-          </menupopup>
-      </splitmenu>
-    </vbox>
-  </hbox>
-</menupopup>
diff --git a/browser/base/content/browser-customization.js b/browser/base/content/browser-customization.js
new file mode 100644
index 0000000000000000000000000000000000000000..369f6cbd22cf9b16cc1c2fb7d0b6c1372c1f4ed8
--- /dev/null
+++ b/browser/base/content/browser-customization.js
@@ -0,0 +1,97 @@
+# -*- Mode: javascript; 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/.
+
+/**
+ * Customization handler prepares this browser window for entering and exiting
+ * customization mode by handling customizationstarting and customizationending
+ * events.
+ */
+let CustomizationHandler = {
+  handleEvent: function(aEvent) {
+    switch(aEvent.type) {
+      case "customizationstarting":
+        this._customizationStarting();
+        break;
+      case "customizationending":
+        this._customizationEnding(aEvent.detail);
+        break;
+    }
+  },
+
+  isCustomizing: function() {
+    return document.documentElement.hasAttribute("customizing") ||
+           document.documentElement.hasAttribute("customize-exiting");
+  },
+
+  _customizationStarting: function() {
+    // Disable the toolbar context menu items
+    let menubar = document.getElementById("main-menubar");
+    for (let childNode of menubar.childNodes)
+      childNode.setAttribute("disabled", true);
+
+    let cmd = document.getElementById("cmd_CustomizeToolbars");
+    cmd.setAttribute("disabled", "true");
+
+    let splitter = document.getElementById("urlbar-search-splitter");
+    if (splitter) {
+      splitter.parentNode.removeChild(splitter);
+    }
+
+    CombinedStopReload.uninit();
+    PlacesToolbarHelper.customizeStart();
+    BookmarkingUI.customizeStart();
+    DownloadsButton.customizeStart();
+  },
+
+  _customizationEnding: function(aDetails) {
+    // Update global UI elements that may have been added or removed
+    if (aDetails.changed) {
+      gURLBar = document.getElementById("urlbar");
+
+      gProxyFavIcon = document.getElementById("page-proxy-favicon");
+      gHomeButton.updateTooltip();
+      gIdentityHandler._cacheElements();
+      XULBrowserWindow.init();
+
+#ifndef XP_MACOSX
+      updateEditUIVisibility();
+#endif
+
+      // Hacky: update the PopupNotifications' object's reference to the iconBox,
+      // if it already exists, since it may have changed if the URL bar was
+      // added/removed.
+      if (!window.__lookupGetter__("PopupNotifications")) {
+        PopupNotifications.iconBox =
+          document.getElementById("notification-popup-box");
+      }
+
+    }
+
+    PlacesToolbarHelper.customizeDone();
+    BookmarkingUI.customizeDone();
+    DownloadsButton.customizeDone();
+
+    // The url bar splitter state is dependent on whether stop/reload
+    // and the location bar are combined, so we need this ordering
+    CombinedStopReload.init();
+    UpdateUrlbarSearchSplitterState();
+
+    // Update the urlbar
+    if (gURLBar) {
+      URLBarSetURI();
+      XULBrowserWindow.asyncUpdateUI();
+      BookmarkingUI.updateStarState();
+    }
+
+    // Re-enable parts of the UI we disabled during the dialog
+    let menubar = document.getElementById("main-menubar");
+    for (let childNode of menubar.childNodes)
+      childNode.setAttribute("disabled", false);
+    let cmd = document.getElementById("cmd_CustomizeToolbars");
+    cmd.removeAttribute("disabled");
+
+    gBrowser.selectedBrowser.focus();
+  }
+}
diff --git a/browser/base/content/browser-feeds.js b/browser/base/content/browser-feeds.js
index 7bba395408246a6c8f04db282b872853c518f1e8..2bdb33cd09eb19ea93e59a38f8381ade18864157 100644
--- a/browser/base/content/browser-feeds.js
+++ b/browser/base/content/browser-feeds.js
@@ -8,66 +8,53 @@
  * and shows UI when they are discovered.
  */
 var FeedHandler = {
-  /**
-   * The click handler for the Feed icon in the toolbar. Opens the
-   * subscription page if user is not given a choice of feeds.
-   * (Otherwise the list of available feeds will be presented to the
-   * user in a popup menu.)
-   */
-  onFeedButtonClick: function(event) {
-    event.stopPropagation();
-
-    let feeds = gBrowser.selectedBrowser.feeds || [];
-    // If there are multiple feeds, the menu will open, so no need to do
-    // anything. If there are no feeds, nothing to do either.
-    if (feeds.length != 1)
-      return;
-
-    if (event.eventPhase == Event.AT_TARGET &&
-        (event.button == 0 || event.button == 1)) {
-      this.subscribeToFeed(feeds[0].href, event);
-    }
-  },
-
- /** Called when the user clicks on the Subscribe to This Page... menu item.
+  /** Called when the user clicks on the Subscribe to This Page... menu item,
+   * or when the user clicks the feed button when the page contains multiple
+   * feeds.
    * Builds a menu of unique feeds associated with the page, and if there
    * is only one, shows the feed inline in the browser window.
-   * @param   menuPopup
-   *          The feed list menupopup to be populated.
-   * @returns true if the menu should be shown, false if there was only
+   * @param   container
+   *          The feed list container (menupopup or subview) to be populated.
+   * @param   isSubview
+   *          Whether we're creating a subview (true) or menu (false/undefined)
+   * @returns true if the menu/subview should be shown, false if there was only
    *          one feed and the feed should be shown inline in the browser
-   *          window (do not show the menupopup).
+   *          window (do not show the menupopup/subview).
    */
-  buildFeedList: function(menuPopup) {
+  buildFeedList: function(container, isSubview) {
     var feeds = gBrowser.selectedBrowser.feeds;
-    if (feeds == null) {
+    if (!isSubview && feeds == null) {
       // XXX hack -- menu opening depends on setting of an "open"
       // attribute, and the menu refuses to open if that attribute is
       // set (because it thinks it's already open).  onpopupshowing gets
       // called after the attribute is unset, and it doesn't get unset
       // if we return false.  so we unset it here; otherwise, the menu
       // refuses to work past this point.
-      menuPopup.parentNode.removeAttribute("open");
+      container.parentNode.removeAttribute("open");
       return false;
     }
 
-    while (menuPopup.firstChild)
-      menuPopup.removeChild(menuPopup.firstChild);
+    while (container.firstChild)
+      container.removeChild(container.firstChild);
 
-    if (feeds.length <= 1)
+    if (!feeds || feeds.length <= 1)
       return false;
 
     // Build the menu showing the available feed choices for viewing.
+    var itemNodeType = isSubview ? "toolbarbutton" : "menuitem";
     for (let feedInfo of feeds) {
-      var menuItem = document.createElement("menuitem");
+      var item = document.createElement(itemNodeType);
       var baseTitle = feedInfo.title || feedInfo.href;
       var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]);
-      menuItem.setAttribute("class", "feed-menuitem");
-      menuItem.setAttribute("label", labelStr);
-      menuItem.setAttribute("feed", feedInfo.href);
-      menuItem.setAttribute("tooltiptext", feedInfo.href);
-      menuItem.setAttribute("crop", "center");
-      menuPopup.appendChild(menuItem);
+      item.setAttribute("class", "feed-" + itemNodeType);
+      item.setAttribute("label", labelStr);
+      item.setAttribute("feed", feedInfo.href);
+      item.setAttribute("tooltiptext", feedInfo.href);
+      item.setAttribute("crop", "center");
+      if (isSubview) {
+        item.setAttribute("tabindex", "0");
+      }
+      container.appendChild(item);
     }
     return true;
   },
@@ -76,7 +63,7 @@ var FeedHandler = {
    * Subscribe to a given feed.  Called when
    *   1. Page has a single feed and user clicks feed icon in location bar
    *   2. Page has a single feed and user selects Subscribe menu item
-   *   3. Page has multiple feeds and user selects from feed icon popup
+   *   3. Page has multiple feeds and user selects from feed icon popup (or subview)
    *   4. Page has multiple feeds and user selects from Subscribe submenu
    * @param   href
    *          The feed to subscribe to. May be null, in which case the
diff --git a/browser/base/content/browser-fullScreen.js b/browser/base/content/browser-fullScreen.js
index a8ffa754ad028ace501330d35555f7bedd1356b2..4e416ef0437e516c1e268a042defe14754c86e8f 100644
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -17,7 +17,7 @@ var FullScreen = {
       enterFS = !enterFS;
 
     // Toggle the View:FullScreen command, which controls elements like the
-    // fullscreen menuitem, menubars, and the appmenu.
+    // fullscreen menuitem, and menubars.
     let fullscreenCommand = document.getElementById("View:FullScreen");
     if (enterFS) {
       fullscreenCommand.setAttribute("checked", enterFS);
@@ -517,15 +517,6 @@ var FullScreen = {
       // XXX don't interfere with previously collapsed toolbars
       if (el.getAttribute("fullscreentoolbar") == "true") {
         if (!aShow) {
-
-          var toolbarMode = el.getAttribute("mode");
-          if (toolbarMode != "text") {
-            el.setAttribute("saved-mode", toolbarMode);
-            el.setAttribute("saved-iconsize", el.getAttribute("iconsize"));
-            el.setAttribute("mode", "icons");
-            el.setAttribute("iconsize", "small");
-          }
-
           // Give the main nav bar and the tab bar the fullscreen context menu,
           // otherwise remove context menu to prevent breakage
           el.setAttribute("saved-context", el.getAttribute("context"));
@@ -539,18 +530,10 @@ var FullScreen = {
           el.setAttribute("inFullscreen", true);
         }
         else {
-          var restoreAttr = function restoreAttr(attrName) {
-            var savedAttr = "saved-" + attrName;
-            if (el.hasAttribute(savedAttr)) {
-              el.setAttribute(attrName, el.getAttribute(savedAttr));
-              el.removeAttribute(savedAttr);
-            }
+          if (el.hasAttribute("saved-context")) {
+            el.setAttribute("context", el.getAttribute("saved-context"));
+            el.removeAttribute("saved-context");
           }
-
-          restoreAttr("mode");
-          restoreAttr("iconsize");
-          restoreAttr("context");
-
           el.removeAttribute("inFullscreen");
         }
       } else {
@@ -571,11 +554,9 @@ var FullScreen = {
       document.documentElement.setAttribute("inFullscreen", true);
     }
 
-    // In tabs-on-top mode, move window controls to the tab bar,
-    // and in tabs-on-bottom mode, move them back to the navigation toolbar.
     var fullscreenctls = document.getElementById("window-controls");
     var navbar = document.getElementById("nav-bar");
-    var ctlsOnTabbar = window.toolbar.visible && (navbar.collapsed || TabsOnTop.enabled);
+    var ctlsOnTabbar = window.toolbar.visible;
     if (fullscreenctls.parentNode == navbar && ctlsOnTabbar) {
       fullscreenctls.removeAttribute("flex");
       document.getElementById("TabsToolbar").appendChild(fullscreenctls);
diff --git a/browser/base/content/browser-fullZoom.js b/browser/base/content/browser-fullZoom.js
index d92dfcc625e1b27585c8c98c18e468095fc86e22..55f02c38b9e6adc659a2af86dd2a999f02ad86f5 100644
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -397,6 +397,7 @@ var FullZoom = {
    * @param browser  The zoom of this browser will be saved.  Required.
    */
   _applyZoomToPref: function FullZoom__applyZoomToPref(browser) {
+    Services.obs.notifyObservers(null, "browser-fullZoom:zoomChange", "");
     if (!this.siteSpecific ||
         gInPrintPreviewMode ||
         browser.contentDocument.mozSyntheticDocument)
@@ -417,6 +418,7 @@ var FullZoom = {
    * @param browser  The zoom of this browser will be removed.  Required.
    */
   _removePref: function FullZoom__removePref(browser) {
+    Services.obs.notifyObservers(null, "browser-fullZoom:zoomReset", "");
     if (browser.contentDocument.mozSyntheticDocument)
       return;
     let ctxt = this._loadContextFromWindow(browser.contentWindow);
diff --git a/browser/base/content/browser-menubar.inc b/browser/base/content/browser-menubar.inc
index 856f81b92f1b8891fc6f67350d48f058f8e71461..1db9222eb731047edbe04324771685cc36fb4b2e 100644
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -185,11 +185,6 @@
                       accesskey="&viewToolbarsMenu.accesskey;">
                   <menupopup onpopupshowing="onViewToolbarsPopupShowing(event);">
                     <menuseparator/>
-                    <menuitem id="menu_tabsOnTop"
-                              command="cmd_ToggleTabsOnTop"
-                              type="checkbox"
-                              label="&viewTabsOnTop.label;"
-                              accesskey="&viewTabsOnTop.accesskey;"/>
                     <menuitem id="menu_customizeToolbars"
                               label="&viewCustomizeToolbar.label;"
                               accesskey="&viewCustomizeToolbar.accesskey;"
diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js
index 61a9618fe968c4d160568b8c7bd74b1aecffdaa5..9ed823376b5b24b21cb071b8c99dc2a62dea9463 100644
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -134,9 +134,6 @@ var StarUI = {
     document.loadOverlay(
       "chrome://browser/content/places/editBookmarkOverlay.xul",
       (function (aSubject, aTopic, aData) {
-        //XXX We just caused localstore.rdf to be re-applied (bug 640158)
-        retrieveToolbarIconsizesFromTheme();
-
         // Move the header (star, title, button) into the grid,
         // so that it aligns nicely with the other items (bug 484022).
         let header = this._element("editBookmarkPanelHeader");
@@ -745,9 +742,10 @@ var BookmarksEventHandler = {
 // Handles special drag and drop functionality for Places menus that are not
 // part of a Places view (e.g. the bookmarks menu in the menubar).
 var PlacesMenuDNDHandler = {
-  _springLoadDelay: 350, // milliseconds
+  _springLoadDelayMs: 350,
+  _closeDelayMs: 500,
   _loadTimer: null,
-  _closerTimer: null,
+  _closeTimer: null,
 
   /**
    * Called when the user enters the <menu> element during a drag.
@@ -768,7 +766,7 @@ var PlacesMenuDNDHandler = {
       this._loadTimer = null;
       popup.setAttribute("autoopened", "true");
       popup.showPopup(popup);
-    }, this._springLoadDelay, Ci.nsITimer.TYPE_ONE_SHOT);
+    }, this._springLoadDelayMs, Ci.nsITimer.TYPE_ONE_SHOT);
     event.preventDefault();
     event.stopPropagation();
   },
@@ -781,7 +779,8 @@ var PlacesMenuDNDHandler = {
   onDragLeave: function PMDH_onDragLeave(event) {
     // Handle menu-button separate targets.
     if (event.relatedTarget === event.currentTarget ||
-        event.relatedTarget.parentNode === event.currentTarget)
+        (event.relatedTarget &&
+         event.relatedTarget.parentNode === event.currentTarget))
       return;
 
     // Closing menus in a Places popup is handled by the view itself.
@@ -807,7 +806,7 @@ var PlacesMenuDNDHandler = {
         popup.removeAttribute("autoopened");
         popup.hidePopup();
       }
-    }, this._springLoadDelay, Ci.nsITimer.TYPE_ONE_SHOT);
+    }, this._closeDelayMs, Ci.nsITimer.TYPE_ONE_SHOT);
   },
 
   /**
@@ -875,30 +874,52 @@ let PlacesToolbarHelper = {
     if (!viewElt || viewElt._placesView)
       return;
 
-    // If the bookmarks toolbar item is hidden because the parent toolbar is
-    // collapsed or hidden (i.e. in a popup), spare the initialization.  Also,
-    // there is no need to initialize the toolbar if customizing because
-    // init() will be called when the customization is done.
-    let toolbar = viewElt.parentNode.parentNode;
-    if (toolbar.collapsed ||
-        getComputedStyle(toolbar, "").display == "none" ||
-        this._isCustomizing)
+    // If the bookmarks toolbar item is:
+    // - not in a toolbar, or;
+    // - the toolbar is collapsed, or;
+    // - the toolbar is hidden some other way:
+    // don't initialize.  Also, there is no need to initialize the toolbar if
+    // customizing, because that will happen when the customization is done.
+    let toolbar = this._getParentToolbar(viewElt);
+    if (!toolbar || toolbar.collapsed || this._isCustomizing ||
+        getComputedStyle(toolbar, "").display == "none")
       return;
 
     new PlacesToolbar(this._place);
   },
 
   customizeStart: function PTH_customizeStart() {
-    let viewElt = this._viewElt;
-    if (viewElt && viewElt._placesView)
-      viewElt._placesView.uninit();
-
-    this._isCustomizing = true;
+    try {
+      let viewElt = this._viewElt;
+      if (viewElt && viewElt._placesView)
+        viewElt._placesView.uninit();
+    } finally {
+      this._isCustomizing = true;
+    }
   },
 
   customizeDone: function PTH_customizeDone() {
     this._isCustomizing = false;
     this.init();
+  },
+
+  onPlaceholderCommand: function () {
+    let widgetGroup = CustomizableUI.getWidget("personal-bookmarks");
+    let widget = widgetGroup.forWindow(window);
+    if (widget.overflowed ||
+        widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) {
+      PlacesCommandHook.showPlacesOrganizer("BookmarksToolbar");
+    }
+  },
+
+  _getParentToolbar: function(element) {
+    while (element) {
+      if (element.localName == "toolbar") {
+        return element;
+      }
+      element = element.parentNode;
+    }
+    return null;
   }
 };
 
@@ -906,31 +927,33 @@ let PlacesToolbarHelper = {
 //// BookmarkingUI
 
 /**
- * Handles the bookmarks star button in the URL bar, as well as the bookmark
- * menu button.
+ * Handles the bookmarks menu-button in the toolbar.
  */
 
 let BookmarkingUI = {
   get button() {
-    if (!this._button) {
-      this._button = document.getElementById("bookmarks-menu-button");
+    let widgetGroup = CustomizableUI.getWidget("bookmarks-menu-button");
+    if (widgetGroup.areaType == CustomizableUI.TYPE_TOOLBAR) {
+      return widgetGroup.forWindow(window).node;
     }
-    return this._button;
+    return null;
   },
 
   get star() {
-    if (!this._star) {
-      this._star = document.getElementById("star-button");
-    }
-    return this._star;
+    let button = this.button;
+    return button && document.getAnonymousElementByAttribute(button, "anonid",
+                                                             "button");
   },
 
   get anchor() {
-    if (this.star && isElementVisible(this.star)) {
-      // Anchor to the icon, so the panel looks more natural.
-      return this.star;
-    }
-    return null;
+    let widget = CustomizableUI.getWidget("bookmarks-menu-button")
+                               .forWindow(window);
+    if (widget.overflowed)
+      return widget.anchor;
+
+    let star = this.star;
+    return star && document.getAnonymousElementByAttribute(star, "class",
+                                                           "toolbarbutton-icon");
   },
 
   STATUS_UPDATING: -1,
@@ -939,9 +962,9 @@ let BookmarkingUI = {
   get status() {
     if (this._pendingStmt)
       return this.STATUS_UPDATING;
-    return this.star &&
-           this.star.hasAttribute("starred") ? this.STATUS_STARRED
-                                             : this.STATUS_UNSTARRED;
+    let button = this.button;
+    return button && button.hasAttribute("starred") ? this.STATUS_STARRED
+                                                    : this.STATUS_UNSTARRED;
   },
 
   get _starredTooltip()
@@ -974,6 +997,16 @@ let BookmarkingUI = {
     if (event.target != event.currentTarget)
       return;
 
+    let widget = CustomizableUI.getWidget("bookmarks-menu-button")
+                               .forWindow(window);
+    if (widget.overflowed) {
+      // Don't open a popup in the overflow popup, rather just open the Library.
+      event.preventDefault();
+      widget.node.removeAttribute("noautoclose");
+      PlacesCommandHook.showPlacesOrganizer("BookmarksMenu");
+      return;
+    }
+
     if (!this._popupNeedsUpdate)
       return;
     this._popupNeedsUpdate = false;
@@ -990,14 +1023,6 @@ let BookmarkingUI = {
       let personalToolbar = document.getElementById("PersonalToolbar");
       viewToolbarMenuitem.setAttribute("checked", !personalToolbar.collapsed);
     }
-
-    let toolbarMenuitem = getPlacesAnonymousElement("toolbar-autohide");
-    if (toolbarMenuitem) {
-      // If bookmarks items are visible, hide Bookmarks Toolbar menu and the
-      // separator after it.
-      toolbarMenuitem.collapsed = toolbarMenuitem.nextSibling.collapsed =
-        isElementVisible(document.getElementById("personal-bookmarks"));
-    }
   },
 
   /**
@@ -1010,29 +1035,31 @@ let BookmarkingUI = {
 
     if (aState == "invalid") {
       this.star.setAttribute("disabled", "true");
-      this.star.removeAttribute("starred");
+      this.button.removeAttribute("starred");
+      this.button.setAttribute("buttontooltiptext", "");
     }
     else {
       this.star.removeAttribute("disabled");
     }
+    this._updateToolbarStyle();
   },
 
   _updateToolbarStyle: function BUI__updateToolbarStyle() {
-    if (!this.button) {
+    let button = this.button;
+    if (!button)
       return;
-    }
 
     let personalToolbar = document.getElementById("PersonalToolbar");
-    let onPersonalToolbar = this.button.parentNode == personalToolbar ||
-                            this.button.parentNode.parentNode == personalToolbar;
+    let onPersonalToolbar = button.parentNode == personalToolbar ||
+                            button.parentNode.parentNode == personalToolbar;
 
     if (onPersonalToolbar) {
-      this.button.classList.add("bookmark-item");
-      this.button.classList.remove("toolbarbutton-1");
+      button.classList.add("bookmark-item");
+      button.classList.remove("toolbarbutton-1");
     }
     else {
-      this.button.classList.remove("bookmark-item");
-      this.button.classList.add("toolbarbutton-1");
+      button.classList.remove("bookmark-item");
+      button.classList.add("toolbarbutton-1");
     }
   },
 
@@ -1040,9 +1067,9 @@ let BookmarkingUI = {
     // When an element with a placesView attached is removed and re-inserted,
     // XBL reapplies the binding causing any kind of issues and possible leaks,
     // so kill current view and let popupshowing generate a new one.
-    if (this.button && this.button._placesView) {
-      this.button._placesView.uninit();
-    }
+    let button = this.button;
+    if (button && button._placesView)
+      button._placesView.uninit();
   },
 
   customizeStart: function BUI_customizeStart() {
@@ -1054,7 +1081,6 @@ let BookmarkingUI = {
   },
 
   customizeDone: function BUI_customizeDone() {
-    delete this._button;
     this.onToolbarVisibilityChange();
     this._updateToolbarStyle();
   },
@@ -1074,7 +1100,7 @@ let BookmarkingUI = {
   },
 
   updateStarState: function BUI_updateStarState() {
-    if (!this.star || (this._uri && gBrowser.currentURI.equals(this._uri))) {
+    if (!this.button || (this._uri && gBrowser.currentURI.equals(this._uri))) {
       return;
     }
 
@@ -1123,17 +1149,17 @@ let BookmarkingUI = {
   },
 
   _updateStar: function BUI__updateStar() {
-    if (!this.star) {
+    let button = this.button;
+    if (!button)
       return;
-    }
 
     if (this._itemIds.length > 0) {
-      this.star.setAttribute("starred", "true");
-      this.star.setAttribute("tooltiptext", this._starredTooltip);
+      button.setAttribute("starred", "true");
+      button.setAttribute("buttontooltiptext", this._starredTooltip);
     }
     else {
-      this.star.removeAttribute("starred");
-      this.star.setAttribute("tooltiptext", this._unstarredTooltip);
+      button.removeAttribute("starred");
+      button.setAttribute("buttontooltiptext", this._unstarredTooltip);
     }
   },
 
@@ -1141,15 +1167,71 @@ let BookmarkingUI = {
     if (aEvent.target != aEvent.currentTarget) {
       return;
     }
+
+    // Handle special case when the button is in the panel.
+    let widgetGroup = CustomizableUI.getWidget("bookmarks-menu-button");
+    let widget = widgetGroup.forWindow(window);
+    if (widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) {
+      let view = document.getElementById("PanelUI-bookmarks");
+      view.addEventListener("ViewShowing", this.onPanelMenuViewShowing);
+      view.addEventListener("ViewHiding", this.onPanelMenuViewHiding);
+      widget.node.setAttribute("noautoclose", "true");
+      PanelUI.showSubView("PanelUI-bookmarks", widget.node,
+                          CustomizableUI.AREA_PANEL);
+      return;
+    }
+    else if (widget.overflowed) {
+      // Allow to close the panel if the page is already bookmarked, cause
+      // we are going to open the edit bookmark panel.
+      if (this._itemIds.length > 0)
+        widget.node.removeAttribute("noautoclose");
+      else
+        widget.node.setAttribute("noautoclose", "true");
+    }
+
     // Ignore clicks on the star if we are updating its state.
     if (!this._pendingStmt) {
       PlacesCommandHook.bookmarkCurrentPage(this._itemIds.length > 0);
     }
   },
 
+  onPanelMenuViewShowing: function BUI_onViewShowing(aEvent) {
+    // Update checked status of the toolbar toggle.
+    let viewToolbar = document.getElementById("panelMenu_viewBookmarksToolbar");
+    let personalToolbar = document.getElementById("PersonalToolbar");
+    if (personalToolbar.collapsed)
+      viewToolbar.removeAttribute("checked");
+    else
+      viewToolbar.setAttribute("checked", "true");
+    // Setup the Places view.
+    this._panelMenuView = new PlacesPanelMenuView("place:folder=BOOKMARKS_MENU",
+                                                  "panelMenu_bookmarksMenu",
+                                                  "panelMenu_bookmarksMenu");
+  },
+
+  onPanelMenuViewHiding: function BUI_onViewHiding(aEvent) {
+    this._panelMenuView.uninit();
+    delete this._panelMenuView;
+  },
+
+  onPanelMenuViewCommand: function BUI_onPanelMenuViewCommand(aEvent, aView) {
+    let target = aEvent.originalTarget;
+    if (!target._placesNode)
+      return;
+    if (PlacesUtils.nodeIsContainer(target._placesNode))
+      PlacesCommandHook.showPlacesOrganizer([ "BookmarksMenu", target._placesNode.itemId ]);
+    else
+      PlacesUIUtils.openNodeWithEvent(target._placesNode, aEvent, aView);
+    PanelUI.hide();
+  },
+
   // nsINavBookmarkObserver
   onItemAdded: function BUI_onItemAdded(aItemId, aParentId, aIndex, aItemType,
                                         aURI) {
+    if (!this.button) {
+      return;
+    }
+
     if (aURI && aURI.equals(this._uri)) {
       // If a new bookmark has been added to the tracked uri, register it.
       if (this._itemIds.indexOf(aItemId) == -1) {
@@ -1160,6 +1242,10 @@ let BookmarkingUI = {
   },
 
   onItemRemoved: function BUI_onItemRemoved(aItemId) {
+    if (!this.button) {
+      return;
+    }
+
     let index = this._itemIds.indexOf(aItemId);
     // If one of the tracked bookmarks has been removed, unregister it.
     if (index != -1) {
@@ -1170,6 +1256,10 @@ let BookmarkingUI = {
 
   onItemChanged: function BUI_onItemChanged(aItemId, aProperty,
                                             aIsAnnotationProperty, aNewValue) {
+    if (!this.button) {
+      return;
+    }
+
     if (aProperty == "uri") {
       let index = this._itemIds.indexOf(aItemId);
       // If the changed bookmark was tracked, check if it is now pointing to
diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc
index 41af8c405d08ae55414cce910167a3ada60bc162..d969516d768ef2a069b4ff62e31640290ee956e6 100644
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -32,7 +32,6 @@
     <command id="cmd_printPreview" oncommand="PrintUtils.printPreview(PrintPreviewListener);"/>
     <command id="cmd_close" oncommand="BrowserCloseTabOrWindow()"/>
     <command id="cmd_closeWindow" oncommand="BrowserTryToCloseWindow()"/>
-    <command id="cmd_ToggleTabsOnTop" oncommand="TabsOnTop.toggle()"/>
     <command id="cmd_CustomizeToolbars" oncommand="BrowserCustomizeToolbar()"/>
     <command id="cmd_quitApplication" oncommand="goQuitApplication()"/>
 
@@ -109,13 +108,13 @@
       oncommand="OpenBrowserWindow({private: true});"/>
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
-    <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
     <command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/>
     <command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();" hidden="true"/>
     <command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/>
     <command id="Social:FocusChat" oncommand="SocialChatBar.focus();" hidden="true" disabled="true"/>
     <command id="Social:Toggle" oncommand="Social.toggle();" hidden="true"/>
     <command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/>
+    <command id="MenuPanel:Toggle" oncommand="PanelUI.toggle(event);"/>
   </commandset>
 
   <commandset id="placesCommands">
@@ -412,6 +411,13 @@
 #endif
     <key id="key_undoCloseWindow" command="History:UndoCloseWindow" key="&newNavigatorCmd.key;" modifiers="accel,shift"/>
 
+    <key id="key_menuButton" command="MenuPanel:Toggle"
+#ifdef XP_MACOSX
+         key="&toggleMenuPanelMac.key;" modifiers="accel,shift"/>
+#else
+         key="&toggleMenuPanel.key;" modifiers="accel"/>
+#endif
+
 #ifdef XP_GNOME
 #define NUM_SELECT_TAB_MODIFIER alt
 #else
@@ -428,8 +434,6 @@
 #expand    <key id="key_selectTab8" oncommand="gBrowser.selectTabAtIndex(7, event);" key="8" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
 #expand    <key id="key_selectLastTab" oncommand="gBrowser.selectTabAtIndex(-1, event);" key="9" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
 
-    <key id="key_toggleAddonBar" command="Browser:ToggleAddonBar" key="&toggleAddonBarCmd.key;" modifiers="accel"/>
-
   </keyset>
 
 # Used by baseMenuOverlay
diff --git a/browser/base/content/browser-social.js b/browser/base/content/browser-social.js
index b8239bab6237b4e2fd7209cb7f4b00469a3c1e16..54626a3571435a4e7af72792065d75e54536bc59 100644
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -795,9 +795,7 @@ SocialShare = {
     iframe.setAttribute("src", shareEndpoint);
 
     let navBar = document.getElementById("nav-bar");
-    let anchor = navBar.getAttribute("mode") == "text" ?
-                   document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-text") :
-                   document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-icon");
+    let anchor = document.getAnonymousElementByAttribute(this.shareButton, "class", "toolbarbutton-icon");
     this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
     Social.setErrorListener(iframe, this.setErrorMessage.bind(this));
   }
@@ -1130,9 +1128,7 @@ SocialToolbar = {
     });
 
     let navBar = document.getElementById("nav-bar");
-    let anchor = navBar.getAttribute("mode") == "text" ?
-                   document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-text") :
-                   document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-badge-container");
+    let anchor = document.getAnonymousElementByAttribute(aToolbarButton, "class", "toolbarbutton-badge-container");
     // Bug 849216 - open the popup in a setTimeout so we avoid the auto-rollup
     // handling from preventing it being opened in some cases.
     setTimeout(function() {
diff --git a/browser/base/content/browser-tabview.js b/browser/base/content/browser-tabview.js
index e5c2f060d90182a5dbd629e263777b22289a7ad9..6769a1df67eac12b9b3ff06884ace96b12726abd 100644
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -426,16 +426,13 @@ let TabView = {
 
     let toolbar = document.getElementById("TabsToolbar");
     let currentSet = toolbar.currentSet.split(",");
-
     let alltabsPos = currentSet.indexOf("alltabs-button");
     if (-1 == alltabsPos)
       return;
 
-    currentSet[alltabsPos] += "," + buttonId;
-    currentSet = currentSet.join(",");
-    toolbar.currentSet = currentSet;
-    toolbar.setAttribute("currentset", currentSet);
-    document.persist(toolbar.id, "currentset");
+    let allTabsBtn = document.getElementById("alltabs-button");
+    let nextItem = allTabsBtn.nextSibling;
+    toolbar.insertItem(buttonId, nextItem);
   },
 
   // ----------
diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css
index 616d0cdd8fdef3ff63c5c9b12e6752fe89a8dd15..f361d5889a43380cc5b808e5c55252e11ced4c2f 100644
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -21,6 +21,63 @@ searchbar {
   -moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser");
 }
 
+toolbar[customizable="true"] {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar");
+}
+
+%ifdef XP_MACOSX
+#toolbar-menubar {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-stub");
+}
+
+toolbar[customizable="true"]:not([nowindowdrag="true"]) {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
+}
+%endif
+
+#toolbar-menubar[autohide="true"] {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-autohide");
+}
+
+#addon-bar {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#addonbar-delegating");
+  visibility: visible;
+  margin: 0;
+  height: 0 !important;
+  overflow: hidden;
+  padding: 0;
+  border: 0 none;
+}
+
+#addonbar-closebutton {
+  visibility: visible;
+  height: 0 !important;
+}
+
+#status-bar {
+  height: 0 !important;
+  -moz-binding: none;
+  padding: 0;
+  margin: 0;
+}
+
+panelmultiview {
+  -moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelmultiview");
+}
+
+panelview {
+  -moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelview");
+  -moz-box-orient: vertical;
+}
+
+.panel-mainview {
+  transition: transform 150ms;
+}
+
+panelview:not([mainview]):not([current]) {
+  display: none;
+}
+
 tabbrowser {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser");
 }
@@ -47,21 +104,19 @@ tabbrowser {
 
 .tabbrowser-tab:not([pinned]) {
   -moz-box-flex: 100;
-  max-width: 250px;
+  max-width: 180px;
   min-width: 100px;
   width: 0;
   transition: min-width 200ms ease-out,
-              max-width 250ms ease-out,
-              opacity 50ms ease-out 20ms /* hide the tab for the first 20ms of the max-width transition */;
+              max-width 230ms ease-out;
 }
 
 .tabbrowser-tab:not([pinned]):not([fadein]) {
   max-width: 0.1px;
   min-width: 0.1px;
-  opacity: 0 !important;
+  visibility: hidden;
   transition: min-width 200ms ease-out,
-              max-width 250ms ease-out,
-              opacity 50ms ease-out 180ms /* hide the tab for the last 20ms of the max-width transition */;
+              max-width 230ms ease-out;
 }
 
 .tab-throbber:not([fadein]):not([pinned]),
@@ -94,20 +149,13 @@ toolbar[printpreview="true"] {
   -moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
 }
 
-#toolbar-menubar {
-  -moz-box-ordinal-group: 5;
-}
-
-#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
-  -moz-box-ordinal-group: 50;
-}
-
-#TabsToolbar {
-  -moz-box-ordinal-group: 100;
+toolbar[overflowable] > .customization-target {
+  overflow: hidden;
 }
 
-#TabsToolbar[tabsontop="true"] {
-  -moz-box-ordinal-group: 10;
+toolbar:not([overflowing]) > .overflow-button,
+toolbar[customizing] > .overflow-button {
+  display: none;
 }
 
 %ifdef CAN_DRAW_IN_TITLEBAR
@@ -125,43 +173,78 @@ toolbar[printpreview="true"] {
   pointer-events: none;
 }
 
-#main-window[tabsintitlebar] #appmenu-button-container,
 #main-window[tabsintitlebar] #titlebar-buttonbox {
   position: relative;
 }
+
+#titlebar-buttonbox {
+  -moz-appearance: -moz-window-button-box;
+}
+
+%ifdef XP_MACOSX
+#titlebar-fullscreen-button {
+  -moz-appearance: -moz-mac-fullscreen-button;
+}
 %endif
 
-.bookmarks-toolbar-customize,
-#wrapper-personal-bookmarks > #personal-bookmarks > #PlacesToolbar > hbox > #PlacesToolbarItems {
+%ifdef XP_WIN
+#main-window[sizemode="maximized"] #titlebar-buttonbox {
+  -moz-appearance: -moz-window-button-box-maximized;
+}
+%endif
+
+%endif
+
+/* Rules to help integrate SDK widgets */
+toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > .toolbarbutton-text {
+  display: -moz-box;
+}
+
+toolbarpaletteitem > toolbaritem[sdkstylewidget="true"] > iframe {
   display: none;
 }
 
-#wrapper-personal-bookmarks[place="toolbar"] > #personal-bookmarks > #PlacesToolbar > .bookmarks-toolbar-customize {
+#bookmarks-toolbar-placeholder,
+toolbarpaletteitem > #personal-bookmarks > #PlacesToolbar,
+#personal-bookmarks[cui-areatype="menu-panel"] > #PlacesToolbar,
+#personal-bookmarks[cui-areatype="toolbar"].overflowedItem > #PlacesToolbar {
+  display: none;
+}
+
+toolbarpaletteitem > #personal-bookmarks > #bookmarks-toolbar-placeholder,
+#personal-bookmarks[cui-areatype="menu-panel"] > #bookmarks-toolbar-placeholder,
+#personal-bookmarks[cui-areatype="toolbar"].overflowedItem > #bookmarks-toolbar-placeholder {
   display: -moz-box;
 }
 
-#main-window[disablechrome] #navigator-toolbox[tabsontop="true"] > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
-  visibility: collapse;
+#zoom-controls[cui-areatype="toolbar"]:not(.overflowedItem) > #zoom-reset-button > .toolbarbutton-text {
+  display: -moz-box;
 }
 
-#wrapper-urlbar-container #urlbar-container > #urlbar > toolbarbutton,
-#urlbar-container:not([combined]) > #urlbar > toolbarbutton,
-#urlbar-container[combined] + #reload-button + #stop-button,
-#urlbar-container[combined] + #reload-button,
-toolbar:not([mode="icons"]) > #urlbar-container > #urlbar > toolbarbutton,
-toolbar[mode="icons"] > #urlbar-container > #urlbar > #urlbar-reload-button:not([displaystop]) + #urlbar-stop-button,
-toolbar[mode="icons"] > #urlbar-container > #urlbar > #urlbar-reload-button[displaystop],
-toolbar[mode="icons"] > #reload-button:not([displaystop]) + #stop-button,
-toolbar[mode="icons"] > #reload-button[displaystop] {
+#wrapper-urlbar-container > #urlbar-container > #urlbar-wrapper > #urlbar > toolbarbutton,
+#urlbar-reload-button:not([displaystop]) + #urlbar-stop-button,
+#urlbar-reload-button[displaystop] {
   visibility: collapse;
 }
 
-#feed-button > .toolbarbutton-menu-dropmarker {
-  display: none;
+#PanelUI-feeds > .feed-toolbarbutton:-moz-locale-dir(rtl) {
+  direction: rtl;
 }
 
-#feed-menu > .feed-menuitem:-moz-locale-dir(rtl) {
-  direction: rtl;
+#panelMenu_bookmarksMenu {
+  overflow-x: hidden;
+  overflow-y: auto;
+}
+#panelMenu_bookmarksMenu > .bookmark-item {
+  max-width: none;
+}
+
+#urlbar-container {
+  min-width: 50ch;
+}
+
+#search-container {
+  min-width: 25ch;
 }
 
 #main-window:-moz-lwtheme {
@@ -180,27 +263,6 @@ toolbar[mode="icons"] > #reload-button[displaystop] {
   background-position: bottom left;
 }
 
-splitmenu {
-  -moz-binding: url("chrome://browser/content/urlbarBindings.xml#splitmenu");
-}
-
-.splitmenu-menuitem {
-  -moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem");
-  list-style-image: inherit;
-  -moz-image-region: inherit;
-}
-
-.splitmenu-menuitem[iconic="true"] {
-  -moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic");
-}
-
-.splitmenu-menu > .menu-text,
-:-moz-any(.splitmenu-menu, .splitmenu-menuitem) > .menu-accel-container,
-#appmenu-editmenu > .menu-text,
-#appmenu-editmenu > .menu-accel-container {
-  display: none;
-}
-
 .menuitem-tooltip {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#menuitem-tooltip");
 }
@@ -211,18 +273,6 @@ splitmenu {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#menuitem-iconic-tooltip");
 }
 
-%ifdef MENUBAR_CAN_AUTOHIDE
-%ifndef CAN_DRAW_IN_TITLEBAR
-#appmenu-toolbar-button > .toolbarbutton-text {
-  display: -moz-box;
-}
-%endif
-
-#appmenu_offlineModeRecovery:not([checked=true]) {
-  display: none;
-}
-%endif
-
 /* Hide menu elements intended for keyboard access support */
 #main-menubar[openedwithkey=false] .show-only-for-keyboard {
   display: none;
@@ -257,7 +307,7 @@ panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .a
   display: none;
 }
 
-#wrapper-urlbar-container > #urlbar-container > #urlbar {
+#wrapper-urlbar-container > #urlbar-container > #urlbar-wrapper > #urlbar {
   -moz-user-input: disabled;
   cursor: grab;
 }
@@ -270,9 +320,7 @@ panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .a
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#urlbar-rich-result-popup");
 }
 
-#urlbar-container[combined] > #urlbar > #urlbar-icons > #go-button,
-#urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon:not(#go-button),
-#urlbar[pageproxystate="valid"] > #urlbar-icons > #go-button,
+#urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon,
 #urlbar[pageproxystate="invalid"][focused="true"] > #urlbar-go-button ~ toolbarbutton,
 #urlbar[pageproxystate="valid"] > #urlbar-go-button,
 #urlbar:not([focused="true"]) > #urlbar-go-button {
@@ -316,18 +364,20 @@ toolbarbutton.bookmark-item {
   max-width: 13em;
 }
 
-%ifdef MENUBAR_CAN_AUTOHIDE
-#toolbar-menubar:not([autohide="true"]) ~ toolbar > #bookmarks-menu-button,
-#toolbar-menubar:not([autohide="true"]) > #bookmarks-menu-button {
-  display: none;
-}
-%endif
-
 #editBMPanel_tagsSelector {
   /* override default listbox width from xul.css */
   width: auto;
 }
 
+/* The star doesn't make sense as text */
+toolbar[mode="text"] #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+  display: -moz-box !important;
+}
+toolbar[mode="text"] #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-text,
+toolbar[mode="full"] #bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-text {
+  display: none;
+}
+
 menupopup[emptyplacesresult="true"] > .hide-if-empty-places-result {
   display: none;
 }
@@ -352,7 +402,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
 }
 
 #navigator-toolbox ,
-#status-bar ,
 #mainPopupSet {
   min-width: 1px;
 }
@@ -451,14 +500,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
   min-width: 1px;
 }
 
-#nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-icon {
-  display: -moz-box;
-}
-
-#nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-text {
-  display: none;
-}
-
 /* ::::: Ctrl-Tab Panel ::::: */
 
 .ctrlTab-preview > html|img,
@@ -523,17 +564,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#plugin-popupnotification-center-item");
 }
 
-/* override hidden="true" for the status bar compatibility shim
-   in case it was persisted for the real status bar */
-#status-bar {
-  display: -moz-box;
-}
-
-/* Remove the resizer from the statusbar compatibility shim */
-#status-bar[hideresizer] > .statusbar-resizerpanel {
-  display: none;
-}
-
 browser[tabmodalPromptShowing] {
   -moz-user-focus: none !important;
 }
@@ -776,6 +806,17 @@ chatbox:-moz-full-screen-ancestor > .chat-titlebar {
   -moz-margin-start: 2em;
 }
 
+/* Give this menupopup an arrow panel styling */
+#BMB_bookmarksPopup {
+  -moz-appearance: none;
+  -moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-arrow");
+  background: transparent;
+  border: none;
+  transition: opacity 300ms;
+  /* The popup inherits -moz-image-region from the button, must reset it */
+  -moz-image-region: auto;
+}
+
 /* UI Tour */
 
 @keyframes uitour-wobble {
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index e1a10b7158185929e34b764a8b1757ce27f52d4a..fac713990e3916a5d91f651a74f1db25a2faf55c 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -85,6 +85,12 @@ this.__defineSetter__("PluralForm", function (val) {
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
   "resource://gre/modules/TelemetryStopwatch.jsm");
 
+XPCOMUtils.defineLazyGetter(this, "gCustomizeMode", function() {
+  let scope = {};
+  Cu.import("resource:///modules/CustomizeMode.jsm", scope);
+  return new scope.CustomizeMode(window);
+});
+
 #ifdef MOZ_SERVICES_SYNC
 XPCOMUtils.defineLazyModuleGetter(this, "Weave",
   "resource://services-sync/main.js");
@@ -153,6 +159,7 @@ let gInitialPages = [
 ];
 
 #include browser-addons.js
+#include browser-customization.js
 #include browser-feeds.js
 #include browser-fullScreen.js
 #include browser-fullZoom.js
@@ -315,29 +322,22 @@ function SetClickAndHoldHandlers() {
     aElm.addEventListener("click", clickHandler, true);
   }
 
-  // Bug 414797: Clone unified-back-forward-button's context menu into both the
-  // back and the forward buttons.
-  var unifiedButton = document.getElementById("unified-back-forward-button");
-  if (unifiedButton && !unifiedButton._clickHandlersAttached) {
-    unifiedButton._clickHandlersAttached = true;
-
-    let popup = document.getElementById("backForwardMenu").cloneNode(true);
-    popup.removeAttribute("id");
-    // Prevent the context attribute on unified-back-forward-button from being
-    // inherited.
-    popup.setAttribute("context", "");
-
-    let backButton = document.getElementById("back-button");
-    backButton.setAttribute("type", "menu");
-    backButton.appendChild(popup);
-    _addClickAndHoldListenersOnElement(backButton);
-
-    let forwardButton = document.getElementById("forward-button");
-    popup = popup.cloneNode(true);
-    forwardButton.setAttribute("type", "menu");
-    forwardButton.appendChild(popup);
-    _addClickAndHoldListenersOnElement(forwardButton);
-  }
+  // Bug 414797: Clone the back/forward buttons' context menu into both buttons.
+  let popup = document.getElementById("backForwardMenu").cloneNode(true);
+  popup.removeAttribute("id");
+  // Prevent the back/forward buttons' context attributes from being inherited.
+  popup.setAttribute("context", "");
+
+  let backButton = document.getElementById("back-button");
+  backButton.setAttribute("type", "menu");
+  backButton.appendChild(popup);
+  _addClickAndHoldListenersOnElement(backButton);
+
+  let forwardButton = document.getElementById("forward-button");
+  popup = popup.cloneNode(true);
+  forwardButton.setAttribute("type", "menu");
+  forwardButton.appendChild(popup);
+  _addClickAndHoldListenersOnElement(forwardButton);
 }
 
 const gSessionHistoryObserver = {
@@ -737,6 +737,8 @@ const gFormSubmitObserver = {
 };
 
 var gBrowserInit = {
+  delayedStartupFinished: false,
+
   onLoad: function() {
     gMultiProcessBrowser = gPrefService.getBoolPref("browser.tabs.remote");
 
@@ -889,9 +891,6 @@ var gBrowserInit = {
       document.documentElement.setAttribute("height", defaultHeight);
     }
 
-    if (!gShowPageResizers)
-      document.getElementById("status-bar").setAttribute("hideresizer", "true");
-
     if (!window.toolbar.visible) {
       // adjust browser UI for popups
       if (gURLBar) {
@@ -901,16 +900,10 @@ var gBrowserInit = {
       goSetCommandEnabled("cmd_newNavigatorTab", false);
     }
 
-#ifdef MENUBAR_CAN_AUTOHIDE
-    updateAppButtonDisplay();
-#endif
-
     // Misc. inits.
     CombinedStopReload.init();
-    TabsOnTop.init();
     gPrivateBrowsingUI.init();
     TabsInTitlebar.init();
-    retrieveToolbarIconsizesFromTheme();
 
     // Wait until chrome is painted before executing code not critical to making the window visible
     this._boundDelayedStartup = this._delayedStartup.bind(this, mustLoadSidebar);
@@ -1012,7 +1005,13 @@ var gBrowserInit = {
     IndexedDBPromptHelper.init();
     gFormSubmitObserver.init();
     SocialUI.init();
-    AddonManager.addAddonListener(AddonsMgrListener);
+
+    // Initialize the full zoom setting.
+    // We do this before the session restore service gets initialized so we can
+    // apply full zoom settings to tabs restored by the session restore service.
+    FullZoom.init();
+    PanelUI.init();
+    LightweightThemeListener.init();
     WebrtcIndicator.init();
 
     // Ensure login manager is up and running.
@@ -1063,11 +1062,6 @@ var gBrowserInit = {
     if (!getBoolPref("ui.click_hold_context_menus", false))
       SetClickAndHoldHandlers();
 
-    // Initialize the full zoom setting.
-    // We do this before the session restore service gets initialized so we can
-    // apply full zoom settings to tabs restored by the session restore service.
-    FullZoom.init();
-
     // Bug 666804 - NetworkPrioritizer support for e10s
     if (!gMultiProcessBrowser) {
       let NP = {};
@@ -1138,44 +1132,15 @@ var gBrowserInit = {
 
     gBrowserThumbnails.init();
 
-    setUrlAndSearchBarWidthForConditionalForwardButton();
-    window.addEventListener("resize", function resizeHandler(event) {
-      if (event.target == window)
-        setUrlAndSearchBarWidthForConditionalForwardButton();
-    });
-
-#ifdef MENUBAR_CAN_AUTOHIDE
-    // If the user (or the locale) hasn't enabled the top-level "Character
-    // Encoding" menu via the "browser.menu.showCharacterEncoding" preference,
-    // hide it.
-    if ("true" != gPrefService.getComplexValue("browser.menu.showCharacterEncoding",
-                                               Ci.nsIPrefLocalizedString).data)
-      document.getElementById("appmenu_charsetMenu").hidden = true;
-#endif
-
     // Add Devtools menuitems and listeners
     gDevToolsBrowser.registerBrowserWindow(window);
 
-    let appMenuButton = document.getElementById("appmenu-button");
-    let appMenuPopup = document.getElementById("appmenu-popup");
-    if (appMenuButton && appMenuPopup) {
-      let appMenuOpening = null;
-      appMenuButton.addEventListener("mousedown", function(event) {
-        if (event.button == 0)
-          appMenuOpening = new Date();
-      }, false);
-      appMenuPopup.addEventListener("popupshown", function(event) {
-        if (event.target != appMenuPopup || !appMenuOpening)
-          return;
-        let duration = new Date() - appMenuOpening;
-        appMenuOpening = null;
-        Services.telemetry.getHistogramById("FX_APP_MENU_OPEN_MS").add(duration);
-      }, false);
-    }
-
     window.addEventListener("mousemove", MousePosTracker, false);
     window.addEventListener("dragover", MousePosTracker, false);
 
+    gNavToolbox.addEventListener("customizationstarting", CustomizationHandler);
+    gNavToolbox.addEventListener("customizationending", CustomizationHandler);
+
     // End startup crash tracking after a delay to catch crashes while restoring
     // tabs and to postpone saving the pref to disk.
     try {
@@ -1209,6 +1174,7 @@ var gBrowserInit = {
 
       setTimeout(function () { BrowserChromeTest.markAsReady(); }, 0);
     });
+    this.delayedStartupFinished = true;
 
     Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "");
     TelemetryTimestamps.add("delayedStartupFinished");
@@ -1274,8 +1240,6 @@ var gBrowserInit = {
 
     BookmarkingUI.uninit();
 
-    TabsOnTop.uninit();
-
     TabsInTitlebar.uninit();
 
     var enumerator = Services.wm.getEnumerator(null);
@@ -1326,8 +1290,9 @@ var gBrowserInit = {
       BrowserOffline.uninit();
       OfflineApps.uninit();
       IndexedDBPromptHelper.uninit();
-      AddonManager.removeAddonListener(AddonsMgrListener);
       SocialUI.uninit();
+      LightweightThemeListener.uninit();
+      PanelUI.uninit();
     }
 
     // Final window teardown, do this last.
@@ -1352,7 +1317,7 @@ var gBrowserInit = {
                          'viewToolbarsMenu', 'viewSidebarMenuMenu', 'Browser:Reload',
                          'viewFullZoomMenu', 'pageStyleMenu', 'charsetMenu', 'View:PageSource', 'View:FullScreen',
                          'viewHistorySidebar', 'Browser:AddBookmarkAs', 'Browser:BookmarkAllTabs',
-                         'View:PageInfo', 'Browser:ToggleTabView', 'Browser:ToggleAddonBar'];
+                         'View:PageInfo', 'Browser:ToggleTabView'];
     var element;
 
     for (let disabledItem of disabledItems) {
@@ -2151,13 +2116,17 @@ function UpdateUrlbarSearchSplitterState()
   var splitter = document.getElementById("urlbar-search-splitter");
   var urlbar = document.getElementById("urlbar-container");
   var searchbar = document.getElementById("search-container");
-  var stop = document.getElementById("stop-button");
+
+  // If the splitter is already in the right place, we don't need to do anything:
+  if (splitter &&
+      ((splitter.nextSibling == searchbar && splitter.previousSibling == urlbar) ||
+       (splitter.nextSibling == urlbar && splitter.previousSibling == searchbar))) {
+    return;
+  }
 
   var ibefore = null;
   if (urlbar && searchbar) {
-    if (urlbar.nextSibling == searchbar ||
-        urlbar.getAttribute("combined") &&
-        stop && stop.nextSibling == searchbar)
+    if (urlbar.nextSibling == searchbar)
       ibefore = searchbar;
     else if (searchbar.nextSibling == urlbar)
       ibefore = urlbar;
@@ -2170,6 +2139,7 @@ function UpdateUrlbarSearchSplitterState()
       splitter.setAttribute("resizebefore", "flex");
       splitter.setAttribute("resizeafter", "flex");
       splitter.setAttribute("skipintoolbarset", "true");
+      splitter.setAttribute("overflows", "false");
       splitter.className = "chromeclass-toolbar-additional";
     }
     urlbar.parentNode.insertBefore(splitter, ibefore);
@@ -2177,24 +2147,6 @@ function UpdateUrlbarSearchSplitterState()
     splitter.parentNode.removeChild(splitter);
 }
 
-function setUrlAndSearchBarWidthForConditionalForwardButton() {
-  // Workaround for bug 694084: Showing/hiding the conditional forward button resizes
-  // the search bar when the url/search bar splitter hasn't been used.
-  var urlbarContainer = document.getElementById("urlbar-container");
-  var searchbarContainer = document.getElementById("search-container");
-  if (!urlbarContainer ||
-      !searchbarContainer ||
-      urlbarContainer.hasAttribute("width") ||
-      searchbarContainer.hasAttribute("width") ||
-      urlbarContainer.parentNode != searchbarContainer.parentNode)
-    return;
-  urlbarContainer.style.width = searchbarContainer.style.width = "";
-  var urlbarWidth = urlbarContainer.clientWidth;
-  var searchbarWidth = searchbarContainer.clientWidth;
-  urlbarContainer.style.width = urlbarWidth + "px";
-  searchbarContainer.style.width = searchbarWidth + "px";
-}
-
 function UpdatePageProxyState()
 {
   if (gURLBar && gURLBar.value != gLastValidURLStr)
@@ -2594,9 +2546,7 @@ var PrintPreviewListener = {
     if (this._chromeState.sidebarOpen)
       toggleSidebar(this._sidebarCommand);
 
-#ifdef MENUBAR_CAN_AUTOHIDE
-    updateAppButtonDisplay();
-#endif
+    TabsInTitlebar.allowedBy("print-preview", !gInPrintPreviewMode);
   },
   _hideChrome: function () {
     this._chromeState = {};
@@ -2610,9 +2560,6 @@ var PrintPreviewListener = {
     notificationBox.notificationsHidden = true;
 
     document.getElementById("sidebar").setAttribute("src", "about:blank");
-    var addonBar = document.getElementById("addon-bar");
-    this._chromeState.addonBarOpen = !addonBar.collapsed;
-    addonBar.collapsed = true;
     gBrowser.updateWindowResizers();
 
     this._chromeState.findOpen = gFindBarInitialized && !gFindBar.hidden;
@@ -2634,11 +2581,6 @@ var PrintPreviewListener = {
     if (this._chromeState.notificationsOpen)
       gBrowser.getNotificationBox().notificationsHidden = false;
 
-    if (this._chromeState.addonBarOpen) {
-      document.getElementById("addon-bar").collapsed = false;
-      gBrowser.updateWindowResizers();
-    }
-
     if (this._chromeState.findOpen)
       gFindBar.open();
 
@@ -2715,35 +2657,6 @@ function openHomeDialog(aURL)
   }
 }
 
-var bookmarksButtonObserver = {
-  onDrop: function (aEvent)
-  {
-    let name = { };
-    let url = browserDragAndDrop.drop(aEvent, name);
-    try {
-      PlacesUIUtils.showBookmarkDialog({ action: "add"
-                                       , type: "bookmark"
-                                       , uri: makeURI(url)
-                                       , title: name
-                                       , hiddenRows: [ "description"
-                                                     , "location"
-                                                     , "loadInSidebar"
-                                                     , "keyword" ]
-                                       }, window);
-    } catch(ex) { }
-  },
-
-  onDragOver: function (aEvent)
-  {
-    browserDragAndDrop.dragOver(aEvent);
-    aEvent.dropEffect = "link";
-  },
-
-  onDragExit: function (aEvent)
-  {
-  }
-}
-
 var newTabButtonObserver = {
   onDragOver: function (aEvent)
   {
@@ -3286,153 +3199,18 @@ function OpenBrowserWindow(options)
   return win;
 }
 
-var gCustomizeSheet = false;
+//XXXunf Are these still useful to keep around?
 function BrowserCustomizeToolbar() {
-  // Disable the toolbar context menu items
-  var menubar = document.getElementById("main-menubar");
-  for (let childNode of menubar.childNodes)
-    childNode.setAttribute("disabled", true);
-
-  var cmd = document.getElementById("cmd_CustomizeToolbars");
-  cmd.setAttribute("disabled", "true");
-
-  var splitter = document.getElementById("urlbar-search-splitter");
-  if (splitter)
-    splitter.parentNode.removeChild(splitter);
-
-  CombinedStopReload.uninit();
-
-  PlacesToolbarHelper.customizeStart();
-  BookmarkingUI.customizeStart();
-  DownloadsButton.customizeStart();
-
-  TabsInTitlebar.allowedBy("customizing-toolbars", false);
-
-  var customizeURL = "chrome://global/content/customizeToolbar.xul";
-  gCustomizeSheet = getBoolPref("toolbar.customization.usesheet", false);
-
-  if (gCustomizeSheet) {
-    let sheetFrame = document.createElement("iframe");
-    let panel = document.getElementById("customizeToolbarSheetPopup");
-    sheetFrame.id = "customizeToolbarSheetIFrame";
-    sheetFrame.toolbox = gNavToolbox;
-    sheetFrame.panel = panel;
-    sheetFrame.setAttribute("style", panel.getAttribute("sheetstyle"));
-    panel.appendChild(sheetFrame);
-
-    // Open the panel, but make it invisible until the iframe has loaded so
-    // that the user doesn't see a white flash.
-    panel.style.visibility = "hidden";
-    gNavToolbox.addEventListener("beforecustomization", function onBeforeCustomization() {
-      gNavToolbox.removeEventListener("beforecustomization", onBeforeCustomization, false);
-      panel.style.removeProperty("visibility");
-    }, false);
-
-    sheetFrame.setAttribute("src", customizeURL);
-
-    panel.openPopup(gNavToolbox, "after_start", 0, 0);
-  } else {
-    window.openDialog(customizeURL,
-                      "CustomizeToolbar",
-                      "chrome,titlebar,toolbar,location,resizable,dependent",
-                      gNavToolbox);
-  }
+  gCustomizeMode.enter();
 }
 
 function BrowserToolboxCustomizeDone(aToolboxChanged) {
-  if (gCustomizeSheet) {
-    document.getElementById("customizeToolbarSheetPopup").hidePopup();
-    let iframe = document.getElementById("customizeToolbarSheetIFrame");
-    iframe.parentNode.removeChild(iframe);
-  }
-
-  // Update global UI elements that may have been added or removed
-  if (aToolboxChanged) {
-    gURLBar = document.getElementById("urlbar");
-
-    gProxyFavIcon = document.getElementById("page-proxy-favicon");
-    gHomeButton.updateTooltip();
-    gIdentityHandler._cacheElements();
-    window.XULBrowserWindow.init();
-
-#ifndef XP_MACOSX
-    updateEditUIVisibility();
-#endif
-
-    // Hacky: update the PopupNotifications' object's reference to the iconBox,
-    // if it already exists, since it may have changed if the URL bar was
-    // added/removed.
-    if (!window.__lookupGetter__("PopupNotifications"))
-      PopupNotifications.iconBox = document.getElementById("notification-popup-box");
-  }
-
-  PlacesToolbarHelper.customizeDone();
-  BookmarkingUI.customizeDone();
-  DownloadsButton.customizeDone();
-
-  // The url bar splitter state is dependent on whether stop/reload
-  // and the location bar are combined, so we need this ordering
-  CombinedStopReload.init();
-  UpdateUrlbarSearchSplitterState();
-  setUrlAndSearchBarWidthForConditionalForwardButton();
-
-  // Update the urlbar
-  if (gURLBar) {
-    URLBarSetURI();
-    XULBrowserWindow.asyncUpdateUI();
-    BookmarkingUI.updateStarState();
-    SocialUI.updateState();
-  }
-
-  TabsInTitlebar.allowedBy("customizing-toolbars", true);
-
-  // Re-enable parts of the UI we disabled during the dialog
-  var menubar = document.getElementById("main-menubar");
-  for (let childNode of menubar.childNodes)
-    childNode.setAttribute("disabled", false);
-  var cmd = document.getElementById("cmd_CustomizeToolbars");
-  cmd.removeAttribute("disabled");
-
-  // make sure to re-enable click-and-hold
-  if (!getBoolPref("ui.click_hold_context_menus", false))
-    SetClickAndHoldHandlers();
-
-  gBrowser.selectedBrowser.focus();
+  gCustomizeMode.exit(aToolboxChanged);
 }
 
 function BrowserToolboxCustomizeChange(aType) {
-  switch (aType) {
-    case "iconsize":
-    case "mode":
-      retrieveToolbarIconsizesFromTheme();
-      break;
-    default:
-      gHomeButton.updatePersonalToolbarStyle();
-      BookmarkingUI.customizeChange();
-  }
-}
-
-/**
- * Allows themes to override the "iconsize" attribute on toolbars.
- */
-function retrieveToolbarIconsizesFromTheme() {
-  function retrieveToolbarIconsize(aToolbar) {
-    if (aToolbar.localName != "toolbar")
-      return;
-
-    // The theme indicates that it wants to override the "iconsize" attribute
-    // by specifying a special value for the "counter-reset" property on the
-    // toolbar. A custom property cannot be used because getComputedStyle can
-    // only return the values of standard CSS properties.
-    let counterReset = getComputedStyle(aToolbar).counterReset;
-    if (counterReset == "smallicons 0")
-      aToolbar.setAttribute("iconsize", "small");
-    else if (counterReset == "largeicons 0")
-      aToolbar.setAttribute("iconsize", "large");
-  }
-
-  Array.forEach(gNavToolbox.childNodes, retrieveToolbarIconsize);
-  gNavToolbox.externalToolbars.forEach(retrieveToolbarIconsize);
+  gHomeButton.updatePersonalToolbarStyle();
+  BookmarksMenuButton.customizeChange();
 }
 
 /**
@@ -3461,9 +3239,6 @@ function updateEditUIVisibility()
   let editMenuPopupState = document.getElementById("menu_EditPopup").state;
   let contextMenuPopupState = document.getElementById("contentAreaContextMenu").state;
   let placesContextMenuPopupState = document.getElementById("placesContext").state;
-#ifdef MENUBAR_CAN_AUTOHIDE
-  let appMenuPopupState = document.getElementById("appmenu-popup").state;
-#endif
 
   // The UI is visible if the Edit menu is opening or open, if the context menu
   // is open, or if the toolbar has been customized to include the Cut, Copy,
@@ -3474,13 +3249,7 @@ function updateEditUIVisibility()
                    contextMenuPopupState == "open" ||
                    placesContextMenuPopupState == "showing" ||
                    placesContextMenuPopupState == "open" ||
-#ifdef MENUBAR_CAN_AUTOHIDE
-                   appMenuPopupState == "showing" ||
-                   appMenuPopupState == "open" ||
-#endif
-                   document.getElementById("cut-button") ||
-                   document.getElementById("copy-button") ||
-                   document.getElementById("paste-button") ? true : false;
+                   document.getElementById("edit-controls") ? true : false;
 
   // If UI is visible, update the edit commands' enabled state to reflect
   // whether or not they are actually enabled for the current focus/selection.
@@ -3510,9 +3279,6 @@ function updateEditUIVisibility()
 function updateCharacterEncodingMenuState()
 {
   let charsetMenu = document.getElementById("charsetMenu");
-  let appCharsetMenu = document.getElementById("appmenu_charsetMenu");
-  let appDevCharsetMenu =
-    document.getElementById("appmenu_developer_charsetMenu");
   // gBrowser is null on Mac when the menubar shows in the context of
   // non-browser windows. The above elements may be null depending on
   // what parts of the menubar are present. E.g. no app menu on Mac.
@@ -3522,22 +3288,10 @@ function updateCharacterEncodingMenuState()
     if (charsetMenu) {
       charsetMenu.removeAttribute("disabled");
     }
-    if (appCharsetMenu) {
-      appCharsetMenu.removeAttribute("disabled");
-    }
-    if (appDevCharsetMenu) {
-      appDevCharsetMenu.removeAttribute("disabled");
-    }
   } else {
     if (charsetMenu) {
       charsetMenu.setAttribute("disabled", "true");
     }
-    if (appCharsetMenu) {
-      appCharsetMenu.setAttribute("disabled", "true");
-    }
-    if (appDevCharsetMenu) {
-      appDevCharsetMenu.setAttribute("disabled", "true");
-    }
   }
 }
 
@@ -3569,8 +3323,8 @@ var XULBrowserWindow = {
   startTime: 0,
   statusText: "",
   isBusy: false,
-  inContentWhitelist: ["about:addons", "about:downloads", "about:permissions",
-                       "about:sync-progress", "about:preferences"],
+  // Left here for add-on compatibility, see bug 752434
+  inContentWhitelist: [],
 
   QueryInterface: function (aIID) {
     if (aIID.equals(Ci.nsIWebProgressListener) ||
@@ -3599,8 +3353,6 @@ var XULBrowserWindow = {
   },
 
   init: function () {
-    this.throbberElement = document.getElementById("navigator-throbber");
-
     // Initialize the security button's state and tooltip text.
     var securityUI = gBrowser.securityUI;
     this.onSecurityChange(null, null, securityUI.state);
@@ -3724,10 +3476,6 @@ var XULBrowserWindow = {
       if (!(aStateFlags & nsIWebProgressListener.STATE_RESTORING)) {
         this._busyUI = true;
 
-        // Turn the throbber on.
-        if (this.throbberElement)
-          this.throbberElement.setAttribute("busy", "true");
-
         // XXX: This needs to be based on window activity...
         this.stopCommand.removeAttribute("disabled");
         CombinedStopReload.switchToStop();
@@ -3772,10 +3520,6 @@ var XULBrowserWindow = {
       if (this._busyUI) {
         this._busyUI = false;
 
-        // Turn the throbber off.
-        if (this.throbberElement)
-          this.throbberElement.removeAttribute("busy");
-
         this.stopCommand.setAttribute("disabled", "true");
         CombinedStopReload.switchToReload(aRequest instanceof Ci.nsIRequest);
       }
@@ -3842,16 +3586,6 @@ var XULBrowserWindow = {
         SocialUI.updateState();
       }
 
-      // Show or hide browser chrome based on the whitelist
-      if (this.hideChromeForLocation(location)) {
-        document.documentElement.setAttribute("disablechrome", "true");
-      } else {
-        if (SessionStore.getTabValue(gBrowser.selectedTab, "appOrigin"))
-          document.documentElement.setAttribute("disablechrome", "true");
-        else
-          document.documentElement.removeAttribute("disablechrome");
-      }
-
       // Utility functions for disabling find
       var shouldDisableFind = function shouldDisableFind(aDocument) {
         let docElt = aDocument.documentElement;
@@ -3892,6 +3626,17 @@ var XULBrowserWindow = {
         }
       } else
         disableFindCommands(false);
+
+      // Try not to instantiate gCustomizeMode as much as possible,
+      // so don't use CustomizeMode.jsm to check for URI or customizing.
+      let customizingURI = "about:customizing";
+      if (location == customizingURI &&
+          !CustomizationHandler.isCustomizing()) {
+        gCustomizeMode.enter();
+      } else if (location != customizingURI &&
+                 CustomizationHandler.isCustomizing()) {
+        gCustomizeMode.exit();
+      }
     }
     UpdateBackForwardCommands(gBrowser.webNavigation);
 
@@ -3909,12 +3654,8 @@ var XULBrowserWindow = {
     FeedHandler.updateFeeds();
   },
 
-  hideChromeForLocation: function(aLocation) {
-    aLocation = aLocation.toLowerCase();
-    return this.inContentWhitelist.some(function(aSpec) {
-      return aSpec == aLocation;
-    });
-  },
+  // Left here for add-on compatibility, see bug 752434
+  hideChromeForLocation: function() {},
 
   onStatusChange: function (aWebProgress, aRequest, aStatus, aMessage) {
     this.status = aMessage;
@@ -4052,21 +3793,8 @@ var CombinedStopReload = {
     if (this._initialized)
       return;
 
-    var urlbar = document.getElementById("urlbar-container");
-    var reload = document.getElementById("reload-button");
-    var stop = document.getElementById("stop-button");
-
-    if (urlbar) {
-      if (urlbar.parentNode.getAttribute("mode") != "icons" ||
-          !reload || urlbar.nextSibling != reload ||
-          !stop || reload.nextSibling != stop)
-        urlbar.removeAttribute("combined");
-      else {
-        urlbar.setAttribute("combined", "true");
-        reload = document.getElementById("urlbar-reload-button");
-        stop = document.getElementById("urlbar-stop-button");
-      }
-    }
+    let reload = document.getElementById("urlbar-reload-button");
+    let stop = document.getElementById("urlbar-stop-button");
     if (!stop || !reload || reload.nextSibling != stop)
       return;
 
@@ -4398,7 +4126,6 @@ function onViewToolbarsPopupShowing(aEvent, aInsertPoint) {
   var firstMenuItem = aInsertPoint || popup.firstChild;
 
   let toolbarNodes = Array.slice(gNavToolbox.childNodes);
-  toolbarNodes.push(document.getElementById("addon-bar"));
 
   for (let toolbar of toolbarNodes) {
     let toolbarName = toolbar.getAttribute("toolbarname");
@@ -4411,8 +4138,7 @@ function onViewToolbarsPopupShowing(aEvent, aInsertPoint) {
       menuItem.setAttribute("type", "checkbox");
       menuItem.setAttribute("label", toolbarName);
       menuItem.setAttribute("checked", toolbar.getAttribute(hidingAttribute) != "true");
-      if (popup.id != "appmenu_customizeMenu")
-        menuItem.setAttribute("accesskey", toolbar.getAttribute("accesskey"));
+      menuItem.setAttribute("accesskey", toolbar.getAttribute("accesskey"));
       if (popup.id != "toolbar-context-menu")
         menuItem.setAttribute("key", toolbar.getAttribute("key"));
 
@@ -4436,65 +4162,18 @@ function setToolbarVisibility(toolbar, isVisible) {
 
   toolbar.setAttribute(hidingAttribute, !isVisible);
   document.persist(toolbar.id, hidingAttribute);
+  let eventParams = {
+    detail: {
+      visible: isVisible
+    },
+    bubbles: true
+  };
+  let event = new CustomEvent("toolbarvisibilitychange", eventParams);
+  toolbar.dispatchEvent(event);
 
   PlacesToolbarHelper.init();
   BookmarkingUI.onToolbarVisibilityChange();
   gBrowser.updateWindowResizers();
-
-#ifdef MENUBAR_CAN_AUTOHIDE
-  updateAppButtonDisplay();
-#endif
-}
-
-var TabsOnTop = {
-  init: function TabsOnTop_init() {
-    Services.prefs.addObserver(this._prefName, this, false);
-
-    // Only show the toggle UI if the user disabled tabs on top.
-    if (Services.prefs.getBoolPref(this._prefName)) {
-      for (let item of document.querySelectorAll("menuitem[command=cmd_ToggleTabsOnTop]"))
-        item.parentNode.removeChild(item);
-    }
-  },
-
-  uninit: function TabsOnTop_uninit() {
-    Services.prefs.removeObserver(this._prefName, this);
-  },
-
-  toggle: function () {
-    this.enabled = !Services.prefs.getBoolPref(this._prefName);
-  },
-
-  syncUI: function () {
-    let userEnabled = Services.prefs.getBoolPref(this._prefName);
-    let enabled = userEnabled && gBrowser.tabContainer.visible;
-
-    document.getElementById("cmd_ToggleTabsOnTop")
-            .setAttribute("checked", userEnabled);
-
-    document.documentElement.setAttribute("tabsontop", enabled);
-    document.getElementById("navigator-toolbox").setAttribute("tabsontop", enabled);
-    document.getElementById("TabsToolbar").setAttribute("tabsontop", enabled);
-    document.getElementById("nav-bar").setAttribute("tabsontop", enabled);
-    gBrowser.tabContainer.setAttribute("tabsontop", enabled);
-    TabsInTitlebar.allowedBy("tabs-on-top", enabled);
-  },
-
-  get enabled () {
-    return gNavToolbox.getAttribute("tabsontop") == "true";
-  },
-
-  set enabled (val) {
-    Services.prefs.setBoolPref(this._prefName, !!val);
-    return val;
-  },
-
-  observe: function (subject, topic, data) {
-    if (topic == "nsPref:changed")
-      this.syncUI();
-  },
-
-  _prefName: "browser.tabs.onTop"
 }
 
 var TabsInTitlebar = {
@@ -4503,9 +4182,31 @@ var TabsInTitlebar = {
     this._readPref();
     Services.prefs.addObserver(this._prefName, this, false);
 
-    // Don't trust the initial value of the sizemode attribute; wait for
-    // the resize event (handled in tabbrowser.xml).
-    this.allowedBy("sizemode", false);
+    // We need to update the appearance of the titlebar when the menu changes
+    // from the active to the inactive state. We can't, however, rely on
+    // DOMMenuBarInactive, because the menu fires this event and then removes
+    // the inactive attribute after an event-loop spin.
+    //
+    // Because updating the appearance involves sampling the heights and margins
+    // of various elements, it's important that the layout be more or less
+    // settled before updating the titlebar. So instead of listening to
+    // DOMMenuBarActive and DOMMenuBarInactive, we use a MutationObserver to
+    // watch the "invalid" attribute directly.
+    let menu = document.getElementById("toolbar-menubar");
+    this._menuObserver = new MutationObserver(this._onMenuMutate);
+    this._menuObserver.observe(menu, {attributes: true});
+
+    gNavToolbox.addEventListener("customization-transitionend", this);
+
+    this.onAreaReset = function(aArea) {
+      if (aArea == CustomizableUI.AREA_TABSTRIP || aArea == CustomizableUI.AREA_MENUBAR)
+        this._update(true);
+    };
+    this.onWidgetAdded = this.onWidgetRemoved = function(aWidgetId, aArea) {
+      if (aArea == CustomizableUI.AREA_TABSTRIP || aArea == CustomizableUI.AREA_MENUBAR)
+        this._update(true);
+    };
+    CustomizableUI.addListener(this);
 
     this._initialized = true;
 #endif
@@ -4516,17 +4217,23 @@ var TabsInTitlebar = {
     if (allow) {
       if (condition in this._disallowed) {
         delete this._disallowed[condition];
-        this._update();
+        this._update(true);
       }
     } else {
       if (!(condition in this._disallowed)) {
         this._disallowed[condition] = null;
-        this._update();
+        this._update(true);
       }
     }
 #endif
   },
 
+  updateAppearance: function updateAppearance(aForce) {
+#ifdef CAN_DRAW_IN_TITLEBAR
+    this._update(aForce);
+#endif
+  },
+
   get enabled() {
     return document.documentElement.getAttribute("tabsintitlebar") == "true";
   },
@@ -4537,62 +4244,200 @@ var TabsInTitlebar = {
       this._readPref();
   },
 
+  handleEvent: function(ev) {
+    if (ev.type == "customization-transitionend") {
+      this._update(true);
+    }
+  },
+
+  _onMenuMutate: function (aMutations) {
+    for (let mutation of aMutations) {
+      if (mutation.attributeName == "inactive" ||
+          mutation.attributeName == "autohide") {
+        TabsInTitlebar._update(true);
+        return;
+      }
+    }
+  },
+
   _initialized: false,
   _disallowed: {},
   _prefName: "browser.tabs.drawInTitlebar",
+  _lastSizeMode: null,
 
   _readPref: function () {
     this.allowedBy("pref",
                    Services.prefs.getBoolPref(this._prefName));
   },
 
-  _update: function () {
+  _update: function (aForce=false) {
     function $(id) document.getElementById(id);
     function rect(ele) ele.getBoundingClientRect();
+    function verticalMargins(cstyle) parseFloat(cstyle.marginBottom) + parseFloat(cstyle.marginTop);
 
     if (!this._initialized || window.fullScreen)
       return;
 
     let allowed = true;
+
+    if (!aForce) {
+      // _update is called on resize events, because the window is not ready
+      // after sizemode events. However, we only care about the event when the
+      // sizemode is different from the last time we updated the appearance of
+      // the tabs in the titlebar.
+      let sizemode = document.documentElement.getAttribute("sizemode");
+      if (this._lastSizeMode == sizemode) {
+        return;
+      }
+      this._lastSizeMode = sizemode;
+    }
+
     for (let something in this._disallowed) {
       allowed = false;
       break;
     }
 
-    if (allowed == this.enabled)
-      return;
-
     let titlebar = $("titlebar");
+    let titlebarContent = $("titlebar-content");
+    let menubar = $("toolbar-menubar");
 
     if (allowed) {
-      let tabsToolbar       = $("TabsToolbar");
+      // We set the tabsintitlebar attribute first so that our CSS for
+      // tabsintitlebar manifests before we do our measurements.
+      document.documentElement.setAttribute("tabsintitlebar", "true");
+      updateTitlebarDisplay();
+
+      // Try to avoid reflows in this code by calculating dimensions first and
+      // then later set the properties affecting layout together in a batch.
 
-#ifdef MENUBAR_CAN_AUTOHIDE
-      let appmenuButtonBox  = $("appmenu-button-container");
-      this._sizePlaceholder("appmenu-button", rect(appmenuButtonBox).width);
+      // Buttons first:
+      let captionButtonsBoxWidth = rect($("titlebar-buttonbox")).width;
+#ifdef XP_MACOSX
+      let fullscreenButtonWidth = rect($("titlebar-fullscreen-button")).width;
+      // No need to look up the menubar stuff on OS X:
+      let menuHeight = 0;
+      let fullMenuHeight = 0;
+      // Instead, look up the titlebar padding:
+      let titlebarPadding = parseInt(window.getComputedStyle(titlebar).paddingTop, 10);
+#else
+      // Otherwise, get the height and margins separately for the menubar
+      let menuHeight = rect(menubar).height;
+      let menuStyles = window.getComputedStyle(menubar);
+      let fullMenuHeight = verticalMargins(menuStyles) + menuHeight;
 #endif
-      let captionButtonsBox = $("titlebar-buttonbox");
-      this._sizePlaceholder("caption-buttons", rect(captionButtonsBox).width);
+      // Get the full height of the tabs toolbar:
+      let tabsToolbar = $("TabsToolbar");
+      let tabsStyles = window.getComputedStyle(tabsToolbar);
+      let fullTabsHeight = rect(tabsToolbar).height + verticalMargins(tabsStyles);
+
+      // If the navbar overlaps the tabbar using negative margins, we need to take those into
+      // account so we don't overlap it
+      let navbarMarginTop = parseFloat(window.getComputedStyle($("nav-bar")).marginTop);
+      navbarMarginTop = Math.min(navbarMarginTop, 0);
+
+      // And get the height of what's in the titlebar:
+      let titlebarContentHeight = rect(titlebarContent).height;
+
+      // Padding surrounds the tab-view-deck when we are in customization mode,
+      // so take that into account:
+      let areCustomizing = document.documentElement.hasAttribute("customizing") ||
+                           document.documentElement.hasAttribute("customize-exiting");
+      let customizePadding = 0;
+      if (areCustomizing) {
+        let deckStyle = window.getComputedStyle($("tab-view-deck"));
+        customizePadding = parseFloat(deckStyle.paddingTop);
+      }
 
-      let tabsToolbarRect = rect(tabsToolbar);
-      let titlebarTop = rect($("titlebar-content")).top;
-      titlebar.style.marginBottom = - Math.min(tabsToolbarRect.top - titlebarTop,
-                                               tabsToolbarRect.height) + "px";
+      // Begin setting CSS properties which will cause a reflow
+
+      // If the menubar is around (menuHeight is non-zero), try to adjust
+      // its full height (i.e. including margins) to match the titlebar,
+      // by changing the menubar's bottom padding
+      if (menuHeight) {
+        // Calculate the difference between the titlebar's height and that of the menubar
+        let menuTitlebarDelta = titlebarContentHeight - fullMenuHeight;
+        let paddingBottom;
+        // The titlebar is bigger:
+        if (menuTitlebarDelta > 0) {
+          fullMenuHeight += menuTitlebarDelta;
+          // If there is already padding on the menubar, we need to add that
+          // to the difference so the total padding is correct:
+          if ((paddingBottom = menuStyles.paddingBottom)) {
+            menuTitlebarDelta += parseFloat(paddingBottom);
+          }
+          menubar.style.paddingBottom = menuTitlebarDelta + "px";
+        // The menubar is bigger, but has bottom padding we can remove:
+        } else if (menuTitlebarDelta < 0 && (paddingBottom = menuStyles.paddingBottom)) {
+          let existingPadding = parseFloat(paddingBottom);
+          // menuTitlebarDelta is negative; work out what's left, but don't set negative padding:
+          let desiredPadding = Math.max(0, existingPadding + menuTitlebarDelta);
+          menubar.style.paddingBottom = desiredPadding + "px";
+          // We've changed the menu height now:
+          fullMenuHeight += desiredPadding - existingPadding;
+        }
+      }
 
-      document.documentElement.setAttribute("tabsintitlebar", "true");
+      // Next, we calculate how much we need to stretch the titlebar down to
+      // go all the way to the bottom of the tab strip, if necessary.
+      let tabAndMenuHeight = fullTabsHeight + fullMenuHeight;
+      // Oh, and don't forget customization mode:
+      if (areCustomizing) {
+        tabAndMenuHeight += customizePadding;
+      }
+
+      if (tabAndMenuHeight > titlebarContentHeight) {
+        // We need to increase the titlebar content's outer height (ie including margins)
+        // to match the tab and menu height:
+        let extraMargin = tabAndMenuHeight - titlebarContentHeight;
+        // We need to reduce the height by the amount of navbar overlap
+        // (this value is 0 or negative):
+        extraMargin += navbarMarginTop;
+        // On non-OSX, we can just use bottom margin:
+#ifndef XP_MACOSX
+        titlebarContent.style.marginBottom = extraMargin + "px";
+#else
+        // Otherwise, center the content. This means taking the titlebar's
+        // padding into account:
+        let halfMargin = (extraMargin - titlebarPadding) / 2;
+        titlebarContent.style.marginTop =  halfMargin + "px";
+        titlebarContent.style.marginBottom =  (titlebarPadding + halfMargin) + "px";
+#endif
+        titlebarContentHeight += extraMargin;
+      }
 
-      if (!this._draghandle) {
+      // Then we bring up the titlebar by the same amount, but we add any negative margin:
+      titlebar.style.marginBottom = "-" + titlebarContentHeight + "px";
+
+
+      // Finally, size the placeholders:
+#ifdef XP_MACOSX
+      this._sizePlaceholder("fullscreen-button", fullscreenButtonWidth);
+#endif
+      this._sizePlaceholder("caption-buttons", captionButtonsBoxWidth);
+
+      if (!this._draghandles) {
+        this._draghandles = {};
         let tmp = {};
         Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
-        this._draghandle = new tmp.WindowDraggingElement(tabsToolbar);
-        this._draghandle.mouseDownCheck = function () {
+
+        let mouseDownCheck = function () {
           return !this._dragBindingAlive && TabsInTitlebar.enabled;
         };
+
+        this._draghandles.tabsToolbar = new tmp.WindowDraggingElement(tabsToolbar);
+        this._draghandles.tabsToolbar.mouseDownCheck = mouseDownCheck;
+
+        this._draghandles.navToolbox = new tmp.WindowDraggingElement(gNavToolbox);
+        this._draghandles.navToolbox.mouseDownCheck = mouseDownCheck;
       }
     } else {
       document.documentElement.removeAttribute("tabsintitlebar");
+      updateTitlebarDisplay();
 
+      // Reset the margins and padding that might have been modified:
+      titlebarContent.style.marginBottom = "";
       titlebar.style.marginBottom = "";
+      menubar.style.paddingBottom = "";
     }
   },
 
@@ -4606,30 +4451,24 @@ var TabsInTitlebar = {
 #ifdef CAN_DRAW_IN_TITLEBAR
     this._initialized = false;
     Services.prefs.removeObserver(this._prefName, this);
+    this._menuObserver.disconnect();
+    CustomizableUI.removeListener(this);
 #endif
   }
 };
 
-#ifdef MENUBAR_CAN_AUTOHIDE
-function updateAppButtonDisplay() {
-  var displayAppButton =
-    !gInPrintPreviewMode &&
-    window.menubar.visible &&
-    document.getElementById("toolbar-menubar").getAttribute("autohide") == "true";
-
 #ifdef CAN_DRAW_IN_TITLEBAR
-  document.getElementById("titlebar").hidden = !displayAppButton;
+function updateTitlebarDisplay() {
+  document.getElementById("titlebar").hidden = !TabsInTitlebar.enabled;
 
-  if (displayAppButton)
+  if (TabsInTitlebar.enabled)
+#ifdef XP_WIN
     document.documentElement.setAttribute("chromemargin", "0,2,2,2");
-  else
-    document.documentElement.removeAttribute("chromemargin");
-
-  TabsInTitlebar.allowedBy("drawing-in-titlebar", displayAppButton);
 #else
-  document.getElementById("appmenu-toolbar-button").hidden =
-    !displayAppButton;
+    document.documentElement.setAttribute("chromemargin", "0,-1,-1,-1");
 #endif
+  else
+    document.documentElement.removeAttribute("chromemargin");
 }
 #endif
 
@@ -6911,12 +6750,6 @@ let gPrivateBrowsingUI = {
     document.getElementById("Tools:Sanitize").setAttribute("disabled", "true");
 
     if (window.location.href == getBrowserURL()) {
-#ifdef XP_MACOSX
-      if (!PrivateBrowsingUtils.permanentPrivateBrowsing) {
-        document.documentElement.setAttribute("drawintitlebar", true);
-      }
-#endif
-
       // Adjust the window's title
       let docElement = document.documentElement;
       if (!PrivateBrowsingUtils.permanentPrivateBrowsing) {
@@ -6933,7 +6766,6 @@ let gPrivateBrowsingUI = {
         // Adjust the New Window menu entries
         [
           { normal: "menu_newNavigator", private: "menu_newPrivateWindow" },
-          { normal: "appmenu_newNavigator", private: "appmenu_newPrivateWindow" },
         ].forEach(function(menu) {
           let newWindow = document.getElementById(menu.normal);
           let newPrivateWindow = document.getElementById(menu.private);
@@ -7178,11 +7010,6 @@ function duplicateTabIn(aTab, where, delta) {
   }
 }
 
-function toggleAddonBar() {
-  let addonBar = document.getElementById("addon-bar");
-  setToolbarVisibility(addonBar, addonBar.collapsed);
-}
-
 var Scratchpad = {
   openScratchpad: function SP_openScratchpad() {
     return this.ScratchpadManager.openScratchpad();
diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
index 1158166737d0b15b97d94368cb7f040d54251ee1..3303293bae8607e992e51f9fe0ec0af334e6a617 100644
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -9,7 +9,9 @@
 <?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/customizableui/panelUIOverlay.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/browser-lightweightTheme.css" type="text/css"?>
 
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
@@ -38,6 +40,14 @@
         titlemodifier="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
         titlemodifier_normal="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
         titlemodifier_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;"
+#endif
+#ifdef CAN_DRAW_IN_TITLEBAR
+#ifdef XP_WIN
+        chromemargin="0,2,2,2"
+#else
+        chromemargin="0,-1,-1,-1"
+#endif
+        tabsintitlebar="true"
 #endif
         titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
         lightweightthemes="true"
@@ -46,6 +56,7 @@
         macanimationtype="document"
         screenX="4" screenY="4"
         fullscreenbutton="true"
+        sizemode="normal"
         persist="screenX screenY width height sizemode">
 
 # All JS files which are not content (only) dependent that browser.xul
@@ -257,10 +268,6 @@
     <menupopup id="toolbar-context-menu"
                onpopupshowing="onViewToolbarsPopupShowing(event);">
       <menuseparator/>
-      <menuitem command="cmd_ToggleTabsOnTop"
-                type="checkbox"
-                label="&viewTabsOnTop.label;"
-                accesskey="&viewTabsOnTop.accesskey;"/>
       <menuitem command="cmd_CustomizeToolbars"
                 label="&viewCustomizeToolbar.label;"
                 accesskey="&viewCustomizeToolbar.accesskey;"/>
@@ -381,10 +388,6 @@
     <!-- Bookmarks and history tooltip -->
     <tooltip id="bhTooltip"/>
 
-    <panel id="customizeToolbarSheetPopup"
-           noautohide="true"
-           sheetstyle="&dialog.dimensions;"/>
-
     <tooltip id="tabbrowser-tab-tooltip" onpopupshowing="gBrowser.createTooltip(event);"/>
 
     <tooltip id="back-button-tooltip">
@@ -407,6 +410,8 @@
 
 #include popup-notifications.inc
 
+#include ../../components/customizableui/content/panelUI.inc.xul
+
     <hbox id="downloads-animation-container" mousethrough="always">
       <vbox id="downloads-notification-anchor">
         <vbox id="downloads-indicator-notification"/>
@@ -417,24 +422,21 @@
 #ifdef CAN_DRAW_IN_TITLEBAR
 <vbox id="titlebar">
   <hbox id="titlebar-content">
-#ifdef MENUBAR_CAN_AUTOHIDE
-    <hbox id="appmenu-button-container">
-      <button id="appmenu-button"
-              type="menu"
-              label="&brandShortName;"
-              style="-moz-user-focus: ignore;">
-#include browser-appmenu.inc
-      </button>
-    </hbox>
-#endif
     <spacer id="titlebar-spacer" flex="1"/>
-    <hbox id="titlebar-buttonbox-container" align="start">
+    <hbox id="titlebar-buttonbox-container" align="start"
+#ifdef XP_MACOSX
+          ordinal="0"
+#endif
+    >
       <hbox id="titlebar-buttonbox">
         <toolbarbutton class="titlebar-button" id="titlebar-min" oncommand="window.minimize();"/>
         <toolbarbutton class="titlebar-button" id="titlebar-max" oncommand="onTitlebarMaxClick();"/>
         <toolbarbutton class="titlebar-button" id="titlebar-close" command="cmd_closeWindow"/>
       </hbox>
     </hbox>
+#ifdef XP_MACOSX
+    <hbox id="titlebar-fullscreen-button" ordinal="1000"/>
+#endif
   </hbox>
 </vbox>
 #endif
@@ -442,329 +444,451 @@
 <deck flex="1" id="tab-view-deck">
 <vbox flex="1" id="browser-panel">
 
-  <toolbox id="navigator-toolbox"
-           defaultmode="icons" mode="icons"
-           iconsize="large">
+  <toolbox id="navigator-toolbox">
     <!-- Menu -->
     <toolbar type="menubar" id="toolbar-menubar" class="chromeclass-menubar" customizable="true"
              defaultset="menubar-items"
-             mode="icons" iconsize="small" defaulticonsize="small"
-             lockiconsize="true"
+             mode="icons" iconsize="small"
 #ifdef MENUBAR_CAN_AUTOHIDE
              toolbarname="&menubarCmd.label;"
              accesskey="&menubarCmd.accesskey;"
+#ifdef XP_LINUX
+             autohide="true"
+#endif
 #endif
              context="toolbar-context-menu">
-      <toolbaritem id="menubar-items" align="center">
+      <toolbaritem id="menubar-items" align="center"
+                   cui-areatype="toolbar">
 # The entire main menubar is placed into browser-menubar.inc, so that it can be shared by
 # hiddenWindow.xul.
 #include browser-menubar.inc
       </toolbaritem>
 
 #ifdef CAN_DRAW_IN_TITLEBAR
-      <hbox class="titlebar-placeholder" type="appmenu-button" ordinal="0"/>
-      <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/>
+#ifndef XP_MACOSX
+      <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"
+            id="titlebar-placeholder-on-menubar-for-caption-buttons" persist="width"
+            skipintoolbarset="true"/>
+#endif
 #endif
     </toolbar>
 
-    <toolbar id="nav-bar" class="toolbar-primary chromeclass-toolbar"
-             toolbarname="&navbarCmd.label;" accesskey="&navbarCmd.accesskey;"
-             fullscreentoolbar="true" mode="icons" customizable="true"
-             iconsize="large"
-             defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,webrtc-status-button,bookmarks-menu-button,downloads-button,home-button,window-controls"
-             context="toolbar-context-menu">
-
-      <toolbaritem id="unified-back-forward-button" class="chromeclass-toolbar-additional"
-                   context="backForwardMenu" removable="true"
-                   forwarddisabled="true"
-                   title="&backForwardItem.title;">
-        <toolbarbutton id="back-button" class="toolbarbutton-1"
-                       label="&backCmd.label;"
-                       command="Browser:BackOrBackDuplicate"
-                       onclick="checkForMiddleClick(this, event);"
-                       tooltip="back-button-tooltip"/>
-        <toolbarbutton id="forward-button" class="toolbarbutton-1"
-                       label="&forwardCmd.label;"
-                       command="Browser:ForwardOrForwardDuplicate"
-                       onclick="checkForMiddleClick(this, event);"
-                       tooltip="forward-button-tooltip"/>
-        <dummyobservertarget hidden="true"
-                             onbroadcast="if (this.getAttribute('disabled') == 'true')
-                                            this.parentNode.setAttribute('forwarddisabled', 'true');
-                                          else
-                                            this.parentNode.removeAttribute('forwarddisabled');">
-          <observes element="Browser:ForwardOrForwardDuplicate" attribute="disabled"/>
-        </dummyobservertarget>
-      </toolbaritem>
+    <toolbar id="TabsToolbar"
+             class="toolbar-primary"
+             fullscreentoolbar="true"
+             customizable="true"
+             mode="icons"
+             iconsize="small"
+             aria-label="&tabsToolbar.label;"
+             context="toolbar-context-menu"
+             defaultset="tabbrowser-tabs,new-tab-button,alltabs-button,tabs-closebutton"
+             collapsed="true">
 
-      <toolbaritem id="urlbar-container" align="center" flex="400" persist="width" combined="true"
-                   title="&locationItem.title;" class="chromeclass-location" removable="true">
-        <textbox id="urlbar" flex="1"
-                 placeholder="&urlbar.placeholder2;"
-                 type="autocomplete"
-                 autocompletesearch="urlinline history"
-                 autocompletesearchparam="enable-actions"
-                 autocompletepopup="PopupAutoCompleteRichResult"
-                 completeselectedindex="true"
-                 tabscrolling="true"
-                 showcommentcolumn="true"
-                 showimagecolumn="true"
-                 enablehistory="true"
-                 maxrows="6"
-                 newlines="stripsurroundingwhitespace"
-                 oninput="gBrowser.userTypedValue = this.value;"
-                 ontextentered="this.handleCommand(param);"
-                 ontextreverted="return this.handleRevert();"
-                 pageproxystate="invalid"
-                 onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
-                 onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
-          <box id="notification-popup-box" hidden="true" align="center">
-            <image id="default-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="identity-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="password-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="webapps-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="plugins-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="web-notifications-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="plugin-install-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="mixed-content-blocked-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="pointerLock-notification-icon" class="notification-anchor-icon" role="button"/>
-            <image id="servicesInstall-notification-icon" class="notification-anchor-icon" role="button"/>
-          </box>
-          <!-- Use onclick instead of normal popup= syntax since the popup
-               code fires onmousedown, and hence eats our favicon drag events.
-               We only add the identity-box button to the tab order when the location bar
-               has focus, otherwise pressing F6 focuses it instead of the location bar -->
-          <box id="identity-box" role="button"
-               align="center"
-               onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
-               onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
-               ondragstart="gIdentityHandler.onDragStart(event);">
-            <image id="page-proxy-favicon"
-                   onclick="PageProxyClickHandler(event);"
-                   pageproxystate="invalid"/>
-            <hbox id="identity-icon-labels">
-              <label id="identity-icon-label" class="plain" flex="1"/>
-              <label id="identity-icon-country-label" class="plain"/>
-            </hbox>
-          </box>
-          <box id="urlbar-display-box" align="center">
-            <label id="urlbar-display" value="&urlbar.switchToTab.label;"/>
-          </box>
-          <hbox id="urlbar-icons">
-            <image id="page-report-button"
-                   class="urlbar-icon"
-                   hidden="true"
-                   tooltiptext="&pageReportIcon.tooltip;"
-                   onclick="gPopupBlockerObserver.onReportButtonClick(event);"/>
-            <image id="star-button"
-                   class="urlbar-icon"
-                   onclick="if (event.button === 0) BookmarkingUI.onCommand(event);"/>
-            <image id="go-button"
-                   class="urlbar-icon"
-                   tooltiptext="&goEndCap.tooltip;"
-                   onclick="gURLBar.handleCommand(event);"/>
-          </hbox>
-          <toolbarbutton id="urlbar-go-button"
-                         class="chromeclass-toolbar-additional"
-                         onclick="gURLBar.handleCommand(event);"
-                         tooltiptext="&goEndCap.tooltip;"/>
-          <toolbarbutton id="urlbar-reload-button"
-                         class="chromeclass-toolbar-additional"
-                         command="Browser:ReloadOrDuplicate"
-                         onclick="checkForMiddleClick(this, event);"
-                         tooltiptext="&reloadButton.tooltip;"/>
-          <toolbarbutton id="urlbar-stop-button"
-                         class="chromeclass-toolbar-additional"
-                         command="Browser:Stop"
-                         tooltiptext="&stopButton.tooltip;"/>
-        </textbox>
-      </toolbaritem>
+      <tabs id="tabbrowser-tabs"
+            class="tabbrowser-tabs"
+            tabbrowser="content"
+            flex="1"
+            setfocus="false"
+            tooltip="tabbrowser-tab-tooltip"
+            cui-areatype="toolbar"
+            stopwatchid="FX_TAB_CLICK_MS">
+        <tab class="tabbrowser-tab" selected="true" fadein="true"/>
+      </tabs>
 
-      <toolbarbutton id="reload-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&reloadCmd.label;" removable="true"
-                     command="Browser:ReloadOrDuplicate"
+      <toolbarbutton id="new-tab-button"
+                     class="toolbarbutton-1 chromeclass-toolbar-additional"
+                     label="&tabCmd.label;"
+                     command="cmd_newNavigatorTab"
                      onclick="checkForMiddleClick(this, event);"
-                     tooltiptext="&reloadButton.tooltip;"/>
-
-      <toolbarbutton id="stop-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&stopCmd.label;" removable="true"
-                     command="Browser:Stop"
-                     tooltiptext="&stopButton.tooltip;"/>
-
-      <toolbaritem id="search-container" title="&searchItem.title;"
-                   align="center" class="chromeclass-toolbar-additional"
-                   flex="100" persist="width" removable="true">
-        <searchbar id="searchbar" flex="1"/>
-      </toolbaritem>
+                     tooltiptext="&newTabButton.tooltip;"
+                     ondrop="newTabButtonObserver.onDrop(event)"
+                     ondragover="newTabButtonObserver.onDragOver(event)"
+                     ondragenter="newTabButtonObserver.onDragOver(event)"
+                     ondragexit="newTabButtonObserver.onDragExit(event)"
+                     cui-areatype="toolbar"
+                     removable="true"/>
 
-      <toolbarbutton id="webrtc-status-button"
-                     class="toolbarbutton-1 chromeclass-toolbar-additional"
+      <toolbarbutton id="alltabs-button"
+                     class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button"
                      type="menu"
-                     hidden="true"
-                     orient="horizontal"
-                     label="&webrtcIndicatorButton.label;"
-                     tooltiptext="&webrtcIndicatorButton.tooltip;">
-        <menupopup onpopupshowing="WebrtcIndicator.fillPopup(this);"
-                   onpopuphiding="WebrtcIndicator.clearPopup(this);"
-                   oncommand="WebrtcIndicator.menuCommand(event.target);"/>
+                     label="&listAllTabs.label;"
+                     tooltiptext="&listAllTabs.label;"
+                     removable="false">
+        <menupopup id="alltabs-popup"
+                   position="after_end">
+          <menuitem id="menu_tabview"
+                    class="menuitem-iconic"
+                    key="key_tabview"
+                    label="&viewTabGroups.label;"
+                    command="Browser:ToggleTabView"
+                    cui-areatype="toolbar"
+                    observes="tabviewGroupsNumber"/>
+          <menuseparator id="alltabs-popup-separator"/>
+        </menupopup>
       </toolbarbutton>
 
-      <toolbarbutton id="bookmarks-menu-button"
-                     class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     persist="class"
-                     removable="true"
-                     type="menu"
-                     label="&bookmarksMenuButton.label;"
-                     tooltiptext="&bookmarksMenuButton.tooltip;"
-                     ondragenter="PlacesMenuDNDHandler.onDragEnter(event);"
-                     ondragover="PlacesMenuDNDHandler.onDragOver(event);"
-                     ondragleave="PlacesMenuDNDHandler.onDragLeave(event);"
-                     ondrop="PlacesMenuDNDHandler.onDrop(event);">
-        <menupopup id="BMB_bookmarksPopup"
-                   placespopup="true"
-                   context="placesContext"
-                   openInTabs="children"
-                   oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
-                   onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
-                   onpopupshowing="BookmarkingUI.onPopupShowing(event);
-                                   if (!this.parentNode._placesView)
-                                     new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
-                   tooltip="bhTooltip" popupsinherittooltip="true">
-          <menuitem id="BMB_viewBookmarksToolbar"
-                    placesanonid="view-toolbar"
-                    toolbarId="PersonalToolbar"
-                    type="checkbox"
-                    oncommand="onViewToolbarCommand(event)"
-                    label="&viewBookmarksToolbar.label;"/>
-          <menuseparator/>
-          <menuitem id="BMB_bookmarksShowAll"
-                    label="&showAllBookmarks2.label;"
-                    command="Browser:ShowAllBookmarks"
-                    key="manBookmarkKb"/>
-          <menuseparator/>
-          <menuitem id="BMB_bookmarkThisPage"
+      <toolbarbutton id="tabs-closebutton"
+                     class="close-button tabs-closebutton close-icon"
+                     command="cmd_close"
+                     label="&closeTab.label;"
+                     cui-areatype="toolbar"
+                     tooltiptext="&closeTab.label;"/>
+
+#ifdef CAN_DRAW_IN_TITLEBAR
+      <hbox class="titlebar-placeholder" type="caption-buttons"
+            id="titlebar-placeholder-on-TabsToolbar-for-captions-buttons" persist="width"
 #ifndef XP_MACOSX
-                    class="menuitem-iconic"
+            ordinal="1000"
 #endif
-                    label="&bookmarkThisPageCmd.label;"
-                    command="Browser:AddBookmarkAs"
-                    key="addBookmarkAsKb"/>
-          <menuitem id="BMB_subscribeToPageMenuitem"
+            skipintoolbarset="true"/>
+
+#ifdef XP_MACOSX
+      <hbox class="titlebar-placeholder" type="fullscreen-button"
+            id="titlebar-placeholder-on-TabsToolbar-for-fullscreen-button" persist="width"
+            skipintoolbarset="true"/>
+#endif
+#endif
+    </toolbar>
+
+    <!--
+           CAVEAT EMPTOR
+           Should you need to add items to the toolbar here, make sure to also add them
+           to the default placements of buttons in CustomizableUI.jsm, so the
+           customization code doesn't get confused.
+      -->
+    <toolbar id="nav-bar" class="toolbar-primary chromeclass-toolbar"
+             aria-label="&navbarCmd.label;"
+             fullscreentoolbar="true" mode="icons" customizable="true"
+             iconsize="small"
+             defaultset="urlbar-container,search-container,webrtc-status-button,bookmarks-menu-button,downloads-button,home-button,social-share-button,social-toolbar-item"
+             customizationtarget="nav-bar-customization-target"
+             overflowable="true"
+             overflowbutton="nav-bar-overflow-button"
+             overflowtarget="widget-overflow-list"
+             context="toolbar-context-menu">
+
+      <hbox id="nav-bar-customization-target" class="customization-target" flex="1">
+        <toolbaritem id="urlbar-container" flex="400" persist="width"
+                     forwarddisabled="true" title="&locationItem.title;" removable="false"
+                     cui-areatype="toolbar"
+                     class="chromeclass-location" overflows="false">
+          <toolbarbutton id="back-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+                         label="&backCmd.label;"
+                         command="Browser:BackOrBackDuplicate"
+                         onclick="checkForMiddleClick(this, event);"
+                         tooltip="back-button-tooltip"
+                         context="backForwardMenu"/>
+          <toolbarbutton id="forward-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+                         label="&forwardCmd.label;"
+                         command="Browser:ForwardOrForwardDuplicate"
+                         onclick="checkForMiddleClick(this, event);"
+                         tooltip="forward-button-tooltip"
+                         context="backForwardMenu"/>
+          <dummyobservertarget hidden="true"
+                               onbroadcast="if (this.getAttribute('disabled') == 'true')
+                                              this.parentNode.setAttribute('forwarddisabled', 'true');
+                                            else
+                                              this.parentNode.removeAttribute('forwarddisabled');">
+            <observes element="Browser:ForwardOrForwardDuplicate" attribute="disabled"/>
+          </dummyobservertarget>
+          <hbox id="urlbar-wrapper" flex="1" align="center">
+            <textbox id="urlbar" flex="1"
+                     placeholder="&urlbar.placeholder2;"
+                     type="autocomplete"
+                     autocompletesearch="urlinline history"
+                     autocompletesearchparam="enable-actions"
+                     autocompletepopup="PopupAutoCompleteRichResult"
+                     completeselectedindex="true"
+                     tabscrolling="true"
+                     showcommentcolumn="true"
+                     showimagecolumn="true"
+                     enablehistory="true"
+                     maxrows="6"
+                     newlines="stripsurroundingwhitespace"
+                     oninput="gBrowser.userTypedValue = this.value;"
+                     ontextentered="this.handleCommand(param);"
+                     ontextreverted="return this.handleRevert();"
+                     pageproxystate="invalid"
+                     onfocus="document.getElementById('identity-box').style.MozUserFocus= 'normal'"
+                     onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
+              <box id="notification-popup-box" hidden="true" align="center">
+                <image id="default-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="identity-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="geo-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="addons-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="indexedDB-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="password-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="webapps-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="plugins-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="web-notifications-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="plugin-install-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="mixed-content-blocked-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="pointerLock-notification-icon" class="notification-anchor-icon" role="button"/>
+                <image id="servicesInstall-notification-icon" class="notification-anchor-icon" role="button"/>
+              </box>
+              <!-- Use onclick instead of normal popup= syntax since the popup
+                   code fires onmousedown, and hence eats our favicon drag events.
+                   We only add the identity-box button to the tab order when the location bar
+                   has focus, otherwise pressing F6 focuses it instead of the location bar -->
+              <box id="identity-box" role="button"
+                   align="center"
+                   onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
+                   onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
+                   ondragstart="gIdentityHandler.onDragStart(event);">
+                <image id="page-proxy-favicon"
+                       onclick="PageProxyClickHandler(event);"
+                       pageproxystate="invalid"/>
+                <hbox id="identity-icon-labels">
+                  <label id="identity-icon-label" class="plain" flex="1"/>
+                  <label id="identity-icon-country-label" class="plain"/>
+                </hbox>
+              </box>
+              <box id="urlbar-display-box" align="center">
+                <label id="urlbar-display" value="&urlbar.switchToTab.label;"/>
+              </box>
+              <hbox id="urlbar-icons">
+                <image id="page-report-button"
+                       class="urlbar-icon"
+                       hidden="true"
+                       tooltiptext="&pageReportIcon.tooltip;"
+                       onclick="gPopupBlockerObserver.onReportButtonClick(event);"/>
+                <image id="star-button"
+                       class="urlbar-icon"
+                       onclick="if (event.button === 0) BookmarkingUI.onCommand(event);"/>
+              </hbox>
+              <toolbarbutton id="urlbar-go-button"
+                             class="chromeclass-toolbar-additional"
+                             onclick="gURLBar.handleCommand(event);"
+                             tooltiptext="&goEndCap.tooltip;"/>
+              <toolbarbutton id="urlbar-reload-button"
+                             class="chromeclass-toolbar-additional"
+                             command="Browser:ReloadOrDuplicate"
+                             onclick="checkForMiddleClick(this, event);"
+                             tooltiptext="&reloadButton.tooltip;"/>
+              <toolbarbutton id="urlbar-stop-button"
+                             class="chromeclass-toolbar-additional"
+                             command="Browser:Stop"
+                             tooltiptext="&stopButton.tooltip;"/>
+            </textbox>
+          </hbox>
+        </toolbaritem>
+
+        <toolbaritem id="search-container" title="&searchItem.title;"
+                     align="center" class="chromeclass-toolbar-additional panel-wide-item"
+                     cui-areatype="toolbar"
+                     flex="100" persist="width" removable="true">
+          <searchbar id="searchbar" flex="1"/>
+        </toolbaritem>
+
+        <toolbarbutton id="webrtc-status-button"
+                       class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       type="menu"
+                       hidden="true"
+                       orient="horizontal"
+                       label="&webrtcIndicatorButton.label;"
+                       tooltiptext="&webrtcIndicatorButton.tooltip;"
+                       cui-areatype="toolbar"
+                       overflows="false">
+          <menupopup onpopupshowing="WebrtcIndicator.fillPopup(this);"
+                     onpopuphiding="WebrtcIndicator.clearPopup(this);"
+                     oncommand="WebrtcIndicator.menuCommand(event.target);"/>
+        </toolbarbutton>
+
+        <toolbarbutton id="bookmarks-menu-button"
+                       class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       persist="class"
+                       removable="true"
+                       type="menu-button"
+                       label="&bookmarksMenuButton.label;"
+                       tooltiptext="&bookmarksMenuButton.tooltip;"
+                       ondragenter="PlacesMenuDNDHandler.onDragEnter(event);"
+                       ondragover="PlacesMenuDNDHandler.onDragOver(event);"
+                       ondragleave="PlacesMenuDNDHandler.onDragLeave(event);"
+                       ondrop="PlacesMenuDNDHandler.onDrop(event);"
+                       cui-areatype="toolbar"
+                       oncommand="BookmarkingUI.onCommand(event);">
+          <menupopup id="BMB_bookmarksPopup"
+                     placespopup="true"
+                     context="placesContext"
+                     openInTabs="children"
+                     anonanchorclass="toolbarbutton-menubutton-dropmarker"
+                     oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
+                     onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
+                     onpopupshowing="BookmarkingUI.onPopupShowing(event);
+                                     if (!this.parentNode._placesView)
+                                       new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
+                     tooltip="bhTooltip" popupsinherittooltip="true">
+            <menuitem id="BMB_bookmarksShowAll"
+                      label="&showAllBookmarks2.label;"
+                      command="Browser:ShowAllBookmarks"
+                      key="manBookmarkKb"/>
+            <menuitem id="BMB_viewBookmarksSidebar"
+                      label="&viewBookmarksSidebar2.label;"
+                      type="checkbox"
+                      oncommand="toggleSidebar('viewBookmarksSidebar');">
+              <observes element="viewBookmarksSidebar" attribute="checked"/>
+            </menuitem>
+            <menuseparator/>
+            <menuitem id="BMB_subscribeToPageMenuitem"
 #ifndef XP_MACOSX
-                    class="menuitem-iconic"
+                      class="menuitem-iconic"
 #endif
-                    label="&subscribeToPageMenuitem.label;"
-                    oncommand="return FeedHandler.subscribeToFeed(null, event);"
-                    onclick="checkForMiddleClick(this, event);"
-                    observes="singleFeedMenuitemState"/>
-          <menu id="BMB_subscribeToPageMenupopup"
+                      label="&subscribeToPageMenuitem.label;"
+                      oncommand="return FeedHandler.subscribeToFeed(null, event);"
+                      onclick="checkForMiddleClick(this, event);"
+                      observes="singleFeedMenuitemState"/>
+            <menu id="BMB_subscribeToPageMenupopup"
 #ifndef XP_MACOSX
-                class="menu-iconic"
+                  class="menu-iconic"
 #endif
-                label="&subscribeToPageMenupopup.label;"
-                observes="multipleFeedsMenuState">
-            <menupopup id="BMB_subscribeToPageSubmenuMenupopup"
-                       onpopupshowing="return FeedHandler.buildFeedList(event.target);"
-                       oncommand="return FeedHandler.subscribeToFeed(null, event);"
-                       onclick="checkForMiddleClick(this, event);"/>
-          </menu>
-          <menuseparator/>
-          <menu id="BMB_bookmarksToolbar"
-                placesanonid="toolbar-autohide"
-                class="menu-iconic bookmark-item"
-                label="&personalbarCmd.label;"
-                container="true">
-            <menupopup id="BMB_bookmarksToolbarPopup"
-                       placespopup="true"
-                       context="placesContext"
-                       onpopupshowing="if (!this.parentNode._placesView)
-                                         new PlacesMenu(event, 'place:folder=TOOLBAR');"/>
-          </menu>
-          <menuseparator/>
-          <!-- Bookmarks menu items -->
-          <menuseparator builder="end"
-                         class="hide-if-empty-places-result"/>
-          <menuitem id="BMB_unsortedBookmarks"
-                    label="&bookmarksMenuButton.unsorted.label;"
-                    oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks');"
-                    class="menuitem-iconic"/>
-        </menupopup>
-      </toolbarbutton>
+                  label="&subscribeToPageMenupopup.label;"
+                  observes="multipleFeedsMenuState">
+              <menupopup id="BMB_subscribeToPageSubmenuMenupopup"
+                         onpopupshowing="return FeedHandler.buildFeedList(event.target);"
+                         oncommand="return FeedHandler.subscribeToFeed(null, event);"
+                         onclick="checkForMiddleClick(this, event);"/>
+            </menu>
+            <menuseparator/>
+            <menu id="BMB_bookmarksToolbar"
+                  class="menu-iconic bookmark-item"
+                  label="&personalbarCmd.label;"
+                  container="true">
+              <menupopup id="BMB_bookmarksToolbarPopup"
+                         placespopup="true"
+                         context="placesContext"
+                         onpopupshowing="if (!this.parentNode._placesView)
+                                           new PlacesMenu(event, 'place:folder=TOOLBAR');">
+                <menuitem id="BMB_viewBookmarksToolbar"
+                          placesanonid="view-toolbar"
+                          toolbarId="PersonalToolbar"
+                          type="checkbox"
+                          oncommand="onViewToolbarCommand(event)"
+                          label="&viewBookmarksToolbar.label;"/>
+                <menuseparator/>
+                <!-- Bookmarks toolbar items -->
+              </menupopup>
+            </menu>
+            <menu id="BMB_unsortedBookmarks"
+                  class="menu-iconic bookmark-item"
+                  label="&bookmarksMenuButton.unsorted.label;"
+                  container="true">
+              <menupopup id="BMB_unsortedBookmarksPopup"
+                         placespopup="true"
+                         context="placesContext"
+                         onpopupshowing="if (!this.parentNode._placesView)
+                                           new PlacesMenu(event, 'place:folder=UNFILED_BOOKMARKS');"/>
+            </menu>
+            <menuseparator/>
+            <!-- Bookmarks menu items -->
+          </menupopup>
+        </toolbarbutton>
 
-      <toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     persist="class" removable="true"
-                     label="&homeButton.label;"
-                     ondragover="homeButtonObserver.onDragOver(event)"
-                     ondragenter="homeButtonObserver.onDragOver(event)"
-                     ondrop="homeButtonObserver.onDrop(event)"
-                     ondragexit="homeButtonObserver.onDragExit(event)"
-                     onclick="BrowserGoHome(event);"
-                     aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
-
-      <toolbarbutton id="social-share-button"
-                     class="toolbarbutton-1 chromeclass-toolbar-additional"
+        <!-- This is a placeholder for the Downloads Indicator.  It is visible
+             during the customization of the toolbar, in the palette, and before
+             the Downloads Indicator overlay is loaded. -->
+        <toolbarbutton id="downloads-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       oncommand="DownloadsIndicatorView.onCommand(event);"
+                       ondrop="DownloadsIndicatorView.onDrop(event);"
+                       ondragover="DownloadsIndicatorView.onDragOver(event);"
+                       ondragenter="DownloadsIndicatorView.onDragOver(event);"
+                       label="&downloads.label;"
+                       removable="true"
+                       cui-areatype="toolbar"
+                       tooltiptext="&downloads.tooltip;"/>
+
+        <toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       persist="class" removable="true"
+                       label="&homeButton.label;"
+                       ondragover="homeButtonObserver.onDragOver(event)"
+                       ondragenter="homeButtonObserver.onDragOver(event)"
+                       ondrop="homeButtonObserver.onDrop(event)"
+                       ondragexit="homeButtonObserver.onDragExit(event)"
+                       onclick="BrowserGoHome(event);"
+                       cui-areatype="toolbar"
+                       aboutHomeOverrideTooltip="&abouthome.pageTitle;"/>
+
+
+        <toolbarbutton id="social-share-button"
+                       class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       hidden="true"
+                       overflows="false"
+                       label="&sharePageCmd.label;"
+                       tooltiptext="&sharePageCmd.label;"
+                       cui-areatype="toolbar"
+                       command="Social:SharePage"/>
+
+        <toolbaritem id="social-toolbar-item"
+                     class="chromeclass-toolbar-additional toolbaritem-with-separator"
+                     removable="false"
+                     title="&socialToolbar.title;"
                      hidden="true"
-                     label="&sharePageCmd.label;"
-                     tooltiptext="&sharePageCmd.label;"
-                     command="Social:SharePage"/>
-
-      <toolbaritem id="social-toolbar-item"
-                   class="chromeclass-toolbar-additional"
-                   removable="false"
-                   title="&socialToolbar.title;"
-                   hidden="true"
-                   skipintoolbarset="true"
-                   observes="socialActiveBroadcaster">
+                     overflows="false"
+                     cui-areatype="toolbar"
+                     observes="socialActiveBroadcaster">
         <toolbarbutton id="social-notification-icon" class="default-notification-icon toolbarbutton-1 notification-anchor-icon"
                    oncommand="PopupNotifications._reshowNotifications(this,
                                 document.getElementById('social-sidebar-browser'));"/>
-        <toolbarbutton id="social-provider-button"
-                       class="toolbarbutton-1"
-                       type="menu">
-          <menupopup id="social-statusarea-popup">
-            <menuitem class="social-statusarea-user menuitem-iconic" pack="start" align="center"
-                      observes="socialBroadcaster_userDetails"
-                      oncommand="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();">
-              <image class="social-statusarea-user-portrait"
-                     observes="socialBroadcaster_userDetails"/>
-              <vbox>
-                <label class="social-statusarea-loggedInStatus"
+          <toolbarbutton id="social-provider-button"
+                         class="toolbarbutton-1"
+                         type="menu">
+            <menupopup id="social-statusarea-popup">
+              <menuitem class="social-statusarea-user menuitem-iconic" pack="start" align="center"
+                        observes="socialBroadcaster_userDetails"
+                        oncommand="SocialUI.showProfile(); document.getElementById('social-statusarea-popup').hidePopup();">
+                <image class="social-statusarea-user-portrait"
                        observes="socialBroadcaster_userDetails"/>
-              </vbox>
-            </menuitem>
+                <vbox>
+                  <label class="social-statusarea-loggedInStatus"
+                         observes="socialBroadcaster_userDetails"/>
+                </vbox>
+              </menuitem>
 #ifndef XP_WIN
-            <menuseparator class="social-statusarea-separator"/>
+              <menuseparator class="social-statusarea-separator"/>
 #endif
-            <menuitem class="social-toggle-sidebar-menuitem"
-                      type="checkbox"
-                      autocheck="false"
-                      command="Social:ToggleSidebar"
-                      label="&social.toggleSidebar.label;"
-                      accesskey="&social.toggleSidebar.accesskey;"/>
-            <menuitem class="social-toggle-notifications-menuitem"
-                      type="checkbox"
-                      autocheck="false"
-                      command="Social:ToggleNotifications"
-                      label="&social.toggleNotifications.label;"
-                      accesskey="&social.toggleNotifications.accesskey;"/>
-            <menuitem class="social-toggle-menuitem" command="Social:Toggle"/>
-            <menuseparator/>
-            <menuseparator class="social-provider-menu" hidden="true"/>
-            <menuitem class="social-addons-menuitem" command="Social:Addons"
-                      label="&social.addons.label;"/>
-            <menuitem label="&social.learnMore.label;"
-                      accesskey="&social.learnMore.accesskey;"
-                      oncommand="SocialUI.showLearnMore();"/>
-          </menupopup>
-        </toolbarbutton>
+              <menuitem class="social-toggle-sidebar-menuitem"
+                        type="checkbox"
+                        autocheck="false"
+                        command="Social:ToggleSidebar"
+                        label="&social.toggleSidebar.label;"
+                        accesskey="&social.toggleSidebar.accesskey;"/>
+              <menuitem class="social-toggle-notifications-menuitem"
+                        type="checkbox"
+                        autocheck="false"
+                        command="Social:ToggleNotifications"
+                        label="&social.toggleNotifications.label;"
+                        accesskey="&social.toggleNotifications.accesskey;"/>
+              <menuitem class="social-toggle-menuitem" command="Social:Toggle"/>
+              <menuseparator/>
+              <menuseparator class="social-provider-menu" hidden="true"/>
+              <menuitem class="social-addons-menuitem" command="Social:Addons"
+                        label="&social.addons.label;"/>
+              <menuitem label="&social.learnMore.label;"
+                        accesskey="&social.learnMore.accesskey;"
+                        oncommand="SocialUI.showLearnMore();"/>
+            </menupopup>
+          </toolbarbutton>
+        </toolbaritem>
+      </hbox>
+
+      <toolbarbutton id="nav-bar-overflow-button"
+                     class="toolbarbutton-1 chromeclass-toolbar-additional overflow-button"
+                     skipintoolbarset="true"
+                     tooltiptext="&navbarOverflow.label;"/>
+
+      <toolbaritem id="PanelUI-button"
+                   class="chromeclass-toolbar-additional"
+                   removable="false"
+                   title="&appmenu.title;">
+        <toolbarbutton id="PanelUI-menu-button"
+                       class="toolbarbutton-1"
+                       label="&brandShortName;"
+                       tooltiptext="&appmenu.title;"/>
       </toolbaritem>
 
-      <hbox id="window-controls" hidden="true" pack="end">
+      <hbox id="window-controls" hidden="true" pack="end" skipintoolbarset="true"
+            ordinal="1000">
         <toolbarbutton id="minimize-button"
                        tooltiptext="&fullScreenMinimize.tooltip;"
                        oncommand="window.minimize();"/>
@@ -782,16 +906,23 @@
     <toolbarset id="customToolbars" context="toolbar-context-menu"/>
 
     <toolbar id="PersonalToolbar"
-             mode="icons" iconsize="small" defaulticonsize="small"
-             lockiconsize="true"
+             mode="icons" iconsize="small"
              class="chromeclass-directories"
              context="toolbar-context-menu"
              defaultset="personal-bookmarks"
              toolbarname="&personalbarCmd.label;" accesskey="&personalbarCmd.accesskey;"
              collapsed="true"
              customizable="true">
-      <toolbaritem flex="1" id="personal-bookmarks" title="&bookmarksItem.title;"
+      <toolbaritem id="personal-bookmarks"
+                   flex="1"
+                   title="&bookmarksToolbarItem.label;"
+                   cui-areatype="toolbar"
                    removable="true">
+        <toolbarbutton id="bookmarks-toolbar-placeholder"
+                       type="wrap"
+                       mousethrough="never"
+                       label="&bookmarksToolbarItem.label;"
+                       oncommand="PlacesToolbarHelper.onPlaceholderCommand();"/>
         <hbox flex="1"
               id="PlacesToolbar"
               context="placesContext"
@@ -799,9 +930,6 @@
               oncommand="BookmarksEventHandler.onCommand(event, this._placesView);"
               tooltip="bhTooltip"
               popupsinherittooltip="true">
-          <toolbarbutton class="bookmark-item bookmarks-toolbar-customize"
-                         mousethrough="never"
-                         label="&bookmarksToolbarItem.label;"/>
           <hbox flex="1">
             <hbox align="center">
               <image id="PlacesToolbarDropIndicator"
@@ -829,88 +957,10 @@
       </toolbaritem>
     </toolbar>
 
-#ifdef MENUBAR_CAN_AUTOHIDE
-#ifndef CAN_DRAW_IN_TITLEBAR
-#define APPMENU_ON_TABBAR
-#endif
-#endif
-
-
-    <toolbar id="TabsToolbar"
-             class="toolbar-primary"
-             fullscreentoolbar="true"
-             customizable="true"
-             mode="icons" lockmode="true"
-             iconsize="small" defaulticonsize="small" lockiconsize="true"
-             aria-label="&tabsToolbar.label;"
-             context="toolbar-context-menu"
-#ifdef APPMENU_ON_TABBAR
-             defaultset="appmenu-toolbar-button,tabbrowser-tabs,new-tab-button,alltabs-button,tabs-closebutton"
-#else
-             defaultset="tabbrowser-tabs,new-tab-button,alltabs-button,tabs-closebutton"
-#endif
-             collapsed="true">
-
-#ifdef APPMENU_ON_TABBAR
-      <toolbarbutton id="appmenu-toolbar-button"
-                     class="chromeclass-toolbar-additional"
-                     type="menu"
-                     label="&brandShortName;"
-                     tooltiptext="&appMenuButton.tooltip;">
-#include browser-appmenu.inc
-      </toolbarbutton>
-#endif
-
-      <tabs id="tabbrowser-tabs"
-            class="tabbrowser-tabs"
-            tabbrowser="content"
-            flex="1"
-            setfocus="false"
-            tooltip="tabbrowser-tab-tooltip"
-            stopwatchid="FX_TAB_CLICK_MS">
-        <tab class="tabbrowser-tab" selected="true" fadein="true"/>
-      </tabs>
-
-      <toolbarbutton id="new-tab-button"
-                     class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&tabCmd.label;"
-                     command="cmd_newNavigatorTab"
-                     onclick="checkForMiddleClick(this, event);"
-                     tooltiptext="&newTabButton.tooltip;"
-                     ondrop="newTabButtonObserver.onDrop(event)"
-                     ondragover="newTabButtonObserver.onDragOver(event)"
-                     ondragenter="newTabButtonObserver.onDragOver(event)"
-                     ondragexit="newTabButtonObserver.onDragExit(event)"
-                     removable="true"/>
-
-      <toolbarbutton id="alltabs-button"
-                     class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button"
-                     type="menu"
-                     label="&listAllTabs.label;"
-                     tooltiptext="&listAllTabs.label;"
-                     removable="true">
-        <menupopup id="alltabs-popup"
-                   position="after_end">
-          <menuitem id="menu_tabview"
-                    class="menuitem-iconic"
-                    key="key_tabview"
-                    label="&viewTabGroups.label;"
-                    command="Browser:ToggleTabView"
-                    observes="tabviewGroupsNumber"/>
-          <menuseparator id="alltabs-popup-separator"/>
-        </menupopup>
-      </toolbarbutton>
-
-      <toolbarbutton id="tabs-closebutton"
-                     class="close-button tabs-closebutton"
-                     command="cmd_close"
-                     label="&closeTab.label;"
-                     tooltiptext="&closeTab.label;"/>
-
-#ifdef CAN_DRAW_IN_TITLEBAR
-      <hbox class="titlebar-placeholder" type="appmenu-button" ordinal="0"/>
-      <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/>
-#endif
+    <!-- This is a shim which will go away ASAP. See bug 749804 for details -->
+    <toolbar id="addon-bar" toolbar-delegate="nav-bar">
+      <hbox id="addonbar-closebutton"/>
+      <statusbar id="status-bar"/>
     </toolbar>
 
     <toolbarpalette id="BrowserToolbarPalette">
@@ -919,31 +969,13 @@
 # or removing default items with the toolbarbutton-1 class.
 
       <toolbarbutton id="print-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&printButton.label;" command="cmd_print"
-                     tooltiptext="&printButton.tooltip;"/>
-
-      <!-- This is a placeholder for the Downloads Indicator.  It is visible
-           during the customization of the toolbar, in the palette, and before
-           the Downloads Indicator overlay is loaded. -->
-      <toolbarbutton id="downloads-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     oncommand="DownloadsIndicatorView.onCommand(event);"
-                     ondrop="DownloadsIndicatorView.onDrop(event);"
-                     ondragover="DownloadsIndicatorView.onDragOver(event);"
-                     ondragenter="DownloadsIndicatorView.onDragOver(event);"
-                     label="&downloads.label;"
-                     tooltiptext="&downloads.tooltip;"/>
-
-      <toolbarbutton id="history-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     observes="viewHistorySidebar" label="&historyButton.label;"
-                     tooltiptext="&historyButton.tooltip;"/>
-
-      <toolbarbutton id="bookmarks-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     observes="viewBookmarksSidebar"
-                     tooltiptext="&bookmarksButton.tooltip;"
-                     ondrop="bookmarksButtonObserver.onDrop(event)"
-                     ondragover="bookmarksButtonObserver.onDragOver(event)"
-                     ondragenter="bookmarksButtonObserver.onDragOver(event)"
-                     ondragexit="bookmarksButtonObserver.onDragExit(event)"/>
+#ifdef XP_MACOSX
+                     command="cmd_print"
+#else
+                     command="cmd_printPreview"
+#endif
+                     label="&printButton.label;" tooltiptext="&printButton.tooltip;"/>
+
 
       <toolbarbutton id="new-window-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&newNavigatorCmd.label;"
@@ -960,47 +992,6 @@
                      label="&fullScreenCmd.label;"
                      tooltiptext="&fullScreenButton.tooltip;"/>
 
-      <toolbaritem id="zoom-controls" class="chromeclass-toolbar-additional"
-                   title="&zoomControls.label;">
-        <toolbarbutton id="zoom-out-button" class="toolbarbutton-1"
-                       label="&fullZoomReduceCmd.label;"
-                       command="cmd_fullZoomReduce"
-                       tooltiptext="&zoomOutButton.tooltip;"/>
-        <toolbarbutton id="zoom-in-button" class="toolbarbutton-1"
-                       label="&fullZoomEnlargeCmd.label;"
-                       command="cmd_fullZoomEnlarge"
-                       tooltiptext="&zoomInButton.tooltip;"/>
-      </toolbaritem>
-
-      <toolbarbutton id="feed-button"
-                     type="menu"
-                     class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     disabled="true"
-                     label="&feedButton.label;"
-                     tooltiptext="&feedButton.tooltip;"
-                     onclick="return FeedHandler.onFeedButtonClick(event);">
-        <menupopup position="after_end"
-                   id="feed-menu"
-                   onpopupshowing="return FeedHandler.buildFeedList(this);"
-                   oncommand="return FeedHandler.subscribeToFeed(null, event);"
-                   onclick="checkForMiddleClick(this, event);"/>
-      </toolbarbutton>
-
-      <toolbarbutton id="cut-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&cutCmd.label;"
-                     command="cmd_cut"
-                     tooltiptext="&cutButton.tooltip;"/>
-
-      <toolbarbutton id="copy-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&copyCmd.label;"
-                     command="cmd_copy"
-                     tooltiptext="&copyButton.tooltip;"/>
-
-      <toolbarbutton id="paste-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&pasteCmd.label;"
-                     command="cmd_paste"
-                     tooltiptext="&pasteButton.tooltip;"/>
-
 #ifdef MOZ_SERVICES_SYNC
       <toolbarbutton id="sync-button"
                      class="toolbarbutton-1 chromeclass-toolbar-additional"
@@ -1008,11 +999,6 @@
                      oncommand="gSyncUI.handleToolbarButton()"/>
 #endif
 
-      <toolbaritem id="navigator-throbber" title="&throbberItem.title;" align="center" pack="center"
-                   mousethrough="always">
-        <image/>
-      </toolbaritem>
-
       <toolbarbutton id="tabview-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&tabGroupsButton.label;"
                      command="Browser:ToggleTabView"
@@ -1023,46 +1009,50 @@
 
   <hbox id="fullscr-toggler" collapsed="true"/>
 
-  <hbox flex="1" id="browser">
-    <vbox id="browser-border-start" hidden="true" layer="true"/>
-    <vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">
-      <sidebarheader id="sidebar-header" align="center">
-        <label id="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/>
-        <image id="sidebar-throbber"/>
-        <toolbarbutton class="tabs-closebutton" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="toggleSidebar();"/>
-      </sidebarheader>
-      <browser id="sidebar" flex="1" autoscroll="false" disablehistory="true"
-                style="min-width: 14em; width: 18em; max-width: 36em;"/>
-    </vbox>
-
-    <splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
-    <vbox id="appcontent" flex="1">
-      <tabbrowser id="content"
-                  flex="1" contenttooltip="aHTMLTooltip"
-                  tabcontainer="tabbrowser-tabs"
-                  contentcontextmenu="contentAreaContextMenu"
-                  autocompletepopup="PopupAutoComplete"
-                  selectpopup="ContentSelectDropdown"/>
-      <chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/>
-    </vbox>
-    <splitter id="social-sidebar-splitter"
-              class="chromeclass-extrachrome sidebar-splitter"
-              observes="socialSidebarBroadcaster"/>
-    <vbox id="social-sidebar-box"
-          class="chromeclass-extrachrome"
-          observes="socialSidebarBroadcaster"
-          persist="width">
-      <browser id="social-sidebar-browser"
-               type="content"
-               context="contentAreaContextMenu"
-               disableglobalhistory="true"
-               tooltip="aHTMLTooltip"
+  <deck id="content-deck" flex="1">
+    <hbox flex="1" id="browser">
+      <vbox id="browser-border-start" hidden="true" layer="true"/>
+      <vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">
+        <sidebarheader id="sidebar-header" align="center">
+          <label id="sidebar-title" persist="value" flex="1" crop="end" control="sidebar"/>
+          <image id="sidebar-throbber"/>
+          <toolbarbutton class="tabs-closebutton close-icon" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="toggleSidebar();"/>
+        </sidebarheader>
+        <browser id="sidebar" flex="1" autoscroll="false" disablehistory="true"
+                  style="min-width: 14em; width: 18em; max-width: 36em;"/>
+      </vbox>
+
+      <splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
+      <vbox id="appcontent" flex="1">
+        <tabbrowser id="content"
+                    flex="1" contenttooltip="aHTMLTooltip"
+                    tabcontainer="tabbrowser-tabs"
+                    contentcontextmenu="contentAreaContextMenu"
+                    autocompletepopup="PopupAutoComplete"
+                    selectpopup="ContentSelectDropdown"
+                    onclick="contentAreaClick(event, false);"/>
+        <chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/>
+      </vbox>
+      <splitter id="social-sidebar-splitter"
+                class="chromeclass-extrachrome sidebar-splitter"
+                observes="socialSidebarBroadcaster"/>
+      <vbox id="social-sidebar-box"
+            class="chromeclass-extrachrome"
+            observes="socialSidebarBroadcaster"
+            persist="width">
+        <browser id="social-sidebar-browser"
+                 type="content"
+                 context="contentAreaContextMenu"
+                 disableglobalhistory="true"
+                 tooltip="aHTMLTooltip"
                popupnotificationanchor="social-notification-icon"
-               flex="1"
-               style="min-width: 14em; width: 18em; max-width: 36em;"/>
-    </vbox>
-    <vbox id="browser-border-end" hidden="true" layer="true"/>
-  </hbox>
+                 flex="1"
+                 style="min-width: 14em; width: 18em; max-width: 36em;"/>
+      </vbox>
+      <vbox id="browser-border-end" hidden="true" layer="true"/>
+    </hbox>
+#include ../../components/customizableui/content/customizeMode.inc.xul
+  </deck>
 
   <hbox id="full-screen-warning-container" hidden="true" fadeout="true">
     <hbox style="width: 100%;" pack="center"> <!-- Inner hbox needed due to bug 579776. -->
@@ -1119,56 +1109,28 @@
                          tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
 #endif
    </toolbar>
-
-    <toolbar id="addon-bar"
-             toolbarname="&addonBarCmd.label;" accesskey="&addonBarCmd.accesskey;"
-             collapsed="true"
-             class="toolbar-primary chromeclass-toolbar"
-             context="toolbar-context-menu" toolboxid="navigator-toolbox"
-             mode="icons" iconsize="small" defaulticonsize="small"
-             lockiconsize="true"
-             defaultset="addonbar-closebutton,spring,status-bar"
-             customizable="true"
-             key="key_toggleAddonBar">
-      <toolbarbutton id="addonbar-closebutton"
-                     tooltiptext="&addonBarCloseButton.tooltip;"
-                     oncommand="setToolbarVisibility(this.parentNode, false);"/>
-      <statusbar id="status-bar" ordinal="1000"/>
-    </toolbar>
   </vbox>
 
-#ifndef XP_UNIX
   <svg:svg height="0">
+#include tab-shape.inc.svg
+
+#ifndef XP_UNIX
     <svg:clipPath id="windows-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
       <svg:path d="M 0,0 C 0.16,0.11 0.28,0.29 0.28,0.5 0.28,0.71 0.16,0.89 0,1 L 1,1 1,0 0,0 z"/>
     </svg:clipPath>
     <svg:clipPath id="windows-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
-      <svg:path d="M 0,0 0,7.8 C 2.5,11 4,14 4,18 4,22 2.5,25 0,28 l 0,22 10000,0 0,-50 L 0,0 z"/>
+      <svg:path d="m 0,-5 l 0,7.8 c 2.5,3.2 4,6.2 4,10.2 c 0,4 -1.5,7 -4,10 l 0,22l10000,0 l 0,-50 l -10000,0 z"/>
     </svg:clipPath>
-  </svg:svg>
 #endif
 #ifdef XP_MACOSX
-  <svg:svg height="0">
     <svg:clipPath id="osx-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
       <svg:path d="M 0,0 C 0.15,0.12 0.25,0.3 0.25,0.5 0.25,0.7 0.15,0.88 0,1 L 1,1 1,0 0,0 z"/>
     </svg:clipPath>
     <svg:clipPath id="osx-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
-      <svg:path d="m 0,-5 0,4.03 C 3.6,1.8 6,6.1 6,11 6,16 3.6,20 0,23 l 0,27 10000,0 0,-55 L 0,-5 z"/>
-    </svg:clipPath>
-    <svg:clipPath id="osx-tab-ontop-left-curve-clip-path" clipPathUnits="userSpaceOnUse">
-      <svg:path d="M 9,0 C 7.3,0 6,1.3 6,3 l 0,14 c 0,3 -2.2,5 -5,5 l -1,0 0,1 12,0 0,-1 0,-19 0,-3 -3,0 z"/>
-    </svg:clipPath>
-    <svg:clipPath id="osx-tab-ontop-right-curve-clip-path" clipPathUnits="userSpaceOnUse">
-      <svg:path d="m 0,0 0,3 0,19 0,1 12,0 0,-1 -1,0 C 8.2,22 6,20 6,17 L 6,3 C 6,1.3 4.7,0 3,0 L 0,0 z"/>
-    </svg:clipPath>
-    <svg:clipPath id="osx-tab-onbottom-left-curve-clip-path" clipPathUnits="userSpaceOnUse">
-      <svg:path d="m 0,0 0,1 1,0 c 2.8,0 5,2.2 5,5 l 0,14 c 0,2 1.3,3 3,3 l 3,0 0,-3 L 12,1 12,0 0,0 z"/>
+      <svg:path d="m -3,-10 l -0.1,7.7 c 6.6,1.8 8.8,7.6 8.8,12.5 c 0,5 -1.9,11.5 -8.25,13.25 l 0.05,25.75 l 10000,0 l 0,-55 l -10000,-4.2 z"/>
     </svg:clipPath>
-    <svg:clipPath id="osx-tab-onbottom-right-curve-clip-path" clipPathUnits="userSpaceOnUse">
-      <svg:path d="m 0,0 0,1 0,19 0,3 3,0 c 1.7,0 3,-1 3,-3 L 6,6 C 6,3.2 8.2,1 11,1 L 12,1 12,0 0,0 z"/>
-    </svg:clipPath>
-  </svg:svg>
 #endif
+  </svg:svg>
 
 </vbox>
 # <iframe id="tab-view"> is dynamically appended as the 2nd child of #tab-view-deck.
diff --git a/browser/base/content/global-scripts.inc b/browser/base/content/global-scripts.inc
index b4de574ae922eab322043d586562b16c6b1c9d90..22b61aeae84d84b71fddc6be2b57e735dd5559da 100755
--- a/browser/base/content/global-scripts.inc
+++ b/browser/base/content/global-scripts.inc
@@ -9,5 +9,6 @@
 <script type="application/javascript" src="chrome://browser/content/browser.js"/>
 <script type="application/javascript" src="chrome://browser/content/downloads/downloads.js"/>
 <script type="application/javascript" src="chrome://browser/content/downloads/indicator.js"/>
+<script type="application/javascript" src="chrome://browser/content/customizableui/panelUI.js"/>
 <script type="application/javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
 <script type="application/javascript" src="chrome://global/content/viewSourceUtils.js"/>
diff --git a/browser/base/content/newtab/newTab.xul b/browser/base/content/newtab/newTab.xul
index bab2c28e79cbad621a6ab7193b51aeb496843e8c..6fc202f296eff827dc4d4bdd798d4e874f51ea50 100644
--- a/browser/base/content/newtab/newTab.xul
+++ b/browser/base/content/newtab/newTab.xul
@@ -31,6 +31,7 @@
                       label="&newtab.undo.restoreButton;"
                       class="newtab-undo-button" />
           <xul:toolbarbutton id="newtab-undo-close-button" tabindex="-1"
+                             class="close-icon"
                              tooltiptext="&newtab.undo.closeTooltip;" />
         </div>
       </div>
diff --git a/browser/base/content/sync/notification.xml b/browser/base/content/sync/notification.xml
index 94e83f14181748c995e603f127b31c4c669819b2..7a2b773821cf482f477cd11d2b65ea6dcbc92bf7 100644
--- a/browser/base/content/sync/notification.xml
+++ b/browser/base/content/sync/notification.xml
@@ -83,7 +83,7 @@
     <content>
       <xul:hbox class="notification-inner outset" flex="1" xbl:inherits="type">
         <xul:toolbarbutton ondblclick="event.stopPropagation();"
-                           class="messageCloseButton tabbable"
+                           class="messageCloseButton close-icon tabbable"
                            xbl:inherits="hidden=hideclose"
                            tooltiptext="&closeNotification.tooltip;"
                            oncommand="document.getBindingParent(this).close()"/>
diff --git a/browser/base/content/tab-shape.inc.svg b/browser/base/content/tab-shape.inc.svg
new file mode 100644
index 0000000000000000000000000000000000000000..f97889389e21f98087c4f7c17e4aa494bf6282d6
--- /dev/null
+++ b/browser/base/content/tab-shape.inc.svg
@@ -0,0 +1,11 @@
+<!-- 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/. -->
+
+<svg:clipPath id="tab-curve-clip-path-start" clipPathUnits="objectBoundingBox">
+  <svg:path d="m 1,0.0625 0.05,0 0,0.938 -1,0 0,-0.028 C 0.32082458,0.95840561 0.4353096,0.81970962 0.48499998,0.5625 0.51819998,0.3905 0.535,0.0659 1,0.0625 z"/>
+</svg:clipPath>
+
+<svg:clipPath id="tab-curve-clip-path-end" clipPathUnits="objectBoundingBox">
+  <svg:path d="m 0,0.0625 -0.05,0 0,0.938 1,0 0,-0.028 C 0.67917542,0.95840561 0.56569036,0.81970962 0.51599998,0.5625 0.48279998,0.3905 0.465,0.0659 0,0.0625 z"/>
+</svg:clipPath>
diff --git a/browser/base/content/tabbrowser.css b/browser/base/content/tabbrowser.css
index 2dd6a05297c86438453509be8ed1693ffac289fe..e47e3d6e428786a6b5148e8ef6c0c25c6dde89a0 100644
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -41,6 +41,7 @@ tabpanels {
   z-index: 2;
 }
 
+.tab-icon-image:not([src]):not([pinned]),
 .tab-throbber:not([busy]),
 .tab-throbber[busy] + .tab-icon-image {
   display: none;
diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml
index 999509c21e8012b708473ac0e4b4423770cbb63f..98735de61cbe3d00a4fd50eee2383c9197600485 100644
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -207,8 +207,7 @@
           if (!window.gShowPageResizers)
             return;
 
-          var show = document.getElementById("addon-bar").collapsed &&
-                     window.windowState == window.STATE_NORMAL;
+          var show = window.windowState == window.STATE_NORMAL;
           for (let i = 0; i < this.browsers.length; i++) {
             this.browsers[i].showWindowResizer = show;
           }
@@ -999,7 +998,7 @@
             this.mCurrentTab = this.tabContainer.selectedItem;
             this.showTab(this.mCurrentTab);
 
-            var backForwardContainer = document.getElementById("unified-back-forward-button");
+            var backForwardContainer = document.getElementById("urlbar-container");
             if (backForwardContainer) {
               backForwardContainer.setAttribute("switchingtabs", "true");
               window.addEventListener("MozAfterPaint", function removeSwitchingtabsAttr() {
@@ -1500,8 +1499,7 @@
             if (remote)
               b.setAttribute("remote", "true");
 
-            if (window.gShowPageResizers && document.getElementById("addon-bar").collapsed &&
-                window.windowState == window.STATE_NORMAL) {
+            if (window.gShowPageResizers && window.windowState == window.STATE_NORMAL) {
               b.setAttribute("showresizer", "true");
             }
 
@@ -1927,6 +1925,11 @@
             aTab.closing = true;
             this._removingTabs.push(aTab);
             this._visibleTabs = null; // invalidate cache
+
+            // Invalidate hovered tab state tracking for this closing tab.
+            if (this.tabContainer._hoveredTab == aTab)
+              aTab._mouseleave();
+
             if (newTab)
               this.addTab(BROWSER_NEW_TAB_URL, {skipAnimation: true});
             else
@@ -3245,6 +3248,28 @@
           return !tab.pinned && !tab.hidden;
         ]]></body>
       </method>
+      <field name="_tabMarginLeft">null</field>
+      <field name="_tabMarginRight">null</field>
+      <method name="_adjustElementStartAndEnd">
+        <parameter name="aTab"/>
+        <parameter name="tabStart"/>
+        <parameter name="tabEnd"/>
+        <body><![CDATA[
+          if (this._tabMarginLeft === null || this._tabMarginRight === null) {
+            let tabMiddle = document.getAnonymousElementByAttribute(aTab, "class", "tab-background-middle");
+            let tabMiddleStyle = window.getComputedStyle(tabMiddle, null);
+            this._tabMarginLeft = parseFloat(tabMiddleStyle.marginLeft);
+            this._tabMarginRight = parseFloat(tabMiddleStyle.marginRight);
+          }
+          if (this._tabMarginLeft < 0) {
+            tabStart = tabStart + this._tabMarginLeft;
+          }
+          if (this._tabMarginRight < 0) {
+            tabEnd = tabEnd - this._tabMarginRight;
+          }
+          return [tabStart, tabEnd];
+        ]]></body>
+      </method>
     </implementation>
 
     <handlers>
@@ -3266,8 +3291,11 @@
       <handler event="overflow"><![CDATA[
         if (event.detail == 0)
           return; // Ignore vertical events
-
         var tabs = document.getBindingParent(this);
+        var numberOfTabs = tabs.tabbrowser.visibleTabs.length;
+        if (numberOfTabs == 1)
+          return;
+
         tabs.setAttribute("overflow", "true");
         tabs._positionPinnedTabs();
         tabs._handleTabSelect(false);
@@ -3364,6 +3392,15 @@
       <field name="_afterSelectedTab">null</field>
       <field name="_beforeHoveredTab">null</field>
       <field name="_afterHoveredTab">null</field>
+      <field name="_hoveredTab">null</field>
+
+      <property name="_isCustomizing" readonly="true">
+        <getter>
+          let root = document.documentElement;
+          return root.getAttribute("customizing") == "true" ||
+                 root.getAttribute("customize-exiting") == "true";
+        </getter>
+      </property>
 
       <method name="_setPositionalAttributes">
         <body><![CDATA[
@@ -3394,6 +3431,12 @@
             this._lastTab.removeAttribute("last-visible-tab");
           this._lastTab = visibleTabs[lastVisible];
           this._lastTab.setAttribute("last-visible-tab", "true");
+
+          let hoveredTab = this._hoveredTab;
+          if (hoveredTab) {
+            hoveredTab._mouseleave();
+            hoveredTab._mouseenter();
+          }
         ]]></body>
       </method>
 
@@ -3472,10 +3515,6 @@
           document.getElementById("menu_close").setAttribute("label",
             this.tabbrowser.mStringBundle.getString(visible ? "tabs.closeTab" : "tabs.close"));
 
-          goSetCommandEnabled("cmd_ToggleTabsOnTop", visible);
-
-          TabsOnTop.syncUI();
-
           TabsInTitlebar.allowedBy("tabs-visible", visible);
         ]]></body>
       </method>
@@ -3827,16 +3866,16 @@
               if (aEvent.target != window)
                 break;
 
-              let sizemode = document.documentElement.getAttribute("sizemode");
-              TabsInTitlebar.allowedBy("sizemode",
-                                       sizemode == "maximized" || sizemode == "fullscreen");
+              TabsInTitlebar.updateAppearance();
 
-              var width = this.mTabstrip.boxObject.width;
-              if (width != this.mTabstripWidth) {
-                this.adjustTabstrip();
-                this._fillTrailingGap();
-                this._handleTabSelect();
-                this.mTabstripWidth = width;
+              if (this.tabbrowser.visibleTabs.length > 1) {
+                var width = this.mTabstrip.boxObject.width;
+                if (width != this.mTabstripWidth) {
+                  this.adjustTabstrip();
+                  this._fillTrailingGap();
+                  this._handleTabSelect();
+                  this.mTabstripWidth = width;
+                }
               }
 
               this.tabbrowser.updateWindowResizers();
@@ -4130,8 +4169,7 @@
         // When the tabbar has an unified appearance with the titlebar
         // and menubar, a double-click in it should have the same behavior
         // as double-clicking the titlebar
-        if (TabsInTitlebar.enabled ||
-            (TabsOnTop.enabled && this.parentNode._dragBindingAlive))
+        if (TabsInTitlebar.enabled || this.parentNode._dragBindingAlive)
           return;
 #endif
 
@@ -4254,7 +4292,7 @@
 
       <handler event="dragstart"><![CDATA[
         var tab = this._getDragTargetTab(event);
-        if (!tab)
+        if (!tab || this._isCustomizing)
           return;
 
         let dt = event.dataTransfer;
@@ -4498,7 +4536,7 @@
 
         var dt = event.dataTransfer;
         var draggedTab = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
-        if (dt.mozUserCancelled || dt.dropEffect != "none") {
+        if (dt.mozUserCancelled || dt.dropEffect != "none" || this._isCustomizing) {
           delete draggedTab._dragData;
           return;
         }
@@ -4630,7 +4668,7 @@
                      role="presentation"/>
           <xul:toolbarbutton anonid="close-button"
                              xbl:inherits="fadein,pinned,selected"
-                             class="tab-close-button"/>
+                             class="tab-close-button close-icon"/>
         </xul:hbox>
       </xul:stack>
     </content>
@@ -4651,6 +4689,54 @@
       <field name="mCorrespondingMenuitem">null</field>
       <field name="closing">false</field>
       <field name="lastAccessed">0</field>
+
+      <method name="_mouseenter">
+        <body><![CDATA[
+          if (this.closing)
+            return;
+
+          let tabContainer = this.parentNode;
+          let visibleTabs = tabContainer.tabbrowser.visibleTabs;
+          let tabIndex = visibleTabs.indexOf(this);
+          if (tabIndex == 0) {
+            tabContainer._beforeHoveredTab = null;
+          } else {
+            let candidate = visibleTabs[tabIndex - 1];
+            if (!candidate.selected) {
+              tabContainer._beforeHoveredTab = candidate;
+              candidate.setAttribute("beforehovered", "true");
+            }
+          }
+
+          if (tabIndex == visibleTabs.length - 1) {
+            tabContainer._afterHoveredTab = null;
+          } else {
+            let candidate = visibleTabs[tabIndex + 1];
+            if (!candidate.selected) {
+              tabContainer._afterHoveredTab = candidate;
+              candidate.setAttribute("afterhovered", "true");
+            }
+          }
+
+          tabContainer._hoveredTab = this;
+        ]]></body>
+      </method>
+
+      <method name="_mouseleave">
+        <body><![CDATA[
+          let tabContainer = this.parentNode;
+          if (tabContainer._beforeHoveredTab) {
+            tabContainer._beforeHoveredTab.removeAttribute("beforehovered");
+            tabContainer._beforeHoveredTab = null;
+          }
+          if (tabContainer._afterHoveredTab) {
+            tabContainer._afterHoveredTab.removeAttribute("afterhovered");
+            tabContainer._afterHoveredTab = null;
+          }
+
+          tabContainer._hoveredTab = null;
+        ]]></body>
+      </method>
     </implementation>
 
     <handlers>
@@ -4659,47 +4745,14 @@
         if (anonid == "close-button")
           this.mOverCloseButton = true;
 
-        let tab = event.target;
-        if (tab.closing)
-          return;
-
-        let tabContainer = this.parentNode;
-        let visibleTabs = tabContainer.tabbrowser.visibleTabs;
-        let tabIndex = visibleTabs.indexOf(tab);
-        if (tabIndex == 0) {
-          tabContainer._beforeHoveredTab = null;
-        } else {
-          let candidate = visibleTabs[tabIndex - 1];
-          if (!candidate.selected) {
-            tabContainer._beforeHoveredTab = candidate;
-            candidate.setAttribute("beforehovered", "true");
-          }
-        }
-
-        if (tabIndex == visibleTabs.length - 1) {
-          tabContainer._afterHoveredTab = null;
-        } else {
-          let candidate = visibleTabs[tabIndex + 1];
-          if (!candidate.selected) {
-            tabContainer._afterHoveredTab = candidate;
-            candidate.setAttribute("afterhovered", "true");
-          }
-        }
+        this._mouseenter();
       ]]></handler>
       <handler event="mouseout"><![CDATA[
         let anonid = event.originalTarget.getAttribute("anonid");
         if (anonid == "close-button")
           this.mOverCloseButton = false;
 
-        let tabContainer = this.parentNode;
-        if (tabContainer._beforeHoveredTab) {
-          tabContainer._beforeHoveredTab.removeAttribute("beforehovered");
-          tabContainer._beforeHoveredTab = null;
-        }
-        if (tabContainer._afterHoveredTab) {
-          tabContainer._afterHoveredTab.removeAttribute("afterhovered");
-          tabContainer._afterHoveredTab = null;
-        }
+        this._mouseleave();
       ]]></handler>
       <handler event="dragstart" phase="capturing">
         this.style.MozUserFocus = '';
diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini
index 31b315a464427b4b7304d717b1badd95a2c93b04..232ccb7ea8ed96a7570df149b2065984bbc059f8 100644
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -17,7 +17,6 @@ support-files =
   bug792517.html
   bug792517.sjs
   bug839103.css
-  disablechrome.html
   discovery.html
   domplate_test.js
   download_page.html
@@ -105,9 +104,6 @@ run-if = crashreporter
 [browser_aboutHome.js]
 [browser_aboutSyncProgress.js]
 [browser_addKeywordSearch.js]
-[browser_addon_bar_aomlistener.js]
-[browser_addon_bar_close_button.js]
-[browser_addon_bar_shortcut.js]
 [browser_alltabslistener.js]
 [browser_blob-channelname.js]
 [browser_bookmark_titles.js]
@@ -188,10 +184,7 @@ run-if = toolkit == "cocoa"
 [browser_bug595507.js]
 [browser_bug596687.js]
 [browser_bug597218.js]
-[browser_bug598923.js]
-[browser_bug599325.js]
 [browser_bug609700.js]
-[browser_bug616836.js]
 [browser_bug623155.js]
 [browser_bug623893.js]
 [browser_bug624734.js]
@@ -238,11 +231,9 @@ run-if = toolkit == "cocoa"
 [browser_contentAreaClick.js]
 [browser_contextSearchTabPosition.js]
 [browser_ctrlTab.js]
-[browser_customize.js]
 [browser_customize_popupNotification.js]
 [browser_datareporting_notification.js]
 run-if = datareporting
-[browser_disablechrome.js]
 [browser_discovery.js]
 [browser_duplicateIDs.js]
 [browser_drag.js]
@@ -304,6 +295,9 @@ skip-if = true  # disabled until the tree view is added
 [browser_tab_dragdrop.js]
 [browser_tab_dragdrop2.js]
 [browser_tab_dragdrop2_frame1.xul]
+[browser_tabbar_big_widgets.js]
+skip-if = os == "linux" # No tabs in titlebar on linux
+
 [browser_tabfocus.js]
 [browser_tabopen_reflows.js]
 [browser_tabs_isActive.js]
@@ -325,6 +319,7 @@ skip-if = true  # disabled until the tree view is added
 [browser_visibleTabs_bookmarkAllTabs.js]
 [browser_visibleTabs_contextMenu.js]
 [browser_visibleTabs_tabPreview.js]
+[browser_windowopen_reflows.js]
 [browser_wyciwyg_urlbarCopying.js]
 [browser_zbug569342.js]
 [browser_registerProtocolHandler_notification.js]
diff --git a/browser/base/content/test/general/browser_addon_bar.js b/browser/base/content/test/general/browser_addon_bar.js
deleted file mode 100644
index 3607eb1220cb323c1a883e6a3e4d736c04ad2de6..0000000000000000000000000000000000000000
--- a/browser/base/content/test/general/browser_addon_bar.js
+++ /dev/null
@@ -1,63 +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/. */
-
-function test() {
-  waitForExplicitFinish();
-
-  let addonbar = document.getElementById("addon-bar");
-  ok(addonbar.collapsed, "addon bar is collapsed by default");
-
-  let topMenu, toolbarMenu;
-
-  function onTopMenuShown(event) {
-    ok(1, "top menu popupshown listener called");
-    event.currentTarget.removeEventListener("popupshown", arguments.callee, false);
-    // open the customize or toolbars menu
-    toolbarMenu = document.getElementById("appmenu_customizeMenu") ||
-                      document.getElementById("viewToolbarsMenu").firstElementChild;
-    toolbarMenu.addEventListener("popupshown", onToolbarMenuShown, false);
-    toolbarMenu.addEventListener("popuphidden", onToolbarMenuHidden, false);
-    toolbarMenu.openPopup();
-  }
-
-  function onTopMenuHidden(event) {
-    ok(1, "top menu popuphidden listener called");
-    event.currentTarget.removeEventListener("popuphidden", arguments.callee, false);
-    finish();
-  }
-
-  function onToolbarMenuShown(event) {
-    ok(1, "sub menu popupshown listener called");
-    event.currentTarget.removeEventListener("popupshown", arguments.callee, false);
-
-    // test the menu item's default state
-    let menuitem = document.getElementById("toggle_addon-bar");
-    ok(menuitem, "found the menu item");
-    is(menuitem.getAttribute("checked"), "false", "menuitem is not checked by default");
-
-    // click on the menu item
-    // TODO: there's got to be a way to check+command in one shot
-    menuitem.setAttribute("checked", "true");
-    menuitem.click();
-
-    // now the addon bar should be visible and the menu checked
-    is(addonbar.getAttribute("collapsed"), "false", "addon bar is visible after executing the command");
-    is(menuitem.getAttribute("checked"), "true", "menuitem is checked after executing the command");
-
-    toolbarMenu.hidePopup();
-  }
-
-  function onToolbarMenuHidden(event) {
-    ok(1, "toolbar menu popuphidden listener called");
-    event.currentTarget.removeEventListener("popuphidden", arguments.callee, false);
-    topMenu.hidePopup();
-  }
-
-  // open the appmenu or view menu
-  topMenu = document.getElementById("appmenu-popup") ||
-            document.getElementById("menu_viewPopup");
-  topMenu.addEventListener("popupshown", onTopMenuShown, false);
-  topMenu.addEventListener("popuphidden", onTopMenuHidden, false);
-  topMenu.openPopup();
-}
diff --git a/browser/base/content/test/general/browser_addon_bar_aomlistener.js b/browser/base/content/test/general/browser_addon_bar_aomlistener.js
deleted file mode 100644
index 75a539e0727492da7d378cbe614139a9547be103..0000000000000000000000000000000000000000
--- a/browser/base/content/test/general/browser_addon_bar_aomlistener.js
+++ /dev/null
@@ -1,67 +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/. */
-
-function test() {
-
-  let addonbar = document.getElementById("addon-bar");
-  ok(addonbar.collapsed, "addon bar is collapsed by default");
-
-  function addItem(id) {
-    let button = document.createElement("toolbarbutton");
-    button.id = id;
-    let palette = document.getElementById("navigator-toolbox").palette;
-    palette.appendChild(button);
-    addonbar.insertItem(id, null, null, false);
-  }
-
-  // call onInstalling
-  AddonsMgrListener.onInstalling();
-
-  // add item to the bar
-  let id = "testbutton";
-  addItem(id);
-
-  // call onInstalled
-  AddonsMgrListener.onInstalled();
-
-  // confirm bar is visible
-  ok(!addonbar.collapsed, "addon bar is not collapsed after toggle");
-
-  // call onUninstalling
-  AddonsMgrListener.onUninstalling();
-
-  // remove item from the bar
-  addonbar.currentSet = addonbar.currentSet.replace("," + id, "");
-
-  // call onUninstalled
-  AddonsMgrListener.onUninstalled();
-
-  // confirm bar is not visible
-  ok(addonbar.collapsed, "addon bar is collapsed after toggle");
-
-  // call onEnabling
-  AddonsMgrListener.onEnabling();
-
-  // add item to the bar
-  let id = "testbutton";
-  addItem(id);
-
-  // call onEnabled
-  AddonsMgrListener.onEnabled();
-
-  // confirm bar is visible
-  ok(!addonbar.collapsed, "addon bar is not collapsed after toggle");
-
-  // call onDisabling
-  AddonsMgrListener.onDisabling();
-
-  // remove item from the bar
-  addonbar.currentSet = addonbar.currentSet.replace("," + id, "");
-
-  // call onDisabled
-  AddonsMgrListener.onDisabled();
-
-  // confirm bar is not visible
-  ok(addonbar.collapsed, "addon bar is collapsed after toggle");
-}
diff --git a/browser/base/content/test/general/browser_addon_bar_close_button.js b/browser/base/content/test/general/browser_addon_bar_close_button.js
deleted file mode 100644
index 7d3afb333ba5469fbd8f6469b5991c94ad15bdb0..0000000000000000000000000000000000000000
--- a/browser/base/content/test/general/browser_addon_bar_close_button.js
+++ /dev/null
@@ -1,19 +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/. */
-
-function test() {
-  let addonbar = document.getElementById("addon-bar");
-  ok(addonbar.collapsed, "addon bar is collapsed by default");
-
-  // make add-on bar visible
-  setToolbarVisibility(addonbar, true);
-  ok(!addonbar.collapsed, "addon bar is not collapsed after toggle");
-
-  // click the close button
-  let closeButton = document.getElementById("addonbar-closebutton");
-  EventUtils.synthesizeMouseAtCenter(closeButton, {});
-
-  // confirm addon bar is closed
-  ok(addonbar.collapsed, "addon bar is collapsed after clicking close button");
-}
diff --git a/browser/base/content/test/general/browser_addon_bar_shortcut.js b/browser/base/content/test/general/browser_addon_bar_shortcut.js
deleted file mode 100644
index 847f967214c59f1245639f090afed6b64149568a..0000000000000000000000000000000000000000
--- a/browser/base/content/test/general/browser_addon_bar_shortcut.js
+++ /dev/null
@@ -1,18 +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/. */
-
-function test() {
-  let addonbar = document.getElementById("addon-bar");
-  ok(addonbar.collapsed, "addon bar is collapsed by default");
-
-  // show the add-on bar
-  EventUtils.synthesizeKey("/", { accelKey: true }, window);
-  ok(!addonbar.collapsed, "addon bar is not collapsed after toggle");
-
-  // hide the add-on bar
-  EventUtils.synthesizeKey("/", { accelKey: true }, window);
-
-  // confirm addon bar is closed
-  ok(addonbar.collapsed, "addon bar is collapsed after toggle");
-}
diff --git a/browser/base/content/test/general/browser_bug462289.js b/browser/base/content/test/general/browser_bug462289.js
index fcde120ffc645d678d54e94e587bfbd62d0435df..eee46c01e117744c93548d2852ad78e5f7b8c32a 100644
--- a/browser/base/content/test/general/browser_bug462289.js
+++ b/browser/base/content/test/general/browser_bug462289.js
@@ -34,16 +34,9 @@ function step3()
   is(gBrowser.selectedTab, tab1, "2nd click on selected tab1 keeps tab selected");
   isnot(document.activeElement, tab1, "2nd click on selected tab1 does not activate tab");
 
-  if (gNavToolbox.getAttribute("tabsontop") == "true") {
-    ok(true, "[tabsontop=true] focusing URLBar then sending 1 Shift+Tab.");
-    gURLBar.focus();
-    EventUtils.synthesizeKey("VK_TAB", {shiftKey: true});
-  } else {
-    ok(true, "[tabsontop=false] focusing SearchBar then sending Tab(s) until out of nav-bar.");
-    document.getElementById("searchbar").focus();
-    while (focus_in_navbar())
-      EventUtils.synthesizeKey("VK_TAB", { });
-  }
+  ok(true, "focusing URLBar then sending 1 Shift+Tab.");
+  gURLBar.focus();
+  EventUtils.synthesizeKey("VK_TAB", {shiftKey: true});
   is(gBrowser.selectedTab, tab1, "tab key to selected tab1 keeps tab selected");
   is(document.activeElement, tab1, "tab key to selected tab1 activates tab");
 
diff --git a/browser/base/content/test/general/browser_bug598923.js b/browser/base/content/test/general/browser_bug598923.js
deleted file mode 100644
index 35e9c09f0d23355b02c29faa3889d2e09f35e07e..0000000000000000000000000000000000000000
--- a/browser/base/content/test/general/browser_bug598923.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// Test:
-// * if add-on is installed to the add-on bar, the bar is made visible.
-// * if add-on is uninstalled from the add-on bar, and no more add-ons there,
-//   the bar is hidden.
-
-function test() {
-  let aml = AddonsMgrListener;
-  ok(aml, "AddonsMgrListener exists");
-  // check is hidden
-  is(aml.addonBar.collapsed, true, "add-on bar is hidden initially");
-  // aob gets the count
-  AddonsMgrListener.onInstalling();
-  // add an item
-  let element = document.createElement("toolbaritem");
-  element.id = "bug598923-addon-item";
-  aml.addonBar.appendChild(element);
-  // aob checks the count, makes visible
-  AddonsMgrListener.onInstalled();
-  // check is visible
-  is(aml.addonBar.collapsed, false, "add-on bar has been made visible");
-  // aob gets the count
-  AddonsMgrListener.onUninstalling();
-  // remove an item
-  aml.addonBar.removeChild(element);
-  // aob checks the count, makes hidden
-  AddonsMgrListener.onUninstalled();
-  // check is hidden
-  is(aml.addonBar.collapsed, true, "add-on bar is hidden again");
-}
diff --git a/browser/base/content/test/general/browser_bug599325.js b/browser/base/content/test/general/browser_bug599325.js
deleted file mode 100644
index d721fc6632c79ee81cb84d37590c95d18e7c810c..0000000000000000000000000000000000000000
--- a/browser/base/content/test/general/browser_bug599325.js
+++ /dev/null
@@ -1,21 +0,0 @@
-function test() {
-  waitForExplicitFinish();
-
-  let addonBar = document.getElementById("addon-bar");
-  ok(addonBar, "got addon bar");
-  ok(!isElementVisible(addonBar), "addon bar initially hidden");
-
-  openToolbarCustomizationUI(function () {
-    ok(isElementVisible(addonBar),
-       "add-on bar is visible during toolbar customization");
-
-    closeToolbarCustomizationUI(onClose);
-  });
-
-  function onClose() {
-    ok(!isElementVisible(addonBar),
-       "addon bar is hidden after toolbar customization");
-
-    finish();
-  }
-}
diff --git a/browser/base/content/test/general/browser_bug616836.js b/browser/base/content/test/general/browser_bug616836.js
deleted file mode 100644
index efaaa837ab0fdb5ed953b27109e7b4c4d9b81070..0000000000000000000000000000000000000000
--- a/browser/base/content/test/general/browser_bug616836.js
+++ /dev/null
@@ -1,4 +0,0 @@
-function test() {
-  is(document.querySelectorAll("#appmenu-popup [accesskey]").length, 0,
-     "there should be no items with access keys in the app menu popup");
-}
diff --git a/browser/base/content/test/general/browser_bug624734.js b/browser/base/content/test/general/browser_bug624734.js
index 7d5caeea5e952bfcb84b816ec29998a5fe60ba85..7c5e5e31bd783b0253dce0a0b9f3601f755032f1 100644
--- a/browser/base/content/test/general/browser_bug624734.js
+++ b/browser/base/content/test/general/browser_bug624734.js
@@ -4,6 +4,15 @@
 
 // Bug 624734 - Star UI has no tooltip until bookmarked page is visited
 
+function finishTest() {
+  is(BookmarkingUI.button.getAttribute("buttontooltiptext"),
+     BookmarkingUI._unstarredTooltip,
+     "Star icon should have the unstarred tooltip text");
+
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
 function test() {
   waitForExplicitFinish();
 
@@ -11,12 +20,11 @@ function test() {
   tab.linkedBrowser.addEventListener("load", (function(event) {
     tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
 
-    is(BookmarkingUI.star.getAttribute("tooltiptext"),
-       BookmarkingUI._unstarredTooltip,
-       "Star icon should have the unstarred tooltip text");
-  
-    gBrowser.removeCurrentTab();
-    finish();
+    if (BookmarkingUI.status == BookmarkingUI.STATUS_UPDATING) {
+      waitForCondition(function() BookmarkingUI.status != BookmarkingUI.STATUS_UPDATING, finishTest, "BookmarkingUI was updating for too long");
+    } else {
+      finishTest();
+    }
   }), true);
 
   tab.linkedBrowser.loadURI("http://example.com/browser/browser/base/content/test/general/dummy_page.html");
diff --git a/browser/base/content/test/general/browser_customize.js b/browser/base/content/test/general/browser_customize.js
deleted file mode 100644
index 8cff36686ede7bbfabcadfb6804d2e3358cd7bd5..0000000000000000000000000000000000000000
--- a/browser/base/content/test/general/browser_customize.js
+++ /dev/null
@@ -1,24 +0,0 @@
-function test() {
-  waitForExplicitFinish();
-
-  openToolbarCustomizationUI(customizationWindowLoaded);
-}
-
-function customizationWindowLoaded(win) {
-  let x = win.screenX;
-  let iconModeList = win.document.getElementById("modelist");
-
-  iconModeList.addEventListener("popupshown", function popupshown() {
-    iconModeList.removeEventListener("popupshown", popupshown, false);
-
-    executeSoon(function () {
-      is(win.screenX, x,
-         "toolbar customization window shouldn't move when the iconmode menulist is opened");
-      iconModeList.open = false;
-    
-      closeToolbarCustomizationUI(finish);
-    });
-  }, false);
-
-  iconModeList.open = true;
-}
diff --git a/browser/base/content/test/general/browser_disablechrome.js b/browser/base/content/test/general/browser_disablechrome.js
deleted file mode 100644
index e00cf16575975b10898e287e20772dba1cd68a44..0000000000000000000000000000000000000000
--- a/browser/base/content/test/general/browser_disablechrome.js
+++ /dev/null
@@ -1,216 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-// Tests that the disablechrome attribute gets propogated to the main UI
-
-const HTTPSRC = "http://example.com/browser/browser/base/content/test/general/";
-
-function is_element_hidden(aElement) {
-  var style = window.getComputedStyle(document.getElementById("nav-bar"), "");
-  if (style.visibility != "visible" || style.display == "none")
-    return true;
-
-  if (aElement.ownerDocument != aElement.parentNode)
-    return is_element_hidden(aElement.parentNode);
-
-  return false;
-}
-
-function is_chrome_hidden() {
-  is(document.documentElement.getAttribute("disablechrome"), "true", "Attribute should be set");
-  if (TabsOnTop.enabled)
-    ok(is_element_hidden(document.getElementById("nav-bar")), "Toolbar should be hidden");
-  else
-    ok(!is_element_hidden(document.getElementById("nav-bar")), "Toolbar should not be hidden");
-}
-
-function is_chrome_visible() {
-  isnot(document.getElementById("main-window").getAttribute("disablechrome"), "true", "Attribute should not be set");
-  ok(!is_element_hidden(document.getElementById("nav-bar")), "Toolbar should not be hidden");
-}
-
-function load_page(aURL, aCanHide, aCallback) {
-  gNewBrowser.addEventListener("pageshow", function() {
-    // Filter out about:blank loads
-    if (gNewBrowser.currentURI.spec != aURL)
-      return;
-
-    gNewBrowser.removeEventListener("pageshow", arguments.callee, false);
-
-    if (aCanHide)
-      is_chrome_hidden();
-    else
-      is_chrome_visible();
-
-    if (aURL == "about:addons") {
-      function check_after_init() {
-        if (aCanHide)
-          is_chrome_hidden();
-        else
-          is_chrome_visible();
-
-        aCallback();
-      }
-
-      if (gNewBrowser.contentWindow.gIsInitializing) {
-        gNewBrowser.contentDocument.addEventListener("Initialized", function() {
-          gNewBrowser.contentDocument.removeEventListener("Initialized", arguments.callee, false);
-
-          check_after_init();
-        }, false);
-      }
-      else {
-        check_after_init();
-      }
-    }
-    else {
-      executeSoon(aCallback);
-    }
-  }, false);
-  gNewBrowser.loadURI(aURL);
-}
-
-var gOldTab;
-var gNewTab;
-var gNewBrowser;
-
-function test() {
-  // Opening the add-ons manager and waiting for it to load the discovery pane
-  // takes more time in windows debug builds
-  requestLongerTimeout(2);
-
-  var gOldTabsOnTop = TabsOnTop.enabled;
-  registerCleanupFunction(function() {
-    TabsOnTop.enabled = gOldTabsOnTop;
-  });
-
-  waitForExplicitFinish();
-
-  gOldTab = gBrowser.selectedTab;
-  gNewTab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
-  gNewBrowser = gBrowser.selectedBrowser;
-
-  info("Tabs on top");
-  TabsOnTop.enabled = true;
-
-  run_http_test_1();
-}
-
-function end_test() {
-  gBrowser.removeTab(gNewTab);
-  finish();
-}
-
-function test_url(aURL, aCanHide, aNextTest) {
-  is_chrome_visible();
-  info("Page load");
-  load_page(aURL, aCanHide, function() {
-    info("Switch away");
-    gBrowser.selectedTab = gOldTab;
-    is_chrome_visible();
-
-    info("Switch back");
-    gBrowser.selectedTab = gNewTab;
-    if (aCanHide)
-      is_chrome_hidden();
-    else
-      is_chrome_visible();
-
-    gBrowser.removeTab(gNewTab);
-    gNewTab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
-    gNewBrowser = gBrowser.selectedBrowser;
-
-    gBrowser.selectedTab = gOldTab;
-
-    info("Background load");
-    load_page(aURL, false, function() {
-      info("Switch back");
-      gBrowser.selectedTab = gNewTab;
-      if (aCanHide)
-        is_chrome_hidden();
-      else
-        is_chrome_visible();
-
-      load_page("about:blank", false, aNextTest);
-    });
-  });
-}
-
-// Should never hide the chrome
-function run_http_test_1() {
-  info("HTTP tests");
-  test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test);
-}
-
-// Should hide the chrome
-function run_chrome_about_test() {
-  info("Chrome about: tests");
-  test_url("about:addons", true, function() {
-    info("Tabs on bottom");
-    TabsOnTop.enabled = false;
-    run_http_test_2();
-  });
-}
-
-// Should never hide the chrome
-function run_http_test_2() {
-  info("HTTP tests");
-  test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_2);
-}
-
-// Should not hide the chrome
-function run_chrome_about_test_2() {
-  info("Chrome about: tests");
-  test_url("about:addons", true, run_http_test3);
-}
-
-function run_http_test3() {
-  info("HTTP tests");
-  test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_3);
-}
-
-// Should not hide the chrome
-function run_chrome_about_test_3() {
-  info("Chrome about: tests");
-  test_url("about:Addons", true, function(){
-    info("Tabs on top");
-    TabsOnTop.enabled = true;
-    run_http_test4();
-  });
-}
-
-function run_http_test4() {
-  info("HTTP tests");
-  test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_4);
-}
-
-function run_chrome_about_test_4() {
-  info("Chrome about: tests");
-  test_url("about:Addons", true, run_http_test5);
- }
-
-function run_http_test5() {
-  info("HTTP tests");
-  test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_5);
-}
-
-// Should hide the chrome
-function run_chrome_about_test_5() {
-  info("Chrome about: tests");
-  test_url("about:preferences", true, function(){
-    info("Tabs on bottom");
-    TabsOnTop.enabled = false;
-    run_http_test6();
-  });
-}
-
-function run_http_test6() {
-  info("HTTP tests");
-  test_url(HTTPSRC + "disablechrome.html", false, run_chrome_about_test_6);
-}
-
-function run_chrome_about_test_6() {
-  info("Chrome about: tests");
-  test_url("about:preferences", true, end_test);
-}
\ No newline at end of file
diff --git a/browser/base/content/test/general/browser_overflowScroll.js b/browser/base/content/test/general/browser_overflowScroll.js
index 8c0eac70949d048498069697b98e1170d12cf5f0..bc82ab4193f803133b06466fe56788dc028e2126 100644
--- a/browser/base/content/test/general/browser_overflowScroll.js
+++ b/browser/base/content/test/general/browser_overflowScroll.js
@@ -7,8 +7,8 @@ function rect(ele)           ele.getBoundingClientRect();
 function width(ele)          rect(ele).width;
 function left(ele)           rect(ele).left;
 function right(ele)          rect(ele).right;
-function isLeft(ele, msg)    is(left(ele), left(scrollbox), msg);
-function isRight(ele, msg)   is(right(ele), right(scrollbox), msg);
+function isLeft(ele, msg)    is(left(ele) + tabstrip._tabMarginLeft, left(scrollbox), msg);
+function isRight(ele, msg)   is(right(ele) - tabstrip._tabMarginRight, right(scrollbox), msg);
 function elementFromPoint(x) tabstrip._elementFromPoint(x);
 function nextLeftElement()   elementFromPoint(left(scrollbox) - 1);
 function nextRightElement()  elementFromPoint(right(scrollbox) + 1);
@@ -62,7 +62,11 @@ function runOverflowTests(aEvent) {
   EventUtils.synthesizeMouse(upButton, 1, 1, {});
   isLeft(element, "Scrolled one tab to the left with a single click");
 
-  element = elementFromPoint(left(scrollbox) - width(scrollbox));
+  let elementPoint = left(scrollbox) - width(scrollbox);
+  element = elementFromPoint(elementPoint);
+  if (elementPoint == right(element)) {
+    element = element.nextSibling;
+  }
   EventUtils.synthesizeMouse(upButton, 1, 1, {clickCount: 2});
   isLeft(element, "Scrolled one page of tabs with a double click");
 
diff --git a/browser/base/content/test/general/browser_tabbar_big_widgets.js b/browser/base/content/test/general/browser_tabbar_big_widgets.js
new file mode 100644
index 0000000000000000000000000000000000000000..7a4c4513845dc88bff8ff020f88c6ee7887b8312
--- /dev/null
+++ b/browser/base/content/test/general/browser_tabbar_big_widgets.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const kButtonId = "test-tabbar-size-with-large-buttons";
+
+function test() {
+  registerCleanupFunction(cleanup);
+  let titlebar = document.getElementById("titlebar");
+  let originalHeight = titlebar.getBoundingClientRect().height;
+  let button = document.createElement("toolbarbutton");
+  button.id = kButtonId;
+  button.setAttribute("style", "min-height: 100px");
+  gNavToolbox.palette.appendChild(button);
+  CustomizableUI.addWidgetToArea(kButtonId, CustomizableUI.AREA_TABSTRIP);
+  let currentHeight = titlebar.getBoundingClientRect().height;
+  ok(currentHeight > originalHeight, "Titlebar should have grown");
+  CustomizableUI.removeWidgetFromArea(kButtonId);
+  currentHeight = titlebar.getBoundingClientRect().height;
+  is(currentHeight, originalHeight, "Titlebar should have gone back to its original size.");
+}
+
+function cleanup() {
+  let btn = document.getElementById(kButtonId);
+  if (btn) {
+    btn.remove();
+  }
+}
+
diff --git a/browser/base/content/test/general/browser_windowopen_reflows.js b/browser/base/content/test/general/browser_windowopen_reflows.js
new file mode 100644
index 0000000000000000000000000000000000000000..8df4e2e8fb597567d9ec1565c59c657df50103b0
--- /dev/null
+++ b/browser/base/content/test/general/browser_windowopen_reflows.js
@@ -0,0 +1,115 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const EXPECTED_REFLOWS = [
+  // handleEvent flushes layout to get the tabstrip width after a resize.
+  "handleEvent@chrome://browser/content/tabbrowser.xml|",
+
+  // Loading a tab causes a reflow.
+  "loadTabs@chrome://browser/content/tabbrowser.xml|" +
+    "loadOneOrMoreURIs@chrome://browser/content/browser.js|" +
+    "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|",
+
+  // Selecting the address bar causes a reflow.
+  "select@chrome://global/content/bindings/textbox.xml|" +
+    "focusAndSelectUrlBar@chrome://browser/content/browser.js|" +
+    "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|",
+
+  // Focusing the content area causes a reflow.
+  "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|",
+
+  // Sometimes sessionstore collects data during this test, which causes a sync reflow
+  // (https://bugzilla.mozilla.org/show_bug.cgi?id=892154 will fix this)
+  "ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm",
+];
+
+if (Services.appinfo.OS == "Darwin") {
+  // TabsInTitlebar._update causes a reflow on OS X trying to do calculations
+  // since layout info is already dirty. This doesn't seem to happen before
+  // MozAfterPaint on other platforms.
+  EXPECTED_REFLOWS.push("rect@chrome://browser/content/browser.js|" +
+                          "TabsInTitlebar._update@chrome://browser/content/browser.js|" +
+                          "updateAppearance@chrome://browser/content/browser.js|" +
+                          "handleEvent@chrome://browser/content/tabbrowser.xml|");
+
+  // _onOverflow causes a reflow getting widths.
+  EXPECTED_REFLOWS.push("OverflowableToolbar.prototype._onOverflow@resource:///modules/CustomizableUI.jsm|" +
+                        "OverflowableToolbar.prototype.init@resource:///modules/CustomizableUI.jsm|" +
+                        "OverflowableToolbar.prototype.observe@resource:///modules/CustomizableUI.jsm|" +
+                        "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|");
+  // Same as above since in packaged builds there are no function names and the resource URI includes "app"
+  EXPECTED_REFLOWS.push("@resource://app/modules/CustomizableUI.jsm|" +
+                          "@resource://app/modules/CustomizableUI.jsm|" +
+                          "@resource://app/modules/CustomizableUI.jsm|" +
+                          "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|");
+}
+
+/*
+ * This test ensures that there are no unexpected
+ * uninterruptible reflows when opening new windows.
+ */
+function test() {
+  waitForExplicitFinish();
+
+  // Add a reflow observer and open a new window
+  let win = OpenBrowserWindow();
+  let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                    .getInterface(Ci.nsIWebNavigation)
+                    .QueryInterface(Ci.nsIDocShell);
+  docShell.addWeakReflowObserver(observer);
+
+  // Wait until the mozafterpaint event occurs.
+  waitForMozAfterPaint(win, function paintListener() {
+    // Remove reflow observer and clean up.
+    docShell.removeWeakReflowObserver(observer);
+    win.close();
+
+    finish();
+  });
+}
+
+let observer = {
+  reflow: function (start, end) {
+    // Gather information about the current code path.
+    let stack = new Error().stack;
+    let path = stack.split("\n").slice(1).map(line => {
+      return line.replace(/:\d+$/, "");
+    }).join("|");
+    let pathWithLineNumbers = (new Error().stack).split("\n").slice(1).join("|");
+
+    // Stack trace is empty. Reflow was triggered by native code.
+    if (path === "") {
+      return;
+    }
+
+    // Check if this is an expected reflow.
+    for (let expectedStack of EXPECTED_REFLOWS) {
+      if (path.startsWith(expectedStack) ||
+          // Accept an empty function name for gBrowserInit._delayedStartup or TabsInTitlebar._update to workaround bug 906578.
+          path.startsWith(expectedStack.replace(/(^|\|)(gBrowserInit\._delayedStartup|TabsInTitlebar\._update)@/, "$1@"))) {
+        ok(true, "expected uninterruptible reflow '" + expectedStack + "'");
+        return;
+      }
+    }
+
+    ok(false, "unexpected uninterruptible reflow '" + pathWithLineNumbers + "'");
+  },
+
+  reflowInterruptible: function (start, end) {
+    // We're not interested in interruptible reflows.
+  },
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIReflowObserver,
+                                         Ci.nsISupportsWeakReference])
+};
+
+function waitForMozAfterPaint(win, callback) {
+  win.addEventListener("MozAfterPaint", function onEnd(event) {
+    if (event.target != win)
+      return;
+    win.removeEventListener("MozAfterPaint", onEnd);
+    executeSoon(callback);
+  });
+}
diff --git a/browser/base/content/test/general/disablechrome.html b/browser/base/content/test/general/disablechrome.html
deleted file mode 100644
index 7879e1ce9fd77d4d90054013725af5137e8ef31a..0000000000000000000000000000000000000000
--- a/browser/base/content/test/general/disablechrome.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<html>
-<body>
-</body>
-</html>
diff --git a/browser/base/content/test/general/head.js b/browser/base/content/test/general/head.js
index 1d33893e8ede3f3d2ac7cd14d05e43af1cb0ae4b..3f3702ec3827aa141569aa823f17348806b37287 100644
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -37,49 +37,27 @@ function updateTabContextMenu(tab) {
   menu.hidePopup();
 }
 
-function findToolbarCustomizationWindow(aBrowserWin) {
-  if (!aBrowserWin)
-    aBrowserWin = window;
-
-  let iframe = aBrowserWin.document.getElementById("customizeToolbarSheetIFrame");
-  let win = iframe && iframe.contentWindow;
-  if (win)
-    return win;
-
-  win = findChromeWindowByURI("chrome://global/content/customizeToolbar.xul");
-  if (win && win.opener == aBrowserWin)
-    return win;
-
-  throw Error("Failed to find the customization window");
-}
-
 function openToolbarCustomizationUI(aCallback, aBrowserWin) {
   if (!aBrowserWin)
     aBrowserWin = window;
 
-  aBrowserWin.document.getElementById("cmd_CustomizeToolbars").doCommand();
-
-  aBrowserWin.gNavToolbox.addEventListener("beforecustomization", function UI_loaded() {
-    aBrowserWin.gNavToolbox.removeEventListener("beforecustomization", UI_loaded);
+  aBrowserWin.gCustomizeMode.enter();
 
-    let win = findToolbarCustomizationWindow(aBrowserWin);
-    waitForFocus(function () {
-      aCallback(win);
-    }, win);
+  aBrowserWin.gNavToolbox.addEventListener("customizationready", function UI_loaded() {
+    aBrowserWin.gNavToolbox.removeEventListener("customizationready", UI_loaded);
+    executeSoon(function() {
+      aCallback(aBrowserWin)
+    });
   });
 }
 
 function closeToolbarCustomizationUI(aCallback, aBrowserWin) {
-  let win = findToolbarCustomizationWindow(aBrowserWin);
-
-  win.addEventListener("unload", function unloaded() {
-    win.removeEventListener("unload", unloaded);
+  aBrowserWin.gNavToolbox.addEventListener("aftercustomization", function unloaded() {
+    aBrowserWin.gNavToolbox.removeEventListener("aftercustomization", unloaded);
     executeSoon(aCallback);
   });
 
-  let button = win.document.getElementById("donebutton");
-  button.focus();
-  button.doCommand();
+  aBrowserWin.gCustomizeMode.exit();
 }
 
 function waitForCondition(condition, nextTest, errorMsg) {
diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml
index f4a593fe05832abeeee9bcad09a864db2ac498a9..c19e499984c98f59130697dd3d6a66923de868c6 100644
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -937,7 +937,7 @@
             <xul:menupopup anonid="menupopup"
                            xbl:inherits="oncommand=menucommand">
               <children/>
-              <xul:menuitem class="menuitem-iconic popup-notification-closeitem"
+              <xul:menuitem class="menuitem-iconic popup-notification-closeitem close-icon"
                             label="&closeNotificationItem.label;"
                             xbl:inherits="oncommand=closeitemcommand"/>
             </xul:menupopup>
@@ -946,7 +946,7 @@
       </xul:vbox>
       <xul:vbox pack="start">
         <xul:toolbarbutton anonid="closebutton"
-                           class="messageCloseButton popup-notification-closebutton tabbable"
+                           class="messageCloseButton close-icon popup-notification-closebutton tabbable"
                            xbl:inherits="oncommand=closebuttoncommand"
                            tooltiptext="&closeNotification.tooltip;"/>
       </xul:vbox>
@@ -1169,7 +1169,7 @@
             <xul:menupopup anonid="menupopup"
                            xbl:inherits="oncommand=menucommand">
               <children/>
-              <xul:menuitem class="menuitem-iconic popup-notification-closeitem"
+              <xul:menuitem class="menuitem-iconic popup-notification-closeitem close-icon"
                             label="&closeNotificationItem.label;"
                             xbl:inherits="oncommand=closeitemcommand"/>
             </xul:menupopup>
@@ -1178,7 +1178,7 @@
       </xul:vbox>
       <xul:vbox pack="start">
         <xul:toolbarbutton anonid="closebutton"
-                           class="messageCloseButton popup-notification-closebutton tabbable"
+                           class="messageCloseButton close-icon popup-notification-closebutton tabbable"
                            xbl:inherits="oncommand=closebuttoncommand"
                            tooltiptext="&closeNotification.tooltip;"/>
       </xul:vbox>
@@ -1508,7 +1508,7 @@
             <xul:label class="text-link click-to-play-plugins-notification-link" anonid="click-to-play-plugins-notification-link" />
           </xul:description>
           <xul:toolbarbutton anonid="closebutton"
-                             class="messageCloseButton popup-notification-closebutton tabbable"
+                             class="messageCloseButton popup-notification-closebutton tabbable close-icon"
                              xbl:inherits="oncommand=closebuttoncommand"
                              tooltiptext="&closeNotification.tooltip;"/>
         </xul:hbox>
@@ -2027,7 +2027,7 @@
                              onclick="document.getBindingParent(this).onLinkClick();"/>
           </xul:description>
         </xul:hbox>
-        <xul:toolbarbutton class="panel-promo-closebutton"
+        <xul:toolbarbutton class="panel-promo-closebutton close-icon"
                            oncommand="document.getBindingParent(this).onCloseButtonCommand();"
                            tooltiptext="&closeNotification.tooltip;"/>
       </xul:hbox>
diff --git a/browser/base/jar.mn b/browser/base/jar.mn
index 3113094fcb844882197054d78820f9121137f0eb..f6c615674d35639e41b3d761f69acf463df6ecec 100644
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -13,8 +13,7 @@ browser.jar:
 #endif
 %  overlay chrome://global/content/viewSource.xul chrome://browser/content/viewSourceOverlay.xul
 %  overlay chrome://global/content/viewPartialSource.xul chrome://browser/content/viewSourceOverlay.xul
-%  style chrome://global/content/customizeToolbar.xul chrome://browser/content/browser.css
-%  style chrome://global/content/customizeToolbar.xul chrome://browser/skin/
+
 *       content/browser/aboutDialog.xul               (content/aboutDialog.xul)
 *       content/browser/aboutDialog.js                (content/aboutDialog.js)
         content/browser/aboutDialog.css               (content/aboutDialog.css)
diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp
index c1de734b7f451159cd1ebd080733de355e6ff716..15d813804dc267a4bff5f06b0f6bfcec7361d548 100644
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -92,6 +92,8 @@ static RedirEntry kRedirMap[] = {
 #endif
   { "app-manager", "chrome://browser/content/devtools/app-manager/index.xul",
     nsIAboutModule::ALLOW_SCRIPT },
+  { "customizing", "chrome://browser/content/customizableui/aboutCustomizing.xhtml",
+    nsIAboutModule::ALLOW_SCRIPT },
 };
 static const int kRedirTotal = NS_ARRAY_LENGTH(kRedirMap);
 
diff --git a/browser/components/build/nsModule.cpp b/browser/components/build/nsModule.cpp
index c0b927396281578efe7212688cdf303afc10d2d6..3ae8c28898ef2cca6d5652aad7a52509af0b16c7 100644
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -110,6 +110,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #endif
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "app-manager", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
+    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "customizing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #if defined(XP_WIN)
     { NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
 #elif defined(XP_MACOSX)
diff --git a/browser/components/customizableui/content/aboutCustomizing.xhtml b/browser/components/customizableui/content/aboutCustomizing.xhtml
new file mode 100644
index 0000000000000000000000000000000000000000..9a55f5b5ff6f30c45ecbba062e23a6a209c32838
--- /dev/null
+++ b/browser/components/customizableui/content/aboutCustomizing.xhtml
@@ -0,0 +1,23 @@
+<?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/. -->
+
+<!DOCTYPE html [
+  <!ENTITY % htmlDTD
+    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+    "DTD/xhtml1-strict.dtd">
+  %htmlDTD;
+  <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
+  %brandDTD;
+  <!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
+  %browserDTD;
+]>
+
+<html xmlns="http://www.w3.org/1999/xhtml"
+      disablefastfind="true">
+	<head>
+		<title>&customizeMode.tabTitle;</title>
+	</head>
+	<body></body>
+</html>
diff --git a/browser/components/customizableui/content/customizeMode.inc.xul b/browser/components/customizableui/content/customizeMode.inc.xul
new file mode 100644
index 0000000000000000000000000000000000000000..5f860153ac7ad09d360acb4d5baaea566f81906c
--- /dev/null
+++ b/browser/components/customizableui/content/customizeMode.inc.xul
@@ -0,0 +1,28 @@
+<!-- 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/. -->
+
+<hbox id="customization-container" flex="1" hidden="true">
+  <vbox flex="1" id="customization-palette-container">
+    <label id="customization-header" value="&customizeMode.menuAndToolbars.header;"/>
+    <vbox id="customization-palette" flex="1"/>
+    <hbox pack="start">
+      <button id="customization-reset-button" oncommand="gCustomizeMode.reset();" label="&customizeMode.restoreDefaults;" class="customizationmode-button"/>
+    </hbox>
+  </vbox>
+  <vbox id="customization-panel-container">
+    <vbox id="customization-panelWrapper">
+      <html:style html:type="text/html" scoped="scoped">
+        @import url(chrome://global/skin/popup.css);
+      </html:style>
+      <box class="panel-arrowbox">
+        <box flex="1"/>
+        <image class="panel-arrow" side="top"/>
+      </box>
+      <box class="panel-arrowcontent" side="top" flex="1">
+        <hbox id="customization-panelHolder"/>
+        <box class="panel-inner-arrowcontentfooter" hidden="true"/>
+      </box>
+    </vbox>
+  </vbox>
+</hbox>
diff --git a/browser/components/customizableui/content/jar.mn b/browser/components/customizableui/content/jar.mn
new file mode 100644
index 0000000000000000000000000000000000000000..43f68f4c3dea12132e035027d52f25206e0eafaa
--- /dev/null
+++ b/browser/components/customizableui/content/jar.mn
@@ -0,0 +1,11 @@
+# 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/.
+
+browser.jar:
+  content/browser/customizableui/aboutCustomizing.xhtml
+  content/browser/customizableui/panelUI.css
+  content/browser/customizableui/panelUI.js
+  content/browser/customizableui/panelUI.xml
+  content/browser/customizableui/toolbar.xml
+
diff --git a/browser/components/customizableui/content/moz.build b/browser/components/customizableui/content/moz.build
new file mode 100644
index 0000000000000000000000000000000000000000..895d11993cfbb162d47a99608e92843c5a06e999
--- /dev/null
+++ b/browser/components/customizableui/content/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
diff --git a/browser/components/customizableui/content/panelUI.css b/browser/components/customizableui/content/panelUI.css
new file mode 100644
index 0000000000000000000000000000000000000000..a3f46df3534ca03299ab3ed91fa1929ffd25f073
--- /dev/null
+++ b/browser/components/customizableui/content/panelUI.css
@@ -0,0 +1,31 @@
+/* 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/. */
+
+.panel-viewstack[viewtype="main"] > .panel-clickcapturer {
+  pointer-events: none;
+}
+
+.panel-mainview,
+.panel-viewcontainer,
+.panel-viewstack {
+  overflow: hidden;
+}
+
+.panel-viewstack {
+  position: relative;
+}
+
+.panel-subviews {
+  -moz-stack-sizing: ignore;
+  transform: translateX(0);
+  overflow-y: auto;
+}
+
+.panel-subviews[panelopen] {
+  transition: transform 150ms;
+}
+
+.panel-viewcontainer[panelopen]:-moz-any(:not([viewtype="main"]),[transitioning="true"]) {
+  transition: height 150ms;
+}
diff --git a/browser/components/customizableui/content/panelUI.inc.xul b/browser/components/customizableui/content/panelUI.inc.xul
new file mode 100644
index 0000000000000000000000000000000000000000..212779084f7f9450c21eec9d9c48e5e39ded1e7a
--- /dev/null
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -0,0 +1,153 @@
+<!-- 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/. -->
+
+<panel id="PanelUI-popup"
+       role="group"
+       type="arrow"
+       level="top"
+       hidden="true"
+       noautofocus="true">
+  <panelmultiview id="PanelUI-multiView" mainViewId="PanelUI-mainView">
+    <panelview id="PanelUI-mainView" contextmenu="customizationPanelContextMenu">
+      <vbox id="PanelUI-contents-scroller">
+        <vbox id="PanelUI-contents"/>
+      </vbox>
+
+      <footer id="PanelUI-footer">
+        <!-- The parentNode is used so that the footer is presented as the anchor
+             instead of just the button being the anchor. -->
+        <toolbarbutton id="PanelUI-help" label="&helpMenu.label;" tabindex="0"
+                       oncommand="PanelUI.showHelpView(this.parentNode);"/>
+        <toolbarbutton id="PanelUI-customize" label="&appMenuCustomize.label;" tabindex="0"
+                       oncommand="gCustomizeMode.toggle();"/>
+        <toolbarbutton id="PanelUI-quit" tabindex="0"
+#ifdef XP_WIN
+                       label="&quitApplicationCmdWin.label;"
+#else
+                       label="&quitApplicationCmd.label;"
+#endif
+                       command="cmd_quitApplication"/>
+      </footer>
+    </panelview>
+
+    <panelview id="PanelUI-history" flex="1">
+      <label value="&appMenuHistory.label;"/>
+      <toolbarbutton id="appMenuClearRecentHistory" tabindex="0"
+                     label="&appMenuHistory.clearRecent.label;"
+                     command="Tools:Sanitize"/>
+      <toolbarbutton id="appMenuRestoreLastSession" tabindex="0"
+                     label="&appMenuHistory.restoreSession.label;"
+                     command="Browser:RestoreLastSession"/>
+      <menuseparator id="PanelUI-recentlyClosedTabs-separator"/>
+      <vbox id="PanelUI-recentlyClosedTabs"/>
+      <menuseparator id="PanelUI-recentlyClosedWindows-separator"/>
+      <vbox id="PanelUI-recentlyClosedWindows"/>
+      <menuseparator id="PanelUI-historyItems-separator"/>
+      <vbox id="PanelUI-historyItems"/>
+      <label value="&appMenuHistory.showAll.label;"
+             id="PanelUI-historyMore"
+             class="text-link"
+             onclick="PlacesCommandHook.showPlacesOrganizer('History'); CustomizableUI.hidePanelForNode(this);"/>
+    </panelview>
+
+    <panelview id="PanelUI-bookmarks" flex="1">
+      <toolbarbutton id="panelMenuBookmarkThisPage"
+                     label="&bookmarkThisPageCmd.label;"
+                     command="Browser:AddBookmarkAs"
+                     onclick="PanelUI.hide();"/>
+      <toolbarseparator/>
+      <toolbarbutton id="panelMenu_showAllBookmarks"
+                     label="&showAllBookmarks2.label;"
+                     command="Browser:ShowAllBookmarks"
+                     onclick="PanelUI.hide();"/>
+      <toolbarbutton id="panelMenu_viewBookmarksSidebar"
+                     label="&viewBookmarksSidebar2.label;"
+                     oncommand="toggleSidebar('viewBookmarksSidebar'); PanelUI.hide();">
+        <observes element="viewBookmarksSidebar" attribute="checked"/>
+      </toolbarbutton>
+      <toolbarbutton id="panelMenu_viewBookmarksToolbar"
+                     label="&viewBookmarksToolbar.label;"
+                     type="checkbox"
+                     toolbarId="PersonalToolbar"
+                     oncommand="onViewToolbarCommand(event); PanelUI.hide();"/>
+      <toolbarseparator/>
+      <toolbarbutton id="panelMenu_bookmarksToolbar"
+                     label="&personalbarCmd.label;"
+                     oncommand="PlacesCommandHook.showPlacesOrganizer('BookmarksToolbar'); PanelUI.hide();"/>
+      <toolbarbutton id="panelMenu_unsortedBookmarks"
+                     label="&unsortedBookmarksCmd.label;"
+                     oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks'); PanelUI.hide();"/>
+      <toolbarseparator/>
+      <toolbaritem id="panelMenu_bookmarksMenu"
+                   flex="1"
+                   orient="vertical"
+                   smoothscroll="false"
+                   onclick="if (event.button == 1) BookmarkingUI.onPanelMenuViewCommand(event, this._placesView);"
+                   oncommand="BookmarkingUI.onPanelMenuViewCommand(event, this._placesView);"
+                   flatList="true"
+                   tooltip="bhTooltip">
+        <!-- bookmarks menu items -->
+      </toolbaritem>
+
+    </panelview>
+
+    <panelview id="PanelUI-feeds" flex="1" oncommand="FeedHandler.subscribeToFeed(null, event);"></panelview>
+
+    <panelview id="PanelUI-helpView" flex="1">
+      <label value="&helpMenu.label;"/>
+      <vbox id="PanelUI-helpItems"/>
+    </panelview>
+
+    <panelview id="PanelUI-developer" flex="1">
+      <label value="&webDeveloperMenu.label;"/>
+      <vbox id="PanelUI-developerItems"/>
+    </panelview>
+
+    <panelview id="PanelUI-characterEncodingView" flex="1">
+      <label value="&charsetMenu.label;"/>
+      <toolbarbutton label="&charsetCustomize.label;"
+                     oncommand="PanelUI.onCharsetCustomizeCommand();"/>
+
+      <vbox id="PanelUI-characterEncodingView-customlist"
+            class="PanelUI-characterEncodingView-list"/>
+      <vbox>
+        <label value="&charsetMenuAutodet.label;"/>
+        <vbox id="PanelUI-characterEncodingView-autodetect"
+              class="PanelUI-characterEncodingView-list"/>
+      </vbox>
+    </panelview>
+
+  </panelmultiview>
+  <popupset id="customizationContextMenus">
+    <menupopup id="customizationContextMenu">
+      <menuitem oncommand="gCustomizeMode.addToToolbar(document.popupNode)"
+                accesskey="&customizeMenu.addToToolbar.accesskey;"
+                label="&customizeMenu.addToToolbar.label;"/>
+      <menuitem oncommand="gCustomizeMode.removeFromPanel(document.popupNode)"
+                accesskey="&customizeMenu.removeFromMenu.accesskey;"
+                label="&customizeMenu.removeFromMenu.label;"/>
+      <menuseparator/>
+      <menuitem command="cmd_CustomizeToolbars"
+                accesskey="&viewCustomizeToolbar.accesskey;"
+                label="&viewCustomizeToolbar.label;"/>
+    </menupopup>
+
+    <menupopup id="customizationPanelContextMenu">
+      <menuitem command="cmd_CustomizeToolbars"
+                accesskey="&customizeMenu.addMoreItems.accesskey;"
+                label="&customizeMenu.addMoreItems.label;"/>
+    </menupopup>
+  </popupset>
+</panel>
+
+<panel id="widget-overflow"
+       role="group"
+       type="arrow"
+       level="top"
+       hidden="true"
+       consumeoutsideclicks="true">
+  <vbox id="widget-overflow-scroller">
+    <vbox id="widget-overflow-list"/>
+  </vbox>
+</panel>
diff --git a/browser/components/customizableui/content/panelUI.js b/browser/components/customizableui/content/panelUI.js
new file mode 100644
index 0000000000000000000000000000000000000000..2071414eb3eadf7fb7ec45a0350db24680b5cd7b
--- /dev/null
+++ b/browser/components/customizableui/content/panelUI.js
@@ -0,0 +1,400 @@
+/* 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/. */
+
+XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
+                                  "resource:///modules/CustomizableUI.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ScrollbarSampler",
+                                  "resource:///modules/ScrollbarSampler.jsm");
+/**
+ * Maintains the state and dispatches events for the main menu panel.
+ */
+
+const PanelUI = {
+  /** Panel events that we listen for. **/
+  get kEvents() ["popupshowing", "popupshown", "popuphiding", "popuphidden"],
+  /**
+   * Used for lazily getting and memoizing elements from the document. Lazy
+   * getters are set in init, and memoizing happens after the first retrieval.
+   */
+  get kElements() {
+    return {
+      contents: "PanelUI-contents",
+      mainView: "PanelUI-mainView",
+      multiView: "PanelUI-multiView",
+      helpView: "PanelUI-helpView",
+      menuButton: "PanelUI-menu-button",
+      panel: "PanelUI-popup",
+      scroller: "PanelUI-contents-scroller"
+    };
+  },
+
+  init: function() {
+    for (let [k, v] of Iterator(this.kElements)) {
+      // Need to do fresh let-bindings per iteration
+      let getKey = k;
+      let id = v;
+      this.__defineGetter__(getKey, function() {
+        delete this[getKey];
+        return this[getKey] = document.getElementById(id);
+      });
+    }
+
+    this.menuButton.addEventListener("mousedown", this);
+    this.menuButton.addEventListener("keypress", this);
+  },
+
+  _eventListenersAdded: false,
+  _ensureEventListenersAdded: function() {
+    if (this._eventListenersAdded)
+      return;
+    this._addEventListeners();
+  },
+
+  _addEventListeners: function() {
+    for (let event of this.kEvents) {
+      this.panel.addEventListener(event, this);
+    }
+
+    this.helpView.addEventListener("ViewShowing", this._onHelpViewShow, false);
+    this.helpView.addEventListener("ViewHiding", this._onHelpViewHide, false);
+    this._eventListenersAdded = true;
+  },
+
+  uninit: function() {
+    if (!this._eventListenersAdded) {
+      return;
+    }
+
+    for (let event of this.kEvents) {
+      this.panel.removeEventListener(event, this);
+    }
+    this.helpView.removeEventListener("ViewShowing", this._onHelpViewShow);
+    this.helpView.removeEventListener("ViewHiding", this._onHelpViewHide);
+    this.menuButton.removeEventListener("mousedown", this);
+    this.menuButton.removeEventListener("keypress", this);
+  },
+
+  /**
+   * Customize mode extracts the mainView and puts it somewhere else while the
+   * user customizes. Upon completion, this function can be called to put the
+   * panel back to where it belongs in normal browsing mode.
+   *
+   * @param aMainView
+   *        The mainView node to put back into place.
+   */
+  setMainView: function(aMainView) {
+    this._ensureEventListenersAdded();
+    this.multiView.setMainView(aMainView);
+  },
+
+  /**
+   * Opens the menu panel if it's closed, or closes it if it's
+   * open.
+   *
+   * @param aEvent the event that triggers the toggle.
+   */
+  toggle: function(aEvent) {
+    // Don't show the panel if the window is in customization mode,
+    // since this button doubles as an exit path for the user in this case.
+    if (document.documentElement.hasAttribute("customizing")) {
+      return;
+    }
+    this._ensureEventListenersAdded();
+    if (this.panel.state == "open") {
+      this.hide();
+    } else if (this.panel.state == "closed") {
+      this.show(aEvent);
+    }
+  },
+
+  /**
+   * Opens the menu panel. If the event target has a child with the
+   * toolbarbutton-icon attribute, the panel will be anchored on that child.
+   * Otherwise, the panel is anchored on the event target itself.
+   *
+   * @param aEvent the event (if any) that triggers showing the menu.
+   */
+  show: function(aEvent) {
+    if (this.panel.state == "open" || this.panel.state == "showing" ||
+        document.documentElement.hasAttribute("customizing")) {
+      return;
+    }
+
+    this.ensureReady().then(() => {
+      this.panel.hidden = false;
+      let editControlPlacement = CustomizableUI.getPlacementOfWidget("edit-controls");
+      if (editControlPlacement && editControlPlacement.area == CustomizableUI.AREA_PANEL) {
+        updateEditUIVisibility();
+      }
+
+      let anchor;
+      if (!aEvent ||
+          aEvent.type == "command") {
+        anchor = this.menuButton;
+      } else {
+        anchor = aEvent.target;
+      }
+      let iconAnchor =
+        document.getAnonymousElementByAttribute(anchor, "class",
+                                                "toolbarbutton-icon");
+
+      // Only focus the panel if it's opened using the keyboard, so that
+      // cut/copy/paste buttons will work for mouse users.
+      let keyboardOpened = aEvent && aEvent.sourceEvent &&
+                           aEvent.sourceEvent.target.localName == "key";
+      this.panel.setAttribute("noautofocus", !keyboardOpened);
+      this.panel.openPopup(iconAnchor || anchor, "bottomcenter topright");
+    });
+  },
+
+  /**
+   * If the menu panel is being shown, hide it.
+   */
+  hide: function() {
+    if (document.documentElement.hasAttribute("customizing")) {
+      return;
+    }
+
+    this.panel.hidePopup();
+  },
+
+  handleEvent: function(aEvent) {
+    switch (aEvent.type) {
+      case "popupshowing":
+        // Fall through
+      case "popupshown":
+        // Fall through
+      case "popuphiding":
+        // Fall through
+      case "popuphidden":
+        this._updatePanelButton(aEvent.target);
+        break;
+      case "mousedown":
+        if (aEvent.button == 0)
+          this.toggle(aEvent);
+        break;
+      case "keypress":
+        this.toggle(aEvent);
+        break;
+    }
+  },
+
+  /**
+   * Registering the menu panel is done lazily for performance reasons. This
+   * method is exposed so that CustomizationMode can force panel-readyness in the
+   * event that customization mode is started before the panel has been opened
+   * by the user.
+   *
+   * @param aCustomizing (optional) set to true if this was called while entering
+   *        customization mode. If that's the case, we trust that customization
+   *        mode will handle calling beginBatchUpdate and endBatchUpdate.
+   *
+   * @return a Promise that resolves once the panel is ready to roll.
+   */
+  ensureReady: function(aCustomizing=false) {
+    if (this._readyPromise) {
+      return this._readyPromise;
+    }
+    this._readyPromise = Task.spawn(function() {
+      if (!this._scrollWidth) {
+        // In order to properly center the contents of the panel, while ensuring
+        // that we have enough space on either side to show a scrollbar, we have to
+        // do a bit of hackery. In particular, we calculate a new width for the
+        // scroller, based on the system scrollbar width.
+        this._scrollWidth =
+          (yield ScrollbarSampler.getSystemScrollbarWidth()) + "px";
+        let cstyle = window.getComputedStyle(this.scroller);
+        let widthStr = cstyle.width;
+        // Get the calculated padding on the left and right sides of
+        // the scroller too. We'll use that in our final calculation so
+        // that if a scrollbar appears, we don't have the contents right
+        // up against the edge of the scroller.
+        let paddingLeft = cstyle.paddingLeft;
+        let paddingRight = cstyle.paddingRight;
+        let calcStr = [widthStr, this._scrollWidth,
+                       paddingLeft, paddingRight].join(" + ");
+        this.scroller.style.width = "calc(" + calcStr + ")";
+      }
+
+      if (aCustomizing) {
+        CustomizableUI.registerMenuPanel(this.contents);
+      } else {
+        this.beginBatchUpdate();
+        CustomizableUI.registerMenuPanel(this.contents);
+        this.endBatchUpdate();
+      }
+    }.bind(this)).then(null, Cu.reportError);
+
+    return this._readyPromise;
+  },
+
+  /**
+   * Switch the panel to the main view if it's not already
+   * in that view.
+   */
+  showMainView: function() {
+    this._ensureEventListenersAdded();
+    this.multiView.showMainView();
+  },
+
+  /**
+   * Switch the panel to the help view if it's not already
+   * in that view.
+   */
+  showHelpView: function(aAnchor) {
+    this._ensureEventListenersAdded();
+    this.multiView.showSubView("PanelUI-helpView", aAnchor);
+  },
+
+  /**
+   * Shows a subview in the panel with a given ID.
+   *
+   * @param aViewId the ID of the subview to show.
+   * @param aAnchor the element that spawned the subview.
+   * @param aPlacementArea the CustomizableUI area that aAnchor is in.
+   */
+  showSubView: function(aViewId, aAnchor, aPlacementArea) {
+    this._ensureEventListenersAdded();
+    let viewNode = document.getElementById(aViewId);
+    if (!viewNode) {
+      Cu.reportError("Could not show panel subview with id: " + aViewId);
+      return;
+    }
+
+    if (!aAnchor) {
+      Cu.reportError("Expected an anchor when opening subview with id: " + aViewId);
+      return;
+    }
+
+    if (aPlacementArea == CustomizableUI.AREA_PANEL) {
+      this.multiView.showSubView(aViewId, aAnchor);
+    } else if (!aAnchor.open) {
+      aAnchor.open = true;
+      // Emit the ViewShowing event so that the widget definition has a chance
+      // to lazily populate the subview with things.
+      let evt = document.createEvent("CustomEvent");
+      evt.initCustomEvent("ViewShowing", true, true, viewNode);
+      viewNode.dispatchEvent(evt);
+      if (evt.defaultPrevented) {
+        return;
+      }
+
+      let tempPanel = document.createElement("panel");
+      tempPanel.setAttribute("type", "arrow");
+      tempPanel.setAttribute("id", "customizationui-widget-panel");
+      tempPanel.setAttribute("level", "top");
+      document.getElementById(CustomizableUI.AREA_NAVBAR).appendChild(tempPanel);
+
+      let multiView = document.createElement("panelmultiview");
+      tempPanel.appendChild(multiView);
+      multiView.setMainView(viewNode);
+      CustomizableUI.addPanelCloseListeners(tempPanel);
+
+      let panelRemover = function() {
+        tempPanel.removeEventListener("popuphidden", panelRemover);
+        CustomizableUI.removePanelCloseListeners(tempPanel);
+        let evt = new CustomEvent("ViewHiding", {detail: viewNode});
+        viewNode.dispatchEvent(evt);
+        aAnchor.open = false;
+
+        this.multiView.appendChild(viewNode);
+        tempPanel.parentElement.removeChild(tempPanel);
+      }.bind(this);
+      tempPanel.addEventListener("popuphidden", panelRemover);
+
+      let iconAnchor =
+        document.getAnonymousElementByAttribute(aAnchor, "class",
+                                                "toolbarbutton-icon");
+
+      tempPanel.openPopup(iconAnchor || aAnchor, "bottomcenter topright");
+    }
+  },
+
+  /**
+   * This function can be used as a command event listener for subviews
+   * so that the panel knows if and when to close itself.
+   */
+  onCommandHandler: function(aEvent) {
+    if (!aEvent.originalTarget.hasAttribute("noautoclose")) {
+      PanelUI.hide();
+    }
+  },
+
+  /**
+   * Open a dialog window that allow the user to customize listed character sets.
+   */
+  onCharsetCustomizeCommand: function() {
+    this.hide();
+    window.openDialog("chrome://global/content/customizeCharset.xul",
+                      "PrefWindow",
+                      "chrome,modal=yes,resizable=yes",
+                      "browser");
+  },
+
+  /** 
+   * Signal that we're about to make a lot of changes to the contents of the
+   * panels all at once. For performance, we ignore the mutations.
+   */
+  beginBatchUpdate: function() {
+    this._ensureEventListenersAdded();
+    this.multiView.ignoreMutations = true;
+  },
+
+  /**
+   * Signal that we're done making bulk changes to the panel. We now pay
+   * attention to mutations. This automatically synchronizes the multiview
+   * container with whichever view is displayed if the panel is open.
+   */
+  endBatchUpdate: function(aReason) {
+    this._ensureEventListenersAdded();
+    this.multiView.ignoreMutations = false;
+  },
+
+  /**
+   * Sets the anchor node into the open or closed state, depending
+   * on the state of the panel.
+   */
+  _updatePanelButton: function() {
+    this.menuButton.open = this.panel.state == "open" ||
+                           this.panel.state == "showing";
+  },
+
+  _onHelpViewShow: function(aEvent) {
+    // Call global menu setup function
+    buildHelpMenu();
+
+    let helpMenu = document.getElementById("menu_HelpPopup");
+    let items = this.getElementsByTagName("vbox")[0];
+    let attrs = ["oncommand", "onclick", "label", "key", "disabled"];
+    let NSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+    // Remove all buttons from the view
+    while (items.firstChild) {
+      items.removeChild(items.firstChild);
+    }
+
+    // Add the current set of menuitems of the Help menu to this view
+    let menuItems = Array.prototype.slice.call(helpMenu.getElementsByTagName("menuitem"));
+    let fragment = document.createDocumentFragment();
+    for (let node of menuItems) {
+      if (node.hidden)
+        continue;
+      let button = document.createElementNS(NSXUL, "toolbarbutton");
+      // Copy specific attributes from a menuitem of the Help menu
+      for (let attrName of attrs) {
+        if (!node.hasAttribute(attrName))
+          continue;
+        button.setAttribute(attrName, node.getAttribute(attrName));
+      }
+      fragment.appendChild(button);
+    }
+    items.appendChild(fragment);
+
+    this.addEventListener("command", PanelUI.onCommandHandler);
+  },
+
+  _onHelpViewHide: function(aEvent) {
+    this.removeEventListener("command", PanelUI.onCommandHandler);
+  }
+};
diff --git a/browser/components/customizableui/content/panelUI.xml b/browser/components/customizableui/content/panelUI.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3e1de7a2ad0d1ce2b4f3321a513b2398cc27b157
--- /dev/null
+++ b/browser/components/customizableui/content/panelUI.xml
@@ -0,0 +1,342 @@
+<?xml version="1.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/. -->
+
+<bindings id="browserPanelUIBindings"
+          xmlns="http://www.mozilla.org/xbl"
+          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+          xmlns:xbl="http://www.mozilla.org/xbl">
+
+  <binding id="panelmultiview">
+    <resources>
+      <stylesheet src="chrome://browser/content/customizableui/panelUI.css"/>
+    </resources>
+    <content>
+      <xul:box anonid="viewContainer" class="panel-viewcontainer" xbl:inherits="panelopen,viewtype,transitioning">
+        <xul:stack anonid="viewStack" xbl:inherits="viewtype" viewtype="main" class="panel-viewstack">
+          <xul:vbox anonid="mainViewContainer" class="panel-mainview"/>
+
+          <!-- Used to capture click events over the PanelUI-mainView if we're in
+               subview mode. That way, any click on the PanelUI-mainView causes us
+               to revert to the mainView mode, whereupon PanelUI-click-capture then
+               allows click events to go through it. -->
+          <xul:vbox anonid="clickCapturer" class="panel-clickcapturer"/>
+
+          <!-- We manually set display: none (via a CSS attribute selector) on the
+               subviews that are not being displayed. We're using this over a deck
+               because a deck assumes the size of its largest child, regardless of
+               whether or not it is shown. That's not good for our case, since we
+               want to allow each subview to be uniquely sized. -->
+          <xul:vbox anonid="subViews" class="panel-subviews" xbl:inherits="panelopen">
+            <children includes="panelview"/>
+          </xul:vbox>
+        </xul:stack>
+      </xul:box>
+    </content>
+    <implementation implements="nsIDOMEventListener">
+      <field name="_clickCapturer" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "clickCapturer");
+      </field>
+      <field name="_viewContainer" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "viewContainer");
+      </field>
+      <field name="_mainViewContainer" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "mainViewContainer");
+      </field>
+      <field name="_subViews" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "subViews");
+      </field>
+      <field name="_viewStack" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "viewStack");
+      </field>
+      <field name="_panel" readonly="true">
+        this.parentNode;
+      </field>
+
+      <field name="_currentSubView">null</field>
+      <field name="_anchorElement">null</field>
+      <field name="_mainViewHeight">0</field>
+      <field name="_subViewObserver">null</field>
+      <field name="__transitioning">false</field>
+      <field name="_ignoreMutations">false</field>
+
+      <property name="showingSubView" readonly="true"
+                onget="return this._viewStack.getAttribute('viewtype') == 'subview'"/>
+      <property name="_mainViewId" onget="return this.getAttribute('mainViewId');" onset="this.setAttribute('mainViewId', val); return val;"/>
+      <property name="_mainView" readonly="true"
+                onget="return this._mainViewId ? document.getElementById(this._mainViewId) : null;"/>
+
+      <property name="ignoreMutations">
+        <getter>
+          return this._ignoreMutations;
+        </getter>
+        <setter><![CDATA[
+          this._ignoreMutations = val;
+          if (!val && this._panel.state == "open") {
+            if (this.showingSubView) {
+              this._syncContainerWithSubView();
+            } else {
+              this._syncContainerWithMainView();
+            }
+          }
+        ]]></setter>
+      </property>
+
+      <property name="_transitioning">
+        <getter>
+          return this.__transitioning;
+        </getter>
+        <setter><![CDATA[
+          this.__transitioning = val;
+          if (val) {
+            this.setAttribute("transitioning", "true");
+          } else {
+            this.removeAttribute("transitioning");
+          }
+        ]]></setter>
+      </property>
+      <constructor><![CDATA[
+        this._clickCapturer.addEventListener("click", this);
+        this._panel.addEventListener("popupshowing", this);
+        this._panel.addEventListener("popupshown", this);
+        this._panel.addEventListener("popuphidden", this);
+        this._subViews.addEventListener("overflow", this);
+        this._mainViewContainer.addEventListener("overflow", this);
+
+        // Get a MutationObserver ready to react to subview size changes. We
+        // only attach this MutationObserver when a subview is being displayed.
+        this._subViewObserver =
+          new MutationObserver(this._syncContainerWithSubView.bind(this));
+        this._mainViewObserver =
+          new MutationObserver(this._syncContainerWithMainView.bind(this));
+
+        this._mainViewContainer.setAttribute("panelid",
+                                             this._panel.id);
+
+        if (this._mainView) {
+          this.setMainView(this._mainView);
+        }
+        this.setAttribute("viewtype", "main");
+      ]]></constructor>
+
+      <destructor><![CDATA[
+        if (this._mainView) {
+          this._mainView.removeAttribute("mainview");
+        }
+        this._mainViewObserver.disconnect();
+        this._subViewObserver.disconnect();
+        this._panel.removeEventListener("popupshowing", this);
+        this._panel.removeEventListener("popupshown", this);
+        this._panel.removeEventListener("popuphidden", this);
+        this._subViews.removeEventListener("overflow", this);
+        this._mainViewContainer.removeEventListener("overflow", this);
+        this._clickCapturer.removeEventListener("click", this);
+      ]]></destructor>
+
+      <method name="setMainView">
+        <parameter name="aNewMainView"/>
+        <body><![CDATA[
+        if (this._mainView) {
+          this._mainViewObserver.disconnect();
+          this._subViews.appendChild(this._mainView);
+          this._mainView.removeAttribute("mainview");
+        }
+        this._mainViewId = aNewMainView.id;
+        aNewMainView.setAttribute("mainview", "true");
+        this._mainViewContainer.appendChild(aNewMainView);
+        ]]></body>
+      </method>
+
+      <method name="showMainView">
+        <body><![CDATA[
+          if (this.showingSubView) {
+            let viewNode = this._currentSubView;
+            let evt = document.createEvent("CustomEvent");
+            evt.initCustomEvent("ViewHiding", true, true, viewNode);
+            viewNode.dispatchEvent(evt);
+
+            viewNode.removeAttribute("current");
+            this._currentSubView = null;
+
+            this._subViewObserver.disconnect();
+
+            this._transitioning = true;
+
+            this._viewContainer.addEventListener("transitionend", function trans() {
+              this._viewContainer.removeEventListener("transitionend", trans);
+              this._transitioning = false;
+            }.bind(this));
+            this._viewContainer.style.height = this._mainViewHeight + "px";
+
+            this.setAttribute("viewtype", "main");
+          }
+
+          this._mainViewObserver.observe(this._mainView, {
+            attributes: true,
+            characterData: true,
+            childList: true,
+            subtree: true
+          });
+
+          this._shiftMainView();
+        ]]></body>
+      </method>
+
+      <method name="showSubView">
+        <parameter name="aViewId"/>
+        <parameter name="aAnchor"/>
+        <body><![CDATA[
+          let viewNode = this.querySelector("#" + aViewId);
+          viewNode.setAttribute("current", true);
+          // Emit the ViewShowing event so that the widget definition has a chance
+          // to lazily populate the subview with things.
+          let evt = document.createEvent("CustomEvent");
+          evt.initCustomEvent("ViewShowing", true, true, viewNode);
+          viewNode.dispatchEvent(evt);
+          if (evt.defaultPrevented) {
+            return;
+          }
+
+          this._currentSubView = viewNode;
+
+          // Now we have to transition to transition the panel. There are a few parts
+          // to this:
+          //
+          // 1) The main view content gets shifted so that the center of the anchor
+          //    node is at the left-most edge of the panel.
+          // 2) The subview deck slides in so that it takes up almost all of the
+          //    panel.
+          // 3) If the subview is taller then the main panel contents, then the panel
+          //    must grow to meet that new height. Otherwise, it must shrink.
+          //
+          // All three of these actions make use of CSS transformations, so they
+          // should all occur simultaneously.
+          this.setAttribute("viewtype", "subview");
+          this._shiftMainView(aAnchor);
+
+          this._mainViewHeight = this._viewStack.clientHeight;
+
+          this._transitioning = true;
+          this._viewContainer.addEventListener("transitionend", function trans() {
+            this._viewContainer.removeEventListener("transitionend", trans);
+            this._transitioning = false;
+          }.bind(this));
+          this._viewContainer.style.height = this._subViews.scrollHeight + "px";
+
+          this._subViewObserver.observe(viewNode, {
+            attributes: true,
+            characterData: true,
+            childList: true,
+            subtree: true
+          });
+        ]]></body>
+      </method>
+
+      <method name="_shiftMainView">
+        <parameter name="aAnchor"/>
+        <body><![CDATA[
+          if (aAnchor) {
+            // We need to find the edge of the anchor, relative to the main panel.
+            // Then we need to add half the width of the anchor. This is the target
+            // that we need to transition to.
+            let anchorRect = aAnchor.getBoundingClientRect();
+            let mainViewRect = this._mainViewContainer.getBoundingClientRect();
+            let center = aAnchor.clientWidth / 2;
+            let direction = aAnchor.ownerDocument.defaultView.getComputedStyle(aAnchor, null).direction;
+            let edge, target;
+            if (direction == "ltr") {
+              edge = anchorRect.left - mainViewRect.left;
+              target = "-" + (edge + center);
+            } else {
+              edge = mainViewRect.right - anchorRect.right;
+              target = edge + center;
+            }
+            this._mainViewContainer.style.transform = "translateX(" + target + "px)";
+            aAnchor.classList.add("panel-multiview-anchor");
+          } else {
+            this._mainViewContainer.style.transform = "";
+            if (this.anchorElement)
+              this.anchorElement.classList.remove("panel-multiview-anchor");
+          }
+          this.anchorElement = aAnchor;
+        ]]></body>
+      </method>
+
+      <method name="handleEvent">
+        <parameter name="aEvent"/>
+        <body><![CDATA[
+          switch(aEvent.type) {
+            case "click":
+              if (aEvent.originalTarget == this._clickCapturer) {
+                this.showMainView();
+              }
+              break;
+            case "overflow":
+              // Resize the right view on the next tick.
+              if (this.showingSubView) {
+                setTimeout(this._syncContainerWithSubView.bind(this), 0);
+              } else if (!this.transitioning) {
+                setTimeout(this._syncContainerWithMainView.bind(this), 0);
+              }
+              break;
+            case "popupshowing":
+              this.setAttribute("panelopen", "true");
+              this._syncContainerWithMainView();
+              break;
+            case "popupshown":
+              this._setMaxHeight();
+              break;
+            case "popuphidden":
+              this.removeAttribute("panelopen");
+              this._mainView.style.height = "";
+              this.showMainView();
+              break;
+          }
+        ]]></body>
+      </method>
+
+      <method name="_setMaxHeight">
+        <body><![CDATA[
+          // Ignore the mutation that'll fire when we set the height of
+          // the main view.
+          this.ignoreMutations = true;
+          this._mainView.style.height =
+            this.getBoundingClientRect().height + "px";
+          this.ignoreMutations = false;
+        ]]></body>
+      </method>
+      <method name="_syncContainerWithSubView">
+        <body><![CDATA[
+          if (!this.ignoreMutations && this.showingSubView) {
+            this._viewContainer.style.height =
+              this._subViews.scrollHeight + "px";
+          }
+        ]]></body>
+      </method>
+      <method name="_syncContainerWithMainView">
+        <body><![CDATA[
+          if (!this.ignoreMutations && !this.showingSubView && !this._transitioning) {
+            this._viewContainer.style.height =
+              this._mainView.scrollHeight + "px";
+          }
+        ]]></body>
+      </method>
+
+    </implementation>
+  </binding>
+
+  <binding id="panelview">
+    <implementation>
+      <property name="panelMultiView" readonly="true">
+        <getter><![CDATA[
+          if (this.parentNode.localName != "panelmultiview") {
+            return document.getBindingParent(this.parentNode);
+          }
+
+          return this.parentNode;
+        ]]></getter>
+      </property>
+    </implementation>
+  </binding>
+</bindings>
diff --git a/browser/components/customizableui/content/toolbar.xml b/browser/components/customizableui/content/toolbar.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4176c8f431c9c7cea4b0f14ca055555be2165339
--- /dev/null
+++ b/browser/components/customizableui/content/toolbar.xml
@@ -0,0 +1,556 @@
+<?xml version="1.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/. -->
+
+<bindings id="browserToolbarBindings"
+          xmlns="http://www.mozilla.org/xbl"
+          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+          xmlns:xbl="http://www.mozilla.org/xbl">
+
+  <binding id="toolbar">
+    <resources>
+      <stylesheet src="chrome://global/skin/toolbar.css"/>
+    </resources>
+    <implementation implements="nsIAccessibleProvider">
+      <field name="overflowedDuringConstruction">null</field>
+
+      <property name="accessibleType" readonly="true">
+        <getter>
+          return Components.interfaces.nsIAccessibleProvider.XULToolbar;
+        </getter>
+      </property>
+
+      <constructor><![CDATA[
+          let scope = {};
+          Cu.import("resource:///modules/CustomizableUI.jsm", scope);
+          // Add an early overflow event listener that will mark if the
+          // toolbar overflowed during construction.
+          if (scope.CustomizableUI.isAreaOverflowable(this.id)) {
+            this.addEventListener("overflow", this);
+            this.addEventListener("underflow", this);
+          }
+
+          if (document.readyState == "complete") {
+            this._init();
+          } else {
+            // Need to wait until XUL overlays are loaded. See bug 554279.
+            let self = this;
+            document.addEventListener("readystatechange", function onReadyStateChange() {
+              if (document.readyState != "complete")
+                return;
+              document.removeEventListener("readystatechange", onReadyStateChange, false);
+              self._init();
+            }, false);
+          }
+      ]]></constructor>
+
+      <method name="_init">
+        <body><![CDATA[
+          let scope = {};
+          Cu.import("resource:///modules/CustomizableUI.jsm", scope);
+          let CustomizableUI = scope.CustomizableUI;
+
+          // Searching for the toolbox palette in the toolbar binding because
+          // toolbars are constructed first.
+          let toolbox = this.toolbox;
+          if (toolbox && !toolbox.palette) {
+            for (let node of toolbox.children) {
+              if (node.localName == "toolbarpalette") {
+                // Hold on to the palette but remove it from the document.
+                toolbox.palette = node;
+                toolbox.removeChild(node);
+                break;
+              }
+            }
+          }
+
+          // pass the current set of children for comparison with placements:
+          let children = [node.id for (node of this.childNodes)
+                          if (node.getAttribute("skipintoolbarset") != "true" && node.id)];
+          CustomizableUI.registerToolbarNode(this, children);
+        ]]></body>
+      </method>
+
+      <method name="handleEvent">
+        <parameter name="aEvent"/>
+        <body><![CDATA[
+          if (aEvent.type == "overflow" && aEvent.detail > 0) {
+            if (this.overflowable && this.overflowable.initialized) {
+              this.overflowable.onOverflow(aEvent);
+            } else {
+              this.overflowedDuringConstruction = aEvent;
+            }
+          } else if (aEvent.type == "underflow" && aEvent.detail > 0) {
+            this.overflowedDuringConstruction = null;
+          }
+        ]]></body>
+      </method>
+
+      <method name="insertItem">
+        <parameter name="aId"/>
+        <parameter name="aBeforeElt"/>
+        <parameter name="aWrapper"/>
+        <body><![CDATA[
+          if (aWrapper) {
+            Cu.reportError("Can't insert " + aId + ": using insertItem " +
+                           "no longer supports wrapper elements.");
+            return null;
+          }
+
+          // Hack, the customizable UI code makes this be the last position
+          let pos = null;
+          if (aBeforeElt) {
+            let beforeInfo = CustomizableUI.getPlacementOfWidget(aBeforeElt.id);
+            if (beforeInfo.area != this.id) {
+              Cu.reportError("Can't insert " + aId + " before " +
+                             aBeforeElt.id + " which isn't in this area (" +
+                             this.id + ").");
+              return null;
+            }
+            pos = beforeInfo.position;
+          }
+
+          CustomizableUI.addWidgetToArea(aId, this.id, pos);
+          return this.ownerDocument.getElementById(aId);
+        ]]></body>
+      </method>
+
+      <property name="toolbarName"
+                onget="return this.getAttribute('toolbarname');"
+                onset="this.setAttribute('toolbarname', val); return val;"/>
+
+      <property name="customizationTarget" readonly="true">
+        <getter><![CDATA[
+          if (this._customizationTarget)
+            return this._customizationTarget;
+
+          let id = this.getAttribute("customizationtarget");
+          if (id)
+            this._customizationTarget = document.getElementById(id);
+
+          if (this._customizationTarget)
+            this._customizationTarget.insertItem = this.insertItem.bind(this);
+          else
+            this._customizationTarget = this;
+
+          return this._customizationTarget;
+        ]]></getter>
+      </property>
+
+      <property name="toolbox" readonly="true">
+        <getter><![CDATA[
+          if (this._toolbox)
+            return this._toolbox;
+
+          let toolboxId = this.getAttribute("toolboxid");
+          if (toolboxId) {
+            let toolbox = document.getElementById(toolboxId);
+            if (toolbox) {
+              if (toolbox.externalToolbars.indexOf(this) == -1)
+                toolbox.externalToolbars.push(this);
+
+              this._toolbox = toolbox;
+            }
+          }
+
+          if (!this._toolbox && this.parentNode &&
+              this.parentNode.localName == "toolbox") {
+            this._toolbox = this.parentNode;
+          }
+
+          return this._toolbox;
+        ]]></getter>
+      </property>
+
+      <property name="currentSet">
+        <getter><![CDATA[
+          let currentWidgets = new Set();
+          for (let node of this.customizationTarget.children) {
+            let realNode = node.localName == "toolbarpaletteitem" ? node.firstChild : node;
+            if (realNode.getAttribute("skipintoolbarset") != "true") {
+              currentWidgets.add(realNode.id);
+            }
+          }
+          if (this.getAttribute("overflowing") == "true") {
+            let overflowTarget = this.getAttribute("overflowtarget");
+            let overflowList = this.ownerDocument.getElementById(overflowTarget);
+            for (let node of overflowList.children) {
+              let realNode = node.localName == "toolbarpaletteitem" ? node.firstChild : node;
+              if (realNode.getAttribute("skipintoolbarset") != "true") {
+                currentWidgets.add(realNode.id);
+              }
+            }
+          }
+          let orderedPlacements = CustomizableUI.getWidgetIdsInArea(this.id);
+          return orderedPlacements.filter((x) => currentWidgets.has(x)).join(',');
+        ]]></getter>
+        <setter><![CDATA[
+          // Get list of new and old ids:
+          let newVal = (val || '').split(',').filter(x => x);
+          let oldIds = CustomizableUI.getWidgetIdsInArea(this.id);
+
+          // Get a list of items only in the new list
+          let newIds = [id for (id of newVal) if (oldIds.indexOf(id) == -1)];
+          CustomizableUI.beginBatchUpdate();
+          for (let newId of newIds) {
+            oldIds = CustomizableUI.getWidgetIdsInArea(this.id);
+            let nextId = newId;
+            let pos;
+            do {
+              // Get the next item
+              nextId = newVal[newVal.indexOf(nextId) + 1];
+              // Figure out where it is in the old list
+              pos = oldIds.indexOf(nextId);
+              // If it's not in the old list, repeat:
+            } while (pos == -1 && nextId);
+            if (pos == -1) {
+              pos = null; // We didn't find anything, insert at the end
+            }
+            CustomizableUI.addWidgetToArea(newId, this.id, pos);
+          }
+
+          let currentIds = this.currentSet.split(',');
+          let removedIds = [id for (id of currentIds) if (newIds.indexOf(id) == -1 && newVal.indexOf(id) == -1)];
+          for (let removedId of removedIds) {
+            CustomizableUI.removeWidgetFromArea(removedId);
+          }
+          CustomizableUI.endBatchUpdate();
+        ]]></setter>
+      </property>
+
+
+    </implementation>
+  </binding>
+
+  <binding id="toolbar-menubar-stub">
+    <implementation>
+      <property name="toolbox" readonly="true">
+        <getter><![CDATA[
+          if (this._toolbox)
+            return this._toolbox;
+
+          if (this.parentNode && this.parentNode.localName == "toolbox") {
+            this._toolbox = this.parentNode;
+          }
+
+          return this._toolbox;
+        ]]></getter>
+      </property>
+      <property name="currentSet" readonly="true">
+        <getter><![CDATA[
+          return this.getAttribute("defaultset");
+        ]]></getter>
+      </property>
+      <method name="insertItem">
+        <body><![CDATA[
+          return null;
+        ]]></body>
+      </method>
+    </implementation>
+  </binding>
+
+  <!-- The toolbar-menubar-autohide and toolbar-drag bindings are almost
+       verbatim copies of their toolkit counterparts - they just inherit from
+       the customizableui's toolbar binding instead of toolkit's. We're currently
+       OK with the maintainance burden of having two copies of a binding, since
+       the long term goal is to move the customization framework into toolkit. -->
+
+  <binding id="toolbar-menubar-autohide"
+           extends="chrome://browser/content/customizableui/toolbar.xml#toolbar">
+    <implementation>
+      <constructor>
+        this._setInactive();
+      </constructor>
+      <destructor>
+        this._setActive();
+      </destructor>
+
+      <field name="_inactiveTimeout">null</field>
+
+      <field name="_contextMenuListener"><![CDATA[({
+        toolbar: this,
+        contextMenu: null,
+
+        get active () !!this.contextMenu,
+
+        init: function (event) {
+          let node = event.target;
+          while (node != this.toolbar) {
+            if (node.localName == "menupopup")
+              return;
+            node = node.parentNode;
+          }
+
+          let contextMenuId = this.toolbar.getAttribute("context");
+          if (!contextMenuId)
+            return;
+
+          this.contextMenu = document.getElementById(contextMenuId);
+          if (!this.contextMenu)
+            return;
+
+          this.contextMenu.addEventListener("popupshown", this, false);
+          this.contextMenu.addEventListener("popuphiding", this, false);
+          this.toolbar.addEventListener("mousemove", this, false);
+        },
+        handleEvent: function (event) {
+          switch (event.type) {
+            case "popupshown":
+              this.toolbar.removeEventListener("mousemove", this, false);
+              break;
+            case "popuphiding":
+            case "mousemove":
+              this.toolbar._setInactiveAsync();
+              this.toolbar.removeEventListener("mousemove", this, false);
+              this.contextMenu.removeEventListener("popuphiding", this, false);
+              this.contextMenu.removeEventListener("popupshown", this, false);
+              this.contextMenu = null;
+              break;
+          }
+        }
+      })]]></field>
+
+      <method name="_setInactive">
+        <body><![CDATA[
+          this.setAttribute("inactive", "true");
+        ]]></body>
+      </method>
+
+      <method name="_setInactiveAsync">
+        <body><![CDATA[
+          this._inactiveTimeout = setTimeout(function (self) {
+            if (self.getAttribute("autohide") == "true") {
+              self._inactiveTimeout = null;
+              self._setInactive();
+            }
+          }, 0, this);
+        ]]></body>
+      </method>
+
+      <method name="_setActive">
+        <body><![CDATA[
+          if (this._inactiveTimeout) {
+            clearTimeout(this._inactiveTimeout);
+            this._inactiveTimeout = null;
+          }
+          this.removeAttribute("inactive");
+        ]]></body>
+      </method>
+    </implementation>
+
+    <handlers>
+      <handler event="DOMMenuBarActive"     action="this._setActive();"/>
+      <handler event="popupshowing"         action="this._setActive();"/>
+      <handler event="mousedown" button="2" action="this._contextMenuListener.init(event);"/>
+      <handler event="DOMMenuBarInactive"><![CDATA[
+        if (!this._contextMenuListener.active)
+          this._setInactiveAsync();
+      ]]></handler>
+    </handlers>
+  </binding>
+
+  <binding id="toolbar-drag"
+           extends="chrome://browser/content/customizableui/toolbar.xml#toolbar">
+    <implementation>
+      <field name="_dragBindingAlive">true</field>
+      <constructor><![CDATA[
+        if (!this._draggableStarted) {
+          this._draggableStarted = true;
+          try {
+            let tmp = {};
+            Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
+            let draggableThis = new tmp.WindowDraggingElement(this);
+            draggableThis.mouseDownCheck = function(e) {
+              return this._dragBindingAlive;
+            };
+          } catch (e) {}
+        }
+      ]]></constructor>
+    </implementation>
+  </binding>
+
+
+<!-- This is a peculiar binding. It is here to deal with overlayed/inserted add-on content,
+      and immediately direct such content elsewhere. -->
+  <binding id="addonbar-delegating">
+    <implementation>
+      <constructor><![CDATA[
+          // Reading these immediately so nobody messes with them anymore:
+          this._delegatingToolbar = this.getAttribute("toolbar-delegate");
+          // Leaving those in here to unbreak some code:
+          if (document.readyState == "complete") {
+            this._init();
+          } else {
+            // Need to wait until XUL overlays are loaded. See bug 554279.
+            let self = this;
+            document.addEventListener("readystatechange", function onReadyStateChange() {
+              if (document.readyState != "complete")
+                return;
+              document.removeEventListener("readystatechange", onReadyStateChange, false);
+              self._init();
+            }, false);
+          }
+      ]]></constructor>
+
+      <method name="_init">
+        <body><![CDATA[
+          // Searching for the toolbox palette in the toolbar binding because
+          // toolbars are constructed first.
+          let toolbox = this.toolbox;
+          if (toolbox && !toolbox.palette) {
+            for (let node of toolbox.children) {
+              if (node.localName == "toolbarpalette") {
+                // Hold on to the palette but remove it from the document.
+                toolbox.palette = node;
+                toolbox.removeChild(node);
+              }
+            }
+          }
+
+          // pass the current set of children for comparison with placements:
+          let children = [node.id for (node of this.childNodes)
+                          if (node.getAttribute("skipintoolbarset") != "true" && node.id)];
+          CustomizableUI.registerToolbarNode(this, children);
+          this.evictNodes();
+          // We can't easily use |this| or strong bindings for the observer fn here
+          // because that creates leaky circular references when the node goes away,
+          // and XBL destructors are unreliable.
+          let mutationObserver = new MutationObserver(function(mutations) {
+            if (!mutations.length) {
+              return;
+            }
+            let toolbar = mutations[0].target;
+            // Can't use our own attribute because we might not have one if we're set to
+            // collapsed
+            let areCustomizing = toolbar.ownerDocument.documentElement.getAttribute("customizing");
+            if (!toolbar._isModifying && !areCustomizing) {
+              toolbar.evictNodes();
+            }
+          });
+          mutationObserver.observe(this, {childList: true});
+        ]]></body>
+      </method>
+      <method name="evictNodes">
+        <body><![CDATA[
+          this._isModifying = true;
+          let i = this.childNodes.length;
+          while (i--) {
+            let node = this.childNodes[i];
+            if (this.childNodes[i].id) {
+              this.evictNode(this.childNodes[i]);
+            } else {
+              node.remove();
+            }
+          }
+          this._isModifying = false;
+        ]]></body>
+      </method>
+      <method name="evictNode">
+        <parameter name="aNode"/>
+        <body>
+        <![CDATA[
+          if (this._whiteListed.has(aNode.id) || CustomizableUI.isSpecialWidget(aNode.id)) {
+            return;
+          }
+          const kItemMaxWidth = 100;
+          let oldParent = aNode.parentNode;
+
+          try {
+            aNode.setAttribute("removable", "true");
+
+            let nodeWidth = aNode.getBoundingClientRect().width;
+            if (nodeWidth == 0 || nodeWidth > kItemMaxWidth) {
+              throw new Error(aNode.id + " is too big (" + nodeWidth +
+                              "px wide), moving to the palette");
+            }
+            CustomizableUI.addWidgetToArea(aNode.id, this._delegatingToolbar);
+          } catch (ex) {
+            Cu.reportError(ex);
+            // This will throw if the node is too big, or can't be moved there for
+            // some reason. Try to remove it anyway:
+            try {
+              CustomizableUI.removeWidgetFromArea(aNode.id);
+            } catch (ex) {
+              Cu.reportError(ex);
+              aNode.remove();
+            }
+          }
+
+          // Surprise: addWidgetToArea(palette) will get you nothing if the palette
+          // is not constructed yet. Fix:
+          if (aNode.parentNode == oldParent) {
+            let palette = this.toolbox.palette;
+            if (palette && oldParent != palette) {
+              palette.appendChild(aNode);
+            }
+          }
+        ]]></body>
+      </method>
+      <method name="insertItem">
+        <parameter name="aId"/>
+        <parameter name="aBeforeElt"/>
+        <parameter name="aWrapper"/>
+        <body><![CDATA[
+          if (aWrapper) {
+            Cu.reportError("Can't insert " + aId + ": using insertItem " +
+                           "no longer supports wrapper elements.");
+            return null;
+          }
+
+          let widget = CustomizableUI.getWidget(aId);
+          widget = widget && widget.forWindow(window);
+          let node = widget && widget.node;
+          if (!node) {
+            return null;
+          }
+
+          this._isModifying = true;
+          // Temporarily add it here so it can have a width, then ditch it:
+          this.appendChild(node);
+          this.evictNode(node);
+          this._isModifying = false;
+          // We will now have moved stuff around; kick off an aftercustomization event
+          // so add-ons know we've just moved their stuff:
+          if (window.gCustomizeMode) {
+            window.gCustomizeMode.dispatchToolboxEvent("aftercustomization");
+          }
+          return node;
+        ]]></body>
+      </method>
+      <property name="customizationTarget" readonly="true">
+        <getter><![CDATA[
+          return this;
+        ]]></getter>
+      </property>
+      <property name="currentSet">
+        <getter><![CDATA[
+          return [node.id for (node of this.children)].join(',');
+        ]]></getter>
+        <setter><![CDATA[
+          let v = val.split(',');
+          let newButtons = v.filter(x => x && (!this._whiteListed.has(x) &&
+                                               !CustomizableUI.isSpecialWidget(x) &&
+                                               !this._currentSetMigrated.has(x)));
+          for (x of newButtons) {
+            this._currentSetMigrated.add(x);
+            this.insertItem(x);
+          }
+        ]]></setter>
+      </property>
+      <property name="toolbox" readonly="true">
+        <getter><![CDATA[
+          if (!this._toolbox && this.parentNode &&
+              this.parentNode.localName == "toolbox") {
+            this._toolbox = this.parentNode;
+          }
+
+          return this._toolbox;
+        ]]></getter>
+      </property>
+      <field name="_whiteListed" readonly="true">new Set(["addonbar-closebutton", "status-bar"])</field>
+      <field name="_isModifying">false</field>
+      <field name="_currentSetMigrated">new Set()</field>
+    </implementation>
+  </binding>
+</bindings>
diff --git a/browser/components/customizableui/moz.build b/browser/components/customizableui/moz.build
new file mode 100644
index 0000000000000000000000000000000000000000..2ee6d89f028abbd17ce1440d82af15c6c90deaca
--- /dev/null
+++ b/browser/components/customizableui/moz.build
@@ -0,0 +1,12 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+PARALLEL_DIRS += [
+		'content',
+		'src',
+]
+
+BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
diff --git a/browser/components/customizableui/src/CustomizableUI.jsm b/browser/components/customizableui/src/CustomizableUI.jsm
new file mode 100644
index 0000000000000000000000000000000000000000..c2cc976fd544758357264450e8b2ae4933c906a5
--- /dev/null
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -0,0 +1,2611 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["CustomizableUI"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PanelWideWidgetTracker",
+  "resource:///modules/PanelWideWidgetTracker.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "CustomizableWidgets",
+  "resource:///modules/CustomizableWidgets.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
+  "resource://gre/modules/DeferredTask.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
+  "resource://gre/modules/PrivateBrowsingUtils.jsm");
+XPCOMUtils.defineLazyGetter(this, "gWidgetsBundle", function() {
+  const kUrl = "chrome://browser/locale/customizableui/customizableWidgets.properties";
+  return Services.strings.createBundle(kUrl);
+});
+XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
+  "resource://gre/modules/ShortcutUtils.jsm");
+XPCOMUtils.defineLazyServiceGetter(this, "gELS",
+  "@mozilla.org/eventlistenerservice;1", "nsIEventListenerService");
+
+const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+const kSpecialWidgetPfx = "customizableui-special-";
+
+const kCustomizationContextMenu = "customizationContextMenu";
+
+
+const kPrefCustomizationState        = "browser.uiCustomization.state";
+const kPrefCustomizationAutoAdd      = "browser.uiCustomization.autoAdd";
+const kPrefCustomizationDebug        = "browser.uiCustomization.debug";
+
+/**
+ * The keys are the handlers that are fired when the event type (the value)
+ * is fired on the subview. A widget that provides a subview has the option
+ * of providing onViewShowing and onViewHiding event handlers.
+ */
+const kSubviewEvents = [
+  "ViewShowing",
+  "ViewHiding"
+];
+
+/**
+ * gPalette is a map of every widget that CustomizableUI.jsm knows about, keyed
+ * on their IDs.
+ */
+let gPalette = new Map();
+
+/**
+ * gAreas maps area IDs to Sets of properties about those areas. An area is a
+ * place where a widget can be put.
+ */
+let gAreas = new Map();
+
+/**
+ * gPlacements maps area IDs to Arrays of widget IDs, indicating that the widgets
+ * are placed within that area (either directly in the area node, or in the
+ * customizationTarget of the node).
+ */
+let gPlacements = new Map();
+
+/**
+ * gFuturePlacements represent placements that will happen for areas that have
+ * not yet loaded (due to lazy-loading). This can occur when add-ons register
+ * widgets.
+ */
+let gFuturePlacements = new Map();
+
+//XXXunf Temporary. Need a nice way to abstract functions to build widgets
+//       of these types.
+let gSupportedWidgetTypes = new Set(["button", "view", "custom"]);
+
+/**
+ * gPanelsForWindow is a list of known panels in a window which we may need to close
+ * should command events fire which target them.
+ */
+let gPanelsForWindow = new WeakMap();
+
+/**
+ * gSeenWidgets remembers which widgets the user has seen for the first time
+ * before. This way, if a new widget is created, and the user has not seen it
+ * before, it can be put in its default location. Otherwise, it remains in the
+ * palette.
+ */
+let gSeenWidgets = new Set();
+
+/**
+ * gDirtyAreaCache is a set of area IDs for areas where items have been added,
+ * moved or removed at least once. This set is persisted, and is used to
+ * optimize building of toolbars in the default case where no toolbars should
+ * be "dirty".
+ */
+let gDirtyAreaCache = new Set();
+
+let gSavedState = null;
+let gRestoring = false;
+let gDirty = false;
+let gInBatchStack = 0;
+let gResetting = false;
+
+/**
+ * gBuildAreas maps area IDs to actual area nodes within browser windows.
+ */
+let gBuildAreas = new Map();
+
+/**
+ * gBuildWindows is a map of windows that have registered build areas, mapped
+ * to a Set of known toolboxes in that window.
+ */
+let gBuildWindows = new Map();
+
+let gNewElementCount = 0;
+let gGroupWrapperCache = new Map();
+let gSingleWrapperCache = new WeakMap();
+let gListeners = new Set();
+
+let gModuleName = "[CustomizableUI]";
+#include logging.js
+
+let CustomizableUIInternal = {
+  initialize: function() {
+    LOG("Initializing");
+
+    this.addListener(this);
+    this._defineBuiltInWidgets();
+    this.loadSavedState();
+
+    let panelPlacements = [
+      "edit-controls",
+      "zoom-controls",
+      "new-window-button",
+      "privatebrowsing-button",
+      "save-page-button",
+      "print-button",
+      "history-panelmenu",
+      "fullscreen-button",
+      "find-button",
+      "preferences-button",
+      "add-ons-button",
+    ];
+    let showCharacterEncoding = Services.prefs.getComplexValue(
+      "browser.menu.showCharacterEncoding",
+      Ci.nsIPrefLocalizedString
+    ).data;
+    if (showCharacterEncoding == "true") {
+      panelPlacements.push("characterencoding-button");
+    }
+
+    this.registerArea(CustomizableUI.AREA_PANEL, {
+      anchor: "PanelUI-menu-button",
+      type: CustomizableUI.TYPE_MENU_PANEL,
+      defaultPlacements: panelPlacements
+    });
+    PanelWideWidgetTracker.init();
+
+    this.registerArea(CustomizableUI.AREA_NAVBAR, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR,
+      overflowable: true,
+      defaultPlacements: [
+        "urlbar-container",
+        "search-container",
+        "webrtc-status-button",
+        "bookmarks-menu-button",
+        "downloads-button",
+        "home-button",
+        "social-share-button",
+        "social-toolbar-item",
+      ]
+    });
+#ifndef XP_MACOSX
+    this.registerArea(CustomizableUI.AREA_MENUBAR, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR,
+      defaultPlacements: [
+        "menubar-items",
+      ]
+    });
+#endif
+    this.registerArea(CustomizableUI.AREA_TABSTRIP, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR,
+      defaultPlacements: [
+        "tabbrowser-tabs",
+        "new-tab-button",
+        "alltabs-button",
+        "tabs-closebutton",
+      ]
+    });
+    this.registerArea(CustomizableUI.AREA_BOOKMARKS, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR,
+      defaultPlacements: [
+        "personal-bookmarks",
+      ]
+    });
+
+    this.registerArea(CustomizableUI.AREA_ADDONBAR, {
+      type: CustomizableUI.TYPE_TOOLBAR,
+      legacy: true,
+      defaultPlacements: ["addonbar-closebutton", "status-bar"]
+    });
+  },
+
+  _defineBuiltInWidgets: function() {
+    //XXXunf Need to figure out how to auto-add new builtin widgets in new
+    //       app versions to already customized areas.
+    for (let widgetDefinition of CustomizableWidgets) {
+      this.createBuiltinWidget(widgetDefinition);
+    }
+  },
+
+  wrapWidget: function(aWidgetId) {
+    if (gGroupWrapperCache.has(aWidgetId)) {
+      return gGroupWrapperCache.get(aWidgetId);
+    }
+
+    let provider = this.getWidgetProvider(aWidgetId);
+    if (!provider) {
+      return null;
+    }
+
+    if (provider == CustomizableUI.PROVIDER_API) {
+      let widget = gPalette.get(aWidgetId);
+      if (!widget.wrapper) {
+        widget.wrapper = new WidgetGroupWrapper(widget);
+        gGroupWrapperCache.set(aWidgetId, widget.wrapper);
+      }
+      return widget.wrapper;
+    }
+
+    // PROVIDER_SPECIAL gets treated the same as PROVIDER_XUL.
+    let wrapper = new XULWidgetGroupWrapper(aWidgetId);
+    gGroupWrapperCache.set(aWidgetId, wrapper);
+    return wrapper;
+  },
+
+  registerArea: function(aName, aProperties) {
+    if (typeof aName != "string" || !/^[a-z0-9-_]{1,}$/i.test(aName)) {
+      throw new Error("Invalid area name");
+    }
+    if (gAreas.has(aName)) {
+      throw new Error("Area already registered");
+    }
+
+    let props = new Map();
+    for (let key in aProperties) {
+      //XXXgijs for special items, we need to make sure they have an appropriate ID
+      // so we aren't perpetually in a non-default state:
+      if (key == "defaultPlacements" && Array.isArray(aProperties[key])) {
+        props.set(key, aProperties[key].map(x => this.isSpecialWidget(x) ? this.ensureSpecialWidgetId(x) : x ));
+      } else {
+        props.set(key, aProperties[key]);
+      }
+    }
+    gAreas.set(aName, props);
+
+    if (props.get("legacy")) {
+      // Guarantee this area exists in gFuturePlacements, to avoid checking it in
+      // various places elsewhere.
+      gFuturePlacements.set(aName, new Set());
+    } else {
+      this.restoreStateForArea(aName);
+    }
+  },
+
+  unregisterArea: function(aName) {
+    if (typeof aName != "string" || !/^[a-z0-9-_]{1,}$/i.test(aName)) {
+      throw new Error("Invalid area name");
+    }
+    if (!gAreas.has(aName)) {
+      throw new Error("Area not registered");
+    }
+
+    // Move all the widgets out
+    this.beginBatchUpdate();
+    let placements = gPlacements.get(aName);
+    placements.forEach(this.removeWidgetFromArea, this);
+
+    // Delete all remaining traces.
+    gAreas.delete(aName);
+    gPlacements.delete(aName);
+    gFuturePlacements.delete(aName);
+    gBuildAreas.delete(aName);
+    this.endBatchUpdate(true);
+  },
+
+  registerToolbarNode: function(aToolbar, aExistingChildren) {
+    let area = aToolbar.id;
+    if (gBuildAreas.has(area) && gBuildAreas.get(area).has(aToolbar)) {
+      return;
+    }
+    this.beginBatchUpdate();
+    let document = aToolbar.ownerDocument;
+    let areaProperties = gAreas.get(area);
+
+    if (!areaProperties) {
+      throw new Error("Unknown customization area: " + area);
+    }
+
+    let placements = gPlacements.get(area);
+    if (!placements && areaProperties.has("legacy")) {
+      let legacyState = aToolbar.getAttribute("currentset");
+      if (legacyState) {
+        legacyState = legacyState.split(",").filter(s => s);
+      }
+
+      // Manually restore the state here, so the legacy state can be converted. 
+      this.restoreStateForArea(area, legacyState);
+      placements = gPlacements.get(area);
+    }
+
+    // Check that the current children and the current placements match. If
+    // not, mark it as dirty:
+    if (aExistingChildren.length != placements.length ||
+        aExistingChildren.every((id, i) => id == placements[i])) {
+      gDirtyAreaCache.add(area);
+    }
+
+    if (areaProperties.has("overflowable")) {
+      aToolbar.overflowable = new OverflowableToolbar(aToolbar);
+    }
+
+    this.registerBuildArea(area, aToolbar);
+
+    // We only build the toolbar if it's been marked as "dirty". Dirty means
+    // one of the following things:
+    // 1) Items have been added, moved or removed from this toolbar before.
+    // 2) The number of children of the toolbar does not match the length of
+    //    the placements array for that area.
+    //
+    // This notion of being "dirty" is stored in a cache which is persisted
+    // in the saved state.
+    if (gDirtyAreaCache.has(area)) {
+      this.buildArea(area, placements, aToolbar);
+    }
+    aToolbar.setAttribute("currentset", placements.join(","));
+    this.endBatchUpdate();
+  },
+
+  buildArea: function(aArea, aPlacements, aAreaNode) {
+    let document = aAreaNode.ownerDocument;
+    let window = document.defaultView;
+    let inPrivateWindow = PrivateBrowsingUtils.isWindowPrivate(window);
+    let container = aAreaNode.customizationTarget;
+
+    if (!container) {
+      throw new Error("Expected area " + aArea
+                      + " to have a customizationTarget attribute.");
+    }
+
+    this.beginBatchUpdate();
+
+    let currentNode = container.firstChild;
+    let placementsToRemove = new Set();
+    for (let id of aPlacements) {
+      while (currentNode && currentNode.getAttribute("skipintoolbarset") == "true") {
+        currentNode = currentNode.nextSibling;
+      }
+
+      if (currentNode && currentNode.id == id) {
+        currentNode = currentNode.nextSibling;
+        continue;
+      }
+
+      let [provider, node] = this.getWidgetNode(id, window);
+      if (!node) {
+        LOG("Unknown widget: " + id);
+        continue;
+      }
+
+      // If the placements have items in them which are (now) no longer removable,
+      // we shouldn't be moving them:
+      if (node.parentNode != container && !this.isWidgetRemovable(node)) {
+        placementsToRemove.add(id);
+        continue;
+      }
+
+      if (inPrivateWindow && provider == CustomizableUI.PROVIDER_API) {
+        let widget = gPalette.get(id);
+        if (!widget.showInPrivateBrowsing && inPrivateWindow) {
+          continue;
+        }
+      }
+
+      this.ensureButtonContextMenu(node, aArea == CustomizableUI.AREA_PANEL);
+      if (node.localName == "toolbarbutton" && aArea == CustomizableUI.AREA_PANEL) {
+        node.setAttribute("tabindex", "0");
+        if (!node.hasAttribute("type")) {
+          node.setAttribute("type", "wrap");
+        }
+      }
+
+      this.insertWidgetBefore(node, currentNode, container, aArea);
+      if (gResetting) {
+        this.notifyListeners("onWidgetReset", id, aArea);
+      }
+    }
+
+    if (currentNode) {
+      let palette = aAreaNode.toolbox ? aAreaNode.toolbox.palette : null;
+      let limit = currentNode.previousSibling;
+      let node = container.lastChild;
+      while (node && node != limit) {
+        let previousSibling = node.previousSibling;
+        // Nodes opt-in to removability. If they're removable, and we haven't
+        // seen them in the placements array, then we toss them into the palette
+        // if one exists. If no palette exists, we just remove the node. If the
+        // node is not removable, we leave it where it is. However, we can only
+        // safely touch elements that have an ID - both because we depend on
+        // IDs, and because such elements are not intended to be widgets
+        // (eg, titlebar-placeholder elements).
+        if (node.id && node.getAttribute("skipintoolbarset") != "true") {
+          if (this.isWidgetRemovable(node)) {
+            if (palette && !this.isSpecialWidget(node.id)) {
+              palette.appendChild(node);
+              this.removeLocationAttributes(node);
+            } else {
+              container.removeChild(node);
+            }
+          } else {
+            this.setLocationAttributes(currentNode, aArea);
+            node.setAttribute("removable", false);
+            LOG("Adding non-removable widget to placements of " + aArea + ": " +
+                node.id);
+            gPlacements.get(aArea).push(node.id);
+            gDirty = true;
+          }
+        }
+        node = previousSibling;
+      }
+    }
+
+    // If there are placements in here which aren't removable from their original area,
+    // we remove them from this area's placement array. They will (have) be(en) added
+    // to their original area's placements array in the block above this one.
+    if (placementsToRemove.size) {
+      let placementAry = gPlacements.get(aArea);
+      for (let id of placementsToRemove) {
+        let index = placementAry.indexOf(id);
+        placementAry.splice(index, 1);
+      }
+    }
+
+    if (gResetting) {
+      this.notifyListeners("onAreaReset", aArea);
+    }
+
+    this.endBatchUpdate();
+  },
+
+  addPanelCloseListeners: function(aPanel) {
+    gELS.addSystemEventListener(aPanel, "click", this, false);
+    gELS.addSystemEventListener(aPanel, "keypress", this, false);
+    let win = aPanel.ownerDocument.defaultView;
+    if (!gPanelsForWindow.has(win)) {
+      gPanelsForWindow.set(win, new Set());
+    }
+    gPanelsForWindow.get(win).add(this._getPanelForNode(aPanel));
+  },
+
+  removePanelCloseListeners: function(aPanel) {
+    gELS.removeSystemEventListener(aPanel, "click", this, false);
+    gELS.removeSystemEventListener(aPanel, "keypress", this, false);
+    let win = aPanel.ownerDocument.defaultView;
+    let panels = gPanelsForWindow.get(win);
+    if (panels) {
+      panels.delete(this._getPanelForNode(aPanel));
+    }
+  },
+
+  ensureButtonContextMenu: function(aNode, aShouldHaveCustomizationMenu) {
+    let currentContextMenu = aNode.getAttribute("context") ||
+                             aNode.getAttribute("contextmenu");
+    if (aShouldHaveCustomizationMenu) {
+      if (!currentContextMenu)
+        aNode.setAttribute("context", kCustomizationContextMenu);
+    } else {
+      if (currentContextMenu == kCustomizationContextMenu)
+        aNode.removeAttribute("context");
+    }
+  },
+
+  getWidgetProvider: function(aWidgetId) {
+    if (this.isSpecialWidget(aWidgetId)) {
+      return CustomizableUI.PROVIDER_SPECIAL;
+    }
+    if (gPalette.has(aWidgetId)) {
+      return CustomizableUI.PROVIDER_API;
+    }
+    // If this was an API widget that was destroyed, return null:
+    if (gSeenWidgets.has(aWidgetId)) {
+      return null;
+    }
+
+    // We fall back to the XUL provider, but we don't know for sure (at this
+    // point) whether it exists there either. So the API is technically lying.
+    // Ideally, it would be able to return an error value (or throw an
+    // exception) if it really didn't exist. Our code calling this function
+    // handles that fine, but this is a public API.
+    return CustomizableUI.PROVIDER_XUL;
+  },
+
+  getWidgetNode: function(aWidgetId, aWindow) {
+    let document = aWindow.document;
+
+    if (this.isSpecialWidget(aWidgetId)) {
+      let widgetNode = document.getElementById(aWidgetId) ||
+                       this.createSpecialWidget(aWidgetId, document);
+      return [ CustomizableUI.PROVIDER_SPECIAL, widgetNode];
+    }
+
+    let widget = gPalette.get(aWidgetId);
+    if (widget) {
+      // If we have an instance of this widget already, just use that.
+      if (widget.instances.has(document)) {
+        LOG("An instance of widget " + aWidgetId + " already exists in this "
+            + "document. Reusing.");
+        return [ CustomizableUI.PROVIDER_API,
+                 widget.instances.get(document) ];
+      }
+
+      return [ CustomizableUI.PROVIDER_API,
+               this.buildWidget(document, widget) ];
+    }
+
+    LOG("Searching for " + aWidgetId + " in toolbox.");
+    let node = this.findWidgetInWindow(aWidgetId, aWindow);
+    if (node) {
+      return [ CustomizableUI.PROVIDER_XUL, node ];
+    }
+
+    LOG("No node for " + aWidgetId + " found.");
+    return [];
+  },
+
+  registerMenuPanel: function(aPanel) {
+    if (gBuildAreas.has(CustomizableUI.AREA_PANEL) &&
+        gBuildAreas.get(CustomizableUI.AREA_PANEL).has(aPanel)) {
+      return;
+    }
+
+    let document = aPanel.ownerDocument;
+
+    for (let btn of aPanel.querySelectorAll("toolbarbutton")) {
+      btn.setAttribute("tabindex", "0");
+      this.ensureButtonContextMenu(btn, true);
+      if (!btn.hasAttribute("type")) {
+        btn.setAttribute("type", "wrap");
+      }
+    }
+
+    aPanel.toolbox = document.getElementById("navigator-toolbox");
+    aPanel.customizationTarget = aPanel;
+
+    this.addPanelCloseListeners(aPanel);
+
+    let placements = gPlacements.get(CustomizableUI.AREA_PANEL);
+    this.buildArea(CustomizableUI.AREA_PANEL, placements, aPanel);
+    this.registerBuildArea(CustomizableUI.AREA_PANEL, aPanel);
+  },
+
+  onWidgetAdded: function(aWidgetId, aArea, aPosition) {
+    this.insertNode(aWidgetId, aArea, aPosition, true);
+  },
+
+  onWidgetRemoved: function(aWidgetId, aArea) {
+    let areaNodes = gBuildAreas.get(aArea);
+    if (!areaNodes) {
+      return;
+    }
+
+    let area = gAreas.get(aArea);
+    let showInPrivateBrowsing = gPalette.has(aWidgetId)
+                              ? gPalette.get(aWidgetId).showInPrivateBrowsing
+                              : true;
+
+    for (let areaNode of areaNodes) {
+      let window = areaNode.ownerDocument.defaultView;
+      if (!showInPrivateBrowsing &&
+          PrivateBrowsingUtils.isWindowPrivate(window)) {
+        continue;
+      }
+
+      let container = areaNode.customizationTarget;
+      let widgetNode = container.ownerDocument.getElementById(aWidgetId);
+      if (!widgetNode) {
+        ERROR("Widget not found, unable to remove");
+        continue;
+      }
+
+      this.notifyListeners("onWidgetBeforeDOMChange", widgetNode, null, container, true);
+
+      // We remove location attributes here to make sure they're gone too when a
+      // widget is removed from a toolbar to the palette. See bug 930950.
+      this.removeLocationAttributes(widgetNode);
+      if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) {
+        container.removeChild(widgetNode);
+      } else {
+        widgetNode.removeAttribute("tabindex");
+        if (widgetNode.getAttribute("type") == "wrap") {
+          widgetNode.removeAttribute("type");
+        }
+        areaNode.toolbox.palette.appendChild(widgetNode);
+      }
+      this.notifyListeners("onWidgetAfterDOMChange", widgetNode, null, container, true);
+
+      if (area.get("type") == CustomizableUI.TYPE_TOOLBAR) {
+        areaNode.setAttribute("currentset", areaNode.currentSet);
+      }
+
+      let windowCache = gSingleWrapperCache.get(window);
+      if (windowCache) {
+        windowCache.delete(aWidgetId);
+      }
+    }
+  },
+
+  onWidgetMoved: function(aWidgetId, aArea, aOldPosition, aNewPosition) {
+    this.insertNode(aWidgetId, aArea, aNewPosition);
+  },
+
+  registerBuildArea: function(aArea, aNode) {
+    // We ensure that the window is registered to have its customization data
+    // cleaned up when unloading.
+    let window = aNode.ownerDocument.defaultView;
+    if (window.closed) {
+      return;
+    }
+    this.registerBuildWindow(window);
+
+    // Also register this build area's toolbox.
+    if (aNode.toolbox) {
+      gBuildWindows.get(window).add(aNode.toolbox);
+    }
+
+    if (!gBuildAreas.has(aArea)) {
+      gBuildAreas.set(aArea, new Set());
+    }
+
+    gBuildAreas.get(aArea).add(aNode);
+  },
+
+  registerBuildWindow: function(aWindow) {
+    if (!gBuildWindows.has(aWindow)) {
+      gBuildWindows.set(aWindow, new Set());
+
+      aWindow.addEventListener("unload", this);
+      aWindow.addEventListener("command", this, true);
+    }
+  },
+
+  unregisterBuildWindow: function(aWindow) {
+    aWindow.removeEventListener("unload", this);
+    aWindow.removeEventListener("command", this, true);
+    gPanelsForWindow.delete(aWindow);
+    gBuildWindows.delete(aWindow);
+    gSingleWrapperCache.delete(aWindow);
+    let document = aWindow.document;
+
+    for (let [areaId, areaNodes] of gBuildAreas) {
+      let areaProperties = gAreas.get(areaId);
+      for (let node of areaNodes) {
+        if (node.ownerDocument == document) {
+          if (areaProperties.has("overflowable")) {
+            node.overflowable.uninit();
+            node.overflowable = null;
+          }
+          areaNodes.delete(node);
+        }
+      }
+    }
+
+    for (let [,widget] of gPalette) {
+      widget.instances.delete(document);
+      this.notifyListeners("onWidgetInstanceRemoved", widget.id, document);
+    }
+  },
+
+  setLocationAttributes: function(aNode, aArea) {
+    let props = gAreas.get(aArea);
+    if (!props) {
+      throw new Error("Expected area " + aArea + " to have a properties Map " +
+                      "associated with it.");
+    }
+
+    aNode.setAttribute("cui-areatype", props.get("type") || "");
+    let anchor = props.get("anchor");
+    if (anchor) {
+      aNode.setAttribute("cui-anchorid", anchor);
+    }
+  },
+
+  removeLocationAttributes: function(aNode) {
+    aNode.removeAttribute("cui-areatype");
+    aNode.removeAttribute("cui-anchorid");
+  },
+
+  insertNode: function(aWidgetId, aArea, aPosition, isNew) {
+    let areaNodes = gBuildAreas.get(aArea);
+    if (!areaNodes) {
+      return;
+    }
+
+    let placements = gPlacements.get(aArea);
+    if (!placements) {
+      ERROR("Could not find any placements for " + aArea +
+            " when moving a widget.");
+      return;
+    }
+
+    let nextNodeId = placements[aPosition + 1];
+    // Go through each of the nodes associated with this area and move the
+    // widget to the requested location.
+    for (let areaNode of areaNodes) {
+      this.insertNodeInWindow(aWidgetId, areaNode, nextNodeId, isNew);
+    }
+  },
+
+  insertNodeInWindow: function(aWidgetId, aAreaNode, aNextNodeId, isNew) {
+    let window = aAreaNode.ownerDocument.defaultView;
+    let showInPrivateBrowsing = gPalette.has(aWidgetId)
+                              ? gPalette.get(aWidgetId).showInPrivateBrowsing
+                              : true;
+
+    if (!showInPrivateBrowsing && PrivateBrowsingUtils.isWindowPrivate(window)) {
+      return;
+    }
+
+    let [, widgetNode] = this.getWidgetNode(aWidgetId, window);
+    if (!widgetNode) {
+      ERROR("Widget '" + aWidgetId + "' not found, unable to move");
+      return;
+    }
+
+    let areaId = aAreaNode.id;
+    if (isNew) {
+      this.ensureButtonContextMenu(widgetNode, areaId == CustomizableUI.AREA_PANEL);
+      if (widgetNode.localName == "toolbarbutton" && areaId == CustomizableUI.AREA_PANEL) {
+        widgetNode.setAttribute("tabindex", "0");
+        if (!widgetNode.hasAttribute("type")) {
+          widgetNode.setAttribute("type", "wrap");
+        }
+      }
+    }
+
+    let container = aAreaNode.customizationTarget;
+    let [insertionContainer, nextNode] = this.findInsertionPoints(widgetNode, aNextNodeId, aAreaNode);
+    this.insertWidgetBefore(widgetNode, nextNode, insertionContainer, areaId);
+
+    if (gAreas.get(areaId).get("type") == CustomizableUI.TYPE_TOOLBAR) {
+      aAreaNode.setAttribute("currentset", aAreaNode.currentSet);
+    }
+  },
+
+  findInsertionPoints: function(aNode, aNextNodeId, aAreaNode) {
+    let props = gAreas.get(aAreaNode.id);
+    if (props.get("type") == CustomizableUI.TYPE_TOOLBAR && props.get("overflowable") &&
+        aAreaNode.getAttribute("overflowing") == "true") {
+      return aAreaNode.overflowable.getOverflowedInsertionPoints(aNode, aNextNodeId);
+    }
+    let nextNode = null;
+    if (aNextNodeId) {
+      nextNode = aAreaNode.customizationTarget.querySelector(idToSelector(aNextNodeId));
+    }
+    return [aAreaNode.customizationTarget, nextNode];
+  },
+
+  insertWidgetBefore: function(aNode, aNextNode, aContainer, aArea) {
+    this.notifyListeners("onWidgetBeforeDOMChange", aNode, aNextNode, aContainer);
+    this.setLocationAttributes(aNode, aArea);
+    aContainer.insertBefore(aNode, aNextNode);
+    this.notifyListeners("onWidgetAfterDOMChange", aNode, aNextNode, aContainer);
+  },
+
+  handleEvent: function(aEvent) {
+    switch (aEvent.type) {
+      case "command":
+        if (!this._originalEventInPanel(aEvent)) {
+          break;
+        }
+        aEvent = aEvent.sourceEvent;
+        // Fall through
+      case "click":
+      case "keypress":
+        this.maybeAutoHidePanel(aEvent);
+        break;
+      case "unload":
+        this.unregisterBuildWindow(aEvent.currentTarget);
+        break;
+    }
+  },
+
+  _originalEventInPanel: function(aEvent) {
+    let e = aEvent.sourceEvent;
+    if (!e) {
+      return false;
+    }
+    let node = this._getPanelForNode(e.target);
+    if (!node) {
+      return false;
+    }
+    let win = e.view;
+    let panels = gPanelsForWindow.get(win);
+    return !!panels && panels.has(node);
+  },
+
+  isSpecialWidget: function(aId) {
+    return (aId.startsWith(kSpecialWidgetPfx) ||
+            aId.startsWith("separator") ||
+            aId.startsWith("spring") ||
+            aId.startsWith("spacer"));
+  },
+
+  ensureSpecialWidgetId: function(aId) {
+    let nodeType = aId.match(/spring|spacer|separator/)[0];
+    // If the ID we were passed isn't a generated one, generate one now:
+    if (nodeType == aId) {
+      // Ids are differentiated through a unique count suffix.
+      return kSpecialWidgetPfx + aId + (++gNewElementCount);
+    }
+    return aId;
+  },
+
+  createSpecialWidget: function(aId, aDocument) {
+    let nodeName = "toolbar" + aId.match(/spring|spacer|separator/)[0];
+    let node = aDocument.createElementNS(kNSXUL, nodeName);
+    node.id = this.ensureSpecialWidgetId(aId);
+    if (nodeName == "toolbarspring") {
+      node.flex = 1;
+    }
+    return node;
+  },
+
+  /* Find a XUL-provided widget in a window. Don't try to use this
+   * for an API-provided widget or a special widget.
+   */
+  findWidgetInWindow: function(aId, aWindow) {
+    if (!gBuildWindows.has(aWindow)) {
+      throw new Error("Build window not registered");
+    }
+
+    if (!aId) {
+      ERROR("findWidgetInWindow was passed an empty string.");
+      return null;
+    }
+
+    let document = aWindow.document;
+
+    // look for a node with the same id, as the node may be
+    // in a different toolbar.
+    let node = document.getElementById(aId);
+    if (node) {
+      let parent = node.parentNode;
+      while (parent && !(parent.customizationTarget ||
+                         parent.localName == "toolbarpaletteitem")) {
+        parent = parent.parentNode;
+      }
+
+      if (parent && ((parent.customizationTarget == node.parentNode &&
+                      gBuildWindows.get(aWindow).has(parent.toolbox)) ||
+                     parent.localName == "toolbarpaletteitem")) {
+        // Normalize the removable attribute. For backwards compat, if
+        // the widget is not defined in a toolbox palette then absence
+        // of the "removable" attribute means it is not removable.
+        if (!node.hasAttribute("removable")) {
+          parent = parent.localName == "toolbarpaletteitem" ? parent.parentNode : parent;
+          // If we first see this in customization mode, it may be in the
+          // customization palette instead of the toolbox palette.
+          node.setAttribute("removable", !parent.customizationTarget);
+        }
+
+        return node;
+      }
+    }
+
+    let toolboxes = gBuildWindows.get(aWindow);
+    for (let toolbox of toolboxes) {
+      if (toolbox.palette) {
+        // Attempt to locate a node with a matching ID within
+        // the palette.
+        let node = toolbox.palette.querySelector(idToSelector(aId));
+        if (node) {
+          // Normalize the removable attribute. For backwards compat, this
+          // is optional if the widget is defined in the toolbox palette,
+          // and defaults to *true*, unlike if it was defined elsewhere.
+          if (!node.hasAttribute("removable")) {
+            node.setAttribute("removable", true);
+          }
+          return node;
+        }
+      }
+    }
+    return null;
+  },
+
+  buildWidget: function(aDocument, aWidget) {
+    if (typeof aWidget == "string") {
+      aWidget = gPalette.get(aWidget);
+    }
+    if (!aWidget) {
+      throw new Error("buildWidget was passed a non-widget to build.");
+    }
+
+    LOG("Building " + aWidget.id + " of type " + aWidget.type);
+
+    let node;
+    if (aWidget.type == "custom") {
+      if (aWidget.onBuild) {
+        try {
+          node = aWidget.onBuild(aDocument);
+        } catch (ex) {
+          ERROR("Custom widget with id " + aWidget.id + " threw an error: " + ex.message);
+        }
+      }
+      if (!node || !(node instanceof aDocument.defaultView.XULElement))
+        ERROR("Custom widget with id " + aWidget.id + " does not return a valid node");
+    }
+    else {
+      node = aDocument.createElementNS(kNSXUL, "toolbarbutton");
+
+      node.setAttribute("id", aWidget.id);
+      node.setAttribute("widget-id", aWidget.id);
+      node.setAttribute("widget-type", aWidget.type);
+      if (aWidget.disabled) {
+        node.setAttribute("disabled", true);
+      }
+      node.setAttribute("removable", aWidget.removable);
+      node.setAttribute("overflows", aWidget.overflows);
+      node.setAttribute("label", this.getLocalizedProperty(aWidget, "label"));
+      let additionalTooltipArguments = [];
+      if (aWidget.shortcutId) {
+        let keyEl = aDocument.getElementById(aWidget.shortcutId);
+        if (keyEl) {
+          additionalTooltipArguments.push(ShortcutUtils.prettifyShortcut(keyEl));
+        } else {
+          ERROR("Key element with id '" + aWidget.shortcutId + "' for widget '" + aWidget.id +
+                "' not found!");
+        }
+      }
+      let tooltip = this.getLocalizedProperty(aWidget, "tooltiptext", additionalTooltipArguments);
+      node.setAttribute("tooltiptext", tooltip);
+      node.setAttribute("class", "toolbarbutton-1 chromeclass-toolbar-additional");
+
+      let commandHandler = this.handleWidgetCommand.bind(this, aWidget, node);
+      node.addEventListener("command", commandHandler, false);
+      let clickHandler = this.handleWidgetClick.bind(this, aWidget, node);
+      node.addEventListener("click", clickHandler, false);
+
+      // If the widget has a view, and has view showing / hiding listeners,
+      // hook those up to this widget.
+      if (aWidget.type == "view" &&
+          (aWidget.onViewShowing || aWidget.onViewHiding)) {
+        LOG("Widget " + aWidget.id + " has a view with showing and hiding events. Auto-registering event handlers.");
+        let viewNode = aDocument.getElementById(aWidget.viewId);
+
+        if (viewNode) {
+          // PanelUI relies on the .PanelUI-subView class to be able to show only
+          // one sub-view at a time.
+          viewNode.classList.add("PanelUI-subView");
+
+          for (let eventName of kSubviewEvents) {
+            let handler = "on" + eventName;
+            if (typeof aWidget[handler] == "function") {
+              viewNode.addEventListener(eventName, aWidget[handler], false);
+            }
+          }
+
+          LOG("Widget " + aWidget.id + " showing and hiding event handlers set.");
+        } else {
+          ERROR("Could not find the view node with id: " + aWidget.viewId +
+                ", for widget: " + aWidget.id + ".");
+        }
+      }
+
+      if (aWidget.onCreated) {
+        aWidget.onCreated(node);
+      }
+    }
+
+    aWidget.instances.set(aDocument, node);
+    return node;
+  },
+
+  getLocalizedProperty: function(aWidget, aProp, aFormatArgs, aDef) {
+    if (typeof aWidget == "string") {
+      aWidget = gPalette.get(aWidget);
+    }
+    if (!aWidget) {
+      throw new Error("getLocalizedProperty was passed a non-widget to work with.");
+    }
+    let def, name;
+    // Let widgets pass their own string identifiers or strings, so that
+    // we can use strings which aren't the default (in case string ids change)
+    // and so that non-builtin-widgets can also provide labels, tooltips, etc.
+    if (aWidget[aProp]) {
+      name = aWidget[aProp];
+      // By using this as the default, if a widget provides a full string rather
+      // than a string ID for localization, we will fall back to that string
+      // and return that.
+      def = aDef || name;
+    } else {
+      name = aWidget.id + "." + aProp;
+      def = aDef || "";
+    }
+    try {
+      if (Array.isArray(aFormatArgs) && aFormatArgs.length) {
+        return gWidgetsBundle.formatStringFromName(name, aFormatArgs,
+          aFormatArgs.length) || def;
+      }
+      return gWidgetsBundle.GetStringFromName(name) || def;
+    } catch(ex) {
+      if (!def) {
+        ERROR("Could not localize property '" + name + "'.");
+      }
+    }
+    return def;
+  },
+
+  handleWidgetCommand: function(aWidget, aNode, aEvent) {
+    LOG("handleWidgetCommand");
+
+    if (aWidget.type == "button") {
+      this.maybeAutoHidePanel(aEvent);
+
+      if (aWidget.onCommand) {
+        try {
+          aWidget.onCommand.call(null, aEvent);
+        } catch (e) {
+          ERROR(e);
+        }
+      } else {
+        //XXXunf Need to think this through more, and formalize.
+        Services.obs.notifyObservers(aNode,
+                                     "customizedui-widget-command",
+                                     aWidget.id);
+      }
+    } else if (aWidget.type == "view") {
+      let ownerWindow = aNode.ownerDocument.defaultView;
+      ownerWindow.PanelUI.showSubView(aWidget.viewId, aNode,
+                                      this.getPlacementOfWidget(aNode.id).area);
+    }
+  },
+
+  handleWidgetClick: function(aWidget, aNode, aEvent) {
+    LOG("handleWidgetClick");
+    if (aWidget.type == "button") {
+      this.maybeAutoHidePanel(aEvent);
+    }
+
+    if (aWidget.onClick) {
+      try {
+        aWidget.onClick.call(null, aEvent);
+      } catch(e) {
+        Cu.reportError(e);
+      }
+    } else {
+      //XXXunf Need to think this through more, and formalize.
+      Services.obs.notifyObservers(aNode, "customizedui-widget-click", aWidget.id);
+    }
+  },
+
+  _getPanelForNode: function(aNode) {
+    let panel = aNode;
+    while (panel && panel.localName != "panel")
+      panel = panel.parentNode;
+    return panel;
+  },
+
+  /*
+   * If people put things in the panel which need more than single-click interaction,
+   * we don't want to close it. Right now we check for text inputs and menu buttons.
+   * Anything else we should take care of?
+   */
+  _isOnInteractiveElement: function(aEvent) {
+    let target = aEvent.originalTarget;
+    let panel = aEvent.currentTarget;
+    let inInput = false;
+    let inMenu = false;
+    while (!inInput && !inMenu && target != aEvent.currentTarget) {
+      inInput = target.localName == "input";
+      inMenu = target.type == "menu";
+      target = target.parentNode;
+    }
+    return inMenu || inInput;
+  },
+
+  hidePanelForNode: function(aNode) {
+    let panel = this._getPanelForNode(aNode);
+    if (panel) {
+      panel.hidePopup();
+    }
+  },
+
+  maybeAutoHidePanel: function(aEvent) {
+    if (aEvent.type == "keypress") {
+      if (aEvent.keyCode != aEvent.DOM_VK_ENTER &&
+          aEvent.keyCode != aEvent.DOM_VK_RETURN) {
+        return;
+      }
+      // If the user hit enter/return, we don't check preventDefault - it makes sense
+      // that this was prevented, but we probably still want to close the panel.
+      // If consumers don't want this to happen, they should specify noautoclose.
+
+    } else if (aEvent.type != "command") { // mouse events:
+      if (aEvent.defaultPrevented || aEvent.button != 0) {
+        return;
+      }
+      let isInteractive = this._isOnInteractiveElement(aEvent);
+      LOG("maybeAutoHidePanel: interactive ? " + isInteractive);
+      if (isInteractive) {
+        return;
+      }
+    }
+
+    if (aEvent.target.getAttribute("noautoclose") == "true" ||
+        aEvent.target.getAttribute("widget-type") == "view") {
+      return;
+    }
+
+    // If we get here, we can actually hide the popup:
+    this.hidePanelForNode(aEvent.target);
+  },
+
+  getUnusedWidgets: function(aWindowPalette) {
+    // We use a Set because there can be overlap between the widgets in
+    // gPalette and the items in the palette, especially after the first
+    // customization, since programmatically generated widgets will remain
+    // in the toolbox palette.
+    let widgets = new Set();
+
+    // It's possible that some widgets have been defined programmatically and
+    // have not been overlayed into the palette. We can find those inside
+    // gPalette.
+    for (let [id, widget] of gPalette) {
+      if (!widget.currentArea) {
+        widgets.add(id);
+      }
+    }
+
+    LOG("Iterating the actual nodes of the window palette");
+    for (let node of aWindowPalette.children) {
+      LOG("In palette children: " + node.id);
+      if (node.id && !this.getPlacementOfWidget(node.id)) {
+        widgets.add(node.id);
+      }
+    }
+
+    return [...widgets];
+  },
+
+  getPlacementOfWidget: function(aWidgetId, aOnlyRegistered) {
+    if (aOnlyRegistered && !this.widgetExists(aWidgetId)) {
+      return null;
+    }
+
+    for (let [area, placements] of gPlacements) {
+      let index = placements.indexOf(aWidgetId);
+      if (index != -1) {
+        return { area: area, position: index };
+      }
+    }
+
+    return null;
+  },
+
+  widgetExists: function(aWidgetId) {
+    if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) {
+      return true;
+    }
+
+    // Destroyed API widgets are in gSeenWidgets, but not in gPalette:
+    if (gSeenWidgets.has(aWidgetId)) {
+      return false;
+    }
+
+    // We're assuming XUL widgets always exist, as it's much harder to check,
+    // and checking would be much more error prone.
+    return true;
+  },
+
+  addWidgetToArea: function(aWidgetId, aArea, aPosition, aInitialAdd) {
+    if (!gAreas.has(aArea)) {
+      throw new Error("Unknown customization area: " + aArea);
+    }
+
+    // If this is a lazy area that hasn't been restored yet, we can't yet modify
+    // it - would would at least like to add to it. So we keep track of it in
+    // gFuturePlacements,  and use that to add it when restoring the area. We
+    // throw away aPosition though, as that can only be bogus if the area hasn't
+    // yet been restorted (caller can't possibly know where its putting the
+    // widget in relation to other widgets).
+    if (this.isAreaLazy(aArea)) {
+      gFuturePlacements.get(aArea).add(aWidgetId);
+      return;
+    }
+
+    if (this.isSpecialWidget(aWidgetId)) {
+      aWidgetId = this.ensureSpecialWidgetId(aWidgetId);
+    }
+
+    let oldPlacement = this.getPlacementOfWidget(aWidgetId);
+    if (oldPlacement && oldPlacement.area == aArea) {
+      this.moveWidgetWithinArea(aWidgetId, aPosition);
+      return;
+    }
+
+    // Do nothing if the widget is not allowed to move to the target area.
+    if (!this.canWidgetMoveToArea(aWidgetId, aArea)) {
+      return;
+    }
+
+    if (oldPlacement) {
+      this.removeWidgetFromArea(aWidgetId);
+    }
+
+    if (!gPlacements.has(aArea)) {
+      gPlacements.set(aArea, [aWidgetId]);
+      aPosition = 0;
+    } else {
+      let placements = gPlacements.get(aArea);
+      if (typeof aPosition != "number") {
+        aPosition = placements.length;
+      }
+      if (aPosition < 0) {
+        aPosition = 0;
+      }
+      placements.splice(aPosition, 0, aWidgetId);
+    }
+
+    let widget = gPalette.get(aWidgetId);
+    if (widget) {
+      widget.currentArea = aArea;
+      widget.currentPosition = aPosition;
+    }
+
+    // We initially set placements with addWidgetToArea, so in that case
+    // we don't consider the area "dirtied".
+    if (!aInitialAdd) {
+      gDirtyAreaCache.add(aArea);
+    }
+
+    gDirty = true;
+    this.saveState();
+
+    this.notifyListeners("onWidgetAdded", aWidgetId, aArea, aPosition);
+  },
+
+  removeWidgetFromArea: function(aWidgetId) {
+    let oldPlacement = this.getPlacementOfWidget(aWidgetId);
+    if (!oldPlacement) {
+      return;
+    }
+
+    if (!this.isWidgetRemovable(aWidgetId)) {
+      return;
+    }
+
+    let placements = gPlacements.get(oldPlacement.area);
+    let position = placements.indexOf(aWidgetId);
+    if (position != -1) {
+      placements.splice(position, 1);
+    }
+
+    let widget = gPalette.get(aWidgetId);
+    if (widget) {
+      widget.currentArea = null;
+      widget.currentPosition = null;
+    }
+
+    gDirty = true;
+    this.saveState();
+    gDirtyAreaCache.add(oldPlacement.area);
+
+    this.notifyListeners("onWidgetRemoved", aWidgetId, oldPlacement.area);
+  },
+
+  moveWidgetWithinArea: function(aWidgetId, aPosition) {
+    let oldPlacement = this.getPlacementOfWidget(aWidgetId);
+    if (!oldPlacement) {
+      return;
+    }
+
+    let placements = gPlacements.get(oldPlacement.area);
+    if (typeof aPosition != "number") {
+      aPosition = placements.length;
+    } else if (aPosition < 0) {
+      aPosition = 0;
+    } else if (aPosition > placements.length) {
+      aPosition = placements.length;
+    }
+
+    if (aPosition == oldPlacement.position) {
+      return;
+    }
+
+    placements.splice(oldPlacement.position, 1);
+    // If we just removed the item from *before* where it is now added,
+    // we need to compensate the position offset for that:
+    if (oldPlacement.position < aPosition) {
+      aPosition--;
+    }
+    placements.splice(aPosition, 0, aWidgetId);
+
+    let widget = gPalette.get(aWidgetId);
+    if (widget) {
+      widget.currentPosition = aPosition;
+    }
+
+    gDirty = true;
+    gDirtyAreaCache.add(oldPlacement.area);
+
+    this.saveState();
+
+    this.notifyListeners("onWidgetMoved", aWidgetId, oldPlacement.area,
+                         oldPlacement.position, aPosition);
+  },
+
+  // Note that this does not populate gPlacements, which is done lazily so that
+  // the legacy state can be migrated, which is only available once a browser
+  // window is openned.
+  // The panel area is an exception here, since it has no legacy state and is 
+  // built lazily - and therefore wouldn't otherwise result in restoring its
+  // state immediately when a browser window opens, which is important for
+  // other consumers of this API.
+  loadSavedState: function() {
+    let state = null;
+    try {
+      state = Services.prefs.getCharPref(kPrefCustomizationState);
+    } catch (e) {
+      LOG("No saved state found");
+      // This will fail if nothing has been customized, so silently fall back to
+      // the defaults.
+    }
+
+    if (!state) {
+      return;
+    }
+    try {
+      gSavedState = JSON.parse(state);
+    } catch(e) {
+      LOG("Error loading saved UI customization state, falling back to defaults.");
+    }
+
+    if (!("placements" in gSavedState)) {
+      gSavedState.placements = {};
+    }
+
+    gSeenWidgets = new Set(gSavedState.seen || []);
+    gDirtyAreaCache = new Set(gSavedState.dirtyAreaCache || []);
+    gNewElementCount = gSavedState.newElementCount || 0;
+  },
+
+  restoreStateForArea: function(aArea, aLegacyState) {
+    if (gPlacements.has(aArea)) {
+      // Already restored.
+      return;
+    }
+
+    this.beginBatchUpdate();
+    gRestoring = true;
+
+    let restored = false;
+    gPlacements.set(aArea, []);
+
+    if (gSavedState && aArea in gSavedState.placements) {
+      LOG("Restoring " + aArea + " from saved state");
+      let placements = gSavedState.placements[aArea];
+      for (let id of placements)
+        this.addWidgetToArea(id, aArea);
+      gDirty = false;
+      restored = true;
+    }
+
+    if (!restored && aLegacyState) {
+      LOG("Restoring " + aArea + " from legacy state");
+      for (let id of aLegacyState)
+        this.addWidgetToArea(id, aArea);
+      // Don't override dirty state, to ensure legacy state is saved here and
+      // therefore only used once.
+      restored = true;
+    }
+
+    if (!restored) {
+      LOG("Restoring " + aArea + " from default state");
+      let defaults = gAreas.get(aArea).get("defaultPlacements");
+      if (defaults) {
+        for (let id of defaults)
+          this.addWidgetToArea(id, aArea, null, true);
+      }
+      gDirty = false;
+    }
+
+    // Finally, add widgets to the area that were added before the it was able
+    // to be restored. This can occur when add-ons register widgets for a
+    // lazily-restored area before it's been restored.
+    if (gFuturePlacements.has(aArea)) {
+      for (let id of gFuturePlacements.get(aArea))
+        this.addWidgetToArea(id, aArea);
+    }
+
+    LOG("Placements for " + aArea + ":\n\t" + gPlacements.get(aArea).join("\n\t"));
+
+    gRestoring = false;
+    this.endBatchUpdate();
+  },
+
+  saveState: function() {
+    if (gInBatchStack || !gDirty) {
+      return;
+    }
+    let state = { placements: gPlacements,
+                  seen: gSeenWidgets,
+                  dirtyAreaCache: gDirtyAreaCache,
+                  newElementCount: gNewElementCount };
+
+    LOG("Saving state.");
+    let serialized = JSON.stringify(state, this.serializerHelper);
+    LOG("State saved as: " + serialized);
+    Services.prefs.setCharPref(kPrefCustomizationState, serialized);
+    gDirty = false;
+  },
+
+  serializerHelper: function(aKey, aValue) {
+    if (typeof aValue == "object" && aValue.constructor.name == "Map") {
+      let result = {};
+      for (let [mapKey, mapValue] of aValue)
+        result[mapKey] = mapValue;
+      return result;
+    }
+
+    if (typeof aValue == "object" && aValue.constructor.name == "Set") {
+      return [...aValue];
+    }
+
+    return aValue;
+  },
+
+  beginBatchUpdate: function() {
+    gInBatchStack++;
+  },
+
+  endBatchUpdate: function(aForceDirty) {
+    gInBatchStack--;
+    if (aForceDirty === true) {
+      gDirty = true;
+    }
+    if (gInBatchStack == 0) {
+      this.saveState();
+    } else if (gInBatchStack < 0) {
+      throw new Error("The batch editing stack should never reach a negative number.");
+    }
+  },
+
+  addListener: function(aListener) {
+    gListeners.add(aListener);
+  },
+
+  removeListener: function(aListener) {
+    if (aListener == this) {
+      return;
+    }
+
+    gListeners.delete(aListener);
+  },
+
+  notifyListeners: function(aEvent, ...aArgs) {
+    if (gRestoring) {
+      return;
+    }
+
+    for (let listener of gListeners) {
+      try {
+        if (typeof listener[aEvent] == "function") {
+          listener[aEvent].apply(listener, aArgs);
+        }
+      } catch (e) {
+        ERROR(e + " -- " + e.fileName + ":" + e.lineNumber);
+      }
+    }
+  },
+
+  createWidget: function(aProperties) {
+    let widget = this.normalizeWidget(aProperties, CustomizableUI.SOURCE_EXTERNAL);
+    //XXXunf This should probably throw.
+    if (!widget) {
+      return;
+    }
+
+    gPalette.set(widget.id, widget);
+    this.notifyListeners("onWidgetCreated", widget.id);
+
+    if (widget.defaultArea) {
+      let area = gAreas.get(widget.defaultArea);
+      //XXXgijs this won't have any effect for legacy items. Sort of OK because
+      // consumers can modify currentset? Maybe?
+      if (area.has("defaultPlacements")) {
+        area.get("defaultPlacements").push(widget.id);
+      } else {
+        area.set("defaultPlacements", [widget.id]);
+      }
+    }
+
+    // Look through previously saved state to see if we're restoring a widget.
+    let seenAreas = new Set();
+    for (let [area, placements] of gPlacements) {
+      seenAreas.add(area);
+      let index = gPlacements.get(area).indexOf(widget.id);
+      if (index != -1) {
+        widget.currentArea = area;
+        widget.currentPosition = index;
+        break;
+      }
+    }
+
+    // Also look at saved state data directly in areas that haven't yet been
+    // restored. Can't rely on this for restored areas, as they may have
+    // changed.
+    if (!widget.currentArea && gSavedState) {
+      for (let area of Object.keys(gSavedState.placements)) {
+        if (seenAreas.has(area)) {
+          continue;
+        }
+
+        let index = gSavedState.placements[area].indexOf(widget.id);
+        if (index != -1) {
+          widget.currentArea = area;
+          widget.currentPosition = index;
+          break;
+        }
+      }
+    }
+
+    // If we're restoring the widget to it's old placement, fire off the
+    // onWidgetAdded event - our own handler will take care of adding it to
+    // any build areas.
+    if (widget.currentArea) {
+      this.notifyListeners("onWidgetAdded", widget.id, widget.currentArea,
+                           widget.currentPosition);
+    } else {
+      let autoAdd = true;
+      try {
+        autoAdd = Services.prefs.getBoolPref(kPrefCustomizationAutoAdd);
+      } catch (e) {}
+
+      // If the widget doesn't have an existing placement, and it hasn't been
+      // seen before, then add it to its default area so it can be used.
+      if (autoAdd && !widget.currentArea && !gSeenWidgets.has(widget.id)) {
+        this.beginBatchUpdate();
+        gSeenWidgets.add(widget.id);
+
+        if (widget.defaultArea) {
+          if (this.isAreaLazy(widget.defaultArea)) {
+            gFuturePlacements.get(widget.defaultArea).add(widget.id);
+          } else {
+            this.addWidgetToArea(widget.id, widget.defaultArea);
+          }
+        }
+
+        this.endBatchUpdate(true);
+      }
+    }
+
+    this.notifyListeners("onWidgetAfterCreation", widget.id, widget.currentArea);
+    return widget.id;
+  },
+
+  createBuiltinWidget: function(aData) {
+    // This should only ever be called on startup, before any windows are
+    // opened - so we know there's no build areas to handle. Also, builtin
+    // widgets are expected to be (mostly) static, so shouldn't affect the
+    // current placement settings.
+    let widget = this.normalizeWidget(aData, CustomizableUI.SOURCE_BUILTIN);
+    if (!widget) {
+      ERROR("Error creating builtin widget: " + aData.id);
+      return;
+    }
+
+    LOG("Creating built-in widget with id: " + widget.id);
+    gPalette.set(widget.id, widget);
+  },
+
+  // Returns true if the area will eventually lazily restore (but hasn't yet).
+  isAreaLazy: function(aArea) {
+    if (gPlacements.has(aArea)) {
+      return false;
+    }
+    return gAreas.get(aArea).has("legacy");
+  },
+
+  //XXXunf Log some warnings here, when the data provided isn't up to scratch.
+  normalizeWidget: function(aData, aSource) {
+    let widget = {
+      implementation: aData,
+      source: aSource || "addon",
+      instances: new Map(),
+      currentArea: null,
+      removable: false,
+      overflows: true,
+      defaultArea: null,
+      shortcutId: null,
+      tooltiptext: null,
+      showInPrivateBrowsing: true,
+    };
+
+    if (typeof aData.id != "string" || !/^[a-z0-9-_]{1,}$/i.test(aData.id)) {
+      ERROR("Given an illegal id in normalizeWidget: " + aData.id);
+      return null;
+    }
+
+    delete widget.implementation.currentArea;
+    widget.implementation.__defineGetter__("currentArea", function() widget.currentArea);
+
+    const kReqStringProps = ["id"];
+    for (let prop of kReqStringProps) {
+      if (typeof aData[prop] != "string") {
+        ERROR("Missing required property '" + prop + "' in normalizeWidget: "
+              + aData.id);
+        return null;
+      }
+      widget[prop] = aData[prop];
+    }
+
+    const kOptStringProps = ["label", "tooltiptext", "shortcutId"];
+    for (let prop of kOptStringProps) {
+      if (typeof aData[prop] == "string") {
+        widget[prop] = aData[prop];
+      }
+    }
+
+    const kOptBoolProps = ["removable", "showInPrivateBrowsing", "overflows"];
+    for (let prop of kOptBoolProps) {
+      if (typeof aData[prop] == "boolean") {
+        widget[prop] = aData[prop];
+      }
+    }
+
+    if (aData.defaultArea && gAreas.has(aData.defaultArea)) {
+      widget.defaultArea = aData.defaultArea;
+    }
+
+    if ("type" in aData && gSupportedWidgetTypes.has(aData.type)) {
+      widget.type = aData.type;
+    } else {
+      widget.type = "button";
+    }
+
+    widget.disabled = aData.disabled === true;
+
+    this.wrapWidgetEventHandler("onClick", widget);
+    this.wrapWidgetEventHandler("onCreated", widget);
+
+    if (widget.type == "button") {
+      widget.onCommand = typeof aData.onCommand == "function" ?
+                           aData.onCommand :
+                           null;
+    } else if (widget.type == "view") {
+      if (typeof aData.viewId != "string") {
+        ERROR("Expected a string for widget " + widget.id + " viewId, but got "
+              + aData.viewId);
+        return null;
+      }
+      widget.viewId = aData.viewId;
+
+      this.wrapWidgetEventHandler("onViewShowing", widget);
+      this.wrapWidgetEventHandler("onViewHiding", widget);
+    } else if (widget.type == "custom") {
+      this.wrapWidgetEventHandler("onBuild", widget);
+    }
+
+    if (gPalette.has(widget.id)) {
+      return null;
+    }
+
+    return widget;
+  },
+
+  wrapWidgetEventHandler: function(aEventName, aWidget) {
+    if (typeof aWidget.implementation[aEventName] != "function") {
+      aWidget[aEventName] = null;
+      return;
+    }
+    aWidget[aEventName] = function(...aArgs) {
+      // Wrap inside a try...catch to properly log errors, until bug 862627 is
+      // fixed, which in turn might help bug 503244.
+      try {
+        // Don't copy the function to the normalized widget object, instead
+        // keep it on the original object provided to the API so that
+        // additional methods can be implemented and used by the event
+        // handlers.
+        return aWidget.implementation[aEventName].apply(aWidget.implementation,
+                                                        aArgs);
+      } catch (e) {
+        Cu.reportError(e);
+      }
+    };
+  },
+
+  destroyWidget: function(aWidgetId) {
+    let widget = gPalette.get(aWidgetId);
+    if (!widget) {
+      return;
+    }
+
+    // Remove it from the default placements of an area if it was added there:
+    if (widget.defaultArea) {
+      let area = gAreas.get(widget.defaultArea);
+      if (area) {
+        let defaultPlacements = area.get("defaultPlacements");
+        // We can assume this is present because if a widget has a defaultArea,
+        // we automatically create a defaultPlacements array for that area.
+        let widgetIndex = defaultPlacements.indexOf(aWidgetId);
+        if (widgetIndex != -1) {
+          defaultPlacements.splice(widgetIndex, 1);
+        }
+      }
+    }
+
+    // This will not remove the widget from gPlacements - we want to keep the
+    // setting so the widget gets put back in it's old position if/when it
+    // returns.
+
+    let area = widget.currentArea;
+    let buildAreaNodes = area && gBuildAreas.get(area);
+    if (buildAreaNodes) {
+      for (let buildNode of buildAreaNodes) {
+        let widgetNode = buildNode.ownerDocument.getElementById(aWidgetId);
+        let windowCache = gSingleWrapperCache.get(buildNode.ownerDocument.defaultView);
+        if (windowCache) {
+          windowCache.delete(aWidgetId);
+        }
+        if (widgetNode) {
+          widgetNode.parentNode.removeChild(widgetNode);
+        }
+        if (widget.type == "view") {
+          let viewNode = buildNode.ownerDocument.getElementById(widget.viewId);
+          if (viewNode) {
+            for (let eventName of kSubviewEvents) {
+              let handler = "on" + eventName;
+              if (typeof widget[handler] == "function") {
+                viewNode.removeEventListener(eventName, widget[handler], false);
+              }
+            }
+          }
+        }
+      }
+    }
+
+    gPalette.delete(aWidgetId);
+    gGroupWrapperCache.delete(aWidgetId);
+
+    this.notifyListeners("onWidgetDestroyed", aWidgetId);
+  },
+
+  getCustomizeTargetForArea: function(aArea, aWindow) {
+    let buildAreaNodes = gBuildAreas.get(aArea);
+    if (!buildAreaNodes) {
+      return null;
+    }
+
+    for (let node of buildAreaNodes) {
+      if (node.ownerDocument.defaultView === aWindow) {
+        return node.customizationTarget ? node.customizationTarget : node;
+      }
+    }
+
+    return null;
+  },
+
+  reset: function() {
+    gResetting = true;
+    Services.prefs.clearUserPref(kPrefCustomizationState);
+    LOG("State reset");
+
+    // Reset placements to make restoring default placements possible.
+    gPlacements = new Map();
+    gDirtyAreaCache = new Set();
+    // Clear the saved state to ensure that defaults will be used.
+    gSavedState = null;
+    // Restore the state for each area to its defaults
+    for (let [areaId,] of gAreas) {
+      this.restoreStateForArea(areaId);
+    }
+
+    // Rebuild each registered area (across windows) to reflect the state that
+    // was reset above.
+    for (let [areaId, areaNodes] of gBuildAreas) {
+      let placements = gPlacements.get(areaId);
+      for (let areaNode of areaNodes) {
+        this.buildArea(areaId, placements, areaNode);
+      }
+    }
+    gResetting = false;
+  },
+
+  /**
+   * @param {String|Node} aWidget - widget ID or a widget node (preferred for performance).
+   * @return {Boolean} whether the widget is removable
+   */
+  isWidgetRemovable: function(aWidget) {
+    let widgetId;
+    let widgetNode;
+    if (typeof aWidget == "string") {
+      widgetId = aWidget;
+    } else {
+      widgetId = aWidget.id;
+      widgetNode = aWidget;
+    }
+    let provider = this.getWidgetProvider(widgetId);
+
+    if (provider == CustomizableUI.PROVIDER_API) {
+      return gPalette.get(widgetId).removable;
+    }
+
+    if (provider == CustomizableUI.PROVIDER_XUL) {
+      if (gBuildWindows.size == 0) {
+        // We don't have any build windows to look at, so just assume for now
+        // that its removable.
+        return true;
+      }
+
+      if (!widgetNode) {
+        // Pick any of the build windows to look at.
+        let [window,] = [...gBuildWindows][0];
+        [, widgetNode] = this.getWidgetNode(widgetId, window);
+      }
+      // If we don't have a node, we assume it's removable. This can happen because
+      // getWidgetProvider returns PROVIDER_XUL by default, but this will also happen
+      // for API-provided widgets which have been destroyed.
+      if (!widgetNode) {
+        return true;
+      }
+      return widgetNode.getAttribute("removable") == "true";
+    }
+
+    // Otherwise this is either a special widget, which is always removable, or
+    // an API widget which has already been removed from gPalette. Returning true
+    // here allows us to then remove its ID from any placements where it might
+    // still occur.
+    return true;
+  },
+
+  canWidgetMoveToArea: function(aWidgetId, aArea) {
+    let placement = this.getPlacementOfWidget(aWidgetId);
+    if (placement && placement.area != aArea &&
+        !this.isWidgetRemovable(aWidgetId)) {
+      return false;
+    }
+    return true;
+  },
+
+  ensureWidgetPlacedInWindow: function(aWidgetId, aWindow) {
+    let placement = this.getPlacementOfWidget(aWidgetId);
+    if (!placement) {
+      return false;
+    }
+    let areaNodes = gBuildAreas.get(placement.area);
+    if (!areaNodes) {
+      return false;
+    }
+    let container = [...areaNodes].filter((n) => n.ownerDocument.defaultView == aWindow);
+    if (!container.length) {
+      return false;
+    }
+    let existingNode = container[0].querySelector(idToSelector(aWidgetId));
+    if (existingNode) {
+      return true;
+    }
+
+    let placementAry = gPlacements.get(placement.area);
+    let nextNodeId = placementAry[placement.position + 1];
+    this.insertNodeInWindow(aWidgetId, container[0], nextNodeId, true);
+    return true;
+  },
+
+  get inDefaultState() {
+    for (let [areaId, props] of gAreas) {
+      let defaultPlacements = props.get("defaultPlacements");
+      // Areas without default placements (like legacy ones?) get skipped
+      if (!defaultPlacements) {
+        continue;
+      }
+
+      let currentPlacements = gPlacements.get(areaId);
+      // We're excluding all of the placement IDs for items that do not exist,
+      // because we don't want to consider them when determining if we're
+      // in the default state. This way, if an add-on introduces a widget
+      // and is then uninstalled, the leftover placement doesn't cause us to
+      // automatically assume that the buttons are not in the default state.
+      let buildAreaNodes = gBuildAreas.get(areaId);
+      if (buildAreaNodes && buildAreaNodes.size) {
+        let container = [...buildAreaNodes][0];
+        // Toolbars have a currentSet property which also deals correctly with overflown
+        // widgets (if any) - use that instead:
+        if (props.get("type") == CustomizableUI.TYPE_TOOLBAR) {
+          currentPlacements = container.currentSet.split(',');
+        } else {
+          // Clone the array so we don't modify the actual placements...
+          currentPlacements = [...currentPlacements];
+          // Loop backwards through the placements so we can easily remove items:
+          let itemIndex = currentPlacements.length;
+          while (itemIndex--) {
+            if (!container.querySelector(idToSelector(currentPlacements[itemIndex]))) {
+              currentPlacements.splice(itemIndex, 1);
+            }
+          }
+        }
+      }
+      LOG("Checking default state for " + areaId + ":\n" + currentPlacements.join(",") +
+          "\nvs.\n" + defaultPlacements.join(","));
+
+      if (currentPlacements.length != defaultPlacements.length) {
+        return false;
+      }
+
+      for (let i = 0; i < currentPlacements.length; ++i) {
+        if (currentPlacements[i] != defaultPlacements[i]) {
+          LOG("Found " + currentPlacements[i] + " in " + areaId + " where " +
+              defaultPlacements[i] + " was expected!");
+          return false;
+        }
+      }
+    }
+
+    return true;
+  }
+};
+Object.freeze(CustomizableUIInternal);
+
+this.CustomizableUI = {
+  get AREA_PANEL() "PanelUI-contents",
+  get AREA_NAVBAR() "nav-bar",
+  get AREA_MENUBAR() "toolbar-menubar",
+  get AREA_TABSTRIP() "TabsToolbar",
+  get AREA_BOOKMARKS() "PersonalToolbar",
+  get AREA_ADDONBAR() "addon-bar",
+
+  get PROVIDER_XUL() "xul",
+  get PROVIDER_API() "api",
+  get PROVIDER_SPECIAL() "special",
+
+  get SOURCE_BUILTIN() "builtin",
+  get SOURCE_EXTERNAL() "external",
+
+  get TYPE_BUTTON() "button",
+  get TYPE_MENU_PANEL() "menu-panel",
+  get TYPE_TOOLBAR() "toolbar",
+
+  addListener: function(aListener) {
+    CustomizableUIInternal.addListener(aListener);
+  },
+  removeListener: function(aListener) {
+    CustomizableUIInternal.removeListener(aListener);
+  },
+  registerArea: function(aName, aProperties) {
+    CustomizableUIInternal.registerArea(aName, aProperties);
+  },
+  registerToolbarNode: function(aToolbar, aExistingChildren) {
+    CustomizableUIInternal.registerToolbarNode(aToolbar, aExistingChildren);
+  },
+  registerMenuPanel: function(aPanel) {
+    CustomizableUIInternal.registerMenuPanel(aPanel);
+  },
+  unregisterArea: function(aName) {
+    CustomizableUIInternal.unregisterArea(aName);
+  },
+  addWidgetToArea: function(aWidgetId, aArea, aPosition) {
+    CustomizableUIInternal.addWidgetToArea(aWidgetId, aArea, aPosition);
+  },
+  removeWidgetFromArea: function(aWidgetId) {
+    CustomizableUIInternal.removeWidgetFromArea(aWidgetId);
+  },
+  moveWidgetWithinArea: function(aWidgetId, aPosition) {
+    CustomizableUIInternal.moveWidgetWithinArea(aWidgetId, aPosition);
+  },
+  ensureWidgetPlacedInWindow: function(aWidgetId, aWindow) {
+    return CustomizableUIInternal.ensureWidgetPlacedInWindow(aWidgetId, aWindow);
+  },
+  beginBatchUpdate: function() {
+    CustomizableUIInternal.beginBatchUpdate();
+  },
+  endBatchUpdate: function(aForceDirty) {
+    CustomizableUIInternal.endBatchUpdate(aForceDirty);
+  },
+  createWidget: function(aProperties) {
+    return CustomizableUIInternal.wrapWidget(
+      CustomizableUIInternal.createWidget(aProperties)
+    );
+  },
+  destroyWidget: function(aWidgetId) {
+    CustomizableUIInternal.destroyWidget(aWidgetId);
+  },
+  getWidget: function(aWidgetId) {
+    return CustomizableUIInternal.wrapWidget(aWidgetId);
+  },
+  getUnusedWidgets: function(aWindowPalette) {
+    return CustomizableUIInternal.getUnusedWidgets(aWindowPalette).map(
+      CustomizableUIInternal.wrapWidget,
+      CustomizableUIInternal
+    );
+  },
+  getWidgetIdsInArea: function(aArea) {
+    if (!gAreas.has(aArea)) {
+      throw new Error("Unknown customization area: " + aArea);
+    }
+    if (!gPlacements.has(aArea)) {
+      throw new Error("Area not yet restored");
+    }
+
+    // We need to clone this, as we don't want to let consumers muck with placements
+    return [...gPlacements.get(aArea)];
+  },
+  getWidgetsInArea: function(aArea) {
+    return this.getWidgetIdsInArea(aArea).map(
+      CustomizableUIInternal.wrapWidget,
+      CustomizableUIInternal
+    );
+  },
+  get areas() {
+    return [area for ([area, props] of gAreas)];
+  },
+  getAreaType: function(aArea) {
+    let area = gAreas.get(aArea);
+    return area ? area.get("type") : null;
+  },
+  getCustomizeTargetForArea: function(aArea, aWindow) {
+    return CustomizableUIInternal.getCustomizeTargetForArea(aArea, aWindow);
+  },
+  reset: function() {
+    CustomizableUIInternal.reset();
+  },
+  getPlacementOfWidget: function(aWidgetId) {
+    return CustomizableUIInternal.getPlacementOfWidget(aWidgetId, true);
+  },
+  isWidgetRemovable: function(aWidgetId) {
+    return CustomizableUIInternal.isWidgetRemovable(aWidgetId);
+  },
+  canWidgetMoveToArea: function(aWidgetId, aArea) {
+    return CustomizableUIInternal.canWidgetMoveToArea(aWidgetId, aArea);
+  },
+  get inDefaultState() {
+    return CustomizableUIInternal.inDefaultState;
+  },
+  getLocalizedProperty: function(aWidget, aProp, aFormatArgs, aDef) {
+    return CustomizableUIInternal.getLocalizedProperty(aWidget, aProp,
+      aFormatArgs, aDef);
+  },
+  hidePanelForNode: function(aNode) {
+    CustomizableUIInternal.hidePanelForNode(aNode);
+  },
+  isSpecialWidget: function(aWidgetId) {
+    return CustomizableUIInternal.isSpecialWidget(aWidgetId);
+  },
+  addPanelCloseListeners: function(aPanel) {
+    CustomizableUIInternal.addPanelCloseListeners(aPanel);
+  },
+  removePanelCloseListeners: function(aPanel) {
+    CustomizableUIInternal.removePanelCloseListeners(aPanel);
+  },
+  onWidgetDrag: function(aWidgetId, aArea) {
+    CustomizableUIInternal.notifyListeners("onWidgetDrag", aWidgetId, aArea);
+  },
+  isAreaOverflowable: function(aAreaId) {
+    let area = gAreas.get(aAreaId);
+    return area ? area.get("type") == this.TYPE_TOOLBAR && area.get("overflowable")
+                : false;
+  },
+};
+Object.freeze(this.CustomizableUI);
+
+
+/**
+ * All external consumers of widgets are really interacting with these wrappers
+ * which provide a common interface.
+ */
+
+/**
+ * WidgetGroupWrapper is the common interface for interacting with an entire
+ * widget group - AKA, all instances of a widget across a series of windows.
+ * This particular wrapper is only used for widgets created via the provider
+ * API.
+ */
+function WidgetGroupWrapper(aWidget) {
+  this.isGroup = true;
+
+  const kBareProps = ["id", "source", "type", "disabled", "label", "tooltiptext",
+                      "showInPrivateBrowsing"];
+  for (let prop of kBareProps) {
+    let propertyName = prop;
+    this.__defineGetter__(propertyName, function() aWidget[propertyName]);
+  }
+
+  this.__defineGetter__("provider", function() CustomizableUI.PROVIDER_API);
+
+  this.__defineSetter__("disabled", function(aValue) {
+    aValue = !!aValue;
+    aWidget.disabled = aValue;
+    for (let [,instance] of aWidget.instances) {
+      instance.disabled = aValue;
+    }
+  });
+
+  this.forWindow = function WidgetGroupWrapper_forWindow(aWindow) {
+    let wrapperMap;
+    if (!gSingleWrapperCache.has(aWindow)) {
+      wrapperMap = new Map();
+      gSingleWrapperCache.set(aWindow, wrapperMap);
+    } else {
+      wrapperMap = gSingleWrapperCache.get(aWindow);
+    }
+    if (wrapperMap.has(aWidget.id)) {
+      return wrapperMap.get(aWidget.id);
+    }
+
+    let instance = aWidget.instances.get(aWindow.document);
+    if (!instance &&
+        (aWidget.showInPrivateBrowsing || !PrivateBrowsingUtils.isWindowPrivate(aWindow))) {
+      instance = CustomizableUIInternal.buildWidget(aWindow.document,
+                                                    aWidget);
+    }
+
+    let wrapper = new WidgetSingleWrapper(aWidget, instance);
+    wrapperMap.set(aWidget.id, wrapper);
+    return wrapper;
+  };
+
+  this.__defineGetter__("instances", function() {
+    // Can't use gBuildWindows here because some areas load lazily:
+    let placement = CustomizableUIInternal.getPlacementOfWidget(aWidget.id);
+    if (!placement) {
+      return [];
+    }
+    let area = placement.area;
+    return [this.forWindow(node.ownerDocument.defaultView) for (node of gBuildAreas.get(area))];
+  });
+
+  this.__defineGetter__("areaType", function() {
+    return gAreas.get(aWidget.currentArea).get("type");
+  });
+
+  Object.freeze(this);
+}
+
+/**
+ * A WidgetSingleWrapper is a wrapper around a single instance of a widget in
+ * a particular window.
+ */
+function WidgetSingleWrapper(aWidget, aNode) {
+  this.isGroup = false;
+
+  this.node = aNode;
+  this.provider = CustomizableUI.PROVIDER_API;
+
+  const kGlobalProps = ["id", "type"];
+  for (let prop of kGlobalProps) {
+    this[prop] = aWidget[prop];
+  }
+
+  const nodeProps = ["label", "tooltiptext"];
+  for (let prop of nodeProps) {
+    let propertyName = prop;
+    // Look at the node for these, instead of the widget data, to ensure the
+    // wrapper always reflects this live instance.
+    this.__defineGetter__(propertyName,
+                          function() aNode.getAttribute(propertyName));
+  }
+
+  this.__defineGetter__("disabled", function() aNode.disabled);
+  this.__defineSetter__("disabled", function(aValue) {
+    aNode.disabled = !!aValue;
+  });
+
+  this.__defineGetter__("anchor", function() {
+    let anchorId;
+    // First check for an anchor for the area:
+    let placement = CustomizableUIInternal.getPlacementOfWidget(aWidgetId);
+    if (placement) {
+      anchorId = gAreas.get(placement.area).get("anchor");
+    }
+    if (!anchorId) {
+      anchorId = aNode.getAttribute("cui-anchorid");
+    }
+
+    return anchorId ? aNode.ownerDocument.getElementById(anchorId)
+                    : aNode;
+  });
+
+  this.__defineGetter__("overflowed", function() {
+    return aNode.classList.contains("overflowedItem");
+  });
+
+  Object.freeze(this);
+}
+
+/**
+ * XULWidgetGroupWrapper is the common interface for interacting with an entire
+ * widget group - AKA, all instances of a widget across a series of windows.
+ * This particular wrapper is only used for widgets created via the old-school
+ * XUL method (overlays, or programmatically injecting toolbaritems, or other
+ * such things).
+ */
+//XXXunf Going to need to hook this up to some events to keep it all live.
+function XULWidgetGroupWrapper(aWidgetId) {
+  this.isGroup = true;
+  this.id = aWidgetId;
+  this.type = "custom";
+  this.provider = CustomizableUI.PROVIDER_XUL;
+
+  this.forWindow = function XULWidgetGroupWrapper_forWindow(aWindow) {
+    let wrapperMap;
+    if (!gSingleWrapperCache.has(aWindow)) {
+      wrapperMap = new Map();
+      gSingleWrapperCache.set(aWindow, wrapperMap);
+    } else {
+      wrapperMap = gSingleWrapperCache.get(aWindow);
+    }
+    if (wrapperMap.has(aWidgetId)) {
+      return wrapperMap.get(aWidgetId);
+    }
+
+    let instance = aWindow.document.getElementById(aWidgetId);
+    if (!instance) {
+      // Toolbar palettes aren't part of the document, so elements in there
+      // won't be found via document.getElementById().
+      instance = aWindow.gNavToolbox.palette.querySelector(idToSelector(aWidgetId));
+    }
+
+    let wrapper = new XULWidgetSingleWrapper(aWidgetId, instance);
+    wrapperMap.set(aWidgetId, wrapper);
+    return wrapper;
+  };
+
+  this.__defineGetter__("areaType", function() {
+    let placement = CustomizableUIInternal.getPlacementOfWidget(aWidgetId);
+    if (!placement) {
+      return null;
+    }
+
+    return gAreas.get(placement.area).get("type");
+  });
+
+  this.__defineGetter__("instances", function() {
+    return [this.forWindow(win) for ([win,] of gBuildWindows)];
+  });
+
+  Object.freeze(this);
+}
+
+/**
+ * A XULWidgetSingleWrapper is a wrapper around a single instance of a XUL 
+ * widget in a particular window.
+ */
+function XULWidgetSingleWrapper(aWidgetId, aNode) {
+  this.isGroup = false;
+
+  this.id = aWidgetId;
+  this.type = "custom";
+  this.provider = CustomizableUI.PROVIDER_XUL;
+
+  this.node = aNode;
+
+  this.__defineGetter__("anchor", function() {
+    let anchorId;
+    // First check for an anchor for the area:
+    let placement = CustomizableUIInternal.getPlacementOfWidget(aWidgetId);
+    if (placement) {
+      anchorId = gAreas.get(placement.area).get("anchor");
+    }
+    if (!anchorId) {
+      anchorId = aNode.getAttribute("cui-anchorid");
+    }
+
+    return anchorId ? aNode.ownerDocument.getElementById(anchorId)
+                    : aNode;
+  });
+
+  this.__defineGetter__("overflowed", function() {
+    return aNode.classList.contains("overflowedItem");
+  });
+
+  Object.freeze(this);
+}
+
+const LAZY_RESIZE_INTERVAL_MS = 200;
+
+function OverflowableToolbar(aToolbarNode) {
+  this._toolbar = aToolbarNode;
+  this._collapsed = new Map();
+  this._enabled = true;
+
+  this._toolbar.setAttribute("overflowable", "true");
+  Services.obs.addObserver(this, "browser-delayed-startup-finished", false);
+}
+
+OverflowableToolbar.prototype = {
+  initialized: false,
+  _forceOnOverflow: false,
+
+  observe: function(aSubject, aTopic, aData) {
+    if (aTopic == "browser-delayed-startup-finished" &&
+        aSubject == this._toolbar.ownerDocument.defaultView) {
+      Services.obs.removeObserver(this, "browser-delayed-startup-finished");
+      this.init();
+    }
+  },
+
+  init: function() {
+    this._target = this._toolbar.customizationTarget;
+    let doc = this._toolbar.ownerDocument;
+    this._list = doc.getElementById(this._toolbar.getAttribute("overflowtarget"));
+    this._list.toolbox = this._toolbar.toolbox;
+    this._list.customizationTarget = this._list;
+
+    let window = doc.defaultView;
+    window.addEventListener("resize", this);
+    window.gNavToolbox.addEventListener("customizationstarting", this);
+    window.gNavToolbox.addEventListener("aftercustomization", this);
+
+    let chevronId = this._toolbar.getAttribute("overflowbutton");
+    this._chevron = doc.getElementById(chevronId);
+    this._chevron.addEventListener("command", this);
+
+    this._panel = doc.getElementById("widget-overflow");
+    this._panel.addEventListener("popuphiding", this);
+    CustomizableUIInternal.addPanelCloseListeners(this._panel);
+
+    CustomizableUI.addListener(this);
+
+    // The 'overflow' event may have been fired before init was called.
+    if (this._toolbar.overflowedDuringConstruction) {
+      this.onOverflow(this._toolbar.overflowedDuringConstruction);
+      this._toolbar.overflowedDuringConstruction = null;
+    }
+
+    this.initialized = true;
+  },
+
+  uninit: function() {
+    this._toolbar.removeEventListener("overflow", this._toolbar);
+    this._toolbar.removeEventListener("underflow", this._toolbar);
+    this._toolbar.removeAttribute("overflowable");
+
+    if (!this.initialized) {
+      Services.obs.removeObserver(this, "browser-delayed-startup-finished");
+      return;
+    }
+
+    this._disable();
+
+    let window = this._toolbar.ownerDocument.defaultView;
+    window.removeEventListener("resize", this);
+    window.gNavToolbox.removeEventListener("customizationstarting", this);
+    window.gNavToolbox.removeEventListener("aftercustomization", this);
+    this._chevron.removeEventListener("command", this);
+    this._panel.removeEventListener("popuphiding", this);
+    CustomizableUI.removeListener(this);
+    CustomizableUIInternal.removePanelCloseListeners(this._panel);
+  },
+
+  handleEvent: function(aEvent) {
+    switch(aEvent.type) {
+      case "resize":
+        this._onResize(aEvent);
+        break;
+      case "command":
+        this._onClickChevron(aEvent);
+        break;
+      case "popuphiding":
+        this._onPanelHiding(aEvent);
+        break;
+      case "customizationstarting":
+        this._disable();
+        break;
+      case "aftercustomization":
+        this._enable();
+        break;
+    }
+  },
+
+  _onClickChevron: function(aEvent) {
+    if (this._chevron.open)
+      this._panel.hidePopup();
+    else {
+      let doc = aEvent.target.ownerDocument;
+      this._panel.hidden = false;
+      let anchor = doc.getAnonymousElementByAttribute(this._chevron, "class", "toolbarbutton-icon");
+      this._panel.openPopup(anchor || this._chevron, "bottomcenter topright");
+    }
+    this._chevron.open = !this._chevron.open;
+  },
+
+  _onPanelHiding: function(aEvent) {
+    this._chevron.open = false;
+  },
+
+  onOverflow: function(aEvent) {
+    if (!this._enabled ||
+        (aEvent && aEvent.target != this._toolbar.customizationTarget))
+      return;
+
+    let child = this._target.lastChild;
+
+    while (child && this._target.scrollLeftMax > 0) {
+      let prevChild = child.previousSibling;
+
+      if (child.getAttribute("overflows") != "false") {
+        this._collapsed.set(child.id, this._target.clientWidth);
+        child.classList.add("overflowedItem");
+        child.setAttribute("cui-anchorid", this._chevron.id);
+
+        this._list.insertBefore(child, this._list.firstChild);
+        if (!this._toolbar.hasAttribute("overflowing")) {
+          CustomizableUI.addListener(this);
+        }
+        this._toolbar.setAttribute("overflowing", "true");
+      }
+      child = prevChild;
+    };
+
+    let win = this._target.ownerDocument.defaultView;
+    win.UpdateUrlbarSearchSplitterState();
+  },
+
+  _onResize: function(aEvent) {
+    if (!this._lazyResizeHandler) {
+      this._lazyResizeHandler = new DeferredTask(this._onLazyResize.bind(this),
+                                                 LAZY_RESIZE_INTERVAL_MS);
+    }
+    this._lazyResizeHandler.start();
+  },
+
+  _moveItemsBackToTheirOrigin: function(shouldMoveAllItems) {
+    let placements = gPlacements.get(this._toolbar.id);
+    while (this._list.firstChild) {
+      let child = this._list.firstChild;
+      let minSize = this._collapsed.get(child.id);
+
+      if (!shouldMoveAllItems &&
+          minSize &&
+          this._target.clientWidth <= minSize) {
+        return;
+      }
+
+      this._collapsed.delete(child.id);
+      let beforeNodeIndex = placements.indexOf(child.id) + 1;
+      // If this is a skipintoolbarset item, meaning it doesn't occur in the placements list,
+      // we're inserting it at the end. This will mean first-in, first-out (more or less)
+      // leading to as little change in order as possible.
+      if (beforeNodeIndex == 0) {
+        beforeNodeIndex = placements.length;
+      }
+      let inserted = false;
+      for (; beforeNodeIndex < placements.length; beforeNodeIndex++) {
+        let beforeNode = this._target.querySelector(idToSelector(placements[beforeNodeIndex]));
+        if (beforeNode) {
+          this._target.insertBefore(child, beforeNode);
+          inserted = true;
+          break;
+        }
+      }
+      if (!inserted) {
+        this._target.appendChild(child);
+      }
+      child.removeAttribute("cui-anchorid");
+      child.classList.remove("overflowedItem");
+    }
+
+    let win = this._target.ownerDocument.defaultView;
+    win.UpdateUrlbarSearchSplitterState();
+
+    if (!this._collapsed.size) {
+      this._toolbar.removeAttribute("overflowing");
+      CustomizableUI.removeListener(this);
+    }
+  },
+
+  _onLazyResize: function() {
+    if (!this._enabled)
+      return;
+
+    this._moveItemsBackToTheirOrigin();
+  },
+
+  _disable: function() {
+    this._enabled = false;
+    this._moveItemsBackToTheirOrigin(true);
+    if (this._lazyResizeHandler) {
+      this._lazyResizeHandler.cancel();
+    }
+  },
+
+  _enable: function() {
+    this._enabled = true;
+    this.onOverflow();
+  },
+
+  onWidgetBeforeDOMChange: function(aNode, aNextNode, aContainer) {
+    if (aContainer != this._target) {
+      return;
+    }
+    // When we (re)move an item, update all the items that come after it in the list
+    // with the minsize *of the item before the to-be-removed node*. This way, we
+    // ensure that we try to move items back as soon as that's possible.
+    if (aNode.parentNode == this._list) {
+      let updatedMinSize;
+      if (aNode.previousSibling) {
+        updatedMinSize = this._collapsed.get(aNode.previousSibling.id);
+      } else {
+        // Force (these) items to try to flow back into the bar:
+        updatedMinSize = 1;
+      }
+      let nextItem = aNode.nextSibling;
+      while (nextItem) {
+        this._collapsed.set(nextItem.id, updatedMinSize);
+        nextItem = nextItem.nextSibling;
+      }
+    }
+  },
+
+  onWidgetAfterDOMChange: function(aNode, aNextNode, aContainer) {
+    if (aContainer != this._target) {
+      return;
+    }
+
+    let nowInBar = aNode.parentNode == aContainer;
+    let nowOverflowed = aNode.parentNode == this._list;
+    let wasOverflowed = this._collapsed.has(aNode.id);
+
+    // If this wasn't overflowed before...
+    if (!wasOverflowed) {
+      // ... but it is now, then we added to the overflow panel. Exciting stuff:
+      if (nowOverflowed) {
+        // NB: we're guaranteed that it has a previousSibling, because if it didn't,
+        // we would have added it to the toolbar instead. See getOverflowedNextNode.
+        let prevId = aNode.previousSibling.id;
+        let minSize = this._collapsed.get(prevId);
+        this._collapsed.set(aNode.id, minSize);
+        aNode.setAttribute("cui-anchorid", this._chevron.id);
+        aNode.classList.add("overflowedItem");
+      }
+      // If it is not overflowed and not in the toolbar, and was not overflowed
+      // either, it moved out of the toolbar. That means there's now space in there!
+      // Let's try to move stuff back:
+      else if (!nowInBar) {
+        this._moveItemsBackToTheirOrigin(true);
+      }
+      // If it's in the toolbar now, then we don't care. An overflow event may
+      // fire afterwards; that's ok!
+    }
+    // If it used to be overflowed...
+    else {
+      // ... and isn't anymore, let's remove our bookkeeping:
+      if (!nowOverflowed) {
+        this._collapsed.delete(aNode.id);
+        aNode.removeAttribute("cui-anchorid");
+        aNode.classList.remove("overflowedItem");
+
+        if (!this._collapsed.size) {
+          this._toolbar.removeAttribute("overflowing");
+          CustomizableUI.removeListener(this);
+        }
+      }
+      // but if it still is, it must have changed places. Bookkeep:
+      else {
+        if (aNode.previousSibling) {
+          let prevId = aNode.previousSibling.id;
+          let minSize = this._collapsed.get(prevId);
+          this._collapsed.set(aNode.id, minSize);
+        } else {
+          // If it's now the first item in the overflow list,
+          // maybe we can return it:
+          this._moveItemsBackToTheirOrigin();
+        }
+      }
+    }
+  },
+
+  getOverflowedInsertionPoints: function(aNode, aNextNodeId) {
+    if (aNode.getAttribute("overflows") == "false") {
+      return [this._target, null];
+    }
+    // Inserting at the end means we're in the overflow list by definition:
+    if (!aNextNodeId) {
+      return [this._list, null];
+    }
+
+    let nextNode = this._list.querySelector(idToSelector(aNextNodeId));
+    // If this is the first item, we can actually just append the node
+    // to the end of the toolbar.  If it results in an overflow event, we'll move
+    // the new node to the overflow target.
+    if (!nextNode.previousSibling) {
+      return [this._target, null];
+    }
+    return [this._list, nextNode];
+  }
+};
+
+// When IDs contain special characters, we need to escape them for use with querySelector:
+function idToSelector(aId) {
+  return "#" + aId.replace(/[ !"'#$%&\(\)*+\-,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&');
+}
+
+CustomizableUIInternal.initialize();
diff --git a/browser/components/customizableui/src/CustomizableWidgets.jsm b/browser/components/customizableui/src/CustomizableWidgets.jsm
new file mode 100644
index 0000000000000000000000000000000000000000..5f1fd8e23a66533dc64444f03add4aa14944ae33
--- /dev/null
+++ b/browser/components/customizableui/src/CustomizableWidgets.jsm
@@ -0,0 +1,778 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+this.EXPORTED_SYMBOLS = ["CustomizableWidgets"];
+
+Cu.import("resource:///modules/CustomizableUI.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+  "resource://gre/modules/PlacesUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils",
+  "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm");
+XPCOMUtils.defineLazyServiceGetter(this, "CharsetManager",
+                                   "@mozilla.org/charset-converter-manager;1",
+                                   "nsICharsetConverterManager");
+
+const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+const kPrefCustomizationDebug = "browser.uiCustomization.debug";
+const kWidePanelItemClass = "panel-wide-item";
+
+let gModuleName = "[CustomizableWidgets]";
+#include logging.js
+
+function setAttributes(aNode, aAttrs) {
+  for (let [name, value] of Iterator(aAttrs)) {
+    if (!value) {
+      if (aNode.hasAttribute(name))
+        aNode.removeAttribute(name);
+    } else {
+      if (name == "label" || name == "tooltiptext")
+        value = CustomizableUI.getLocalizedProperty({id: aAttrs.id}, name);
+      aNode.setAttribute(name, value);
+    }
+  }
+}
+
+function updateCombinedWidgetStyle(aNode, aArea, aModifyAutoclose) {
+  let inPanel = (aArea == CustomizableUI.AREA_PANEL);
+  let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1";
+  if (!aArea)
+    cls = null;
+  let attrs = {class: cls};
+  if (aModifyAutoclose) {
+    attrs.noautoclose = inPanel ? true : null;
+  }
+  for (let i = 0, l = aNode.childNodes.length; i < l; ++i) {
+    setAttributes(aNode.childNodes[i], attrs);
+  }
+}
+
+const CustomizableWidgets = [{
+    id: "history-panelmenu",
+    type: "view",
+    viewId: "PanelUI-history",
+    shortcutId: "key_gotoHistory",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    onViewShowing: function(aEvent) {
+      // Populate our list of history
+      const kMaxResults = 15;
+      let doc = aEvent.detail.ownerDocument;
+
+      let options = PlacesUtils.history.getNewQueryOptions();
+      options.excludeQueries = true;
+      options.includeHidden = false;
+      options.resultType = options.RESULTS_AS_URI;
+      options.queryType = options.QUERY_TYPE_HISTORY;
+      options.sortingMode = options.SORT_BY_DATE_DESCENDING;
+      options.maxResults = kMaxResults;
+      let query = PlacesUtils.history.getNewQuery();
+
+      let items = doc.getElementById("PanelUI-historyItems");
+      // Clear previous history items.
+      while (items.firstChild) {
+        items.removeChild(items.firstChild);
+      }
+
+      PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
+                         .asyncExecuteLegacyQueries([query], 1, options, {
+        handleResult: function (aResultSet) {
+          let onHistoryVisit = function (aUri, aEvent, aItem) {
+            doc.defaultView.openUILink(aUri, aEvent);
+            CustomizableUI.hidePanelForNode(aItem);
+          };
+          let fragment = doc.createDocumentFragment();
+          for (let row, i = 0; (row = aResultSet.getNextRow()); i++) {
+            try {
+              let uri = row.getResultByIndex(1);
+              let title = row.getResultByIndex(2);
+              let icon = row.getResultByIndex(6);
+
+              let item = doc.createElementNS(kNSXUL, "toolbarbutton");
+              item.setAttribute("label", title || uri);
+              item.setAttribute("tabindex", "0");
+              item.addEventListener("command", function (aEvent) {
+                onHistoryVisit(uri, aEvent, item);
+              });
+              item.addEventListener("click", function (aEvent) {
+                onHistoryVisit(uri, aEvent, item);
+              });
+              if (icon)
+                item.setAttribute("image", "moz-anno:favicon:" + icon);
+              fragment.appendChild(item);
+            } catch (e) {
+              ERROR("Error while showing history subview: " + e);
+            }
+          }
+          items.appendChild(fragment);
+        },
+        handleError: function (aError) {
+          LOG("History view tried to show but had an error: " + aError);
+        },
+        handleCompletion: function (aReason) {
+          LOG("History view is being shown!");
+        },
+      });
+
+      let recentlyClosedTabs = doc.getElementById("PanelUI-recentlyClosedTabs");
+      while (recentlyClosedTabs.firstChild) {
+        recentlyClosedTabs.removeChild(recentlyClosedTabs.firstChild);
+      }
+
+      let recentlyClosedWindows = doc.getElementById("PanelUI-recentlyClosedWindows");
+      while (recentlyClosedWindows.firstChild) {
+        recentlyClosedWindows.removeChild(recentlyClosedWindows.firstChild);
+      }
+
+      let tabsFragment = RecentlyClosedTabsAndWindowsMenuUtils.getTabsFragment(doc.defaultView, "toolbarbutton");
+      let separator = doc.getElementById("PanelUI-recentlyClosedTabs-separator");
+      separator.hidden = !tabsFragment.childElementCount;
+      recentlyClosedTabs.appendChild(tabsFragment);
+
+      let windowsFragment = RecentlyClosedTabsAndWindowsMenuUtils.getWindowsFragment(doc.defaultView, "toolbarbutton");
+      separator = doc.getElementById("PanelUI-recentlyClosedWindows-separator");
+      separator.hidden = !windowsFragment.childElementCount;
+      recentlyClosedWindows.appendChild(windowsFragment);
+    },
+    onViewHiding: function(aEvent) {
+      LOG("History view is being hidden!");
+    }
+  }, {
+    id: "privatebrowsing-button",
+    removable: true,
+    shortcutId: "key_privatebrowsing",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    onCommand: function(e) {
+      if (e.target && e.target.ownerDocument && e.target.ownerDocument.defaultView) {
+        let win = e.target.ownerDocument.defaultView;
+        if (typeof win.OpenBrowserWindow == "function") {
+          win.OpenBrowserWindow({private: true});
+        }
+      }
+    }
+  }, {
+    id: "save-page-button",
+    removable: true,
+    shortcutId: "key_savePage",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    onCommand: function(aEvent) {
+      let win = aEvent.target &&
+                aEvent.target.ownerDocument &&
+                aEvent.target.ownerDocument.defaultView;
+      if (win && typeof win.saveDocument == "function") {
+        win.saveDocument(win.content.document);
+      }
+    }
+  }, {
+    id: "find-button",
+    removable: true,
+    shortcutId: "key_find",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    onCommand: function(aEvent) {
+      let win = aEvent.target &&
+                aEvent.target.ownerDocument &&
+                aEvent.target.ownerDocument.defaultView;
+      if (win && win.gFindBar) {
+        win.gFindBar.onFindCommand();
+      }
+    }
+  }, {
+    id: "open-file-button",
+    removable: true,
+    shortcutId: "openFileKb",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    onCommand: function(aEvent) {
+      let win = aEvent.target
+                && aEvent.target.ownerDocument
+                && aEvent.target.ownerDocument.defaultView;
+      if (win && typeof win.BrowserOpenFileWindow == "function") {
+        win.BrowserOpenFileWindow();
+      }
+    }
+  }, {
+    id: "developer-button",
+    type: "view",
+    viewId: "PanelUI-developer",
+    removable: true,
+    shortcutId: "key_devToolboxMenuItem",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    onViewShowing: function(aEvent) {
+      // Populate the subview with whatever menuitems are in the developer
+      // menu. We skip menu elements, because the menu panel has no way
+      // of dealing with those right now.
+      let doc = aEvent.target.ownerDocument;
+      let win = doc.defaultView;
+
+      let items = doc.getElementById("PanelUI-developerItems");
+      let menu = doc.getElementById("menuWebDeveloperPopup");
+      let attrs = ["oncommand", "onclick", "label", "key", "disabled",
+                   "command", "observes"];
+
+      let fragment = doc.createDocumentFragment();
+      let itemsToDisplay = [...menu.children];
+      // Hardcode the addition of the "work offline" menuitem at the bottom:
+      itemsToDisplay.push({localName: "menuseparator", getAttribute: () => {}});
+      itemsToDisplay.push(doc.getElementById("goOfflineMenuitem"));
+      for (let node of itemsToDisplay) {
+        if (node.hidden)
+          continue;
+
+        let item;
+        if (node.localName == "menuseparator") {
+          item = doc.createElementNS(kNSXUL, "menuseparator");
+        } else if (node.localName == "menuitem") {
+          item = doc.createElementNS(kNSXUL, "toolbarbutton");
+          item.setAttribute("tabindex", "0");
+        } else {
+          continue;
+        }
+        for (let attr of attrs) {
+          let attrVal = node.getAttribute(attr);
+          if (attrVal)
+            item.setAttribute(attr, attrVal);
+        }
+        fragment.appendChild(item);
+      }
+      items.appendChild(fragment);
+
+      aEvent.target.addEventListener("command", win.PanelUI.onCommandHandler);
+    },
+    onViewHiding: function(aEvent) {
+      let doc = aEvent.target.ownerDocument;
+      let win = doc.defaultView;
+      let items = doc.getElementById("PanelUI-developerItems");
+      let parent = items.parentNode;
+      // We'll take the container out of the document before cleaning it out
+      // to avoid reflowing each time we remove something.
+      parent.removeChild(items);
+
+      while (items.firstChild) {
+        items.firstChild.remove();
+      }
+
+      parent.appendChild(items);
+      aEvent.target.removeEventListener("command",
+                                        win.PanelUI.onCommandHandler);
+    }
+  }, {
+    id: "add-ons-button",
+    removable: true,
+    shortcutId: "key_openAddons",
+    defaultArea: CustomizableUI.AREA_PANEL,
+    onCommand: function(aEvent) {
+      let win = aEvent.target &&
+                aEvent.target.ownerDocument &&
+                aEvent.target.ownerDocument.defaultView;
+      if (win && typeof win.BrowserOpenAddonsMgr == "function") {
+        win.BrowserOpenAddonsMgr();
+      }
+    }
+  }, {
+    id: "preferences-button",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+#ifdef XP_WIN
+    label: "preferences-button.labelWin",
+    tooltiptext: "preferences-button.tooltipWin",
+#endif
+    onCommand: function(aEvent) {
+      let win = aEvent.target &&
+                aEvent.target.ownerDocument &&
+                aEvent.target.ownerDocument.defaultView;
+      if (win && typeof win.openPreferences == "function") {
+        win.openPreferences();
+      }
+    }
+  }, {
+    id: "zoom-controls",
+    type: "custom",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    onBuild: function(aDocument) {
+      const kPanelId = "PanelUI-popup";
+      let inPanel = (this.currentArea == CustomizableUI.AREA_PANEL);
+      let noautoclose = inPanel ? "true" : null;
+      let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1";
+
+      if (!this.currentArea)
+        cls = null;
+
+      let buttons = [{
+        id: "zoom-out-button",
+        noautoclose: noautoclose,
+        command: "cmd_fullZoomReduce",
+        class: cls,
+        label: true,
+        tooltiptext: true
+      }, {
+        id: "zoom-reset-button",
+        noautoclose: noautoclose,
+        command: "cmd_fullZoomReset",
+        class: cls,
+        tooltiptext: true
+      }, {
+        id: "zoom-in-button",
+        noautoclose: noautoclose,
+        command: "cmd_fullZoomEnlarge",
+        class: cls,
+        label: true,
+        tooltiptext: true
+      }];
+
+      let node = aDocument.createElementNS(kNSXUL, "toolbaritem");
+      node.setAttribute("id", "zoom-controls");
+      node.setAttribute("title", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
+      // Set this as an attribute in addition to the property to make sure we can style correctly.
+      node.setAttribute("removable", "true");
+      node.classList.add("chromeclass-toolbar-additional");
+      node.classList.add("toolbaritem-combined-buttons");
+      node.classList.add(kWidePanelItemClass);
+
+      buttons.forEach(function(aButton) {
+        let btnNode = aDocument.createElementNS(kNSXUL, "toolbarbutton");
+        setAttributes(btnNode, aButton);
+        if (inPanel)
+          btnNode.setAttribute("tabindex", "0");
+        node.appendChild(btnNode);
+      });
+
+      // The middle node is the 'Reset Zoom' button.
+      let zoomResetButton = node.childNodes[1];
+      let window = aDocument.defaultView;
+      function updateZoomResetButton() {
+        //XXXgijs in some tests we get called very early, and there's no docShell on the
+        // tabbrowser. This breaks the zoom toolkit code (see bug 897410). Don't let that happen:
+        let zoomFactor = 100;
+        if (window.gBrowser.docShell) {
+          zoomFactor = Math.floor(window.ZoomManager.zoom * 100);
+        }
+        zoomResetButton.setAttribute("label", CustomizableUI.getLocalizedProperty(
+          buttons[1], "label", [zoomFactor]
+        ));
+      };
+
+      // Register ourselves with the service so we know when the zoom prefs change.
+      Services.obs.addObserver(updateZoomResetButton, "browser-fullZoom:zoomChange", false);
+      Services.obs.addObserver(updateZoomResetButton, "browser-fullZoom:zoomReset", false);
+
+      if (inPanel && this.currentArea) {
+        let panel = aDocument.getElementById(kPanelId);
+        panel.addEventListener("popupshowing", updateZoomResetButton);
+      } else {
+        updateZoomResetButton();
+      }
+
+      let listener = {
+        onWidgetAdded: function(aWidgetId, aArea, aPosition) {
+          if (aWidgetId != this.id)
+            return;
+
+          updateCombinedWidgetStyle(node, aArea, true);
+          updateZoomResetButton();
+
+          if (aArea == CustomizableUI.AREA_PANEL) {
+            let panel = aDocument.getElementById(kPanelId);
+            panel.addEventListener("popupshowing", updateZoomResetButton);
+          }
+        }.bind(this),
+
+        onWidgetRemoved: function(aWidgetId, aPrevArea) {
+          if (aWidgetId != this.id)
+            return;
+
+          if (aPrevArea == CustomizableUI.AREA_PANEL) {
+            let panel = aDocument.getElementById(kPanelId);
+            panel.removeEventListener("popupshowing", updateZoomResetButton);
+          }
+
+          // When a widget is demoted to the palette ('removed'), it's visual
+          // style should change.
+          updateCombinedWidgetStyle(node, null, true);
+          updateZoomResetButton();
+        }.bind(this),
+
+        onWidgetReset: function(aWidgetId) {
+          if (aWidgetId != this.id)
+            return;
+          updateCombinedWidgetStyle(node, this.currentArea, true);
+          updateZoomResetButton();
+        }.bind(this),
+
+        onWidgetMoved: function(aWidgetId, aArea) {
+          if (aWidgetId != this.id)
+            return;
+          updateCombinedWidgetStyle(node, aArea, true);
+          updateZoomResetButton();
+        }.bind(this),
+
+        onWidgetInstanceRemoved: function(aWidgetId, aDoc) {
+          if (aWidgetId != this.id || aDoc != aDocument)
+            return;
+
+          CustomizableUI.removeListener(listener);
+          Services.obs.removeObserver(updateZoomResetButton, "browser-fullZoom:zoomChange");
+          Services.obs.removeObserver(updateZoomResetButton, "browser-fullZoom:zoomReset");
+          let panel = aDoc.getElementById(kPanelId);
+          panel.removeEventListener("popupshowing", updateZoomResetButton);
+        }.bind(this),
+
+        onWidgetDrag: function(aWidgetId, aArea) {
+          if (aWidgetId != this.id)
+            return;
+          aArea = aArea || this.currentArea;
+          updateCombinedWidgetStyle(node, aArea, true);
+        }.bind(this)
+      };
+      CustomizableUI.addListener(listener);
+
+      return node;
+    }
+  }, {
+    id: "edit-controls",
+    type: "custom",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    onBuild: function(aDocument) {
+      let inPanel = (this.currentArea == CustomizableUI.AREA_PANEL);
+      let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1";
+
+      if (!this.currentArea)
+        cls = null;
+
+      let buttons = [{
+        id: "cut-button",
+        command: "cmd_cut",
+        class: cls,
+        label: true,
+        tooltiptext: true
+      }, {
+        id: "copy-button",
+        command: "cmd_copy",
+        class: cls,
+        label: true,
+        tooltiptext: true
+      }, {
+        id: "paste-button",
+        command: "cmd_paste",
+        class: cls,
+        label: true,
+        tooltiptext: true
+      }];
+
+      let node = aDocument.createElementNS(kNSXUL, "toolbaritem");
+      node.setAttribute("id", "edit-controls");
+      node.setAttribute("title", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
+      // Set this as an attribute in addition to the property to make sure we can style correctly.
+      node.setAttribute("removable", "true");
+      node.classList.add("chromeclass-toolbar-additional");
+      node.classList.add("toolbaritem-combined-buttons");
+      node.classList.add(kWidePanelItemClass);
+
+      buttons.forEach(function(aButton) {
+        let btnNode = aDocument.createElementNS(kNSXUL, "toolbarbutton");
+        setAttributes(btnNode, aButton);
+        if (inPanel)
+          btnNode.setAttribute("tabindex", "0");
+        node.appendChild(btnNode);
+      });
+
+      let listener = {
+        onWidgetAdded: function(aWidgetId, aArea, aPosition) {
+          if (aWidgetId != this.id)
+            return;
+          updateCombinedWidgetStyle(node, aArea);
+        }.bind(this),
+
+        onWidgetRemoved: function(aWidgetId, aPrevArea) {
+          if (aWidgetId != this.id)
+            return;
+          // When a widget is demoted to the palette ('removed'), it's visual
+          // style should change.
+          updateCombinedWidgetStyle(node);
+        }.bind(this),
+
+        onWidgetReset: function(aWidgetId) {
+          if (aWidgetId != this.id)
+            return;
+          updateCombinedWidgetStyle(node, this.currentArea);
+        }.bind(this),
+
+        onWidgetMoved: function(aWidgetId, aArea) {
+          if (aWidgetId != this.id)
+            return;
+          updateCombinedWidgetStyle(node, aArea);
+        }.bind(this),
+
+        onWidgetInstanceRemoved: function(aWidgetId, aDoc) {
+          if (aWidgetId != this.id || aDoc != aDocument)
+            return;
+          CustomizableUI.removeListener(listener);
+        }.bind(this),
+
+        onWidgetDrag: function(aWidgetId, aArea) {
+          if (aWidgetId != this.id)
+            return;
+          aArea = aArea || this.currentArea;
+          updateCombinedWidgetStyle(node, aArea);
+        }.bind(this)
+      };
+      CustomizableUI.addListener(listener);
+
+      return node;
+    }
+  },
+  {
+    id: "feed-button",
+    type: "view",
+    viewId: "PanelUI-feeds",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    onClick: function(aEvent) {
+      let win = aEvent.target.ownerDocument.defaultView;
+      let feeds = win.gBrowser.selectedBrowser.feeds;
+
+      // Here, we only care about the case where we have exactly 1 feed and the
+      // user clicked...
+      let isClick = (aEvent.button == 0 || aEvent.button == 1);
+      if (feeds && feeds.length == 1 && isClick) {
+        aEvent.preventDefault();
+        aEvent.stopPropagation();
+        win.FeedHandler.subscribeToFeed(feeds[0].href, aEvent);
+        CustomizableUI.hidePanelForNode(aEvent.target);
+      }
+    },
+    onViewShowing: function(aEvent) {
+      let doc = aEvent.detail.ownerDocument;
+      let container = doc.getElementById("PanelUI-feeds");
+      let gotView = doc.defaultView.FeedHandler.buildFeedList(container, true);
+
+      // For no feeds or only a single one, don't show the panel.
+      if (!gotView) {
+        aEvent.preventDefault();
+        aEvent.stopPropagation();
+        return;
+      }
+    },
+    onCreated: function(node) {
+      let win = node.ownerDocument.defaultView;
+      let selectedBrowser = win.gBrowser.selectedBrowser;
+      let feeds = selectedBrowser && selectedBrowser.feeds;
+      if (!feeds || !feeds.length) {
+        node.setAttribute("disabled", "true");
+      }
+    }
+  }, {
+    id: "characterencoding-button",
+    type: "view",
+    viewId: "PanelUI-characterEncodingView",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    maybeDisableMenu: function(aDocument) {
+      let window = aDocument.defaultView;
+      return !(window.gBrowser &&
+               window.gBrowser.docShell &&
+               window.gBrowser.docShell.mayEnableCharacterEncodingMenu);
+    },
+    getCharsetList: function(aSection, aDocument) {
+      let currCharset = aDocument.defaultView.content.document.characterSet;
+
+      let list = "";
+      try {
+        let pref = "intl.charsetmenu.browser." + aSection;
+        list = Services.prefs.getComplexValue(pref,
+                                              Ci.nsIPrefLocalizedString).data;
+      } catch (e) {}
+
+      list = list.trim();
+      if (!list)
+        return [];
+
+      list = list.split(",");
+
+      let items = [];
+      for (let charset of list) {
+        charset = charset.trim();
+
+        let notForBrowser = false;
+        try {
+          notForBrowser = CharsetManager.getCharsetData(charset,
+                                                        "notForBrowser");
+        } catch (e) {}
+
+        if (notForBrowser)
+          continue;
+
+        let title = charset;
+        try {
+          title = CharsetManager.getCharsetTitle(charset);
+        } catch (e) {}
+
+        items.push({value: charset, name: title, current: charset == currCharset});
+      }
+
+      return items;
+    },
+    getAutoDetectors: function(aDocument) {
+      let detectorEnum = CharsetManager.GetCharsetDetectorList();
+      let currDetector;
+      try {
+        currDetector = Services.prefs.getComplexValue(
+          "intl.charset.detector", Ci.nsIPrefLocalizedString).data;
+      } catch (e) {}
+      if (!currDetector)
+        currDetector = "off";
+      currDetector = "chardet." + currDetector;
+
+      let items = [];
+
+      while (detectorEnum.hasMore()) {
+        let detector = detectorEnum.getNext();
+
+        let title = detector;
+        try {
+          title = CharsetManager.getCharsetTitle(detector);
+        } catch (e) {}
+
+        items.push({value: detector, name: title, current: detector == currDetector});
+      }
+
+      items.sort((aItem1, aItem2) => {
+        return aItem1.name.localeCompare(aItem2.name);
+      });
+
+      return items;
+    },
+    populateList: function(aDocument, aContainerId, aSection) {
+      let containerElem = aDocument.getElementById(aContainerId);
+
+      while (containerElem.firstChild) {
+        containerElem.removeChild(containerElem.firstChild);
+      }
+
+      containerElem.addEventListener("command", this.onCommand, false);
+
+      let list = [];
+      if (aSection == "autodetect") {
+        list = this.getAutoDetectors(aDocument);
+      } else if (aSection == "browser") {
+        let staticList = this.getCharsetList("static", aDocument);
+        let cacheList = this.getCharsetList("cache", aDocument);
+        // Combine lists, and de-duplicate.
+        let checkedIn = new Set();
+        for (let item of staticList.concat(cacheList)) {
+          let itemName = item.name.toLowerCase();
+          if (!checkedIn.has(itemName)) {
+            list.push(item);
+            checkedIn.add(itemName);
+          }
+        }
+      }
+
+      // Update the appearance of the buttons when it's not possible to
+      // customize encoding.
+      let disabled = this.maybeDisableMenu(aDocument);
+      for (let item of list) {
+        let elem = aDocument.createElementNS(kNSXUL, "toolbarbutton");
+        elem.setAttribute("label", item.name);
+        elem.section = aSection;
+        elem.value = item.value;
+        if (item.current)
+          elem.setAttribute("current", "true");
+        if (disabled)
+          elem.setAttribute("disabled", "true");
+        containerElem.appendChild(elem);
+      }
+    },
+    onViewShowing: function(aEvent) {
+      let document = aEvent.target.ownerDocument;
+
+      this.populateList(document,
+                        "PanelUI-characterEncodingView-customlist",
+                        "browser");
+      this.populateList(document,
+                        "PanelUI-characterEncodingView-autodetect",
+                        "autodetect");
+    },
+    onCommand: function(aEvent) {
+      let node = aEvent.target;
+      if (!node.hasAttribute || !node.section) {
+        return;
+      }
+
+      CustomizableUI.hidePanelForNode(node);
+      let window = node.ownerDocument.defaultView;
+      let section = node.section;
+      let value = node.value;
+
+      // The behavior as implemented here is directly based off of the
+      // `MultiplexHandler()` method in browser.js.
+      if (section == "browser") {
+        window.BrowserSetForcedCharacterSet(value);
+      } else if (section == "autodetect") {
+        value = value.replace(/^chardet\./, "");
+        if (value == "off") {
+          value = "";
+        }
+        // Set the detector pref.
+        try {
+          let str = Cc["@mozilla.org/supports-string;1"]
+                      .createInstance(Ci.nsISupportsString);
+          str.data = value;
+          Services.prefs.setComplexValue("intl.charset.detector", Ci.nsISupportsString, str);
+        } catch (e) {
+          Cu.reportError("Failed to set the intl.charset.detector preference.");
+        }
+        // Prepare a browser page reload with a changed charset.
+        window.BrowserCharsetReload();
+      }
+    },
+    onCreated: function(aNode) {
+      const kPanelId = "PanelUI-popup";
+      let document = aNode.ownerDocument;
+
+      let updateButton = () => {
+        if (this.maybeDisableMenu(document))
+          aNode.setAttribute("disabled", "true");
+        else
+          aNode.removeAttribute("disabled");
+      };
+
+      if (this.currentArea == CustomizableUI.AREA_PANEL) {
+        let panel = document.getElementById(kPanelId);
+        panel.addEventListener("popupshowing", updateButton);
+      }
+
+      let listener = {
+        onWidgetAdded: (aWidgetId, aArea) => {
+          if (aWidgetId != this.id)
+            return;
+          if (aArea == CustomizableUI.AREA_PANEL) {
+            let panel = document.getElementById(kPanelId);
+            panel.addEventListener("popupshowing", updateButton);
+          }
+        },
+        onWidgetRemoved: (aWidgetId, aPrevArea) => {
+          if (aWidgetId != this.id)
+            return;
+          if (aPrevArea == CustomizableUI.AREA_PANEL) {
+            let panel = document.getElementById(kPanelId);
+            panel.removeEventListener("popupshowing", updateButton);
+          }
+        },
+        onWidgetInstanceRemoved: (aWidgetId, aDoc) => {
+          if (aWidgetId != this.id || aDoc != document)
+            return;
+
+          CustomizableUI.removeListener(listener);
+          let panel = aDoc.getElementById(kPanelId);
+          panel.removeEventListener("popupshowing", updateButton);
+        }
+      };
+      CustomizableUI.addListener(listener);
+    }
+  }];
diff --git a/browser/components/customizableui/src/CustomizeMode.jsm b/browser/components/customizableui/src/CustomizeMode.jsm
new file mode 100644
index 0000000000000000000000000000000000000000..27e5d768aa95749f0b97397cfdf5d3bdab379856
--- /dev/null
+++ b/browser/components/customizableui/src/CustomizeMode.jsm
@@ -0,0 +1,1430 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["CustomizeMode"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+const kPrefCustomizationDebug = "browser.uiCustomization.debug";
+const kPrefCustomizationAnimation = "browser.uiCustomization.disableAnimation";
+const kPaletteId = "customization-palette";
+const kAboutURI = "about:customizing";
+const kDragDataTypePrefix = "text/toolbarwrapper-id/";
+const kPlaceholderClass = "panel-customization-placeholder";
+const kWidePanelItemClass = "panel-wide-item";
+// TODO(bug 885574): Merge this constant with the one in CustomizableWidgets.jsm,
+//                   maybe just use a pref for this.
+const kColumnsInMenuPanel = 3;
+const kSkipSourceNodePref = "browser.uiCustomization.skipSourceNodeCheck";
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource:///modules/CustomizableUI.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Promise.jsm");
+
+let gModuleName = "[CustomizeMode]";
+#include logging.js
+
+let gDisableAnimation = null;
+
+function CustomizeMode(aWindow) {
+  if (gDisableAnimation === null) {
+    gDisableAnimation = Services.prefs.getPrefType(kPrefCustomizationAnimation) == Ci.nsIPrefBranch.PREF_BOOL &&
+                        Services.prefs.getBoolPref(kPrefCustomizationAnimation);
+  }
+  this.window = aWindow;
+  this.document = aWindow.document;
+  this.browser = aWindow.gBrowser;
+
+  // There are two palettes - there's the palette that can be overlayed with
+  // toolbar items in browser.xul. This is invisible, and never seen by the
+  // user. Then there's the visible palette, which gets populated and displayed
+  // to the user when in customizing mode.
+  this.visiblePalette = this.document.getElementById(kPaletteId);
+};
+
+CustomizeMode.prototype = {
+  _changed: false,
+  _transitioning: false,
+  window: null,
+  document: null,
+  // areas is used to cache the customizable areas when in customization mode.
+  areas: null,
+  // When in customizing mode, we swap out the reference to the invisible
+  // palette in gNavToolbox.palette for our visiblePalette. This way, for the
+  // customizing browser window, when widgets are removed from customizable
+  // areas and added to the palette, they're added to the visible palette.
+  // _stowedPalette is a reference to the old invisible palette so we can
+  // restore gNavToolbox.palette to its original state after exiting
+  // customization mode.
+  _stowedPalette: null,
+  _dragOverItem: null,
+  _customizing: false,
+  _skipSourceNodeCheck: null,
+
+  get panelUIContents() {
+    return this.document.getElementById("PanelUI-contents");
+  },
+
+  toggle: function() {
+    if (this._transitioning) {
+      return;
+    }
+    if (this._customizing) {
+      this.exit();
+    } else {
+      this.enter();
+    }
+  },
+
+  enter: function() {
+    if (this._customizing || this._transitioning) {
+      return;
+    }
+
+    // We don't need to switch to kAboutURI, or open a new tab at
+    // kAboutURI if we're already on it.
+    if (this.browser.selectedBrowser.currentURI.spec != kAboutURI) {
+      this.window.switchToTabHavingURI(kAboutURI, true);
+      return;
+    }
+
+    Task.spawn(function() {
+      // We shouldn't start customize mode until after browser-delayed-startup has finished:
+      if (!this.window.gBrowserInit.delayedStartupFinished) {
+        let delayedStartupDeferred = Promise.defer();
+        let delayedStartupObserver = function(aSubject) {
+          if (aSubject == this.window) {
+            Services.obs.removeObserver(delayedStartupObserver, "browser-delayed-startup-finished");
+            delayedStartupDeferred.resolve();
+          }
+        }.bind(this);
+        Services.obs.addObserver(delayedStartupObserver, "browser-delayed-startup-finished", false);
+        yield delayedStartupDeferred.promise;
+      }
+
+      // Disable lightweight themes while in customization mode since
+      // they don't have large enough images to pad the full browser window.
+      if (this.document.documentElement._lightweightTheme)
+        this.document.documentElement._lightweightTheme.disable();
+
+      this.dispatchToolboxEvent("beforecustomization");
+
+      let window = this.window;
+      let document = this.document;
+
+      // Add a keypress listener to the document so that we can quickly exit
+      // customization mode when pressing ESC.
+      document.addEventListener("keypress", this);
+
+      // Same goes for the menu button - if we're customizing, a mousedown to the
+      // menu button means a quick exit from customization mode.
+      window.PanelUI.hide();
+      window.PanelUI.menuButton.addEventListener("mousedown", this);
+      window.PanelUI.menuButton.open = true;
+      window.PanelUI.beginBatchUpdate();
+
+      // Move the mainView in the panel to the holder so that we can see it
+      // while customizing.
+      let panelHolder = document.getElementById("customization-panelHolder");
+      panelHolder.appendChild(window.PanelUI.mainView);
+
+      this._transitioning = true;
+
+      let customizer = document.getElementById("customization-container");
+      customizer.parentNode.selectedPanel = customizer;
+      customizer.hidden = false;
+
+      yield this._doTransition(true);
+
+      // Let everybody in this window know that we're about to customize.
+      this.dispatchToolboxEvent("customizationstarting");
+
+      // The menu panel is lazy, and registers itself when the popup shows. We
+      // need to force the menu panel to register itself, or else customization
+      // is really not going to work. We pass "true" to ensureRegistered to
+      // indicate that we're handling calling startBatchUpdate and
+      // endBatchUpdate.
+      yield window.PanelUI.ensureReady(true);
+
+      this._showPanelCustomizationPlaceholders();
+      CustomizableUI.addListener(this);
+
+      yield this._wrapToolbarItems();
+      yield this.populatePalette();
+
+      window.PanelUI.mainView.addEventListener("contextmenu", this, true);
+      this.visiblePalette.addEventListener("dragstart", this, true);
+      this.visiblePalette.addEventListener("dragover", this, true);
+      this.visiblePalette.addEventListener("dragexit", this, true);
+      this.visiblePalette.addEventListener("drop", this, true);
+      this.visiblePalette.addEventListener("dragend", this, true);
+
+      window.gNavToolbox.addEventListener("toolbarvisibilitychange", this);
+
+      document.getElementById("PanelUI-help").setAttribute("disabled", true);
+      document.getElementById("PanelUI-quit").setAttribute("disabled", true);
+
+      this._updateResetButton();
+
+      this._skipSourceNodeCheck = Services.prefs.getPrefType(kSkipSourceNodePref) == Ci.nsIPrefBranch.PREF_BOOL &&
+                                  Services.prefs.getBoolPref(kSkipSourceNodePref);
+
+      let customizableToolbars = document.querySelectorAll("toolbar[customizable=true]:not([autohide=true]):not([collapsed=true])");
+      for (let toolbar of customizableToolbars)
+        toolbar.setAttribute("customizing", true);
+
+      window.PanelUI.endBatchUpdate();
+      this._customizing = true;
+      this._transitioning = false;
+      this.dispatchToolboxEvent("customizationready");
+    }.bind(this)).then(null, ERROR);
+  },
+
+  exit: function() {
+    if (!this._customizing || this._transitioning) {
+      return;
+    }
+
+    CustomizableUI.removeListener(this);
+
+    this.document.removeEventListener("keypress", this);
+    this.window.PanelUI.menuButton.removeEventListener("mousedown", this);
+    this.window.PanelUI.menuButton.open = false;
+
+    this.window.PanelUI.beginBatchUpdate();
+
+    this._removePanelCustomizationPlaceholders();
+
+    this._transitioning = true;
+
+    let window = this.window;
+    let document = this.document;
+    let documentElement = document.documentElement;
+
+    Task.spawn(function() {
+      yield this.depopulatePalette();
+
+      yield this._doTransition(false);
+
+      let customizer = document.getElementById("customization-container");
+      customizer.hidden = true;
+      let browser = document.getElementById("browser");
+      browser.parentNode.selectedPanel = browser;
+
+      window.gNavToolbox.removeEventListener("toolbarvisibilitychange", this);
+
+      window.PanelUI.mainView.removeEventListener("contextmenu", this, true);
+      this.visiblePalette.removeEventListener("dragstart", this, true);
+      this.visiblePalette.removeEventListener("dragover", this, true);
+      this.visiblePalette.removeEventListener("dragexit", this, true);
+      this.visiblePalette.removeEventListener("drop", this, true);
+      this.visiblePalette.removeEventListener("dragend", this, true);
+
+      yield this._unwrapToolbarItems();
+
+      if (this._changed) {
+        // XXXmconley: At first, it seems strange to also persist the old way with
+        //             currentset - but this might actually be useful for switching
+        //             to old builds. We might want to keep this around for a little
+        //             bit.
+        this.persistCurrentSets();
+      }
+
+      // And drop all area references.
+      this.areas = [];
+
+      // Let everybody in this window know that we're starting to
+      // exit customization mode.
+      this.dispatchToolboxEvent("customizationending");
+
+      window.PanelUI.setMainView(window.PanelUI.mainView);
+      window.PanelUI.menuButton.disabled = false;
+
+      // We have to use setAttribute/removeAttribute here instead of the
+      // property because the XBL property will be set later, and right
+      // now we'd be setting an expando, which breaks the XBL property.
+      document.getElementById("PanelUI-help").removeAttribute("disabled");
+      document.getElementById("PanelUI-quit").removeAttribute("disabled");
+
+      // We need to set this._customizing to false before removing the tab
+      // or the TabSelect event handler will think that we are exiting
+      // customization mode for a second time.
+      this._customizing = false;
+
+      if (this.browser.selectedBrowser.currentURI.spec == kAboutURI) {
+        let custBrowser = this.browser.selectedBrowser;
+        if (custBrowser.canGoBack) {
+          // If there's history to this tab, just go back.
+          custBrowser.goBack();
+        } else {
+          // If we can't go back, we're removing the about:customization tab.
+          // We only do this if we're the top window for this window (so not
+          // a dialog window, for example).
+          if (window.getTopWin(true) == window) {
+            let customizationTab = this.browser.selectedTab;
+            if (this.browser.browsers.length == 1) {
+              window.BrowserOpenTab();
+            }
+            this.browser.removeTab(customizationTab);
+          }
+        }
+      }
+
+      if (this.document.documentElement._lightweightTheme)
+        this.document.documentElement._lightweightTheme.enable();
+
+      let customizableToolbars = document.querySelectorAll("toolbar[customizable=true]:not([autohide=true])");
+      for (let toolbar of customizableToolbars)
+        toolbar.removeAttribute("customizing");
+
+      this.window.PanelUI.endBatchUpdate();
+      this._changed = false;
+      this._transitioning = false;
+      this.dispatchToolboxEvent("aftercustomization");
+    }.bind(this)).then(null, ERROR);
+  },
+
+  /**
+   * The customize mode transition has 3 phases when entering:
+   * 1) Pre-customization mode
+   *    This is the starting phase of the browser.
+   * 2) customize-entering
+   *    This phase is a transition, optimized for smoothness.
+   * 3) customize-entered
+   *    After the transition completes, this phase draws all of the
+   *    expensive detail that isn't necessary during the second phase.
+   *
+   * Exiting customization mode has a similar set of phases, but in reverse
+   * order - customize-entered, customize-exiting, pre-customization mode.
+   *
+   * When in the customize-entering, customize-entered, or customize-exiting
+   * phases, there is a "customizing" attribute set on the main-window to simplify
+   * excluding certain styles while in any phase of customize mode.
+   */
+  _doTransition: function(aEntering) {
+    let deferred = Promise.defer();
+    let deck = this.document.getElementById("tab-view-deck");
+
+    let customizeTransitionEnd = function(aEvent) {
+      if (aEvent.originalTarget != deck || aEvent.propertyName != "padding-bottom") {
+        return;
+      }
+      deck.removeEventListener("transitionend", customizeTransitionEnd);
+
+      if (!aEntering) {
+        this.document.documentElement.removeAttribute("customize-exiting");
+        this.document.documentElement.removeAttribute("customizing");
+      } else {
+        this.document.documentElement.setAttribute("customize-entered", true);
+        this.document.documentElement.removeAttribute("customize-entering");
+      }
+      this.dispatchToolboxEvent("customization-transitionend", aEntering);
+
+      deferred.resolve();
+    }.bind(this);
+    deck.addEventListener("transitionend", customizeTransitionEnd);
+
+    if (gDisableAnimation) {
+      deck.setAttribute("fastcustomizeanimation", true);
+    }
+    if (aEntering) {
+      this.document.documentElement.setAttribute("customizing", true);
+      this.document.documentElement.setAttribute("customize-entering", true);
+    } else {
+      this.document.documentElement.setAttribute("customize-exiting", true);
+      this.document.documentElement.removeAttribute("customize-entered");
+    }
+    return deferred.promise;
+  },
+
+  dispatchToolboxEvent: function(aEventType, aDetails={}) {
+    let evt = this.document.createEvent("CustomEvent");
+    evt.initCustomEvent(aEventType, true, true, {changed: this._changed});
+    let result = this.window.gNavToolbox.dispatchEvent(evt);
+  },
+
+  addToToolbar: function(aNode) {
+    CustomizableUI.addWidgetToArea(aNode.id, CustomizableUI.AREA_NAVBAR);
+  },
+
+  removeFromPanel: function(aNode) {
+    CustomizableUI.removeWidgetFromArea(aNode.id);
+  },
+
+  populatePalette: function() {
+    let fragment = this.document.createDocumentFragment();
+    let toolboxPalette = this.window.gNavToolbox.palette;
+
+    return Task.spawn(function() {
+      let unusedWidgets = CustomizableUI.getUnusedWidgets(toolboxPalette);
+      for (let widget of unusedWidgets) {
+        let paletteItem = this.makePaletteItem(widget, "palette");
+        fragment.appendChild(paletteItem);
+      }
+
+      this.visiblePalette.appendChild(fragment);
+      this._stowedPalette = this.window.gNavToolbox.palette;
+      this.window.gNavToolbox.palette = this.visiblePalette;
+    }.bind(this)).then(null, ERROR);
+  },
+
+  //XXXunf Maybe this should use -moz-element instead of wrapping the node?
+  //       Would ensure no weird interactions/event handling from original node,
+  //       and makes it possible to put this in a lazy-loaded iframe/real tab
+  //       while still getting rid of the need for overlays.
+  makePaletteItem: function(aWidget, aPlace) {
+    let widgetNode = aWidget.forWindow(this.window).node;
+    let wrapper = this.createWrapper(widgetNode, aPlace);
+    wrapper.appendChild(widgetNode);
+    return wrapper;
+  },
+
+  depopulatePalette: function() {
+    return Task.spawn(function() {
+      this.visiblePalette.hidden = true;
+      let paletteChild = this.visiblePalette.firstChild;
+      let nextChild;
+      while (paletteChild) {
+        nextChild = paletteChild.nextElementSibling;
+        let provider = CustomizableUI.getWidget(paletteChild.id).provider;
+        if (provider == CustomizableUI.PROVIDER_XUL) {
+          let unwrappedPaletteItem =
+            yield this.deferredUnwrapToolbarItem(paletteChild);
+          this._stowedPalette.appendChild(unwrappedPaletteItem);
+        } else if (provider == CustomizableUI.PROVIDER_API) {
+          //XXXunf Currently this doesn't destroy the (now unused) node. It would
+          //       be good to do so, but we need to keep strong refs to it in
+          //       CustomizableUI (can't iterate of WeakMaps), and there's the
+          //       question of what behavior wrappers should have if consumers
+          //       keep hold of them.
+          //widget.destroyInstance(widgetNode);
+        } else if (provider == CustomizableUI.PROVIDER_SPECIAL) {
+          this.visiblePalette.removeChild(paletteChild);
+        }
+
+        paletteChild = nextChild;
+      }
+      this.visiblePalette.hidden = false;
+      this.window.gNavToolbox.palette = this._stowedPalette;
+    }.bind(this)).then(null, ERROR);
+  },
+
+  isCustomizableItem: function(aNode) {
+    return aNode.localName == "toolbarbutton" ||
+           aNode.localName == "toolbaritem" ||
+           aNode.localName == "toolbarseparator" ||
+           aNode.localName == "toolbarspring" ||
+           aNode.localName == "toolbarspacer";
+  },
+
+  isWrappedToolbarItem: function(aNode) {
+    return aNode.localName == "toolbarpaletteitem";
+  },
+
+  deferredWrapToolbarItem: function(aNode, aPlace) {
+    let deferred = Promise.defer();
+
+    dispatchFunction(function() {
+      let wrapper = this.wrapToolbarItem(aNode, aPlace);
+      deferred.resolve(wrapper);
+    }.bind(this))
+
+    return deferred.promise;
+  },
+
+  wrapToolbarItem: function(aNode, aPlace) {
+    if (!this.isCustomizableItem(aNode)) {
+      return aNode;
+    }
+    let wrapper = this.createWrapper(aNode, aPlace);
+    // It's possible that this toolbar node is "mid-flight" and doesn't have
+    // a parent, in which case we skip replacing it. This can happen if a
+    // toolbar item has been dragged into the palette. In that case, we tell
+    // CustomizableUI to remove the widget from its area before putting the
+    // widget in the palette - so the node will have no parent.
+    if (aNode.parentNode) {
+      aNode = aNode.parentNode.replaceChild(wrapper, aNode);
+    }
+    wrapper.appendChild(aNode);
+    return wrapper;
+  },
+
+  createWrapper: function(aNode, aPlace) {
+    let wrapper = this.document.createElement("toolbarpaletteitem");
+
+    // "place" is used by toolkit to add the toolbarpaletteitem-palette
+    // binding to a toolbarpaletteitem, which gives it a label node for when
+    // it's sitting in the palette.
+    wrapper.setAttribute("place", aPlace);
+
+    // Ensure the wrapped item doesn't look like it's in any special state, and
+    // can't be interactved with when in the customization palette.
+    if (aNode.hasAttribute("command")) {
+      wrapper.setAttribute("itemcommand", aNode.getAttribute("command"));
+      aNode.removeAttribute("command");
+    }
+
+    if (aNode.checked) {
+      wrapper.setAttribute("itemchecked", "true");
+      aNode.checked = false;
+    }
+
+    if (aNode.hasAttribute("id")) {
+      wrapper.setAttribute("id", "wrapper-" + aNode.getAttribute("id"));
+    }
+
+    if (aNode.hasAttribute("title")) {
+      wrapper.setAttribute("title", aNode.getAttribute("title"));
+    } else if (aNode.hasAttribute("label")) {
+      wrapper.setAttribute("title", aNode.getAttribute("label"));
+    }
+
+    if (aNode.hasAttribute("flex")) {
+      wrapper.setAttribute("flex", aNode.getAttribute("flex"));
+    }
+
+    wrapper.addEventListener("mousedown", this);
+    wrapper.addEventListener("mouseup", this);
+
+    return wrapper;
+  },
+
+  deferredUnwrapToolbarItem: function(aWrapper) {
+    let deferred = Promise.defer();
+    dispatchFunction(function() {
+      deferred.resolve(this.unwrapToolbarItem(aWrapper));
+    }.bind(this));
+    return deferred.promise;
+  },
+
+  unwrapToolbarItem: function(aWrapper) {
+    if (aWrapper.nodeName != "toolbarpaletteitem") {
+      return aWrapper;
+    }
+    aWrapper.removeEventListener("mousedown", this);
+    aWrapper.removeEventListener("mouseup", this);
+
+    let toolbarItem = aWrapper.firstChild;
+    if (!toolbarItem) {
+      ERROR("no toolbarItem child for " + aWrapper.tagName + "#" + aWrapper.id);
+    }
+
+    if (aWrapper.hasAttribute("itemchecked")) {
+      toolbarItem.checked = true;
+    }
+
+    if (aWrapper.hasAttribute("itemcommand")) {
+      let commandID = aWrapper.getAttribute("itemcommand");
+      toolbarItem.setAttribute("command", commandID);
+
+      //XXX Bug 309953 - toolbarbuttons aren't in sync with their commands after customizing
+      let command = this.document.getElementById(commandID);
+      if (command && command.hasAttribute("disabled")) {
+        toolbarItem.setAttribute("disabled", command.getAttribute("disabled"));
+      }
+    }
+
+    if (aWrapper.parentNode) {
+      aWrapper.parentNode.replaceChild(toolbarItem, aWrapper);
+    }
+    return toolbarItem;
+  },
+
+  _wrapToolbarItems: function() {
+    let window = this.window;
+    // Add drag-and-drop event handlers to all of the customizable areas.
+    return Task.spawn(function() {
+      this.areas = [];
+      for (let area of CustomizableUI.areas) {
+        let target = CustomizableUI.getCustomizeTargetForArea(area, window);
+        target.addEventListener("dragstart", this, true);
+        target.addEventListener("dragover", this, true);
+        target.addEventListener("dragexit", this, true);
+        target.addEventListener("drop", this, true);
+        target.addEventListener("dragend", this, true);
+        for (let child of target.children) {
+          if (this.isCustomizableItem(child)) {
+            yield this.deferredWrapToolbarItem(child, getPlaceForItem(child));
+          }
+        }
+        this.areas.push(target);
+      }
+    }.bind(this)).then(null, ERROR);
+  },
+
+  _wrapItemsInArea: function(target) {
+    for (let child of target.children) {
+      if (this.isCustomizableItem(child)) {
+        this.wrapToolbarItem(child, getPlaceForItem(child));
+      }
+    }
+  },
+
+  _unwrapItemsInArea: function(target) {
+    for (let toolbarItem of target.children) {
+      if (this.isWrappedToolbarItem(toolbarItem)) {
+        this.unwrapToolbarItem(toolbarItem);
+      }
+    }
+  },
+
+  _unwrapToolbarItems: function() {
+    return Task.spawn(function() {
+      for (let target of this.areas) {
+        for (let toolbarItem of target.children) {
+          if (this.isWrappedToolbarItem(toolbarItem)) {
+            yield this.deferredUnwrapToolbarItem(toolbarItem);
+          }
+        }
+        target.removeEventListener("dragstart", this, true);
+        target.removeEventListener("dragover", this, true);
+        target.removeEventListener("dragexit", this, true);
+        target.removeEventListener("drop", this, true);
+        target.removeEventListener("dragend", this, true);
+      }
+    }.bind(this)).then(null, ERROR);
+  },
+
+  persistCurrentSets: function(aSetBeforePersisting)  {
+    let document = this.document;
+    let toolbars = document.querySelectorAll("toolbar[customizable='true'][currentset]");
+    for (let toolbar of toolbars) {
+      if (aSetBeforePersisting) {
+        let set = toolbar.currentSet;
+        toolbar.setAttribute("currentset", set);
+      }
+      // Persist the currentset attribute directly on hardcoded toolbars.
+      document.persist(toolbar.id, "currentset");
+    }
+  },
+
+  reset: function() {
+    this.resetting = true;
+    return Task.spawn(function() {
+      this._removePanelCustomizationPlaceholders();
+      yield this.depopulatePalette();
+      yield this._unwrapToolbarItems();
+
+      CustomizableUI.reset();
+
+      yield this._wrapToolbarItems();
+      yield this.populatePalette();
+
+      this.persistCurrentSets(true);
+
+      this._updateResetButton();
+      this._showPanelCustomizationPlaceholders();
+      this.resetting = false;
+    }.bind(this)).then(null, ERROR);
+  },
+
+  _onToolbarVisibilityChange: function(aEvent) {
+    let toolbar = aEvent.target;
+    if (aEvent.detail.visible) {
+      toolbar.setAttribute("customizing", "true");
+    } else {
+      toolbar.removeAttribute("customizing");
+    }
+  },
+
+  onWidgetMoved: function(aWidgetId, aArea, aOldPosition, aNewPosition) {
+    this._onUIChange();
+  },
+
+  onWidgetAdded: function(aWidgetId, aArea, aPosition) {
+    this._onUIChange();
+  },
+
+  onWidgetRemoved: function(aWidgetId, aArea) {
+    this._onUIChange();
+  },
+
+  onWidgetBeforeDOMChange: function(aNodeToChange, aSecondaryNode, aContainer) {
+    if (aContainer.ownerDocument.defaultView != this.window || this.resetting) {
+      return;
+    }
+    if (aContainer.id == CustomizableUI.AREA_PANEL) {
+      this._removePanelCustomizationPlaceholders();
+    }
+    // If we get called for widgets that aren't in the window yet, they might not have
+    // a parentNode at all.
+    if (aNodeToChange.parentNode) {
+      this.unwrapToolbarItem(aNodeToChange.parentNode);
+    }
+    if (aSecondaryNode) {
+      this.unwrapToolbarItem(aSecondaryNode.parentNode);
+    }
+  },
+
+  onWidgetAfterDOMChange: function(aNodeToChange, aSecondaryNode, aContainer) {
+    if (aContainer.ownerDocument.defaultView != this.window || this.resetting) {
+      return;
+    }
+    // If the node is still attached to the container, wrap it again:
+    if (aNodeToChange.parentNode) {
+      let place = getPlaceForItem(aNodeToChange);
+      this.wrapToolbarItem(aNodeToChange, place);
+      if (aSecondaryNode) {
+        this.wrapToolbarItem(aSecondaryNode, place);
+      }
+    } else {
+      // If not, it got removed.
+
+      // If an API-based widget is removed while customizing, append it to the palette.
+      // The _applyDrop code itself will take care of positioning it correctly, if
+      // applicable. We need the code to be here so removing widgets using CustomizableUI's
+      // API also does the right thing (and adds it to the palette)
+      let widgetId = aNodeToChange.id;
+      let widget = CustomizableUI.getWidget(widgetId);
+      if (widget.provider == CustomizableUI.PROVIDER_API) {
+        let paletteItem = this.makePaletteItem(widget, "palette");
+        this.visiblePalette.appendChild(paletteItem);
+      }
+    }
+    if (aContainer.id == CustomizableUI.AREA_PANEL) {
+      this._showPanelCustomizationPlaceholders();
+    }
+  },
+
+  onWidgetDestroyed: function(aWidgetId) {
+    let wrapper = this.document.getElementById("wrapper-" + aWidgetId);
+    if (wrapper) {
+      let wasInPanel = wrapper.parentNode == this.panelUIContents;
+      wrapper.remove();
+      if (wasInPanel) {
+        this._showPanelCustomizationPlaceholders();
+      }
+    }
+  },
+
+  onWidgetAfterCreation: function(aWidgetId, aArea) {
+    // If the node was added to an area, we would have gotten an onWidgetAdded notification,
+    // plus associated DOM change notifications, so only do stuff for the palette:
+    if (!aArea) {
+      let widgetNode = this.document.getElementById(aWidgetId);
+      if (widgetNode) {
+        this.wrapToolbarItem(widgetNode, "palette");
+      } else {
+        let widget = CustomizableUI.getWidget(aWidgetId);
+        this.visiblePalette.appendChild(this.makePaletteItem(widget, "palette"));
+      }
+    }
+  },
+
+  _onUIChange: function() {
+    this._changed = true;
+    this._updateResetButton();
+    this.dispatchToolboxEvent("customizationchange");
+  },
+
+  _updateResetButton: function() {
+    let btn = this.document.getElementById("customization-reset-button");
+    btn.disabled = CustomizableUI.inDefaultState;
+  },
+
+  handleEvent: function(aEvent) {
+    switch(aEvent.type) {
+      case "toolbarvisibilitychange":
+        this._onToolbarVisibilityChange(aEvent);
+        break;
+      case "contextmenu":
+        aEvent.preventDefault();
+        aEvent.stopPropagation();
+        break;
+      case "dragstart":
+        this._onDragStart(aEvent);
+        break;
+      case "dragover":
+        this._onDragOver(aEvent);
+        break;
+      case "drop":
+        this._onDragDrop(aEvent);
+        break;
+      case "dragexit":
+        this._onDragExit(aEvent);
+        break;
+      case "dragend":
+        this._onDragEnd(aEvent);
+        break;
+      case "mousedown":
+        if (aEvent.button == 0 &&
+            (aEvent.originalTarget == this.window.PanelUI.menuButton)) {
+          this.exit();
+          aEvent.preventDefault();
+          return;
+        }
+        this._onMouseDown(aEvent);
+        break;
+      case "mouseup":
+        this._onMouseUp(aEvent);
+        break;
+      case "keypress":
+        if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) {
+          this.exit();
+        }
+        break;
+    }
+  },
+
+  _onDragStart: function(aEvent) {
+    __dumpDragData(aEvent);
+    let item = aEvent.target;
+    while (item && item.localName != "toolbarpaletteitem") {
+      if (item.localName == "toolbar" ||
+          item.classList.contains(kPlaceholderClass)) {
+        return;
+      }
+      item = item.parentNode;
+    }
+
+    let dt = aEvent.dataTransfer;
+    let documentId = aEvent.target.ownerDocument.documentElement.id;
+    let draggedItem = item.firstChild;
+
+    dt.mozSetDataAt(kDragDataTypePrefix + documentId, draggedItem.id, 0);
+    dt.effectAllowed = "move";
+
+    let itemRect = draggedItem.getBoundingClientRect();
+    let itemCenter = {x: itemRect.left + itemRect.width / 2,
+                      y: itemRect.top + itemRect.height / 2};
+    this._dragOffset = {x: aEvent.clientX - itemCenter.x,
+                        y: aEvent.clientY - itemCenter.y};
+
+    // Hack needed so that the dragimage will still show the
+    // item as it appeared before it was hidden.
+    let win = aEvent.target.ownerDocument.defaultView;
+    win.setTimeout(function() {
+      // For automated tests, we sometimes start exiting customization mode
+      // before this fires, which leaves us with placeholders inserted after
+      // we've exited. So we need to check that we are indeed customizing.
+      if (this._customizing && !this._transitioning) {
+        item.hidden = true;
+        this._showPanelCustomizationPlaceholders();
+      }
+    }.bind(this), 0);
+  },
+
+  _onDragOver: function(aEvent) {
+    if (this._isUnwantedDragDrop(aEvent)) {
+      return;
+    }
+
+    __dumpDragData(aEvent);
+
+    let document = aEvent.target.ownerDocument;
+    let documentId = document.documentElement.id;
+    if (!aEvent.dataTransfer.mozTypesAt(0)) {
+      return;
+    }
+
+    let draggedItemId =
+      aEvent.dataTransfer.mozGetDataAt(kDragDataTypePrefix + documentId, 0);
+    let draggedWrapper = document.getElementById("wrapper-" + draggedItemId);
+    let targetArea = this._getCustomizableParent(aEvent.currentTarget);
+    let originArea = this._getCustomizableParent(draggedWrapper);
+
+    // Do nothing if the target or origin are not customizable.
+    if (!targetArea || !originArea) {
+      return;
+    }
+
+    // Do nothing if the widget is not allowed to be removed.
+    if (targetArea.id == kPaletteId &&
+       !CustomizableUI.isWidgetRemovable(draggedItemId)) {
+      return;
+    }
+
+    // Do nothing if the widget is not allowed to move to the target area.
+    if (targetArea.id != kPaletteId &&
+        !CustomizableUI.canWidgetMoveToArea(draggedItemId, targetArea.id)) {
+      return;
+    }
+
+    let targetNode = this._getDragOverNode(aEvent, targetArea);
+
+    // We need to determine the place that the widget is being dropped in
+    // the target.
+    let dragOverItem, dragValue;
+    if (targetNode == targetArea.customizationTarget) {
+      // We'll assume if the user is dragging directly over the target, that
+      // they're attempting to append a child to that target.
+      dragOverItem = targetNode.lastChild || targetNode;
+      dragValue = "after";
+    } else {
+      let targetParent = targetNode.parentNode;
+      let position = Array.indexOf(targetParent.children, targetNode);
+      if (position == -1) {
+        dragOverItem = targetParent.lastChild;
+        dragValue = "after";
+      } else {
+        dragOverItem = targetParent.children[position];
+        // Check if the aDraggedItem is hovered past the first half of dragOverItem
+        let window = dragOverItem.ownerDocument.defaultView;
+        let direction = window.getComputedStyle(dragOverItem, null).direction;
+        let itemRect = dragOverItem.getBoundingClientRect();
+        let dropTargetCenter = itemRect.left + (itemRect.width / 2);
+        if (targetParent == window.PanelUI.contents) {
+          dragValue = "true";
+          if (direction == "ltr" && aEvent.clientX > dropTargetCenter) {
+            position++;
+          } else if (direction == "rtl" && aEvent.clientX < dropTargetCenter) {
+            position--;
+          }
+          dragOverItem = position == -1 ? targetParent.firstChild : targetParent.children[position];
+        } else {
+          let existingDir = dragOverItem.getAttribute("dragover");
+          if ((existingDir == "before") == (direction == "ltr")) {
+            dropTargetCenter += (parseInt(dragOverItem.style.borderLeftWidth) || 0) / 2;
+          } else {
+            dropTargetCenter -= (parseInt(dragOverItem.style.borderRightWidth) || 0) / 2;
+          }
+          let before = direction == "ltr" ? aEvent.clientX < dropTargetCenter : aEvent.clientX > dropTargetCenter;
+          dragValue = before ? "before" : "after";
+        }
+      }
+    }
+
+    if (this._dragOverItem && dragOverItem != this._dragOverItem) {
+      this._setDragActive(this._dragOverItem, false);
+    }
+
+    if (dragOverItem != this._dragOverItem || dragValue != dragOverItem.getAttribute("dragover")) {
+      if (dragOverItem != targetArea.customizationTarget) {
+        this._setDragActive(dragOverItem, dragValue, draggedItemId);
+      }
+      this._dragOverItem = dragOverItem;
+    }
+
+    aEvent.preventDefault();
+    aEvent.stopPropagation();
+  },
+
+  _onDragDrop: function(aEvent) {
+    if (this._isUnwantedDragDrop(aEvent)) {
+      return;
+    }
+
+    __dumpDragData(aEvent);
+
+    let targetArea = this._getCustomizableParent(aEvent.currentTarget);
+    let document = aEvent.target.ownerDocument;
+    let documentId = document.documentElement.id;
+    let draggedItemId =
+      aEvent.dataTransfer.mozGetDataAt(kDragDataTypePrefix + documentId, 0);
+    let draggedWrapper = document.getElementById("wrapper-" + draggedItemId);
+    let originArea = this._getCustomizableParent(draggedWrapper);
+    if (this._dragWidthMap) {
+      this._dragWidthMap.clear();
+    }
+    // Do nothing if the target area or origin area are not customizable.
+    if (!targetArea || !originArea) {
+      return;
+    }
+    let targetNode = this._dragOverItem;
+    let dropDir = targetNode.getAttribute("dragover");
+    // Need to insert *after* this node if we promised the user that:
+    if (targetNode != targetArea && dropDir == "after") {
+      if (targetNode.nextSibling) {
+        targetNode = targetNode.nextSibling;
+      } else {
+        targetNode = targetArea;
+      }
+    }
+    // If the target node is a placeholder, get its sibling as the real target.
+    while (targetNode.classList.contains(kPlaceholderClass) && targetNode.nextSibling) {
+      targetNode = targetNode.nextSibling;
+    }
+    if (targetNode.tagName == "toolbarpaletteitem") {
+      targetNode = targetNode.firstChild;
+    }
+
+    this._setDragActive(this._dragOverItem, false);
+    this._removePanelCustomizationPlaceholders();
+
+    try {
+      this._applyDrop(aEvent, targetArea, originArea, draggedItemId, targetNode);
+    } catch (ex) {
+      ERROR(ex, ex.stack);
+    }
+
+    this._showPanelCustomizationPlaceholders();
+  },
+
+  _applyDrop: function(aEvent, aTargetArea, aOriginArea, aDraggedItemId, aTargetNode) {
+    let document = aEvent.target.ownerDocument;
+    let draggedItem = document.getElementById(aDraggedItemId);
+    draggedItem.hidden = false;
+    draggedItem.removeAttribute("mousedown");
+
+    // Do nothing if the target was dropped onto itself (ie, no change in area
+    // or position).
+    if (draggedItem == aTargetNode) {
+      return;
+    }
+
+    // Is the target area the customization palette?
+    if (aTargetArea.id == kPaletteId) {
+      // Did we drag from outside the palette?
+      if (aOriginArea.id !== kPaletteId) {
+        if (!CustomizableUI.isWidgetRemovable(aDraggedItemId)) {
+          return;
+        }
+
+        CustomizableUI.removeWidgetFromArea(aDraggedItemId);
+      }
+      draggedItem = draggedItem.parentNode;
+
+      // If the target node is the palette itself, just append
+      if (aTargetNode == this.visiblePalette) {
+        this.visiblePalette.appendChild(draggedItem);
+      } else {
+        // The items in the palette are wrapped, so we need the target node's parent here:
+        this.visiblePalette.insertBefore(draggedItem, aTargetNode.parentNode);
+      }
+      return;
+    }
+
+    if (!CustomizableUI.canWidgetMoveToArea(aDraggedItemId, aTargetArea.id)) {
+      return;
+    }
+
+    // Skipintoolbarset items won't really be moved:
+    if (draggedItem.getAttribute("skipintoolbarset") == "true") {
+      // These items should never leave their area:
+      if (aTargetArea != aOriginArea) {
+        return;
+      }
+      let place = draggedItem.parentNode.getAttribute("place");
+      this.unwrapToolbarItem(draggedItem.parentNode);
+      if (aTargetNode == aTargetArea.customizationTarget) {
+        aTargetArea.customizationTarget.appendChild(draggedItem);
+      } else {
+        this.unwrapToolbarItem(aTargetNode.parentNode);
+        aTargetArea.customizationTarget.insertBefore(draggedItem, aTargetNode);
+        this.wrapToolbarItem(aTargetNode, place);
+      }
+      this.wrapToolbarItem(draggedItem, place);
+      return;
+    }
+
+    // Is the target the customization area itself? If so, we just add the
+    // widget to the end of the area.
+    if (aTargetNode == aTargetArea.customizationTarget) {
+      CustomizableUI.addWidgetToArea(aDraggedItemId, aTargetArea.id);
+      return;
+    }
+
+    // We need to determine the place that the widget is being dropped in
+    // the target.
+    let placement;
+    let itemForPlacement = aTargetNode;
+    // Skip the skipintoolbarset items when determining the place of the item:
+    while (itemForPlacement && itemForPlacement.getAttribute("skipintoolbarset") == "true" &&
+           itemForPlacement.parentNode &&
+           itemForPlacement.parentNode.nodeName == "toolbarpaletteitem") {
+      itemForPlacement = itemForPlacement.parentNode.nextSibling;
+      if (itemForPlacement && itemForPlacement.nodeName == "toolbarpaletteitem") {
+        itemForPlacement = itemForPlacement.firstChild;
+      }
+    }
+    if (itemForPlacement && !itemForPlacement.classList.contains(kPlaceholderClass)) {
+      let targetNodeId = (itemForPlacement.nodeName == "toolbarpaletteitem") ?
+                            itemForPlacement.firstChild && itemForPlacement.firstChild.id :
+                            itemForPlacement.id;
+      placement = CustomizableUI.getPlacementOfWidget(targetNodeId);
+    }
+    if (!placement) {
+      LOG("Could not get a position for " + aTargetNode.nodeName + "#" + aTargetNode.id + "." + aTargetNode.className);
+    }
+    let position = placement ? placement.position : null;
+
+
+    // Is the target area the same as the origin? Since we've already handled
+    // the possibility that the target is the customization palette, we know
+    // that the widget is moving within a customizable area.
+    if (aTargetArea == aOriginArea) {
+      CustomizableUI.moveWidgetWithinArea(aDraggedItemId, position);
+    } else {
+      CustomizableUI.addWidgetToArea(aDraggedItemId, aTargetArea.id, position);
+    }
+    // If we dropped onto a skipintoolbarset item, manually correct the drop location:
+    if (aTargetNode != itemForPlacement) {
+      let draggedWrapper = draggedItem.parentNode;
+      let container = draggedWrapper.parentNode;
+      container.insertBefore(draggedWrapper, aTargetNode.parentNode);
+    }
+  },
+
+  _onDragExit: function(aEvent) {
+    if (this._isUnwantedDragDrop(aEvent)) {
+      return;
+    }
+
+    __dumpDragData(aEvent);
+
+    if (this._dragOverItem) {
+      this._setDragActive(this._dragOverItem, false);
+    }
+  },
+
+  _onDragEnd: function(aEvent) {
+    if (this._isUnwantedDragDrop(aEvent)) {
+      return;
+    }
+
+    __dumpDragData(aEvent);
+    let document = aEvent.target.ownerDocument;
+    document.documentElement.removeAttribute("customizing-movingItem");
+
+    let documentId = document.documentElement.id;
+    if (!aEvent.dataTransfer.mozTypesAt(0)) {
+      return;
+    }
+
+    let draggedItemId =
+      aEvent.dataTransfer.mozGetDataAt(kDragDataTypePrefix + documentId, 0);
+
+    let draggedWrapper = document.getElementById("wrapper-" + draggedItemId);
+    draggedWrapper.hidden = false;
+    draggedWrapper.removeAttribute("mousedown");
+    this._showPanelCustomizationPlaceholders();
+  },
+
+  _isUnwantedDragDrop: function(aEvent) {
+    // The simulated events generated by synthesizeDragStart/synthesizeDrop in
+    // mochitests are used only for testing whether the right data is being put
+    // into the dataTransfer. Neither cause a real drop to occur, so they don't
+    // set the source node. There isn't a means of testing real drag and drops,
+    // so this pref skips the check but it should only be set by test code.
+    if (this._skipSourceNodeCheck) {
+      return false;
+    }
+
+    /* Discard drag events that originated from a separate window to
+       prevent content->chrome privilege escalations. */
+    let mozSourceNode = aEvent.dataTransfer.mozSourceNode;
+    // mozSourceNode is null in the dragStart event handler or if
+    // the drag event originated in an external application.
+    return !mozSourceNode ||
+           mozSourceNode.ownerDocument.defaultView != this.window;
+  },
+
+  _setDragActive: function(aItem, aValue, aDraggedItemId) {
+    if (!aItem) {
+      return;
+    }
+
+    if (aValue) {
+      if (aItem.hasAttribute("dragover") != aValue) {
+        aItem.setAttribute("dragover", aValue);
+
+        // Calculate width of the item when it'd be dropped in this position
+        let window = aItem.ownerDocument.defaultView;
+        let draggedItem = window.document.getElementById(aDraggedItemId);
+        let width = this._getDragItemWidth(aItem, draggedItem);
+        if (width) {
+          let panelContents = window.PanelUI.contents;
+          if (aItem.parentNode == panelContents) {
+            this._setPanelDragActive(aItem, draggedItem, width);
+          } else {
+            let direction = window.getComputedStyle(aItem).direction;
+            let prop, otherProp;
+            // If we're inserting before in ltr, or after in rtl:
+            if ((aValue == "before") == (direction == "ltr")) {
+              prop = "borderLeftWidth";
+              otherProp = "border-right-width";
+            } else {
+              // otherwise:
+              prop = "borderRightWidth";
+              otherProp = "border-left-width";
+            }
+            aItem.style[prop] = width;
+            aItem.style.removeProperty(otherProp);
+          }
+        }
+      }
+    } else {
+      aItem.removeAttribute("dragover");
+      // Remove both property values in the case that the end padding
+      // had been set.
+      aItem.style.removeProperty("border-left-width");
+      aItem.style.removeProperty("border-right-width");
+    }
+  },
+
+  _setPanelDragActive: function(aDragOverNode, aDraggedItem, aWidth) {
+    let document = aDragOverNode.ownerDocument;
+    let window = document.defaultView;
+    let panelContents = window.PanelUI.contents;
+    while (!aDragOverNode.id && aDragOverNode.parentNode != panelContents)
+        aDragOverNode = aDragOverNode.parentNode;
+    if (!aDragOverNode.id)
+      return;
+
+    if (!aDragOverNode.previousSibling ||
+        !aDragOverNode.previousSibling.classList.contains(kPlaceholderClass)) {
+      let isPlaceholderAtEnd = function(aPlaceholder) {
+        do {
+          aPlaceholder = aPlaceholder.nextSibling;
+          if (!aPlaceholder)
+            return true;
+          if (!aPlaceholder.classList.contains(kPlaceholderClass))
+            return false;
+        } while (aPlaceholder.nextSibling)
+        return true;
+      }
+
+      let resetAnimAttributes = function(aPlaceholder) {
+        if (!aPlaceholder)
+          return;
+        aPlaceholder.removeAttribute("expand");
+        aPlaceholder.removeAttribute("contract");
+        aPlaceholder.removeAttribute("hidden");
+        aPlaceholder.style.removeProperty("width");
+      }
+
+      let placeholders = Array.slice(panelContents.getElementsByClassName(kPlaceholderClass));
+
+      let toExpand = placeholders.shift();
+      let toContract = placeholders.shift();
+      if (toContract && isPlaceholderAtEnd(toContract))
+        toContract = null;
+      // Seek to find hidden placeholders first to use for the expand transition.
+      while (toExpand.getAttribute("hidden") != "true" && placeholders.length)
+        toExpand = placeholders.shift();
+
+      if (toExpand.transitioning || (toContract && toContract.transitioning))
+        return;
+
+      let wasHidden = (toContract && toContract.getAttribute("hidden") == "true") ||
+                      toExpand.getAttribute("hidden") == "true";
+      resetAnimAttributes(toContract);
+      resetAnimAttributes(toExpand);
+
+      aDragOverNode.parentNode.insertBefore(toExpand, aDragOverNode);
+      toExpand.style.width = "0px";
+      toExpand.setAttribute("expand", "true");
+      toExpand.transitioning = true;
+      if (toContract) {
+        toContract.style.width = aWidth;
+        toContract.setAttribute("contract", "true");
+        toContract.transitioning = true;
+      }
+
+      window.mozRequestAnimationFrame(() => {
+        if (toContract)
+          toContract.style.width = "0px";
+        toExpand.style.width = aWidth;
+      });
+      toExpand.addEventListener("transitionend", function expandTransitionEnd() {
+        toExpand.removeEventListener("transitionend", expandTransitionEnd, false);
+        toExpand.transitioning = false;
+      });
+      if (toContract) {
+        toContract.addEventListener("transitionend", function contractTransitionEnd() {
+          toContract.removeEventListener("transitionend", contractTransitionEnd, false);
+          panelContents.appendChild(toContract);
+          if (wasHidden)
+            toContract.setAttribute("hidden", "true");
+          toContract.transitioning = false;
+        });
+      }
+    }
+  },
+
+  _getDragItemWidth: function(aDragOverNode, aDraggedItem) {
+    // Cache it good, cache it real good.
+    if (!this._dragWidthMap)
+      this._dragWidthMap = new WeakMap();
+    if (!this._dragWidthMap.has(aDraggedItem))
+      this._dragWidthMap.set(aDraggedItem, new WeakMap());
+    let itemMap = this._dragWidthMap.get(aDraggedItem);
+    let targetArea = this._getCustomizableParent(aDragOverNode);
+    if (!targetArea)
+      return;
+    // Return the width for this target from cache, if it exists.
+    let width = itemMap.get(targetArea);
+    if (width)
+      return width;
+
+    // Calculate width of the item when it'd be dropped in this position.
+    let currentParent = aDraggedItem.parentNode;
+    let currentSibling = aDraggedItem.nextSibling;
+
+    // Move the widget temporarily next to the placeholder.
+    aDragOverNode.parentNode.insertBefore(aDraggedItem, aDragOverNode);
+    // Update the node's areaType.
+    let areaType = CustomizableUI.getAreaType(targetArea.id);
+    const kAreaType = "cui-areatype";
+    let currentType = aDraggedItem.hasAttribute(kAreaType) &&
+                      aDraggedItem.getAttribute(kAreaType);
+    if (areaType)
+      aDraggedItem.setAttribute(kAreaType, areaType);
+    CustomizableUI.onWidgetDrag(aDraggedItem.id, targetArea.id);
+    // Fetch the new width.
+    width = Math.floor(aDraggedItem.getBoundingClientRect().width) + "px";
+    // Put the item back into its previous position.
+    if (currentSibling)
+      currentParent.insertBefore(aDraggedItem, currentSibling);
+    else
+      currentParent.appendChild(aDraggedItem);
+    // restore the areaType
+    if (areaType) {
+      if (currentType === false)
+        aDraggedItem.removeAttribute(kAreaType);
+      else
+        aDraggedItem.setAttribute(kAreaType, currentType);
+    }
+    CustomizableUI.onWidgetDrag(aDraggedItem.id);
+    // Cache the found value of width for this target.
+    itemMap.set(targetArea, width);
+    return width;
+  },
+
+  _getCustomizableParent: function(aElement) {
+    let areas = CustomizableUI.areas;
+    areas.push(kPaletteId);
+    while (aElement) {
+      if (areas.indexOf(aElement.id) != -1) {
+        return aElement;
+      }
+      aElement = aElement.parentNode;
+    }
+    return null;
+  },
+
+  _getDragOverNode: function(aEvent, aAreaElement) {
+    let expectedParent = aAreaElement.customizationTarget || aAreaElement;
+    // Our tests are stupid. Cope:
+    if (!aEvent.clientX  && !aEvent.clientY) {
+      return aEvent.target;
+    }
+    // Offset the drag event's position with the offset to the center of
+    // the thing we're dragging
+    let dragX = aEvent.clientX - this._dragOffset.x;
+    let dragY = aEvent.clientY - this._dragOffset.y;
+
+    // Ensure this is within the container
+    let bounds = expectedParent.getBoundingClientRect();
+    dragX = Math.min(bounds.right, Math.max(dragX, bounds.left));
+    dragY = Math.min(bounds.bottom, Math.max(dragY, bounds.top));
+
+    let targetNode = aAreaElement.ownerDocument.elementFromPoint(dragX, dragY);
+    while (targetNode && targetNode.parentNode != expectedParent) {
+      targetNode = targetNode.parentNode;
+    }
+    return targetNode || aEvent.target;
+  },
+
+  _onMouseDown: function(aEvent) {
+    LOG("_onMouseDown");
+    let doc = aEvent.target.ownerDocument;
+    doc.documentElement.setAttribute("customizing-movingItem", true);
+    let item = this._getWrapper(aEvent.target);
+    if (item) {
+      item.setAttribute("mousedown", "true");
+    }
+  },
+
+  _onMouseUp: function(aEvent) {
+    LOG("_onMouseUp");
+    let doc = aEvent.target.ownerDocument;
+    doc.documentElement.removeAttribute("customizing-movingItem");
+    let item = this._getWrapper(aEvent.target);
+    if (item) {
+      item.removeAttribute("mousedown");
+    }
+  },
+
+  _getWrapper: function(aElement) {
+    while (aElement && aElement.localName != "toolbarpaletteitem") {
+      if (aElement.localName == "toolbar")
+        return null;
+      aElement = aElement.parentNode;
+    }
+    return aElement;
+  },
+
+  _showPanelCustomizationPlaceholders: function() {
+    this._removePanelCustomizationPlaceholders();
+    let doc = this.document;
+    let contents = this.panelUIContents;
+    let visibleWideItems = contents.querySelectorAll("toolbarpaletteitem:not([hidden]) > ." + kWidePanelItemClass);
+    let visibleChildren = contents.querySelectorAll("toolbarpaletteitem:not([hidden])");
+    // TODO(bug 885578): Still doesn't handle a hole when there is a wide
+    //                   widget located at the bottom of the panel.
+    let narrowItemsAfterWideItem = 0;
+    let node = contents.lastChild;
+    while (node && !node.classList.contains(kWidePanelItemClass) &&
+           (!node.firstChild || !node.firstChild.classList.contains(kWidePanelItemClass))) {
+      if (!node.hidden) {
+        narrowItemsAfterWideItem++;
+      }
+      node = node.previousSibling;
+    }
+
+    let orphanedItems = narrowItemsAfterWideItem % kColumnsInMenuPanel;
+    let placeholders = kColumnsInMenuPanel - orphanedItems;
+
+    while (placeholders--) {
+      let placeholder = doc.createElement("toolbarpaletteitem");
+      placeholder.classList.add(kPlaceholderClass);
+      //XXXjaws The toolbarbutton child here is only necessary to get
+      //  the styling right here.
+      let placeholderChild = doc.createElement("toolbarbutton");
+      placeholderChild.classList.add(kPlaceholderClass + "-child");
+      placeholder.appendChild(placeholderChild);
+      contents.appendChild(placeholder);
+    }
+  },
+
+  _removePanelCustomizationPlaceholders: function() {
+    let contents = this.panelUIContents;
+    let oldPlaceholders = contents.getElementsByClassName(kPlaceholderClass);
+    while (oldPlaceholders.length) {
+      contents.removeChild(oldPlaceholders[0]);
+    }
+  }
+};
+
+function getPlaceForItem(aElement) {
+  let place;
+  let node = aElement;
+  while (node && !place) {
+    if (node.localName == "toolbar")
+      place = "toolbar";
+    else if (node.id == CustomizableUI.AREA_PANEL)
+      place = "panel";
+    else if (node.id == kPaletteId)
+      place = "palette";
+
+    node = node.parentNode;
+  }
+  return place;
+}
+
+function __dumpDragData(aEvent, caller) {
+  let str = "Dumping drag data (CustomizeMode.jsm) {\n";
+  str += "  type: " + aEvent["type"] + "\n";
+  for (let el of ["target", "currentTarget", "relatedTarget"]) {
+    if (aEvent[el]) {
+      str += "  " + el + ": " + aEvent[el] + "(localName=" + aEvent[el].localName + "; id=" + aEvent[el].id + ")\n";
+    }
+  }
+  for (let prop in aEvent.dataTransfer) {
+    if (typeof aEvent.dataTransfer[prop] != "function") {
+      str += "  dataTransfer[" + prop + "]: " + aEvent.dataTransfer[prop] + "\n";
+    }
+  }
+  str += "}";
+  LOG(str);
+}
+
+function dispatchFunction(aFunc) {
+  Services.tm.currentThread.dispatch(aFunc, Ci.nsIThread.DISPATCH_NORMAL);
+}
diff --git a/browser/components/customizableui/src/PanelWideWidgetTracker.jsm b/browser/components/customizableui/src/PanelWideWidgetTracker.jsm
new file mode 100644
index 0000000000000000000000000000000000000000..8aa28a7ab0f7188620c0cee10c0b9621397e912a
--- /dev/null
+++ b/browser/components/customizableui/src/PanelWideWidgetTracker.jsm
@@ -0,0 +1,183 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+this.EXPORTED_SYMBOLS = ["PanelWideWidgetTracker"];
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
+  "resource:///modules/CustomizableUI.jsm");
+
+let gModuleName = "[PanelWideWidgetTracker]";
+#include logging.js
+
+let gPanel = CustomizableUI.AREA_PANEL;
+// We keep track of the widget placements for the panel locally:
+let gPanelPlacements = [];
+
+// All the wide widgets we know of:
+let gWideWidgets = new Set();
+// All the widgets we know of:
+let gSeenWidgets = new Set();
+
+// The class by which we recognize wide widgets:
+const kWidePanelItemClass = "panel-wide-item";
+
+// TODO(bug 885574): Merge this constant with the one in CustomizeMode.jsm,
+//                   maybe just use a pref for this.
+const kColumnsInMenuPanel = 3;
+
+let PanelWideWidgetTracker = {
+  // Listeners used to validate panel contents whenever they change:
+  onWidgetAdded: function(aWidgetId, aArea, aPosition) {
+    if (aArea == gPanel) {
+      gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
+      let moveForward = this.shouldMoveForward(aWidgetId, aPosition);
+      this.adjustWidgets(aWidgetId, moveForward);
+    }
+  },
+  onWidgetMoved: function(aWidgetId, aArea, aOldPosition, aNewPosition) {
+    if (aArea == gPanel) {
+      gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
+      let moveForward = this.shouldMoveForward(aWidgetId, aNewPosition);
+      this.adjustWidgets(aWidgetId, moveForward);
+    }
+  },
+  onWidgetRemoved: function(aWidgetId, aPrevArea) {
+    if (aPrevArea == gPanel) {
+      gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
+      let pos = gPanelPlacements.indexOf(aWidgetId);
+      this.adjustWidgets(aWidgetId, false);
+    }
+  },
+  onWidgetReset: function(aWidgetId) {
+    gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
+  },
+  // Listener to keep abreast of any new nodes. We use the DOM one because
+  // we need access to the actual node's classlist, so we can't use the ones above.
+  // Furthermore, onWidgetCreated only fires for API-based widgets, not for XUL ones.
+  onWidgetAfterDOMChange: function(aNode, aNextNode, aContainer) {
+    if (!gSeenWidgets.has(aNode.id)) {
+      if (aNode.classList.contains(kWidePanelItemClass)) {
+        gWideWidgets.add(aNode.id);
+      }
+      gSeenWidgets.add(aNode.id);
+    }
+  },
+  // When widgets get destroyed, we remove them from our sets of stuff we care about:
+  onWidgetDestroyed: function(aWidgetId) {
+    gSeenWidgets.delete(aWidgetId);
+    gWideWidgets.delete(aWidgetId);
+  },
+  shouldMoveForward: function(aWidgetId, aPosition) {
+    let currentWidgetAtPosition = gPanelPlacements[aPosition + 1];
+    let rv = gWideWidgets.has(currentWidgetAtPosition) && !gWideWidgets.has(aWidgetId);
+    // We might now think we can move forward, but for that we need at least 2 more small
+    // widgets to be present:
+    if (rv) {
+      let furtherWidgets = gPanelPlacements.slice(aPosition + 2);
+      let realWidgets = 0;
+      if (furtherWidgets.length >= 2) {
+        while (furtherWidgets.length && realWidgets < 2) {
+          let w = furtherWidgets.shift();
+          if (!gWideWidgets.has(w) && this.checkWidgetStatus(w)) {
+            realWidgets++;
+          }
+        }
+      }
+      if (realWidgets < 2) {
+        rv = false;
+      }
+    }
+    return rv;
+  },
+  adjustWidgets: function(aWidgetId, aMoveForwards) {
+    if (this.adjusting) {
+      return;
+    }
+    this.adjusting = true;
+    let widgetsAffected = [w for (w of gPanelPlacements) if (gWideWidgets.has(w))];
+    // If we're moving the wide widgets forwards (down/to the right in the panel)
+    // we want to start with the last widgets. Otherwise we move widgets over other wide
+    // widgets, which might mess up their order. Likewise, if moving backwards we should start with
+    // the first widget and work our way down/right from there.
+    let compareFn = aMoveForwards ? (function(a, b) a < b) : (function(a, b) a > b)
+    widgetsAffected.sort(function(a, b) compareFn(gPanelPlacements.indexOf(a),
+                                                  gPanelPlacements.indexOf(b)));
+    for (let widget of widgetsAffected) {
+      this.adjustPosition(widget, aMoveForwards);
+    }
+    this.adjusting = false;
+  },
+  // This function is called whenever an item gets moved in the menu panel. It
+  // adjusts the position of widgets within the panel to prevent "gaps" between
+  // wide widgets that could be filled up with single column widgets
+  adjustPosition: function(aWidgetId, aMoveForwards) {
+    // Make sure that there are n % columns = 0 narrow buttons before the widget.
+    let placementIndex = gPanelPlacements.indexOf(aWidgetId);
+    let prevSiblingCount = 0;
+    let fixedPos = null;
+    while (placementIndex--) {
+      let thisWidgetId = gPanelPlacements[placementIndex];
+      if (gWideWidgets.has(thisWidgetId)) {
+        continue;
+      }
+      let widgetStatus = this.checkWidgetStatus(thisWidgetId);
+      if (!widgetStatus) {
+        continue;
+      }
+      if (widgetStatus == "public-only") {
+        fixedPos = !fixedPos ? placementIndex : Math.min(fixedPos, placementIndex);
+        prevSiblingCount = 0;
+      } else {
+        prevSiblingCount++;
+      }
+    }
+
+    if (fixedPos !== null || prevSiblingCount % kColumnsInMenuPanel) {
+      let desiredPos = (fixedPos !== null) ? fixedPos : gPanelPlacements.indexOf(aWidgetId);
+      let desiredChange = -(prevSiblingCount % kColumnsInMenuPanel);
+      if (aMoveForwards && fixedPos == null) {
+        // +1 because otherwise we'd count ourselves:
+        desiredChange = kColumnsInMenuPanel + desiredChange + 1;
+      }
+      desiredPos += desiredChange;
+      CustomizableUI.moveWidgetWithinArea(aWidgetId, desiredPos);
+    }
+  },
+
+  /*
+   * Check whether a widget id is actually known anywhere.
+   * @returns false if the widget doesn't exist,
+   *          "public-only" if it's not shown in private windows
+   *          "real" if it does exist and is shown even in private windows
+   */
+  checkWidgetStatus: function(aWidgetId) {
+    let widgetWrapper = CustomizableUI.getWidget(aWidgetId);
+    // This widget might not actually exist:
+    if (!widgetWrapper) {
+      return false;
+    }
+    // This widget might still not actually exist:
+    if (widgetWrapper.provider == CustomizableUI.PROVIDER_XUL &&
+        widgetWrapper.instances.length == 0) {
+      return false;
+    }
+
+    // Or it might only be there some of the time:
+    if (widgetWrapper.provider == CustomizableUI.PROVIDER_API &&
+        widgetWrapper.showInPrivateBrowsing === false) {
+      return "public-only";
+    }
+    return "real";
+  },
+
+  init: function() {
+    // Initialize our local placements copy and register the listener
+    gPanelPlacements = CustomizableUI.getWidgetIdsInArea(gPanel);
+    CustomizableUI.addListener(this);
+  },
+};
diff --git a/browser/components/customizableui/src/ScrollbarSampler.jsm b/browser/components/customizableui/src/ScrollbarSampler.jsm
new file mode 100644
index 0000000000000000000000000000000000000000..374d918113d4eea771bb27a5d94fe069b2658df8
--- /dev/null
+++ b/browser/components/customizableui/src/ScrollbarSampler.jsm
@@ -0,0 +1,66 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["ScrollbarSampler"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Promise",
+                                  "resource://gre/modules/Promise.jsm");
+
+let gSystemScrollbarWidth = null;
+
+this.ScrollbarSampler = {
+  getSystemScrollbarWidth: function() {
+    let deferred = Promise.defer();
+
+    if (gSystemScrollbarWidth !== null) {
+      deferred.resolve(gSystemScrollbarWidth);
+      return deferred.promise;
+    }
+
+    this._sampleSystemScrollbarWidth().then(function(systemScrollbarWidth) {
+      gSystemScrollbarWidth = systemScrollbarWidth;
+      deferred.resolve(gSystemScrollbarWidth);
+    });
+    return deferred.promise;
+  },
+
+  _sampleSystemScrollbarWidth: function() {
+    let deferred = Promise.defer();
+    let hwin = Services.appShell.hiddenDOMWindow;
+    let hdoc = hwin.document.documentElement;
+    let iframe = hwin.document.createElementNS("http://www.w3.org/1999/xhtml",
+                                               "html:iframe");
+    iframe.setAttribute("srcdoc", '<body style="overflow-y: scroll"></body>');
+    hdoc.appendChild(iframe);
+
+    let cwindow = iframe.contentWindow;
+    let utils = cwindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                       .getInterface(Ci.nsIDOMWindowUtils);
+
+    cwindow.addEventListener("load", function onLoad(aEvent) {
+      cwindow.removeEventListener("load", onLoad);
+      let sbWidth = {};
+      try {
+        utils.getScrollbarSize(true, sbWidth, {});
+      } catch(e) {
+        Cu.reportError("Could not sample scrollbar size: " + e + " -- " +
+                       e.stack);
+        sbWidth.value = 0;
+      }
+      // Minimum width of 10 so that we have enough padding:
+      sbWidth.value = Math.max(sbWidth.value, 10);
+      deferred.resolve(sbWidth.value);
+      iframe.remove();
+    });
+
+    return deferred.promise;
+  }
+};
+Object.freeze(this.ScrollbarSampler);
diff --git a/browser/components/customizableui/src/logging.js b/browser/components/customizableui/src/logging.js
new file mode 100644
index 0000000000000000000000000000000000000000..6998dc04e82d6288a6479b6e59c02f7dc65ba461
--- /dev/null
+++ b/browser/components/customizableui/src/logging.js
@@ -0,0 +1,25 @@
+#if 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/. */
+#endif
+
+XPCOMUtils.defineLazyModuleGetter(this, "console",
+  "resource://gre/modules/devtools/Console.jsm");
+
+let gDebug = false;
+try {
+  gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
+} catch (e) {}
+
+function LOG(...args) {
+  if (gDebug) {
+    args.unshift(gModuleName);
+    console.log.apply(console, args);
+  }
+}
+
+function ERROR(...args) {
+  args.unshift(gModuleName);
+  console.error.apply(console, args);
+}
diff --git a/browser/components/customizableui/src/moz.build b/browser/components/customizableui/src/moz.build
new file mode 100644
index 0000000000000000000000000000000000000000..d82151e22573aa65f99de7f97385e025470a6509
--- /dev/null
+++ b/browser/components/customizableui/src/moz.build
@@ -0,0 +1,16 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+EXTRA_JS_MODULES += [
+    'ScrollbarSampler.jsm',
+]
+
+EXTRA_PP_JS_MODULES += [
+    'CustomizableUI.jsm',
+    'CustomizableWidgets.jsm',
+    'CustomizeMode.jsm',
+    'PanelWideWidgetTracker.jsm',
+]
diff --git a/browser/components/customizableui/test/browser.ini b/browser/components/customizableui/test/browser.ini
new file mode 100644
index 0000000000000000000000000000000000000000..5b05e094b063d161dbabecfceac9b4db3ee50482
--- /dev/null
+++ b/browser/components/customizableui/test/browser.ini
@@ -0,0 +1,38 @@
+[DEFAULT]
+support-files =
+  head.js
+
+[browser_873501_handle_specials.js]
+[browser_876926_customize_mode_wrapping.js]
+[browser_876944_customize_mode_create_destroy.js]
+[browser_877006_missing_view.js]
+[browser_877178_unregisterArea.js]
+[browser_877447_skip_missing_ids.js]
+[browser_878452_drag_to_panel.js]
+[browser_880382_drag_wide_widgets_in_panel.js]
+[browser_885530_showInPrivateBrowsing.js]
+[browser_886323_buildArea_removable_nodes.js]
+[browser_887438_currentset_shim.js]
+[browser_888817_currentset_updating.js]
+[browser_890140_orphaned_placeholders.js]
+[browser_890262_destroyWidget_after_add_to_panel.js]
+[browser_892955_isWidgetRemovable_for_removed_widgets.js]
+[browser_892956_destroyWidget_defaultPlacements.js]
+[browser_909779_overflow_toolbars_new_window.js]
+[browser_913972_currentset_overflow.js]
+
+[browser_914138_widget_API_overflowable_toolbar.js]
+# Because of the specific widths, this test is fragile and has been disabled.
+# NB: it was designed for mac only, but started randomly failing there.
+skip-if = true
+
+[browser_914863_disabled_help_quit_buttons.js]
+[browser_918049_skipintoolbarset_dnd.js]
+[browser_923857_customize_mode_event_wrapping_during_reset.js]
+[browser_927717_customize_drag_empty_toolbar.js]
+
+[browser_934113_menubar_removable.js]
+# Because this test is about the menubar, it can't be run on mac
+skip-if = os == "mac"
+
+[browser_panel_toggle.js]
diff --git a/browser/components/customizableui/test/browser_873501_handle_specials.js b/browser/components/customizableui/test/browser_873501_handle_specials.js
new file mode 100644
index 0000000000000000000000000000000000000000..d518c1af0951f4d6bcdf7e652dfb15e0e70a0f9c
--- /dev/null
+++ b/browser/components/customizableui/test/browser_873501_handle_specials.js
@@ -0,0 +1,91 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const kToolbarName = "test-specials-toolbar";
+
+let gTests = [
+  {
+    desc: "Add a toolbar with two springs and the downloads button.",
+    run: function() {
+      // Create the toolbar with a single spring:
+      createToolbarWithPlacements(kToolbarName, ["spring"]);
+      ok(document.getElementById(kToolbarName), "Toolbar should be created.");
+
+      // Check it's there with a generated ID:
+      assertAreaPlacements(kToolbarName, [/customizableui-special-spring\d+/]);
+      let [springId] = getAreaWidgetIds(kToolbarName);
+
+      // Add a second spring, check if that's there and doesn't share IDs
+      CustomizableUI.addWidgetToArea("spring", kToolbarName);
+      assertAreaPlacements(kToolbarName, [springId,
+                                          /customizableui-special-spring\d+/]);
+      let [, spring2Id] = getAreaWidgetIds(kToolbarName);
+
+      isnot(springId, spring2Id, "Springs shouldn't have identical IDs.");
+
+      // Try moving the downloads button to this new toolbar, between the two springs:
+      CustomizableUI.addWidgetToArea("downloads-button", kToolbarName, 1);
+      assertAreaPlacements(kToolbarName, [springId, "downloads-button", spring2Id]);
+    },
+    teardown: removeCustomToolbars
+  },
+  {
+    desc: "Add separators around the downloads button.",
+    run: function() {
+      createToolbarWithPlacements(kToolbarName, ["separator"]);
+      ok(document.getElementById(kToolbarName), "Toolbar should be created.");
+
+      // Check it's there with a generated ID:
+      assertAreaPlacements(kToolbarName, [/customizableui-special-separator\d+/]);
+      let [separatorId] = getAreaWidgetIds(kToolbarName);
+
+      CustomizableUI.addWidgetToArea("separator", kToolbarName);
+      assertAreaPlacements(kToolbarName, [separatorId,
+                                          /customizableui-special-separator\d+/]);
+      let [, separator2Id] = getAreaWidgetIds(kToolbarName);
+
+      isnot(separatorId, separator2Id, "Separator ids shouldn't be equal.");
+
+      CustomizableUI.addWidgetToArea("downloads-button", kToolbarName, 1);
+      assertAreaPlacements(kToolbarName, [separatorId, "downloads-button", separator2Id]);
+    },
+    teardown: removeCustomToolbars
+  },
+  {
+    desc: "Add spacers around the downloads button.",
+    run: function() {
+      createToolbarWithPlacements(kToolbarName, ["spacer"]);
+      ok(document.getElementById(kToolbarName), "Toolbar should be created.");
+
+      // Check it's there with a generated ID:
+      assertAreaPlacements(kToolbarName, [/customizableui-special-spacer\d+/]);
+      let [spacerId] = getAreaWidgetIds(kToolbarName);
+
+      CustomizableUI.addWidgetToArea("spacer", kToolbarName);
+      assertAreaPlacements(kToolbarName, [spacerId,
+                                          /customizableui-special-spacer\d+/]);
+      let [, spacer2Id] = getAreaWidgetIds(kToolbarName);
+
+      isnot(spacerId, spacer2Id, "Spacer ids shouldn't be equal.");
+
+      CustomizableUI.addWidgetToArea("downloads-button", kToolbarName, 1);
+      assertAreaPlacements(kToolbarName, [spacerId, "downloads-button", spacer2Id]);
+    },
+    teardown: removeCustomToolbars
+  }
+];
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function cleanup() {
+  removeCustomToolbars();
+}
+
+function test() {
+  waitForExplicitFinish();
+  registerCleanupFunction(cleanup);
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js b/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js
new file mode 100644
index 0000000000000000000000000000000000000000..9d4d4289e90ff46ca0627037017414e272d8a0fb
--- /dev/null
+++ b/browser/components/customizableui/test/browser_876926_customize_mode_wrapping.js
@@ -0,0 +1,161 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const kXULWidgetId = "sync-button";
+const kAPIWidgetId = "feed-button";
+const kPanel = CustomizableUI.AREA_PANEL;
+const kToolbar = CustomizableUI.AREA_NAVBAR;
+const kVisiblePalette = "customization-palette";
+const kPlaceholderClass = "panel-customization-placeholder";
+
+function checkWrapper(id) {
+  is(document.querySelectorAll("#wrapper-" + id).length, 1, "There should be exactly 1 wrapper for " + id + " in the customizing window.");
+}
+
+let move = {
+  "drag": function(id, target) {
+    let targetNode = document.getElementById(target);
+    if (targetNode.customizationTarget) {
+      targetNode = targetNode.customizationTarget;
+    }
+    simulateItemDrag(document.getElementById(id), targetNode);
+  },
+  "dragToItem": function(id, target) {
+    let targetNode = document.getElementById(target);
+    if (targetNode.customizationTarget) {
+      targetNode = targetNode.customizationTarget;
+    }
+    let items = targetNode.querySelectorAll("toolbarpaletteitem:not(." + kPlaceholderClass + ")");
+    if (target == kPanel) {
+      targetNode = items[items.length - 1];
+    } else {
+      targetNode = items[0];
+    }
+    simulateItemDrag(document.getElementById(id), targetNode);
+  },
+  "API": function(id, target) {
+    if (target == kVisiblePalette) {
+      return CustomizableUI.removeWidgetFromArea(id);
+    }
+    return CustomizableUI.addWidgetToArea(id, target, null);
+  }
+}
+
+function isLast(containerId, defaultPlacements, id) {
+  assertAreaPlacements(containerId, defaultPlacements.concat([id]));
+  is(document.getElementById(containerId).customizationTarget.lastChild.firstChild.id, id,
+     "Widget " + id + " should be in " + containerId + " in customizing window.");
+  is(otherWin.document.getElementById(containerId).customizationTarget.lastChild.id, id,
+     "Widget " + id + " should be in " + containerId + " in other window.");
+}
+
+function isFirst(containerId, defaultPlacements, id) {
+  assertAreaPlacements(containerId, [id].concat(defaultPlacements));
+  is(document.getElementById(containerId).customizationTarget.firstChild.firstChild.id, id,
+     "Widget " + id + " should be in " + containerId + " in customizing window.");
+  is(otherWin.document.getElementById(containerId).customizationTarget.firstChild.id, id,
+     "Widget " + id + " should be in " + containerId + " in other window.");
+}
+
+function checkToolbar(id, method) {
+  // Place at start of the toolbar:
+  let toolbarPlacements = getAreaWidgetIds(kToolbar);
+  move[method](id, kToolbar);
+  if (method == "dragToItem") {
+    isFirst(kToolbar, toolbarPlacements, id);
+  } else {
+    isLast(kToolbar, toolbarPlacements, id);
+  }
+  checkWrapper(id);
+}
+
+function checkPanel(id, method) {
+  let panelPlacements = getAreaWidgetIds(kPanel);
+  move[method](id, kPanel);
+  let children = document.getElementById(kPanel).querySelectorAll("toolbarpaletteitem:not(." + kPlaceholderClass + ")");
+  let otherChildren = otherWin.document.getElementById(kPanel).children;
+  let newPlacements = panelPlacements.concat([id]);
+  // Relative position of the new item from the end:
+  let position = -1;
+  // For the drag to item case, we drag to the last item, making the dragged item the
+  // penultimate item. We can't well use the first item because the panel has complicated
+  // rules about rearranging wide items (which, by default, the first two items are).
+  if (method == "dragToItem") {
+    newPlacements.pop();
+    newPlacements.splice(panelPlacements.length - 1, 0, id);
+    position = -2;
+  }
+  assertAreaPlacements(kPanel, newPlacements);
+  is(children[children.length + position].firstChild.id, id,
+     "Widget " + id + " should be in " + kPanel + " in customizing window.");
+  is(otherChildren[otherChildren.length + position].id, id,
+     "Widget " + id + " should be in " + kPanel + " in other window.");
+  checkWrapper(id);
+}
+
+function checkPalette(id, method) {
+  // Move back to palette:
+  move[method](id, kVisiblePalette);
+  ok(CustomizableUI.inDefaultState, "Should end in default state");
+  let visibleChildren = gCustomizeMode.visiblePalette.children;
+  let expectedChild = method == "dragToItem" ? visibleChildren[0] : visibleChildren[visibleChildren.length - 1];
+  is(expectedChild.firstChild.id, id, "Widget " + id + " was moved using " + method + " and should now be wrapped in palette in customizing window.");
+  if (id == kXULWidgetId) {
+    ok(otherWin.gNavToolbox.palette.querySelector("#" + id), "Widget " + id + " should be in invisible palette in other window.");
+  }
+  checkWrapper(id);
+}
+
+let otherWin;
+let gTests = [
+  {
+    desc: "Moving widgets in two windows, one with customize mode and one without, should work",
+    setup: startCustomizing,
+    run: function() {
+      otherWin = yield openAndLoadWindow(null, true);
+      // Open and close the panel to force its construction:
+      let shownPromise = promisePanelShown(otherWin);
+      otherWin.PanelUI.toggle({type: "command"});
+      yield shownPromise;
+      let hiddenPromise = promisePanelHidden(otherWin);
+      otherWin.PanelUI.toggle({type: "command"});
+      yield hiddenPromise;
+
+      ok(CustomizableUI.inDefaultState, "Should start in default state");
+
+      for (let widgetId of [kXULWidgetId, kAPIWidgetId]) {
+        for (let method of ["API", "drag", "dragToItem"]) {
+          info("Moving widget " + widgetId + " using " + method);
+          checkToolbar(widgetId, method);
+          checkPanel(widgetId, method);
+          checkPalette(widgetId, method);
+          checkPanel(widgetId, method);
+          checkToolbar(widgetId, method);
+          checkPalette(widgetId, method);
+        }
+      }
+
+      otherWin.close();
+      otherWin = null;
+    },
+    teardown: function() {
+      if (otherWin) {
+        otherWin.close();
+      }
+      yield endCustomizing();
+    }
+  }
+];
+
+function asyncCleanup() {
+  Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck");
+  yield resetCustomization();
+}
+
+function test() {
+  Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
+
diff --git a/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js b/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js
new file mode 100644
index 0000000000000000000000000000000000000000..1c25cf345b2e107c511b468f7dbfea331410310b
--- /dev/null
+++ b/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js
@@ -0,0 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const kTestWidget1 = "test-customize-mode-create-destroy1";
+const kTestWidget2 = "test-customize-mode-create-destroy2";
+
+let gTests = [
+  {
+    desc: "Creating and destroying a widget should correctly wrap/unwrap stuff",
+    setup: startCustomizing,
+    run: function() {
+      CustomizableUI.createWidget({id: kTestWidget1, label: 'Pretty label', tooltiptext: 'Pretty tooltip'});
+      let elem = document.getElementById(kTestWidget1);
+      let wrapper = document.getElementById("wrapper-" + kTestWidget1);
+      ok(elem, "There should be an item");
+      ok(wrapper, "There should be a wrapper");
+      is(wrapper.firstChild.id, kTestWidget1, "Wrapper should have test widget");
+      is(wrapper.parentNode.id, "customization-palette", "Wrapper should be in palette");
+      CustomizableUI.destroyWidget(kTestWidget1);
+      wrapper = document.getElementById("wrapper-" + kTestWidget1);
+      ok(!wrapper, "There should be a wrapper");
+      let item = document.getElementById(kTestWidget1);
+      ok(!item, "There should no longer be an item");
+    },
+  },
+  {
+    desc: "Creating and destroying a widget should correctly deal with panel placeholders",
+    run: function() {
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      is(panel.querySelectorAll(".panel-customization-placeholder").length, 3, "The number of placeholders should be correct.");
+      CustomizableUI.createWidget({id: kTestWidget2, label: 'Pretty label', tooltiptext: 'Pretty tooltip', defaultArea: CustomizableUI.AREA_PANEL});
+      let elem = document.getElementById(kTestWidget2);
+      let wrapper = document.getElementById("wrapper-" + kTestWidget2);
+      ok(elem, "There should be an item");
+      ok(wrapper, "There should be a wrapper");
+      is(wrapper.firstChild.id, kTestWidget2, "Wrapper should have test widget");
+      is(wrapper.parentNode, panel, "Wrapper should be in panel");
+      is(panel.querySelectorAll(".panel-customization-placeholder").length, 2, "The number of placeholders should be correct.");
+      CustomizableUI.destroyWidget(kTestWidget2);
+      wrapper = document.getElementById("wrapper-" + kTestWidget2);
+      ok(!wrapper, "There should be a wrapper");
+      let item = document.getElementById(kTestWidget2);
+      ok(!item, "There should no longer be an item");
+    },
+    teardown: endCustomizing
+  },
+];
+
+function asyncCleanup() {
+  yield endCustomizing();
+  try {
+    CustomizableUI.destroyWidget(kTestWidget1);
+  } catch (ex) {}
+  try {
+    CustomizableUI.destroyWidget(kTestWidget2);
+  } catch (ex) {}
+  yield resetCustomization();
+}
+
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_877006_missing_view.js b/browser/components/customizableui/test/browser_877006_missing_view.js
new file mode 100644
index 0000000000000000000000000000000000000000..f65861d6314e40dc5212e5e09627b2549a2fa441
--- /dev/null
+++ b/browser/components/customizableui/test/browser_877006_missing_view.js
@@ -0,0 +1,50 @@
+/* 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/. */
+
+let gTests = [
+  {
+    desc: "Should be able to add broken view widget",
+    run: function() {
+      const kWidgetId = 'test-877006-broken-widget';
+      let widgetSpec = {
+        id: kWidgetId,
+        type: 'view',
+        viewId: 'idontexist',
+        /* Empty handler so we try to attach it maybe? */
+        onViewShowing: function() {
+        },
+      };
+
+      let noError = true;
+      try {
+        CustomizableUI.createWidget(widgetSpec);
+        CustomizableUI.addWidgetToArea(kWidgetId, CustomizableUI.AREA_NAVBAR);
+      } catch (ex) {
+        Cu.reportError(ex);
+        noError = false;
+      }
+      ok(noError, "Should not throw an exception trying to add a broken view widget.");
+
+      noError = true;
+      try {
+        CustomizableUI.destroyWidget(kWidgetId);
+      } catch (ex) {
+        Cu.reportError(ex);
+        noError = false;
+      }
+      ok(noError, "Should not throw an exception trying to remove the broken view widget.");
+    }
+  }
+];
+
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
+
diff --git a/browser/components/customizableui/test/browser_877178_unregisterArea.js b/browser/components/customizableui/test/browser_877178_unregisterArea.js
new file mode 100644
index 0000000000000000000000000000000000000000..eb458ac152959627c2389b94009079c0688c2161
--- /dev/null
+++ b/browser/components/customizableui/test/browser_877178_unregisterArea.js
@@ -0,0 +1,67 @@
+/* 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/. */
+
+let gTests = [
+  {
+    desc: "Sanity checks",
+    run: function() {
+      SimpleTest.doesThrow(function() CustomizableUI.registerArea("@foo"),
+                           "Registering areas with an invalid ID should throw.");
+
+      SimpleTest.doesThrow(function() CustomizableUI.registerArea([]),
+                           "Registering areas with an invalid ID should throw.");
+
+      SimpleTest.doesThrow(function() CustomizableUI.registerArea(CustomizableUI.AREA_NAVBAR),
+                           "Registering an area with an ID that's already registered should throw.");
+
+      SimpleTest.doesThrow(function() CustomizableUI.unregisterArea("@foo"),
+                           "Unregistering areas with an invalid ID should throw.");
+
+      SimpleTest.doesThrow(function() CustomizableUI.unregisterArea([]),
+                           "Unregistering areas with an invalid ID should throw.");
+
+      SimpleTest.doesThrow(function() CustomizableUI.unregisterArea("unknown"),
+                           "Unregistering an area that's not registered should throw.");
+    }
+  },
+  {
+    desc: "Check areas are loaded with their default placements.",
+    run: function() {
+      ok(CustomizableUI.inDefaultState, "Everything should be in its default state.");
+    }
+  },
+  {
+    desc: "Check registering and unregistering a new area.",
+    run: function() {
+      const kToolbarId = "test-registration-toolbar";
+      const kButtonId = "test-registration-button";
+      createDummyXULButton(kButtonId);
+      createToolbarWithPlacements(kToolbarId, ["spring", kButtonId, "spring"]);
+      assertAreaPlacements(kToolbarId,
+                           [/customizableui-special-spring\d+/,
+                            kButtonId,
+                            /customizableui-special-spring\d+/]);
+      ok(CustomizableUI.inDefaultState, "With a new toolbar and default placements, " +
+                                        "everything should still be in a default state.");
+      removeCustomToolbars(); // Will call unregisterArea for us
+      ok(CustomizableUI.inDefaultState, "When the toolbar is unregistered, " +
+                                        "everything should still be in a default state.");
+    }
+  }
+];
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function cleanup() {
+  removeCustomToolbars();
+}
+
+function test() {
+  waitForExplicitFinish();
+  registerCleanupFunction(cleanup);
+  runTests(gTests, asyncCleanup);
+}
+
diff --git a/browser/components/customizableui/test/browser_877447_skip_missing_ids.js b/browser/components/customizableui/test/browser_877447_skip_missing_ids.js
new file mode 100644
index 0000000000000000000000000000000000000000..038dc4f295a707fe17e54274fc4669807ac4dddf
--- /dev/null
+++ b/browser/components/customizableui/test/browser_877447_skip_missing_ids.js
@@ -0,0 +1,35 @@
+/* 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/. */
+
+let gTests = [
+  {
+    run: function() {
+      const kButtonId = "look-at-me-disappear-button";
+      CustomizableUI.reset();
+      ok(CustomizableUI.inDefaultState, "Should be in the default state.");
+      let btn = createDummyXULButton(kButtonId, "Gone!");
+      CustomizableUI.addWidgetToArea(kButtonId, CustomizableUI.AREA_NAVBAR);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in the default state.");
+      is(btn.parentNode.parentNode.id, CustomizableUI.AREA_NAVBAR, "Button should be in navbar");
+      btn.remove();
+      is(btn.parentNode, null, "Button is no longer in the navbar");
+      ok(CustomizableUI.inDefaultState, "Should be back in the default state, " +
+                                        "despite unknown button ID in placements.");
+    }
+  }
+];
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function cleanup() {
+  removeCustomToolbars();
+}
+
+function test() {
+  waitForExplicitFinish();
+  registerCleanupFunction(cleanup);
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_878452_drag_to_panel.js b/browser/components/customizableui/test/browser_878452_drag_to_panel.js
new file mode 100644
index 0000000000000000000000000000000000000000..f70501035b133ecd8ff32884e43a7a47573b90f1
--- /dev/null
+++ b/browser/components/customizableui/test/browser_878452_drag_to_panel.js
@@ -0,0 +1,80 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+let gTests = [
+  {
+    desc: "Dragging an item from the palette to another button in the panel should work.",
+    setup: startCustomizing,
+    run: function() {
+      let btn = document.getElementById("developer-button");
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+
+      let lastButtonIndex = placements.length - 1;
+      let lastButton = placements[lastButtonIndex];
+      let placementsAfterInsert = placements.slice(0, lastButtonIndex).concat(["developer-button", lastButton]);
+      let lastButtonNode = document.getElementById(lastButton);
+      simulateItemDrag(btn, lastButtonNode);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      let palette = document.getElementById("customization-palette");
+      simulateItemDrag(btn, palette);
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+  {
+    desc: "Dragging an item from the palette to the panel itself should also work.",
+    setup: startCustomizing,
+    run: function() {
+      let btn = document.getElementById("developer-button");
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+
+      let placementsAfterAppend = placements.concat(["developer-button"]);
+      simulateItemDrag(btn, panel);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      let palette = document.getElementById("customization-palette");
+      simulateItemDrag(btn, palette);
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+  {
+    desc: "Dragging an item from the palette to an empty panel should also work.",
+    setup: function() {
+      let widgetIds = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+      while (widgetIds.length) {
+        CustomizableUI.removeWidgetFromArea(widgetIds.shift());
+      }
+      return startCustomizing()
+    },
+    run: function() {
+      let btn = document.getElementById("developer-button");
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+
+      assertAreaPlacements(panel.id, []);
+
+      let placementsAfterAppend = ["developer-button"];
+      simulateItemDrag(btn, panel);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      let palette = document.getElementById("customization-palette");
+      simulateItemDrag(btn, palette);
+      assertAreaPlacements(panel.id, []);
+    },
+  }
+];
+
+function asyncCleanup() {
+  yield endCustomizing();
+  Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck");
+  yield resetCustomization();
+}
+
+function test() {
+  Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
+
diff --git a/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js b/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js
new file mode 100644
index 0000000000000000000000000000000000000000..9c1af8191522281c185bad7fbaaa2a9fa9a3f21c
--- /dev/null
+++ b/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js
@@ -0,0 +1,458 @@
+/* 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/. */
+
+let gTests = [
+  {
+    desc: "Dragging the zoom controls to be before the print button " +
+          "should not move any controls.",
+    setup: startCustomizing,
+    run: function() {
+      let zoomControls = document.getElementById("zoom-controls");
+      let printButton = document.getElementById("print-button");
+      let placementsAfterMove = ["edit-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "zoom-controls",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button"];
+      simulateItemDrag(zoomControls, printButton);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      let newWindowButton = document.getElementById("new-window-button");
+      simulateItemDrag(zoomControls, newWindowButton);
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+  {
+    desc: "Dragging the zoom controls to be before the save button " +
+          "should not move any controls.",
+    setup: startCustomizing,
+    run: function() {
+      let zoomControls = document.getElementById("zoom-controls");
+      let savePageButton = document.getElementById("save-page-button");
+      let placementsAfterMove = ["edit-controls",
+                                 "zoom-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button"];
+      simulateItemDrag(zoomControls, savePageButton);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      ok(CustomizableUI.inDefaultState, "Should be in default state.");
+    },
+  },
+  {
+    desc: "Dragging the zoom controls to be before the new-window " +
+          "button should not move any widgets.",
+    setup: startCustomizing,
+    run: function() {
+      let zoomControls = document.getElementById("zoom-controls");
+      let newWindowButton = document.getElementById("new-window-button");
+      let placementsAfterMove = ["edit-controls",
+                                 "zoom-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button"];
+      simulateItemDrag(zoomControls, newWindowButton);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      ok(CustomizableUI.inDefaultState, "Should still be in default state.");
+    },
+  },
+  {
+    desc: "Dragging the zoom controls to be before the history-panelmenu " +
+          "should move the zoom-controls in to the row higher than the " +
+          "history-panelmenu.",
+    setup: startCustomizing,
+    run: function() {
+      let zoomControls = document.getElementById("zoom-controls");
+      let historyPanelMenu = document.getElementById("history-panelmenu");
+      let placementsAfterMove = ["edit-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "zoom-controls",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button"];
+      simulateItemDrag(zoomControls, historyPanelMenu);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      let newWindowButton = document.getElementById("new-window-button");
+      simulateItemDrag(zoomControls, newWindowButton);
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+  {
+    desc: "Dragging the zoom controls to be before the preferences-button " +
+          "should move the zoom-controls in to the row higher than the " +
+          "preferences-button.",
+    setup: startCustomizing,
+    run: function() {
+      let zoomControls = document.getElementById("zoom-controls");
+      let preferencesButton = document.getElementById("preferences-button");
+      let placementsAfterMove = ["edit-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "zoom-controls",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button"];
+      simulateItemDrag(zoomControls, preferencesButton);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      let newWindowButton = document.getElementById("new-window-button");
+      simulateItemDrag(zoomControls, newWindowButton);
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+  {
+    desc: "Dragging an item from the palette to before the zoom-controls " +
+          "should move it and two other buttons before the zoom controls.",
+    setup: startCustomizing,
+    run: function() {
+      let developerButton = document.getElementById("developer-button");
+      let zoomControls = document.getElementById("zoom-controls");
+      let placementsAfterInsert = ["edit-controls",
+                                   "developer-button",
+                                   "new-window-button",
+                                   "privatebrowsing-button",
+                                   "zoom-controls",
+                                   "save-page-button",
+                                   "print-button",
+                                   "history-panelmenu",
+                                   "fullscreen-button",
+                                   "find-button",
+                                   "preferences-button",
+                                   "add-ons-button"];
+      simulateItemDrag(developerButton, zoomControls);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      let palette = document.getElementById("customization-palette");
+      // Check that the palette items are re-wrapped correctly.
+      let feedWrapper = document.getElementById("wrapper-feed-button");
+      let feedButton = document.getElementById("feed-button");
+      is(feedButton.parentNode, feedWrapper,
+         "feed-button should be a child of wrapper-feed-button");
+      is(feedWrapper.getAttribute("place"), "palette",
+         "The feed-button wrapper should have it's place set to 'palette'");
+      simulateItemDrag(developerButton, palette);
+      is(developerButton.parentNode.tagName, "toolbarpaletteitem",
+         "The developer-button should be wrapped by a toolbarpaletteitem");
+      let newWindowButton = document.getElementById("new-window-button");
+      simulateItemDrag(zoomControls, newWindowButton);
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+  {
+    desc: "Dragging an item from the palette to before the edit-controls " +
+          "should move it and two other buttons before the edit and zoom controls.",
+    setup: startCustomizing,
+    run: function() {
+      let developerButton = document.getElementById("developer-button");
+      let editControls = document.getElementById("edit-controls");
+      let placementsAfterInsert = ["developer-button",
+                                   "new-window-button",
+                                   "privatebrowsing-button",
+                                   "edit-controls",
+                                   "zoom-controls",
+                                   "save-page-button",
+                                   "print-button",
+                                   "history-panelmenu",
+                                   "fullscreen-button",
+                                   "find-button",
+                                   "preferences-button",
+                                   "add-ons-button"];
+      simulateItemDrag(developerButton, editControls);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      let palette = document.getElementById("customization-palette");
+      // Check that the palette items are re-wrapped correctly.
+      let feedWrapper = document.getElementById("wrapper-feed-button");
+      let feedButton = document.getElementById("feed-button");
+      is(feedButton.parentNode, feedWrapper,
+         "feed-button should be a child of wrapper-feed-button");
+      is(feedWrapper.getAttribute("place"), "palette",
+         "The feed-button wrapper should have it's place set to 'palette'");
+      simulateItemDrag(developerButton, palette);
+      is(developerButton.parentNode.tagName, "toolbarpaletteitem",
+         "The developer-button should be wrapped by a toolbarpaletteitem");
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+  {
+    desc: "Dragging the edit-controls to be before the zoom-controls button " +
+          "should not move any widgets.",
+    setup: startCustomizing,
+    run: function() {
+      let editControls = document.getElementById("edit-controls");
+      let zoomControls = document.getElementById("zoom-controls");
+      let placementsAfterMove = ["edit-controls",
+                                 "zoom-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button"];
+      simulateItemDrag(editControls, zoomControls);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      ok(CustomizableUI.inDefaultState, "Should still be in default state.");
+    },
+  },
+  {
+    desc: "Dragging the edit-controls to be before the new-window-button should " +
+          "move the zoom-controls before the edit-controls.",
+    setup: startCustomizing,
+    run: function() {
+      let editControls = document.getElementById("edit-controls");
+      let newWindowButton = document.getElementById("new-window-button");
+      let placementsAfterMove = ["zoom-controls",
+                                 "edit-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button"];
+      simulateItemDrag(editControls, newWindowButton);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      let zoomControls = document.getElementById("zoom-controls");
+      simulateItemDrag(editControls, zoomControls);
+      ok(CustomizableUI.inDefaultState, "Should still be in default state.");
+    },
+  },
+  {
+    desc: "Dragging the edit-controls to be before the privatebrowsing-button " +
+          "should move the edit-controls in to the row higher than the " +
+          "privatebrowsing-button.",
+    setup: startCustomizing,
+    run: function() {
+      let editControls = document.getElementById("edit-controls");
+      let privateBrowsingButton = document.getElementById("privatebrowsing-button");
+      let placementsAfterMove = ["zoom-controls",
+                                 "edit-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button"];
+      simulateItemDrag(editControls, privateBrowsingButton);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      let zoomControls = document.getElementById("zoom-controls");
+      simulateItemDrag(editControls, zoomControls);
+      ok(CustomizableUI.inDefaultState, "Should still be in default state.");
+    },
+  },
+  {
+    desc: "Dragging the edit-controls to be before the save-page-button " +
+          "should move the edit-controls in to the row higher than the " +
+          "save-page-button.",
+    setup: startCustomizing,
+    run: function() {
+      let editControls = document.getElementById("edit-controls");
+      let savePageButton = document.getElementById("save-page-button");
+      let placementsAfterMove = ["zoom-controls",
+                                 "edit-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button"];
+      simulateItemDrag(editControls, savePageButton);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      let zoomControls = document.getElementById("zoom-controls");
+      simulateItemDrag(editControls, zoomControls);
+      ok(CustomizableUI.inDefaultState, "Should still be in default state.");
+    },
+  },
+  {
+    desc: "Dragging the edit-controls to the panel itself should append " +
+          "the edit controls to the bottom of the panel.",
+    setup: startCustomizing,
+    run: function() {
+      let editControls = document.getElementById("edit-controls");
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      let placementsAfterMove = ["zoom-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button",
+                                 "edit-controls"];
+      simulateItemDrag(editControls, panel);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      let zoomControls = document.getElementById("zoom-controls");
+      simulateItemDrag(editControls, zoomControls);
+      ok(CustomizableUI.inDefaultState, "Should still be in default state.");
+    },
+  },
+  {
+    desc: "Dragging the edit-controls to the customization-palette and " +
+          "back should work.",
+    setup: startCustomizing,
+    run: function() {
+      let editControls = document.getElementById("edit-controls");
+      let palette = document.getElementById("customization-palette");
+      let placementsAfterMove = ["zoom-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button"];
+      let paletteChildElementCount = palette.childElementCount;
+      simulateItemDrag(editControls, palette);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      is(paletteChildElementCount + 1, palette.childElementCount,
+         "The palette should have a new child, congratulations!");
+      is(editControls.parentNode.id, "wrapper-edit-controls",
+         "The edit-controls should be properly wrapped.");
+      is(editControls.parentNode.getAttribute("place"), "palette",
+         "The edit-controls should have the place of 'palette'.");
+      let zoomControls = document.getElementById("zoom-controls");
+      simulateItemDrag(editControls, zoomControls);
+      is(paletteChildElementCount, palette.childElementCount,
+         "The palette child count should have returned to its prior value.");
+      ok(CustomizableUI.inDefaultState, "Should still be in default state.");
+    },
+  },
+  {
+    desc: "Dragging the edit-controls to each of the panel placeholders " +
+          "should append the edit-controls to the bottom of the panel.",
+    setup: startCustomizing,
+    run: function() {
+      let editControls = document.getElementById("edit-controls");
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      for (let i = 0; i < 3; i++) {
+        // NB: We can't just iterate over all of the placeholders
+        // because each drag-drop action recreates them.
+        let placeholder = panel.getElementsByClassName("panel-customization-placeholder")[i];
+        let placementsAfterMove = ["zoom-controls",
+                                   "new-window-button",
+                                   "privatebrowsing-button",
+                                   "save-page-button",
+                                   "print-button",
+                                   "history-panelmenu",
+                                   "fullscreen-button",
+                                   "find-button",
+                                   "preferences-button",
+                                   "add-ons-button",
+                                   "edit-controls"];
+        simulateItemDrag(editControls, placeholder);
+        assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+        let zoomControls = document.getElementById("zoom-controls");
+        simulateItemDrag(editControls, zoomControls);
+        ok(CustomizableUI.inDefaultState, "Should still be in default state.");
+      }
+    },
+  },
+  {
+    desc: "Dragging the developer-button back on to itself should work.",
+    setup: startCustomizing,
+    run: function() {
+      let developerButton = document.getElementById("developer-button");
+      is(developerButton.parentNode.tagName, "toolbarpaletteitem",
+         "developer-button should be wrapped by a toolbarpaletteitem");
+      simulateItemDrag(developerButton, developerButton);
+      is(developerButton.parentNode.tagName, "toolbarpaletteitem",
+         "developer-button should be wrapped by a toolbarpaletteitem");
+      let editControls = document.getElementById("edit-controls");
+      is(editControls.parentNode.tagName, "toolbarpaletteitem",
+         "edit-controls should be wrapped by a toolbarpaletteitem");
+      ok(CustomizableUI.inDefaultState, "Should still be in default state.");
+    },
+  },
+  {
+    desc: "Dragging a small button onto the last big button should work.",
+    setup: startCustomizing,
+    run: function() {
+      let editControls = document.getElementById("edit-controls");
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      let target = panel.getElementsByClassName("panel-customization-placeholder")[0];
+      let placementsAfterMove = ["zoom-controls",
+                                 "new-window-button",
+                                 "privatebrowsing-button",
+                                 "save-page-button",
+                                 "print-button",
+                                 "history-panelmenu",
+                                 "fullscreen-button",
+                                 "find-button",
+                                 "preferences-button",
+                                 "add-ons-button",
+                                 "edit-controls"];
+      simulateItemDrag(editControls, target);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+      let itemToDrag = "sync-button";
+      let button = document.getElementById(itemToDrag);
+      placementsAfterMove.push(itemToDrag);
+      simulateItemDrag(button, editControls);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
+
+      // Put stuff back:
+      let palette = document.getElementById("customization-palette");
+      let zoomControls = document.getElementById("zoom-controls");
+      simulateItemDrag(button, palette);
+      simulateItemDrag(editControls, zoomControls);
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+];
+
+function asyncCleanup() {
+  yield endCustomizing();
+  Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck");
+  yield resetCustomization();
+}
+
+function test() {
+  Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
+  waitForExplicitFinish();
+  requestLongerTimeout(5);
+  runTests(gTests, asyncCleanup);
+}
+
diff --git a/browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js b/browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js
new file mode 100644
index 0000000000000000000000000000000000000000..1203c2bf801a43b0917579d6d025fe3587b18fba
--- /dev/null
+++ b/browser/components/customizableui/test/browser_885530_showInPrivateBrowsing.js
@@ -0,0 +1,151 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const kWidgetId = "some-widget";
+
+function assertWidgetExists(aWindow, aExists) {
+  if (aExists) {
+    ok(aWindow.document.getElementById(kWidgetId),
+       "Should have found test widget in the window");
+  } else {
+    is(aWindow.document.getElementById(kWidgetId), null,
+       "Should not have found test widget in the window");
+  }
+}
+
+let gTests = [
+  {
+    desc: "A widget that is created with showInPrivateBrowsing undefined should " +
+          "have that value default to false.",
+    run: function() {
+      let wrapper = CustomizableUI.createWidget({
+        id: kWidgetId
+      });
+      ok(wrapper.showInPrivateBrowsing,
+         "showInPrivateBrowsing should have defaulted to true.");
+      CustomizableUI.destroyWidget(kWidgetId);
+    },
+  },
+  {
+    desc: "Add a widget via the API with showInPrivateBrowsing set to false " +
+          "and ensure it does not appear in pre-existing or newly created " +
+          "private windows.",
+    run: function() {
+      let plain = yield openAndLoadWindow();
+      let private = yield openAndLoadWindow({private: true});
+
+      CustomizableUI.createWidget({
+        id: kWidgetId,
+        removable: true,
+        showInPrivateBrowsing: false
+      });
+      CustomizableUI.addWidgetToArea(kWidgetId,
+                                     CustomizableUI.AREA_NAVBAR);
+      assertWidgetExists(plain, true);
+      assertWidgetExists(private, false);
+
+      // Now open up some new windows. The widget should exist in the new
+      // plain window, but not the new private window.
+      let plain2 = yield openAndLoadWindow();
+      let private2 = yield openAndLoadWindow({private: true});
+
+      assertWidgetExists(plain2, true);
+      assertWidgetExists(private2, false);
+
+      // Try moving the widget around and make sure it doesn't get added
+      // to the private windows. We'll start by appending it to the tabstrip.
+      CustomizableUI.addWidgetToArea(kWidgetId,
+                                     CustomizableUI.AREA_TABSTRIP);
+      assertWidgetExists(plain, true);
+      assertWidgetExists(plain2, true);
+      assertWidgetExists(private, false);
+      assertWidgetExists(private2, false);
+
+      // And then move it to the beginning of the tabstrip.
+      CustomizableUI.moveWidgetWithinArea(kWidgetId, 0);
+      assertWidgetExists(plain, true);
+      assertWidgetExists(plain2, true);
+      assertWidgetExists(private, false);
+      assertWidgetExists(private2, false);
+
+      CustomizableUI.removeWidgetFromArea("some-widget");
+      assertWidgetExists(plain, false);
+      assertWidgetExists(plain2, false);
+      assertWidgetExists(private, false);
+      assertWidgetExists(private2, false);
+
+      plain.close();
+      plain2.close();
+      private.close();
+      private2.close();
+
+      CustomizableUI.destroyWidget("some-widget");
+    },
+  },
+  {
+    desc: "Add a widget via the API with showInPrivateBrowsing set to true, " +
+          "and ensure that it appears in pre-existing or newly created " +
+          "private browsing windows.",
+    run: function() {
+      let plain = yield openAndLoadWindow();
+      let private = yield openAndLoadWindow({private: true});
+
+      CustomizableUI.createWidget({
+        id: kWidgetId,
+        removable: true,
+        showInPrivateBrowsing: true
+      });
+      CustomizableUI.addWidgetToArea(kWidgetId,
+                                     CustomizableUI.AREA_NAVBAR);
+      assertWidgetExists(plain, true);
+      assertWidgetExists(private, true);
+
+      // Now open up some new windows. The widget should exist in the new
+      // plain window, but not the new private window.
+      let plain2 = yield openAndLoadWindow();
+      let private2 = yield openAndLoadWindow({private: true});
+
+      assertWidgetExists(plain2, true);
+      assertWidgetExists(private2, true);
+
+      // Try moving the widget around and make sure it doesn't get added
+      // to the private windows. We'll start by appending it to the tabstrip.
+      CustomizableUI.addWidgetToArea(kWidgetId,
+                                     CustomizableUI.AREA_TABSTRIP);
+      assertWidgetExists(plain, true);
+      assertWidgetExists(plain2, true);
+      assertWidgetExists(private, true);
+      assertWidgetExists(private2, true);
+
+      // And then move it to the beginning of the tabstrip.
+      CustomizableUI.moveWidgetWithinArea(kWidgetId, 0);
+      assertWidgetExists(plain, true);
+      assertWidgetExists(plain2, true);
+      assertWidgetExists(private, true);
+      assertWidgetExists(private2, true);
+
+      CustomizableUI.removeWidgetFromArea("some-widget");
+      assertWidgetExists(plain, false);
+      assertWidgetExists(plain2, false);
+      assertWidgetExists(private, false);
+      assertWidgetExists(private2, false);
+
+      plain.close();
+      plain2.close();
+      private.close();
+      private2.close();
+
+      CustomizableUI.destroyWidget("some-widget");
+    },
+  }
+];
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js b/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js
new file mode 100644
index 0000000000000000000000000000000000000000..6296a975a82cdcd4fba3f2b6d71116a4226e97fd
--- /dev/null
+++ b/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js
@@ -0,0 +1,56 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const kButtonId = "test-886323-removable-moved-node";
+const kLazyAreaId = "test-886323-lazy-area-for-removability-testing";
+
+let gNavBar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+let gLazyArea;
+let gTests = [
+  {
+    desc: "Removable nodes shouldn't be moved by buildArea",
+    setup: function() {
+      let dummyBtn = createDummyXULButton(kButtonId, "Dummy");
+      dummyBtn.setAttribute("removable", "true");
+      gNavBar.customizationTarget.appendChild(dummyBtn);
+      let popupSet = document.getElementById("mainPopupSet");
+      gLazyArea = document.createElementNS(kNSXUL, "panel");
+      gLazyArea.id = kLazyAreaId;
+      gLazyArea.setAttribute("hidden", "true");
+      popupSet.appendChild(gLazyArea);
+      CustomizableUI.registerArea(kLazyAreaId, {
+        type: CustomizableUI.TYPE_MENU_PANEL,
+        defaultPlacements: []
+      });
+    },
+    run: function() {
+      CustomizableUI.addWidgetToArea(kButtonId, kLazyAreaId);
+      assertAreaPlacements(kLazyAreaId, [kButtonId],
+                           "Placements should have changed because widget is removable.");
+      let btn = document.getElementById(kButtonId);
+      btn.setAttribute("removable", "false");
+      gLazyArea.customizationTarget = gLazyArea;
+      CustomizableUI.registerToolbarNode(gLazyArea, []);
+      assertAreaPlacements(kLazyAreaId, [], "Placements should no longer include widget.");
+      is(btn.parentNode.id, gNavBar.customizationTarget.id,
+         "Button shouldn't actually have moved as it's not removable");
+    },
+    teardown: function() {
+      let btn = document.getElementById(kButtonId);
+      if (btn) btn.remove();
+      CustomizableUI.removeWidgetFromArea(kButtonId);
+      CustomizableUI.unregisterArea(kLazyAreaId);
+      gLazyArea.remove();
+    }
+  }
+];
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_887438_currentset_shim.js b/browser/components/customizableui/test/browser_887438_currentset_shim.js
new file mode 100644
index 0000000000000000000000000000000000000000..f469df0aa7d5f017505b2ab620555ffa8804e02e
--- /dev/null
+++ b/browser/components/customizableui/test/browser_887438_currentset_shim.js
@@ -0,0 +1,84 @@
+/* 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/. */
+
+let navbar = document.getElementById("nav-bar")
+let navbarCT = navbar.customizationTarget;
+let overflowPanelList = document.getElementById("widget-overflow-list");
+let gTests = [
+  {
+    desc: "Reading currentset",
+    run: function() {
+      let nodeIds = [];
+      for (let node of navbarCT.childNodes) {
+        if (node.getAttribute("skipintoolbarset") != "true") {
+          nodeIds.push(node.id);
+        }
+      }
+      for (let node of overflowPanelList.childNodes) {
+        if (node.getAttribute("skipintoolbarset") != "true") {
+          nodeIds.push(node.id);
+        }
+      }
+      let currentSet = navbar.currentSet;
+      is(currentSet.split(',').length, nodeIds.length, "Should be just as many nodes as there are.");
+      is(currentSet, nodeIds.join(','), "Current set and node IDs should match.");
+    }
+  },
+  {
+    desc: "Insert, then remove items",
+    run: function() {
+      let currentSet = navbar.currentSet;
+      let newCurrentSet = currentSet.replace('home-button', 'feed-button,sync-button,home-button');
+      navbar.currentSet = newCurrentSet;
+      is(newCurrentSet, navbar.currentSet, "Current set should match expected current set.");
+      let feedBtn = document.getElementById("feed-button");
+      let syncBtn = document.getElementById("sync-button");
+      ok(feedBtn, "Feed button should have been added.");
+      ok(syncBtn, "Sync button should have been added.");
+      if (feedBtn && syncBtn) {
+        let feedParent = feedBtn.parentNode;
+        let syncParent = syncBtn.parentNode;
+        ok(feedParent == navbarCT || feedParent == overflowPanelList,
+           "Feed button should be in navbar or overflow");
+        ok(syncParent == navbarCT || syncParent == overflowPanelList,
+           "Feed button should be in navbar or overflow");
+        is(feedBtn.nextElementSibling, syncBtn, "Feed button should be next to sync button.");
+        let homeBtn = document.getElementById("home-button");
+        is(syncBtn.nextElementSibling, homeBtn, "Sync button should be next to home button.");
+      }
+      navbar.currentSet = currentSet;
+      is(currentSet, navbar.currentSet, "Should be able to remove the added items.");
+    }
+  },
+  {
+    desc: "Simultaneous insert/remove:",
+    run: function() {
+      let currentSet = navbar.currentSet;
+      let newCurrentSet = currentSet.replace('home-button', 'feed-button');
+      navbar.currentSet = newCurrentSet;
+      is(newCurrentSet, navbar.currentSet, "Current set should match expected current set.");
+      let feedBtn = document.getElementById("feed-button");
+      ok(feedBtn, "Feed button should have been added.");
+      let homeBtn = document.getElementById("home-button");
+      ok(!homeBtn, "Home button should have been removed.");
+      if (feedBtn) {
+        let feedParent = feedBtn.parentNode;
+        ok(feedParent == navbarCT || feedParent == overflowPanelList,
+           "Feed button should be in navbar or overflow");
+      }
+      navbar.currentSet = currentSet;
+      is(currentSet, navbar.currentSet, "Should be able to return to original state.");
+    }
+  }
+];
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
+
diff --git a/browser/components/customizableui/test/browser_888817_currentset_updating.js b/browser/components/customizableui/test/browser_888817_currentset_updating.js
new file mode 100644
index 0000000000000000000000000000000000000000..2d70a6152267b289a210aff30b1f10f744fad1af
--- /dev/null
+++ b/browser/components/customizableui/test/browser_888817_currentset_updating.js
@@ -0,0 +1,65 @@
+/* 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/. */
+
+let gTests = [
+  {
+    desc: "Adding, moving and removing items should update the relevant currentset attributes",
+    setup: function() {
+      let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
+      setToolbarVisibility(personalbar, true);
+    },
+    run: function() {
+      ok(CustomizableUI.inDefaultState, "Should be in the default state when we start");
+
+      let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+      let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
+      let navbarCurrentset = navbar.getAttribute("currentset") || navbar.currentSet;
+      let personalbarCurrentset = personalbar.getAttribute("currentset") || personalbar.currentSet;
+
+      let otherWin = yield openAndLoadWindow();
+      let otherNavbar = otherWin.document.getElementById(CustomizableUI.AREA_NAVBAR);
+      let otherPersonalbar = otherWin.document.getElementById(CustomizableUI.AREA_BOOKMARKS);
+
+      CustomizableUI.moveWidgetWithinArea("home-button", 0);
+      navbarCurrentset = "home-button," + navbarCurrentset.replace(",home-button", "");
+      is(navbar.getAttribute("currentset"), navbarCurrentset,
+         "Should have updated currentSet after move.");
+      is(otherNavbar.getAttribute("currentset"), navbarCurrentset,
+         "Should have updated other window's currentSet after move.");
+
+      CustomizableUI.addWidgetToArea("home-button", CustomizableUI.AREA_BOOKMARKS);
+      navbarCurrentset = navbarCurrentset.replace("home-button,", "");
+      personalbarCurrentset = personalbarCurrentset + ",home-button";
+      is(navbar.getAttribute("currentset"), navbarCurrentset,
+         "Should have updated navbar currentSet after implied remove.");
+      is(otherNavbar.getAttribute("currentset"), navbarCurrentset,
+         "Should have updated other window's navbar currentSet after implied remove.");
+      is(personalbar.getAttribute("currentset"), personalbarCurrentset,
+         "Should have updated personalbar currentSet after add.");
+      is(otherPersonalbar.getAttribute("currentset"), personalbarCurrentset,
+         "Should have updated other window's personalbar currentSet after add.");
+
+      CustomizableUI.removeWidgetFromArea("home-button");
+      personalbarCurrentset = personalbarCurrentset.replace(",home-button", "");
+      is(personalbar.getAttribute("currentset"), personalbarCurrentset,
+         "Should have updated currentSet after remove.");
+      is(otherPersonalbar.getAttribute("currentset"), personalbarCurrentset,
+         "Should have updated other window's currentSet after remove.");
+
+      otherWin.close();
+      // Reset in asyncCleanup will put our button back for us.
+    }
+  }
+];
+
+function asyncCleanup() {
+  let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
+  setToolbarVisibility(personalbar, false);
+  yield resetCustomization();
+}
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js b/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
new file mode 100644
index 0000000000000000000000000000000000000000..601c59ecd5c2b6f0c715a240895e0dcf15609fb9
--- /dev/null
+++ b/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
@@ -0,0 +1,135 @@
+/* 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/. */
+
+let gTests = [
+  {
+    desc: "One orphaned item should have two placeholders next to it.",
+    setup: startCustomizing,
+    run: function() {
+      let btn = document.getElementById("developer-button");
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+
+      let placementsAfterAppend = placements.concat(["developer-button"]);
+      simulateItemDrag(btn, panel);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders before exiting");
+
+      yield endCustomizing();
+      yield startCustomizing();
+      is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders after re-entering");
+
+      let palette = document.getElementById("customization-palette");
+      simulateItemDrag(btn, palette);
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+  {
+    desc: "Two orphaned items should have one placeholder next to them (case 1).",
+    setup: startCustomizing,
+    run: function() {
+      let btn = document.getElementById("developer-button");
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+
+      let placementsAfterAppend = placements.concat(["developer-button", "sync-button"]);
+      simulateItemDrag(btn, panel);
+      btn = document.getElementById("sync-button");
+      simulateItemDrag(btn, panel);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders before exiting");
+
+      yield endCustomizing();
+      yield startCustomizing();
+      is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders after re-entering");
+
+      let palette = document.getElementById("customization-palette");
+      simulateItemDrag(btn, palette);
+      btn = document.getElementById("developer-button");
+      simulateItemDrag(btn, palette);
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+  {
+    desc: "Two orphaned items should have one placeholder next to them (case 2).",
+    setup: startCustomizing,
+    run: function() {
+      let btn = document.getElementById("add-ons-button");
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      let palette = document.getElementById("customization-palette");
+      let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+
+      let placementsAfterAppend = placements.filter(p => p != btn.id);
+      simulateItemDrag(btn, palette);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders before exiting");
+
+      yield endCustomizing();
+      yield startCustomizing();
+      is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders after re-entering");
+
+      simulateItemDrag(btn, panel);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+  {
+    desc: "A wide widget at the bottom of the panel should have three placeholders after it.",
+    setup: startCustomizing,
+    run: function() {
+      let btn = document.getElementById("edit-controls");
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+
+      let placementsAfterAppend = placements.concat([placements.shift()]);
+      simulateItemDrag(btn, panel);
+      assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
+      ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
+      is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders before exiting");
+
+      yield endCustomizing();
+      yield startCustomizing();
+      is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering");
+
+      let zoomControls = document.getElementById("zoom-controls");
+      simulateItemDrag(btn, zoomControls);
+      ok(CustomizableUI.inDefaultState, "Should be in default state again.");
+    },
+  },
+  {
+    desc: "The default placements should have three placeholders at the bottom.",
+    setup: startCustomizing,
+    run: function() {
+      let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+      ok(CustomizableUI.inDefaultState, "Should be in default state.");
+      is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders before exiting");
+
+      yield endCustomizing();
+      yield startCustomizing();
+      is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering");
+
+      ok(CustomizableUI.inDefaultState, "Should still be in default state.");
+    },
+  },
+];
+
+function asyncCleanup() {
+  yield endCustomizing();
+  Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck");
+  yield resetCustomization();
+}
+
+function test() {
+  Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
+
+function getVisiblePlaceholderCount(aPanel) {
+  let visiblePlaceholders = aPanel.querySelectorAll(".panel-customization-placeholder:not([hidden=true])");
+  return visiblePlaceholders.length;
+}
diff --git a/browser/components/customizableui/test/browser_890262_destroyWidget_after_add_to_panel.js b/browser/components/customizableui/test/browser_890262_destroyWidget_after_add_to_panel.js
new file mode 100644
index 0000000000000000000000000000000000000000..d3bcf96b01eb5c74bfef6d5c10005fd3f0898ed9
--- /dev/null
+++ b/browser/components/customizableui/test/browser_890262_destroyWidget_after_add_to_panel.js
@@ -0,0 +1,75 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const kLazyAreaId = "test-890262-lazy-area";
+const kWidget1Id  = "test-890262-widget1";
+const kWidget2Id  = "test-890262-widget2";
+
+let gTests = [
+  {
+    desc: "Destroying a widget after defaulting it to a non-legacy area should work.",
+    run: function() {
+      CustomizableUI.createWidget({
+        id: kWidget1Id,
+        removable: true,
+        defaultArea: kLazyAreaId
+      });
+      let noError = true;
+      try {
+        CustomizableUI.destroyWidget(kWidget1Id);
+      } catch (ex) {
+        Cu.reportError(ex);
+        noError = false;
+      }
+      ok(noError, "Shouldn't throw an exception for a widget that was created in a not-yet-constructed area");
+    }
+  },
+  {
+    desc: "Destroying a widget after moving it to a non-legacy area should work.",
+    run: function() {
+      CustomizableUI.createWidget({
+        id: kWidget2Id,
+        removable: true,
+        defaultArea: CustomizableUI.AREA_NAVBAR
+      });
+
+      CustomizableUI.addWidgetToArea(kWidget2Id, kLazyAreaId);
+      let noError = true;
+      try {
+        CustomizableUI.destroyWidget(kWidget2Id);
+      } catch (ex) {
+        Cu.reportError(ex);
+        noError = false;
+      }
+      ok(noError, "Shouldn't throw an exception for a widget that was added to a not-yet-constructed area");
+    }
+  }
+];
+
+function asyncCleanup() {
+  let lazyArea = document.getElementById(kLazyAreaId);
+  if (lazyArea) {
+    lazyArea.remove();
+  }
+  try {
+    CustomizableUI.unregisterArea(kLazyAreaId);
+  } catch (ex) {} // If we didn't register successfully for some reason
+  yield resetCustomization();
+}
+
+function setupArea() {
+  let lazyArea = document.createElementNS(kNSXUL, "hbox");
+  lazyArea.id = kLazyAreaId;
+  document.getElementById("nav-bar").appendChild(lazyArea);
+  CustomizableUI.registerArea(kLazyAreaId, {
+    type: CustomizableUI.TYPE_TOOLBAR,
+    defaultPlacements: []
+  });
+}
+
+function test() {
+  waitForExplicitFinish();
+  setupArea();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_892955_isWidgetRemovable_for_removed_widgets.js b/browser/components/customizableui/test/browser_892955_isWidgetRemovable_for_removed_widgets.js
new file mode 100644
index 0000000000000000000000000000000000000000..b8023845dab57bfc03e60a0de1ea2bbc551bc702
--- /dev/null
+++ b/browser/components/customizableui/test/browser_892955_isWidgetRemovable_for_removed_widgets.js
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const kWidgetId = "test-892955-remove-widget";
+
+let gTests = [
+  {
+    desc: "Removing a destroyed widget should work.",
+    run: function() {
+      let widgetSpec = {
+        id: kWidgetId,
+        defaultArea: CustomizableUI.AREA_NAVBAR
+      };
+
+      CustomizableUI.createWidget(widgetSpec);
+      CustomizableUI.destroyWidget(kWidgetId);
+      let noError = true;
+      try {
+        CustomizableUI.removeWidgetFromArea(kWidgetId);
+      } catch (ex) {
+        noError = false;
+        Cu.reportError(ex);
+      }
+      ok(noError, "Shouldn't throw an error removing a destroyed widget.");
+    }
+  }
+];
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_892956_destroyWidget_defaultPlacements.js b/browser/components/customizableui/test/browser_892956_destroyWidget_defaultPlacements.js
new file mode 100644
index 0000000000000000000000000000000000000000..c678fd7130dc18e87579e70ea00b5ff29bc53529
--- /dev/null
+++ b/browser/components/customizableui/test/browser_892956_destroyWidget_defaultPlacements.js
@@ -0,0 +1,31 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const kWidgetId = "test-892956-destroyWidget-defaultPlacement";
+
+let gTests = [
+  {
+    desc: "destroyWidget should clean up defaultPlacements if the widget had a defaultArea",
+    run: function() {
+      ok(CustomizableUI.inDefaultState, "Should be in the default state when we start");
+
+      let widgetSpec = {
+        id: kWidgetId,
+        defaultArea: CustomizableUI.AREA_NAVBAR
+      };
+      CustomizableUI.createWidget(widgetSpec);
+      CustomizableUI.destroyWidget(kWidgetId);
+      ok(CustomizableUI.inDefaultState, "Should be in the default state when we finish");
+    }
+  }
+];
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js b/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js
new file mode 100644
index 0000000000000000000000000000000000000000..30a07c73918608df7bf7d49958c6a8cd6c0d9479
--- /dev/null
+++ b/browser/components/customizableui/test/browser_909779_overflow_toolbars_new_window.js
@@ -0,0 +1,38 @@
+/* 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/. */
+
+let gTests = [
+  {
+    desc: "Resize to a small window, open a new window, check that new window handles overflow properly",
+    run: function() {
+      let originalWindowWidth = window.outerWidth;
+      let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+      ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
+      let oldChildCount = navbar.customizationTarget.childElementCount;
+      window.resizeTo(400, window.outerHeight);
+      yield waitForCondition(() => navbar.hasAttribute("overflowing"));
+      ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
+
+      ok(navbar.customizationTarget.childElementCount < oldChildCount, "Should have fewer children.");
+      let newWindow = yield openAndLoadWindow();
+      let otherNavBar = newWindow.document.getElementById(CustomizableUI.AREA_NAVBAR);
+      yield waitForCondition(() => otherNavBar.hasAttribute("overflowing"));
+      ok(otherNavBar.hasAttribute("overflowing"), "Other window should have an overflowing toolbar.");
+      newWindow.close();
+
+      window.resizeTo(originalWindowWidth, window.outerHeight);
+      yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
+      ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar.");
+    }
+  }
+];
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_913972_currentset_overflow.js b/browser/components/customizableui/test/browser_913972_currentset_overflow.js
new file mode 100644
index 0000000000000000000000000000000000000000..4c16166e2b5625a4ad89fcacce07e570b04a5e82
--- /dev/null
+++ b/browser/components/customizableui/test/browser_913972_currentset_overflow.js
@@ -0,0 +1,62 @@
+/* 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/. */
+
+let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+let gTests = [
+  {
+    desc: "Resize to a small window, resize back, shouldn't affect currentSet",
+    run: function() {
+      let originalWindowWidth = window.outerWidth;
+      let oldCurrentSet = navbar.currentSet;
+      ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
+      ok(CustomizableUI.inDefaultState, "Should start in default state.");
+      let oldChildCount = navbar.customizationTarget.childElementCount;
+      window.resizeTo(400, window.outerHeight);
+      yield waitForCondition(() => navbar.hasAttribute("overflowing"));
+      ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
+      is(navbar.currentSet, oldCurrentSet, "Currentset should be the same when overflowing.");
+      ok(CustomizableUI.inDefaultState, "Should still be in default state when overflowing.");
+      ok(navbar.customizationTarget.childElementCount < oldChildCount, "Should have fewer children.");
+      window.resizeTo(originalWindowWidth, window.outerHeight);
+      yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
+      ok(!navbar.hasAttribute("overflowing"), "Should no longer have an overflowing toolbar.");
+      is(navbar.currentSet, oldCurrentSet, "Currentset should still be the same now we're no longer overflowing.");
+      ok(CustomizableUI.inDefaultState, "Should still be in default state now we're no longer overflowing.");
+
+      // Verify actual physical placements match those of the placement array:
+      let placementCounter = 0;
+      let placements = CustomizableUI.getWidgetIdsInArea(CustomizableUI.AREA_NAVBAR);
+      for (let node of navbar.customizationTarget.childNodes) {
+        if (node.getAttribute("skipintoolbarset") == "true") {
+          continue;
+        }
+        is(placements[placementCounter++], node.id, "Nodes should match after overflow");
+      }
+      is(placements.length, placementCounter, "Should have as many nodes as expected");
+      is(navbar.customizationTarget.childElementCount, oldChildCount, "Number of nodes should match");
+    }
+  },
+  {
+    desc: "Enter and exit customization mode, check that currentSet works",
+    run: function() {
+      let oldCurrentSet = navbar.currentSet;
+      ok(CustomizableUI.inDefaultState, "Should start in default state.");
+      yield startCustomizing();
+      ok(CustomizableUI.inDefaultState, "Should be in default state in customization mode.");
+      is(navbar.currentSet, oldCurrentSet, "Currentset should be the same in customization mode.");
+      yield endCustomizing();
+      ok(CustomizableUI.inDefaultState, "Should be in default state after customization mode.");
+      is(navbar.currentSet, oldCurrentSet, "Currentset should be the same after customization mode.");
+    }
+  }
+];
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_914138_widget_API_overflowable_toolbar.js b/browser/components/customizableui/test/browser_914138_widget_API_overflowable_toolbar.js
new file mode 100644
index 0000000000000000000000000000000000000000..7534f617c7580e187fa1c520b1a43684e12d267a
--- /dev/null
+++ b/browser/components/customizableui/test/browser_914138_widget_API_overflowable_toolbar.js
@@ -0,0 +1,171 @@
+/* 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/. */
+
+let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR);
+let overflowList = document.getElementById(navbar.getAttribute("overflowtarget"));
+
+const kTestBtn1 = "test-addWidgetToArea-overflow";
+const kTestBtn2 = "test-removeWidgetFromArea-overflow";
+const kHomeBtn = "home-button";
+const kDownloadsBtn = "downloads-button";
+const kSearchBox = "search-container";
+const kStarBtn = "bookmarks-menu-button";
+
+let originalWindowWidth;
+
+let gTests = [
+  {
+    desc: "Adding a widget should add it next to the widget it's being inserted next to.",
+    setup: function() {
+      originalWindowWidth = window.outerWidth;
+      createDummyXULButton(kTestBtn1, "Test");
+    },
+    run: function() {
+      ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
+      ok(CustomizableUI.inDefaultState, "Should start in default state.");
+
+      window.resizeTo(400, window.outerHeight);
+      yield waitForCondition(() => navbar.hasAttribute("overflowing"));
+      ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
+      ok(!navbar.querySelector("#" + kHomeBtn), "Home button should no longer be in the navbar");
+      ok(overflowList.querySelector("#" + kHomeBtn), "Home button should be overflowing");
+
+      let placementOfHomeButton = CustomizableUI.getWidgetIdsInArea(navbar.id).indexOf(kHomeBtn);
+      CustomizableUI.addWidgetToArea(kTestBtn1, navbar.id, placementOfHomeButton);
+      ok(!navbar.querySelector("#" + kTestBtn1), "New button should not be in the navbar");
+      ok(overflowList.querySelector("#" + kTestBtn1), "New button should be overflowing");
+      let nextEl = document.getElementById(kTestBtn1).nextSibling;
+      is(nextEl && nextEl.id, kHomeBtn, "Test button should be next to home button.");
+
+      window.resizeTo(originalWindowWidth, window.outerHeight);
+      yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
+      ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar.");
+      ok(navbar.querySelector("#" + kHomeBtn), "Home button should be in the navbar");
+      ok(!overflowList.querySelector("#" + kHomeBtn), "Home button should no longer be overflowing");
+      ok(navbar.querySelector("#" + kTestBtn1), "Test button should be in the navbar");
+      ok(!overflowList.querySelector("#" + kTestBtn1), "Test button should no longer be overflowing");
+    },
+    teardown: function() {
+      let el = document.getElementById(kTestBtn1);
+      if (el) {
+        CustomizableUI.removeWidgetFromArea(kTestBtn1);
+        el.remove();
+      }
+      window.resizeTo(originalWindowWidth, window.outerHeight);
+    }
+  },
+  {
+    desc: "Removing a widget from the toolbar should try to move items back.",
+    setup: function() {
+      // This is pretty weird. We're going to try to move only the home button into the overlay:
+      let downloadsBtn = document.getElementById(kDownloadsBtn);
+      // Guarantee overflow of too much stuff:
+      window.resizeTo(700, window.outerHeight);
+      let inc = 15;
+      while (window.outerWidth < originalWindowWidth &&
+             downloadsBtn.parentNode != navbar.customizationTarget) {
+        window.resizeTo(window.outerWidth + inc, window.outerHeight);
+        yield waitFor(500);
+      }
+    },
+    run: function() {
+      ok(overflowList.querySelector("#home-button"), "Home button should be overflowing");
+      CustomizableUI.removeWidgetFromArea("downloads-button");
+      is(document.getElementById("home-button").parentNode, navbar.customizationTarget, "Home button should move back.");
+      ok(!navbar.hasAttribute("overflowing"), "Navbar is no longer overflowing");
+    },
+    teardown: function() {
+      window.resizeTo(originalWindowWidth, window.outerHeight);
+      yield waitForCondition(function() !navbar.hasAttribute("overflowing"));
+      CustomizableUI.reset();
+    }
+  },
+  {
+    desc: "Removing a widget should remove it from the overflow list if that is where it is, and update it accordingly.",
+    setup: function() {
+      createDummyXULButton(kTestBtn2, "Test");
+    },
+    run: function() {
+      ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
+      ok(CustomizableUI.inDefaultState, "Should start in default state.");
+      CustomizableUI.addWidgetToArea(kTestBtn2, navbar.id);
+      ok(!navbar.hasAttribute("overflowing"), "Should still have a non-overflowing toolbar.");
+
+      window.resizeTo(400, window.outerHeight);
+      yield waitForCondition(() => navbar.hasAttribute("overflowing"));
+      ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar.");
+      ok(!navbar.querySelector("#" + kTestBtn2), "Test button should not be in the navbar");
+      ok(overflowList.querySelector("#" + kTestBtn2), "Test button should be overflowing");
+
+      CustomizableUI.removeWidgetFromArea(kTestBtn2);
+
+      ok(!overflowList.querySelector("#" + kTestBtn2), "Test button should not be overflowing.");
+      ok(!navbar.querySelector("#" + kTestBtn2), "Test button should not be in the navbar");
+      ok(gNavToolbox.palette.querySelector("#" + kTestBtn2), "Test button should be in the palette");
+
+      window.resizeTo(originalWindowWidth, window.outerHeight);
+      yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
+      ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar.");
+    },
+    teardown: function() {
+      let el = document.getElementById(kTestBtn2);
+      if (el) {
+        CustomizableUI.removeWidgetFromArea(kTestBtn2);
+        el.remove();
+      }
+      window.resizeTo(originalWindowWidth, window.outerHeight);
+    }
+  },
+  {
+    desc: "Overflow everything that can, then reorganize that list",
+    setup: function() {
+      ok(!navbar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar.");
+      ok(CustomizableUI.inDefaultState, "Should start in default state.");
+
+      window.resizeTo(480, window.outerHeight);
+      yield waitForCondition(() => navbar.hasAttribute("overflowing"));
+      ok(!navbar.querySelector("#" + kSearchBox), "Search container should be overflowing");
+    },
+    run: function() {
+      let placements = CustomizableUI.getWidgetIdsInArea(navbar.id);
+      let searchboxPlacement = placements.indexOf(kSearchBox);
+      CustomizableUI.moveWidgetWithinArea(kHomeBtn, searchboxPlacement);
+      yield waitForCondition(() => navbar.querySelector("#" + kHomeBtn));
+      ok(navbar.querySelector("#" + kHomeBtn), "Home button should have moved back");
+      let inc = 15;
+      window.resizeTo(640, window.outerHeight);
+      while (window.outerWidth < originalWindowWidth &&
+             !navbar.querySelector("#" + kSearchBox)) {
+        window.resizeTo(window.outerWidth + inc, window.outerHeight);
+        yield waitFor(500);
+      }
+      ok(!navbar.querySelector("#" + kStarBtn), "Star button should still be overflowed");
+      CustomizableUI.moveWidgetWithinArea(kStarBtn);
+      let starButtonOverflowed = overflowList.querySelector("#" + kStarBtn);
+      ok(starButtonOverflowed && !starButtonOverflowed.nextSibling, "Star button should be last item");
+      window.resizeTo(window.outerWidth + 15, window.outerHeight);
+      yield waitForCondition(() => navbar.querySelector("#" + kDownloadsBtn) && navbar.hasAttribute("overflowing"));
+      ok(navbar.hasAttribute("overflowing"), "navbar should still be overflowing");
+      CustomizableUI.moveWidgetWithinArea(kHomeBtn);
+      let homeButtonOverflowed = overflowList.querySelector("#" + kHomeBtn);
+      ok(homeButtonOverflowed, "Home button should be in overflow list");
+      ok(navbar.hasAttribute("overflowing"), "navbar should still be overflowing");
+      ok(homeButtonOverflowed && !homeButtonOverflowed.nextSibling, "Home button should be last item");
+    },
+    teardown: function() {
+      window.resizeTo(originalWindowWidth, window.outerHeight);
+      yield waitForCondition(() => !navbar.hasAttribute("overflowing"));
+      ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar.");
+    }
+  }
+];
+
+function asyncCleanup() {
+  yield resetCustomization();
+}
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_914863_disabled_help_quit_buttons.js b/browser/components/customizableui/test/browser_914863_disabled_help_quit_buttons.js
new file mode 100644
index 0000000000000000000000000000000000000000..e3d3f23b4860482a4dad702e46be844974f2b388
--- /dev/null
+++ b/browser/components/customizableui/test/browser_914863_disabled_help_quit_buttons.js
@@ -0,0 +1,26 @@
+/* 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/. */
+
+let gTests = [
+  {
+    desc: "Entering then exiting customization mode should reenable the Help and Exit buttons.",
+    run: function() {
+      yield startCustomizing();
+      let helpButton = document.getElementById("PanelUI-help");
+      let quitButton = document.getElementById("PanelUI-quit");
+      ok(helpButton.getAttribute("disabled") == "true", "Help button should be disabled while in customization mode.");
+      ok(quitButton.getAttribute("disabled") == "true", "Quit button should be disabled while in customization mode.");
+      yield endCustomizing();
+
+      ok(!helpButton.hasAttribute("disabled"), "Help button should not be disabled.");
+      ok(!quitButton.hasAttribute("disabled"), "Quit button should not be disabled.");
+    }
+  },
+];
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests);
+}
+
diff --git a/browser/components/customizableui/test/browser_918049_skipintoolbarset_dnd.js b/browser/components/customizableui/test/browser_918049_skipintoolbarset_dnd.js
new file mode 100644
index 0000000000000000000000000000000000000000..291133a72a2b0c0557a4a86dca5462968bbf428d
--- /dev/null
+++ b/browser/components/customizableui/test/browser_918049_skipintoolbarset_dnd.js
@@ -0,0 +1,46 @@
+/* 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/. */
+
+let navbar;
+let skippedItem;
+let gTests = [
+  {
+    desc: "Attempting to drag a skipintoolbarset item should work.",
+    setup: function() {
+      navbar = document.getElementById("nav-bar");
+      skippedItem = document.createElement("toolbarbutton");
+      skippedItem.id = "test-skipintoolbarset-item";
+      skippedItem.setAttribute("label", "Test");
+      skippedItem.setAttribute("skipintoolbarset", "true");
+      navbar.customizationTarget.appendChild(skippedItem);
+    },
+    run: function() {
+      let downloadsButton = document.getElementById("downloads-button");
+      yield startCustomizing();
+      ok(CustomizableUI.inDefaultState, "Should still be in default state");
+      simulateItemDrag(skippedItem, downloadsButton);
+      ok(CustomizableUI.inDefaultState, "Should still be in default state");
+      let skippedItemWrapper = skippedItem.parentNode;
+      is(skippedItemWrapper.nextSibling && skippedItemWrapper.nextSibling.id,
+         downloadsButton.parentNode.id, "Should be next to downloads button");
+      simulateItemDrag(downloadsButton, skippedItem);
+      let downloadWrapper = downloadsButton.parentNode;
+      is(downloadWrapper.nextSibling && downloadWrapper.nextSibling.id,
+         skippedItem.parentNode.id, "Should be next to skipintoolbarset item");
+      ok(CustomizableUI.inDefaultState, "Should still be in default state");
+    }
+  },
+];
+function asyncCleanup() {
+  yield endCustomizing();
+  skippedItem.remove();
+  Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck");
+  yield resetCustomization();
+}
+
+function test() {
+  Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_923857_customize_mode_event_wrapping_during_reset.js b/browser/components/customizableui/test/browser_923857_customize_mode_event_wrapping_during_reset.js
new file mode 100644
index 0000000000000000000000000000000000000000..8f6d523799e5a1291e421a71603543cce10bffa0
--- /dev/null
+++ b/browser/components/customizableui/test/browser_923857_customize_mode_event_wrapping_during_reset.js
@@ -0,0 +1,38 @@
+/* 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/. */
+
+let gTests = [
+  {
+    desc: "Customize mode reset button should revert correctly",
+    setup: function() {
+      yield startCustomizing();
+    },
+    run: function() {
+      let devButton = document.getElementById("developer-button");
+      let downloadsButton = document.getElementById("downloads-button");
+      let searchBox = document.getElementById("search-container");
+      let palette = document.getElementById("customization-palette");
+      ok(devButton && downloadsButton && searchBox && palette, "Stuff should exist");
+      simulateItemDrag(devButton, downloadsButton);
+      simulateItemDrag(searchBox, palette);
+      gCustomizeMode.reset();
+      yield waitForCondition(function() !gCustomizeMode.resetting);
+      ok(CustomizableUI.inDefaultState, "Should be back in default state");
+    },
+    teardown: function() {
+      yield endCustomizing();
+    }
+  }
+];
+
+function asyncCleanup() {
+  Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck");
+  yield resetCustomization();
+}
+
+function test() {
+  Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_927717_customize_drag_empty_toolbar.js b/browser/components/customizableui/test/browser_927717_customize_drag_empty_toolbar.js
new file mode 100644
index 0000000000000000000000000000000000000000..1f39e2971da83857a326d66c7a66e3253d96e6fd
--- /dev/null
+++ b/browser/components/customizableui/test/browser_927717_customize_drag_empty_toolbar.js
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const kTestToolbarId = "test-empty-drag";
+let gTests = [
+  {
+    desc: "Attempting to drag an item to an empty container should work.",
+    setup: function() {
+      createToolbarWithPlacements(kTestToolbarId, "");
+    },
+    run: function() {
+      yield startCustomizing();
+      let downloadButton = document.getElementById("downloads-button");
+      let customToolbar = document.getElementById(kTestToolbarId);
+      simulateItemDrag(downloadButton, customToolbar);
+      assertAreaPlacements(kTestToolbarId, ["downloads-button"]);
+      ok(downloadButton.parentNode && downloadButton.parentNode.parentNode == customToolbar,
+         "Button should really be in toolbar");
+    },
+    teardown: function() {
+      yield endCustomizing();
+      removeCustomToolbars();
+    }
+  },
+];
+function asyncCleanup() {
+  yield endCustomizing();
+  Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck");
+  yield resetCustomization();
+}
+
+function test() {
+  Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_934113_menubar_removable.js b/browser/components/customizableui/test/browser_934113_menubar_removable.js
new file mode 100644
index 0000000000000000000000000000000000000000..bb08283c6a764172d492411143cff6fc71b324af
--- /dev/null
+++ b/browser/components/customizableui/test/browser_934113_menubar_removable.js
@@ -0,0 +1,32 @@
+/* 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/. */
+
+let gTests = [
+  {
+    desc: "Attempting to drag the menubar to the navbar shouldn't work.",
+    setup: startCustomizing,
+    run: function() {
+      let menuItems = document.getElementById("menubar-items");
+      let navbar = document.getElementById("nav-bar");
+      let menubar = document.getElementById("toolbar-menubar");
+      simulateItemDrag(menuItems, navbar.customizationTarget);
+      is(getAreaWidgetIds("nav-bar").indexOf("menubar-items"), -1, "Menu bar shouldn't be in the navbar.");
+      ok(!navbar.querySelector("#menubar-items"), "Shouldn't find menubar items in the navbar.");
+      ok(menubar.querySelector("#menubar-items"), "Should find menubar items in the menubar.");
+      isnot(getAreaWidgetIds("toolbar-menubar").indexOf("menubar-items"), -1, "Menubar items shouldn't be missing from the navbar.");
+    },
+    teardown: endCustomizing
+  },
+];
+function asyncCleanup() {
+  yield endCustomizing();
+  Services.prefs.clearUserPref("browser.uiCustomization.skipSourceNodeCheck");
+  yield resetCustomization();
+}
+
+function test() {
+  Services.prefs.setBoolPref("browser.uiCustomization.skipSourceNodeCheck", true);
+  waitForExplicitFinish();
+  runTests(gTests, asyncCleanup);
+}
diff --git a/browser/components/customizableui/test/browser_panel_toggle.js b/browser/components/customizableui/test/browser_panel_toggle.js
new file mode 100644
index 0000000000000000000000000000000000000000..2e6ef6ce84b4f2ce686bc938f02205017e3260dd
--- /dev/null
+++ b/browser/components/customizableui/test/browser_panel_toggle.js
@@ -0,0 +1,53 @@
+/* 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/. */
+
+/**
+ * Test opening and closing the menu panel UI.
+ */
+
+let gTests = [
+  {
+    desc: "Show and hide the menu panel programmatically without an event (like UITour.jsm would)",
+    setup: null,
+    run: function() {
+      let shownPromise = promisePanelShown(window);
+      PanelUI.show();
+      yield shownPromise;
+
+      is(PanelUI.panel.getAttribute("panelopen"), "true", "Check that panel has panelopen attribute");
+      is(PanelUI.panel.state, "open", "Check that panel state is 'open'");
+
+      let hiddenPromise = promisePanelHidden(window);
+      PanelUI.hide();
+      yield hiddenPromise;
+
+      ok(!PanelUI.panel.hasAttribute("panelopen"), "Check that panel doesn't have the panelopen attribute");
+      is(PanelUI.panel.state, "closed", "Check that panel state is 'closed'");
+    },
+  },
+  {
+    desc: "Toggle the menu panel open and closed",
+    setup: null,
+    run: function() {
+      let shownPromise = promisePanelShown(window);
+      PanelUI.toggle({type: "command"});
+      yield shownPromise;
+
+      is(PanelUI.panel.getAttribute("panelopen"), "true", "Check that panel has panelopen attribute");
+      is(PanelUI.panel.state, "open", "Check that panel state is 'open'");
+
+      let hiddenPromise = promisePanelHidden(window);
+      PanelUI.toggle({type: "command"});
+      yield hiddenPromise;
+
+      ok(!PanelUI.panel.hasAttribute("panelopen"), "Check that panel doesn't have the panelopen attribute");
+      is(PanelUI.panel.state, "closed", "Check that panel state is 'closed'");
+    },
+  },
+];
+
+function test() {
+  waitForExplicitFinish();
+  runTests(gTests);
+}
diff --git a/browser/components/customizableui/test/head.js b/browser/components/customizableui/test/head.js
new file mode 100644
index 0000000000000000000000000000000000000000..3e92df81e3879669e7fedbb523e2f8faa9c01515
--- /dev/null
+++ b/browser/components/customizableui/test/head.js
@@ -0,0 +1,254 @@
+/* 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/. */
+
+
+// Avoid leaks by using tmp for imports...
+let tmp = {};
+Cu.import("resource://gre/modules/Promise.jsm", tmp);
+Cu.import("resource://gre/modules/Task.jsm", tmp);
+Cu.import("resource:///modules/CustomizableUI.jsm", tmp);
+let {Promise, Task, CustomizableUI} = tmp;
+
+let ChromeUtils = {};
+let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader);
+scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", ChromeUtils);
+
+let {synthesizeDragStart, synthesizeDrop} = ChromeUtils;
+
+const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+function createDummyXULButton(id, label) {
+  let btn = document.createElementNS(kNSXUL, "toolbarbutton");
+  btn.id = id;
+  btn.setAttribute("label", label || id);
+  btn.className = "toolbarbutton-1 chromeclass-toolbar-additional";
+  window.gNavToolbox.palette.appendChild(btn);
+  return btn;
+}
+
+let gAddedToolbars = new Set();
+
+function createToolbarWithPlacements(id, placements) {
+  gAddedToolbars.add(id);
+  let tb = document.createElementNS(kNSXUL, "toolbar");
+  tb.id = id;
+  tb.setAttribute("customizable", "true");
+  CustomizableUI.registerArea(id, {
+    type: CustomizableUI.TYPE_TOOLBAR,
+    defaultPlacements: placements
+  });
+  gNavToolbox.appendChild(tb);
+}
+
+function removeCustomToolbars() {
+  CustomizableUI.reset();
+  for (let toolbarId of gAddedToolbars) {
+    CustomizableUI.unregisterArea(toolbarId);
+    document.getElementById(toolbarId).remove();
+  }
+  gAddedToolbars.clear();
+}
+
+function resetCustomization() {
+  return CustomizableUI.reset();
+}
+
+function assertAreaPlacements(areaId, expectedPlacements) {
+  let actualPlacements = getAreaWidgetIds(areaId);
+  is(actualPlacements.length, expectedPlacements.length,
+     "Area " + areaId + " should have " + expectedPlacements.length + " items.");
+  let minItems = Math.min(expectedPlacements.length, actualPlacements.length);
+  for (let i = 0; i < minItems; i++) {
+    if (typeof expectedPlacements[i] == "string") {
+      is(actualPlacements[i], expectedPlacements[i],
+         "Item " + i + " in " + areaId + " should match expectations.");
+    } else if (expectedPlacements[i] instanceof RegExp) {
+      ok(expectedPlacements[i].test(actualPlacements[i]),
+         "Item " + i + " (" + actualPlacements[i] + ") in " +
+         areaId + " should match " + expectedPlacements[i]); 
+    } else {
+      ok(false, "Unknown type of expected placement passed to " +
+                " assertAreaPlacements. Is your test broken?");
+    }
+  }
+}
+
+function todoAssertAreaPlacements(areaId, expectedPlacements) {
+  let actualPlacements = getAreaWidgetIds(areaId);
+  let isPassing = actualPlacements.length == expectedPlacements.length;
+  let minItems = Math.min(expectedPlacements.length, actualPlacements.length);
+  for (let i = 0; i < minItems; i++) {
+    if (typeof expectedPlacements[i] == "string") {
+      isPassing = isPassing && actualPlacements[i] == expectedPlacements[i];
+    } else if (expectedPlacements[i] instanceof RegExp) {
+      isPassing = isPassing && expectedPlacements[i].test(actualPlacements[i]);
+    } else {
+      ok(false, "Unknown type of expected placement passed to " +
+                " assertAreaPlacements. Is your test broken?");
+    }
+  }
+  todo(isPassing, "The area placements for " + areaId +
+                  " should equal the expected placements.")
+}
+
+function getAreaWidgetIds(areaId) {
+  return CustomizableUI.getWidgetIdsInArea(areaId);
+}
+
+function simulateItemDrag(toDrag, target) {
+  let docId = toDrag.ownerDocument.documentElement.id;
+  let dragData = [[{type: 'text/toolbarwrapper-id/' + docId,
+                    data: toDrag.id}]];
+  synthesizeDragStart(toDrag.parentNode, dragData);
+  synthesizeDrop(target, target, dragData);
+}
+
+function endCustomizing() {
+  if (document.documentElement.getAttribute("customizing") != "true") {
+    return true;
+  }
+  let deferredEndCustomizing = Promise.defer();
+  function onCustomizationEnds() {
+    window.gNavToolbox.removeEventListener("aftercustomization", onCustomizationEnds);
+    deferredEndCustomizing.resolve();
+  }
+  window.gNavToolbox.addEventListener("aftercustomization", onCustomizationEnds);
+  window.gCustomizeMode.exit();
+
+  return deferredEndCustomizing.promise.then(function() {
+    let deferredLoadNewTab = Promise.defer();
+
+    //XXXgijs so some tests depend on this tab being about:blank. Make it so.
+    let newTabBrowser = window.gBrowser.selectedBrowser;
+    newTabBrowser.stop();
+
+    // If we stop early enough, this might actually be about:blank.
+    if (newTabBrowser.contentDocument.location.href == "about:blank") {
+      return;
+    }
+
+    // Otherwise, make it be about:blank, and wait for that to be done.
+    function onNewTabLoaded(e) {
+      newTabBrowser.removeEventListener("load", onNewTabLoaded, true);
+      deferredLoadNewTab.resolve();
+    }
+    newTabBrowser.addEventListener("load", onNewTabLoaded, true);
+    newTabBrowser.contentDocument.location.replace("about:blank");
+    return deferredLoadNewTab.promise;
+  });
+}
+
+function startCustomizing() {
+  if (document.documentElement.getAttribute("customizing") == "true") {
+    return;
+  }
+  let deferred = Promise.defer();
+  function onCustomizing() {
+    window.gNavToolbox.removeEventListener("customizationready", onCustomizing);
+    deferred.resolve();
+  }
+  window.gNavToolbox.addEventListener("customizationready", onCustomizing);
+  window.gCustomizeMode.enter();
+  return deferred.promise;
+}
+
+function openAndLoadWindow(aOptions, aWaitForDelayedStartup=false) {
+  let deferred = Promise.defer();
+  let win = OpenBrowserWindow(aOptions);
+  if (aWaitForDelayedStartup) {
+    Services.obs.addObserver(function onDS(aSubject, aTopic, aData) {
+      if (aSubject != win) {
+        return;
+      }
+      Services.obs.removeObserver(onDS, "browser-delayed-startup-finished");
+      deferred.resolve(win);
+    }, "browser-delayed-startup-finished", false);
+
+  } else {
+    win.addEventListener("load", function onLoad() {
+      win.removeEventListener("load", onLoad);
+      deferred.resolve(win);
+    });
+  }
+  return deferred.promise;
+}
+
+function promisePanelShown(win) {
+  let panelEl = win.PanelUI.panel;
+  let deferred = Promise.defer();
+  function onPanelOpen(e) {
+    panelEl.removeEventListener("popupshown", onPanelOpen);
+    deferred.resolve();
+  };
+  panelEl.addEventListener("popupshown", onPanelOpen);
+  return deferred.promise;
+}
+
+function promisePanelHidden(win) {
+  let panelEl = win.PanelUI.panel;
+  let deferred = Promise.defer();
+  function onPanelClose(e) {
+    panelEl.removeEventListener("popuphidden", onPanelClose);
+    deferred.resolve();
+  }
+  panelEl.addEventListener("popuphidden", onPanelClose);
+  return deferred.promise;
+}
+
+function waitForCondition(aConditionFn, aMaxTries=50, aCheckInterval=100) {
+  function tryNow() {
+    tries++;
+    if (aConditionFn()) {
+      deferred.resolve();
+    } else if (tries < aMaxTries) {
+      tryAgain();
+    } else {
+      deferred.reject("Condition timed out: " + aConditionFn.toSource());
+    }
+  }
+  function tryAgain() {
+    setTimeout(tryNow, aCheckInterval);
+  }
+  let deferred = Promise.defer();
+  let tries = 0;
+  tryAgain();
+  return deferred.promise;
+}
+
+function waitFor(aTimeout=100) {
+  let deferred = Promise.defer();
+  setTimeout(function() deferred.resolve(), aTimeout);
+  return deferred.promise;
+}
+
+function testRunner(testAry, asyncCleanup) {
+  Services.prefs.setBoolPref("browser.uiCustomization.disableAnimation", true);
+  for (let test of testAry) {
+    info(test.desc);
+
+    if (test.setup)
+      yield test.setup();
+
+    info("Running test");
+    yield test.run();
+    info("Cleanup");
+    if (test.teardown)
+      yield test.teardown();
+    ok(!document.getElementById(CustomizableUI.AREA_NAVBAR).hasAttribute("overflowing"), "Shouldn't overflow");
+  }
+  if (asyncCleanup) {
+    yield asyncCleanup();
+  }
+  ok(CustomizableUI.inDefaultState, "Should remain in default state");
+  Services.prefs.clearUserPref("browser.uiCustomization.disableAnimation");
+}
+
+function runTests(testAry, asyncCleanup) {
+  Task.spawn(testRunner(gTests, asyncCleanup)).then(finish, ex => {
+    // The stack of ok() here is misleading due to Promises. The stack of the
+    // actual exception is likely much more valuable, hence concatentating it.
+    ok(false, "Unexpected exception: " + ex + " With stack: " + ex.stack);
+    finish();
+  }).then(null, Cu.reportError);
+}
diff --git a/browser/components/downloads/content/downloads.js b/browser/components/downloads/content/downloads.js
index eca4a94c6d5b02d73c80dd6bf907c33989590f07..1ec5cdbeec31dfedc1325d7d16ee43ff627366f9 100644
--- a/browser/components/downloads/content/downloads.js
+++ b/browser/components/downloads/content/downloads.js
@@ -641,11 +641,6 @@ const DownloadsOverlayLoader = {
       this._overlayLoading = false;
       this._loadedOverlays[aOverlay] = true;
 
-      // Loading the overlay causes all the persisted XUL attributes to be
-      // reapplied, including "iconsize" on the toolbars.  Until bug 640158 is
-      // fixed, we must recalculate the correct "iconsize" attributes manually.
-      retrieveToolbarIconsizesFromTheme();
-
       this.processPendingRequests();
     }
 
diff --git a/browser/components/downloads/content/indicator.js b/browser/components/downloads/content/indicator.js
index 6d31504ae61a5d0e37418910c08356fc62b9fe9e..7547b53c7a1c629fb1c6cc22f5bc6ec05b493272 100644
--- a/browser/components/downloads/content/indicator.js
+++ b/browser/components/downloads/content/indicator.js
@@ -110,10 +110,12 @@ const DownloadsButton = {
 
     indicator.open = this._anchorRequested;
 
-    // Determine if we're located on an invisible toolbar.
-    if (!isElementVisible(indicator.parentNode)) {
-      return null;
-    }
+    let widget = CustomizableUI.getWidget("downloads-button")
+                               .forWindow(window);
+     // Determine if the indicator is located on an invisible toolbar.
+     if (!isElementVisible(indicator.parentNode) && !widget.overflowed) {
+       return null;
+     }
 
     return DownloadsIndicatorView.indicatorAnchor;
   },
@@ -317,10 +319,20 @@ const DownloadsIndicatorView = {
       return;
     }
 
-    // If the anchor is not there or its container is hidden, don't show
-    // a notification
     let anchor = DownloadsButton._placeholder;
+    let widgetGroup = CustomizableUI.getWidget("downloads-button");
+    let widgetInWindow = widgetGroup.forWindow(window);
+    if (widgetInWindow.overflowed || widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) {
+      if (anchor && isElementVisible(anchor.parentNode)) {
+        // If the panel is open, don't do anything:
+        return;
+      }
+
+      // Otherwise, try to use the anchor of the panel:
+      anchor = widgetInWindow.anchor;
+    }
     if (!anchor || !isElementVisible(anchor.parentNode)) {
+      // Our container isn't visible, so can't show the animation:
       return;
     }
 
@@ -481,7 +493,14 @@ const DownloadsIndicatorView = {
 
   onCommand: function DIV_onCommand(aEvent)
   {
-    DownloadsPanel.showPanel();
+    // If the downloads button is in the menu panel, open the Library
+    let widgetGroup = CustomizableUI.getWidget("downloads-button");
+    if (widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) {
+      DownloadsPanel.showDownloadsHistory();
+    } else {
+      DownloadsPanel.showPanel();
+    }
+
     aEvent.stopPropagation();
   },
 
@@ -512,7 +531,6 @@ const DownloadsIndicatorView = {
   },
 
   _indicator: null,
-  _indicatorAnchor: null,
   __indicatorCounter: null,
   __indicatorProgress: null,
 
@@ -536,8 +554,12 @@ const DownloadsIndicatorView = {
 
   get indicatorAnchor()
   {
-    return this._indicatorAnchor ||
-      (this._indicatorAnchor = document.getElementById("downloads-indicator-anchor"));
+    let widget = CustomizableUI.getWidget("downloads-button")
+                               .forWindow(window);
+    if (widget.overflowed) {
+      return widget.anchor;
+    }
+    return document.getElementById("downloads-indicator-anchor");
   },
 
   get _indicatorCounter()
@@ -560,7 +582,6 @@ const DownloadsIndicatorView = {
 
   _onCustomizedAway: function() {
     this._indicator = null;
-    this._indicatorAnchor = null;
     this.__indicatorCounter = null;
     this.__indicatorProgress = null;
   },
diff --git a/browser/components/downloads/test/browser/browser.ini b/browser/components/downloads/test/browser/browser.ini
index 4a6cb36249a576549560697152cfcf044b392abe..11e1c49fda63b24bf6a309897dbf1aed4661fac4 100644
--- a/browser/components/downloads/test/browser/browser.ini
+++ b/browser/components/downloads/test/browser/browser.ini
@@ -3,3 +3,4 @@ support-files = head.js
 
 [browser_basic_functionality.js]
 [browser_first_download_panel.js]
+[browser_overflow_anchor.js]
diff --git a/browser/components/downloads/test/browser/browser_overflow_anchor.js b/browser/components/downloads/test/browser/browser_overflow_anchor.js
new file mode 100644
index 0000000000000000000000000000000000000000..682c39ffd967e6eb8daffceaa7ec11f772181a66
--- /dev/null
+++ b/browser/components/downloads/test/browser/browser_overflow_anchor.js
@@ -0,0 +1,115 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure the downloads button and indicator overflows into the nav-bar
+ * chevron properly, and then when those buttons are clicked in the overflow
+ * panel that the downloads panel anchors to the chevron.
+ */
+function test_task() {
+  try {
+    // Ensure that state is reset in case previous tests didn't finish.
+    yield task_resetState();
+
+    // Record the original width of the window so we can put it back when
+    // this test finishes.
+    let oldWidth = window.outerWidth;
+
+    // The downloads button should not be overflowed to begin with.
+    let button = CustomizableUI.getWidget("downloads-button")
+                               .forWindow(window);
+    ok(!button.overflowed, "Downloads button should not be overflowed.");
+
+    // Hack - we lock the size of the default flex-y items in the nav-bar,
+    // namely, the URL and search inputs. That way we can resize the
+    // window without worrying about them flexing.
+    const kFlexyItems = ["urlbar-container", "search-container"];
+    registerCleanupFunction(() => unlockWidth(kFlexyItems));
+    lockWidth(kFlexyItems);
+
+    // Resize the window to half of its original size. That should
+    // be enough to overflow the downloads button.
+    window.resizeTo(oldWidth / 2, window.outerHeight);
+    yield waitForOverflowed(button, true);
+
+    let promise = promisePanelOpened();
+    button.node.doCommand();
+    yield promise;
+
+    let panel = DownloadsPanel.panel;
+    let chevron = document.getElementById("nav-bar-overflow-button");
+    is(panel.anchorNode, chevron, "Panel should be anchored to the chevron.");
+
+    DownloadsPanel.hidePanel();
+
+    // Unlock the widths on the flex-y items.
+    unlockWidth(kFlexyItems);
+
+    // Put the window back to its original dimensions.
+    window.resizeTo(oldWidth, window.outerHeight);
+
+    // The downloads button should eventually be un-overflowed.
+    yield waitForOverflowed(button, false);
+
+    // Now try opening the panel again.
+    promise = promisePanelOpened();
+    button.node.doCommand();
+    yield promise;
+
+    is(panel.anchorNode.id, "downloads-indicator-anchor");
+
+    DownloadsPanel.hidePanel();
+  } finally {
+    // Clean up when the test finishes.
+    yield task_resetState();
+  }
+}
+
+/**
+ * For some node IDs, finds the nodes and sets their min-width's to their
+ * current width, preventing them from flex-shrinking.
+ *
+ * @param aItemIDs an array of item IDs to set min-width on.
+ */
+function lockWidth(aItemIDs) {
+  for (let itemID of aItemIDs) {
+    let item = document.getElementById(itemID);
+    let curWidth = item.getBoundingClientRect().width + "px";
+    item.style.minWidth = curWidth;
+  }
+}
+
+/**
+ * Clears the min-width's set on a set of IDs by lockWidth.
+ *
+ * @param aItemIDs an array of ItemIDs to remove min-width on.
+ */
+function unlockWidth(aItemIDs) {
+  for (let itemID of aItemIDs) {
+    let item = document.getElementById(itemID);
+    item.style.minWidth = "";
+  }
+}
+
+/**
+ * Waits for a node to enter or exit the overflowed state.
+ *
+ * @param aItem the node to wait for.
+ * @param aIsOverflowed if we're waiting for the item to be overflowed.
+ */
+function waitForOverflowed(aItem, aIsOverflowed) {
+  let deferOverflow = Promise.defer();
+  if (aItem.overflowed == aIsOverflowed) {
+    return deferOverflow.resolve();
+  }
+
+  let observer = new MutationObserver(function(aMutations) {
+    if (aItem.overflowed == aIsOverflowed) {
+      observer.disconnect();
+      deferOverflow.resolve();
+    }
+  });
+  observer.observe(aItem.node, {attributes: true});
+
+  return deferOverflow.promise;
+}
diff --git a/browser/components/moz.build b/browser/components/moz.build
index 0b7ceb049df846e13f8f3503733d0bd7c7b63f11..7284adb906f2542bbb7aedd39ddadeb7b8b2e99e 100644
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -7,6 +7,7 @@
 PARALLEL_DIRS += [
     'about',
     'certerror',
+    'customizableui',
     'dirprovider',
     'downloads',
     'feeds',
diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js
index 0faef0444a310cde5457a3984184a3da3c6c3812..f5faade1039c4b6c7f9843bc3697cd0fbada168c 100644
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1285,57 +1285,17 @@ BrowserGlue.prototype = {
   },
 
   _migrateUI: function BG__migrateUI() {
-    const UI_VERSION = 14;
+    const UI_VERSION = 17;
     const BROWSER_DOCURL = "chrome://browser/content/browser.xul#";
-
-    let wasCustomizedAndOnAustralis = Services.prefs.prefHasUserValue("browser.uiCustomization.state");
     let currentUIVersion = 0;
     try {
       currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
     } catch(ex) {}
-    if (!wasCustomizedAndOnAustralis && currentUIVersion >= UI_VERSION)
+    if (currentUIVersion >= UI_VERSION)
       return;
 
     this._rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
     this._dataSource = this._rdf.GetDataSource("rdf:local-store");
-
-    // No version check for this as this code should run until we have Australis everywhere:
-    if (wasCustomizedAndOnAustralis) {
-      // This profile's been on australis! If it's missing the back/fwd button
-      // or go/stop/reload button, then put them back:
-      let currentsetResource = this._rdf.GetResource("currentset");
-      let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar");
-      let currentset = this._getPersist(toolbarResource, currentsetResource);
-      let oldCurrentset = currentset;
-      if (currentset) {
-        if (currentset.indexOf("unified-back-forward-button") == -1) {
-          currentset = currentset.replace("urlbar-container",
-                                          "unified-back-forward-button,urlbar-container");
-        }
-        if (currentset.indexOf("reload-button") == -1) {
-          currentset = currentset.replace("urlbar-container", "urlbar-container,reload-button");
-        }
-        if (currentset.indexOf("stop-button") == -1) {
-          currentset = currentset.replace("reload-button", "reload-button,stop-button");
-        }
-      }
-      Services.prefs.clearUserPref("browser.uiCustomization.state");
-
-      if (oldCurrentset != currentset) {
-        this._setPersist(toolbarResource, currentsetResource, currentset);
-      }
-      // If we don't have anything else to do, we can bail here:
-      if (currentUIVersion >= UI_VERSION) {
-        if (this._dirty) {
-          this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();
-        }
-        delete this._rdf;
-        delete this._dataSource;
-        return;
-      }
-    }
-
-
     this._dirty = false;
 
     if (currentUIVersion < 2) {
@@ -1519,6 +1479,60 @@ BrowserGlue.prototype = {
       OS.File.remove(path);
     }
 
+    if (currentUIVersion < 15) {
+      // Migrate users from text or text&icons mode to icons mode.
+      let updateToolbars = function (aToolbarIds, aResourceName, aResourceValue) {
+        let resource = this._rdf.GetResource(aResourceName);
+        for (toolbarId of aToolbarIds) {
+          let toolbar = this._rdf.GetResource(BROWSER_DOCURL + toolbarId);
+          let oldValue = this._getPersist(toolbar, resource);
+          if (oldValue && oldValue != aResourceValue) {
+            this._setPersist(toolbar, resource, aResourceValue);
+          }
+        }
+      }.bind(this);
+
+      updateToolbars(["navigator-toolbox", "nav-bar", "PersonalToolbar", "addon-bar"], "mode", "icons");
+      // Exclude PersonalToolbar and addon-bar since they have lockiconsize="true".
+      updateToolbars(["navigator-toolbox", "nav-bar"], "iconsize", "large");
+    }
+
+    if (currentUIVersion < 16) {
+      let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar");
+      let collapsedResource = this._rdf.GetResource("collapsed");
+      let isCollapsed = this._getPersist(toolbarResource, collapsedResource);
+      if (isCollapsed == "true") {
+        this._setPersist(toolbarResource, collapsedResource, "false");
+      }
+    }
+
+    // Insert the bookmarks-menu-button into the nav-bar if it isn't already
+    // there.
+    if (currentUIVersion < 17) {
+      let currentsetResource = this._rdf.GetResource("currentset");
+      let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar");
+      let currentset = this._getPersist(toolbarResource, currentsetResource);
+      // Need to migrate only if toolbar is customized.
+      if (currentset) {
+        if (!currentset.contains("bookmarks-menu-button")) {
+          // The button isn't in the nav-bar, so let's look for an appropriate
+          // place to put it.
+          if (currentset.contains("downloads-button")) {
+            currentset = currentset.replace(/(^|,)downloads-button($|,)/,
+                                            "$1bookmarks-menu-button,downloads-button$2");
+          } else if (currentset.contains("home-button")) {
+            currentset = currentset.replace(/(^|,)home-button($|,)/,
+                                            "$1bookmarks-menu-button,home-button$2");
+          } else {
+            // Just append.
+            currentset = currentset.replace(/(^|,)window-controls($|,)/,
+                                            "$1bookmarks-menu-button,window-controls$2")
+          }
+          this._setPersist(toolbarResource, currentsetResource, currentset);
+        }
+      }
+    }
+
     if (this._dirty)
       this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();
 
diff --git a/browser/components/places/content/browserPlacesViews.js b/browser/components/places/content/browserPlacesViews.js
index 33006fc3250e683b463cf3e09a9fcd5fa802ad4d..8c5900b26c523c53cf3a38860e20df756fb21e01 100644
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -1745,3 +1745,157 @@ PlacesMenu.prototype = {
   }
 };
 
+function PlacesPanelMenuView(aPlace, aViewId, aRootId) {
+  this._viewElt = document.getElementById(aViewId);
+  this._rootElt = document.getElementById(aRootId);
+  this._viewElt._placesView = this;
+
+  PlacesViewBase.call(this, aPlace);
+}
+
+PlacesPanelMenuView.prototype = {
+  __proto__: PlacesViewBase.prototype,
+
+  QueryInterface: function PAMV_QueryInterface(aIID) {
+    return PlacesViewBase.prototype.QueryInterface.apply(this, arguments);
+  },
+
+  uninit: function PAMV_uninit() {
+    PlacesViewBase.prototype.uninit.apply(this, arguments);
+  },
+
+  _insertNewItem:
+  function PAMV__insertNewItem(aChild, aBefore) {
+    this._domNodes.delete(aChild);
+
+    let type = aChild.type;
+    let button;
+    if (type == Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR) {
+      button = document.createElement("toolbarseparator");
+    }
+    else {
+      button = document.createElement("toolbarbutton");
+      button.className = "bookmark-item";
+      button.setAttribute("label", aChild.title);
+      let icon = aChild.icon;
+      if (icon)
+        button.setAttribute("image", icon);
+
+      if (PlacesUtils.containerTypes.indexOf(type) != -1) {
+        button.setAttribute("container", "true");
+
+        if (PlacesUtils.nodeIsQuery(aChild)) {
+          button.setAttribute("query", "true");
+          if (PlacesUtils.nodeIsTagQuery(aChild))
+            button.setAttribute("tagContainer", "true");
+        }
+        else if (PlacesUtils.nodeIsFolder(aChild)) {
+          PlacesUtils.livemarks.getLivemark(
+            { id: aChild.itemId },
+            function (aStatus, aLivemark) {
+              if (Components.isSuccessCode(aStatus)) {
+                button.setAttribute("livemark", "true");
+                this.controller.cacheLivemarkInfo(aChild, aLivemark);
+              }
+            }.bind(this)
+          );
+        }
+      }
+      else if (PlacesUtils.nodeIsURI(aChild)) {
+        button.setAttribute("scheme",
+                            PlacesUIUtils.guessUrlSchemeForUI(aChild.uri));
+      }
+    }
+
+    button._placesNode = aChild;
+    if (!this._domNodes.has(aChild))
+      this._domNodes.set(aChild, button);
+
+    this._rootElt.insertBefore(button, aBefore);
+  },
+
+  nodeInserted:
+  function PAMV_nodeInserted(aParentPlacesNode, aPlacesNode, aIndex) {
+    let parentElt = this._getDOMNodeForPlacesNode(aParentPlacesNode);
+    if (parentElt != this._rootElt)
+      return;
+
+    let children = this._rootElt.childNodes;
+    this._insertNewItem(aPlacesNode,
+      aIndex < children.length ? children[aIndex] : null);
+  },
+
+  nodeRemoved:
+  function PAMV_nodeRemoved(aParentPlacesNode, aPlacesNode, aIndex) {
+    let parentElt = this._getDOMNodeForPlacesNode(aParentPlacesNode);
+    if (parentElt != this._rootElt)
+      return;
+
+    let elt = this._getDOMNodeForPlacesNode(aPlacesNode);
+    this._removeChild(elt);
+  },
+
+  nodeMoved:
+  function PAMV_nodeMoved(aPlacesNode,
+                          aOldParentPlacesNode, aOldIndex,
+                          aNewParentPlacesNode, aNewIndex) {
+    let parentElt = this._getDOMNodeForPlacesNode(aNewParentPlacesNode);
+    if (parentElt != this._rootElt)
+      return;
+
+    let elt = this._getDOMNodeForPlacesNode(aPlacesNode);
+    this._removeChild(elt);
+    this._rootElt.insertBefore(elt, this._rootElt.childNodes[aNewIndex]);
+  },
+
+  nodeAnnotationChanged:
+  function PAMV_nodeAnnotationChanged(aPlacesNode, aAnno) {
+    let elt = this._getDOMNodeForPlacesNode(aPlacesNode);
+    // There's no UI representation for the root node.
+    if (elt == this._rootElt)
+      return;
+
+    if (elt.parentNode != this._rootElt)
+      return;
+
+    // All livemarks have a feedURI, so use it as our indicator.
+    if (aAnno == PlacesUtils.LMANNO_FEEDURI) {
+      elt.setAttribute("livemark", true);
+
+      PlacesUtils.livemarks.getLivemark(
+        { id: aPlacesNode.itemId },
+        function (aStatus, aLivemark) {
+          if (Components.isSuccessCode(aStatus)) {
+            this.controller.cacheLivemarkInfo(aPlacesNode, aLivemark);
+            this.invalidateContainer(aPlacesNode);
+          }
+        }.bind(this)
+      );
+    }
+  },
+
+  nodeTitleChanged: function PAMV_nodeTitleChanged(aPlacesNode, aNewTitle) {
+    let elt = this._getDOMNodeForPlacesNode(aPlacesNode);
+
+    // There's no UI representation for the root node.
+    if (elt == this._rootElt)
+      return;
+
+    PlacesViewBase.prototype.nodeTitleChanged.apply(this, arguments);
+  },
+
+  invalidateContainer: function PAMV_invalidateContainer(aPlacesNode) {
+    let elt = this._getDOMNodeForPlacesNode(aPlacesNode);
+    if (elt != this._rootElt)
+      return;
+
+    // Container is the toolbar itself.
+    while (this._rootElt.hasChildNodes()) {
+      this._rootElt.removeChild(this._rootElt.firstChild);
+    }
+
+    for (let i = 0; i < this._resultNode.childCount; ++i) {
+      this._insertNewItem(this._resultNode.getChild(i), null);
+    }
+  }
+};
diff --git a/browser/components/places/content/menu.xml b/browser/components/places/content/menu.xml
index 3d297be533b94c44773c45fdc5f392d4a39f2de8..16de5cc57666ab96ecfac1d771e965cba218e95b 100644
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -80,8 +80,8 @@
               elt = elt.parentNode;
 
             // Calculate positions taking care of arrowscrollbox
-            let eventY = aEvent.layerY;
             let scrollbox = this._scrollBox;
+            let eventY = aEvent.layerY + (scrollbox.boxObject.y - this.boxObject.y);
             let scrollboxOffset = scrollbox.scrollBoxObject.y -
                                   (scrollbox.boxObject.y - this.boxObject.y);
             let eltY = elt.boxObject.y - scrollboxOffset;
@@ -485,4 +485,121 @@
 
     </handlers>
   </binding>
+
+  <!-- Most of this is copied from the arrowpanel binding in popup.xml -->
+  <binding id="places-popup-arrow"
+           extends="chrome://browser/content/places/menu.xml#places-popup-base">
+    <content flip="both" side="top" position="bottomcenter topleft">
+      <xul:box anonid="container" class="panel-arrowcontainer" flex="1"
+               xbl:inherits="side,panelopen">
+        <xul:box anonid="arrowbox" class="panel-arrowbox">
+          <xul:image anonid="arrow" class="panel-arrow" xbl:inherits="side"/>
+        </xul:box>
+        <xul:box class="panel-arrowcontent" xbl:inherits="side,align,dir,orient,pack" flex="1">
+          <xul:vbox class="menupopup-drop-indicator-bar" hidden="true">
+            <xul:image class="menupopup-drop-indicator" mousethrough="always"/>
+          </xul:vbox>
+          <xul:arrowscrollbox class="popup-internal-box" flex="1" orient="vertical"
+                              smoothscroll="false">
+            <children/>
+          </xul:arrowscrollbox>
+        </xul:box>
+      </xul:box>
+    </content>
+
+    <implementation>
+      <method name="adjustArrowPosition">
+        <body><![CDATA[
+          var arrow = document.getAnonymousElementByAttribute(this, "anonid", "arrow");
+
+          var anchor = this.anchorNode;
+          if (!anchor) {
+            arrow.hidden = true;
+            return;
+          }
+
+          var container = document.getAnonymousElementByAttribute(this, "anonid", "container");
+          var arrowbox = document.getAnonymousElementByAttribute(this, "anonid", "arrowbox");
+
+          // if this panel has a "sliding" arrow, we may have previously set margins...
+          arrowbox.style.removeProperty("margin");
+
+          var position = this.alignmentPosition;
+          if (position.indexOf("start_") == 0 || position.indexOf("end_") == 0) {
+            container.orient = "";
+            arrowbox.orient = "vertical";
+            if (position.indexOf("_after") > 0) {
+              arrowbox.pack = "end";
+              arrowbox.style.marginBottom = this.alignmentOffset + "px";
+            } else {
+              arrowbox.pack = "start";
+              arrowbox.style.marginTop = this.alignmentOffset + "px";
+            }
+
+            // The assigned side stays the same regardless of direction.
+            var isRTL = (window.getComputedStyle(this).direction == "rtl");
+
+            if (position.indexOf("start_") == 0) {
+              container.dir = "reverse";
+              this.setAttribute("side", isRTL ? "left" : "right");
+            }
+            else {
+              container.dir = "";
+              this.setAttribute("side", isRTL ? "right" : "left");
+            }
+          }
+          else if (position.indexOf("before_") == 0 || position.indexOf("after_") == 0) {
+            container.orient = "vertical";
+            arrowbox.orient = "";
+            if (position.indexOf("_end") > 0) {
+              arrowbox.pack = "end";
+              arrowbox.style.marginRight = this.alignmentOffset + "px";
+            } else {
+              arrowbox.pack = "start";
+              arrowbox.style.marginLeft = this.alignmentOffset + "px";
+            }
+
+            if (position.indexOf("before_") == 0) {
+              container.dir = "reverse";
+              this.setAttribute("side", "bottom");
+            }
+            else {
+              container.dir = "";
+              this.setAttribute("side", "top");
+            }
+          }
+          arrow.hidden = false;
+        ]]></body>
+      </method>
+    </implementation>
+
+    <handlers>
+      <handler event="popupshowing" phase="target"><![CDATA[
+        this.adjustArrowPosition();
+      ]]></handler>
+      <handler event="popupshown" phase="target"><![CDATA[
+        this.setAttribute("panelopen", "true");
+
+        // Allow anchoring to a specified element inside the anchor.
+        var anchorClass = this.getAttribute("anonanchorclass");
+        if (anchorClass && this.anchorNode) {
+          let anchor =
+            document.getAnonymousElementByAttribute(this.anchorNode, "class",
+                                                    anchorClass);
+          if (anchor) {
+            let offsetX = anchor.boxObject.width / 2;
+            if (this.alignmentPosition.endsWith("_end"))
+              offsetX *= -1;
+            this.popupBoxObject.moveToAnchor(anchor, this.alignmentPosition,
+                                             offsetX, 0,
+                                             false);
+            this.adjustArrowPosition();
+          }
+        }
+      ]]></handler>
+      <handler event="popuphidden" phase="target"><![CDATA[
+        this.removeAttribute("panelopen");
+      ]]></handler>
+    </handlers>
+  </binding>
 </bindings>
diff --git a/browser/components/tabview/test/browser_tabview_bug626791.js b/browser/components/tabview/test/browser_tabview_bug626791.js
index d9f885cd8fadfe9a7de2c467d5d61cccd86e329f..2a57d1a2642aa9a171ac9ce788364599a5baed2e 100644
--- a/browser/components/tabview/test/browser_tabview_bug626791.js
+++ b/browser/components/tabview/test/browser_tabview_bug626791.js
@@ -1,6 +1,9 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+Cu.import("resource:///modules/CustomizableUI.jsm");
+
+
 function test() {
   let cw;
   let win;
@@ -31,10 +34,7 @@ function test() {
     let pos = currentSet.indexOf(buttonId);
 
     if (-1 < pos) {
-      currentSet.splice(pos, 1);
-      toolbar.setAttribute("currentset", currentSet.join(","));
-      toolbar.currentSet = currentSet.join(",");
-      win.document.persist(toolbar.id, "currentset");
+      CustomizableUI.removeWidgetFromArea("tabview-button");
     }
   }
 
diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd
index 39bcc493abc8e54d61656599a97bf548829b5255..9b165c1d7fecccbd872e2bbb2699c1a2f6b9f037 100644
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -15,6 +15,9 @@
                                                                 inside the private browsing mode -->
 <!ENTITY mainWindow.titlePrivateBrowsingSuffix "(Private Browsing)">
 
+<!ENTITY appmenu.title                       "Customize and Control &brandFullName;">
+<!ENTITY navbarOverflow.label                "More tools…">
+
 <!-- Tab context menu -->
 <!ENTITY  reloadTab.label                    "Reload Tab">
 <!ENTITY  reloadTab.accesskey                "R">
@@ -159,10 +162,8 @@ These should match what Safari and other Apple applications use on OS X Lion. --
 <!ENTITY printButton.label            "Print">
 <!ENTITY printButton.tooltip          "Print this page">
 
-<!ENTITY backForwardItem.title        "Back/Forward">
 <!ENTITY locationItem.title           "Location">
 <!ENTITY searchItem.title             "Search">
-<!ENTITY bookmarksItem.title          "Bookmarks">
 
 <!-- Toolbar items --> 
 <!ENTITY homeButton.label             "Home">
@@ -176,7 +177,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
 <!ENTITY bookmarksMenuButton.label          "Bookmarks">
 <!ENTITY bookmarksMenuButton.tooltip        "Display your bookmarks">
 <!ENTITY bookmarksMenuButton.unsorted.label "Unsorted Bookmarks">
-<!ENTITY viewBookmarksSidebar.label         "Show in Sidebar">
+<!ENTITY viewBookmarksSidebar2.label        "View Bookmarks Sidebar">
 <!ENTITY viewBookmarksToolbar.label         "View Bookmarks Toolbar">
 
 <!-- LOCALIZATION NOTE (bookmarksSidebarGtkCmd.commandkey): This command
@@ -328,12 +329,29 @@ These should match what Safari and other Apple applications use on OS X Lion. --
 <!ENTITY showAllHistoryCmd.commandkey "H">
 
 <!ENTITY appMenuCustomize.label "Customize">
+<!ENTITY appMenuHistory.label "History">
+<!ENTITY appMenuHistory.showAll.label "Show All History">
+<!ENTITY appMenuHistory.clearRecent.label "Clear Recent History…">
+<!ENTITY appMenuHistory.restoreSession.label "Restore Previous Session">
+
+<!ENTITY customizeMenu.addToToolbar.label "Add to Toolbar">
+<!ENTITY customizeMenu.addToToolbar.accesskey "A">
+<!ENTITY customizeMenu.removeFromMenu.label "Remove from Menu">
+<!ENTITY customizeMenu.removeFromMenu.accesskey "R">
+<!ENTITY customizeMenu.addMoreItems.label "Add More Items…">
+<!ENTITY customizeMenu.addMoreItems.accesskey "A">
 
 <!ENTITY openCmd.commandkey           "l">
 <!ENTITY urlbar.placeholder2          "Search or enter address">
 <!ENTITY urlbar.accesskey             "d">
 <!ENTITY urlbar.switchToTab.label     "Switch to tab:">
 
+<!-- LOCALIZATION NOTE (toggleMenuPanelMac.key) ideally this should be the same as
+     toggleMenuPanel. However, the modifier is different on mac (cmd+shift rather than ctrl)
+     and so you may need to pick a different key to avoid conflicts with other shortcuts. -->
+<!ENTITY toggleMenuPanel.key          "m">
+<!ENTITY toggleMenuPanelMac.key       "m">
+
 <!-- 
   Comment duplicated from browser-sets.inc:
 
@@ -647,6 +665,13 @@ just addresses the organization to follow, e.g. "This site is run by " -->
 <!ENTITY social.learnMore.accesskey "l">
 <!ENTITY social.closeNotificationItem.label "Not Now">
 
+
+
+<!ENTITY customizeMode.tabTitle "Customize &brandShortName;">
+<!ENTITY customizeMode.menuAndToolbars.label "Menu and toolbars">
+<!ENTITY customizeMode.menuAndToolbars.header "More Tools to Add to the Menu and Toolbar">
+<!ENTITY customizeMode.restoreDefaults "Restore Defaults">
+
 <!ENTITY social.chatBar.commandkey "c">
 <!ENTITY social.chatBar.label "Focus chats">
 <!ENTITY social.chatBar.accesskey "c">
@@ -723,5 +748,8 @@ just addresses the organization to follow, e.g. "This site is run by " -->
 <!ENTITY zoomControls.label            "Zoom Controls">
 <!ENTITY addonBarCloseButton.tooltip   "Close Add-on Bar">
 <!ENTITY toggleAddonBarCmd.key         "/">
+<!ENTITY backForwardItem.title         "Back/Forward">
+<!ENTITY viewBookmarksSidebar.label    "Show in Sidebar">
+<!ENTITY bookmarksItem.title           "Bookmarks">
 <!-- end of strings to be removed post-Australis -->
 
diff --git a/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties b/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties
new file mode 100644
index 0000000000000000000000000000000000000000..58718c02c626302765a03545a962079cde1a3029
--- /dev/null
+++ b/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties
@@ -0,0 +1,76 @@
+# 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/.
+
+history-panelmenu.label = History
+# LOCALIZATION NOTE (history-panelmenu.tooltiptext): Use the unicode ellipsis char,
+# \u2026, or use "..." if \u2026 doesn't suit traditions in your locale.
+history-panelmenu.tooltiptext = History… (%S)
+
+privatebrowsing-button.label = New Private Window
+# LOCALIZATION NOTE(privatebrowsing-button.tooltiptext): %S is the keyboard shortcut
+privatebrowsing-button.tooltiptext = Open a new Private Browsing window (%S)
+
+save-page-button.label = Save Page
+# LOCALIZATION NOTE(save-page-button.tooltiptext): %S is the keyboard shortcut
+save-page-button.tooltiptext = Save this page (%S)
+
+find-button.label = Find
+# LOCALIZATION NOTE(find-button.tooltiptext): %S is the keyboard shortcut
+find-button.tooltiptext = Find in this page (%S)
+
+open-file-button.label = Open File
+# LOCALIZATION NOTE(open-file-button.tooltiptext): %S is the keyboard shortcut
+open-file-button.tooltiptext = Open file (%S)
+
+developer-button.label = Developer
+# LOCALIZATION NOTE(developer-button.tooltiptext): %S is the keyboard shortcut
+developer-button.tooltiptext = Web Developer Tools (%S)
+
+add-ons-button.label = Add-ons
+# LOCALIZATION NOTE(add-ons-button.tooltiptext): %S is the keyboard shortcut
+add-ons-button.tooltiptext = Add-ons Manager (%S)
+
+preferences-button.label = Preferences
+# LOCALIZATION NOTE (preferences-button.tooltiptext): Use the unicode ellipsis char,
+# \u2026, or use "..." if \u2026 doesn't suit traditions in your locale.
+preferences-button.tooltiptext = Preferences…
+# LOCALIZATION NOTE (preferences-button.labelWin): Windows-only label for Options
+preferences-button.labelWin = Options
+# LOCALIZATION NOTE (preferences-button.tooltipWin): Windows-only tooltip for Options
+preferences-button.tooltipWin = Options
+
+zoom-controls.label = Zoom Controls
+zoom-controls.tooltiptext = Zoom Controls
+
+zoom-out-button.label = Zoom out
+zoom-out-button.tooltiptext = Zoom out
+
+# LOCALIZATION NOTE(zoom-reset-button.label): %S is the current zoom level,
+# %% will be displayed as a single % character (% is commonly used to define
+# format specifiers, so it needs to be escaped).
+zoom-reset-button.label = %S%%
+zoom-reset-button.tooltiptext = Reset zoom level
+
+zoom-in-button.label = Zoom in
+zoom-in-button.tooltiptext = Zoom in
+
+edit-controls.label = Edit Controls
+edit-controls.tooltiptext = Edit Controls
+
+cut-button.label = Cut
+cut-button.tooltiptext = Cut
+
+copy-button.label = Copy
+copy-button.tooltiptext = Copy
+
+paste-button.label = Paste
+paste-button.tooltiptext = Paste
+
+# LOCALIZATION NOTE (feed-button.tooltiptext): Use the unicode ellipsis char,
+# \u2026, or use "..." if \u2026 doesn't suit traditions in your locale.
+feed-button.label = Subscribe
+feed-button.tooltiptext = Subscribe to this page…
+
+characterencoding-button.label = Character Encoding
+characterencoding-button.tooltiptext = Character encoding
diff --git a/browser/locales/jar.mn b/browser/locales/jar.mn
index 99ae32d671d051aa14fac78d269b5e35e51ca29a..23af3724066a53266668629b21d54300dce2311e 100644
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -22,6 +22,7 @@
     locale/browser/browser.dtd                     (%chrome/browser/browser.dtd)
     locale/browser/baseMenuOverlay.dtd             (%chrome/browser/baseMenuOverlay.dtd)
     locale/browser/browser.properties              (%chrome/browser/browser.properties)
+    locale/browser/customizableui/customizableWidgets.properties (%chrome/browser/customizableui/customizableWidgets.properties)
     locale/browser/devtools/appcacheutils.properties  (%chrome/browser/devtools/appcacheutils.properties)
     locale/browser/devtools/debugger.dtd              (%chrome/browser/devtools/debugger.dtd)
     locale/browser/devtools/debugger.properties       (%chrome/browser/devtools/debugger.properties)
diff --git a/browser/modules/UITour.jsm b/browser/modules/UITour.jsm
index 67c74a8b1cb439a0b752aa5d1223d7018f2ef9e3..6ae917fb768da1b87bb01342cd876777c222d05f 100644
--- a/browser/modules/UITour.jsm
+++ b/browser/modules/UITour.jsm
@@ -26,8 +26,8 @@ this.UITour = {
 
   highlightEffects: ["wobble", "zoom", "color"],
   targets: new Map([
-    ["backforward", "#unified-back-forward-button"],
-    ["appmenu", "#appmenu-button"],
+    ["backforward", "#back-button"],
+    ["appmenu", "#PanelUI-menu-button"],
     ["home", "#home-button"],
     ["urlbar", "#urlbar"],
     ["bookmarks", "#bookmarks-menu-button"],
@@ -388,7 +388,7 @@ this.UITour = {
     }
 
     if (aMenuName == "appmenu")
-      openMenuButton("appmenu-button");
+      aWindow.PanelUI.show();
     else if (aMenuName == "bookmarks")
       openMenuButton("bookmarks-menu-button");
   },
diff --git a/browser/modules/webappsUI.jsm b/browser/modules/webappsUI.jsm
index 7afbb32d0724cdc9ca76a1de12c16906258bed08..f44555359d140c068f562b05938b5342b253789e 100644
--- a/browser/modules/webappsUI.jsm
+++ b/browser/modules/webappsUI.jsm
@@ -96,48 +96,6 @@ this.webappsUI = {
     return someWindow && Services.wm.getOuterWindowWithId(aId);
   },
 
-  openURL: function(aUrl, aOrigin) {
-    let browserEnumerator = Services.wm.getEnumerator("navigator:browser");
-    let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
-
-    // Check each browser instance for our URL
-    let found = false;
-    while (!found && browserEnumerator.hasMoreElements()) {
-      let browserWin = browserEnumerator.getNext();
-      if (browserWin.closed) {
-        continue;
-      }
-      let tabbrowser = browserWin.gBrowser;
-
-      // Check each tab of this browser instance
-      let numTabs = tabbrowser.tabs.length;
-      for (let index = 0; index < numTabs; index++) {
-        let tab = tabbrowser.tabs[index];
-        let appURL = ss.getTabValue(tab, "appOrigin");
-        if (appURL == aOrigin) {
-          // The URL is already opened. Select this tab.
-          tabbrowser.selectedTab = tab;
-          browserWin.focus();
-          found = true;
-          break;
-        }
-      }
-    }
-
-    // Our URL isn't open. Open it now.
-    if (!found) {
-      let recentWindow = Services.wm.getMostRecentWindow("navigator:browser");
-      if (recentWindow) {
-        // Use an existing browser window
-        let browser = recentWindow.gBrowser;
-        let tab = browser.addTab(aUrl);
-        browser.pinTab(tab);
-        browser.selectedTab = tab;
-        ss.setTabValue(tab, "appOrigin", aOrigin);
-      }
-    }
-  },
-
   doInstall: function(aData, aWindow) {
     let browser = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIWebNavigation)
diff --git a/browser/themes/linux/Go-arrow.png b/browser/themes/linux/Go-arrow.png
deleted file mode 100644
index 259c8a4f01cd6a929a3440a5b579fef5275ce0ae..0000000000000000000000000000000000000000
Binary files a/browser/themes/linux/Go-arrow.png and /dev/null differ
diff --git a/browser/themes/linux/Makefile.in b/browser/themes/linux/Makefile.in
index 173ca68435c6cf993204e3cca62ac579ab2537ba..67f553d6ef9c39898f407b06a620793765675727 100644
--- a/browser/themes/linux/Makefile.in
+++ b/browser/themes/linux/Makefile.in
@@ -5,3 +5,23 @@
 ICON_FILES := icon.png
 ICON_DEST = $(FINAL_TARGET)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
 INSTALL_TARGETS += ICON
+
+# By default, the pre-processor used for jar.mn will use "%" as a marker for ".css" files and "#"
+# otherwise. This falls apart when a file using one marker needs to include a file with the other
+# marker since the pre-processor instructions in the included file will not be processed. The
+# following SVG files need to include a file which uses "%" as the marker so we invoke the pre-
+# processor ourselves here with the marker specified. The resulting SVG files will get packaged by
+# the processing of the jar file in this directory.
+tab-selected-svg: $(srcdir)/../shared/tab-selected.svg
+	$(call py_action,preprocessor, \
+	  --marker "%" -D TAB_SIDE=start \
+	  $(ACDEFINES) \
+	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-start.svg)
+	$(call py_action,preprocessor, \
+	  --marker "%" -D TAB_SIDE=end \
+	  $(ACDEFINES) \
+	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-end.svg)
+
+.PHONY: tab-selected-svg
+
+export:: tab-selected-svg
diff --git a/browser/themes/linux/Toolbar-inverted.png b/browser/themes/linux/Toolbar-inverted.png
new file mode 100644
index 0000000000000000000000000000000000000000..b42fd7475dbe89ff00dfcf875c45f76c839fab05
Binary files /dev/null and b/browser/themes/linux/Toolbar-inverted.png differ
diff --git a/browser/themes/linux/Toolbar-small.png b/browser/themes/linux/Toolbar-small.png
index bcc8f63dcd9fef85eaec6181a36f75e7519c81b6..8f100a54a7d34d0f754e2908657083598fc75ded 100644
Binary files a/browser/themes/linux/Toolbar-small.png and b/browser/themes/linux/Toolbar-small.png differ
diff --git a/browser/themes/linux/Toolbar.png b/browser/themes/linux/Toolbar.png
index 2851657ecaf324ffd663dbb6b3e37586c977b939..687cc1b3dad4197e98b3f39a8d75878c954b13f9 100644
Binary files a/browser/themes/linux/Toolbar.png and b/browser/themes/linux/Toolbar.png differ
diff --git a/browser/themes/linux/browser-lightweightTheme.css b/browser/themes/linux/browser-lightweightTheme.css
new file mode 100644
index 0000000000000000000000000000000000000000..012b7191ce9654796c10b617fdd20843e7f96fbb
--- /dev/null
+++ b/browser/themes/linux/browser-lightweightTheme.css
@@ -0,0 +1,29 @@
+/* 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 linuxShared.inc
+%filter substitution
+
+/*
+ * LightweightThemeListener will append the current lightweight theme's header
+ * image to the background-image for each of the following rulesets.
+ */
+
+/* Lightweight theme on tabs */
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
+  background-attachment: scroll, fixed;
+  background-color: transparent;
+  background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
+  background-position: 0 0, right top;
+}
+
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
+  background-attachment: scroll, scroll, fixed;
+  background-color: transparent;
+  background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
+                    @fgTabTextureLWT@;/*,
+                    lwtHeader;*/
+  background-position: 0 0, 0 0, right top;
+}
diff --git a/browser/themes/linux/browser.css b/browser/themes/linux/browser.css
index e042ba5994d97c959f75376ec6ed06382153bf7a..1728faf0dd8892b3fc99902e7f894f4962f73a08 100644
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -10,14 +10,12 @@
 @namespace html url("http://www.w3.org/1999/xhtml");
 
 %include ../shared/browser.inc
+%include linuxShared.inc
 %filter substitution
-%define toolbarHighlight rgba(255,255,255,.3)
-%define selectedTabHighlight rgba(255,255,255,.8) 1px, rgba(255,255,255,.5) 3px
+
 %define forwardTransitionLength 150ms
-%define conditionalForwardWithUrlbar       window:not([chromehidden~=toolbar]) :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"][mode=icons],                #nav-bar:not([currentset])[mode=icons])                 > #unified-back-forward-button
-%define conditionalForwardWithUrlbar_small window:not([chromehidden~=toolbar]) :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"][mode=icons][iconsize=small],#nav-bar:not([currentset])[mode=icons][iconsize=small]) > #unified-back-forward-button
-%define conditionalForwardWithUrlbarWidth 32
-%define conditionalForwardWithUrlbarWidth_small 24
+%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
+%define conditionalForwardWithUrlbarWidth 26
 
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
@@ -31,14 +29,10 @@
   -moz-appearance: none;
   background-color: transparent;
   border-top: none;
-}
-
-#main-window:not([disablechrome]) #navigator-toolbox[tabsontop=true] {
   border-bottom: 1px solid ThreeDShadow;
 }
 
-#navigator-toolbox[tabsontop=true] > toolbar:not(:-moz-lwtheme):not(#toolbar-menubar):not(#TabsToolbar),
-#navigator-toolbox[tabsontop=false] > toolbar:not(:-moz-lwtheme):not(#toolbar-menubar) {
+#navigator-toolbox > toolbar:not(:-moz-lwtheme):not(#toolbar-menubar):not(#TabsToolbar) {
   -moz-appearance: none;
   border-style: none;
   background-color: -moz-Dialog;
@@ -49,13 +43,19 @@
   padding-bottom: 1px;
 }
 
-#nav-bar:not(:-moz-lwtheme),
-#nav-bar[collapsed=true] + toolbar:not(:-moz-lwtheme),
-#nav-bar[collapsed=true] + #customToolbars + #PersonalToolbar:not(:-moz-lwtheme),
-#nav-bar[tabsontop=true],
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar,
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar {
+#nav-bar {
   background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
+  box-shadow: 0 1px 0 @toolbarHighlight@ inset;
+  margin-top: -1px; /* Move up 1px into the TabsToolbar */
+  padding-top: 2px;
+  padding-bottom: 2px;
+  /* Position the toolbar above the bottom of background tabs */
+  position: relative;
+  z-index: 1;
+}
+
+#nav-bar-overflow-button {
+  -moz-image-region: rect(-5px, 12px, 11px, -4px);
 }
 
 #personal-bookmarks {
@@ -73,7 +73,8 @@
 }
 
 /* Places toolbar */
-toolbarbutton.bookmark-item {
+toolbarbutton.bookmark-item,
+#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder {
   margin: 0;
   padding: 2px 3px;
 }
@@ -86,13 +87,15 @@ toolbarbutton.bookmark-item[open="true"] {
   -moz-padding-end: 2px;
 }
 
-.bookmark-item > .toolbarbutton-icon {
+.bookmark-item > .toolbarbutton-icon,
+#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
   width: 16px;
   height: 16px;
 }
 
-/* Prevent [mode="icons"] from hiding the label */
-.bookmark-item > .toolbarbutton-text {
+/* Force the display of the label for bookmarks */
+.bookmark-item > .toolbarbutton-text,
+#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-text {
   display: -moz-box !important;
 }
 
@@ -105,12 +108,7 @@ toolbarbutton.bookmark-item[open="true"] {
   display: -moz-box !important;
 }
 
-#wrapper-personal-bookmarks[place="palette"] > .toolbarpaletteitem-box {
-  background: url("chrome://browser/skin/places/bookmarksToolbar.png") no-repeat center;
-}
-
-.bookmarks-toolbar-customize {
-  max-width: 15em !important;
+#bookmarks-toolbar-placeholder {
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important;
 }
 
@@ -213,7 +211,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   -moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic");
 }
 
-#appmenu_newNavigator,
 #placesContext_open\:newwindow,
 #menu_newNavigator,
 #context-openlink,
@@ -222,8 +219,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   -moz-image-region: rect(0px 80px 16px 64px);
 }
 
-#appmenu_newTab,
-#appmenu_newTab_popup,
 #placesContext_open\:newtab,
 #placesContext_openContainer\:tabs,
 #menu_newNavigatorTab,
@@ -233,7 +228,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   -moz-image-region: rect(0px 64px 16px 48px);
 }
 
-#appmenu_openFile,
 #menu_openFile {
   list-style-image: url("moz-icon://stock/gtk-open?size=menu");
 }
@@ -250,7 +244,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   list-style-image: url("moz-icon://stock/gtk-media-pause?size=menu");
 }
 
-#appmenu_savePage,
 #menu_savePage,
 #context-savelink,
 #context-saveimage,
@@ -261,19 +254,15 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   list-style-image: url("moz-icon://stock/gtk-save-as?size=menu");
 }
 
-#appmenu_printPreview,
 #menu_printPreview {
   list-style-image: url("moz-icon://stock/gtk-print-preview?size=menu");
 }
 
-#appmenu_print,
-#appmenu_print_popup,
 #menu_print,
 #context-printframe {
   list-style-image: url("moz-icon://stock/gtk-print?size=menu");
 }
 
-#appmenu-quit,
 #menu_FileQuitItem {
   list-style-image: url("moz-icon://stock/gtk-quit?size=menu");
 }
@@ -356,7 +345,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   list-style-image: url("moz-icon://stock/gtk-select-all?size=menu");
 }
 
-#appmenu_find,
 #menu_find {
   list-style-image: url("moz-icon://stock/gtk-find?size=menu");
 }
@@ -365,8 +353,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   list-style-image: url("moz-icon://stock/gtk-find?size=menu&state=disabled");
 }
 
-#appmenu_customize,
-#appmenu_preferences,
 #menu_preferences {
   list-style-image: url("moz-icon://stock/gtk-preferences?size=menu");
 }
@@ -433,15 +419,11 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu&state=disabled");
 }
 
-#appmenu_history,
-#appmenu_showAllHistory,
 #menu_showAllHistory {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
   -moz-image-region: rect(0px 32px 16px 16px);
 }
 
-#appmenu_bookmarks,
-#appmenu_showAllBookmarks,
 #bookmarksShowAll {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
   -moz-image-region: rect(0px 48px 16px 32px);
@@ -455,25 +437,21 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
 }
 
 #bookmarksToolbarFolderMenu,
-#BMB_bookmarksToolbar {
+#BMB_bookmarksToolbar,
+#panelMenu_bookmarksToolbar {
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
 }
 
-#BMB_bookmarkThisPage {
-  list-style-image: url("chrome://browser/skin/places/starPage.png");
-}
-
-#BMB_unsortedBookmarks {
+#BMB_unsortedBookmarks,
+#panelMenu_unsortedBookmarks {
   list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png");
 }
 
-#appmenu_downloads,
 #menu_openDownloads {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
   -moz-image-region: rect(0px 16px 16px 0px);
 }
 
-#appmenu_addons,
 #menu_openAddons {
   list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png");
 }
@@ -484,8 +462,6 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   list-style-image: url("moz-icon://stock/gtk-info?size=menu");
 }
 
-#appmenu_privateBrowsing,
-#appmenu_newPrivateWindow,
 #privateBrowsingItem {
   list-style-image: url("chrome://browser/skin/Privacy-16.png");
 }
@@ -494,18 +470,14 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
   list-style-image: url("moz-icon://stock/gtk-properties?size=menu");
 }
 
-#appmenu_sanitizeHistory,
 #sanitizeItem {
   list-style-image: url("moz-icon://stock/gtk-clear?size=menu");
 }
 
-#appmenu_help,
-#appmenu_openHelp,
 #menu_openHelp {
   list-style-image: url("moz-icon://stock/gtk-help?size=menu");
 }
 
-#appmenu_about,
 #aboutName {
   list-style-image: url("moz-icon://stock/gtk-about?size=menu");
 }
@@ -515,21 +487,10 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
 }
 
 /* Primary toolbar buttons */
-.toolbarbutton-1:not([type="menu-button"]) {
-  -moz-box-orient: vertical;
-  min-width: 0;
-  list-style-image: url("chrome://browser/skin/Toolbar.png");
-}
-
 .toolbarbutton-1 > .toolbarbutton-icon {
   -moz-margin-end: 0;
 }
 
-toolbar[mode="full"] .toolbarbutton-1:not([type="menu-button"]),
-toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
-  min-width: 57px;
-}
-
 .toolbarbutton-1:not([type="menu-button"]),
 .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   padding: 5px;
@@ -539,66 +500,14 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   padding: 5px !important;
 }
 
-/* 24px primary toolbar buttons */
-#back-button {
-  list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=toolbar");
-}
-#back-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=toolbar&state=disabled");
-}
-
-#back-button:-moz-locale-dir(rtl) {
-  list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=toolbar");
-}
-#back-button[disabled="true"]:-moz-locale-dir(rtl) {
-  list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=toolbar&state=disabled");
-}
-
-#forward-button,
-@conditionalForwardWithUrlbar@ > #forward-button {
-  list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar");
-}
-#forward-button:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar@ > #forward-button:-moz-locale-dir(rtl) {
-  list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar");
-}
-
 #forward-button[disabled] {
-  list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=toolbar&state=disabled");
-}
-#forward-button[disabled]:-moz-locale-dir(rtl) {
-  list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=toolbar&state=disabled");
-}
-
-@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
-  transition: @forwardTransitionLength@ ease-out;
-}
-
-@conditionalForwardWithUrlbar@ > #forward-button[disabled] {
   transform: scale(0);
   opacity: 0;
   pointer-events: none;
 }
 
-#reload-button {
-  list-style-image: url("moz-icon://stock/gtk-refresh?size=toolbar");
-}
-#reload-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-refresh?size=toolbar&state=disabled");
-}
-
-#stop-button {
-  list-style-image: url("moz-icon://stock/gtk-stop?size=toolbar");
-}
-#stop-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-stop?size=toolbar&state=disabled");
-}
-
-#home-button {
-  list-style-image: url("moz-icon://stock/gtk-home?size=toolbar");
-}
-#home-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-home?size=toolbar&state=disabled");
+@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
+  transition: @forwardTransitionLength@ ease-out;
 }
 
 /* tabview button */
@@ -629,34 +538,10 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   -moz-image-region: rect(0, 64px, 16px, 48px);
 }
 
-#downloads-button {
-  -moz-image-region: rect(0px 24px 24px 0px);
-}
-
-#history-button {
-  -moz-image-region: rect(0px 48px 24px 24px);
-}
-
-#bookmarks-button,
-#bookmarks-menu-button {
+#bookmarks-button {
   -moz-image-region: rect(0px 72px 24px 48px);
 }
 
-#bookmarks-menu-button.bookmark-item {
-  list-style-image: url("chrome://browser/skin/Toolbar-small.png");
-}
-
-#bookmarks-menu-button.toolbarbutton-1 {
-  -moz-box-orient: horizontal;
-}
-
-#print-button {
-  list-style-image: url("moz-icon://stock/gtk-print?size=toolbar");
-}
-#print-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-print?size=toolbar&state=disabled");
-}
-
 #new-tab-button {
   -moz-image-region: rect(0px 96px 24px 72px);
 }
@@ -665,39 +550,6 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   -moz-image-region: rect(0px 120px 24px 96px);
 }
 
-#cut-button {
-  list-style-image: url("moz-icon://stock/gtk-cut?size=toolbar");
-}
-#cut-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-cut?size=toolbar&state=disabled");
-}
-
-#copy-button {
-  list-style-image: url("moz-icon://stock/gtk-copy?size=toolbar");
-}
-#copy-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-copy?size=toolbar&state=disabled");
-}
-
-#paste-button {
-  list-style-image: url("moz-icon://stock/gtk-paste?size=toolbar");
-}
-#paste-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-paste?size=toolbar&state=disabled");
-}
-
-#fullscreen-button {
-  list-style-image: url("moz-icon://stock/gtk-fullscreen?size=toolbar");
-}
-
-#zoom-out-button {
-  list-style-image: url("moz-icon://stock/gtk-zoom-out?size=toolbar");
-}
-
-#zoom-in-button {
-  list-style-image: url("moz-icon://stock/gtk-zoom-in?size=toolbar");
-}
-
 #sync-button {
   -moz-image-region: rect(0px 144px 24px 120px);
 }
@@ -718,159 +570,36 @@ toolbar[mode="full"] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   -moz-image-region: rect(0px 192px 24px 168px);
 }
 
-/* 16px primary toolbar buttons */
-toolbar[iconsize="small"] .toolbarbutton-1:not([type="menu-button"]) {
-  -moz-box-orient: vertical;
-  min-width: 0;
-  list-style-image: url("chrome://browser/skin/Toolbar-small.png");
-}
-
-toolbar[iconsize="small"] .toolbarbutton-1[type="menu-button"] {
-  border: 0 !important;
-}
-
-toolbar[iconsize="small"] #back-button {
-  list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=menu");
-}
 .unified-nav-back[_moz-menuactive] {
   list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=menu") !important;
 }
-toolbar[iconsize="small"] #back-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-go-back-ltr?size=menu&state=disabled");
-}
-
-toolbar[iconsize="small"] #back-button:-moz-locale-dir(rtl) {
-  list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=menu");
-}
 .unified-nav-back[_moz-menuactive]:-moz-locale-dir(rtl) {
   list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=menu") !important;
 }
-toolbar[iconsize="small"] #back-button[disabled="true"]:-moz-locale-dir(rtl) {
-  list-style-image: url("moz-icon://stock/gtk-go-back-rtl?size=menu&state=disabled");
-}
-
-toolbar[iconsize=small] #forward-button,
-@conditionalForwardWithUrlbar_small@ > #forward-button {
-  list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu");
-}
 .unified-nav-forward[_moz-menuactive] {
   list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu") !important;
 }
-toolbar[iconsize=small] #forward-button[disabled] {
-  list-style-image: url("moz-icon://stock/gtk-go-forward-ltr?size=menu&state=disabled");
-}
-
-toolbar[iconsize=small] #forward-button:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar_small@ > #forward-button:-moz-locale-dir(rtl) {
-  list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu");
-}
 .unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) {
   list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu") !important;
 }
-toolbar[iconsize=small] #forward-button[disabled]:-moz-locale-dir(rtl) {
-  list-style-image: url("moz-icon://stock/gtk-go-forward-rtl?size=menu&state=disabled");
-}
-
-toolbar[iconsize="small"] #stop-button {
-  list-style-image: url("moz-icon://stock/gtk-stop?size=menu");
-}
-toolbar[iconsize="small"] #stop-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-stop?size=menu&state=disabled");
-}
-
-toolbar[iconsize="small"] #reload-button {
-  list-style-image: url("moz-icon://stock/gtk-refresh?size=menu");
-}
-toolbar[iconsize="small"] #reload-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-refresh?size=menu&state=disabled");
-}
-
-toolbar[iconsize="small"] #home-button,
 #home-button.bookmark-item {
   list-style-image: url("moz-icon://stock/gtk-home?size=menu");
 }
-toolbar[iconsize="small"] #home-button[disabled="true"],
 #home-button.bookmark-item[disabled="true"] {
   list-style-image: url("moz-icon://stock/gtk-home?size=menu&state=disabled");
 }
 
-toolbar[iconsize="small"] #downloads-button {
-  -moz-image-region: rect(0px 16px 16px 0px);
-}
-
-toolbar[iconsize="small"] #webrtc-status-button /* temporary placeholder (bug 824825) */,
-toolbar[iconsize="small"] #history-button {
-  -moz-image-region: rect(0px 32px 16px 16px);
-}
-
-toolbar[iconsize="small"] #bookmarks-button,
-toolbar[iconsize="small"] #bookmarks-menu-button,
-#bookmarks-menu-button.bookmark-item {
-  -moz-image-region: rect(0px 48px 16px 32px);
-}
-
-toolbar[iconsize="small"] #print-button {
-  list-style-image: url("moz-icon://stock/gtk-print?size=menu");
-}
-toolbar[iconsize="small"] #print-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-print?size=menu&state=disabled");
-}
-
-toolbar[iconsize="small"] #new-tab-button {
-  -moz-image-region: rect(0px 64px 16px 48px);
-}
-
-toolbar[iconsize="small"] #new-window-button {
-  -moz-image-region: rect(0px 80px 16px 64px);
-}
-
-toolbar[iconsize="small"] #cut-button {
-  list-style-image: url("moz-icon://stock/gtk-cut?size=menu");
-}
-toolbar[iconsize="small"] #cut-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-cut?size=menu&state=disabled");
-}
-
-toolbar[iconsize="small"] #copy-button {
-  list-style-image: url("moz-icon://stock/gtk-copy?size=menu");
-}
-toolbar[iconsize="small"] #copy-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-copy?size=menu&state=disabled");
-}
-
-toolbar[iconsize="small"] #paste-button {
-  list-style-image: url("moz-icon://stock/gtk-paste?size=menu");
-}
-toolbar[iconsize="small"] #paste-button[disabled="true"] {
-  list-style-image: url("moz-icon://stock/gtk-paste?size=menu&state=disabled");
-}
-
-toolbar[iconsize="small"] #fullscreen-button {
-  list-style-image: url("moz-icon://stock/gtk-fullscreen?size=menu");
-}
-
-toolbar[iconsize="small"] #zoom-out-button {
-  list-style-image: url("moz-icon://stock/gtk-zoom-out?size=menu");
-}
-
-toolbar[iconsize="small"] #zoom-in-button {
-  list-style-image: url("moz-icon://stock/gtk-zoom-in?size=menu");
-}
-
-toolbar[iconsize="small"] #sync-button {
-  -moz-image-region: rect(0px 96px 16px 80px);
-}
-toolbar[iconsize="small"] #sync-button[status="active"] {
-  list-style-image: url("chrome://browser/skin/sync-16-throbber.png");
-  -moz-image-region: rect(0px 16px 16px 0px);
-}
+/* Menu panel buttons */
 
-toolbar[iconsize="small"] #feed-button {
-  -moz-image-region: rect(0px 112px 16px 96px);
-}
+%include ../shared/toolbarbuttons.inc.css
+%include ../shared/menupanel.inc.css
 
-toolbar[iconsize="small"] #webrtc-status-button {
-  -moz-image-region: rect(0px 128px 16px 112px);
+#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon,
+#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker,
+#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-dropmarker,
+#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
+#main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon {
+  opacity: 0.4;
 }
 
 /* Fullscreen window controls */
@@ -915,39 +644,28 @@ toolbar[iconsize="small"] #webrtc-status-button {
   -moz-box-align: stretch;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper {
   -moz-padding-start: @conditionalForwardWithUrlbarWidth@px;
   -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
   position: relative;
   pointer-events: none;
 }
 
-@conditionalForwardWithUrlbar_small@ + #urlbar-container {
-  -moz-padding-start: @conditionalForwardWithUrlbarWidth_small@px;
-  -moz-margin-start: -@conditionalForwardWithUrlbarWidth_small@px;
-}
-
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar {
   pointer-events: all;
 }
 
-@conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
   transition: margin-left @forwardTransitionLength@ ease-out,
               margin-right @forwardTransitionLength@ ease-out;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
   margin-left: -@conditionalForwardWithUrlbarWidth@px;
 }
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
   margin-right: -@conditionalForwardWithUrlbarWidth@px;
 }
-@conditionalForwardWithUrlbar_small@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
-  margin-left: -@conditionalForwardWithUrlbarWidth_small@px;
-}
-@conditionalForwardWithUrlbar_small@[forwarddisabled] + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
-  margin-right: -@conditionalForwardWithUrlbarWidth_small@px;
-}
 
 #urlbar-icons {
   -moz-box-align: center;
@@ -964,7 +682,7 @@ toolbar[iconsize="small"] #webrtc-status-button {
   -moz-margin-start: -4px;
 }
 
-#urlbar-search-splitter + #urlbar-container > #urlbar ,
+#urlbar-search-splitter + #urlbar-container > #urlbar-wrapper > #urlbar,
 #urlbar-search-splitter + #search-container > #searchbar > .searchbar-textbox {
   -moz-margin-start: 0;
 }
@@ -1433,35 +1151,61 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
 
 /* Combined go/reload/stop button in location bar */
 
-#go-button {
-  padding-top: 2px;
-  padding-bottom: 2px;
-}
-
 #urlbar > toolbarbutton {
   -moz-appearance: none;
-  padding: 0;
-  border: none;
+  padding: 0 2px;
   cursor: pointer;
-  width: 22px;
+  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 {
+  background-image: radial-gradient(circle closest-side, hsla(200,100%,70%,.2), hsla(200,100%,70%,0));
+  -moz-image-region: rect(14px, 14px, 28px, 0);
+}
+
+#urlbar-reload-button:not([disabled]):hover:active {
+  background-image: radial-gradient(circle closest-side, hsla(200,100%,60%,.1), hsla(200,100%,60%,0));
+  -moz-image-region: rect(28px, 14px, 42px, 0);
+}
+
+#urlbar-reload-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
+  transform: scaleX(-1);
 }
 
-#go-button,
 #urlbar-go-button {
-  list-style-image: url("chrome://browser/skin/Go-arrow.png");
+  -moz-image-region: rect(0, 42px, 14px, 28px);
+}
+
+#urlbar-go-button:hover {
+  background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.2), hsla(110,70%,50%,0));
+  -moz-image-region: rect(14px, 42px, 28px, 28px);
+}
+
+#urlbar-go-button:hover:active {
+  background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.1), hsla(110,70%,50%,0));
+  -moz-image-region: rect(28px, 42px, 42px, 28px);
 }
 
-#go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
 #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   transform: scaleX(-1);
 }
 
-#urlbar-reload-button {
-  list-style-image: url("moz-icon://stock/gtk-refresh?size=menu");
+#urlbar-stop-button {
+  -moz-image-region: rect(0, 28px, 14px, 14px);
 }
 
-#urlbar-stop-button {
-  list-style-image: url("moz-icon://stock/gtk-stop?size=menu");
+#urlbar-stop-button:not([disabled]):hover {
+  background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.3), hsla(5,100%,75%,0));
+  -moz-image-region: rect(14px, 28px, 28px, 14px);
+}
+
+#urlbar-stop-button:hover:active {
+  background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.1), hsla(5,100%,75%,0));
+  -moz-image-region: rect(28px, 28px, 42px, 14px);
 }
 
 /* Popup blocker button */
@@ -1533,25 +1277,53 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-/* Star button */
-#star-button {
-  list-style-image: url("chrome://browser/skin/places/starPage.png");
+/* bookmarks menu-button */
+
+#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker {
+  -moz-appearance: none !important;
 }
 
-#star-button[starred="true"] {
-  list-style-image: url("chrome://browser/skin/places/pageStarred.png");
+#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+  padding: 9px 3px;
 }
 
-/* bookmarks menu-button */
+#bookmarks-menu-button[cui-areatype="toolbar"].bookmark-item > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
+#bookmarks-menu-button.bookmark-item {
+  list-style-image: url("chrome://browser/skin/Toolbar-small.png");
+}
+
+#bookmarks-menu-button.bookmark-item {
+  -moz-image-region: rect(0px 144px 16px 128px);
+}
 
-#bookmarks-menu-button[disabled] > .toolbarbutton-icon,
-#bookmarks-menu-button[disabled] > .toolbarbutton-menu-dropmarker,
-#bookmarks-menu-button[disabled] > .toolbarbutton-menubutton-dropmarker,
-#bookmarks-menu-button[disabled] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-#bookmarks-menu-button > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon {
+#bookmarks-menu-button.bookmark-item[starred] {
+  -moz-image-region: rect(16px 144px 32px 128px);
+}
+
+#bookmarks-menu-button[cui-areatype="toolbar"].bookmark-item > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+  -moz-image-region: rect(0px 160px 16px 144px);
+}
+
+#bookmarks-menu-button[disabled][cui-areatype="toolbar"] > .toolbarbutton-icon,
+#bookmarks-menu-button[disabled][cui-areatype="toolbar"] > .toolbarbutton-menu-dropmarker,
+#bookmarks-menu-button[disabled][cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker,
+#bookmarks-menu-button[disabled][cui-areatype="toolbar"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
+#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon {
   opacity: .4;
 }
 
+#BMB_bookmarksPopup[side="top"],
+#BMB_bookmarksPopup[side="bottom"] {
+  margin-left: -16px;
+  margin-right: -16px;
+}
+
+#BMB_bookmarksPopup[side="left"],
+#BMB_bookmarksPopup[side="right"] {
+  margin-top: -16px;
+  margin-bottom: -16px;
+}
+
 /* Bookmarking panel */
 #editBookmarkPanelStarIcon {
   list-style-image: url("chrome://browser/skin/places/starred48.png");
@@ -1612,147 +1384,52 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   text-shadow: none;
 }
 
-/* Throbber */
-#navigator-throbber {
-  width: 16px;
-  min-height: 16px;
-  margin: 0 3px;
-}
+/* Tabstrip */
 
-#navigator-throbber[busy="true"] {
-  list-style-image: url("chrome://global/skin/icons/loading_16.png");
-}
+%include ../shared/tabs.inc.css
 
-#navigator-throbber,
-#wrapper-navigator-throbber > #navigator-throbber {
-  list-style-image: url("chrome://global/skin/icons/notloading_16.png");
+#tabbrowser-tabs {
+  /* override the global style to allow the selected tab to be above the nav-bar */
+  z-index: auto;
 }
 
-/* Tabstrip */
-
 #TabsToolbar {
   min-height: 0;
   padding: 0;
+  position: relative;
 }
 
-#TabsToolbar[tabsontop=true]:not(:-moz-lwtheme) {
-  -moz-appearance: menubar;
-  color: -moz-menubartext;
-  box-shadow: 0 -1px 0 rgba(0,0,0,.1) inset;
-}
-
-#TabsToolbar[tabsontop=true]:not(:-moz-lwtheme):-moz-system-metric(menubar-drag) {
-  -moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbar-drag");
-}
-
-#TabsToolbar[tabsontop=false] {
-  background-image: linear-gradient(to top, rgba(0,0,0,.3) 1px, rgba(0,0,0,.05) 1px, transparent 50%);
-}
-
-.tabbrowser-tab,
-.tabs-newtab-button {
-  position: static;
-  -moz-appearance: none;
-  background: linear-gradient(hsla(0,0%,100%,.2), hsla(0,0%,45%,.2) 2px, hsla(0,0%,32%,.2) 80%);
-  background-origin: border-box;
-  background-position: 1px 2px;
-  background-size: 100% calc(100% - 2px);
-  background-repeat: no-repeat;
-  color: inherit;
-  margin: 0;
-  padding: 0;
-  border-width: 4px 5px 3px 6px;
-  border-style: solid;
-  border-image: url(tabbrowser/tab.png) 4 5 3 6 fill repeat stretch;
-  border-radius: 10px 8px 0 0;
-  min-height: 25px; /* reserve space for the sometimes hidden close button */
-}
-
-.tabbrowser-tab:hover,
-.tabs-newtab-button:hover {
-  background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.2) 4px, hsla(0,0%,75%,.2) 80%);
-}
-
-.tabbrowser-tab[selected="true"] {
-  background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%),
-                    linear-gradient(-moz-dialog, -moz-dialog);
-  color: -moz-dialogtext;
-}
-
-.tabbrowser-tab[remote] {
-  text-decoration: underline;
-}
-
-#main-window[tabsontop=false]:not([disablechrome]) .tabbrowser-tab[selected=true]:not(:-moz-lwtheme) {
-  background-image: linear-gradient(to top, rgba(0,0,0,.3) 1px, transparent 1px),
-                    linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%),
-                    linear-gradient(-moz-dialog, -moz-dialog);
-}
-
-.tabbrowser-tab[selected="true"]:-moz-lwtheme {
-  background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 32%);
-  color: inherit;
-}
-
-.tabbrowser-tab:-moz-lwtheme-brighttext:not([selected="true"]),
-.tabs-newtab-button:-moz-lwtheme-brighttext {
-  background-image: linear-gradient(hsla(0,0%,60%,.6), hsla(0,0%,40%,.6) 4px, hsla(0,0%,30%,.6) 80%);
-}
-
-.tabbrowser-tab:-moz-lwtheme-brighttext:not([selected="true"]):hover,
-.tabs-newtab-button:-moz-lwtheme-brighttext:hover {
-  background-image: linear-gradient(hsla(0,0%,80%,.6), hsla(0,0%,60%,.6) 4px, hsla(0,0%,45%,.6) 80%);
-}
-
-.tabbrowser-tab:-moz-lwtheme-darktext:not([selected="true"]),
-.tabs-newtab-button:-moz-lwtheme-darktext {
-  background-image: linear-gradient(hsla(0,0%,100%,.5), hsla(0,0%,60%,.5) 4px, hsla(0,0%,45%,.5) 80%);
+/*
+ * Draw the bottom border of the tabstrip:
+ */
+#TabsToolbar::after {
+  content: "";
+  position: absolute;
+  bottom: 1px;
+  left: 0;
+  right: 0;
+  z-index: 0;
+  border-bottom: 1px solid hsla(0,0%,0%,.3);
 }
 
-.tabbrowser-tab:-moz-lwtheme-darktext:not([selected="true"]):hover,
-.tabs-newtab-button:-moz-lwtheme-darktext:hover {
-  background-image: linear-gradient(hsla(0,0%,100%,.5), hsla(0,0%,80%,.5) 4px, hsla(0,0%,60%,.5) 80%);
+#TabsToolbar:not(:-moz-lwtheme) {
+  -moz-appearance: menubar;
+  color: -moz-menubartext;
 }
 
-.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) {
-  background-image: radial-gradient(circle farthest-corner at 50% 3px, rgba(233,242,252,1) 3%, rgba(172,206,255,.75) 40%, rgba(87,151,201,.5) 80%, rgba(87,151,201,0));
-}
-.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]):hover {
-  background-image: linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.6) 2px, hsla(0,0%,75%,.2) 80%),
-                    radial-gradient(circle farthest-corner at 50% 3px, rgba(233,242,252,1) 3%, rgba(172,206,255,.75) 40%, rgba(87,151,201,.5) 80%, rgba(87,151,201,0));
+#toolbar-menubar:not([autohide="true"]):not(:-moz-lwtheme):-moz-system-metric(menubar-drag),
+#TabsToolbar:not(:-moz-lwtheme):-moz-system-metric(menubar-drag) {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
 }
 
-#tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab > .tab-stack > .tab-content[pinned] {
-  min-height: 18px; /* corresponds to the max. height of non-textual tab contents, i.e. the tab close button */
+#TabsToolbar:not(:-moz-lwtheme) > #tabbrowser-tabs > .tabbrowser-tab:not([selected]) {
+  color: -moz-menubartext;
 }
 
-.tabbrowser-tab:focus > .tab-stack {
+.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label {
   outline: 1px dotted;
 }
 
-.tab-throbber,
-.tab-icon-image {
-  width: 16px;
-  height: 16px;
-  -moz-margin-end: 3px;
-  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
-}
-
-.tab-throbber {
-  list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png");
-}
-
-.tab-throbber[progress] {
-  list-style-image: url("chrome://browser/skin/tabbrowser/loading.png");
-}
-
-.tab-throbber[pinned],
-.tab-icon-image[pinned],
-.tabs-newtab-button > .toolbarbutton-icon {
-  -moz-margin-start: 2px;
-  -moz-margin-end: 2px;
-}
-
 #context_reloadTab {
   list-style-image: url("moz-icon://stock/gtk-refresh?size=menu");
 }
@@ -1776,7 +1453,8 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
 /* Tab drag and drop */
 .tab-drop-indicator {
   list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png);
-  margin-bottom: -11px;
+  margin-bottom: -9px;
+  z-index: 3;
 }
 
 /* In-tab close button */
@@ -1787,11 +1465,10 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
 }
 
 .tab-close-button {
-  padding: 0;
   list-style-image: url("moz-icon://stock/gtk-close?size=menu");
-  margin-top: -1px;
+  margin-top: 0;
   margin-bottom: -1px;
-  -moz-margin-end: -1px;
+  -moz-margin-end: -4px;
 }
 
 /* Tabstrip new tab button */
@@ -1912,10 +1589,6 @@ toolbarbutton.chevron > .toolbarbutton-icon {
   margin: 0;
 }
 
-toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon {
-  display: -moz-box; /* display chevron icon in text mode */
-}
-
 /* Ctrl-Tab */
 
 .ctrlTab-preview {
@@ -1953,80 +1626,6 @@ toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon {
   margin-top: 10px;
 }
 
-/* Application button menu */
-
-.splitmenu-menuitem {
-  -moz-margin-end: 1px;
-}
-
-#appmenu-toolbar-button:not(:hover):not([open]):not(:-moz-lwtheme) {
-  color: inherit;
-}
-
-#appmenu-toolbar-button > .toolbarbutton-text,
-#appmenu-toolbar-button > .toolbarbutton-menu-dropmarker {
-  margin-top: -2px !important;
-  margin-bottom: -2px !important;
-}
-#appmenuSecondaryPane {
-  -moz-border-start: 1px solid ThreeDShadow;
-}
-#appmenuSecondaryPane-spacer {
-  min-height: 1em;
-}
-#appmenu-cut,
-#appmenu-editmenu-cut {
-  list-style-image: url("moz-icon://stock/gtk-cut?size=menu");
-}
-#appmenu-copy,
-#appmenu-editmenu-copy {
-  list-style-image: url("moz-icon://stock/gtk-copy?size=menu");
-}
-#appmenu-paste,
-#appmenu-editmenu-paste {
-  list-style-image: url("moz-icon://stock/gtk-paste?size=menu");
-}
-#wrapper-appmenu-toolbar-button,
-.appmenu-edit-button[disabled="true"] {
-  opacity: .3;
-}
-
-/* Add-on bar */
-
-#addon-bar {
-  box-shadow: 0 1px 0 rgba(0,0,0,.15) inset;
-  padding: 0;
-  min-height: 20px;
-}
-
-#status-bar {
-  min-height: 0;
-  -moz-appearance: none;
-  background-color: transparent;
-  border: none;
-}
-
-#addon-bar[customizing] > #status-bar {
-  opacity: .5;
-  background-image: repeating-linear-gradient(135deg,
-                                              rgba(255,255,255,.3), rgba(255,255,255,.3) 5px,
-                                              rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px);
-}
-
-#status-bar > statusbarpanel {
-  border-width: 0;
-  -moz-appearance: none;
-}
-
-#addonbar-closebutton {
-  list-style-image: url("moz-icon://stock/gtk-close?size=menu");
-}
-
-#addonbar-closebutton > .toolbarbutton-icon {
-  margin-top: -2px;
-  margin-bottom: -2px;
-}
-
 /* Status panel */
 
 .statuspanel-label {
@@ -2228,6 +1827,46 @@ chatbox {
   border-top-right-radius: 2.5px;
 }
 
+/* Customization mode */
+
+%include ../shared/customizableui/customizeMode.inc.css
+
+#main-window[customizing] #tab-view-deck {
+  background-image: url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"),
+                    url("chrome://browser/skin/customizableui/background-noise-toolbar.png"),
+                    linear-gradient(to bottom, #bcbcbc, #b5b5b5);
+  background-attachment: fixed;
+}
+
+#main-window:-moz-any([customize-entering],[customize-entered]) #tab-view-deck {
+  padding: 2em;
+}
+
+#main-window[customize-entered] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar),
+#main-window[customize-entered] #customization-container {
+  border: 3px solid hsla(0,0%,0%,.1);
+  border-top-width: 0;
+  background-clip: padding-box;
+  background-origin: padding-box;
+  -moz-border-right-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2);
+  -moz-border-bottom-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2);
+  -moz-border-left-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2);
+}
+
+#main-window[customize-entered] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
+  border-bottom-width: 0;
+}
+
+#main-window[customize-entered] #TabsToolbar {
+  -moz-appearance: none;
+  background-clip: padding-box;
+  border-right: 3px solid transparent;
+  border-left: 3px solid transparent;
+}
+
+/* End customization mode */
+
+
 #main-window[privatebrowsingmode=temporary] #TabsToolbar::before {
   display: -moz-box;
   content: "";
diff --git a/browser/themes/linux/customizableui/background-noise-toolbar.png b/browser/themes/linux/customizableui/background-noise-toolbar.png
new file mode 100644
index 0000000000000000000000000000000000000000..d09ba9dafb5ede66e92ce577ecaa6f9575dba104
Binary files /dev/null and b/browser/themes/linux/customizableui/background-noise-toolbar.png differ
diff --git a/browser/themes/linux/customizableui/customizeMode-gridTexture.png b/browser/themes/linux/customizableui/customizeMode-gridTexture.png
new file mode 100644
index 0000000000000000000000000000000000000000..a7c2775cfc799da31a505b249f5a59b89c148a58
Binary files /dev/null and b/browser/themes/linux/customizableui/customizeMode-gridTexture.png differ
diff --git a/browser/themes/linux/customizableui/customizeMode-separatorHorizontal.png b/browser/themes/linux/customizableui/customizeMode-separatorHorizontal.png
new file mode 100644
index 0000000000000000000000000000000000000000..5e17cb4db08e310e6c3a9e14c5bd722772dfb639
Binary files /dev/null and b/browser/themes/linux/customizableui/customizeMode-separatorHorizontal.png differ
diff --git a/browser/themes/linux/customizableui/customizeMode-separatorVertical.png b/browser/themes/linux/customizableui/customizeMode-separatorVertical.png
new file mode 100644
index 0000000000000000000000000000000000000000..dc4caee812878f246c87d71093768eb36c5656fc
Binary files /dev/null and b/browser/themes/linux/customizableui/customizeMode-separatorVertical.png differ
diff --git a/browser/themes/linux/customizableui/panelUIOverlay.css b/browser/themes/linux/customizableui/panelUIOverlay.css
new file mode 100644
index 0000000000000000000000000000000000000000..c9a604c01a47daf133d5a8d370f2f22bf4b2b547
--- /dev/null
+++ b/browser/themes/linux/customizableui/panelUIOverlay.css
@@ -0,0 +1,9 @@
+/* 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/customizableui/panelUIOverlay.inc.css
+
+#BMB_bookmarksPopup > menuitem[type="checkbox"] {
+  -moz-appearance: none !important; /* important, to override toolkit rule */
+}
diff --git a/browser/themes/linux/downloads/indicator.css b/browser/themes/linux/downloads/indicator.css
index d7e3f29bbab8dfebd6e6a2b22d6ca562542f7965..086baf4fad6a3bf635593c2c788a27258d255ae0 100644
--- a/browser/themes/linux/downloads/indicator.css
+++ b/browser/themes/linux/downloads/indicator.css
@@ -17,33 +17,14 @@
   z-index: 5;
 }
 
-toolbar[iconsize="small"] > #downloads-button > #downloads-indicator-anchor {
-  min-width: 16px;
-  min-height: 16px;
-}
-
-toolbar[iconsize="large"] > #downloads-button > #downloads-indicator-anchor {
-  min-width: 24px;
-  min-height: 24px;
-}
-
 /*** Main indicator icon ***/
 
-toolbar[iconsize="small"] > #downloads-button > #downloads-indicator-anchor > #downloads-indicator-icon {
-  background: -moz-image-rect(url("chrome://browser/skin/Toolbar-small.png"),
-                              0, 16, 16, 0) center no-repeat;
-}
-
-toolbar[iconsize="large"] > #downloads-button > #downloads-indicator-anchor > #downloads-indicator-icon {
+#downloads-button[cui-areatype="toolbar"] > #downloads-indicator-anchor > #downloads-indicator-icon {
   background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
-                              0, 24, 24, 0) center no-repeat;
-}
-
-toolbar[iconsize="small"] > #downloads-button[attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
-  background-image: url("chrome://browser/skin/downloads/download-glow-small.png");
+                              0, 198, 18, 180) center no-repeat;
 }
 
-toolbar[iconsize="large"] > #downloads-button[attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
+#downloads-button[cui-areatype="toolbar"][attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
   background-image: url("chrome://browser/skin/downloads/download-glow.png");
 }
 
@@ -159,8 +140,3 @@ toolbar[iconsize="large"] > #downloads-button[attention] > #downloads-indicator-
 #downloads-button[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
   background-image: linear-gradient(#4b5000, #515700);
 }
-
-toolbar[mode="full"] > #downloads-button > .toolbarbutton-text {
-  margin: 0;
-  text-align: center;
-}
diff --git a/browser/themes/linux/jar.mn b/browser/themes/linux/jar.mn
index a082f41e0a39f61bac762fb8e69e62ef8821a980..461e6a88af323f7c41e3b9233c9dc8eb55c70483 100644
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -21,12 +21,16 @@ browser.jar:
   skin/classic/browser/aboutTabCrashed.css
   skin/classic/browser/actionicon-tab.png
 * skin/classic/browser/browser.css
+* skin/classic/browser/browser-lightweightTheme.css
   skin/classic/browser/click-to-play-warning-stripes.png
+  skin/classic/browser/customizableui/background-noise-toolbar.png  (customizableui/background-noise-toolbar.png)
+  skin/classic/browser/customizableui/customizeMode-gridTexture.png  (customizableui/customizeMode-gridTexture.png)
+  skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png  (customizableui/customizeMode-separatorHorizontal.png)
+  skin/classic/browser/customizableui/customizeMode-separatorVertical.png  (customizableui/customizeMode-separatorVertical.png)
 * skin/classic/browser/engineManager.css
   skin/classic/browser/fullscreen-darknoise.png
   skin/classic/browser/Geolocation-16.png
   skin/classic/browser/Geolocation-64.png
-  skin/classic/browser/Go-arrow.png
   skin/classic/browser/identity.png
   skin/classic/browser/identity-icons-generic.png
   skin/classic/browser/identity-icons-https.png
@@ -34,6 +38,11 @@ browser.jar:
   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/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
@@ -50,17 +59,20 @@ browser.jar:
   skin/classic/browser/Privacy-16.png
   skin/classic/browser/Privacy-48.png
   skin/classic/browser/privatebrowsing-mask.png
+  skin/classic/browser/reload-stop-go.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/Secure.png
   skin/classic/browser/Security-broken.png
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/slowStartup-16.png
   skin/classic/browser/Toolbar.png
+  skin/classic/browser/Toolbar-inverted.png
   skin/classic/browser/Toolbar-small.png
   skin/classic/browser/urlbar-arrow.png
   skin/classic/browser/webRTC-shareDevice-16.png
   skin/classic/browser/webRTC-shareDevice-64.png
   skin/classic/browser/webRTC-sharingDevice-16.png
+* skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
   skin/classic/browser/downloads/allDownloadsViewOverlay.css   (downloads/allDownloadsViewOverlay.css)
   skin/classic/browser/downloads/buttons.png          (downloads/buttons.png)
   skin/classic/browser/downloads/contentAreaDownloadsView.css  (downloads/contentAreaDownloadsView.css)
@@ -85,7 +97,6 @@ browser.jar:
   skin/classic/browser/places/calendar.png            (places/calendar.png)
 * skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
   skin/classic/browser/places/livemark-item.png       (places/livemark-item.png)
-  skin/classic/browser/places/pageStarred.png         (places/pageStarred.png)
   skin/classic/browser/places/star-icons.png          (places/star-icons.png)
   skin/classic/browser/places/starred48.png           (places/starred48.png)
   skin/classic/browser/places/unstarred48.png         (places/unstarred48.png)
@@ -93,7 +104,6 @@ browser.jar:
   skin/classic/browser/places/organizer.css           (places/organizer.css)
   skin/classic/browser/places/organizer.xml           (places/organizer.xml)
   skin/classic/browser/places/query.png               (places/query.png)
-  skin/classic/browser/places/starPage.png            (places/starPage.png)
   skin/classic/browser/places/tag.png                 (places/tag.png)
   skin/classic/browser/places/toolbarDropMarker.png   (places/toolbarDropMarker.png)
   skin/classic/browser/places/unsortedBookmarks.png   (places/unsortedBookmarks.png)
@@ -116,8 +126,21 @@ browser.jar:
   skin/classic/browser/tabbrowser/connecting.png      (tabbrowser/connecting.png)
   skin/classic/browser/tabbrowser/loading.png         (tabbrowser/loading.png)
   skin/classic/browser/tabbrowser/tab.png             (tabbrowser/tab.png)
-  skin/classic/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png)
-  skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
+  skin/classic/browser/tabbrowser/tab-active-middle.png     (tabbrowser/tab-active-middle.png)
+  skin/classic/browser/tabbrowser/tab-background-end.png    (tabbrowser/tab-background-end.png)
+  skin/classic/browser/tabbrowser/tab-background-middle.png (tabbrowser/tab-background-middle.png)
+  skin/classic/browser/tabbrowser/tab-background-start.png  (tabbrowser/tab-background-start.png)
+  skin/classic/browser/tabbrowser/tab-overflow-border.png   (tabbrowser/tab-overflow-border.png)
+
+# NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in
+#       Makefile.in with a non-default marker of "%" and the result of that gets packaged.
+  skin/classic/browser/tabbrowser/tab-selected-end.svg      (tab-selected-end.svg)
+  skin/classic/browser/tabbrowser/tab-selected-start.svg    (tab-selected-start.svg)
+
+  skin/classic/browser/tabbrowser/tab-stroke-end.png        (tabbrowser/tab-stroke-end.png)
+  skin/classic/browser/tabbrowser/tab-stroke-start.png      (tabbrowser/tab-stroke-start.png)
+  skin/classic/browser/tabbrowser/tabDragIndicator.png      (tabbrowser/tabDragIndicator.png)
+  skin/classic/browser/tabbrowser/tab-separator.png         (tabbrowser/tab-separator.png)
   skin/classic/browser/tabview/edit-light.png         (tabview/edit-light.png)
   skin/classic/browser/tabview/search.png             (tabview/search.png)
   skin/classic/browser/tabview/stack-expander.png     (tabview/stack-expander.png)
diff --git a/browser/themes/linux/linuxShared.inc b/browser/themes/linux/linuxShared.inc
new file mode 100644
index 0000000000000000000000000000000000000000..fc70d58aab98f9ad0642c07d7c08cdaa590ae226
--- /dev/null
+++ b/browser/themes/linux/linuxShared.inc
@@ -0,0 +1,10 @@
+/* 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/. */
+
+%filter substitution
+
+%define toolbarHighlight rgba(255,255,255,.3)
+%define fgTabTexture linear-gradient(transparent 0px, transparent 2px, hsla(0,0%,100%,0.35) 2px, hsla(0,0%,100%,0.35) 3px, hsla(0,0%,100%,0.65) 3px, hsla(0,0%,100%,0.65) 4px, @toolbarHighlight@)
+%define fgTabTextureLWT @fgTabTexture@
+%define fgTabBackgroundColor -moz-dialog
diff --git a/browser/themes/linux/menuPanel-customize.png b/browser/themes/linux/menuPanel-customize.png
new file mode 100644
index 0000000000000000000000000000000000000000..e0b0a70a3b82a18c974bd1bc5f1dff863405dd61
Binary files /dev/null and b/browser/themes/linux/menuPanel-customize.png differ
diff --git a/browser/themes/linux/menuPanel-exit.png b/browser/themes/linux/menuPanel-exit.png
new file mode 100644
index 0000000000000000000000000000000000000000..6359d7262a286a34074f6f245636ad15a95993b5
Binary files /dev/null and b/browser/themes/linux/menuPanel-exit.png differ
diff --git a/browser/themes/linux/menuPanel-help.png b/browser/themes/linux/menuPanel-help.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d23717748de84d681bfabd3c326420931a90e84
Binary files /dev/null and b/browser/themes/linux/menuPanel-help.png differ
diff --git a/browser/themes/linux/menuPanel-small.png b/browser/themes/linux/menuPanel-small.png
new file mode 100644
index 0000000000000000000000000000000000000000..4cd3e52b13d26ae5c4d85cb3ed3c00cd6c70f2ab
Binary files /dev/null and b/browser/themes/linux/menuPanel-small.png differ
diff --git a/browser/themes/linux/menuPanel.png b/browser/themes/linux/menuPanel.png
new file mode 100644
index 0000000000000000000000000000000000000000..59061ec0aaa38b85dddacb4c31f257c4ad43ecf5
Binary files /dev/null and b/browser/themes/linux/menuPanel.png differ
diff --git a/browser/themes/linux/places/pageStarred.png b/browser/themes/linux/places/pageStarred.png
deleted file mode 100644
index 61a9f90e05b15a6206727be766294d7baa593995..0000000000000000000000000000000000000000
Binary files a/browser/themes/linux/places/pageStarred.png and /dev/null differ
diff --git a/browser/themes/linux/places/starPage.png b/browser/themes/linux/places/starPage.png
deleted file mode 100644
index 3193a3535f1e390211aa403ad757b10cc9d5a884..0000000000000000000000000000000000000000
Binary files a/browser/themes/linux/places/starPage.png and /dev/null differ
diff --git a/browser/themes/linux/reload-stop-go.png b/browser/themes/linux/reload-stop-go.png
new file mode 100644
index 0000000000000000000000000000000000000000..1017be9032a298c8aa1f4a5cd4576087d8bb6f0d
Binary files /dev/null and b/browser/themes/linux/reload-stop-go.png differ
diff --git a/browser/themes/linux/tabbrowser/tab-active-middle.png b/browser/themes/linux/tabbrowser/tab-active-middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3e5e18ba3ceddcf098a5b98a5f40c784a7e3d52
Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-active-middle.png differ
diff --git a/browser/themes/linux/tabbrowser/tab-background-end.png b/browser/themes/linux/tabbrowser/tab-background-end.png
new file mode 100644
index 0000000000000000000000000000000000000000..2e515a39efeaafc71c8ee00bc29baa7ca952ce0f
Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-background-end.png differ
diff --git a/browser/themes/linux/tabbrowser/tab-background-middle.png b/browser/themes/linux/tabbrowser/tab-background-middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..addb64b13f422a34d6b87e4e75488f9fa2e35ba3
Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-background-middle.png differ
diff --git a/browser/themes/linux/tabbrowser/tab-background-start.png b/browser/themes/linux/tabbrowser/tab-background-start.png
new file mode 100644
index 0000000000000000000000000000000000000000..243bf0099ffe7760843fc75b98d1029d9c9efbef
Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-background-start.png differ
diff --git a/browser/themes/linux/tabbrowser/tab-separator.png b/browser/themes/linux/tabbrowser/tab-separator.png
new file mode 100644
index 0000000000000000000000000000000000000000..63f77f1b760b2e66e2fab7e739979b7cdede2116
Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-separator.png differ
diff --git a/browser/themes/linux/tabbrowser/tab-stroke-end.png b/browser/themes/linux/tabbrowser/tab-stroke-end.png
new file mode 100644
index 0000000000000000000000000000000000000000..099978580391777f4fdd196fc9aa160ebf4123a7
Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-stroke-end.png differ
diff --git a/browser/themes/linux/tabbrowser/tab-stroke-start.png b/browser/themes/linux/tabbrowser/tab-stroke-start.png
new file mode 100644
index 0000000000000000000000000000000000000000..e5a7b5ee9aecb73410b5cacdd4951b2520b54bca
Binary files /dev/null and b/browser/themes/linux/tabbrowser/tab-stroke-start.png differ
diff --git a/browser/themes/osx/Makefile.in b/browser/themes/osx/Makefile.in
index 173ca68435c6cf993204e3cca62ac579ab2537ba..67f553d6ef9c39898f407b06a620793765675727 100644
--- a/browser/themes/osx/Makefile.in
+++ b/browser/themes/osx/Makefile.in
@@ -5,3 +5,23 @@
 ICON_FILES := icon.png
 ICON_DEST = $(FINAL_TARGET)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
 INSTALL_TARGETS += ICON
+
+# By default, the pre-processor used for jar.mn will use "%" as a marker for ".css" files and "#"
+# otherwise. This falls apart when a file using one marker needs to include a file with the other
+# marker since the pre-processor instructions in the included file will not be processed. The
+# following SVG files need to include a file which uses "%" as the marker so we invoke the pre-
+# processor ourselves here with the marker specified. The resulting SVG files will get packaged by
+# the processing of the jar file in this directory.
+tab-selected-svg: $(srcdir)/../shared/tab-selected.svg
+	$(call py_action,preprocessor, \
+	  --marker "%" -D TAB_SIDE=start \
+	  $(ACDEFINES) \
+	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-start.svg)
+	$(call py_action,preprocessor, \
+	  --marker "%" -D TAB_SIDE=end \
+	  $(ACDEFINES) \
+	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-end.svg)
+
+.PHONY: tab-selected-svg
+
+export:: tab-selected-svg
diff --git a/browser/themes/osx/Toolbar-background-noise.png b/browser/themes/osx/Toolbar-background-noise.png
new file mode 100644
index 0000000000000000000000000000000000000000..aab0a02c84d63603ec1fc3a385a08c5cf5360fd2
Binary files /dev/null and b/browser/themes/osx/Toolbar-background-noise.png differ
diff --git a/browser/themes/osx/Toolbar-inverted.png b/browser/themes/osx/Toolbar-inverted.png
new file mode 100644
index 0000000000000000000000000000000000000000..b09decd7a34c1eed025073756b885a0c1d0720e3
Binary files /dev/null and b/browser/themes/osx/Toolbar-inverted.png differ
diff --git a/browser/themes/osx/Toolbar-inverted@2x.png b/browser/themes/osx/Toolbar-inverted@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..4547610430304709a8f23833b15fe82425e7ee53
Binary files /dev/null and b/browser/themes/osx/Toolbar-inverted@2x.png differ
diff --git a/browser/themes/osx/Toolbar-lion.png b/browser/themes/osx/Toolbar-lion.png
deleted file mode 100644
index a91ba7bfd66d6fc9301e77f111b3aa21aaec5b50..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/Toolbar-lion.png and /dev/null differ
diff --git a/browser/themes/osx/Toolbar-lion@2x.png b/browser/themes/osx/Toolbar-lion@2x.png
deleted file mode 100644
index 10b7994858574011d207310e4b79b165f468330a..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/Toolbar-lion@2x.png and /dev/null differ
diff --git a/browser/themes/osx/Toolbar.png b/browser/themes/osx/Toolbar.png
index c1868929dd8edf012a0f720931d163309cd9da11..60261520e9b73bb62ebfd0d7562cd47a508ff12a 100644
Binary files a/browser/themes/osx/Toolbar.png and b/browser/themes/osx/Toolbar.png differ
diff --git a/browser/themes/osx/Toolbar@2x.png b/browser/themes/osx/Toolbar@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..88ff4569ee336884329d9a07e78fdaaddc3bc432
Binary files /dev/null and b/browser/themes/osx/Toolbar@2x.png differ
diff --git a/browser/themes/osx/browser-lightweightTheme.css b/browser/themes/osx/browser-lightweightTheme.css
new file mode 100644
index 0000000000000000000000000000000000000000..03d3b3d731c1747cf0d3f0bdb0645bbfbd35cad4
--- /dev/null
+++ b/browser/themes/osx/browser-lightweightTheme.css
@@ -0,0 +1,28 @@
+/* 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.inc
+
+/*
+ * LightweightThemeListener will append the current lightweight theme's header
+ * image to the background-image for each of the following rulesets.
+ */
+
+/* Lightweight theme on tabs */
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
+  background-attachment: scroll, fixed;
+  background-color: transparent;
+  background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
+  background-position: 0 0, right top;
+}
+
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
+  background-attachment: scroll, scroll, fixed;
+  background-color: transparent;
+  background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
+                    @fgTabTextureLWT@;/*,
+                    lwtHeader;*/
+  background-position: 0 0, 0 0, right top;
+}
diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css
index d3ebbae79d8459990274da5d91033465c4256ba3..ec932255d097b813eeb50b05a18aee7048abb5b3 100644
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -7,8 +7,10 @@
 %include shared.inc
 %filter substitution
 %define forwardTransitionLength 150ms
-%define conditionalForwardWithUrlbar window:not([chromehidden~=toolbar]) #navigator-toolbox[iconsize=large][mode=icons] > :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"],#nav-bar:not([currentset])) > #unified-back-forward-button
+%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
 %define conditionalForwardWithUrlbarWidth 27
+%define spaceAboveTabbar 9px
+%define toolbarButtonPressed :hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"])
 
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 @namespace html url("http://www.w3.org/1999/xhtml");
@@ -18,42 +20,65 @@
   opacity: .9;
 }
 
+#navigator-toolbox::after {
+  -moz-box-ordinal-group: 101; /* tabs toolbar is 100 */
+  background-image: linear-gradient(to top, hsla(0,0%,0%,.15), hsla(0,0%,0%,.15) 1px, hsla(0,0%,100%,.15) 1px, hsla(0,0%,100%,.15) 2px, transparent 3px);
+  content: "";
+  display: -moz-box;
+  height: 2px;
+  margin-top: -2px;
+  position: relative;
+  z-index: 2; /* navbar is at 1 */
+}
+
 #navigator-toolbox toolbarbutton:-moz-lwtheme {
   color: inherit;
   text-shadow: inherit;
 }
 
-#PersonalToolbar:-moz-lwtheme,
-#nav-bar:-moz-lwtheme,
-#main-window[privatebrowsingmode=temporary] #nav-bar[tabsontop=false] {
-  -moz-appearance: none !important;
-  background: none !important;
-  /* Switching to a lightweight theme shouldn't move the content area,
-     so avoid changing border widths here. */
-  border-color: transparent !important;
-}
-
 #main-window {
   -moz-appearance: none;
   background-color: #eeeeee;
 }
 
-#titlebar-buttonbox-container,
-#main-window:not([drawintitlebar=true]) > #titlebar {
+#titlebar-buttonbox > .titlebar-button {
   display: none;
 }
 
-#titlebar {
-  height: 22px;
+/* NB: these would be -moz-margin-start/end if it wasn't for the fact that OS X
+ * doesn't reverse the order of the items in the titlebar in RTL mode. */
+.titlebar-placeholder[type="caption-buttons"],
+#titlebar-buttonbox {
+  margin-left: 7px;
 }
 
-#main-window[chromehidden~="toolbar"][chromehidden~="location"][chromehidden~="directories"] {
-  border-top: 1px solid rgba(0,0,0,0.65);
+@media (-moz-mac-lion-theme) {
+  .titlebar-placeholder[type="fullscreen-button"],
+  #titlebar-fullscreen-button {
+    margin-right: 7px;
+  }
 }
 
-#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
-  -moz-box-align: center;
-  padding: 2px 4px;
+/* Fullscreen and caption buttons don't move with RTL on OS X so override the automatic ordering. */
+.titlebar-placeholder[type="fullscreen-button"]:-moz-locale-dir(ltr),
+.titlebar-placeholder[type="caption-buttons"]:-moz-locale-dir(rtl) {
+  -moz-box-ordinal-group: 1000;
+}
+.titlebar-placeholder[type="caption-buttons"]:-moz-locale-dir(ltr),
+.titlebar-placeholder[type="fullscreen-button"]:-moz-locale-dir(rtl) {
+  -moz-box-ordinal-group: 0;
+}
+
+#main-window[chromehidden~="toolbar"] > #titlebar {
+  padding-top: 22px;
+}
+
+#main-window:not(:-moz-lwtheme):not([privatebrowsingmode=temporary]) > #titlebar {
+  -moz-appearance: -moz-window-titlebar;
+}
+
+#main-window[chromehidden~="toolbar"][chromehidden~="location"][chromehidden~="directories"] {
+  border-top: 1px solid rgba(0,0,0,0.65);
 }
 
 /* Because of -moz-box-align: center above, separators will be invisible unless
@@ -62,49 +87,54 @@ toolbarseparator {
   min-height: 22px;
 }
 
-/* We need more height when toolbar buttons show both icon and text. */
-toolbar[mode="full"] toolbarseparator {
-  min-height: 36px;
+#navigator-toolbox > toolbar:not(#TabsToolbar):not(#nav-bar):not(:-moz-lwtheme) {
+  -moz-appearance: none;
+  background: url(chrome://browser/skin/Toolbar-background-noise.png) hsl(0,0%,83%);
 }
 
 #nav-bar {
-  padding-bottom: 4px !important;
+  -moz-appearance: none;
+  background: url(chrome://browser/skin/Toolbar-background-noise.png),
+              linear-gradient(hsl(0,0%,93%), hsl(0,0%,83%));
+  background-clip: border-box;
+  background-origin: border-box !important;
+
+  /* Move the noise texture out of the top 1px strip because that overlaps
+     with the tabbar and we don't want to repaint it when animating tabs.
+     The noise image is at least 100px high, so repeating it only horizontally
+     is enough. */
+  background-repeat: repeat-x, no-repeat;
+  background-position: 0 1px, 0 0;
+
+  box-shadow: inset 0 1px 0 hsla(0,0%,100%,.4);
+  margin-top: -1px;
+  /* Position the toolbar above the bottom of background tabs */
+  position: relative;
+  z-index: 1;
 }
 
-#PersonalToolbar {
-  -moz-appearance: none;
-  margin-top: -2px; /* overlay the bottom border of the toolbar above us */
-  padding-top: 1px !important;
-  background-color: -moz-mac-chrome-active;
-  border-bottom: 1px solid rgba(0, 0, 0, 0.57);
+@media (min-resolution: 2dppx) {
+  #nav-bar {
+    background-size: 100px 100px, auto;
+  }
 }
 
-#nav-bar[tabsontop=true],
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar,
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar {
-  -moz-appearance: none;
-  margin-top: 0; /* don't overlay the bottom border of the tabs toolbar */
-  padding-top: 4px !important;
-  border-bottom: 1px solid rgba(0, 0, 0, 0.57);
-  background-color: -moz-mac-chrome-active;
-  background-image: linear-gradient(rgba(255,255,255,.43), rgba(255,255,255,0)) !important; /* override lwtheme style */
-  background-origin: border-box !important;
+#nav-bar-customization-target {
+  padding: 4px;
 }
 
-#PersonalToolbar:-moz-lwtheme,
-#nav-bar[tabsontop=true]:-moz-lwtheme,
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar:-moz-lwtheme,
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar:-moz-lwtheme {
-  background-color: transparent;
-  border-bottom-color: transparent;
+#PersonalToolbar {
+  padding: 0 4px 4px;
+}
+
+#navigator-toolbox > toolbar:not(#TabsToolbar):-moz-lwtheme {
+  background-color: @toolbarColorLWT@;
+  background-image: url(chrome://browser/skin/Toolbar-background-noise.png);
 }
 
 #PersonalToolbar:not(:-moz-lwtheme):-moz-window-inactive,
-#nav-bar[tabsontop=true]:not(:-moz-lwtheme):-moz-window-inactive,
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar:not(:-moz-lwtheme):-moz-window-inactive,
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar:not(:-moz-lwtheme):-moz-window-inactive {
+#nav-bar:not(:-moz-lwtheme):-moz-window-inactive {
   background-color: -moz-mac-chrome-inactive;
-  border-bottom-color: rgba(0, 0, 0, 0.32);
 }
 
 /* ----- BOOKMARK TOOLBAR ----- */
@@ -123,10 +153,6 @@ toolbarbutton.chevron > .toolbarbutton-text {
   display: none;
 }
 
-toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon {
-  display: -moz-box; /* display chevron icon in text mode */
-}
-
 toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   transform: scaleX(-1);
 }
@@ -143,7 +169,8 @@ toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon {
 
 /* ----- BOOKMARK BUTTONS ----- */
 
-toolbarbutton.bookmark-item {
+toolbarbutton.bookmark-item,
+#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder {
   font-weight: bold;
   color: #222;
   border: 0;
@@ -171,8 +198,9 @@ toolbarbutton.bookmark-item {
   }
 }
 
-.bookmark-item > .toolbarbutton-text {
-  display: -moz-box !important; /* prevent [mode="icons"] from hiding the label */
+.bookmark-item > .toolbarbutton-text,
+#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-text {
+  display: -moz-box !important; /* Force the display of the label for bookmarks */
   margin: 0 !important;
 }
 
@@ -210,14 +238,16 @@ toolbarbutton.bookmark-item > menupopup {
   -moz-margin-start: 3px;
 }
 
-.bookmark-item > .toolbarbutton-icon {
+.bookmark-item > .toolbarbutton-icon,
+#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
   width: 16px;
   min-height: 16px;
   max-height: 16px;
 }
 
 .bookmark-item > .toolbarbutton-icon[label]:not([label=""]),
-.bookmark-item > .toolbarbutton-icon[type="menu"] {
+.bookmark-item > .toolbarbutton-icon[type="menu"],
+#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon[label]:not([label=""]) {
   -moz-margin-end: 5px;
 }
 
@@ -311,31 +341,22 @@ toolbarbutton.bookmark-item > menupopup {
 
 @media (min-resolution: 2dppx) {
   .bookmark-item > .toolbarbutton-icon,
-  .bookmark-item > .menu-iconic-left > .menu-iconic-icon {
+  .bookmark-item > .menu-iconic-left > .menu-iconic-icon,
+  #personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
     image-rendering: -moz-crisp-edges;
   }
 }
 
-#wrapper-personal-bookmarks[place="palette"] > .toolbarpaletteitem-box {
-  background: url("chrome://browser/skin/places/bookmarksToolbar.png") no-repeat center;
-}
-
-.bookmarks-toolbar-customize {
-  max-width: 15em !important;
+#bookmarks-toolbar-placeholder {
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important;
 }
 
 @media (min-resolution: 2dppx) {
-  #wrapper-personal-bookmarks[place="palette"] > .toolbarpaletteitem-box {
-    background-image: url("chrome://browser/skin/places/bookmarksToolbar@2x.png");
-    background-size: 16px;
-  }
-
-  .bookmarks-toolbar-customize {
+  #bookmarks-toolbar-placeholder {
     list-style-image: url("chrome://browser/skin/places/bookmarksToolbar@2x.png") !important;
   }
 
-  .bookmarks-toolbar-customize > .toolbarbutton-icon {
+  #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
     width: 16px;
   }
 }
@@ -348,11 +369,13 @@ toolbarbutton.bookmark-item > menupopup {
 }
 
 #bookmarksToolbarFolderMenu,
-#BMB_bookmarksToolbar {
+#BMB_bookmarksToolbar,
+#panelMenu_bookmarksToolbar {
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
 }
 
-#BMB_unsortedBookmarks {
+#BMB_unsortedBookmarks,
+#panelMenu_unsortedBookmarks {
   list-style-image: url("chrome://browser/skin/places/unfiledBookmarks.png");
 }
 
@@ -374,32 +397,11 @@ toolbarbutton.bookmark-item > menupopup {
 .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
 #restore-button {
   -moz-box-orient: vertical;
-  -moz-appearance: toolbarbutton;
   height: 22px;
   padding: 0;
   border: 0;
 }
 
-.toolbarbutton-1:not([type="menu-button"]):-moz-lwtheme,
-.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-lwtheme,
-.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-lwtheme,
-#restore-button:-moz-lwtheme {
-  -moz-appearance: none;
-  padding: 0 3px;
-  border: 1px solid rgba(0, 0, 0, 0.4);
-  border-radius: @toolbarbuttonCornerRadius@;
-  background: linear-gradient(rgba(255,255,255,0.5), rgba(255,255,255,0.2) 50%, rgba(255,255,255,0.1) 50%, rgba(255,255,255,0.2)) repeat-x;
-  background-origin: border-box;
-  box-shadow: inset 0 1px rgba(255,255,255,0.3), 0 1px rgba(255,255,255,0.2);
-}
-
-.toolbarbutton-1:not([type="menu-button"]):-moz-lwtheme-darktext,
-.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-lwtheme-darktext,
-.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-lwtheme-darktext,
-#restore-button:-moz-lwtheme-darktext {
-  background-image: linear-gradient(rgba(255,255,255,0.3), rgba(50,50,50,0.2) 50%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.13));
-}
-
 .toolbarbutton-1[type="menu-button"] {
   padding: 0;
 }
@@ -412,668 +414,991 @@ toolbarbutton.bookmark-item > menupopup {
 .toolbarbutton-1,
 #restore-button {
   margin: 0 4px;
-  list-style-image: url("chrome://browser/skin/Toolbar.png");
 }
 
-@media (min-resolution: 2dppx) {
-  /* Whitelist built-in buttons, instead of .toolbarbutton-1,
-     to avoid potentially breaking add-on toolbar buttons. */
-  :-moz-any(@primaryToolbarButtons@):not(#tabview-button) {
-    list-style-image: url("chrome://browser/skin/Toolbar@2x.png");
-  }
-
-  :-moz-any(@primaryToolbarButtons@):not(#tabview-button) > .toolbarbutton-icon,
-  :-moz-any(@primaryToolbarButtons@):not(#tabview-button) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
-    width: 20px;
-  }
+/**
+ * Draw seperators before toolbar button dropmarkers, as well as between
+ * consecutive toolbarbutton-1's within a toolbaritem.
+ */
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker::before,
+#nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1 + .toolbarbutton-1::before {
+  content: "";
+  display: -moz-box;
+  position: absolute;
+  top: calc(50% - 9px);
+  width: 1px;
+  height: 18px;
+  -moz-margin-end: -1px;
+  background-image: linear-gradient(hsla(210,54%,20%,.2) 0, hsla(210,54%,20%,.2) 18px);
+  background-clip: padding-box;
+  background-position: center;
+  background-repeat: no-repeat;
+  background-size: 1px 18px;
+  box-shadow: 0 0 0 1px hsla(0,0%,100%,.2);
 }
 
-toolbar:not([mode="icons"]) .toolbarbutton-1:not([type="menu-button"]),
-toolbar:not([mode="icons"]) .toolbarbutton-1 > .toolbarbutton-menubutton-button,
-toolbar:not([mode="icons"]) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
-toolbar:not([mode="icons"]) #restore-button {
-  -moz-appearance: none;
-  padding: 0;
-  height: auto;
-  border: none;
-  box-shadow: none;
-  background: none;
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+  -moz-margin-start: 10px;
 }
 
-.toolbarbutton-1:not([type="menu-button"]),
-.toolbarbutton-1 > .toolbarbutton-menubutton-button,
-#restore-button {
-  min-width: 28px;
-}
+@media not all and (min-resolution: 2dppx) {
+%include ../shared/toolbarbuttons.inc.css
+%include ../shared/menupanel.inc.css
 
-toolbar:not([mode="icons"]) .toolbarbutton-1:not([type="menu-button"]),
-toolbar:not([mode="icons"]) .toolbarbutton-1 > .toolbarbutton-menubutton-button,
-toolbar:not([mode="icons"]) #restore-button {
-  min-width: 0;
-}
+  #back-button:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(18px, 36px, 36px, 18px);
+  }
 
-.toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
-.toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
-  margin: 2px;
-}
+  #forward-button:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(18px, 72px, 36px, 54px);
+  }
 
-.toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
-.toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
-.toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
-#restore-button[disabled="true"] > .toolbarbutton-icon {
-  opacity: .4;
-}
+  #home-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 126px, 36px, 108px);
+  }
 
-@media (-moz-mac-lion-theme) {
-  .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
-  .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
-  .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
-  #restore-button[disabled="true"] > .toolbarbutton-icon,
-  .toolbarbutton-1[disabled="true"] > .toolbarbutton-menu-dropmarker,
-  .toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-dropmarker,
-  .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-icon,
-  .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-badge-container > .toolbarbutton-icon,
-  #restore-button:not(:hover):-moz-window-inactive > .toolbarbutton-icon,
-  .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menu-dropmarker,
-  .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
-  .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
-    opacity: .5;
+  #bookmarks-menu-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 144px, 36px, 126px);
   }
 
-  .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon,
-  .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
-  .toolbarbutton-1:-moz-window-inactive > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
-  #restore-button:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon {
-    opacity: .25;
+  #bookmarks-menu-button[open] {
+    -moz-image-region: rect(36px, 144px, 54px, 126px);
   }
-}
 
-.toolbarbutton-1 > .toolbarbutton-menu-dropmarker,
-.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
-  list-style-image: url(chrome://browser/skin/toolbarbutton-dropmarker.png);
-}
+  #bookmarks-menu-button[starred]@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 162px, 36px, 144px);
+  }
 
-@media (min-resolution: 2dppx) {
-  .toolbarbutton-1 > .toolbarbutton-menu-dropmarker,
-  .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
-    list-style-image: url(chrome://browser/skin/toolbarbutton-dropmarker@2x.png);
+  #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+    -moz-image-region: rect(0px, 630px, 18px, 612px);
   }
 
-  .toolbarbutton-1 > .toolbarbutton-menu-dropmarker > .dropmarker-icon,
-  .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
-    width: 7px;
+  #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker:hover:active:not([disabled="true"]) > .dropmarker-icon {
+    -moz-image-region: rect(18px, 630px, 36px, 612px);
   }
-}
 
-.toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
-  -moz-margin-end: 1px;
-}
+  #history-panelmenu@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 180px, 36px, 162px);
+  }
 
-.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
-  padding: 2px 4px 0;
-  -moz-border-start: none !important;
-}
+  #history-panelmenu[open] {
+    -moz-image-region: rect(36px, 180px, 54px, 162px);
+  }
 
-toolbar:not([mode="icons"]) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
-  width: auto;
-  padding-top: 0;
-}
+  #downloads-indicator@toolbarButtonPressed@,
+  #downloads-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 198px, 36px, 180px);
+  }
 
-.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(rtl),
-.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(ltr) {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
+  #add-ons-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 216px, 36px, 198px);
+  }
 
-.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(ltr),
-.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(rtl) {
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
+  #open-file-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 234px, 36px, 216px);
+  }
 
-toolbar:not([mode="icons"]) .toolbarbutton-1:not([open="true"]) > .toolbarbutton-menubutton-dropmarker {
-  opacity: .7;
-}
+  #save-page-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 252px, 36px, 234px);
+  }
 
-.toolbarbutton-1 > .toolbarbutton-text,
-.toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-text {
-  margin: 2px 0 0;
-}
+  #sync-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 270px, 36px, 252px);
+  }
 
-toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not([disabled="true"]):active:hover:-moz-lwtheme,
-toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"])[open="true"]:-moz-lwtheme,
-toolbar[mode="icons"] .toolbarbutton-1:not([disabled="true"]) > .toolbarbutton-menubutton-button:active:hover:-moz-lwtheme,
-toolbar[mode="icons"] .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker:-moz-lwtheme,
-toolbar[mode="icons"] #restore-button:not([disabled="true"]):active:hover:-moz-lwtheme {
-  text-shadow: @loweredShadow@;
-  background-color: rgba(0,0,0,0.2);
-  box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
-}
+  #feed-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 288px, 36px, 270px);
+  }
 
-toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not(#fullscreen-button)[checked="true"]:-moz-lwtheme {
-  background-color: rgba(0,0,0,0.4);
-  box-shadow: inset 0 2px 5px rgba(0,0,0,0.7), 0 1px rgba(255,255,255,0.2);
-}
+  #social-share-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 306px, 36px, 288px);
+  }
 
-toolbar[mode="icons"] .toolbarbutton-1:not([type="menu-button"]):not(#fullscreen-button)[checked="true"]:not([disabled="true"]):active:hover:-moz-lwtheme {
-  background-color: rgba(0, 0, 0, 0.6);
-  box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.8), 0 1px rgba(255, 255, 255, 0.2);
-}
+  #characterencoding-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 324px, 36px, 306px);
+  }
 
-toolbar[mode="icons"] .toolbarbutton-1 > menupopup {
-  margin-top: 1px;
-}
+  #characterencoding-button[open] {
+    -moz-image-region: rect(36px, 324px, 54px, 306px);
+  }
 
-#navigator-toolbox > toolbar {
-  /* force iconsize="small" on these toolbars */
-  counter-reset: smallicons;
-}
+  #new-window-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 342px, 36px, 324px);
+  }
 
-/* unified back/forward button */
+  #new-tab-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 360px, 36px, 342px);
+  }
 
-#unified-back-forward-button {
-  -moz-box-align: center;
-}
+  #privatebrowsing-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 378px, 36px, 360px);
+  }
 
-#back-button,
-#forward-button:-moz-locale-dir(rtl),
-toolbar[mode="icons"] #back-button:-moz-locale-dir(rtl):-moz-lwtheme {
-  -moz-image-region: rect(0, 40px, 20px, 20px);
-}
+  #find-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 396px, 36px, 378px);
+  }
 
-@media (min-resolution: 2dppx) {
-  #back-button,
-  #forward-button:-moz-locale-dir(rtl),
-  toolbar[mode="icons"] #back-button:-moz-locale-dir(rtl):-moz-lwtheme {
-    -moz-image-region: rect(0, 80px, 40px, 40px);
+  #print-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 414px, 36px, 396px);
   }
-}
 
-#forward-button,
-#back-button:-moz-locale-dir(rtl),
-#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button:-moz-locale-dir(rtl),
-toolbar[mode="icons"] #forward-button:-moz-locale-dir(rtl):-moz-lwtheme {
-  -moz-image-region: rect(0, 60px, 20px, 40px);
-}
+  #fullscreen-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 432px, 36px, 414px);
+  }
 
-@media (min-resolution: 2dppx) {
-  #forward-button,
-  #back-button:-moz-locale-dir(rtl),
-  #navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button:-moz-locale-dir(rtl),
-  toolbar[mode="icons"] #forward-button:-moz-locale-dir(rtl):-moz-lwtheme {
-    -moz-image-region: rect(0, 120px, 40px, 80px);
+  #developer-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 450px, 36px, 432px);
   }
-}
 
-#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:-moz-locale-dir(rtl),
-#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button:-moz-locale-dir(rtl),
-toolbar[mode="icons"] #back-button:-moz-locale-dir(rtl):-moz-lwtheme,
-toolbar[mode="icons"] #forward-button:-moz-locale-dir(rtl):-moz-lwtheme {
-  transform: scaleX(-1);
-}
+  #developer-button[open] {
+    -moz-image-region: rect(36px, 450px, 54px, 432px);
+  }
 
-#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button {
-  -moz-appearance: none;
-  -moz-margin-end: -7px;
-  position: relative;
-  z-index: 1;
-  -moz-image-region: rect(0, 20px, 20px, 0);
-  width: 30px;
-  height: 30px;
-  padding: 4px 5px 4px 3px;
-  border-radius: 10000px;
-}
+  #preferences-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 468px, 36px, 450px);
+  }
 
-@media (min-resolution: 2dppx) {
-  #navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button {
-    -moz-image-region: rect(0, 40px, 40px, 0);
+  #PanelUI-menu-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 486px, 36px, 468px);
   }
-}
 
-#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:not(:-moz-lwtheme) {
-  height: 31px;
-  padding: 4px 5px 5px 3px;
-  margin-bottom: -1px;
-  background: url(chrome://browser/skin/keyhole-circle.png) 0 0 no-repeat;
-  border-radius: 0;
-}
+  #PanelUI-menu-button[open] {
+    -moz-image-region: rect(36px, 486px, 54px, 468px);
+  }
 
-@media (min-resolution: 2dppx) {
-  #navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:not(:-moz-lwtheme) {
-    background-image: url(chrome://browser/skin/keyhole-circle@2x.png);
-    background-size: 90px;
+  #cut-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 504px, 36px, 486px);
   }
-}
 
-#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:-moz-window-inactive:not(:-moz-lwtheme) {
-  background-position: -60px 0;
-}
+  #copy-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 522px, 36px, 504px);
+  }
 
-#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button:not([disabled="true"]):active:hover:not(:-moz-lwtheme),
-#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #back-button[open="true"]:not(:-moz-lwtheme) {
-  background-position: -30px 0;
-}
+  #paste-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 540px, 36px, 522px);
+  }
 
-toolbar[mode="icons"] #forward-button {
-  -moz-margin-start: 0;
-}
+  #zoom-out-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 558px, 36px, 540px);
+  }
 
-#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button > .toolbarbutton-icon {
-  /* shift the icon away from the back button */
-  margin-left: 3px;
-  margin-right: -1px;
-}
+  #zoom-in-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 576px, 36px, 558px);
+  }
 
-#navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button {
-  clip-path: url(chrome://browser/content/browser.xul#osx-keyhole-forward-clip-path);
-}
+  #webrtc-status-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 594px, 36px, 576px);
+  }
 
-@conditionalForwardWithUrlbar@ > #forward-button:not(:-moz-lwtheme) {
-  -moz-appearance: none;
-  -moz-padding-start: 2px;
-  background: linear-gradient(hsl(0,0%,99%), hsl(0,0%,67%)) padding-box;
-  border: 1px solid;
-  border-color: hsl(0,0%,31%) hsla(0,0%,29%,.6) hsl(0,0%,27%);
-  box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35),
-              0 1px 0 hsla(0,0%,100%,.2);
-}
+  #nav-bar-overflow-button@toolbarButtonPressed@ {
+    -moz-image-region: rect(18px, 612px, 36px, 594px);
+  }
 
-@conditionalForwardWithUrlbar@ > #forward-button {
-  border-radius: 0;
-  -moz-margin-end: 0;
-}
+  #nav-bar-overflow-button[open] {
+    -moz-image-region: rect(36px, 612px, 54px, 594px);
+  }
 
-@conditionalForwardWithUrlbar@ > #forward-button:-moz-lwtheme {
-  -moz-padding-start: 2px;
-  -moz-padding-end: 0;
-}
+  /**
+   * OSX has a unique set of icons when fullscreen is in the checked state.
+   */
 
-@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
-  transition: opacity @forwardTransitionLength@ ease-out;
+  #fullscreen-button[checked="true"]:not([cui-areatype="menu-panel"]) {
+    -moz-image-region: rect(36px, 432px, 54px, 414px);
+  }
+
+  #fullscreen-button[checked="true"]@toolbarButtonPressed@ {
+    -moz-image-region: rect(54px, 432px, 72px, 414px);
+  }
 }
 
-@conditionalForwardWithUrlbar@ > #forward-button:hover:active:not(:-moz-lwtheme) {
-  background-image: linear-gradient(hsl(0,0%,74%), hsl(0,0%,61%));
-  box-shadow: inset rgba(0,0,0,.3) 0 -6px 10px,
-              inset #000 0 1px 3px,
-              inset rgba(0,0,0,.2) 0 1px 3px,
-              0 1px 0 hsla(0,0%,100%,.2);
-}
+@media (min-resolution: 2dppx) {
+  /* Whitelist built-in buttons, instead of .toolbarbutton-1,
+     to avoid potentially breaking add-on toolbar buttons. */
 
-@conditionalForwardWithUrlbar@ > #forward-button:-moz-window-inactive:not(:-moz-lwtheme) {
-  border-color: hsl(0,0%,64%) hsl(0,0%,65%) hsl(0,0%,66%);
-  background-image: linear-gradient(hsl(0,0%,99%), hsl(0,0%,82%));
-  box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35);
-}
+  :-moz-any(@primaryToolbarButtons@),
+  #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+    list-style-image: url("chrome://browser/skin/Toolbar@2x.png");
+  }
 
-@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
-  opacity: 0;
-}
+  :-moz-any(@primaryToolbarButtons@):-moz-lwtheme-brighttext,
+  #bookmarks-menu-button[cui-areatype="toolbar"]:-moz-lwtheme-brighttext > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+    list-style-image: url("chrome://browser/skin/Toolbar-inverted@2x.png");
+  }
 
-@media (-moz-mac-lion-theme) {
-  @conditionalForwardWithUrlbar@ > #forward-button:not(:-moz-lwtheme) {
-    background-image: linear-gradient(hsla(0,0%,100%,.73), hsla(0,0%,100%,.05) 85%);
-    border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.25) hsla(0,0%,0%,.2);
-    box-shadow: inset 0 1px 0 hsla(0,0%,100%,.2),
-                inset 0 0 1px hsla(0,0%,100%,.1),
-                0 1px 0 hsla(0,0%,100%,.2);
+  #back-button {
+    -moz-image-region: rect(0, 72px, 36px, 36px);
   }
 
-  @conditionalForwardWithUrlbar@ > #forward-button:hover:active:not(:-moz-lwtheme) {
-    background-image: linear-gradient(hsla(0,0%,60%,.37), hsla(0,0%,100%,.35) 95%);
-    border-color: hsla(0,0%,0%,.43) hsla(0,0%,0%,.25) hsla(0,0%,0%,.37);
-    box-shadow: inset 0 1px 0 hsla(0,0%,0%,.02),
-                inset 0 1px 2px hsla(0,0%,0%,.2),
-                0 1px 0 hsla(0,0%,100%,.2);
+  #back-button:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 72px, 72px, 36px);
   }
 
-  @conditionalForwardWithUrlbar@ > #forward-button:-moz-window-inactive:not(:-moz-lwtheme) {
-    background-image: none;
-    border-color: hsla(0,0%,0%,.2);
+  #forward-button {
+    -moz-image-region: rect(0, 144px, 36px, 108px);
   }
-}
 
-#navigator-toolbox[iconsize="small"][mode="icons"] > #nav-bar #forward-button {
-  width: 27px;
-}
+  #forward-button:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 144px, 72px, 108px);
+  }
 
-#navigator-toolbox[iconsize="small"][mode="icons"] > #nav-bar #forward-button:-moz-lwtheme {
-  padding-left: 2px;
-}
+  #home-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 252px, 36px, 216px);
+  }
 
-toolbar[mode="icons"] #forward-button:-moz-lwtheme {
-  border-top-left-radius: 0;
-  border-bottom-left-radius: 0;
-}
+  #home-button[cui-areatype="toolbar"]:hover:active {
+    -moz-image-region: rect(36px, 252px, 72px, 216px);
+  }
 
-#navigator-toolbox[iconsize="small"][mode="icons"] > #nav-bar #back-button {
-  -moz-margin-end: 0;
-  width: 26px;
-}
+  #bookmarks-menu-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 288px, 36px, 252px);
+  }
 
-#navigator-toolbox[iconsize="small"][mode="icons"] > #nav-bar #back-button:-moz-lwtheme {
-  padding-right: 2px;
-  border-right-width: 0;
-  border-top-right-radius: 0;
-  border-bottom-right-radius: 0;
-}
+  #bookmarks-menu-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 288px, 72px, 252px);
+  }
 
-.unified-nav-back[_moz-menuactive]:-moz-locale-dir(ltr),
-.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) {
-  list-style-image: url("chrome://browser/skin/menu-back.png") !important;
-}
+  #bookmarks-menu-button[cui-areatype="toolbar"][open] {
+    -moz-image-region: rect(72px, 288px, 108px, 252px);
+  }
 
-.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(ltr),
-.unified-nav-back[_moz-menuactive]:-moz-locale-dir(rtl) {
-  list-style-image: url("chrome://browser/skin/menu-forward.png") !important;
-}
+  #bookmarks-menu-button[cui-areatype="toolbar"][starred] {
+    -moz-image-region: rect(0, 324px, 36px, 288px);
+  }
 
+  #bookmarks-menu-button[cui-areatype="toolbar"][starred]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 324px, 72px, 288px);
+  }
 
-/* reload button */
+  #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+    -moz-image-region: rect(0px, 1260px, 36px, 1224px);
+  }
 
-#reload-button {
-  -moz-image-region: rect(0, 80px, 20px, 60px);
-}
+  #bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker:hover:active:not([disabled="true"]) > .dropmarker-icon {
+    -moz-image-region: rect(36px, 1260px, 72px, 1224px);
+  }
 
-@media (min-resolution: 2dppx) {
-  #reload-button {
-    -moz-image-region: rect(0, 160px, 40px, 120px);
+  #history-panelmenu[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 360px, 36px, 324px);
   }
-}
 
-/* stop button */
+  #history-panelmenu[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 360px, 72px, 324px);
+  }
 
-#stop-button {
-  -moz-image-region: rect(0, 100px, 20px, 80px);
-}
+  #history-panelmenu[cui-areatype="toolbar"][open] {
+    -moz-image-region: rect(72px, 360px, 108px, 324px);
+  }
 
-@media (min-resolution: 2dppx) {
-  #stop-button {
-    -moz-image-region: rect(0, 200px, 40px, 160px);
+  #downloads-indicator[cui-areatype="toolbar"],
+  #downloads-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 396px, 36px, 360px);
   }
-}
 
-/* home button */
+  #downloads-indicator[cui-areatype="toolbar"]:hover:active:not([disabled="true"]),
+  #downloads-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 396px, 72px, 360px);
+  }
 
-#home-button {
-  -moz-image-region: rect(0, 120px, 20px, 100px);
-}
+  #add-ons-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 432px, 36px, 396px);
+  }
 
-#home-button.bookmark-item {
-  list-style-image: url("chrome://browser/skin/home.png");
-  -moz-image-region: rect(0, 12px, 12px, 0);
-}
+  #add-ons-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 432px, 72px, 396px);
+  }
 
-#home-button.bookmark-item:hover {
-  -moz-image-region: rect(0, 24px, 12px, 12px);
-}
+  #open-file-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 468px, 36px, 432px);
+  }
 
-#home-button.bookmark-item > .toolbarbutton-icon {
-  display: -moz-box !important;
-  -moz-margin-start: -2px;
-  -moz-margin-end: 3px;
-}
+  #open-file-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 468px, 72px, 432px);
+  }
 
-@media (min-resolution: 2dppx) {
-  #home-button:not(.bookmark-item) {
-    -moz-image-region: rect(0, 240px, 40px, 200px);
+  #save-page-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 504px, 36px, 468px);
   }
-}
 
-/* tabview button */
+  #save-page-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 504px, 72px, 468px);
+  }
 
-#tabview-button,
-#menu_tabview {
-  list-style-image: url(chrome://browser/skin/tabview/tabview.png);
-}
+  #sync-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 540px, 36px, 504px);
+  }
 
-#tabview-button {
-  -moz-image-region: rect(0, 100px, 20px, 80px);
+  #sync-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 540px, 72px, 504px);
+  }
+
+  #feed-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 576px, 36px, 540px);
+  }
+
+  #feed-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 576px, 72px, 540px);
+  }
+
+  #social-share-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 612px, 36px, 576px);
+  }
+
+  #social-share-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 612px, 72px, 576px);
+  }
+
+  #characterencoding-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 648px, 36px, 612px);
+  }
+
+  #characterencoding-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 648px, 72px, 612px);
+  }
+
+  #characterencoding-button[cui-areatype="toolbar"][open] {
+    -moz-image-region: rect(72px, 648px, 108px, 612px);
+  }
+
+  #new-window-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 684px, 36px, 648px);
+  }
+
+  #new-window-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 684px, 72px, 648px);
+  }
+
+  #new-tab-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 720px, 36px, 684px);
+  }
+
+  #new-tab-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 720px, 72px, 684px);
+  }
+
+  #privatebrowsing-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 756px, 36px, 720px);
+  }
+
+  #privatebrowsing-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 756px, 72px, 720px);
+  }
+
+  #find-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 792px, 36px, 756px);
+  }
+
+  #find-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 792px, 72px, 756px);
+  }
+
+  #print-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 828px, 36px, 792px);
+  }
+
+  #print-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 828px, 72px, 792px);
+  }
+
+  #fullscreen-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 864px, 36px, 828px);
+  }
+
+  #fullscreen-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 864px, 72px, 828px);
+  }
+
+  #fullscreen-button[cui-areatype="toolbar"][checked="true"] {
+    -moz-image-region: rect(72px, 864px, 108px, 828px);
+  }
+
+  #fullscreen-button[cui-areatype="toolbar"][checked="true"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(108px, 864px, 144px, 828px);
+  }
+
+  #developer-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 900px, 36px, 864px);
+  }
+
+  #developer-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 900px, 72px, 864px);
+  }
+
+  #developer-button[cui-areatype="toolbar"][open] {
+    -moz-image-region: rect(72px, 900px, 108px, 864px);
+  }
+
+  #preferences-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 936px, 36px, 900px);
+  }
+
+  #preferences-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 936px, 72px, 900px);
+  }
+
+  #PanelUI-menu-button {
+    -moz-image-region: rect(0, 972px, 36px, 936px);
+  }
+
+  #PanelUI-menu-button:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 972px, 72px, 936px);
+  }
+
+  #PanelUI-menu-button[open] {
+    -moz-image-region: rect(72px, 972px, 108px, 936px);
+  }
+
+  #edit-controls[cui-areatype="toolbar"] > #cut-button {
+    -moz-image-region: rect(0, 1008px, 36px, 972px);
+  }
+
+  #edit-controls[cui-areatype="toolbar"] > #cut-button:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 1008px, 72px, 972px);
+  }
+
+  #edit-controls[cui-areatype="toolbar"] > #copy-button {
+    -moz-image-region: rect(0, 1044px, 36px, 1008px);
+  }
+
+  #edit-controls[cui-areatype="toolbar"] > #copy-button:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 1044px, 72px, 1008px);
+  }
+
+  #edit-controls[cui-areatype="toolbar"] > #paste-button {
+    -moz-image-region: rect(0, 1080px, 36px, 1044px);
+  }
+
+  #edit-controls[cui-areatype="toolbar"] > #paste-button:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 1080px, 72px, 1044px);
+  }
+
+  #zoom-controls[cui-areatype="toolbar"] > #zoom-out-button {
+    -moz-image-region: rect(0, 1116px, 36px, 1080px);
+  }
+
+  #zoom-controls[cui-areatype="toolbar"] > #zoom-out-button:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 1116px, 72px, 1080px);
+  }
+
+  #zoom-controls[cui-areatype="toolbar"] > #zoom-in-button {
+    -moz-image-region: rect(0, 1152px, 36px, 1116px);
+  }
+
+  #zoom-controls[cui-areatype="toolbar"] > #zoom-in-button:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 1152px, 72px, 1116px);
+  }
+
+  #webrtc-status-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 1188px, 36px, 1152px);
+  }
+
+  #webrtc-status-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 1188px, 72px, 1152px);
+  }
+
+  #nav-bar-overflow-button {
+    -moz-image-region: rect(0, 1224px, 36px, 1188px);
+  }
+
+  #nav-bar-overflow-button:hover:active:not([disabled="true"]) {
+    -moz-image-region: rect(36px, 1224px, 72px, 1188px);
+  }
+
+  #nav-bar-overflow-button[open] {
+    -moz-image-region: rect(72px, 1224px, 108px, 1188px);
+  }
+
+  :-moz-any(@primaryToolbarButtons@):not(#tabview-button) > .toolbarbutton-icon,
+  :-moz-any(@primaryToolbarButtons@):not(#tabview-button) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+    width: 18px;
+  }
+
+  /* Menu panel and palette styles */
+
+  :-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > :-moz-any(@primaryToolbarButtons@) {
+    list-style-image: url(chrome://browser/skin/menuPanel@2x.png);
+  }
+
+  #home-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #home-button {
+    -moz-image-region: rect(0px, 256px, 64px, 192px);
+  }
+
+  #bookmarks-menu-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #bookmarks-menu-button {
+    -moz-image-region: rect(0px, 320px, 64px, 256px);
+  }
+
+  #bookmarks-menu-button[starred][cui-areatype="menu-panel"] {
+    -moz-image-region: rect(0px, 384px, 64px, 320px);
+  }
+
+  #history-panelmenu[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #history-panelmenu {
+    -moz-image-region: rect(0px, 448px, 64px, 384px);
+  }
+
+  #downloads-button[cui-areatype="menu-panel"],
+  #downloads-indicator[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #downloads-button {
+    -moz-image-region: rect(0px, 512px, 64px, 448px);
+  }
+
+  #add-ons-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #add-ons-button {
+    -moz-image-region: rect(0px, 576px, 64px, 512px);
+  }
+
+  #open-file-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #open-file-button {
+    -moz-image-region: rect(0px, 640px, 64px, 576px);
+  }
+
+  #save-page-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #save-page-button {
+    -moz-image-region: rect(0px, 704px, 64px, 640px);
+  }
+
+  #sync-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #sync-button {
+    -moz-image-region: rect(0px, 768px, 64px, 704px);
+  }
+
+  #feed-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #feed-button {
+    -moz-image-region: rect(0px, 832px, 64px, 768px);
+  }
+
+  #social-share-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #social-share-button {
+    -moz-image-region: rect(0px, 896px, 64px, 832px);
+  }
+
+  #characterencoding-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #characterencoding-button {
+    -moz-image-region: rect(0, 960px, 64px, 896px);
+  }
+
+  #new-window-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #new-window-button {
+    -moz-image-region: rect(0px, 1024px, 64px, 960px);
+  }
+
+  #new-tab-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #new-tab-button {
+    -moz-image-region: rect(0px, 1088px, 64px, 1024px);
+  }
+
+  #privatebrowsing-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #privatebrowsing-button {
+    -moz-image-region: rect(0px, 1152px, 64px, 1088px);
+  }
+
+  #find-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #find-button {
+    -moz-image-region: rect(0px, 1280px, 64px, 1216px);
+  }
+
+  #print-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #print-button {
+    -moz-image-region: rect(0px, 1344px, 64px, 1280px);
+  }
+
+  #fullscreen-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #fullscreen-button {
+    -moz-image-region: rect(0px, 1408px, 64px, 1344px);
+  }
+
+  #developer-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #developer-button {
+    -moz-image-region: rect(0px, 1472px, 64px, 1408px);
+  }
+
+  #preferences-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #preferences-button {
+    -moz-image-region: rect(0px, 1536px, 64px, 1472px);
+  }
+
+  /* Footer and wide panel control icons */
+  #edit-controls@inAnyPanel@ > toolbarbutton,
+  #zoom-controls@inAnyPanel@ > toolbarbutton,
+  toolbarpaletteitem[place="palette"] > #edit-controls > toolbarbutton,
+  toolbarpaletteitem[place="palette"] > #zoom-controls > toolbarbutton {
+    list-style-image: url(chrome://browser/skin/menuPanel-small@2x.png);
+  }
+
+  #edit-controls@inAnyPanel@ > #cut-button,
+  toolbarpaletteitem[place="palette"] > #edit-controls > #cut-button {
+    -moz-image-region: rect(0px, 64px, 32px, 32px);
+  }
+
+  #edit-controls@inAnyPanel@ > #copy-button,
+  toolbarpaletteitem[place="palette"] > #edit-controls > #copy-button {
+    -moz-image-region: rect(0px, 96px, 32px, 64px);
+  }
+
+  #edit-controls@inAnyPanel@ > #paste-button,
+  toolbarpaletteitem[place="palette"] > #edit-controls > #paste-button {
+    -moz-image-region: rect(0px, 128px, 32px, 96px);
+  }
+
+  #zoom-controls@inAnyPanel@ > #zoom-out-button,
+  toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-out-button {
+    -moz-image-region: rect(0px, 160px, 32px, 128px);
+  }
+
+  #zoom-controls@inAnyPanel@ > #zoom-in-button,
+  toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button {
+    -moz-image-region: rect(0px, 192px, 32px, 160px);
+  }
+
+  #PanelUI-quit > .toolbarbutton-icon,
+  #PanelUI-customize > .toolbarbutton-icon,
+  #PanelUI-help > .toolbarbutton-icon {
+    width: 16px;
+  }
 }
 
-#tabview-button[groups="0"] {
-  -moz-image-region: rect(0, 20px, 20px, 0);
+.toolbarbutton-1:not([type="menu-button"]),
+.toolbarbutton-1 > .toolbarbutton-menubutton-button,
+#restore-button {
+  min-width: 28px;
 }
 
-#tabview-button[groups="1"] {
-  -moz-image-region: rect(0, 40px, 20px, 20px);
+.toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
+.toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+  margin: 2px;
 }
 
-#tabview-button[groups="2"] {
-  -moz-image-region: rect(0, 60px, 20px, 40px);
+#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
+#main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
+#main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
+#restore-button[disabled="true"] > .toolbarbutton-icon {
+  opacity: .4;
 }
 
-#tabview-button[groups="3"] {
-  -moz-image-region: rect(0, 80px, 20px, 60px);
+@media (-moz-mac-lion-theme) {
+  #main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-icon,
+  #main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
+  #main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
+  #restore-button[disabled="true"] > .toolbarbutton-icon,
+  #main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-menu-dropmarker,
+  #main-window:not([customizing]) .toolbarbutton-1[disabled="true"] > .toolbarbutton-menubutton-dropmarker,
+  .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-icon,
+  .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-text,
+  .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-badge-container > .toolbarbutton-icon,
+  #restore-button:not(:hover):-moz-window-inactive > .toolbarbutton-icon,
+  .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menu-dropmarker,
+  .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
+  .toolbarbutton-1:not(:hover):-moz-window-inactive > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+    opacity: .5;
+  }
+
+  #main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon,
+  #main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive[disabled="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
+  #main-window:not([customizing]) .toolbarbutton-1:-moz-window-inactive > .toolbarbutton-menubutton-button[disabled="true"] > .toolbarbutton-icon,
+  #restore-button:-moz-window-inactive[disabled="true"] > .toolbarbutton-icon {
+    opacity: .25;
+  }
 }
 
-#menu_tabview {
-  -moz-image-region: rect(2px, 98px, 18px, 82px);
+.toolbarbutton-1 > .toolbarbutton-menu-dropmarker,
+.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
+  list-style-image: url(chrome://browser/skin/toolbarbutton-dropmarker.png);
 }
 
-#menu_tabview[groups="0"] {
-  -moz-image-region: rect(2px, 18px, 18px, 2px);
+@media (min-resolution: 2dppx) {
+  .toolbarbutton-1 > .toolbarbutton-menu-dropmarker,
+  .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
+    list-style-image: url(chrome://browser/skin/toolbarbutton-dropmarker@2x.png);
+  }
+
+  .toolbarbutton-1 > .toolbarbutton-menu-dropmarker > .dropmarker-icon,
+  .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+    width: 7px;
+  }
 }
 
-#menu_tabview[groups="1"] {
-  -moz-image-region: rect(2px, 38px, 18px, 22px);
+.toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
+  -moz-margin-end: 1px;
 }
 
-#menu_tabview[groups="2"] {
-  -moz-image-region: rect(2px, 58px, 18px, 42px);
+.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
+  padding: 2px 4px 0;
+  -moz-border-start: none !important;
 }
 
-#menu_tabview[groups="3"] {
-  -moz-image-region: rect(2px, 78px, 18px, 62px);
+.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(rtl),
+.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(ltr) {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
 }
 
-/* download manager button */
+.toolbarbutton-1 > .toolbarbutton-menubutton-button:-moz-locale-dir(ltr),
+.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-locale-dir(rtl) {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
 
-#downloads-button {
-  -moz-image-region: rect(0, 140px, 20px, 120px);
+.toolbarbutton-1 > .toolbarbutton-text,
+.toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-text {
+  margin: 2px 0 0;
 }
 
-@media (min-resolution: 2dppx) {
-  #downloads-button {
-    -moz-image-region: rect(0, 280px, 40px, 240px);
-  }
+.toolbarbutton-1 > menupopup {
+  margin-top: 1px;
 }
 
-/* history sidebar button */
+/* Common back and forward button styles */
 
-#history-button {
-  -moz-image-region: rect(0, 160px, 20px, 140px);
+#back-button,
+#forward-button {
+  background: linear-gradient(rgba(255,255,255,0.5),
+                              rgba(255,255,255,0.2) 50%,
+                              rgba(255,255,255,0.1) 50%,
+                              rgba(255,255,255,0.2)) repeat-x;
 }
 
-#history-button[checked="true"] {
-  -moz-image-region: rect(20px, 160px, 40px, 140px);
+#back-button:-moz-lwtheme,
+#forward-button:-moz-lwtheme {
+  background-origin: border-box;
+  border: 1px solid rgba(0,0,0,0.4);
+  box-shadow: inset 0 1px rgba(255,255,255,0.3), 0 1px rgba(255,255,255,0.2);
 }
 
-@media (min-resolution: 2dppx) {
-  #history-button {
-    -moz-image-region: rect(0, 320px, 40px, 280px);
-  }
-
-  #history-button[checked="true"] {
-    -moz-image-region: rect(40px, 320px, 80px, 280px);
-  }
+#back-button:active:hover:-moz-lwtheme,
+#forward-button:active:hover:-moz-lwtheme {
+  background-color: rgba(0,0,0,0.2);
+  box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
 }
 
-/* bookmark sidebar & menu buttons */
+#back-button:-moz-window-inactive,
+#forward-button:-moz-window-inactive {
+  background-color: rgba(0,0,0,0.04);
+  border-color: rgba(0,0,0,0.2);
+}
 
-#bookmarks-button,
-#bookmarks-menu-button {
-  -moz-image-region: rect(0, 180px, 20px, 160px);
+#back-button:-moz-locale-dir(rtl),
+#forward-button:-moz-locale-dir(rtl) {
+  transform: scaleX(-1);
 }
 
-#bookmarks-button[checked="true"] {
-  -moz-image-region: rect(20px, 180px, 40px, 160px);
+/* Back button styles */
+
+#back-button {
+  -moz-margin-end: -7px;
+  position: relative;
+  z-index: 1;
+  width: 30px;
+  height: 30px;
+  padding: 4px 5px 4px 3px;
+  border-radius: 10000px;
 }
 
-#bookmarks-menu-button.bookmark-item {
-  -moz-image-region: rect(2px, 178px, 18px, 162px);
-  list-style-image: url("chrome://browser/skin/Toolbar.png");
+#back-button:not(:-moz-lwtheme) {
+  height: 31px;
+  padding: 4px 5px 5px 3px;
+  margin-bottom: -1px;
+  background: url(chrome://browser/skin/keyhole-circle.png) 0 0 no-repeat;
 }
 
 @media (min-resolution: 2dppx) {
-  #bookmarks-button,
-  #bookmarks-menu-button {
-    -moz-image-region: rect(0, 360px, 40px, 320px);
+  #back-button:not(:-moz-lwtheme) {
+    background-image: url(chrome://browser/skin/keyhole-circle@2x.png);
+    background-size: 90px;
   }
+}
 
-  #bookmarks-button[checked="true"] {
-    -moz-image-region: rect(40px, 360px, 80px, 320px);
-  }
+#back-button:-moz-window-inactive:not(:-moz-lwtheme) {
+  background-position: -60px 0;
+}
 
-  #bookmarks-menu-button.bookmark-item {
-    -moz-image-region: rect(4px, 356px, 36px, 324px);
-    list-style-image: url("chrome://browser/skin/Toolbar@2x.png");
-  }
+#back-button:not([disabled="true"]):active:hover:not(:-moz-lwtheme),
+#back-button[open="true"]:not(:-moz-lwtheme) {
+  background-position: -30px 0;
+}
 
-  #bookmarks-menu-button.bookmark-item > .toolbarbutton-icon {
-    width: 16px;
-  }
+/* Forward button styles */
+
+#forward-button {
+  -moz-margin-start: 0;
+  -moz-margin-end: 0;
+  clip-path: url(chrome://browser/content/browser.xul#osx-keyhole-forward-clip-path);
 }
 
-#bookmarks-menu-button.toolbarbutton-1 {
-  -moz-box-orient: horizontal;
+#forward-button > .toolbarbutton-icon {
+  /* shift the icon away from the back button */
+  margin-left: 3px;
+  margin-right: -1px;
 }
 
-/* print button */
+#forward-button:-moz-lwtheme {
+  -moz-padding-start: 2px;
+  -moz-padding-end: 0;
+}
 
-#print-button {
-  -moz-image-region: rect(0, 200px, 20px, 180px);
+#forward-button:not(:-moz-lwtheme) {
+  -moz-padding-start: 2px;
+  background: linear-gradient(hsl(0,0%,99%), hsl(0,0%,67%)) padding-box;
+  border: 1px solid;
+  border-color: hsl(0,0%,31%) hsla(0,0%,29%,.6) hsl(0,0%,27%);
+  box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35),
+              0 1px 0 hsla(0,0%,100%,.2);
 }
 
-@media (min-resolution: 2dppx) {
-  #print-button {
-    -moz-image-region: rect(0, 400px, 40px, 360px);
-  }
+#urlbar-container:not([switchingtabs]) > #forward-button {
+  transition: opacity @forwardTransitionLength@ ease-out;
 }
 
-/* toolbar new tab button */
+#forward-button:hover:active:not(:-moz-lwtheme) {
+  background-image: linear-gradient(hsl(0,0%,74%), hsl(0,0%,61%));
+  box-shadow: inset rgba(0,0,0,.3) 0 -6px 10px,
+              inset #000 0 1px 3px,
+              inset rgba(0,0,0,.2) 0 1px 3px,
+              0 1px 0 hsla(0,0%,100%,.2);
+}
 
-#new-tab-button {
-  -moz-image-region: rect(0, 220px, 20px, 200px);
+#forward-button:-moz-window-inactive:not(:-moz-lwtheme) {
+  border-color: hsl(0,0%,64%) hsl(0,0%,65%) hsl(0,0%,66%);
+  background-image: linear-gradient(hsl(0,0%,99%), hsl(0,0%,82%));
+  box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35);
 }
 
-@media (min-resolution: 2dppx) {
-  #new-tab-button {
-    -moz-image-region: rect(0, 440px, 40px, 400px);
-  }
+#urlbar-container:not(:hover) > #forward-button[disabled] {
+  opacity: 0;
 }
 
-/* new window button */
+@media (-moz-mac-lion-theme) {
+  #forward-button:not(:-moz-lwtheme) {
+    background-image: linear-gradient(hsla(0,0%,100%,.73), hsla(0,0%,100%,.05) 85%);
+    border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.25) hsla(0,0%,0%,.2);
+    box-shadow: inset 0 1px 0 hsla(0,0%,100%,.2),
+                inset 0 0 1px hsla(0,0%,100%,.1),
+                0 1px 0 hsla(0,0%,100%,.2);
+  }
 
-#new-window-button {
-  -moz-image-region: rect(0, 240px, 20px, 220px);
-}
+  #forward-button:hover:active:not(:-moz-lwtheme) {
+    background-image: linear-gradient(hsla(0,0%,60%,.37), hsla(0,0%,100%,.35) 95%);
+    border-color: hsla(0,0%,0%,.43) hsla(0,0%,0%,.25) hsla(0,0%,0%,.37);
+    box-shadow: inset 0 1px 0 hsla(0,0%,0%,.02),
+                inset 0 1px 2px hsla(0,0%,0%,.2),
+                0 1px 0 hsla(0,0%,100%,.2);
+  }
 
-@media (min-resolution: 2dppx) {
-  #new-window-button {
-    -moz-image-region: rect(0, 480px, 40px, 440px);
+  #forward-button:-moz-window-inactive:not(:-moz-lwtheme) {
+    background-image: none;
+    border-color: hsla(0,0%,0%,.2);
   }
 }
 
-/* cut button */
-
-#cut-button {
-  -moz-image-region: rect(0, 260px, 20px, 240px);
+.unified-nav-back[_moz-menuactive]:-moz-locale-dir(ltr),
+.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) {
+  list-style-image: url("chrome://browser/skin/menu-back.png") !important;
 }
 
-@media (min-resolution: 2dppx) {
-  #cut-button {
-    -moz-image-region: rect(0, 520px, 40px, 480px);
-  }
+.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(ltr),
+.unified-nav-back[_moz-menuactive]:-moz-locale-dir(rtl) {
+  list-style-image: url("chrome://browser/skin/menu-forward.png") !important;
 }
 
-/* copy button */
+/* home button */
 
-#copy-button {
-  -moz-image-region: rect(0, 280px, 20px, 260px);
+#home-button.bookmark-item {
+  list-style-image: url("chrome://browser/skin/home.png");
+  -moz-image-region: rect(0, 12px, 12px, 0);
 }
 
-@media (min-resolution: 2dppx) {
-  #copy-button {
-    -moz-image-region: rect(0, 560px, 40px, 520px);
-  }
+#home-button.bookmark-item:hover {
+  -moz-image-region: rect(0, 24px, 12px, 12px);
+}
+
+#home-button.bookmark-item > .toolbarbutton-icon {
+  display: -moz-box !important;
+  -moz-margin-start: -2px;
+  -moz-margin-end: 3px;
 }
 
-/* paste button */
+/* tabview button */
 
-#paste-button {
-  -moz-image-region: rect(0, 300px, 20px, 280px);
+#tabview-button,
+#menu_tabview {
+  list-style-image: url(chrome://browser/skin/tabview/tabview.png);
 }
 
-@media (min-resolution: 2dppx) {
-  #paste-button {
-    -moz-image-region: rect(0, 600px, 40px, 560px);
-  }
+#tabview-button {
+  -moz-image-region: rect(0, 100px, 20px, 80px);
 }
 
-/* alltabs button */
+#tabview-button[groups="0"] {
+  -moz-image-region: rect(0, 20px, 20px, 0);
+}
 
-#alltabs-button {
-  -moz-image-region: rect(0, 380px, 20px, 360px);
+#tabview-button[groups="1"] {
+  -moz-image-region: rect(0, 40px, 20px, 20px);
 }
 
-@media (min-resolution: 2dppx) {
-  #alltabs-button {
-    -moz-image-region: rect(0, 760px, 40px, 720px);
-  }
+#tabview-button[groups="2"] {
+  -moz-image-region: rect(0, 60px, 20px, 40px);
 }
 
-/* fullscreen button */
+#tabview-button[groups="3"] {
+  -moz-image-region: rect(0, 80px, 20px, 60px);
+}
 
-#fullscreen-button {
-  -moz-image-region: rect(0, 340px, 20px, 320px);
+#menu_tabview {
+  -moz-image-region: rect(2px, 98px, 18px, 82px);
 }
 
-#fullscreen-button[checked="true"],
-#restore-button {
-  -moz-image-region: rect(0, 360px, 20px, 340px);
+#menu_tabview[groups="0"] {
+  -moz-image-region: rect(2px, 18px, 18px, 2px);
 }
 
-@media (min-resolution: 2dppx) {
-  #fullscreen-button {
-    -moz-image-region: rect(0, 680px, 40px, 640px);
-  }
+#menu_tabview[groups="1"] {
+  -moz-image-region: rect(2px, 38px, 18px, 22px);
+}
 
-  #fullscreen-button[checked="true"],
-  #restore-button {
-    -moz-image-region: rect(0, 720px, 40px, 680px);
-  }
+#menu_tabview[groups="2"] {
+  -moz-image-region: rect(2px, 58px, 18px, 42px);
 }
 
-/* zoom controls */
+#menu_tabview[groups="3"] {
+  -moz-image-region: rect(2px, 78px, 18px, 62px);
+}
 
-#zoom-controls {
-  -moz-box-align: center;
+#cut-button {
+  -moz-margin-end: 0;
 }
 
-#zoom-out-button {
-  -moz-image-region: rect(0, 400px, 20px, 380px);
+#paste-button {
+  -moz-border-start: none;
+  -moz-margin-start: 0;
 }
 
-#zoom-in-button {
-  -moz-image-region: rect(0, 420px, 20px, 400px);
+#cut-button:-moz-locale-dir(ltr),
+#paste-button:-moz-locale-dir(rtl) {
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
 }
 
-@media (min-resolution: 2dppx) {
-  #zoom-out-button {
-    -moz-image-region: rect(0, 800px, 40px, 760px);
-  }
+#cut-button:-moz-locale-dir(rtl),
+#paste-button:-moz-locale-dir(ltr) {
+  border-top-left-radius: 0;
+  border-bottom-left-radius: 0;
+}
 
-  #zoom-in-button {
-    -moz-image-region: rect(0, 840px, 40px, 800px);
-  }
+#copy-button {
+  border-radius: 0;
+  margin-right: 0;
+  margin-left: 0;
 }
 
-toolbar[mode="icons"] #zoom-out-button {
+/* zoom controls */
+
+#zoom-out-button {
   -moz-margin-end: 0;
 }
 
-toolbar[mode="icons"] #zoom-in-button {
+#zoom-in-button {
   -moz-border-start: none;
   -moz-margin-start: 0;
 }
@@ -1090,48 +1415,23 @@ toolbar[mode="icons"] #zoom-in-button {
   border-bottom-left-radius: 0;
 }
 
-/* sync button */
+#zoom-controls[cui-areatype="toolbar"] > #zoom-reset-button {
+  min-width: 0;
+  margin: 0;
+}
 
-#sync-button {
-  -moz-image-region: rect(0, 440px, 20px, 420px);
+#zoom-controls[cui-areatype="toolbar"] > #zoom-reset-button > .toolbarbutton-text {
+  margin-top: 0;
+  padding-top: 8px;
 }
 
+/* sync button */
+
 #sync-button[status="active"] {
   list-style-image: url("chrome://browser/skin/sync-throbber.png");
   -moz-image-region: rect(0, 20px, 20px, 0px);
 }
 
-@media (min-resolution: 2dppx) {
-  #sync-button:not([status="active"]) {
-    -moz-image-region: rect(0, 880px, 40px, 840px);
-  }
-}
-
-/* feed button */
-
-#feed-button {
-  -moz-image-region: rect(0, 460px, 20px, 440px);
-}
-
-@media (min-resolution: 2dppx) {
-  #feed-button {
-    -moz-image-region: rect(0, 920px, 40px, 880px);
-  }
-}
-
-/* webRTC indicator button */
-
-#webrtc-status-button {
-  -moz-image-region: rect(0, 480px, 20px, 460px);
-}
-
-@media (min-resolution: 2dppx) {
-  #webrtc-status-button {
-    -moz-image-region: rect(0, 960px, 40px, 920px);
-  }
-}
-
-
 /* ----- FULLSCREEN WINDOW CONTROLS ----- */
 
 #minimize-button,
@@ -1179,58 +1479,62 @@ toolbar[mode="icons"] #zoom-in-button {
   box-shadow: @focusRingShadow@;
 }
 
+#urlbar-container {
+  -moz-box-align: center;
+}
+
 #urlbar {
   -moz-padding-end: 4px;
   border-radius: @toolbarbuttonCornerRadius@;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper {
   padding-left: @conditionalForwardWithUrlbarWidth@px;
   -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
   position: relative;
   pointer-events: none;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar {
   -moz-border-start: none;
   margin-left: 0;
   pointer-events: all;
 }
 
-@conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
   transition: margin-left @forwardTransitionLength@ ease-out;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
   border-top-left-radius: 0;
   border-bottom-left-radius: 0;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
   border-top-right-radius: 0;
   border-bottom-right-radius: 0;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
   clip-path: url("chrome://browser/content/browser.xul#osx-urlbar-back-button-clip-path");
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
   margin-left: -@conditionalForwardWithUrlbarWidth@px;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
   /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
   transition-delay: 100s;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar {
   /* when not hovered anymore, trigger a new transition to hide the forward button immediately */
   margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper:-moz-locale-dir(rtl),
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
   /* let osx-urlbar-back-button-clip-path clip the urlbar's right side for RTL */
   transform: scaleX(-1);
 }
@@ -1259,30 +1563,30 @@ toolbar[mode="icons"] #zoom-in-button {
   border-radius: 0;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar > #identity-box {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box {
   border-radius: 0;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
   transition: 0s padding-left;
   padding-left: 10px;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
   transition: 0s padding-right;
   padding-right: 10px;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box {
+@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box {
   /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
   transition-delay: 100s;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
   padding-left: 10.01px;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
   padding-right: 10.01px;
 }
 
@@ -1493,14 +1797,6 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
   -moz-image-region: rect(11px, 16px, 22px, 0);
 }
 
-window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
-  -moz-image-region: rect(0, 32px, 11px, 16px);
-}
-
-window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
-  -moz-image-region: rect(11px, 32px, 22px, 16px);
-}
-
 @media (min-resolution: 2dppx) {
   .ac-result-type-bookmark {
     list-style-image: url("chrome://browser/skin/places/star-icons@2x.png");
@@ -1525,14 +1821,6 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
   richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
     -moz-image-region: rect(22px, 32px, 44px, 0);
   }
-
-  window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-icon {
-    -moz-image-region: rect(0, 64px, 22px, 32px);
-  }
-
-  window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-box > .ac-action-icon {
-    -moz-image-region: rect(22px, 64px, 44px, 32px);
-  }
 }
 
 .autocomplete-treebody::-moz-tree-cell-text(treecolAutoCompleteComment) {
@@ -1559,7 +1847,6 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
 
 /* ----- COMBINED GO/RELOAD/STOP BUTTON IN LOCATION BAR ----- */
 
-#go-button,
 #urlbar > toolbarbutton {
   margin: 0;
   -moz-padding-start: 2px;
@@ -1572,21 +1859,14 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
   background-image: radial-gradient(circle closest-side, hsla(205,100%,70%,.3), hsla(205,100%,70%,0));
 }
 
-#go-button {
-  padding: 0 3px;
-}
-
-#go-button,
 #urlbar-go-button {
   -moz-image-region: rect(0, 42px, 14px, 28px);
 }
 
-#go-button:hover:active,
 #urlbar-go-button:hover:active {
   -moz-image-region: rect(14px, 42px, 28px, 28px);
 }
 
-#go-button:-moz-locale-dir(rtl),
 #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   transform: scaleX(-1);
 }
@@ -1611,19 +1891,32 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
   -moz-image-region: rect(14px, 28px, 28px, 14px);
 }
 
+#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+  width: 16px;
+  height: 16px;
+}
+
+#BMB_bookmarksPopup[side="top"],
+#BMB_bookmarksPopup[side="bottom"] {
+  margin-left: -26px;
+  margin-right: -26px;
+}
+
+#BMB_bookmarksPopup[side="left"],
+#BMB_bookmarksPopup[side="right"] {
+  margin-top: -26px;
+  margin-bottom: -26px;
+}
+
 @media (min-resolution: 2dppx) {
-  #go-button,
   #urlbar > toolbarbutton {
     list-style-image: url("chrome://browser/skin/reload-stop-go@2x.png");
   }
 
-  #go-button,
   #urlbar-go-button {
     -moz-image-region: rect(0, 84px, 28px, 56px);
-    height: 14px;
   }
 
-  #go-button:hover:active,
   #urlbar-go-button:hover:active {
     -moz-image-region: rect(28px, 84px, 56px, 56px);
   }
@@ -1644,7 +1937,6 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
     -moz-image-region: rect(28px, 56px, 56px, 28px);
   }
 
-  #go-button > .toolbarbutton-icon,
   #urlbar > toolbarbutton > .toolbarbutton-icon {
     width: 14px;
   }
@@ -1684,31 +1976,6 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
   transition: height 100ms ease-out, width 100ms ease-out;
 }
 
-#social-share-button {
-  list-style-image: url("chrome://browser/skin/social/share-button.png");
-}
-
-#social-share-button[open],
-#social-share-button:hover:active {
-  list-style-image: url("chrome://browser/skin/social/share-button-active.png");
-}
-
-#social-share-button > .toolbarbutton-icon {
-  width: 13px;
-  height: 14px;
-}
-
-@media (min-resolution: 2dppx) {
-  #social-share-button {
-    list-style-image: url("chrome://browser/skin/social/share-button@2x.png");
-  }
-
-  #social-share-button[open],
-  #social-share-button:hover:active {
-    list-style-image: url("chrome://browser/skin/social/share-button-active@2x.png");
-  }
-}
-
 .social-share-toolbar {
   border-right: 1px solid #dedede;
   background: linear-gradient(to bottom, rgba(247,247,247,.99), rgba(247,247,247,.95));
@@ -1752,35 +2019,35 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-/* Star button */
-#star-button {
+/* bookmarks menu-button */
+
+#bookmarks-menu-button.bookmark-item,
+#bookmarks-menu-button.bookmark-item[open] {
   list-style-image: url("chrome://browser/skin/places/star-icons.png");
-  -moz-image-region: rect(0, 16px, 16px, 0);
+  -moz-image-region: rect(0px 16px 16px 0px);
 }
 
-#star-button:hover:active,
-#star-button[starred="true"] {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
+#bookmarks-menu-button.bookmark-item[starred] {
+  -moz-image-region: rect(0px 32px 16px 16px);
 }
 
-#star-button:hover:active[starred="true"] {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
+#bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button {
+  padding: 0;
 }
 
 @media (min-resolution: 2dppx) {
-  #star-button {
+  #bookmarks-menu-button.bookmark-item,
+  #bookmarks-menu-button.bookmark-item[open] {
     list-style-image: url("chrome://browser/skin/places/star-icons@2x.png");
-    -moz-image-region: rect(0, 32px, 32px, 0);
-    width: 22px;
+    -moz-image-region: rect(0px 32px 32px 0px);
   }
 
-  #star-button:hover:active,
-  #star-button[starred="true"] {
-    -moz-image-region: rect(0, 64px, 32px, 32px);
+  #bookmarks-menu-button.bookmark-item[starred] {
+    -moz-image-region: rect(0px 64px 32px 32px);
   }
 
-  #star-button:hover:active[starred="true"] {
-    -moz-image-region: rect(0, 96px, 32px, 64px);
+  #bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+    width: 16px;
   }
 }
 
@@ -2052,40 +2319,17 @@ window[tabsontop="false"] richlistitem[type~="action"][actiontype="switchtab"][s
 }
 
 .panel-promo-closebutton {
-  list-style-image: url("chrome://global/skin/icons/close.png");
-  -moz-image-region: rect(0, 16px, 16px, 0);
   border: none;
   -moz-margin-end: -14px;
   margin-top: -8px;
 }
 
-.panel-promo-closebutton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.panel-promo-closebutton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
 .panel-promo-closebutton > .toolbarbutton-text {
   padding: 0;
   margin: 0;
 }
 
 @media (min-resolution: 2dppx) {
-  .panel-promo-closebutton {
-    list-style-image: url("chrome://global/skin/icons/close@2x.png");
-    -moz-image-region: rect(0, 32px, 32px, 0);
-  }
-
-  .panel-promo-closebutton:hover {
-    -moz-image-region: rect(0, 64px, 32px, 32px);
-  }
-
-  .panel-promo-closebutton:hover:active {
-    -moz-image-region: rect(0, 96px, 32px, 64px);
-  }
-
   .panel-promo-closebutton > .toolbarbutton-icon {
     width: 16px;
   }
@@ -2132,362 +2376,168 @@ sidebarheader {
   background-image: none !important;
   background-color: transparent;
   -moz-margin-start: -3px;
-  position: relative;
-}
-
-#appcontent ~ .sidebar-splitter {
-  -moz-border-start: 1px solid #ccc;
-  -moz-border-end: none;
-  -moz-margin-start: 0;
-  -moz-margin-end: -3px;
-}
-
-#sidebar-title {
-  color: #535f6d;
-  font-weight: bold;
-}
-
-#sidebar-throbber[loading="true"] {
-  list-style-image: url("chrome://global/skin/icons/loading_16.png");
-}
-
-sidebarheader > .tabs-closebutton > .toolbarbutton-text {
-  display: none;
-}
-
-/* ----- CONTENT ----- */
-
-.browserContainer > findbar {
-  background: @scopeBarBackground@;
-  border-top: @scopeBarSeparatorBorder@;
-  color: -moz-DialogText;
-  text-shadow: none;
-}
-
-/* ----- THROBBER ----- */
-
-#navigator-throbber {
-  width: 17px;
-  min-height: 16px;
-  margin: 0 4px;
-}
-
-#navigator-throbber[busy="true"] {
-  list-style-image: url("chrome://global/skin/icons/loading_16.png");
-}
-
-#wrapper-navigator-throbber > #navigator-throbber {
-  list-style-image: url("chrome://global/skin/icons/notloading_16.png");
-}
-
-toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
-  display: none;
-}
-
-.bookmark-item {
-  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
-}
-
-@media (min-resolution: 2dppx) {
-  .bookmark-item {
-    list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
-  }
-
-  image.bookmark-item {
-    width: 16px;
-  }
-}
-
-.openintabs-menuitem {
-  list-style-image: none;
-}
-
-/* ::::: tabbrowser ::::: */
-
-.tabbrowser-tabbox {
-  margin: 0;
-}
-
-.tab-throbber,
-.tab-icon-image {
-  width: 16px;
-  height: 16px;
-  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
-}
-
-.tab-throbber {
-  list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png");
-}
-
-.tab-throbber[progress] {
-  list-style-image: url("chrome://browser/skin/tabbrowser/loading.png");
-}
-
-@media (min-resolution: 2dppx) {
-  .tab-icon-image {
-    list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
-    image-rendering: -moz-crisp-edges;
-  }
-
-  .tab-throbber {
-    list-style-image: url("chrome://browser/skin/tabbrowser/connecting@2x.png");
-  }
-
-  .tab-throbber[progress] {
-    list-style-image: url("chrome://browser/skin/tabbrowser/loading@2x.png");
-  }
-}
-
-.tabbrowser-tab:not(:hover) > .tab-stack > .tab-content > .tab-icon-image:not([selected="true"]) {
-  opacity: .8;
-}
-
-.tabbrowser-tab:not([pinned]):not([fadein]) {
-  transition: min-width 200ms ease-out /* copied from browser/base/content/browser.css */,
-              max-width 250ms ease-out /* copied from browser/base/content/browser.css */,
-              opacity 50ms ease-out 100ms /* hide the tab for the last 100ms of the max-width transition */;
-}
-
-.tab-stack {
-  /* ensure stable tab height with and without toolbarbuttons on the tab bar */
-  height: 26px;
-}
-
-.tabbrowser-tab,
-.tabs-newtab-button {
-  -moz-appearance: none;
-  font: message-box;
-  font-weight: bold;
-  text-shadow: @loweredShadow@;
-  margin: 0;
-  padding: 0;
-  border: none;
-  text-align: center;
-  -moz-box-align: stretch;
-}
-
-.tabbrowser-tab[remote] {
-  text-decoration: underline;
-}
-
-%define TABSONTOP_TAB #tabbrowser-tabs[tabsontop="true"] > .tabbrowser-tab
-%define TABSONBOTTOM_TAB #tabbrowser-tabs[tabsontop="false"] > .tabbrowser-tab
-%define TABSONTOP_TAB_STACK #tabbrowser-tabs[tabsontop="true"] > .tabbrowser-tab > .tab-stack
-%define TABSONBOTTOM_TAB_STACK #tabbrowser-tabs[tabsontop="false"] > .tabbrowser-tab > .tab-stack
-%define TABSONTOP_NEWTAB_BUTTON #tabbrowser-tabs[tabsontop="true"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button
-%define TABSONBOTTOM_NEWTAB_BUTTON #tabbrowser-tabs[tabsontop="false"] > .tabbrowser-arrowscrollbox > .tabs-newtab-button
-
-@TABSONTOP_TAB_STACK@ > .tab-background {
-  margin-top: 3px;
-}
-
-@TABSONBOTTOM_TAB_STACK@ > .tab-background {
-  margin-bottom: 3px;
-}
-
-@TABSONTOP_TAB_STACK@ > .tab-background:not([selected="true"]):not(:-moz-lwtheme) {
-  margin-bottom: 2px;
-}
-
-@TABSONBOTTOM_TAB_STACK@ > .tab-background:not([selected="true"]) {
-  margin-top: 2px;
-}
-
-.tab-background,
-.tab-content,
-.tabs-newtab-button > .toolbarbutton-icon {
-  -moz-margin-start: -5px;
-  -moz-margin-end: -4px;
-  pointer-events: none;
-}
-
-.tab-close-button {
-  pointer-events: auto;
-}
-
-.tabbrowser-tabs[closebuttons="hidden"] > * > * > * > .tab-close-button:not([pinned]) {
-  display: -moz-box;
-  visibility: hidden;
+  position: relative;
 }
 
-.tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox {
-  -moz-padding-start: 5px;
-  -moz-padding-end: 4px;
+#appcontent ~ .sidebar-splitter {
+  -moz-border-start: 1px solid #ccc;
+  -moz-border-end: none;
+  -moz-margin-start: 0;
+  -moz-margin-end: -3px;
 }
 
-.tab-content,
-.tabs-newtab-button > .toolbarbutton-icon {
-  -moz-box-align: center;
-  border: solid transparent;
-  border-width: 0 11px;
+#sidebar-title {
+  color: #535f6d;
+  font-weight: bold;
 }
 
-.tab-background-start,
-.tab-background-end {
-  width: 12px;
-  height: 21px;
+#sidebar-throbber[loading="true"] {
+  list-style-image: url("chrome://global/skin/icons/loading_16.png");
 }
 
-.tab-background-middle {
-  -moz-box-flex: 1;
+sidebarheader > .tabs-closebutton > .toolbarbutton-text {
+  display: none;
 }
 
-@TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(ltr),
-@TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(rtl) {
-  clip-path: url(chrome://browser/content/browser.xul#osx-tab-ontop-left-curve-clip-path);
-}
+/* ----- CONTENT ----- */
 
-@TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(ltr),
-@TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(rtl) {
-  clip-path: url(chrome://browser/content/browser.xul#osx-tab-ontop-right-curve-clip-path);
+.browserContainer > findbar {
+  background: @scopeBarBackground@;
+  border-top: @scopeBarSeparatorBorder@;
+  color: -moz-DialogText;
+  text-shadow: none;
 }
 
-@TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(ltr),
-@TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(rtl) {
-  clip-path: url(chrome://browser/content/browser.xul#osx-tab-onbottom-left-curve-clip-path);
+toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
+  display: none;
 }
 
-@TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(ltr),
-@TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(rtl) {
-  clip-path: url(chrome://browser/content/browser.xul#osx-tab-onbottom-right-curve-clip-path);
+.bookmark-item {
+  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
 }
 
-.tab-background-start[selected="true"]:not(:-moz-lwtheme),
-.tab-background-middle[selected="true"]:not(:-moz-lwtheme),
-.tab-background-end[selected="true"]:not(:-moz-lwtheme) {
-  background-color: -moz-mac-chrome-active;
-}
+@media (min-resolution: 2dppx) {
+  .bookmark-item {
+    list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
+  }
 
-.tab-background-start[selected="true"]:not(:-moz-lwtheme):-moz-window-inactive,
-.tab-background-middle[selected="true"]:not(:-moz-lwtheme):-moz-window-inactive,
-.tab-background-end[selected="true"]:not(:-moz-lwtheme):-moz-window-inactive {
-  background-color: -moz-mac-chrome-inactive;
+  image.bookmark-item {
+    width: 16px;
+  }
 }
 
-.tab-background-start[pinned][titlechanged]:not([selected="true"]),
-.tab-background-end[pinned][titlechanged]:not([selected="true"]) {
-  background-image: linear-gradient(rgba(148,205,253,.2), rgba(148,205,253,.2)) !important;
+.openintabs-menuitem {
+  list-style-image: none;
 }
 
-@TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-middle[pinned][titlechanged]:not([selected="true"]) {
-  background-image: radial-gradient(circle farthest-corner at 50% 99%, rgba(254,254,255,1) 3%, rgba(210,235,255,.9) 12%, rgba(148,205,253,.6) 30%, rgba(148,205,253,.2) 70%);
-}
+/* ::::: tabbrowser ::::: */
 
-@TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-middle[pinned][titlechanged]:not([selected="true"]) {
-  background-image: radial-gradient(circle farthest-corner at 50% 2px, rgba(254,254,255,1) 3%, rgba(210,235,255,.9) 12%, rgba(148,205,253,.6) 30%, rgba(148,205,253,.2) 70%);
+.tabbrowser-tabbox {
+  margin: 0;
 }
 
-.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start:-moz-lwtheme-brighttext:not([selected="true"]),
-.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle:-moz-lwtheme-brighttext:not([selected="true"]),
-.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end:-moz-lwtheme-brighttext:not([selected="true"]) {
-  background-image: linear-gradient(hsla(0,0%,40%,.6), hsla(0,0%,30%,.6) 50%);
-}
+%include ../shared/tabs.inc.css
 
-.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start:-moz-lwtheme-darktext:not([selected="true"]),
-.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle:-moz-lwtheme-darktext:not([selected="true"]),
-.tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end:-moz-lwtheme-darktext:not([selected="true"]) {
-  background-image: linear-gradient(hsla(0,0%,60%,.5), hsla(0,0%,45%,.5) 50%);
+.tab-label {
+  margin-top: 1px;
+  margin-bottom: 0;
+  text-align: center;
 }
 
-@TABSONTOP_TAB_STACK@ > .tab-content,
-@TABSONTOP_NEWTAB_BUTTON@ > .toolbarbutton-icon {
-  border-image: url(chrome://browser/skin/tabbrowser/tab-top-normal-active.png) 0 11 fill repeat stretch;
-}
+@media (min-resolution: 2dppx) {
+  /* image preloading hack from shared/tabs.inc.css */
+  #TabsToolbar::before {
+    background-image:
+      url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png),
+      url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png),
+      url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png);
+  }
 
-@TABSONTOP_TAB@:hover > .tab-stack > .tab-content:not([selected="true"]),
-@TABSONTOP_NEWTAB_BUTTON@:hover > .toolbarbutton-icon {
-  border-image: url(chrome://browser/skin/tabbrowser/tab-top-hover-active.png) 0 11 fill repeat stretch;
-}
+  .tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]),
+  .tabs-newtab-button:hover {
+    background-image: url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png),
+                      url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png),
+                      url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png);
+  }
 
-@TABSONTOP_TAB_STACK@ > .tab-content[selected="true"] {
-  border-image: url(chrome://browser/skin/tabbrowser/tab-top-selected-active.png) 0 11 fill repeat stretch;
-}
+  .tab-background-middle[selected=true] {
+    background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png),
+                      @fgTabTexture@,
+                      none;
+  }
 
-@TABSONBOTTOM_TAB_STACK@ > .tab-content,
-@TABSONBOTTOM_NEWTAB_BUTTON@ > .toolbarbutton-icon {
-  border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-normal-active.png) 0 11 fill repeat stretch;
-}
+  .tab-background-start[selected=true]:-moz-locale-dir(ltr)::after,
+  .tab-background-end[selected=true]:-moz-locale-dir(rtl)::after {
+    background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-start@2x.png);
+  }
 
-@media (min-resolution: 2dppx) {
-  @TABSONTOP_TAB_STACK@ > .tab-content,
-  @TABSONTOP_NEWTAB_BUTTON@ > .toolbarbutton-icon {
-    border-image: url(chrome://browser/skin/tabbrowser/tab-top-normal-active@2x.png) 0 22 fill repeat stretch;
+  .tab-background-end[selected=true]:-moz-locale-dir(ltr)::after,
+  .tab-background-start[selected=true]:-moz-locale-dir(rtl)::after {
+    background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-end@2x.png);
+  }
+
+  .tab-icon-image {
+    list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
+    image-rendering: -moz-crisp-edges;
+  }
+
+  .tab-throbber {
+    list-style-image: url("chrome://browser/skin/tabbrowser/connecting@2x.png");
   }
 
-  @TABSONTOP_TAB@:hover > .tab-stack > .tab-content:not([selected="true"]),
-  @TABSONTOP_NEWTAB_BUTTON@:hover > .toolbarbutton-icon {
-    border-image: url(chrome://browser/skin/tabbrowser/tab-top-hover-active@2x.png) 0 22 fill repeat stretch;
+  .tab-throbber[progress] {
+    list-style-image: url("chrome://browser/skin/tabbrowser/loading@2x.png");
   }
 
-  @TABSONTOP_TAB_STACK@ > .tab-content[selected="true"] {
-    border-image: url(chrome://browser/skin/tabbrowser/tab-top-selected-active@2x.png) 0 22 fill repeat stretch;
+  /* Background tab separators */
+  #tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
+  .tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
+  #tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
+    background-image: url(chrome://browser/skin/tabbrowser/tab-separator@2x.png);
   }
 }
 
-@TABSONBOTTOM_TAB@:hover > .tab-stack > .tab-content:not([selected="true"]),
-@TABSONBOTTOM_NEWTAB_BUTTON@:hover > .toolbarbutton-icon {
-  border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-hover-active.png) 0 11 fill repeat stretch;
+.tabbrowser-tab:not(:hover) > .tab-stack > .tab-content > .tab-icon-image:not([selected="true"]) {
+  opacity: .9;
 }
 
-@TABSONBOTTOM_TAB_STACK@ > .tab-content[selected="true"] {
-  border-image: url(chrome://browser/skin/tabbrowser/tab-bottom-selected-active.png) 0 11 fill repeat stretch;
+.tab-label:not([selected="true"]) {
+  opacity: .7;
 }
 
-/* preloading hack */
-#TabsToolbar::after {
-  content: '';
-  display: block;
-  background-image:
-    url(chrome://browser/skin/tabbrowser/tab-top-normal-active.png),
-    url(chrome://browser/skin/tabbrowser/tab-top-hover-active.png),
-    url(chrome://browser/skin/tabbrowser/tab-top-selected-active.png),
-    url(chrome://browser/skin/tabbrowser/tab-bottom-normal-active.png),
-    url(chrome://browser/skin/tabbrowser/tab-bottom-hover-active.png),
-    url(chrome://browser/skin/tabbrowser/tab-bottom-selected-active.png),
-    url(chrome://browser/skin/tabbrowser/tabbar-top-bg-active.png),
-    url(chrome://browser/skin/tabbrowser/tabbar-top-bg-inactive.png),
-    url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-active.png),
-    url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-inactive.png);
+.tabbrowser-tab,
+.tabs-newtab-button {
+  font: message-box;
+  font-weight: bold;
+  border: none;
 }
 
-@media (min-resolution: 2dppx) {
-  #TabsToolbar::after {
-    content: '';
-    display: block;
-    background-image:
-      url(chrome://browser/skin/tabbrowser/tab-top-normal-active@2x.png),
-      url(chrome://browser/skin/tabbrowser/tab-top-hover-active@2x.png),
-      url(chrome://browser/skin/tabbrowser/tab-top-selected-active@2x.png),
-      url(chrome://browser/skin/tabbrowser/tab-bottom-normal-active.png),
-      url(chrome://browser/skin/tabbrowser/tab-bottom-hover-active.png),
-      url(chrome://browser/skin/tabbrowser/tab-bottom-selected-active.png),
-      url(chrome://browser/skin/tabbrowser/tabbar-top-bg-active.png),
-      url(chrome://browser/skin/tabbrowser/tabbar-top-bg-inactive.png),
-      url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-active.png),
-      url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-inactive.png);
-  }
+.tabbrowser-tab:not(:-moz-lwtheme) {
+  color: #333;
+  text-shadow: @loweredShadow@;
 }
 
-.tabbrowser-tab:focus > .tab-stack {
-  box-shadow: @focusRingShadow@;
+.tabbrowser-tabs[closebuttons="hidden"] > * > * > * > .tab-close-button:not([pinned]) {
+  display: -moz-box;
+  visibility: hidden;
 }
 
-.tabbrowser-tab:not([selected="true"]):not(:hover):not(:-moz-lwtheme) {
-  color: #222;
+.tabs-newtab-button > .toolbarbutton-icon {
+  -moz-box-align: center;
+  border: solid transparent;
+  border-width: 0 11px;
 }
 
-.tabbrowser-tab[selected="true"] {
-  color: #000;
-  z-index: 1;
-  position: relative;
+.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label {
+  box-shadow: @focusRingShadow@;
 }
 
-.tabbrowser-tab:-moz-lwtheme {
-  color: inherit;
-  text-shadow: inherit;
+#titlebar {
+  padding-top: @spaceAboveTabbar@;
+  min-height: @tabHeight@;
 }
 
-#main-window:not([privatebrowsingmode=temporary]) #navigator-toolbox[tabsontop="true"]:not(:-moz-lwtheme)::before {
+#main-window:not(:-moz-any([privatebrowsingmode=temporary],[customizing],[tabsintitlebar])) #navigator-toolbox:not(:-moz-lwtheme)::before {
   /* We want the titlebar to be unified, but we still want to be able
    * to give #TabsToolbar a background. So we can't set -moz-appearance:
    * toolbar on #TabsToolbar itself. Instead, we set it on a box of the
@@ -2496,74 +2546,43 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   content: '';
   display: block;
   -moz-appearance: toolbar;
-  height: 25px;
-  margin-bottom: -25px;
+  height: calc(@tabHeight@ + 1px);
+  margin-bottom: calc(-1px - @tabHeight@);
 }
 
 #TabsToolbar {
+  position: relative;
   -moz-appearance: none;
-  height: 26px;
   background-repeat: repeat-x;
 }
 
-#TabsToolbar[tabsontop="false"] {
-  margin-top: -2px;
-  padding-top: 2px;
-}
-
-/* For tabs-on-top, only fill the bottom 2px with the chrome background
- * color, so that the borders in tabbar-top-bg-*.png can mix with it.
- * In the top 24px the unified toolbar (from the ::before above) will show.
- */
-#TabsToolbar[tabsontop="true"]:not(:-moz-lwtheme) {
-  padding-bottom: 2px;
-  background: url(chrome://browser/skin/tabbrowser/tabbar-top-bg-active.png),
-              linear-gradient(to top, -moz-mac-chrome-active 2px, transparent 2px);
-}
-
-#TabsToolbar[tabsontop="true"]:not(:-moz-lwtheme):-moz-window-inactive {
-  background: url(chrome://browser/skin/tabbrowser/tabbar-top-bg-inactive.png),
-              linear-gradient(to top, -moz-mac-chrome-inactive 2px, transparent 2px);
-}
-
-/* In tabs-on-bottom mode, fill the whole toolbar with the chrome
- * background color.
+/*
+ * Draw the bottom border of the tabstrip when core doesn't do it for us:
  */
-#TabsToolbar[tabsontop="false"]:not(:-moz-lwtheme) {
-  background: url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-active.png) -moz-mac-chrome-active;
-}
-
-#TabsToolbar[tabsontop="false"]:not(:-moz-lwtheme):-moz-window-inactive {
-  background: url(chrome://browser/skin/tabbrowser/tabbar-bottom-bg-inactive.png) -moz-mac-chrome-inactive;
+#main-window:-moz-any([privatebrowsingmode=temporary],[sizemode="fullscreen"],[customizing],[customize-exiting]) #TabsToolbar::after,
+#main-window:not([tabsintitlebar]) #TabsToolbar::after,
+#TabsToolbar:-moz-lwtheme::after {
+  content: '';
+  /* Because we use placeholders for window controls etc. in the tabstrip,
+   * and position those with ordinal attributes, and because our layout code
+   * expects :before/:after nodes to come first/last in the frame list,
+   * we have to reorder this element to come last, hence the
+   * ordinal group value (see bug 853415). */
+  -moz-box-ordinal-group: 1001;
+  position: absolute;
+  bottom: 1px;
+  left: 0;
+  right: 0;
+  z-index: 0;
+  border-bottom: 1px solid hsla(0,0%,0%,.3);
 }
 
 #tabbrowser-tabs {
   -moz-box-align: stretch;
-  height: 26px;
-}
-
-#tabbrowser-tabs[tabsontop="true"] > .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox:not(:-moz-lwtheme) {
-  margin-bottom: -2px;
-}
-
-#tabbrowser-tabs[tabsontop="false"] > .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox {
-  margin-top: -2px;
-}
-
-@TABSONTOP_NEWTAB_BUTTON@ > .toolbarbutton-icon {
-  padding: 4px 0 2px;
-}
-
-@TABSONTOP_TAB_STACK@ > .tab-content {
-  padding-top: 2px;
 }
 
-@TABSONBOTTOM_NEWTAB_BUTTON@ > .toolbarbutton-icon {
-  padding: 2px 0 4px;
-}
-
-@TABSONBOTTOM_TAB_STACK@ > .tab-content {
-  padding-bottom: 2px;
+.tabs-newtab-button > .toolbarbutton-icon {
+  padding: 6px 0 4px;
 }
 
 /**
@@ -2572,7 +2591,8 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
 
 .tab-drop-indicator {
   list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png);
-  margin-bottom: -8px;
+  margin-top: -2px;
+  z-index: 3;
 }
 
 @media (min-resolution: 2dppx) {
@@ -2591,38 +2611,13 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
 }
 
 .tab-close-button {
-  list-style-image: url("chrome://global/skin/icons/close.png");
   -moz-appearance: none;
   border: none !important;
-  padding: 0;
-  margin: 0;
   background: none;
   cursor: default;
-  -moz-image-region: rect(0, 16px, 16px, 0);
-}
-
-.tab-close-button:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.tab-close-button:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
 @media (min-resolution: 2dppx) {
-  .tab-close-button {
-    list-style-image: url("chrome://global/skin/icons/close@2x.png");
-    -moz-image-region: rect(0, 32px, 32px, 0);
-  }
-
-  .tab-close-button:hover {
-    -moz-image-region: rect(0, 64px, 32px, 32px);
-  }
-
-  .tab-close-button:hover:active {
-    -moz-image-region: rect(0, 96px, 32px, 64px);
-  }
-
   .tab-close-button > .toolbarbutton-icon {
     width: 16px;
   }
@@ -2636,13 +2631,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   border: none;
 }
 
-#tabbrowser-tabs[tabsontop=false] > .tabbrowser-arrowscrollbox > .scrollbutton-up,
-#tabbrowser-tabs[tabsontop=false] > .tabbrowser-arrowscrollbox > .scrollbutton-down,
-#tabbrowser-tabs[tabsontop=false] > .tabbrowser-arrowscrollbox > .scrollbutton-up > .toolbarbutton-icon,
-#tabbrowser-tabs[tabsontop=false] > .tabbrowser-arrowscrollbox > .scrollbutton-down > .toolbarbutton-icon {
-  transform: scaleY(-1);
-}
-
 .tabbrowser-arrowscrollbox > .scrollbutton-up {
   -moz-border-end: 2px solid transparent;
 }
@@ -2667,6 +2655,16 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-right.png");
 }
 
+.tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(ltr):-moz-lwtheme-brighttext,
+.tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(rtl):-moz-lwtheme-brighttext {
+  list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-left-inverted.png");
+}
+
+.tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(ltr):-moz-lwtheme-brighttext,
+.tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(rtl):-moz-lwtheme-brighttext {
+  list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-right-inverted.png");
+}
+
 .tabbrowser-arrowscrollbox > .scrollbutton-up:hover,
 .tabbrowser-arrowscrollbox > .scrollbutton-down:hover {
   -moz-image-region: rect(0, 26px, 20px, 13px);
@@ -2699,6 +2697,16 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
     list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-right@2x.png");
   }
 
+  .tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(ltr):-moz-lwtheme-brighttext,
+  .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(rtl):-moz-lwtheme-brighttext {
+    list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-left-inverted@2x.png");
+  }
+
+  .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-locale-dir(ltr):-moz-lwtheme-brighttext,
+  .tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-locale-dir(rtl):-moz-lwtheme-brighttext {
+    list-style-image: url("chrome://browser/skin/tabbrowser/tab-arrow-right-inverted@2x.png");
+  }
+
   .tabbrowser-arrowscrollbox > .scrollbutton-up:hover,
   .tabbrowser-arrowscrollbox > .scrollbutton-down:hover {
     -moz-image-region: rect(0, 52px, 40px, 26px);
@@ -2738,9 +2746,9 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
  * Tabstrip & add-on bar toolbar buttons
  */
 
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1,
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button,
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
+#TabsToolbar .toolbarbutton-1,
+#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button,
+#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   -moz-appearance: none;
   /* !important flags needed because of bug 561154: */
   margin: 0 !important;
@@ -2751,31 +2759,31 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   box-shadow: none !important;
 }
 
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1:not([type="menu-button"]),
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button {
+#TabsToolbar .toolbarbutton-1:not([type="menu-button"]),
+#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   margin: 0;
   padding: 0 1px;
 }
 
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
+#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   padding-left: 4px;
   padding-right: 4px;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):hover,
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):hover,
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1:not([type="menu-button"]):not([disabled]):not([open]):hover,
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover,
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1:not([disabled]):not([buttonover]):hover > .toolbarbutton-menubutton-dropmarker {
+#TabsToolbar .toolbarbutton-1:not([type="menu-button"]):not([disabled]):not([open]):hover,
+#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover,
+#TabsToolbar .toolbarbutton-1:not([disabled]):not([buttonover]):hover > .toolbarbutton-menubutton-dropmarker {
   background-image: linear-gradient(transparent, rgba(0,0,0,.15)) !important;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):hover:active,
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled]):hover:active,
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1:not([type="menu-button"]):not([disabled]):hover:active,
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1[type="menu"][open],
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active,
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1[open]:not([disabled]):hover > .toolbarbutton-menubutton-dropmarker {
+#TabsToolbar .toolbarbutton-1:not([type="menu-button"]):not([disabled]):hover:active,
+#TabsToolbar .toolbarbutton-1[type="menu"][open],
+#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active,
+#TabsToolbar .toolbarbutton-1[open]:not([disabled]):hover > .toolbarbutton-menubutton-dropmarker {
   background-image: linear-gradient(transparent, rgba(0,0,0,.3)) !important;
 }
 
@@ -2786,6 +2794,12 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   -moz-image-region: rect(0, 18px, 20px, 0);
 }
 
+.tabs-newtab-button:-moz-lwtheme-brighttext,
+#TabsToolbar > #new-tab-button:-moz-lwtheme-brighttext,
+#TabsToolbar > toolbarpaletteitem > #new-tab-button:-moz-lwtheme-brighttext {
+  list-style-image: url(chrome://browser/skin/tabbrowser/newtab-inverted.png);
+}
+
 .tabs-newtab-button:hover,
 #TabsToolbar > #new-tab-button:hover {
   -moz-image-region: rect(0, 36px, 20px, 18px);
@@ -2804,6 +2818,12 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
     -moz-image-region: rect(0, 36px, 40px, 0);
   }
 
+  .tabs-newtab-button:-moz-lwtheme-brighttext,
+  #TabsToolbar > #new-tab-button:-moz-lwtheme-brighttext,
+  #TabsToolbar > toolbarpaletteitem > #new-tab-button:-moz-lwtheme-brighttext {
+    list-style-image: url(chrome://browser/skin/tabbrowser/newtab-inverted@2x.png);
+  }
+
   .tabs-newtab-button:hover,
   #TabsToolbar > #new-tab-button:hover {
     -moz-image-region: rect(0, 72px, 40px, 36px);
@@ -2824,36 +2844,44 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   }
 }
 
-#TabsToolbar #alltabs-button {
+#alltabs-button {
   list-style-image: url(chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon.png);
   -moz-image-region: rect(0, 17px, 20px, 0);
 }
 
-#TabsToolbar > #alltabs-button:not([disabled="true"]):hover {
+#alltabs-button:-moz-lwtheme-brighttext {
+  list-style-image: url(chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon-inverted.png);
+}
+
+#alltabs-button:not([disabled="true"]):hover {
   -moz-image-region: rect(0, 34px, 20px, 17px);
 }
 
-#TabsToolbar > #alltabs-button[open="true"]:not([disabled="true"]),
-#TabsToolbar > #alltabs-button:not([disabled="true"]):hover:active {
+#alltabs-button[open="true"]:not([disabled="true"]),
+#alltabs-button:not([disabled="true"]):hover:active {
   -moz-image-region: rect(0, 51px, 20px, 34px);
 }
 
 @media (min-resolution: 2dppx) {
-  #TabsToolbar #alltabs-button {
+  #alltabs-button {
     list-style-image: url(chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon@2x.png);
     -moz-image-region: rect(0, 34px, 40px, 0);
   }
 
-  #TabsToolbar > #alltabs-button:not([disabled="true"]):hover {
+  #alltabs-button:-moz-lwtheme-brighttext {
+    list-style-image: url(chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png);
+  }
+
+  #alltabs-button:not([disabled="true"]):hover {
     -moz-image-region: rect(0, 68px, 40px, 34px);
   }
 
-  #TabsToolbar > #alltabs-button[open="true"]:not([disabled="true"]),
-  #TabsToolbar > #alltabs-button:not([disabled="true"]):hover:active {
+  #alltabs-button[open="true"]:not([disabled="true"]),
+  #alltabs-button:not([disabled="true"]):hover:active {
     -moz-image-region: rect(0, 102px, 40px, 68px);
   }
 
-  #TabsToolbar #alltabs-button > .toolbarbutton-icon {
+  #alltabs-button > .toolbarbutton-icon {
     width: 17px;
   }
 }
@@ -2889,38 +2917,11 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
 /* Tabstrip close button */
 .tabs-closebutton {
   -moz-padding-end: 4px;
-  list-style-image: url("chrome://global/skin/icons/close.png");
-  -moz-image-region: rect(0, 16px, 16px, 0);
   border: none;
 }
 
-#sidebar-header > .tabs-closebutton {
-  list-style-image: url("chrome://global/skin/icons/close-sidebar.png");
-}
-
-.tabs-closebutton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.tabs-closebutton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
 @media (min-resolution: 2dppx) {
-  :not(#sidebar-header) > .tabs-closebutton {
-    list-style-image: url("chrome://global/skin/icons/close@2x.png");
-    -moz-image-region: rect(0, 32px, 32px, 0);
-  }
-
-  :not(#sidebar-header) > .tabs-closebutton:hover {
-    -moz-image-region: rect(0, 64px, 32px, 32px);
-  }
-
-  :not(#sidebar-header) > .tabs-closebutton:hover:active {
-    -moz-image-region: rect(0, 96px, 32px, 64px);
-  }
-
-  :not(#sidebar-header) > .tabs-closebutton > .toolbarbutton-icon {
+  .tabs-closebutton > .toolbarbutton-icon {
     width: 16px;
   }
 }
@@ -2952,10 +2953,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   background-color: Highlight;
 }
 
-#customizeToolbarSheetPopup {
-  -moz-window-shadow: sheet;
-}
-
 /* Popup Icons */
 #identity-popup-icon {
   height: 64px;
@@ -3107,7 +3104,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   }
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box {
   padding-left: 7px;
 }
 
@@ -3549,69 +3546,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   margin-top: .5em;
 }
 
-/* Add-on bar */
-
-#addon-bar {
-  min-height: 18px;
-  padding-right: 16px; /* replace with -moz-padding-end when/if bug 631729 gets fixed */
-}
-
-#addon-bar:not(:-moz-lwtheme) {
-  -moz-appearance: statusbar;
-}
-
-#status-bar {
-  -moz-appearance: none;
-  padding-right: 0;
-}
-
-#addon-bar[customizing] > #status-bar {
-  opacity: .5;
-  background-image: repeating-linear-gradient(135deg,
-                                              rgba(255,255,255,.3), rgba(255,255,255,.3) 5px,
-                                              rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px);
-}
-
-#status-bar > statusbarpanel {
-  border-width: 0;
-  -moz-appearance: none;
-}
-
-#addonbar-closebutton {
-  padding: 0;
-  margin: 0 6px;
-  list-style-image: url("chrome://global/skin/icons/close.png");
-  border: none;
-  -moz-image-region: rect(0, 16px, 16px, 0);
-}
-
-#addonbar-closebutton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-#addonbar-closebutton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
-@media (min-resolution: 2dppx) {
-  #addonbar-closebutton {
-    list-style-image: url("chrome://global/skin/icons/close@2x.png");
-    -moz-image-region: rect(0, 32px, 32px, 0);
-  }
-
-  #addonbar-closebutton:hover {
-    -moz-image-region: rect(0, 64px, 32px, 32px);
-  }
-
-  #addonbar-closebutton:hover:active {
-    -moz-image-region: rect(0, 96px, 32px, 64px);
-  }
-
-  #addonbar-closebutton > .toolbarbutton-icon {
-    width: 16px;
-  }
-}
-
 /* Status panel */
 
 .statuspanel-label {
@@ -3640,8 +3574,8 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
 
 /* Lion Fullscreen window styling */
 @media (-moz-mac-lion-theme) {
-  #navigator-toolbox[inFullscreen][tabsontop="true"]:not(:-moz-lwtheme)::before {
-    height: 36px;
+  #navigator-toolbox[inFullscreen]:not(:-moz-lwtheme)::before {
+    height: calc(@tabHeight@ + 11px) !important;
   }
   #main-window[inFullscreen]:-moz-lwtheme {
     /* This additional padding matches the change in height in the pseudo-element
@@ -3780,7 +3714,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
   position: relative;
 }
 .toolbarbutton-badge-container > .toolbarbutton-icon {
-  margin: 2px;
+  margin: 7px 2px;
 }
 
 .toolbarbutton-badge[badge]:not([badge=""]) {
@@ -3975,6 +3909,49 @@ window > chatbox {
   border-bottom-right-radius: @toolbarbuttonCornerRadius@;
 }
 
+/* Customization mode */
+
+%include ../shared/customizableui/customizeMode.inc.css
+
+#main-window[customizing] #titlebar {
+  padding-top: 0;
+}
+
+#main-window:-moz-any([customize-entering],[customize-entered]) #tab-view-deck {
+  padding: 0 2em 2em;
+}
+
+#main-window[customizing] #tab-view-deck {
+  background-image: url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"),
+                    url("chrome://browser/skin/customizableui/background-noise-toolbar.png"),
+                    linear-gradient(to bottom, rgb(233,233,233), rgb(178,178,178) 21px);
+  background-attachment: fixed;
+}
+
+#main-window[customize-entered] #navigator-toolbox > toolbar:not(#TabsToolbar),
+#main-window[customize-entered] #customization-container {
+  border: 3px solid hsla(0,0%,0%,.1);
+  border-top-width: 0;
+  background-clip: padding-box;
+  background-origin: padding-box;
+  -moz-border-right-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2);
+  -moz-border-bottom-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2);
+  -moz-border-left-colors: hsla(0,0%,0%,.05) hsla(0,0%,0%,.1) hsla(0,0%,0%,.2);
+}
+
+#main-window[customize-entered] #navigator-toolbox > toolbar:not(#TabsToolbar) {
+  border-bottom-width: 0;
+}
+
+#main-window[customize-entered] #TabsToolbar {
+  margin-top: 9px;
+  background-clip: padding-box;
+  border-right: 3px solid transparent;
+  border-left: 3px solid transparent;
+}
+
+/* End customization mode */
+
 panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="top"],
 panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .panel-arrowbox > .panel-arrow[side="bottom"] {
   list-style-image: url("chrome://global/skin/arrow/panelarrow-light-vertical.png");
@@ -4001,13 +3978,11 @@ panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .
 }
 
 #main-window[privatebrowsingmode=temporary] {
-  background-position: top right 40px;
-}
-
-#main-window[privatebrowsingmode=temporary][inFullscreen] {
-  background-position: top right 10px;
+  background-position: top right 20px;
 }
 
+/* Note that the caption and fullscreen buttons stay in the same position for LTR and RTL but we
+   move the private browsing indicator to the left in RTL. */
 #main-window[privatebrowsingmode=temporary]:-moz-locale-dir(rtl) {
   background-position: top left 70px;
 }
@@ -4016,28 +3991,31 @@ panel[type="arrow"][popupid="click-to-play-plugins"] > .panel-arrowcontainer > .
   background-position: top left 10px;
 }
 
+#main-window[privatebrowsingmode=temporary][inFullscreen] .titlebar-placeholder[type="fullscreen-button"]:-moz-locale-dir(ltr) {
+  /* Override display:none for .titlebar-placeholder in fullscreen so we can have consistent
+     position and padding for the private browsing indicator. */
+  display: -moz-box;
+}
+
 #main-window[privatebrowsingmode=temporary]:-moz-window-inactive {
   background-color: -moz-mac-chrome-inactive;
 }
 
-#main-window[privatebrowsingmode=temporary][inFullscreen] #nav-bar[tabsontop=false] {
-  -moz-padding-end: 50px !important;
+#main-window[privatebrowsingmode=temporary] #TabsToolbar {
+  -moz-padding-end: 46px;
 }
 
 @media (-moz-mac-lion-theme) {
-  #main-window[privatebrowsingmode=temporary][inFullscreen] #TabsToolbar[tabsontop=true] {
-    -moz-padding-end: 50px;
+  #main-window[privatebrowsingmode=temporary] #TabsToolbar:-moz-locale-dir(ltr) {
+    -moz-padding-end: 36px;
   }
 }
 
 @media not all and (-moz-mac-lion-theme) {
+  /* There is no OS fullscreen button prior to Lion so the PB indicator can move closer. */
   #main-window[privatebrowsingmode=temporary] {
     background-position: top right 10px;
   }
-
-  #main-window[privatebrowsingmode=temporary][inFullscreen][tabsontop=true] #window-controls {
-    -moz-padding-end: 50px;
-  }
 }
 
 %include ../shared/UITour.inc.css
diff --git a/browser/themes/osx/customizableui/background-noise-toolbar.png b/browser/themes/osx/customizableui/background-noise-toolbar.png
new file mode 100644
index 0000000000000000000000000000000000000000..d09ba9dafb5ede66e92ce577ecaa6f9575dba104
Binary files /dev/null and b/browser/themes/osx/customizableui/background-noise-toolbar.png differ
diff --git a/browser/themes/osx/customizableui/customizeMode-gridTexture.png b/browser/themes/osx/customizableui/customizeMode-gridTexture.png
new file mode 100644
index 0000000000000000000000000000000000000000..a7c2775cfc799da31a505b249f5a59b89c148a58
Binary files /dev/null and b/browser/themes/osx/customizableui/customizeMode-gridTexture.png differ
diff --git a/browser/themes/osx/customizableui/customizeMode-separatorHorizontal.png b/browser/themes/osx/customizableui/customizeMode-separatorHorizontal.png
new file mode 100644
index 0000000000000000000000000000000000000000..5e17cb4db08e310e6c3a9e14c5bd722772dfb639
Binary files /dev/null and b/browser/themes/osx/customizableui/customizeMode-separatorHorizontal.png differ
diff --git a/browser/themes/osx/customizableui/customizeMode-separatorVertical.png b/browser/themes/osx/customizableui/customizeMode-separatorVertical.png
new file mode 100644
index 0000000000000000000000000000000000000000..dc4caee812878f246c87d71093768eb36c5656fc
Binary files /dev/null and b/browser/themes/osx/customizableui/customizeMode-separatorVertical.png differ
diff --git a/browser/themes/osx/customizableui/panelUIOverlay.css b/browser/themes/osx/customizableui/panelUIOverlay.css
new file mode 100644
index 0000000000000000000000000000000000000000..97ffa35df2d15636a31ed943392805a50ba9dd86
--- /dev/null
+++ b/browser/themes/osx/customizableui/panelUIOverlay.css
@@ -0,0 +1,78 @@
+/* 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/customizableui/panelUIOverlay.inc.css
+
+@media (min-resolution: 2dppx) {
+  #customization-palette toolbarbutton > .toolbarbutton-icon,
+  #PanelUI-contents toolbarbutton > .toolbarbutton-icon {
+    width: 20px;
+  }
+
+  #PanelUI-customize {
+    list-style-image: url(chrome://browser/skin/menuPanel-customize@2x.png);
+  }
+
+  #PanelUI-help {
+    list-style-image: url(chrome://browser/skin/menuPanel-help@2x.png);
+  }
+
+  #PanelUI-quit {
+    list-style-image: url(chrome://browser/skin/menuPanel-exit@2x.png);
+  }
+
+  #PanelUI-customize,
+  #PanelUI-help,
+  #PanelUI-quit {
+    -moz-image-region: rect(0, 32px, 32px, 0);
+  }
+
+  #PanelUI-customize:hover,
+  #PanelUI-help:not([disabled]):hover,
+  #PanelUI-quit:not([disabled]):hover {
+    -moz-image-region: rect(0, 64px, 32px, 32px);
+  }
+
+  #PanelUI-customize:hover:active,
+  #PanelUI-help:not([disabled]):hover:active,
+  #PanelUI-quit:not([disabled]):hover:active {
+    -moz-image-region: rect(0, 96px, 32px, 64px);
+  }
+}
+
+#edit-controls@inAnyPanel@ > toolbarbutton:not(:first-child),
+#zoom-controls@inAnyPanel@ > toolbarbutton:not(:first-child) {
+  margin-left: 0;
+  margin-right: 0;
+}
+#edit-controls@inAnyPanel@ > toolbarbutton:not(:first-child):not(:last-child),
+#zoom-controls@inAnyPanel@ > toolbarbutton:not(:first-child):not(:last-child) {
+  margin-left: 0;
+  margin-right: 0;
+}
+
+#zoom-controls@inAnyPanel@ > #zoom-in-button,
+#zoom-controls@inAnyPanel@ > #zoom-out-button,
+toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button,
+toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-out-button {
+  padding-left: 12px;
+  padding-right: 12px;
+}
+
+.panel-wide-item[cui-areatype="menu-panel"] > toolbarbutton,
+toolbarbutton[cui-areatype="menu-panel"] {
+  margin: 0;
+}
+
+#BMB_bookmarksPopup > menu,
+#BMB_bookmarksPopup > menuitem {
+  padding-top: 5px;
+  padding-bottom: 5px;
+}
+
+/* Override OSX-specific toolkit styles for the bookmarks panel */
+#BMB_bookmarksPopup > menuitem > .menu-accel-container,
+#BMB_bookmarksPopup > menu > .menu-right {
+  -moz-margin-end: 0;
+}
diff --git a/browser/themes/osx/downloads/indicator.css b/browser/themes/osx/downloads/indicator.css
index c5a2308ab2fe6c8e4551716284b9548096603944..142f034cb9a3058712289789316c54912fedf9d5 100644
--- a/browser/themes/osx/downloads/indicator.css
+++ b/browser/themes/osx/downloads/indicator.css
@@ -26,47 +26,58 @@
 
 #downloads-indicator-icon {
   background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
-                              0, 140, 20, 120) center no-repeat;
+                              0, 198, 18, 180) center no-repeat;
 }
 
-#downloads-button[attention]
-#downloads-indicator-icon {
+#downloads-indicator-icon:-moz-lwtheme-brighttext {
+  background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 198, 18, 180);
+}
+
+#downloads-button[attention] #downloads-indicator-icon {
   background-image: url("chrome://browser/skin/downloads/download-glow.png");
 }
 
 /* In the next few rules, we use :not([counter]) as a shortcut that is
    equivalent to -moz-any([progress], [paused]). */
 
-#downloads-button:not([counter])
-#downloads-indicator-counter {
+#downloads-button:not([counter]) #downloads-indicator-counter {
   background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
-                              0, 140, 20, 120) center no-repeat;
+                              0, 198, 18, 180) center no-repeat;
   background-size: 12px;
 }
 
-#downloads-button:not([counter])[attention]
-#downloads-indicator-counter {
+#downloads-button:not([counter]) #downloads-indicator-counter:-moz-lwtheme-brighttext {
+  background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 198, 18, 180);
+}
+
+#downloads-button:not([counter])[attention] #downloads-indicator-counter {
   background-image: url("chrome://browser/skin/downloads/download-glow.png");
 }
 
 @media (min-resolution: 2dppx) {
-  #downloads-indicator-icon:not(:-moz-lwtheme-brighttext) {
-    background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar@2x.png"), 0, 280, 40, 240);
-    background-size: 20px;
+  #downloads-indicator-icon {
+    background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar@2x.png"), 0, 396, 36, 360);
+    background-size: 18px;
   }
 
-  #downloads-button:not([counter]) > #downloads-indicator-anchor >
-  #downloads-indicator-progress-area > #downloads-indicator-counter {
-    background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar@2x.png"), 0, 280, 40, 240);
+  #downloads-indicator-icon:-moz-lwtheme-brighttext {
+    background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted@2x.png"), 0, 396, 36, 360);
   }
 
-  #downloads-button[attention] > #downloads-indicator-anchor >
-  #downloads-indicator-icon {
+  #downloads-button:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
+    background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar@2x.png"), 0, 396, 36, 360);
+  }
+
+  #downloads-button:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter:-moz-lwtheme-brighttext {
+    background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted@2x.png"),
+                                      0, 396, 36, 360);
+  }
+
+  #downloads-button[attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
     background-image: url("chrome://browser/skin/downloads/download-glow@2x.png");
   }
 
-  #downloads-button:not([counter])[attention] > #downloads-indicator-anchor >
-  #downloads-indicator-progress-area > #downloads-indicator-counter {
+  #downloads-button:not([counter])[attention] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
     background-image: url("chrome://browser/skin/downloads/download-glow@2x.png");
   }
 }
@@ -182,10 +193,3 @@
 #downloads-button[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
   background-image: linear-gradient(#4b5000, #515700);
 }
-
-toolbar[mode="full"] > #downloads-button[indicator] > .toolbarbutton-text {
-  margin: 2px 0 0;
-  padding: 0;
-  text-align: center;
-  vertical-align: middle;
-}
diff --git a/browser/themes/osx/jar.mn b/browser/themes/osx/jar.mn
index 25b0b822334b577a8a8a1b9513e0392891ca1d75..140a2048036154b442f7cf74988d55db5f1e9300 100644
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -21,7 +21,12 @@ browser.jar:
   skin/classic/browser/actionicon-tab.png
   skin/classic/browser/actionicon-tab@2x.png
 * skin/classic/browser/browser.css                          (browser.css)
+* skin/classic/browser/browser-lightweightTheme.css
   skin/classic/browser/click-to-play-warning-stripes.png
+  skin/classic/browser/customizableui/background-noise-toolbar.png  (customizableui/background-noise-toolbar.png)
+  skin/classic/browser/customizableui/customizeMode-gridTexture.png  (customizableui/customizeMode-gridTexture.png)
+  skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png  (customizableui/customizeMode-separatorHorizontal.png)
+  skin/classic/browser/customizableui/customizeMode-separatorVertical.png  (customizableui/customizeMode-separatorVertical.png)
 * skin/classic/browser/engineManager.css                    (engineManager.css)
   skin/classic/browser/fullscreen-darknoise.png
   skin/classic/browser/Geolocation-16.png
@@ -51,6 +56,16 @@ browser.jar:
   skin/classic/browser/notification-16@2x.png
   skin/classic/browser/notification-64.png
   skin/classic/browser/notification-64@2x.png
+  skin/classic/browser/menuPanel.png
+  skin/classic/browser/menuPanel@2x.png
+  skin/classic/browser/menuPanel-customize.png
+  skin/classic/browser/menuPanel-customize@2x.png
+  skin/classic/browser/menuPanel-exit.png
+  skin/classic/browser/menuPanel-exit@2x.png
+  skin/classic/browser/menuPanel-help.png
+  skin/classic/browser/menuPanel-help@2x.png
+  skin/classic/browser/menuPanel-small.png
+  skin/classic/browser/menuPanel-small@2x.png
   skin/classic/browser/mixed-content-blocked-16.png
   skin/classic/browser/mixed-content-blocked-16@2x.png
   skin/classic/browser/mixed-content-blocked-64.png
@@ -86,6 +101,9 @@ browser.jar:
   skin/classic/browser/Secure-Glyph@2x.png
   skin/classic/browser/slowStartup-16.png
   skin/classic/browser/Toolbar.png
+  skin/classic/browser/Toolbar@2x.png
+  skin/classic/browser/Toolbar-inverted.png
+  skin/classic/browser/Toolbar-inverted@2x.png
   skin/classic/browser/toolbarbutton-dropmarker.png
   skin/classic/browser/urlbar-history-dropmarker.png
   skin/classic/browser/urlbar-history-dropmarker@2x.png
@@ -99,10 +117,10 @@ browser.jar:
   skin/classic/browser/webRTC-shareDevice-64@2x.png
   skin/classic/browser/webRTC-sharingDevice-16.png
   skin/classic/browser/webRTC-sharingDevice-16@2x.png
+* skin/classic/browser/customizableui/panelUIOverlay.css    (customizableui/panelUIOverlay.css)
   skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
   skin/classic/browser/downloads/buttons.png                (downloads/buttons.png)
   skin/classic/browser/downloads/buttons@2x.png             (downloads/buttons@2x.png)
-  skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
   skin/classic/browser/downloads/download-glow.png          (downloads/download-glow.png)
   skin/classic/browser/downloads/download-glow@2x.png       (downloads/download-glow@2x.png)
   skin/classic/browser/downloads/download-notification-finish.png  (downloads/download-notification-finish.png)
@@ -176,39 +194,54 @@ browser.jar:
   skin/classic/browser/social/services-16@2x.png            (social/services-16@2x.png)
   skin/classic/browser/social/services-64.png               (social/services-64.png)
   skin/classic/browser/social/services-64@2x.png            (social/services-64@2x.png)
-  skin/classic/browser/social/share-button.png              (social/share-button.png)
-  skin/classic/browser/social/share-button@2x.png           (social/share-button@2x.png)
-  skin/classic/browser/social/share-button-active.png       (social/share-button-active.png)
-  skin/classic/browser/social/share-button-active@2x.png    (social/share-button-active@2x.png)
   skin/classic/browser/social/chat-icons.png                             (social/chat-icons.png)
   skin/classic/browser/social/chat-icons@2x.png                          (social/chat-icons@2x.png)
   skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon.png             (tabbrowser/alltabs-box-bkgnd-icon.png)
+  skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon-inverted.png    (tabbrowser/alltabs-box-bkgnd-icon-inverted.png)
+  skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png (tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png)
   skin/classic/browser/tabbrowser/newtab.png                             (tabbrowser/newtab.png)
   skin/classic/browser/tabbrowser/newtab@2x.png                          (tabbrowser/newtab@2x.png)
+  skin/classic/browser/tabbrowser/newtab-inverted.png                    (tabbrowser/newtab-inverted.png)
+  skin/classic/browser/tabbrowser/newtab-inverted@2x.png                 (tabbrowser/newtab-inverted@2x.png)
   skin/classic/browser/tabbrowser/connecting.png                         (tabbrowser/connecting.png)
   skin/classic/browser/tabbrowser/connecting@2x.png                      (tabbrowser/connecting@2x.png)
   skin/classic/browser/tabbrowser/loading.png                            (tabbrowser/loading.png)
   skin/classic/browser/tabbrowser/loading@2x.png                         (tabbrowser/loading@2x.png)
+  skin/classic/browser/tabbrowser/tab-active-middle.png                  (tabbrowser/tab-active-middle.png)
+  skin/classic/browser/tabbrowser/tab-active-middle@2x.png               (tabbrowser/tab-active-middle@2x.png)
   skin/classic/browser/tabbrowser/tab-arrow-left.png                     (tabbrowser/tab-arrow-left.png)
   skin/classic/browser/tabbrowser/tab-arrow-left@2x.png                  (tabbrowser/tab-arrow-left@2x.png)
+  skin/classic/browser/tabbrowser/tab-arrow-left-inverted.png            (tabbrowser/tab-arrow-left-inverted.png)
+  skin/classic/browser/tabbrowser/tab-arrow-left-inverted@2x.png         (tabbrowser/tab-arrow-left-inverted@2x.png)
   skin/classic/browser/tabbrowser/tab-arrow-right.png                    (tabbrowser/tab-arrow-right.png)
   skin/classic/browser/tabbrowser/tab-arrow-right@2x.png                 (tabbrowser/tab-arrow-right@2x.png)
+  skin/classic/browser/tabbrowser/tab-arrow-right-inverted.png           (tabbrowser/tab-arrow-right-inverted.png)
+  skin/classic/browser/tabbrowser/tab-arrow-right-inverted@2x.png        (tabbrowser/tab-arrow-right-inverted@2x.png)
+  skin/classic/browser/tabbrowser/tab-background-end.png                 (tabbrowser/tab-background-end.png)
+  skin/classic/browser/tabbrowser/tab-background-end@2x.png              (tabbrowser/tab-background-end@2x.png)
+  skin/classic/browser/tabbrowser/tab-background-middle.png              (tabbrowser/tab-background-middle.png)
+  skin/classic/browser/tabbrowser/tab-background-middle@2x.png           (tabbrowser/tab-background-middle@2x.png)
+  skin/classic/browser/tabbrowser/tab-background-start.png               (tabbrowser/tab-background-start.png)
+  skin/classic/browser/tabbrowser/tab-background-start@2x.png            (tabbrowser/tab-background-start@2x.png)
+
+# NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in
+#       Makefile.in with a non-default marker of "%" and the result of that gets packaged.
+  skin/classic/browser/tabbrowser/tab-selected-end.svg                   (tab-selected-end.svg)
+  skin/classic/browser/tabbrowser/tab-selected-start.svg                 (tab-selected-start.svg)
+
+  skin/classic/browser/tabbrowser/tab-stroke-end.png                     (tabbrowser/tab-stroke-end.png)
+  skin/classic/browser/tabbrowser/tab-stroke-end@2x.png                  (tabbrowser/tab-stroke-end@2x.png)
+  skin/classic/browser/tabbrowser/tab-stroke-start.png                   (tabbrowser/tab-stroke-start.png)
+  skin/classic/browser/tabbrowser/tab-stroke-start@2x.png                (tabbrowser/tab-stroke-start@2x.png)
   skin/classic/browser/tabbrowser/tabbar-bottom-bg-active.png            (tabbrowser/tabbar-bottom-bg-active.png)
   skin/classic/browser/tabbrowser/tabbar-bottom-bg-inactive.png          (tabbrowser/tabbar-bottom-bg-inactive.png)
-  skin/classic/browser/tabbrowser/tab-bottom-normal-active.png           (tabbrowser/tab-bottom-normal-active.png)
-  skin/classic/browser/tabbrowser/tab-bottom-hover-active.png            (tabbrowser/tab-bottom-hover-active.png)
-  skin/classic/browser/tabbrowser/tab-bottom-selected-active.png         (tabbrowser/tab-bottom-selected-active.png)
   skin/classic/browser/tabbrowser/tabbar-top-bg-active.png               (tabbrowser/tabbar-top-bg-active.png)
   skin/classic/browser/tabbrowser/tabbar-top-bg-inactive.png             (tabbrowser/tabbar-top-bg-inactive.png)
-  skin/classic/browser/tabbrowser/tab-top-normal-active.png              (tabbrowser/tab-top-normal-active.png)
-  skin/classic/browser/tabbrowser/tab-top-normal-active@2x.png           (tabbrowser/tab-top-normal-active@2x.png)
-  skin/classic/browser/tabbrowser/tab-top-hover-active.png               (tabbrowser/tab-top-hover-active.png)
-  skin/classic/browser/tabbrowser/tab-top-hover-active@2x.png            (tabbrowser/tab-top-hover-active@2x.png)
-  skin/classic/browser/tabbrowser/tab-top-selected-active.png            (tabbrowser/tab-top-selected-active.png)
-  skin/classic/browser/tabbrowser/tab-top-selected-active@2x.png         (tabbrowser/tab-top-selected-active@2x.png)
   skin/classic/browser/tabbrowser/tab-overflow-border.png                (tabbrowser/tab-overflow-border.png)
   skin/classic/browser/tabbrowser/tabDragIndicator.png                   (tabbrowser/tabDragIndicator.png)
   skin/classic/browser/tabbrowser/tabDragIndicator@2x.png                (tabbrowser/tabDragIndicator@2x.png)
+  skin/classic/browser/tabbrowser/tab-separator.png                      (tabbrowser/tab-separator.png)
+  skin/classic/browser/tabbrowser/tab-separator@2x.png                   (tabbrowser/tab-separator@2x.png)
   skin/classic/browser/tabview/close.png                    (tabview/close.png)
   skin/classic/browser/tabview/edit-light.png               (tabview/edit-light.png)
   skin/classic/browser/tabview/search.png                   (tabview/search.png)
@@ -349,8 +382,7 @@ browser.jar:
 #endif
   skin/classic/browser/lion/keyhole-circle.png              (keyhole-circle-lion.png)
   skin/classic/browser/keyhole-circle@2x.png                (keyhole-circle-lion@2x.png)
-  skin/classic/browser/lion/Toolbar.png                     (Toolbar-lion.png)
-  skin/classic/browser/Toolbar@2x.png                       (Toolbar-lion@2x.png)
+  skin/classic/browser/Toolbar-background-noise.png         (Toolbar-background-noise.png)
   skin/classic/browser/lion/toolbarbutton-dropmarker.png    (toolbarbutton-dropmarker-lion.png)
   skin/classic/browser/toolbarbutton-dropmarker@2x.png      (toolbarbutton-dropmarker-lion@2x.png)
   skin/classic/browser/lion/tabbrowser/alltabs-box-bkgnd-icon.png      (tabbrowser/alltabs-box-bkgnd-icon-lion.png)
@@ -373,7 +405,6 @@ browser.jar:
   skin/classic/browser/devtools/tooltip/arrow-vertical-light@2x.png   (../shared/devtools/tooltip/arrow-vertical-light@2x.png)
 
 % override chrome://browser/skin/keyhole-circle.png                        chrome://browser/skin/lion/keyhole-circle.png                           os=Darwin osversion>=10.7
-% override chrome://browser/skin/Toolbar.png                               chrome://browser/skin/lion/Toolbar.png                                  os=Darwin osversion>=10.7
 % override chrome://browser/skin/toolbarbutton-dropmarker.png              chrome://browser/skin/lion/toolbarbutton-dropmarker.png                 os=Darwin osversion>=10.7
 % override chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon.png     chrome://browser/skin/lion/tabbrowser/alltabs-box-bkgnd-icon.png        os=Darwin osversion>=10.7
 % override chrome://browser/skin/tabview/tabview.png                       chrome://browser/skin/lion/tabview/tabview.png                          os=Darwin osversion>=10.7
diff --git a/browser/themes/osx/menuPanel-customize.png b/browser/themes/osx/menuPanel-customize.png
new file mode 100644
index 0000000000000000000000000000000000000000..e0b0a70a3b82a18c974bd1bc5f1dff863405dd61
Binary files /dev/null and b/browser/themes/osx/menuPanel-customize.png differ
diff --git a/browser/themes/osx/menuPanel-customize@2x.png b/browser/themes/osx/menuPanel-customize@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..aba481aeb49b48bfc317bdeaeb00ea4048869533
Binary files /dev/null and b/browser/themes/osx/menuPanel-customize@2x.png differ
diff --git a/browser/themes/osx/menuPanel-exit.png b/browser/themes/osx/menuPanel-exit.png
new file mode 100644
index 0000000000000000000000000000000000000000..e230b9c1bc704b75416a472f9a1fe53faf3c7d70
Binary files /dev/null and b/browser/themes/osx/menuPanel-exit.png differ
diff --git a/browser/themes/osx/menuPanel-exit@2x.png b/browser/themes/osx/menuPanel-exit@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..81c901bee74a1042ff4227b96215a911523b477e
Binary files /dev/null and b/browser/themes/osx/menuPanel-exit@2x.png differ
diff --git a/browser/themes/osx/menuPanel-help.png b/browser/themes/osx/menuPanel-help.png
new file mode 100644
index 0000000000000000000000000000000000000000..1f6fecc54ad049dd127de9b37a99546942497c46
Binary files /dev/null and b/browser/themes/osx/menuPanel-help.png differ
diff --git a/browser/themes/osx/menuPanel-help@2x.png b/browser/themes/osx/menuPanel-help@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..4e745644dbea34c8d8e65690a65121f1b7f58b12
Binary files /dev/null and b/browser/themes/osx/menuPanel-help@2x.png differ
diff --git a/browser/themes/osx/menuPanel-small.png b/browser/themes/osx/menuPanel-small.png
new file mode 100644
index 0000000000000000000000000000000000000000..ecd3b7f08aa58358ae1f8b44c124582c1bea3ecd
Binary files /dev/null and b/browser/themes/osx/menuPanel-small.png differ
diff --git a/browser/themes/osx/menuPanel-small@2x.png b/browser/themes/osx/menuPanel-small@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..e41e6f499df1ae2b5cb02ec5c42eaa9042211ce0
Binary files /dev/null and b/browser/themes/osx/menuPanel-small@2x.png differ
diff --git a/browser/themes/osx/menuPanel.png b/browser/themes/osx/menuPanel.png
new file mode 100644
index 0000000000000000000000000000000000000000..4af2c8e2dac31ac9f369ebad5551b6577eda97c9
Binary files /dev/null and b/browser/themes/osx/menuPanel.png differ
diff --git a/browser/themes/osx/menuPanel@2x.png b/browser/themes/osx/menuPanel@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..764048a29bdec15883be9191585ed89f8bcb1684
Binary files /dev/null and b/browser/themes/osx/menuPanel@2x.png differ
diff --git a/browser/themes/osx/newtab/newTab.css b/browser/themes/osx/newtab/newTab.css
index cefab8a42fc36f672069213f9b922a346841130d..0786cfe630d66df6536bea546e690dca836595d3 100644
--- a/browser/themes/osx/newtab/newTab.css
+++ b/browser/themes/osx/newtab/newTab.css
@@ -51,19 +51,9 @@
 #newtab-undo-close-button {
   padding: 0;
   border: none;
-  list-style-image: url("chrome://global/skin/icons/close.png");
-  -moz-image-region: rect(0, 16px, 16px, 0);
   -moz-user-focus: normal;
 }
 
-#newtab-undo-close-button:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-#newtab-undo-close-button:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
 #newtab-undo-close-button > .toolbarbutton-text {
   display: none;
 }
diff --git a/browser/themes/osx/shared.inc b/browser/themes/osx/shared.inc
index 2e8a8f269f46273068957c24c535d52c6c430817..cf095a5fce58dfd8a24493ebfaaf348084e47143 100644
--- a/browser/themes/osx/shared.inc
+++ b/browser/themes/osx/shared.inc
@@ -1,6 +1,12 @@
 %include ../../../toolkit/themes/osx/global/shared.inc
 %include ../shared/browser.inc
 
+%filter substitution
+
+%define fgTabTexture linear-gradient(transparent, transparent 2px, hsla(0,0%,100%,0.6) 2px, hsla(0,0%,100%,0.6) 3px, hsl(0,0%,99%) 3px, hsl(0,0%,93%))
+%define toolbarColorLWT rgba(253,253,253,0.45)
+%define fgTabTextureLWT linear-gradient(transparent, transparent 2px, rgba(254,254,254,0.72) 2px, @toolbarColorLWT@)
+%define fgTabBackgroundColor transparent
 %define hudButton -moz-appearance: none; color: #434343; border-radius: 4px; border: 1px solid #b5b5b5; background: linear-gradient(#fff, #f2f2f2); box-shadow: inset 0 1px rgba(255,255,255,.8), inset 0 0 1px rgba(255,255, 255,.25), 0 1px rgba(255,255,255,.3); background-clip: padding-box; background-origin: padding-box; padding: 2px 6px;
 %define hudButtonPressed box-shadow: inset 0 1px 4px -3px #000, 0 1px rgba(255,255,255,.3);
 %define hudButtonFocused box-shadow: 0 0 1px -moz-mac-focusring inset, 0 0 4px 1px -moz-mac-focusring, 0 0 2px 1px -moz-mac-focusring;
diff --git a/browser/themes/osx/social/share-button-active.png b/browser/themes/osx/social/share-button-active.png
deleted file mode 100644
index 7df438db014c265c35da304c4a846f5e34c46e4b..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/social/share-button-active.png and /dev/null differ
diff --git a/browser/themes/osx/social/share-button-active@2x.png b/browser/themes/osx/social/share-button-active@2x.png
deleted file mode 100644
index 6872dff7b7c4801a39cb9b48b4f352b034271dc0..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/social/share-button-active@2x.png and /dev/null differ
diff --git a/browser/themes/osx/social/share-button.png b/browser/themes/osx/social/share-button.png
deleted file mode 100644
index c5298c143eaaa74773f5066766f923ef076a74ca..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/social/share-button.png and /dev/null differ
diff --git a/browser/themes/osx/social/share-button@2x.png b/browser/themes/osx/social/share-button@2x.png
deleted file mode 100644
index 4545a276dc59f0833b20a8cbb521569b757117fc..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/social/share-button@2x.png and /dev/null differ
diff --git a/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted.png b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted.png
new file mode 100644
index 0000000000000000000000000000000000000000..295b4ad74e62c9d7fb816500a62a1d1e6295f42d
Binary files /dev/null and b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted.png differ
diff --git a/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..23889d7cc5f7cdfa78e750e93a41b2caf9daac46
Binary files /dev/null and b/browser/themes/osx/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png differ
diff --git a/browser/themes/osx/tabbrowser/newtab-inverted.png b/browser/themes/osx/tabbrowser/newtab-inverted.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d29c2cbea688fdf44ba7d1617bd9edd8a04a4c4
Binary files /dev/null and b/browser/themes/osx/tabbrowser/newtab-inverted.png differ
diff --git a/browser/themes/osx/tabbrowser/newtab-inverted@2x.png b/browser/themes/osx/tabbrowser/newtab-inverted@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..6feba0e83eaad385ae512fc611187c10dec6e9d4
Binary files /dev/null and b/browser/themes/osx/tabbrowser/newtab-inverted@2x.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-active-middle.png b/browser/themes/osx/tabbrowser/tab-active-middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3e5e18ba3ceddcf098a5b98a5f40c784a7e3d52
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-active-middle.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-active-middle@2x.png b/browser/themes/osx/tabbrowser/tab-active-middle@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..6cdc4472e71aeb715582a8eeb03bd471e61514e2
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-active-middle@2x.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-arrow-left-inverted.png b/browser/themes/osx/tabbrowser/tab-arrow-left-inverted.png
new file mode 100644
index 0000000000000000000000000000000000000000..b0826024d787c0d6fad3b0672216e88d4a8e1089
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-arrow-left-inverted.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-arrow-left-inverted@2x.png b/browser/themes/osx/tabbrowser/tab-arrow-left-inverted@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..4ca8ec0baedeb9c40240ad2cf8c9f19bf6cb870b
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-arrow-left-inverted@2x.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-arrow-right-inverted.png b/browser/themes/osx/tabbrowser/tab-arrow-right-inverted.png
new file mode 100644
index 0000000000000000000000000000000000000000..0cd8f37a6fb7dbb22ef7062a01d194348cf4e216
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-arrow-right-inverted.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-arrow-right-inverted@2x.png b/browser/themes/osx/tabbrowser/tab-arrow-right-inverted@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..e4ab8cbaa24cb96c0117ba55655c2fb41f6f13b6
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-arrow-right-inverted@2x.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-background-end.png b/browser/themes/osx/tabbrowser/tab-background-end.png
new file mode 100644
index 0000000000000000000000000000000000000000..2e515a39efeaafc71c8ee00bc29baa7ca952ce0f
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-end.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-background-end@2x.png b/browser/themes/osx/tabbrowser/tab-background-end@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..18dba96930805a30ca1af7dd5a30dea29b9e1063
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-end@2x.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-background-middle.png b/browser/themes/osx/tabbrowser/tab-background-middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..addb64b13f422a34d6b87e4e75488f9fa2e35ba3
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-middle.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-background-middle@2x.png b/browser/themes/osx/tabbrowser/tab-background-middle@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..41eba94af8863a032df6dd6a170a511fe06c1cf0
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-middle@2x.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-background-start.png b/browser/themes/osx/tabbrowser/tab-background-start.png
new file mode 100644
index 0000000000000000000000000000000000000000..243bf0099ffe7760843fc75b98d1029d9c9efbef
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-start.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-background-start@2x.png b/browser/themes/osx/tabbrowser/tab-background-start@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..86403921de9c7a9543879e3a4a2963e3d472e26b
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-background-start@2x.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-bottom-hover-active.png b/browser/themes/osx/tabbrowser/tab-bottom-hover-active.png
deleted file mode 100644
index a5fdaba4bb0f223984253e0839b70b9f81f0e7f2..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/tabbrowser/tab-bottom-hover-active.png and /dev/null differ
diff --git a/browser/themes/osx/tabbrowser/tab-bottom-normal-active.png b/browser/themes/osx/tabbrowser/tab-bottom-normal-active.png
deleted file mode 100644
index 1a0dceea376d576199d3c6d4bcf8ac974104c4c3..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/tabbrowser/tab-bottom-normal-active.png and /dev/null differ
diff --git a/browser/themes/osx/tabbrowser/tab-bottom-selected-active.png b/browser/themes/osx/tabbrowser/tab-bottom-selected-active.png
deleted file mode 100644
index 0596cb28dd471f83629de71d56cfd8b348e4d9c1..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/tabbrowser/tab-bottom-selected-active.png and /dev/null differ
diff --git a/browser/themes/osx/tabbrowser/tab-separator.png b/browser/themes/osx/tabbrowser/tab-separator.png
new file mode 100644
index 0000000000000000000000000000000000000000..b643bfc6f67da9c4934f05510b5cbd296e901bcd
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-separator.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-separator@2x.png b/browser/themes/osx/tabbrowser/tab-separator@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..11cfca4c149871587aec2e18b71fd6ef3d49823a
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-separator@2x.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-stroke-end.png b/browser/themes/osx/tabbrowser/tab-stroke-end.png
new file mode 100755
index 0000000000000000000000000000000000000000..099978580391777f4fdd196fc9aa160ebf4123a7
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-stroke-end.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-stroke-end@2x.png b/browser/themes/osx/tabbrowser/tab-stroke-end@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..d321ca579016cf5fe8b0d4be6bbb42e3d2216fa1
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-stroke-end@2x.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-stroke-start.png b/browser/themes/osx/tabbrowser/tab-stroke-start.png
new file mode 100755
index 0000000000000000000000000000000000000000..e5a7b5ee9aecb73410b5cacdd4951b2520b54bca
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-stroke-start.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-stroke-start@2x.png b/browser/themes/osx/tabbrowser/tab-stroke-start@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..64449115cc9ffbcccacffbb3219467fd81086f0d
Binary files /dev/null and b/browser/themes/osx/tabbrowser/tab-stroke-start@2x.png differ
diff --git a/browser/themes/osx/tabbrowser/tab-top-hover-active.png b/browser/themes/osx/tabbrowser/tab-top-hover-active.png
deleted file mode 100644
index f41b253d0bce22c49f06bba7bdf1934813ff3562..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/tabbrowser/tab-top-hover-active.png and /dev/null differ
diff --git a/browser/themes/osx/tabbrowser/tab-top-hover-active@2x.png b/browser/themes/osx/tabbrowser/tab-top-hover-active@2x.png
deleted file mode 100644
index a8215a283d57a01334bd53c4a864ad373cfc4cd8..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/tabbrowser/tab-top-hover-active@2x.png and /dev/null differ
diff --git a/browser/themes/osx/tabbrowser/tab-top-normal-active.png b/browser/themes/osx/tabbrowser/tab-top-normal-active.png
deleted file mode 100644
index 5987a2fe32d7e26d7b0ae3f80625e69ae9b7d45f..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/tabbrowser/tab-top-normal-active.png and /dev/null differ
diff --git a/browser/themes/osx/tabbrowser/tab-top-normal-active@2x.png b/browser/themes/osx/tabbrowser/tab-top-normal-active@2x.png
deleted file mode 100644
index 658b291d3940b0a53d321f54ff86e2ade53cf82f..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/tabbrowser/tab-top-normal-active@2x.png and /dev/null differ
diff --git a/browser/themes/osx/tabbrowser/tab-top-selected-active.png b/browser/themes/osx/tabbrowser/tab-top-selected-active.png
deleted file mode 100644
index 930e76588fed21ab53cd454f1e7f0d82989b814b..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/tabbrowser/tab-top-selected-active.png and /dev/null differ
diff --git a/browser/themes/osx/tabbrowser/tab-top-selected-active@2x.png b/browser/themes/osx/tabbrowser/tab-top-selected-active@2x.png
deleted file mode 100644
index 7de41e77b273e66b7578c11c96efbe054b1655fc..0000000000000000000000000000000000000000
Binary files a/browser/themes/osx/tabbrowser/tab-top-selected-active@2x.png and /dev/null differ
diff --git a/browser/themes/shared/browser.inc b/browser/themes/shared/browser.inc
index 794b6d5c130f508b2a45f9f31b87ffe362d7f495..429ae613c86eb42b0a3be9881e7fea8edd6e0e57 100644
--- a/browser/themes/shared/browser.inc
+++ b/browser/themes/shared/browser.inc
@@ -1,3 +1,4 @@
 %filter substitution
 
-%define primaryToolbarButtons #back-button, #forward-button, #reload-button, #stop-button, #home-button, #print-button, #downloads-button, #history-button, #bookmarks-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-in-button, #sync-button, #feed-button, #alltabs-button, #tabview-button, #webrtc-status-button
+%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-reset-button, #zoom-in-button, #sync-button, #feed-button, #tabview-button, #webrtc-status-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button
+%define inAnyPanel :-moz-any(:not([cui-areatype="toolbar"]),.overflowedItem)
diff --git a/browser/themes/shared/customizableui/customizeMode.inc.css b/browser/themes/shared/customizableui/customizeMode.inc.css
new file mode 100644
index 0000000000000000000000000000000000000000..5c05f5176e779cc437c99e6184ff079dc738ebeb
--- /dev/null
+++ b/browser/themes/shared/customizableui/customizeMode.inc.css
@@ -0,0 +1,201 @@
+/* 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/. */
+
+/* Customization mode */
+
+#tab-view-deck {
+  transition-property: padding;
+  transition-duration: 150ms;
+  transition-timing-function: ease-out;
+}
+
+#tab-view-deck[fastcustomizeanimation] {
+  transition-duration: 1ms;
+  transition-timing-function: linear;
+}
+
+#nav-bar[customize-entered] > #nav-bar-customization-target {
+  margin: 1px 3px;
+}
+
+#nav-bar[customize-entered] > #nav-bar-customization-target,
+#PanelUI-contents > .panel-customization-placeholder {
+  outline: 1px dashed transparent;
+}
+
+#main-window[customizing-movingItem] #nav-bar-customization-target,
+#main-window[customizing-movingItem] .panel-customization-placeholder {
+  outline-color: #bbb;
+}
+
+#PanelUI-contents > .panel-customization-placeholder {
+  cursor: auto;
+  outline-offset: -5px;
+}
+
+#PanelUI-contents > .panel-customization-placeholder > .panel-customization-placeholder-child {
+  list-style-image: none;
+}
+
+#customization-panelHolder {
+  overflow-y: hidden;
+}
+
+#customization-panelWrapper,
+#customization-panelWrapper > .panel-arrowcontent {
+  -moz-box-flex: 1;
+}
+
+#customization-panelHolder > #PanelUI-mainView {
+  display: flex;
+  flex-direction: column;
+  /* Hack alert - by manually setting the preferred height to 0, we convince
+     #PanelUI-mainView to shrink when the window gets smaller in customization
+     mode. Not sure why that is - might have to do with our intermingling of
+     XUL flex, and CSS3 Flexbox. */
+  height: 0;
+}
+
+#customization-panelHolder > #PanelUI-mainView > #PanelUI-contents-scroller {
+  display: flex;
+  flex: auto;
+  flex-direction: column;
+}
+
+#main-window[customize-entered] .customization-target {
+  min-width: 100px;
+  padding-left: 10px;
+  padding-right: 10px;
+}
+
+#customization-container {
+  background-color: rgb(247,247,247);
+}
+
+#customization-palette-container {
+  padding: 25px;
+}
+
+#customization-header {
+  font-size: 1.5em;
+  line-height: 1.5em;
+  color: rgb(64,100,128);
+  font-weight: lighter;
+  margin-bottom: 1em;
+}
+
+#customization-panel-container {
+  padding: 15px 25px 25px;
+  background-image: url("chrome://browser/skin/customizableui/customizeMode-separatorHorizontal.png"),
+                    url("chrome://browser/skin/customizableui/customizeMode-separatorVertical.png"),
+                    url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"),
+                    url("chrome://browser/skin/customizableui/background-noise-toolbar.png"),
+                    linear-gradient(to bottom, #3e86ce, #3878ba);
+  background-position: center top, left center, left top, left top, left top;
+  background-repeat: no-repeat, no-repeat, repeat, repeat, no-repeat;
+  background-size: auto 12px, 12px 100%, auto, auto, auto;
+  background-attachment: scroll, scroll, fixed, fixed, scroll;
+  overflow-y: auto;
+}
+
+#customization-panelWrapper > .panel-arrowcontent {
+  padding: 0 !important;
+}
+
+toolbarpaletteitem {
+  transition: background-color, border-color, box-shadow, border-width;
+  transition-duration: 10ms, 10ms, 10ms, 250ms;
+  transition-timing-function: linear, linear, linear, ease-in-out;
+}
+
+toolbarpaletteitem[mousedown] {
+  box-shadow: inset 0 0 3px hsl(204,100%,40%);
+  cursor: -moz-grabbing;
+  opacity: 0.8;
+}
+
+toolbarpaletteitem > toolbarbutton > .toolbarbutton-icon {
+  transition: transform 50ms ease-in-out;
+}
+
+toolbarpaletteitem[mousedown] > toolbarbutton > .toolbarbutton-icon {
+  transform: scale(1.1);
+}
+
+/* Override the toolkit styling for items being dragged over. */
+toolbarpaletteitem[place="toolbar"] {
+  border-left-width: 0;
+  border-right-width: 0;
+  margin-right: 0;
+  margin-left: 0;
+}
+
+toolbarpaletteitem[dragover] {
+  border-left-color: transparent;
+  border-right-color: transparent;
+}
+
+#customization-palette:not([hidden]) {
+  display: block;
+  overflow: auto;
+  min-height: 3em;
+  margin-bottom: 25px;
+}
+
+toolbarpaletteitem[place="palette"] {
+  width: 110px;
+  height: 94px;
+  overflow: hidden;
+  display: inline-block;
+}
+
+toolbarpaletteitem[place="palette"][hidden] {
+  display: none;
+}
+
+#customization-palette > #wrapper-edit-controls,
+#customization-palette > #wrapper-zoom-controls {
+  width: 225px;
+}
+
+#customization-palette .toolbarpaletteitem-box {
+  -moz-box-pack: center;
+  -moz-box-flex: 1;
+  width: 110px;
+  max-width: 110px;
+}
+
+#wrapper-edit-controls[place="palette"] > .toolbarpaletteitem-box,
+#wrapper-zoom-controls[place="palette"] > .toolbarpaletteitem-box {
+  width: 225px;
+  max-width: 225px;
+}
+
+#wrapper-edit-controls[place="palette"] > #edit-controls > toolbarbutton,
+#wrapper-zoom-controls[place="palette"] > #zoom-controls > toolbarbutton {
+  margin-left: 0;
+  margin-right: 0;
+  max-width: 70px;
+  min-width: 70px;
+  max-height: 24px;
+  height: 24px;
+  margin-top: 24px;
+}
+
+#wrapper-edit-controls[place="palette"] > #edit-controls > toolbarbutton > .toolbarbutton-text,
+#wrapper-zoom-controls[place="palette"] > #zoom-controls > #zoom-reset-button > .toolbarbutton-text {
+  display: inline;
+}
+
+#wrapper-edit-controls[place="palette"] > #edit-controls > toolbarbutton > .toolbarbutton-icon,
+#wrapper-zoom-controls[place="palette"] > #zoom-controls > toolbarbutton > .toolbarbutton-icon {
+  margin: 0;
+  -moz-margin-start: 5px;
+}
+
+#customization-palette > toolbarpaletteitem > label {
+  text-align: center;
+  margin-left: 0;
+  margin-right: 0;
+}
diff --git a/browser/themes/shared/customizableui/panelUIOverlay.inc.css b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
new file mode 100644
index 0000000000000000000000000000000000000000..7b04d642c2512fd370cbecb8358db65a3738acb0
--- /dev/null
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -0,0 +1,549 @@
+/* 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/. */
+
+%filter substitution
+%define menuPanelWidth 21em
+%define exitSubviewGutterWidth 38px
+%define buttonStateHover :not(:-moz-any([disabled],[checked="true"],[open],:active)):hover
+%define buttonStateActive :not([disabled]):-moz-any([open],[checked="true"],:hover:active)
+
+%include ../browser.inc
+
+.panel-subviews {
+  background-image: linear-gradient(to bottom, white 1px, rgba(255, 255, 255, 0) 15px);
+  background-color: -moz-dialog;
+  box-shadow: -1px 0px 0px rgba(0, 0, 0, 0.2), -1px 0px 2px rgba(0, 0, 0, 0.1), 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
+  -moz-margin-start: @exitSubviewGutterWidth@;
+}
+
+.panel-subviews:-moz-locale-dir(rtl) {
+  box-shadow: 1px 0px 0px rgba(0, 0, 0, 0.2), 1px 0px 2px rgba(0, 0, 0, 0.1), -1px 0px 0px rgba(255, 255, 255, 0.2) inset;
+}
+
+.panel-viewstack[viewtype="main"] > .panel-subviews {
+  transform: translateX(@menuPanelWidth@);
+}
+
+.panel-viewstack[viewtype="main"] > .panel-subviews:-moz-locale-dir(rtl) {
+  transform: translateX(-@menuPanelWidth@);
+}
+
+.panel-viewstack:not([viewtype="main"]) > .panel-mainview > #PanelUI-mainView {
+  -moz-box-flex: 1;
+}
+
+#PanelUI-mainView {
+  display: flex;
+  flex-direction: column;
+}
+
+#app-extension-point-end > #PanelUI-menu-button {
+  padding: 2px 5px;
+}
+#app-extension-point-end > #PanelUI-menu-button .toolbarbutton-text {
+  display: none;
+}
+#app-extension-point-end > #PanelUI-menu-button .toolbarbutton-icon {
+  margin: 0;
+}
+
+#PanelUI-popup > arrowscrollbox > autorepeatbutton {
+  display: none;
+}
+#PanelUI-popup > arrowscrollbox > scrollbox {
+  overflow: visible;
+}
+
+#PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent {
+  overflow: hidden;
+  padding: 0;
+  box-shadow: none;
+}
+
+#PanelUI-contents {
+  padding: .5em 0;
+}
+
+toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item) > .toolbarbutton-text,
+#bookmarks-menu-button > toolbarbutton > .toolbarbutton-text,
+#PanelUI-contents > toolbarpaletteitem > toolbaritem > toolbarbutton > .toolbarbutton-text,
+#PanelUI-contents > toolbaritem > toolbarbutton > .toolbarbutton-text,
+#PanelUI-contents > toolbarpaletteitem > toolbarbutton > .toolbarbutton-text,
+#PanelUI-contents > toolbarbutton > .toolbarbutton-text {
+  font-size: 10px;
+}
+
+#wrapper-edit-controls:-moz-any([place="palette"],[place="panel"]) > #edit-controls,
+#wrapper-zoom-controls:-moz-any([place="palette"],[place="panel"]) > #zoom-controls {
+  -moz-margin-start: 0;
+}
+
+#PanelUI-contents,
+.panel-mainview:not([panelid="PanelUI-popup"]) {
+  max-width: @menuPanelWidth@;
+}
+
+panelview:not([mainview]) .toolbarbutton-text,
+#customizationui-widget-panel toolbarbutton > .toolbarbutton-text {
+  text-align: start;
+  -moz-padding-start: 8px;
+  display: -moz-box;
+}
+
+#PanelUI-contents {
+  display: block;
+  flex: auto;
+  margin-left: auto;
+  margin-right: auto;
+  max-width: @menuPanelWidth@;
+}
+
+#PanelUI-contents-scroller {
+  overflow-y: auto;
+  overflow-x: hidden;
+  width: @menuPanelWidth@;
+  padding-left: 5px;
+  padding-right: 5px;
+  flex: auto;
+}
+
+#edit-controls@inAnyPanel@ > toolbarbutton > .toolbarbutton-icon,
+#zoom-controls@inAnyPanel@ > toolbarbutton > .toolbarbutton-icon {
+  min-width: 0;
+  min-height: 0;
+  margin: 0;
+}
+
+toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item),
+#PanelUI-contents toolbarbutton,
+toolbarpaletteitem[place="panel"] > toolbarbutton,
+toolbarpaletteitem[place="palette"] > toolbarbutton,
+toolbarpaletteitem[place="panel"] > toolbaritem > toolbarbutton,
+toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton,
+.panel-customization-placeholder {
+  -moz-appearance: none;
+  -moz-box-orient: vertical;
+  min-width: 7em;
+  max-width: 7em;
+  height: 6em;
+  max-height: 6em;
+}
+
+.panel-customization-placeholder[expand],
+.panel-customization-placeholder[contract] {
+  transition-property: width;
+  transition-duration: 170ms;
+  transition-delay: 20ms;
+  transition-timing-function: ease-in-out;
+  min-width: 0;
+  max-width: none;
+}
+
+#edit-controls:not([cui-areatype="toolbar"]) > toolbarbutton,
+#zoom-controls:not([cui-areatype="toolbar"]) > toolbarbutton {
+  -moz-box-orient: horizontal;
+  min-width: 7em;
+}
+
+#PanelUI-contents > #edit-controls > toolbarbutton,
+#PanelUI-contents > #wrapper-edit-controls > #edit-controls > toolbarbutton,
+#PanelUI-contents > #zoom-controls > toolbarbutton,
+#PanelUI-contents > #wrapper-zoom-controls > #zoom-controls > toolbarbutton {
+  max-width: none;
+  max-height: none;
+  height: auto;
+}
+
+#widget-overflow-list > #edit-controls > toolbarbutton,
+#widget-overflow-list > #zoom-controls > toolbarbutton {
+  -moz-box-orient: horizontal;
+  -moz-box-align: start;
+  max-height: none;
+  height: auto;
+  padding-left: .5em;
+  padding-right: .5em;
+}
+
+.panel-wide-item.overflowedItem,
+.panel-wide-item[cui-areatype="menu-panel"] {
+  -moz-box-align: stretch;
+  padding: .5em 0 .5em;
+}
+
+.panel-combined-button[disabled] > .toolbarbutton-icon {
+  opacity: .5;
+}
+
+toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"] {
+  width: 7em;
+  margin: 0 !important;
+}
+
+toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-widget) {
+  -moz-box-align: center;
+  -moz-box-pack: center;
+}
+
+toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"] > iframe {
+  margin: calc(5em / 12) auto;
+}
+
+toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-item) > .toolbarbutton-text {
+  text-align: center;
+}
+
+.panel-customization-placeholder-child > .toolbarbutton-icon,
+#bookmarks-menu-button[cui-areatype="menu-panel"] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
+toolbarbutton[cui-areatype="menu-panel"] > .toolbarbutton-icon,
+toolbaritem[cui-areatype="menu-panel"] > toolbarbutton > .toolbarbutton-icon,
+toolbarpaletteitem[place="palette"] > #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
+toolbarpaletteitem[place="palette"] > toolbarbutton > .toolbarbutton-icon,
+toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton > .toolbarbutton-icon {
+  min-width: calc(8em / 3);
+  min-height: calc(8em / 3);
+  margin: calc(5em / 12);
+}
+
+toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
+  -moz-box-flex: 1;
+}
+
+#edit-controls@inAnyPanel@ > #copy-button,
+#zoom-controls@inAnyPanel@ > #zoom-reset-button {
+  border-left: none;
+  border-right: none;
+  border-radius: 0;
+}
+
+#zoom-in-button > .toolbarbutton-text,
+#zoom-out-button > .toolbarbutton-text,
+#zoom-reset-button > .toolbarbutton-icon {
+  display: none;
+}
+
+#PanelUI-footer {
+  display: flex;
+  background-color: rgba(0, 0, 0, 0.05);
+  border-top: 1px solid rgba(0,0,0,.1);
+  padding: 0;
+  margin: 0;
+  min-height: 4em;
+}
+
+#PanelUI-help,
+#PanelUI-customize,
+#PanelUI-quit {
+  margin: -1px 0 0;
+  padding: 10px 0;
+  -moz-appearance: none;
+  box-shadow: none;
+  background-image: none;
+  border: 1px solid transparent;
+  border-bottom-style: none;
+  border-radius: 0;
+  transition: background-color;
+  -moz-box-orient: vertical;
+  flex: 1 1 33.33%;
+}
+:-moz-any(#PanelUI-help, #PanelUI-customize, #PanelUI-quit) > .toolbarbutton-icon {
+  margin: 0 0 3px;
+}
+
+#PanelUI-customize {
+  list-style-image: url(chrome://browser/skin/menuPanel-customize.png);
+}
+
+#PanelUI-help {
+  -moz-border-start-style: none;
+  list-style-image: url(chrome://browser/skin/menuPanel-help.png);
+}
+
+#PanelUI-quit {
+  -moz-border-end-style: none;
+  list-style-image: url(chrome://browser/skin/menuPanel-exit.png);
+}
+
+#PanelUI-customize,
+#PanelUI-help,
+#PanelUI-quit {
+  -moz-image-region: rect(0, 16px, 16px, 0);
+}
+
+#PanelUI-customize:hover,
+#PanelUI-help:not([disabled]):hover,
+#PanelUI-quit:not([disabled]):hover {
+  -moz-image-region: rect(0, 32px, 16px, 16px);
+}
+
+#PanelUI-customize:hover:active,
+#PanelUI-help:not([disabled]):hover:active,
+#PanelUI-quit:not([disabled]):hover:active {
+  -moz-image-region: rect(0, 48px, 16px, 32px);
+}
+
+#PanelUI-help[disabled],
+#PanelUI-quit[disabled] {
+  opacity: 0.4;
+}
+
+#PanelUI-help:not([disabled]):hover,
+#PanelUI-customize:hover,
+#PanelUI-quit:not([disabled]):hover {
+  border-color: rgba(8,25,42,0.2);
+  border-top-color: rgba(8,25,42,0.1);
+  background-color: rgba(0,0,0,0.1);
+  box-shadow: none;
+}
+
+#main-window[customize-entered] #PanelUI-customize {
+  color: white;
+  background-image: linear-gradient(rgb(41,123,204), rgb(40,133,203));
+  box-shadow: inset 0 1px 1px rgba(0,0,0,0.5), 0 2px rgba(255,255,255,0.2);
+  text-shadow: 0 1px 0 rgba(0,0,0,0.4);
+}
+
+#main-window[customize-entered] #PanelUI-customize:hover,
+#main-window[customize-entered] #PanelUI-customize:hover:active {
+  background-image: linear-gradient(rgb(38,115,191), rgb(38,125,191));
+}
+
+#customization-palette .toolbarbutton-text {
+  display: none;
+}
+
+panelview toolbarbutton,
+#widget-overflow-list > toolbarbutton,
+.customizationmode-button,
+#BMB_bookmarksPopup > menu,
+#BMB_bookmarksPopup > menuitem {
+  -moz-appearance: none;
+  padding: 2px 6px;
+  background-color: hsla(210,32%,93%,0);
+  background-clip: padding-box;
+  border-radius: 2px;
+  border: 1px solid;
+  border-color: hsla(210,54%,20%,0) hsla(210,54%,20%,0) hsla(210,54%,20%,0);
+  box-shadow: 0 1px hsla(0,0%,100%,0) inset,
+              0 1px hsla(210,54%,20%,0),
+              0 0 2px hsla(210,54%,20%,0);
+  transition-property: background-color, border-color, box-shadow;
+  transition-duration: 150ms;
+}
+
+panelview toolbarbutton@buttonStateHover@,
+#widget-overflow-list > toolbarbutton@buttonStateHover@,
+#edit-controls@inAnyPanel@ > toolbarbutton,
+#zoom-controls@inAnyPanel@ > toolbarbutton,
+.customizationmode-button,
+#BMB_bookmarksPopup > menu@buttonStateHover@,
+#BMB_bookmarksPopup > menuitem@buttonStateHover@ {
+  background-image: -moz-linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
+  border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.2) hsla(210,54%,20%,.25);
+  box-shadow: 0 1px hsla(0,0%,100%,.3) inset,
+              0 1px hsla(210,54%,20%,.03),
+              0 0 2px hsla(210,54%,20%,.1);
+}
+
+panelview toolbarbutton@buttonStateActive@,
+.customizationmode-button:not([disabled]):hover:active,
+#widget-overflow-list > toolbarbutton@buttonStateActive@,
+#BMB_bookmarksPopup > menu@buttonStateActive@,
+#BMB_bookmarksPopup > menuitem@buttonStateActive@ {
+  background-image: -moz-linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
+  background-color: hsla(210,54%,20%,.15);
+  border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
+  box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
+              0 0 1px hsla(210,54%,20%,.2) inset,
+              0 1px 0 hsla(210,54%,20%,0),
+              0 0 2px hsla(210,54%,20%,0);
+  text-shadow: none;
+  transition: none;
+}
+
+#BMB_bookmarksPopup > menu,
+#BMB_bookmarksPopup > menuitem {
+  font: inherit;
+}
+
+#BMB_bookmarksPopup > menu:not([disabled="true"]),
+#BMB_bookmarksPopup > menuitem:not([disabled="true"]) {
+  color: inherit;
+}
+
+#BMB_bookmarksPopup > .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box > .autorepeatbutton-up,
+#BMB_bookmarksPopup > .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box > .autorepeatbutton-down {
+  -moz-appearance: none;
+  margin-top: 0;
+  margin-bottom: 0;
+}
+
+panelview toolbarseparator,
+#BMB_bookmarksPopup > menuseparator {
+  -moz-appearance: none;
+  min-height: 0;
+  border-top: 1px solid ThreeDShadow;
+  margin: 5px 0;
+}
+
+#PanelUI-historyItems > toolbarbutton {
+  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
+}
+
+#PanelUI-recentlyClosedWindows > toolbarbutton > .toolbarbutton-icon,
+#PanelUI-recentlyClosedTabs > toolbarbutton > .toolbarbutton-icon,
+#PanelUI-historyItems > toolbarbutton > .toolbarbutton-icon {
+  width: 16px;
+  height: 16px;
+}
+
+#PanelUI-footer.panel-multiview-anchor,
+#PanelUI-footer.panel-multiview-anchor > #PanelUI-help,
+toolbarbutton.panel-multiview-anchor {
+  background-color: Highlight;
+  background-image: linear-gradient(rgba(255,255,255,0.3), rgba(255,255,255,0));
+  background-repeat: repeat-x;
+  color: HighlightText;
+}
+
+toolbarpaletteitem[place="palette"] > #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker,
+#bookmarks-menu-button[cui-areatype="menu-panel"] > .toolbarbutton-menubutton-dropmarker {
+  display: none;
+}
+
+#edit-controls@inAnyPanel@ > toolbarbutton,
+#zoom-controls@inAnyPanel@ > toolbarbutton {
+  -moz-box-flex: 1;
+}
+
+#search-container[cui-areatype="menu-panel"] {
+  width: @menuPanelWidth@;
+}
+
+toolbarpaletteitem[place="palette"] > #search-container {
+  min-width: 7em;
+  width: 7em;
+}
+
+#edit-controls@inAnyPanel@ > toolbarbutton,
+#zoom-controls@inAnyPanel@ > toolbarbutton {
+  -moz-appearance: none;
+}
+
+#edit-controls@inAnyPanel@ > toolbarbutton[disabled] > .toolbarbutton-icon,
+#zoom-controls@inAnyPanel@ > toolbarbutton[disabled] > .toolbarbutton-icon {
+  opacity: .25;
+}
+
+#edit-controls.overflowedItem > toolbarbutton > .toolbarbutton-text {
+  display: none;
+}
+
+#zoom-controls[cui-areatype="toolbar"] > #zoom-reset-button > .toolbarbutton-text {
+%ifdef XP_MACOSX
+  min-width: 6ch;
+%else
+  min-width: 7ch;
+%endif
+}
+
+#zoom-controls@inAnyPanel@ > #zoom-reset-button {
+  list-style-image: none;
+}
+
+#edit-controls@inAnyPanel@ > #paste-button,
+#zoom-controls@inAnyPanel@ > #zoom-in-button {
+  -moz-border-start-width: 1px;
+  -moz-border-start-style: solid;
+}
+
+#edit-controls@inAnyPanel@ > #cut-button:-moz-locale-dir(ltr),
+#edit-controls@inAnyPanel@ > #paste-button:-moz-locale-dir(rtl),
+#zoom-controls@inAnyPanel@ > #zoom-out-button:-moz-locale-dir(ltr),
+#zoom-controls@inAnyPanel@ > #zoom-in-button:-moz-locale-dir(rtl) {
+  border-top-right-radius: 2px;
+  border-bottom-right-radius: 2px;
+}
+
+#edit-controls@inAnyPanel@ > #cut-button:-moz-locale-dir(rtl),
+#edit-controls@inAnyPanel@ > #paste-button:-moz-locale-dir(ltr),
+#zoom-controls@inAnyPanel@ > #zoom-out-button:-moz-locale-dir(rtl),
+#zoom-controls@inAnyPanel@ > #zoom-in-button:-moz-locale-dir(ltr) {
+  border-top-left-radius: 2px;
+  border-bottom-left-radius: 2px;
+}
+
+#widget-overflow > .panel-arrowcontainer > .panel-arrowcontent {
+  padding: 0;
+}
+
+#widget-overflow-scroller {
+  max-height: 30em;
+  overflow-y: auto;
+  overflow-x: hidden;
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+
+#widget-overflow-list {
+  width: @menuPanelWidth@;
+  padding-left: 10px;
+  padding-right: 10px;
+}
+
+#widget-overflow-list > .overflowedItem {
+  width: 100%;
+  max-width: @menuPanelWidth@;
+  min-height: 36px;
+  background-repeat: no-repeat;
+  background-position: 0 center;
+}
+
+#widget-overflow-list > toolbarbutton,
+#widget-overflow-list > toolbarbutton > toolbarbutton {
+  -moz-box-align: center;
+  -moz-box-orient: horizontal;
+}
+
+#widget-overflow-list > toolbarbutton > .toolbarbutton-text,
+#widget-overflow-list > #bookmarks-menu-button > toolbarbutton > .toolbarbutton-text {
+  text-align: start;
+  -moz-padding-start: .5em;
+}
+
+#widget-overflow-list > #edit-controls,
+#widget-overflow-list > #zoom-controls {
+  min-height: 28px;
+}
+
+#PanelUI-developerItems > toolbarbutton[checked="true"],
+#PanelUI-bookmarks > toolbarbutton[checked="true"],
+.PanelUI-characterEncodingView-list > toolbarbutton[current] {
+  -moz-padding-start: 4px;
+}
+
+#PanelUI-developerItems > toolbarbutton[checked="true"] > .toolbarbutton-text,
+#PanelUI-bookmarks > toolbarbutton[checked="true"] > .toolbarbutton-text,
+.PanelUI-characterEncodingView-list > toolbarbutton[current] > .toolbarbutton-text,
+#customizationui-widget-panel .PanelUI-characterEncodingView-list > toolbarbutton[current] > .toolbarbutton-text {
+  -moz-padding-start: 0px;
+}
+
+#BMB_bookmarksPopup > menuitem[checked="true"]::before,
+#PanelUI-bookmarks > toolbarbutton[checked="true"]::before,
+#PanelUI-developerItems > toolbarbutton[checked="true"]::before,
+.PanelUI-characterEncodingView-list > toolbarbutton[current]::before {
+  content: "✓";
+  display: -moz-box;
+  width: 12px;
+}
+
+#PanelUI-bookmarks > toolbarbutton[checked="true"]::before,
+#PanelUI-developerItems > toolbarbutton[checked="true"]::before,
+.PanelUI-characterEncodingView-list > toolbarbutton[current]::before {
+  -moz-margin-end: -2px;
+}
+
+#BMB_bookmarksPopup > menuitem[checked="true"] > .menu-iconic-left {
+  display: none;
+}
diff --git a/browser/themes/shared/menupanel.inc.css b/browser/themes/shared/menupanel.inc.css
new file mode 100644
index 0000000000000000000000000000000000000000..1fa2532528b8bc1b487c588948c36a33fb4f60f3
--- /dev/null
+++ b/browser/themes/shared/menupanel.inc.css
@@ -0,0 +1,140 @@
+/* Menu panel and palette styles */
+
+:-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > :-moz-any(@primaryToolbarButtons@) {
+  list-style-image: url(chrome://browser/skin/menuPanel.png);
+}
+
+#home-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #home-button {
+  -moz-image-region: rect(0px, 128px, 32px, 96px);
+}
+
+#bookmarks-menu-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #bookmarks-menu-button {
+  -moz-image-region: rect(0px, 160px, 32px, 128px);
+}
+
+#bookmarks-menu-button[starred][cui-areatype="menu-panel"] {
+  -moz-image-region: rect(0px, 192px, 32px, 160px);
+}
+
+#history-panelmenu[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #history-panelmenu {
+  -moz-image-region: rect(0px, 224px, 32px, 192px);
+}
+
+#downloads-button[cui-areatype="menu-panel"],
+#downloads-indicator[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #downloads-button {
+  -moz-image-region: rect(0px, 256px, 32px, 224px);
+}
+
+#add-ons-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #add-ons-button {
+  -moz-image-region: rect(0px, 288px, 32px, 256px);
+}
+
+#open-file-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #open-file-button {
+  -moz-image-region: rect(0px, 320px, 32px, 288px);
+}
+
+#save-page-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #save-page-button {
+  -moz-image-region: rect(0px, 352px, 32px, 320px);
+}
+
+#sync-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #sync-button {
+  -moz-image-region: rect(0px, 384px, 32px, 352px);
+}
+
+#feed-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #feed-button {
+  -moz-image-region: rect(0px, 416px, 32px, 384px);
+}
+
+#social-share-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #social-share-button {
+  -moz-image-region: rect(0px, 448px, 32px, 416px);
+}
+
+#characterencoding-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #characterencoding-button {
+  -moz-image-region: rect(0px, 480px, 32px, 448px);
+}
+
+#new-window-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #new-window-button {
+  -moz-image-region: rect(0px, 512px, 32px, 480px);
+}
+
+#new-tab-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #new-tab-button {
+  -moz-image-region: rect(0px, 544px, 32px, 512px);
+}
+
+#privatebrowsing-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #privatebrowsing-button {
+  -moz-image-region: rect(0px, 576px, 32px, 544px);
+}
+
+#find-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #find-button {
+  -moz-image-region: rect(0px, 640px, 32px, 608px);
+}
+
+#print-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #print-button {
+  -moz-image-region: rect(0px, 672px, 32px, 640px);
+}
+
+#fullscreen-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #fullscreen-button {
+  -moz-image-region: rect(0px, 704px, 32px, 672px);
+}
+
+#developer-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #developer-button {
+  -moz-image-region: rect(0px, 736px, 32px, 704px);
+}
+
+#preferences-button[cui-areatype="menu-panel"],
+toolbarpaletteitem[place="palette"] > #preferences-button {
+  -moz-image-region: rect(0px, 768px, 32px, 736px);
+}
+
+/* Wide panel control icons */
+
+#edit-controls@inAnyPanel@ > toolbarbutton,
+#zoom-controls@inAnyPanel@ > toolbarbutton,
+toolbarpaletteitem[place="palette"] > #edit-controls > toolbarbutton,
+toolbarpaletteitem[place="palette"] > #zoom-controls > toolbarbutton {
+  list-style-image: url(chrome://browser/skin/menuPanel-small.png);
+}
+
+#edit-controls@inAnyPanel@ > #cut-button,
+toolbarpaletteitem[place="palette"] > #edit-controls > #cut-button {
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
+}
+
+#edit-controls@inAnyPanel@ > #copy-button,
+toolbarpaletteitem[place="palette"] > #edit-controls > #copy-button {
+  -moz-image-region: rect(0px, 48px, 16px, 32px);
+}
+
+#edit-controls@inAnyPanel@ > #paste-button,
+toolbarpaletteitem[place="palette"] > #edit-controls > #paste-button {
+  -moz-image-region: rect(0px, 64px, 16px, 48px);
+}
+
+#zoom-controls@inAnyPanel@ > #zoom-out-button,
+toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-out-button {
+  -moz-image-region: rect(0px, 80px, 16px, 64px);
+}
+
+#zoom-controls@inAnyPanel@ > #zoom-in-button,
+toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button {
+  -moz-image-region: rect(0px, 96px, 16px, 80px);
+}
diff --git a/browser/themes/shared/tab-selected.svg b/browser/themes/shared/tab-selected.svg
new file mode 100644
index 0000000000000000000000000000000000000000..4132c4a42460a517bc32b37baf7ede3ebe75717c
--- /dev/null
+++ b/browser/themes/shared/tab-selected.svg
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- 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/. -->
+
+<svg version="1.1"
+     xmlns="http://www.w3.org/2000/svg"
+     xmlns:svg="http://www.w3.org/2000/svg"
+     x="0px"
+     y="0px"
+     width="30px"
+     height="31px"
+     preserveAspectRatio="none"
+     xml:space="preserve">
+  <defs>
+    <style><![CDATA[
+
+%filter substitution
+
+%ifdef XP_MACOSX
+%include ../osx/shared.inc
+%elifdef XP_LINUX
+%include ../linux/linuxShared.inc
+%else
+%include ../windows/windowsShared.inc
+%endif
+
+      #tab-background-fill {
+        background-color: @fgTabBackgroundColor@;
+        background-image: @fgTabTexture@;
+        background-repeat: no-repeat;
+        height: 100%;
+        width: 100%;
+      }
+
+%ifdef WINDOWS_AERO
+      @media (-moz-windows-default-theme) {
+        #tab-background-fill {
+          background-color: @customToolbarColor@;
+        }
+      }
+%endif
+    ]]></style>
+
+%include ../../base/content/tab-shape.inc.svg
+  </defs>
+
+  <foreignObject class="node" x="0" y="0" width="30" height="31" clip-path="url(#tab-curve-clip-path-@TAB_SIDE@)">
+    <body xmlns="http://www.w3.org/1999/xhtml" style="all:unset">
+      <div id="tab-background-fill"></div>
+    </body>
+  </foreignObject>
+</svg>
diff --git a/browser/themes/shared/tabs.inc.css b/browser/themes/shared/tabs.inc.css
new file mode 100644
index 0000000000000000000000000000000000000000..e793f33c29ea07ad92d95678803877c935152e52
--- /dev/null
+++ b/browser/themes/shared/tabs.inc.css
@@ -0,0 +1,283 @@
+%if 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/. */
+%endif
+
+%define tabHeight 31px
+%define tabCurveWidth 30px
+%define tabCurveHalfWidth 15px
+
+/* image preloading hack */
+#TabsToolbar::before {
+  /* Because of bug 853415, we need to ordinal this to the first position: */
+  -moz-box-ordinal-group: 0;
+  content: '';
+  display: block;
+  background-image:
+    url(chrome://browser/skin/tabbrowser/tab-background-end.png),
+    url(chrome://browser/skin/tabbrowser/tab-background-middle.png),
+    url(chrome://browser/skin/tabbrowser/tab-background-start.png);
+}
+
+.tabbrowser-tab,
+.tabs-newtab-button {
+  -moz-appearance: none;
+  background-color: transparent;
+  border-radius: 0;
+  border-width: 0;
+  margin: 0;
+  padding: 0;
+}
+
+.tabbrowser-tab {
+  -moz-box-align: stretch;
+}
+
+.tabbrowser-tab[remote] {
+  text-decoration: underline;
+}
+
+/* The selected tab should appear above adjacent tabs, .tabs-newtab-button and the highlight of #nav-bar */
+.tabbrowser-tab[selected=true] {
+  position: relative;
+  z-index: 2;
+}
+
+.tab-background-middle {
+  -moz-box-flex: 1;
+  background-clip: padding-box;
+  border-left: @tabCurveHalfWidth@ solid transparent;
+  border-right: @tabCurveHalfWidth@ solid transparent;
+  margin: 0 -@tabCurveHalfWidth@;
+}
+
+.tab-content {
+  -moz-padding-end: 9px;
+  -moz-padding-start: 9px;
+}
+
+.tab-throbber,
+.tab-icon-image,
+.tab-close-button {
+  margin-top: 1px;
+}
+
+.tab-throbber,
+.tab-icon-image {
+  height: 16px;
+  width: 16px;
+}
+
+.tab-icon-image {
+  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
+}
+
+.tab-throbber {
+  list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png");
+}
+
+.tab-throbber[progress] {
+  list-style-image: url("chrome://browser/skin/tabbrowser/loading.png");
+}
+
+.tab-throbber:not([pinned]),
+.tab-icon-image:not([pinned]) {
+  -moz-margin-end: 6px;
+}
+
+.tab-label {
+  -moz-margin-end: 0;
+  -moz-margin-start: 0;
+}
+
+.tab-close-button {
+  -moz-margin-start: 4px;
+  -moz-margin-end: -2px;
+  padding: 0;
+}
+
+.tab-background,
+.tabs-newtab-button {
+  /* overlap the tab curves */
+  -moz-margin-end: -@tabCurveHalfWidth@;
+  -moz-margin-start: -@tabCurveHalfWidth@;
+}
+
+.tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox {
+  -moz-padding-end: @tabCurveHalfWidth@;
+  -moz-padding-start: @tabCurveHalfWidth@;
+}
+
+.tab-background-start[selected=true]::after,
+.tab-background-start[selected=true]::before,
+.tab-background-start,
+.tab-background-end,
+.tab-background-end[selected=true]::after,
+.tab-background-end[selected=true]::before {
+  min-height: @tabHeight@;
+  width: @tabCurveWidth@;
+}
+
+.tabbrowser-tab:-moz-lwtheme {
+  color: inherit;
+}
+
+/* Selected tab */
+
+/*
+ Tab background pseudo-elements which are positioned above .tab-background-start/end:
+   - ::before - provides the fill of the tab curve and is clipped to the tab shape. This is where
+                pointer events go for the curve.
+   - ::after  - provides the border/stroke of the tab curve and is overlayed above ::before.  Pointer
+                events go through to ::before to get the proper shape.
+ */
+
+
+.tab-background-start[selected=true]::after,
+.tab-background-end[selected=true]::after {
+  /* position ::after on top of its parent */
+  -moz-margin-start: -@tabCurveWidth@;
+  background-size: 100% 100%;
+  content: "";
+  display: -moz-box;
+  position: relative;
+}
+
+.tab-background-start[selected=true]::before,
+.tab-background-end[selected=true]::before {
+  /* all ::before pseudo elements */
+  content: "";
+  display: -moz-box;
+}
+
+.tab-background-start[selected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
+.tab-background-end[selected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
+  background-image: url(chrome://browser/skin/tabbrowser/tab-selected-start.svg);
+  background-size: 100% 100%;
+}
+
+.tab-background-end[selected=true]:-moz-locale-dir(ltr):not(:-moz-lwtheme)::before,
+.tab-background-start[selected=true]:-moz-locale-dir(rtl):not(:-moz-lwtheme)::before {
+  background-image: url(chrome://browser/skin/tabbrowser/tab-selected-end.svg);
+  background-size: 100% 100%;
+}
+
+/* For lightweight themes, clip the header image on start, middle, and end. */
+.tab-background-start[selected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before,
+.tab-background-end[selected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before {
+  clip-path: url(chrome://browser/content/browser.xul#tab-curve-clip-path-start);
+}
+
+.tab-background-end[selected=true]:-moz-locale-dir(ltr):-moz-lwtheme::before,
+.tab-background-start[selected=true]:-moz-locale-dir(rtl):-moz-lwtheme::before {
+  clip-path: url(chrome://browser/content/browser.xul#tab-curve-clip-path-end);
+}
+
+.tab-background-start[selected=true]:-moz-locale-dir(ltr)::after,
+.tab-background-end[selected=true]:-moz-locale-dir(rtl)::after {
+  background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-start.png);
+}
+
+.tab-background-end[selected=true]:-moz-locale-dir(ltr)::after,
+.tab-background-start[selected=true]:-moz-locale-dir(rtl)::after {
+  background-image: url(chrome://browser/skin/tabbrowser/tab-stroke-end.png);
+}
+
+.tab-background-middle[selected=true] {
+  background-clip: padding-box, padding-box, content-box;
+  background-color: @fgTabBackgroundColor@;
+  background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
+                    @fgTabTexture@,
+                    none;
+  background-repeat: repeat-x;
+  background-size: auto 100%;
+  /* The padding-top combined with background-clip: content-box (the bottom-most) ensure the
+     background-color doesn't extend above the top border. */
+  padding-top: 2px;
+}
+
+/* Selected tab lightweight theme styles.
+   See browser-lightweightTheme.css for information about run-time changes to LWT styles. */
+.tab-background-middle[selected=true]:-moz-lwtheme {
+  background-color: transparent;
+  background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
+                    @fgTabTextureLWT@;/*,
+                    lwtHeader;*/
+  /* Don't stretch the LWT header images */
+  background-size: auto 100%, auto 100%, auto auto;
+}
+
+/* These LWT styles are normally overridden by browser-lightweightTheme.css */
+.tab-background-start[selected=true]:-moz-lwtheme::before,
+.tab-background-end[selected=true]:-moz-lwtheme::before {
+  background-image: @fgTabTextureLWT@;
+}
+
+.tab-background-start[selected=true]:-moz-lwtheme::before,
+.tab-background-end[selected=true]:-moz-lwtheme::before,
+.tab-background-middle[selected=true]:-moz-lwtheme {
+  background-color: transparent;
+}
+
+/* End selected tab */
+
+/* new tab button border and gradient on hover */
+.tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]),
+.tabs-newtab-button:hover {
+  background-image: url(chrome://browser/skin/tabbrowser/tab-background-start.png),
+                    url(chrome://browser/skin/tabbrowser/tab-background-middle.png),
+                    url(chrome://browser/skin/tabbrowser/tab-background-end.png);
+  background-position: left bottom, @tabCurveWidth@ bottom, right bottom;
+  background-repeat: no-repeat;
+  background-size: @tabCurveWidth@ 100%, calc(100% - (2 * @tabCurveWidth@)) 100%, @tabCurveWidth@ 100%;
+}
+
+/* Tab pointer-events */
+.tabbrowser-tab {
+  pointer-events: none;
+}
+
+.tab-background-middle,
+.tabs-newtab-button,
+.tab-close-button {
+  pointer-events: auto;
+}
+
+/* Pinned tabs */
+
+/* Pinned tab separators need position: absolute when positioned (during overflow). */
+#tabbrowser-tabs[positionpinnedtabs] > .tabbrowser-tab[pinned]::before {
+  height: 100%;
+  position: absolute;
+}
+
+.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) > .tab-stack > .tab-content {
+  background-image: radial-gradient(farthest-corner at center bottom, rgb(255,255,255) 3%, rgba(186,221,251,0.75) 20%, rgba(127,179,255,0.25) 40%, rgba(127,179,255,0) 70%);
+  background-position: center bottom 1px;
+  background-repeat: no-repeat;
+  background-size: 85% 100%;
+}
+
+/* Background tab separators (3px wide).
+   Also show separators beside the selected tab when dragging it. */
+#tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
+.tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
+#tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
+  -moz-margin-start: -1.5px;
+  -moz-margin-end: -1.5px;
+  background-image: url(chrome://browser/skin/tabbrowser/tab-separator.png);
+  background-position: left bottom;
+  background-repeat: no-repeat;
+  background-size: 3px 100%;
+  content: "";
+  display: -moz-box;
+  margin-bottom: 1px;
+  width: 3px;
+}
+
+/* New tab button */
+
+.tabs-newtab-button {
+  width: 66px;
+}
diff --git a/browser/themes/shared/toolbarbuttons.inc.css b/browser/themes/shared/toolbarbuttons.inc.css
new file mode 100644
index 0000000000000000000000000000000000000000..293899ef635e02db9058930249f736bfffa99702
--- /dev/null
+++ b/browser/themes/shared/toolbarbuttons.inc.css
@@ -0,0 +1,139 @@
+:-moz-any(@primaryToolbarButtons@),
+#bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+  list-style-image: url("chrome://browser/skin/Toolbar.png");
+}
+
+:-moz-any(@primaryToolbarButtons@):-moz-lwtheme-brighttext,
+#bookmarks-menu-button:-moz-lwtheme-brighttext > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+  list-style-image: url(chrome://browser/skin/Toolbar-inverted.png);
+}
+
+#back-button {
+  -moz-image-region: rect(0, 36px, 18px, 18px);
+}
+
+#forward-button {
+  -moz-image-region: rect(0, 72px, 18px, 54px);
+}
+
+#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
+#forward-button:-moz-locale-dir(rtl) {
+  transform: scaleX(-1);
+}
+
+#home-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 126px, 18px, 108px);
+}
+
+#bookmarks-menu-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 144px, 18px, 126px);
+}
+
+#bookmarks-menu-button[cui-areatype="toolbar"][starred] {
+  -moz-image-region: rect(0, 162px, 18px, 144px);
+}
+
+#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+  -moz-image-region: rect(0, 630px, 18px, 612px);
+}
+
+#history-panelmenu[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 180px, 18px, 162px);
+}
+
+#downloads-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 198px, 18px, 180px);
+}
+
+#add-ons-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 216px, 18px, 198px);
+}
+
+#open-file-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 234px, 18px, 216px);
+}
+
+#save-page-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 252px, 18px, 234px);
+}
+
+#sync-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 270px, 18px, 252px);
+}
+
+#feed-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 288px, 18px, 270px);
+}
+
+#social-share-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0px, 306px, 18px, 288px);
+}
+
+#characterencoding-button[cui-areatype="toolbar"]{
+  -moz-image-region: rect(0, 324px, 18px, 306px);
+}
+
+#new-window-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 342px, 18px, 324px);
+}
+
+#new-tab-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 360px, 18px, 342px);
+}
+
+#privatebrowsing-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 378px, 18px, 360px);
+}
+
+#find-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 396px, 18px, 378px);
+}
+
+#print-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 414px, 18px, 396px);
+}
+
+#fullscreen-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 432px, 18px, 414px);
+}
+
+#developer-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 450px, 18px, 432px);
+}
+
+#preferences-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 468px, 18px, 450px);
+}
+
+#PanelUI-menu-button {
+  -moz-image-region: rect(0, 486px, 18px, 468px);
+}
+
+#edit-controls:not(@inAnyPanel@) > #cut-button {
+  -moz-image-region: rect(0, 504px, 18px, 486px);
+}
+
+#edit-controls:not(@inAnyPanel@) > #copy-button {
+  -moz-image-region: rect(0, 522px, 18px, 504px);
+}
+
+#edit-controls:not(@inAnyPanel@) > #paste-button {
+  -moz-image-region: rect(0, 540px, 18px, 522px);
+}
+
+#zoom-controls:not(@inAnyPanel@) > #zoom-out-button {
+  -moz-image-region: rect(0, 558px, 18px, 540px);
+}
+
+#zoom-controls:not(@inAnyPanel@) > #zoom-in-button {
+  -moz-image-region: rect(0, 576px, 18px, 558px);
+}
+
+#webrtc-status-button:not(@inAnyPanel@) {
+  -moz-image-region: rect(0, 594px, 18px, 576px);
+}
+
+#nav-bar-overflow-button {
+  -moz-image-region: rect(0, 612px, 18px, 594px);
+}
+
diff --git a/browser/themes/windows/Makefile.in b/browser/themes/windows/Makefile.in
index 173ca68435c6cf993204e3cca62ac579ab2537ba..93893379dd7f52714ac3ebf5f3e5cb883ad8c273 100644
--- a/browser/themes/windows/Makefile.in
+++ b/browser/themes/windows/Makefile.in
@@ -5,3 +5,32 @@
 ICON_FILES := icon.png
 ICON_DEST = $(FINAL_TARGET)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
 INSTALL_TARGETS += ICON
+
+# By default, the pre-processor used for jar.mn will use "%" as a marker for ".css" files and "#"
+# otherwise. This falls apart when a file using one marker needs to include a file with the other
+# marker since the pre-processor instructions in the included file will not be processed. The
+# following SVG files need to include a file which uses "%" as the marker so we invoke the pre-
+# processor ourselves here with the marker specified. The resulting SVG files will get packaged by
+# the processing of the jar file in this directory.
+tab-selected-svg: $(srcdir)/../shared/tab-selected.svg
+	$(call py_action,preprocessor, \
+	  --marker % -D TAB_SIDE=start \
+	  $(ACDEFINES) \
+	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-start.svg)
+	$(call py_action,preprocessor, \
+	  --marker % -D TAB_SIDE=end \
+	  $(ACDEFINES) \
+	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-end.svg)
+# Same as above for aero.
+	$(call py_action,preprocessor, \
+	  --marker % -D TAB_SIDE=start -D WINDOWS_AERO \
+	  $(ACDEFINES) \
+	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-start-aero.svg)
+	$(call py_action,preprocessor, \
+	  --marker % -D TAB_SIDE=end -D WINDOWS_AERO \
+	  $(ACDEFINES) \
+	  $(srcdir)/../shared/tab-selected.svg -o tab-selected-end-aero.svg)
+
+.PHONY: tab-selected-svg
+
+export:: tab-selected-svg
diff --git a/browser/themes/windows/Toolbar-aero.png b/browser/themes/windows/Toolbar-aero.png
new file mode 100644
index 0000000000000000000000000000000000000000..14a90c27b49b0f8cf90766357e5c2582b62ef230
Binary files /dev/null and b/browser/themes/windows/Toolbar-aero.png differ
diff --git a/browser/themes/windows/Toolbar-inverted-aero.png b/browser/themes/windows/Toolbar-inverted-aero.png
new file mode 100644
index 0000000000000000000000000000000000000000..b42fd7475dbe89ff00dfcf875c45f76c839fab05
Binary files /dev/null and b/browser/themes/windows/Toolbar-inverted-aero.png differ
diff --git a/browser/themes/windows/Toolbar-inverted.png b/browser/themes/windows/Toolbar-inverted.png
index 2c3253fe80f94776c9a8320252eac24ffff46c9d..b42fd7475dbe89ff00dfcf875c45f76c839fab05 100644
Binary files a/browser/themes/windows/Toolbar-inverted.png and b/browser/themes/windows/Toolbar-inverted.png differ
diff --git a/browser/themes/windows/Toolbar-lunaSilver.png b/browser/themes/windows/Toolbar-lunaSilver.png
new file mode 100644
index 0000000000000000000000000000000000000000..668f8c108f74fc128fbadb4bdb27daa73fda3767
Binary files /dev/null and b/browser/themes/windows/Toolbar-lunaSilver.png differ
diff --git a/browser/themes/windows/Toolbar.png b/browser/themes/windows/Toolbar.png
index b84f6ddadf1a04005a46db5f396e5d29977d24a9..687cc1b3dad4197e98b3f39a8d75878c954b13f9 100644
Binary files a/browser/themes/windows/Toolbar.png and b/browser/themes/windows/Toolbar.png differ
diff --git a/browser/themes/windows/appmenu-dropmarker.png b/browser/themes/windows/appmenu-dropmarker.png
deleted file mode 100644
index 27deaff72225a4c66865190405b071d728899d9c..0000000000000000000000000000000000000000
Binary files a/browser/themes/windows/appmenu-dropmarker.png and /dev/null differ
diff --git a/browser/themes/windows/appmenu-icons.png b/browser/themes/windows/appmenu-icons.png
deleted file mode 100644
index 78f36581631f5a7ad49eac9fae3f029e914c7c49..0000000000000000000000000000000000000000
Binary files a/browser/themes/windows/appmenu-icons.png and /dev/null differ
diff --git a/browser/themes/windows/browser-aero.css b/browser/themes/windows/browser-aero.css
index c7e65fb97d131d48b6cc7c58cd536003fd754560..cecfd870e53170dc751621940a7e549dc9cbee10 100644
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -6,38 +6,16 @@
 %include browser.css
 %undef WINDOWS_AERO
 
-%define customToolbarColor hsl(210,75%,92%)
 %define glassActiveBorderColor rgb(37, 44, 51)
 %define glassInactiveBorderColor rgb(102, 102, 102)
 
 %include downloads/indicator-aero.css
 
 @media not all and (-moz-windows-classic) {
-  #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #appmenu-button-container {
+  #main-window[sizemode="normal"] > #tab-view-deck > #browser-panel > #navigator-toolbox > #toolbar-menubar {
     margin-top: 1px;
   }
 
-  #appmenu-button {
-    border-width: 2px;
-    -moz-border-left-colors: @appMenuButtonBorderColor@;
-    -moz-border-bottom-colors: @appMenuButtonBorderColor@;
-    -moz-border-right-colors: @appMenuButtonBorderColor@;
-    margin-bottom: 1px; /* compensate white outer border */
-    box-shadow: 0 1px 0 rgba(255,255,255,.25) inset,
-                0 0 2px 1px rgba(255,255,255,.25) inset;
-  }
-
-  #main-window[privatebrowsingmode=temporary] #appmenu-button {
-    -moz-border-left-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
-    -moz-border-bottom-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
-    -moz-border-right-colors: rgba(255,255,255,.5) rgba(43,8,65,.9);
-  }
-
-  #appmenu-popup {
-    margin-top: -1px;
-    -moz-margin-start: 1px;
-  }
-
   .panel-promo-message {
     font-style: italic;
   }
@@ -50,45 +28,26 @@
     background-color: @customToolbarColor@;
   }
 
-  .tabbrowser-tab:not(:-moz-lwtheme),
-  .tabs-newtab-button:not(:-moz-lwtheme) {
-    background-image: @toolbarShadowOnTab@, @bgTabTexture@,
-                      linear-gradient(@customToolbarColor@, @customToolbarColor@);
-  }
-
-  .tabbrowser-tab:not(:-moz-lwtheme):hover,
-  .tabs-newtab-button:not(:-moz-lwtheme):hover {
-    background-image: @toolbarShadowOnTab@, @bgTabTextureHover@,
-                      linear-gradient(@customToolbarColor@, @customToolbarColor@);
-  }
-
-  .tabbrowser-tab[selected="true"]:not(:-moz-lwtheme) {
-    background-image: linear-gradient(#fff, @toolbarHighlight@ 50%),
-                      linear-gradient(@customToolbarColor@, @customToolbarColor@);
-  }
-
-  #main-window[tabsontop=false]:not([disablechrome]) .tabbrowser-tab[selected=true]:not(:-moz-lwtheme) {
-    background-image: @toolbarShadowOnTab@,
-                      linear-gradient(#fff, @toolbarHighlight@ 50%),
-                      linear-gradient(@customToolbarColor@, @customToolbarColor@);
+  .tab-background-middle[selected=true]:not(:-moz-lwtheme) {
+    background-color: @customToolbarColor@;
   }
 
   #navigator-toolbox:not(:-moz-lwtheme)::after {
     background-color: #aabccf;
   }
 
-  #navigator-toolbox[tabsontop=true] #urlbar:not(:-moz-lwtheme),
-  #navigator-toolbox[tabsontop=true] .searchbar-textbox:not(:-moz-lwtheme) {
+  #urlbar:not(:-moz-lwtheme),
+  .searchbar-textbox:not(:-moz-lwtheme) {
     border-color: hsla(210,54%,20%,.25) hsla(210,54%,20%,.27) hsla(210,54%,20%,.3);
   }
 
-  #navigator-toolbox[tabsontop=true] #urlbar:not(:-moz-lwtheme):not([focused]):hover,
-  #navigator-toolbox[tabsontop=true] .searchbar-textbox:not(:-moz-lwtheme):not([focused]):hover {
+  #urlbar:not(:-moz-lwtheme):not([focused]):hover,
+  .searchbar-textbox:not(:-moz-lwtheme):not([focused]):hover {
     border-color: hsla(210,54%,20%,.35) hsla(210,54%,20%,.37) hsla(210,54%,20%,.4);
   }
 
-  #navigator-toolbox[tabsontop=true] #urlbar:not(:-moz-lwtheme)[focused],
-  #navigator-toolbox[tabsontop=true] .searchbar-textbox:not(:-moz-lwtheme)[focused] {
+  #urlbar:not(:-moz-lwtheme)[focused],
+  .searchbar-textbox:not(:-moz-lwtheme)[focused] {
     border-color: hsla(206,100%,60%,.65) hsla(206,100%,55%,.65) hsla(206,100%,50%,.65);
   }
 
@@ -152,10 +111,6 @@
     -moz-appearance: -moz-win-exclude-glass;
   }
 
-  #main-window[chromemargin^="0,"][sizemode=normal] #navigator-toolbox {
-    margin-top: -7px;
-  }
-
   /* Artificially draw window borders that are covered by lwtheme, see bug 591930. */
   #main-window[sizemode="normal"] > #titlebar > #titlebar-content:-moz-lwtheme {
     border-top: 2px solid;
@@ -166,27 +121,12 @@
     -moz-border-top-colors: @glassInactiveBorderColor@ rgba(255,255,255,.6);
   }
 
-  #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #appmenu-button-container:-moz-lwtheme {
-    margin-top: -1px;
-  }
-
   #main-window[sizemode="normal"] #titlebar-buttonbox:-moz-lwtheme {
     margin-top: -2px;
   }
 
-  #appmenu-button {
-    margin-bottom: -1px; /* compensate white outer border */
-  }
-
-  #main-window[sizemode=fullscreen]:not(:-moz-lwtheme) {
-    -moz-appearance: none;
-    background-color: #556;
-  }
-
   #toolbar-menubar:not(:-moz-lwtheme),
-  #TabsToolbar[tabsontop=true]:not(:-moz-lwtheme),
-  #nav-bar[tabsontop=false]:not(:-moz-lwtheme),
-  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child:not(:-moz-lwtheme) {
+  #TabsToolbar:not(:-moz-lwtheme) {
     background-color: transparent !important;
     color: black;
     text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
@@ -194,33 +134,13 @@
     border-right-style: none !important;
   }
 
-  :-moz-any(#toolbar-menubar, #nav-bar[tabsontop=false]) :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
-  :-moz-any(#toolbar-menubar, #nav-bar[tabsontop=false]) :-moz-any(@primaryToolbarButtons@) > toolbarbutton > .toolbarbutton-icon:not(:-moz-lwtheme),
-  #TabsToolbar[tabsontop=true] :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
-  #TabsToolbar[tabsontop=true] :-moz-any(@primaryToolbarButtons@) > toolbarbutton > .toolbarbutton-icon:not(:-moz-lwtheme),
-  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child :-moz-any(@primaryToolbarButtons@):not(:-moz-any(#alltabs-button,#tabview-button,#new-tab-button,#sync-button[status])) > .toolbarbutton-icon:not(:-moz-lwtheme),
-  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child :-moz-any(@primaryToolbarButtons@) > toolbarbutton > .toolbarbutton-icon:not(:-moz-lwtheme) {
-    list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
-  }
-
-  :-moz-any(#toolbar-menubar, #TabsToolbar[tabsontop=true], #nav-bar[tabsontop=false]) .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme),
-  :-moz-any(#toolbar-menubar, #TabsToolbar[tabsontop=true], #nav-bar[tabsontop=false]) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme),
-  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child .toolbarbutton-1 > .toolbarbutton-menu-dropmarker:not(:-moz-lwtheme),
-  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:not(:-moz-lwtheme) {
-    list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow-inverted.png");
-  }
-
   /* Vertical toolbar border */
   #main-window[sizemode=normal] #navigator-toolbox::after,
-  #main-window[sizemode=normal] #navigator-toolbox[tabsontop=true] > toolbar:not(#toolbar-menubar):not(#TabsToolbar),
-  #main-window[sizemode=normal] #navigator-toolbox[tabsontop=false] > toolbar:not(#toolbar-menubar):not(#nav-bar) {
+  #main-window[sizemode=normal] #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
     border-left: 1px solid @toolbarShadowColor@;
     border-right: 1px solid @toolbarShadowColor@;
     background-clip: padding-box;
   }
-  #main-window[sizemode=normal] #navigator-toolbox > toolbar:-moz-lwtheme {
-    border-color: transparent !important;
-  }
   #main-window[sizemode=normal] #browser-border-start,
   #main-window[sizemode=normal] #browser-border-end {
     display: -moz-box;
@@ -233,65 +153,36 @@
     background-clip: padding-box;
   }
 
-  #main-window[sizemode=normal][tabsontop=false] #PersonalToolbar:not(:-moz-lwtheme) {
-    border-top-left-radius: 2.5px;
-    border-top-right-radius: 2.5px;
+  /* Toolbar shadow behind tabs */
+  #nav-bar {
+    border-top: 1px solid @toolbarShadowColor@ !important;
+    background-clip: padding-box;
   }
 
-  /* Toolbar shadow behind tabs */
   /* This code is only needed for restored windows (i.e. sizemode=normal)
      because of the border radius on the toolbar below the tab bar. */
-  #main-window[sizemode=normal] #nav-bar[tabsontop=true]:not(:-moz-lwtheme),
-  #main-window[sizemode=normal] #nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar:not(:-moz-lwtheme),
-  #main-window[sizemode=normal] #nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar:not(:-moz-lwtheme),
-  #main-window[sizemode=normal][disablechrome] #navigator-toolbox[tabsontop=true]:not(:-moz-lwtheme)::after {
+  #main-window[sizemode=normal] #nav-bar {
     border-top: 1px solid @toolbarShadowColor@;
     border-top-left-radius: 2.5px;
     border-top-right-radius: 2.5px;
     background-clip: padding-box;
   }
-  #main-window[sizemode=normal] #TabsToolbar[tabsontop=true]:not(:-moz-lwtheme) {
-    margin-bottom: -1px;
-    background-image: none !important;
-  }
-  #main-window[sizemode=normal] #tabbrowser-tabs[tabsontop=true] > .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox > .scrollbox-innerbox:not(:-moz-lwtheme) {
-    position: relative;
-  }
 
-  #navigator-toolbox[tabsontop=false] > #PersonalToolbar {
-    margin-top: 3px;
-  }
-  #navigator-toolbox[tabsontop=false] > #PersonalToolbar:not(:-moz-lwtheme) {
-    margin-top: 2px;
-    border-top: 1px solid @toolbarShadowColor@;
-    background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
-  }
-
-  #main-window[sizemode=normal] #TabsToolbar[tabsontop=true] {
-    padding-left: 4px;
-    padding-right: 4px;
+  /* Cover the top border of the adjacent toolbar */
+  #TabsToolbar {
+    margin-bottom: -1px;
   }
 
-  #main-window[sizemode=normal] #TabsToolbar[tabsontop=false] {
-    padding-left: 2px;
-    padding-right: 2px;
-  }
-
-  /* Rounded corners for when chrome is disabled */
-  #main-window[sizemode=normal][disablechrome] #navigator-toolbox[tabsontop=true]:not(:-moz-lwtheme)::after {
-    visibility: visible;
-    background-color: @customToolbarColor@;
-    background-image: linear-gradient(@toolbarHighlight@, @toolbarHighlight@);
-    height: 4px;
+  #main-window[sizemode=normal] #TabsToolbar {
+    padding-left: 1px;
+    padding-right: 1px;
   }
 
   /* Make the window draggable by glassed toolbars (bug 555081) */
   #toolbar-menubar:not([autohide="true"]),
-  #TabsToolbar[tabsontop="true"],
-  #nav-bar[tabsontop=false],
-  #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"] + #TabsToolbar[tabsontop="false"]:last-child,
-  #navigator-toolbox > toolbar:not(#toolbar-menubar):-moz-lwtheme {
-    -moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbar-drag");
+  #TabsToolbar,
+  #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#addon-bar):-moz-lwtheme {
+    -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
   }
 
   #appcontent:not(:-moz-lwtheme) {
@@ -303,29 +194,6 @@
     border-radius: 4px;
   }
 
-  #navigator-toolbox[tabsontop=false] #urlbar:not(:-moz-lwtheme),
-  #navigator-toolbox[tabsontop=false] .searchbar-textbox:not(:-moz-lwtheme) {
-    background-color: rgba(255,255,255,.725);
-    @navbarTextboxCustomBorder@
-    color: black;
-  }
-
-  #navigator-toolbox[tabsontop=false] html|*.urlbar-input:not(:-moz-lwtheme)::-moz-placeholder,
-  #navigator-toolbox[tabsontop=false] .searchbar-textbox > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input:not(:-moz-lwtheme)::-moz-placeholder {
-    opacity: 1.0;
-    color: #777;
-  }
-
-  #navigator-toolbox[tabsontop=false] #urlbar:not(:-moz-lwtheme):hover,
-  #navigator-toolbox[tabsontop=false] .searchbar-textbox:not(:-moz-lwtheme):hover {
-    background-color: rgba(255,255,255,.898);
-  }
-
-  #navigator-toolbox[tabsontop=false] #urlbar:not(:-moz-lwtheme)[focused],
-  #navigator-toolbox[tabsontop=false] .searchbar-textbox:not(:-moz-lwtheme)[focused] {
-    background-color: white;
-  }
-
   .tabbrowser-tab:not(:-moz-lwtheme) {
     text-shadow: none;
   }
@@ -347,6 +215,57 @@
   }
 }
 
+@media (-moz-windows-glass) {
+  #main-window[sizemode=fullscreen]:not(:-moz-lwtheme) {
+    -moz-appearance: none;
+    background-color: #556;
+  }
+
+  /* Use inverted icons for glassed toolbars */
+  #TabsToolbar > toolbarpaletteitem > #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:not(:-moz-lwtheme),
+  #TabsToolbar > #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:not(:-moz-lwtheme),
+  #toolbar-menubar > toolbarpaletteitem > #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:not(:-moz-lwtheme),
+  #toolbar-menubar > #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:not(:-moz-lwtheme),
+  #toolbar-menubar > toolbarpaletteitem > :-moz-any(@primaryToolbarButtons@):not(:-moz-lwtheme),
+  #toolbar-menubar > :-moz-any(@primaryToolbarButtons@):not(:-moz-lwtheme),
+  #TabsToolbar > toolbarpaletteitem > :-moz-any(@primaryToolbarButtons@):not(:-moz-lwtheme),
+  #TabsToolbar > :-moz-any(@primaryToolbarButtons@):not(:-moz-lwtheme) {
+    list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
+  }
+
+  /* Glass Fog */
+
+  #TabsToolbar:not(:-moz-lwtheme) {
+    background-image: none;
+    position: relative;
+  }
+
+  #TabsToolbar:not(:-moz-lwtheme)::before {
+    box-shadow: 0 0 30px 30px rgba(174,189,204,0.85);
+    content: "";
+    display: -moz-box;
+    height: 0;
+    margin: 0 60px; /* (30px + 30px) from box-shadow */
+    position: absolute;
+    pointer-events: none;
+    top: 50%;
+    width: -moz-available;
+    z-index: -1;
+  }
+
+  /* Need to constrain the glass fog to avoid overlapping layers, see bug 886281. */
+  #main-window:not([customizing]) #navigator-toolbox:not(:-moz-lwtheme) {
+    overflow-y: hidden;
+  }
+
+  #main-window[sizemode=normal] .tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox > .scrollbox-innerbox:not(:-moz-lwtheme) {
+    position: relative;
+  }
+
+  /* End Glass Fog */
+}
+
+
 @media not all and (-moz-windows-compositor) {
   @media (-moz-windows-default-theme) {
     #main-window {
@@ -357,14 +276,26 @@
     }
 
     #toolbar-menubar:not([autohide=true]):not(:-moz-lwtheme),
-    #TabsToolbar[tabsontop=true]:not(:-moz-lwtheme),
-    #navigator-toolbox[tabsontop=false] > toolbar:not(#toolbar-menubar):not(:-moz-lwtheme) {
-      -moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbar-drag");
+    #TabsToolbar:not(:-moz-lwtheme) {
+      -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
       background-color: transparent;
     }
     #toolbar-menubar[autohide=true] {
       background-color: transparent !important;
     }
+
+    /* Render a window top border for lwthemes: */
+    #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme {
+      background-image: linear-gradient(to bottom,
+            @glassActiveBorderColor@ 0, @glassActiveBorderColor@ 1px,
+            rgba(255,255,255,.6) 1px, rgba(255,255,255,.6) 2px, transparent 2px);
+    }
+
+    #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme:-moz-window-inactive {
+      background-image: linear-gradient(to bottom,
+            @glassInactiveBorderColor@ 0, @glassInactiveBorderColor@ 1px,
+            rgba(255,255,255,.6) 1px, rgba(255,255,255,.6) 2px, transparent 2px);
+    }
   }
 
   #print-preview-toolbar:not(:-moz-lwtheme) {
@@ -400,72 +331,3 @@
 #close-button:-moz-locale-dir(rtl) {
   transform: scaleX(-1);
 }
-
-/* ::::: splitmenu highlight style that imitates Windows 7 start menu ::::: */
-@media (-moz-windows-default-theme) {
-  .splitmenu-menuitem,
-  .splitmenu-menu {
-    -moz-appearance: none;
-    padding-top: 2px;
-    padding-bottom: 2px;
-    border: 1px solid transparent;
-  }
-  .splitmenu-menuitem {
-    -moz-margin-end: 0;
-  }
-  .splitmenu-menu {
-    -moz-margin-start: -1px;
-  }
-  .splitmenu-menuitem:-moz-locale-dir(ltr),
-  .splitmenu-menu:-moz-locale-dir(rtl) {
-    border-top-left-radius: 3px;
-    border-bottom-left-radius: 3px;
-  }
-  .splitmenu-menu:-moz-locale-dir(ltr),
-  .splitmenu-menuitem:-moz-locale-dir(rtl) {
-    border-top-right-radius: 3px;
-    border-bottom-right-radius: 3px;
-  }
-
-  .splitmenu-menuitem > .menu-text {
-    -moz-margin-start: 1px !important;
-    -moz-margin-end: 3px !important;
-  }
-  .splitmenu-menu > .menu-right {
-    -moz-margin-end: -3px;
-  }
-
-  .splitmenu-menuitem[iconic],
-  .splitmenu-menu[iconic] {
-    padding-bottom: 1px;
-  }
-  .splitmenu-menuitem[iconic] > .menu-iconic-left {
-    margin-top: -3px;
-    margin-bottom: -2px;
-    -moz-margin-start: -1px;
-  }
-  .splitmenu-menuitem[iconic] > .menu-iconic-text {
-    -moz-margin-start: 2px !important;
-    -moz-margin-end: 3px !important;
-  }
-  .splitmenu-menu[iconic] > .menu-right {
-    margin-top: -1px;
-  }
-
-  .splitmenu-menuitem[_moz-menuactive],
-  .splitmenu-menu[_moz-menuactive] {
-    background-color: transparent;
-    background-image: linear-gradient(#fafbfd, #ebf3fd);
-    border-color: #aeccf1;
-  }
-
-  .splitmenu-menuitem[disabled][_moz-menuactive],
-  .splitmenu-menu[disabled][_moz-menuactive] {
-    background-image: linear-gradient(#f8f9f9, #eaeaea);
-    border-color: #d8d7d7;
-  }
-
-  .splitmenu-menu[_moz-menuactive]:not(:hover):not([open]) {
-    background-image: none;
-  }
-}
diff --git a/browser/themes/windows/browser-lightweightTheme.css b/browser/themes/windows/browser-lightweightTheme.css
new file mode 100644
index 0000000000000000000000000000000000000000..292d0dc7874331da9323b5b220a1e48b08f63d6d
--- /dev/null
+++ b/browser/themes/windows/browser-lightweightTheme.css
@@ -0,0 +1,29 @@
+/* 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 windowsShared.inc
+%filter substitution
+
+/*
+ * LightweightThemeListener will append the current lightweight theme's header
+ * image to the background-image for each of the following rulesets.
+ */
+
+/* Lightweight theme on tabs */
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-start[selected=true]:-moz-lwtheme::before,
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-end[selected=true]:-moz-lwtheme::before {
+  background-attachment: scroll, fixed;
+  background-color: transparent;
+  background-image: @fgTabTextureLWT@;/*, lwtHeader;*/
+  background-position: 0 0, right top;
+}
+
+#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background > .tab-background-middle[selected=true]:-moz-lwtheme {
+  background-attachment: scroll, scroll, fixed;
+  background-color: transparent;
+  background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle.png),
+                    @fgTabTextureLWT@;/*,
+                    lwtHeader;*/
+  background-position: 0 0, 0 0, right top;
+}
diff --git a/browser/themes/windows/browser.css b/browser/themes/windows/browser.css
index 4ef1877fe85a3af6dcb5cfe717cbe13508f1ee27..347db3a73b9ab26ed9e2a13dcfe55a523c08d090 100644
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -8,29 +8,14 @@
 @namespace html url("http://www.w3.org/1999/xhtml");
 
 %include ../shared/browser.inc
+%include windowsShared.inc
 %filter substitution
-%define toolbarHighlight rgba(255,255,255,.5)
-%define selectedTabHighlight rgba(255,255,255,.7)
-%define toolbarShadowColor rgba(10%,10%,10%,.4)
-%define toolbarShadowOnTab linear-gradient(to top, rgba(10%,10%,10%,.4) 1px, transparent 1px)
-%define bgTabTexture linear-gradient(transparent, hsla(0,0%,45%,.1) 1px, hsla(0,0%,32%,.2) 80%, hsla(0,0%,0%,.2))
-%define bgTabTextureHover linear-gradient(hsla(0,0%,100%,.3) 1px, hsla(0,0%,75%,.2) 80%, hsla(0,0%,60%,.2))
+%define toolbarShadowColor hsla(209,67%,12%,0.35)
 %define navbarTextboxCustomBorder border-color: rgba(0,0,0,.32);
-%define navbarLargeIcons #navigator-toolbox[iconsize=large][mode=icons] > #nav-bar
 %define forwardTransitionLength 150ms
-%define conditionalForwardWithUrlbar window:not([chromehidden~=toolbar]) #navigator-toolbox[iconsize=large][mode=icons] > :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"],#nav-bar:not([currentset])) > #unified-back-forward-button
+%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
 %define conditionalForwardWithUrlbarWidth 27
 
-%ifdef MOZ_OFFICIAL_BRANDING
-%define appMenuButtonBorderColor rgba(255,255,255,.5) rgba(83,42,6,.9)
-%else
-%if MOZ_UPDATE_CHANNEL == aurora
-%define appMenuButtonBorderColor hsla(0,0%,100%,.5) hsla(214,89%,21%,.9)
-%else
-%define appMenuButtonBorderColor hsla(0,0%,100%,.5) hsla(210,59%,13%,.9)
-%endif
-%endif
-
 #menubar-items {
   -moz-box-orient: vertical; /* for flex hack */
 }
@@ -39,6 +24,31 @@
   -moz-box-flex: 1; /* make menu items expand to fill toolbar height */
 }
 
+/* We want a 4px gap between the TabsToolbar and the toolbar-menubar when the
+   toolbar-menu is displayed, and a 16px gap when it is not. 1px is taken care
+   of by the (light) outer shadow of the tab, the remaining 3/15 are these margins. */
+#toolbar-menubar:not([autohide="true"]) ~ #TabsToolbar,
+#toolbar-menubar[autohide="true"]:not([inactive]) ~ #TabsToolbar {
+  margin-top: 3px;
+}
+
+#main-window[tabsintitlebar][sizemode="normal"][chromehidden~="menubar"] #toolbar-menubar ~ #TabsToolbar,
+#main-window[tabsintitlebar][sizemode="normal"] #toolbar-menubar[autohide="true"][inactive] ~ #TabsToolbar {
+  margin-top: 15px;
+}
+
+#toolbar-menubar:not([autohide="true"]) {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
+}
+
+#main-window[tabsintitlebar] #main-menubar > menu:not(:-moz-lwtheme) {
+  color: CaptionText;
+}
+
+#main-window[tabsintitlebar] #main-menubar > menu:not(:-moz-lwtheme):-moz-window-inactive {
+  color: InactiveCaptionText;
+}
+
 #navigator-toolbox {
   -moz-appearance: none;
   background-color: transparent;
@@ -52,10 +62,6 @@
   height: 1px;
   background-color: ThreeDShadow;
 }
-#navigator-toolbox[tabsontop=false]::after,
-#main-window[disablechrome] #navigator-toolbox::after {
-  visibility: collapse;
-}
 
 #navigator-toolbox > toolbar:not(:-moz-lwtheme) {
   -moz-appearance: none;
@@ -66,20 +72,26 @@
 %ifdef WINDOWS_AERO
 @media not all and (-moz-windows-compositor) {
 %endif
-  #main-window[tabsintitlebar]:not([inFullscreen]) #toolbar-menubar[inactive] ~ #TabsToolbar:not(:-moz-lwtheme) {
-    background: linear-gradient(to top, @toolbarShadowColor@ 1px, transparent 1px),
-                linear-gradient(rgba(50%,50%,50%,0), ActiveCaption 85%);
+  #toolbar-menubar {
+    background-color: transparent !important;
+  }
+
+  #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme) {
     color: CaptionText;
   }
-  #main-window[tabsintitlebar]:not([inFullscreen]) #toolbar-menubar[inactive] ~ #TabsToolbar:not(:-moz-lwtheme):-moz-window-inactive {
-    background: linear-gradient(to top, @toolbarShadowColor@ 1px, transparent 1px),
-                linear-gradient(rgba(50%,50%,50%,0), InactiveCaption 85%);
+
+  #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme):-moz-window-inactive {
     color: InactiveCaptionText;
   }
 
+  #TabsToolbar:-moz-lwtheme {
+    background: linear-gradient(to top, @toolbarShadowColor@ 2px, transparent 2px);
+  }
+
   #main-window[tabsintitlebar] #titlebar:-moz-lwtheme {
     visibility: hidden;
   }
+
   #main-window[tabsintitlebar] #titlebar-content:-moz-lwtheme {
     -moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox");
     visibility: visible;
@@ -88,449 +100,118 @@
 }
 %endif
 
-#nav-bar[tabsontop=true],
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + toolbar,
-#nav-bar[tabsontop=true][collapsed=true]:not([customizing]) + #customToolbars + #PersonalToolbar {
-  background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
-}
-
-#personal-bookmarks {
-  min-height: 24px;
-}
-
-#print-preview-toolbar:not(:-moz-lwtheme) {
-  -moz-appearance: toolbox;
-}
-
-#browser-bottombox:not(:-moz-lwtheme) {
-  background-color: -moz-dialog;
-}
-
-/* ::::: app menu button ::::: */
-
-#appmenu-button {
-  -moz-appearance: none;
-  background-clip: padding-box;
-  border-radius: 0 0 4px 4px;
-  border: 1px solid;
-  border-top: none;
-  color: white;
-  text-shadow: 0 0 1px rgba(0,0,0,.7),
-               0 1px 1.5px rgba(0,0,0,.5);
-  font-weight: bold;
-  padding: 0 1.5em .05em;
-  margin: 0 0 2px;
-}
-
+/**
+ * In the classic themes, the titlebar has a horizontal gradient, which is
+ * problematic for reading the text of background tabs when they're in the
+ * titlebar. We side-step this issue by layering our own gradient underneath
+ * the tabs.
+ */
 @media (-moz-windows-classic) {
-  #appmenu-button {
-    margin-bottom: 1px;
-  }
-}
-
-%ifndef WINDOWS_AERO
-@media (-moz-windows-default-theme) {
-  #main-window[sizemode="normal"] #appmenu-button {
-    margin-bottom: 5px;
-  }
-}
-%endif
-
-#appmenu-button:hover:active,
-#appmenu-button[open] {
-  border-radius: 0;
-}
-
-%ifdef MOZ_OFFICIAL_BRANDING
-#appmenu-button {
-  background-image: linear-gradient(rgb(247,182,82), rgb(215,98,10) 95%);
-  border-color: rgba(83,42,6,.9);
-  box-shadow: 0 1px 0 rgba(255,255,255,.25) inset,
-              0 0 0 1px rgba(255,255,255,.25) inset;
-}
-#appmenu-button:hover:not(:active):not([open]) {
-  background-image: radial-gradient(farthest-side at bottom, rgba(252,240,89,.5) 10%, rgba(252,240,89,0) 70%),
-                    radial-gradient(farthest-side at bottom, rgb(236,133,0), rgba(255,229,172,0)),
-                    linear-gradient(rgb(246,170,69), rgb(209,74,0) 95%);
-  border-color: rgba(83,42,6,.9);
-  box-shadow: 0 1px 0 rgba(255,255,255,.1) inset,
-              0 0 2px 1px rgba(250,234,169,.7) inset,
-              0 -1px 0 rgba(250,234,169,.5) inset;
-}
-#appmenu-button:hover:active,
-#appmenu-button[open] {
-  background-image: linear-gradient(rgb(246,170,69), rgb(209,74,0) 95%);
-  box-shadow: 0 2px 3px rgba(0,0,0,.4) inset,
-              0 1px 1px rgba(0,0,0,.2) inset;
-}
-%else
-%if MOZ_UPDATE_CHANNEL == aurora
-#appmenu-button {
-  background-image: linear-gradient(hsl(208,99%,37%), hsl(214,90%,23%) 95%);
-  border-color: hsla(214,89%,21%,.9);
-  box-shadow: 0 1px 0 hsla(205,100%,72%,.2) inset,
-              0 0 2px 1px hsla(205,100%,72%,.25) inset;
-}
-#appmenu-button:hover:not(:active):not([open]) {
-  background-image: radial-gradient(farthest-side at bottom, hsla(202,100%,85%,.5) 10%, hsla(202,100%,85%,0) 70%),
-                    radial-gradient(farthest-side at bottom, hsla(205,100%,72%,.7), hsla(205,100%,72%,0)),
-                    linear-gradient(hsl(208,98%,34%), hsl(213,87%,20%) 95%);
-  border-color: hsla(214,89%,21%,.9);
-  box-shadow: 0 1px 0 hsla(205,100%,72%,.15) inset,
-              0 0 2px 1px hsla(205,100%,72%,.5) inset,
-              0 -1px 0 hsla(205,100%,72%,.2) inset;
-}
-#appmenu-button:hover:active,
-#appmenu-button[open] {
-  background-image: linear-gradient(hsl(208,95%,30%), hsl(214,85%,17%) 95%);
-  box-shadow: 0 2px 3px rgba(0,0,0,.4) inset,
-              0 1px 1px rgba(0,0,0,.2) inset;
-}
-%else
-#appmenu-button {
-  background-image: linear-gradient(hsl(211,33%,32%), hsl(209,53%,10%) 95%);
-  border-color: hsla(210,59%,13%,.9);
-  box-shadow: 0 1px 0 hsla(210,48%,90%,.15) inset,
-              0 0 2px 1px hsla(211,65%,85%,.15) inset;
-}
-#appmenu-button:hover:not(:active):not([open]) {
-  background-image: radial-gradient(farthest-side at bottom, hsla(210,48%,90%,.5) 10%, hsla(210,48%,90%,0) 70%),
-                    radial-gradient(farthest-side at bottom, hsla(211,70%,83%,.5), hsla(211,70%,83%,0)),
-                    linear-gradient(hsl(211,33%,32%), hsl(209,53%,10%) 95%);
-  border-color: hsla(210,59%,13%,.9);
-  box-shadow: 0 1px 0 hsla(210,48%,90%,.15) inset,
-              0 0 2px 1px hsla(210,48%,90%,.4) inset,
-              0 -1px 0 hsla(210,48%,90%,.2) inset;
-}
-#appmenu-button:hover:active,
-#appmenu-button[open] {
-  background-image: linear-gradient(hsl(211,33%,26%), hsl(209,53%,6%) 95%);
-  box-shadow: 0 2px 3px rgba(0,0,0,.4) inset,
-              0 1px 1px rgba(0,0,0,.2) inset;
-}
-%endif
-%endif
-
-#main-window[privatebrowsingmode=temporary] #appmenu-button {
-  background-image: linear-gradient(rgb(153,38,211), rgb(105,19,163) 95%);
-  border-color: rgba(43,8,65,.9);
-}
-
-#main-window[privatebrowsingmode=temporary] #appmenu-button:hover:not(:active):not([open]) {
-  background-image: radial-gradient(farthest-side at bottom, rgba(240,193,255,.5) 10%, rgba(240,193,255,0) 70%),
-                    radial-gradient(farthest-side at bottom, rgb(192,81,247), rgba(236,172,255,0)),
-                    linear-gradient(rgb(144,20,207), rgb(95,0,158) 95%);
-  border-color: rgba(43,8,65,.9);
-  box-shadow: 0 1px 0 rgba(255,255,255,.1) inset,
-              0 0 2px 1px rgba(240,193,255,.7) inset,
-              0 -1px 0 rgba(240,193,255,.5) inset;
-}
-
-#main-window[privatebrowsingmode=temporary] #appmenu-button:hover:active,
-#main-window[privatebrowsingmode=temporary] #appmenu-button[open] {
-  background-image: linear-gradient(rgb(144,20,207), rgb(95,0,158) 95%);
-}
-
-#appmenu-button > .button-box {
-  border-style: none;
-  padding: 0;
-}
-
-#appmenu-button > .button-box > .button-menu-dropmarker {
-  list-style-image: url(appmenu-dropmarker.png);
-  width: auto;
-  height: auto;
-  padding: 0;
-  margin: 0;
-  -moz-margin-start: .5em;
-}
-
-.splitmenu-menuitem {
-  -moz-margin-end: 1px;
-%ifdef WINDOWS_AERO
-  -moz-padding-end: 0.5em;
-%endif
-}
-
-.splitmenu-menu {
-  -moz-box-pack: end;
-}
-
-.appmenu-edit-button {
-  -moz-appearance: none;
-  border: 1px solid transparent;
-  padding: 2px;
-  background: transparent;
-  border-radius: 3px;
-}
-
-.appmenu-edit-button[disabled="true"] {
-  opacity: .3;
-}
-
-#appmenuPrimaryPane {
-  -moz-border-end: 1px solid ThreeDShadow;
-}
-
-@media (-moz-windows-default-theme) {
-  #appmenu-popup {
-    -moz-appearance: none;
-    background: white;
-    border: 1px solid ThreeDShadow;
-  }
-  #appmenuPrimaryPane {
-    background-color: rgba(255,255,255,0.5);
-    padding: 2px;
-    -moz-border-end: none;
-  }
-  #appmenuSecondaryPane {
-    background-color: #f1f5fb;
-    box-shadow: 1px 0 2px rgb(204,214,234) inset;
-    -moz-padding-start: 3px;
-    -moz-padding-end: 2px;
-    padding-top: 2px;
-    padding-bottom: 2px;
-    font-family: "Segoe UI Semibold", "Segoe UI", sans-serif;
-  }
-  #appmenuSecondaryPane:-moz-locale-dir(rtl) {
-    box-shadow: -1px 0 2px rgb(204,214,234) inset;
+  #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme) {
+    background: linear-gradient(to top, @toolbarShadowColor@ 2px, transparent 2px),
+                linear-gradient(rgba(50%,50%,50%,0), ActiveCaption 85%);
   }
 
-%ifdef WINDOWS_AERO
-  #appmenuPrimaryPane menupopup {
-    -moz-appearance: none;
-    background-image: linear-gradient(to right, white 26px, ThreeDLightShadow 26px,
-                                      ThreeDLightShadow 27px, ThreeDHighlight 27px,
-                                      ThreeDHighlight 28px, white 28px);
-    border: 3px solid;
-    -moz-border-top-colors: ThreeDShadow white;
-    -moz-border-bottom-colors: ThreeDShadow white;
-    -moz-border-left-colors: ThreeDShadow white;
-    -moz-border-right-colors: ThreeDShadow white;
-  }
-%endif
-
-  #appmenuSecondaryPane menupopup {
-    -moz-appearance: none;
-%ifdef WINDOWS_AERO
-    background-image: linear-gradient(to right, #f1f5fb 26px, ThreeDLightShadow 26px,
-                                      ThreeDLightShadow 27px, ThreeDHighlight 27px,
-                                      ThreeDHighlight 28px, #f1f5fb 28px);
-    border: 3px solid;
-    -moz-border-top-colors: ThreeDShadow #f1f5fb;
-    -moz-border-bottom-colors: ThreeDShadow #f1f5fb;
-    -moz-border-left-colors: ThreeDShadow #f1f5fb;
-    -moz-border-right-colors: ThreeDShadow #f1f5fb;
-%else
-    background-color: #f1f5fb;
-    border: 1px solid ThreeDShadow;
-    padding: 2px;
-%endif
+  #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar:not(:-moz-lwtheme):-moz-window-inactive {
+    background: linear-gradient(to top, @toolbarShadowColor@ 2px, transparent 2px),
+                linear-gradient(rgba(50%,50%,50%,0), InactiveCaption 85%);
   }
 
-%ifdef WINDOWS_AERO
-  #appmenuPrimaryPane menupopup:-moz-locale-dir(rtl) {
-    background-image: linear-gradient(to left, white 26px, ThreeDLightShadow 26px,
-                                      ThreeDLightShadow 27px, ThreeDHighlight 27px,
-                                      ThreeDHighlight 28px, white 28px);
-  }
-  #appmenuSecondaryPane menupopup:-moz-locale-dir(rtl) {
-    background-image: linear-gradient(to left, #f1f5fb 26px, ThreeDLightShadow 26px,
-                                      ThreeDLightShadow 27px, ThreeDHighlight 27px,
-                                      ThreeDHighlight 28px, #f1f5fb 28px);
+  #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme {
+    /* Render a window top border: */
+    background-image: linear-gradient(to bottom,
+          ThreeDLightShadow 0, ThreeDLightShadow 1px,
+          ThreeDHighlight 1px, ThreeDHighlight 2px,
+          ActiveBorder 2px, ActiveBorder 4px, transparent 4px);
   }
+}
 
-  /* Hi-DPI overrides of the menu backgrounds, to adjust where the gutter line falls */
-  @media (min-resolution: 1.25dppx) {
-    #appmenuPrimaryPane menupopup {
-      background-image: linear-gradient(to right, white 22.4px, ThreeDLightShadow 22.4px,
-                                        ThreeDLightShadow 23.2px, ThreeDHighlight 23.2px,
-                                        ThreeDHighlight 24px, white 24px);
-    }
-    #appmenuSecondaryPane menupopup {
-      background-image: linear-gradient(to right, #f1f5fb 22.4px, ThreeDLightShadow 22.4px,
-                                        ThreeDLightShadow 23.2px, ThreeDHighlight 23.2px,
-                                        ThreeDHighlight 24px, #f1f5fb 24px);
-    }
-    #appmenuPrimaryPane menupopup:-moz-locale-dir(rtl) {
-      background-image: linear-gradient(to left, white 22.4px, ThreeDLightShadow 22.4px,
-                                        ThreeDLightShadow 23.2px, ThreeDHighlight 23.2px,
-                                        ThreeDHighlight 24px, white 24px);
-    }
-    #appmenuSecondaryPane menupopup:-moz-locale-dir(rtl) {
-      background-image: linear-gradient(to left, #f1f5fb 22.4px, ThreeDLightShadow 22.4px,
-                                        ThreeDLightShadow 23.2px, ThreeDHighlight 23.2px,
-                                        ThreeDHighlight 24px, #f1f5fb 24px);
-    }
+/* Render a window top border for lwthemes on WinXP modern themes: */
+@media (-moz-windows-theme: luna-blue) {
+  #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme {
+    background-image: linear-gradient(to bottom,
+        rgb(8, 49, 216) 0, rgb(8, 49, 216) 1px,
+        rgb(15, 77, 227) 1px, rgb(15, 77, 227) 2px,
+        rgb(22, 106, 238) 2px, rgb(22, 106, 238) 3px,
+        rgb(8, 85, 221) 3px, rgb(8, 85, 221) 4px,
+        transparent 4px);
   }
 
-  @media (min-resolution: 1.5dppx) {
-    #appmenuPrimaryPane menupopup {
-      background-image: linear-gradient(to right, white 20.6667px, ThreeDLightShadow 20.6667px,
-                                        ThreeDLightShadow 21.3333px, ThreeDHighlight 21.3333px,
-                                        ThreeDHighlight 22px, white 22px);
-    }
-    #appmenuSecondaryPane menupopup {
-      background-image: linear-gradient(to right, #f1f5fb 20.6667px, ThreeDLightShadow 20.6667px,
-                                        ThreeDLightShadow 21.3333px, ThreeDHighlight 21.3333px,
-                                        ThreeDHighlight 22px, #f1f5fb 22px);
-    }
-    #appmenuPrimaryPane menupopup:-moz-locale-dir(rtl) {
-      background-image: linear-gradient(to left, white 20.6667px, ThreeDLightShadow 20.6667px,
-                                        ThreeDLightShadow 21.3333px, ThreeDHighlight 21.3333px,
-                                        ThreeDHighlight 22px, white 22px);
-    }
-    #appmenuSecondaryPane menupopup:-moz-locale-dir(rtl) {
-      background-image: linear-gradient(to left, #f1f5fb 20.6667px, ThreeDLightShadow 20.6667px,
-                                        ThreeDLightShadow 21.3333px, ThreeDHighlight 21.3333px,
-                                        ThreeDHighlight 22px, #f1f5fb 22px);
-    }
+  #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme:-moz-window-inactive {
+    background-image: linear-gradient(to bottom,
+        rgb(91, 104, 205) 0, rgb(91, 104, 205) 1px,
+        rgb(116, 128, 220) 1px, rgb(116, 128, 220) 2px,
+        rgb(117, 140, 221) 2px, rgb(117, 140, 221) 4px,
+        transparent 4px);
   }
+}
 
-  @media (min-resolution: 2dppx) {
-    #appmenuPrimaryPane menupopup {
-      background-image: linear-gradient(to right, white 19.5px, ThreeDLightShadow 19.5px,
-                                        ThreeDLightShadow 20px, ThreeDHighlight 20px,
-                                        ThreeDHighlight 20.5px, white 20.5px);
-    }
-    #appmenuSecondaryPane menupopup {
-      background-image: linear-gradient(to right, #f1f5fb 19.5px, ThreeDLightShadow 19.5px,
-                                        ThreeDLightShadow 20px, ThreeDHighlight 20px,
-                                        ThreeDHighlight 20.5px, #f1f5fb 20.5px);
-    }
-    #appmenuPrimaryPane menupopup:-moz-locale-dir(rtl) {
-      background-image: linear-gradient(to left, white 19.5px, ThreeDLightShadow 19.5px,
-                                        ThreeDLightShadow 20px, ThreeDHighlight 20px,
-                                        ThreeDHighlight 20.5px, white 20.5px);
-    }
-    #appmenuSecondaryPane menupopup:-moz-locale-dir(rtl) {
-      background-image: linear-gradient(to left, #f1f5fb 19.5px, ThreeDLightShadow 19.5px,
-                                        ThreeDLightShadow 20px, ThreeDHighlight 20px,
-                                        ThreeDHighlight 20.5px, #f1f5fb 20.5px);
-    }
+@media (-moz-windows-theme: luna-silver) {
+  #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme {
+    background-image: linear-gradient(to bottom,
+        rgb(102,102,126) 0, rgb(102,102,126) 1px,
+        rgb(168,167,191) 1px, rgb(168,167,191) 2px,
+        white 2px, white 3px,
+        rgb(188,188,207) 3px, rgb(188,188,207) 4px,
+        transparent 4px);
   }
-%endif
 
-  .appmenu-menuseparator {
-    -moz-appearance: none;
-    margin-top: 3px;
-    margin-bottom: 3px;
-%ifdef WINDOWS_AERO
-    -moz-margin-start: 30px;
-%else
-    -moz-margin-start: calc(1.45em + 4px);
-%endif
-    padding: 0;
-    border-top: 1px solid #d6e5f5;
-    border-bottom: none;
+  #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme:-moz-window-inactive {
+    background-image: linear-gradient(to bottom,
+        rgb(186,186,197) 0, rgb(186,186,197) 1px,
+        rgb(236,238,245) 1px, rgb(236,238,245) 2px,
+        white 2px, white 3px,
+        rgb(215,215,227) 3px, rgb(215,215,227) 4px,
+        transparent 4px);
   }
+}
 
-%ifdef WINDOWS_AERO
-  @media (min-resolution: 1.25dppx) {
-    .appmenu-menuseparator {
-      -moz-margin-start: 25px;
-    }
+@media (-moz-windows-theme: luna-olive) {
+  #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme {
+    background-image: linear-gradient(to bottom,
+        rgb(139,161,105) 0, rgb(139,161,105) 1px,
+        rgb(171, 189, 133) 1px, rgb(171, 189, 133) 2px,
+        rgb(164,178,127) 2px, rgb(164,178,127) 3px,
+        transparent 3px);
   }
-  @media (min-resolution: 1.5dppx) {
-    .appmenu-menuseparator {
-      -moz-margin-start: 24px;
-    }
-  }
-  @media (min-resolution: 2dppx) {
-    .appmenu-menuseparator {
-      -moz-margin-start: 22px;
-    }
-  }
-%endif
 
-  .appmenu-edit-button:not([disabled]):hover {
-    border: 1px solid #b8d6fb;
-    box-shadow: inset 0 0 1px white;
-    background: linear-gradient(#fafbfd, #ebf3fd);
-    transition: .2s ease-in;
+  #main-window[tabsintitlebar][sizemode="normal"] #titlebar-content:-moz-lwtheme:-moz-window-inactive {
+    background-image: linear-gradient(to bottom,
+        rgb(207, 214, 188) 0, rgb(207, 214, 188) 1px,
+        rgb(224, 226, 200) 1px, rgb(224, 226, 200) 2px,
+        rgb(214, 216, 190) 2px, rgb(214, 216, 190) 3px,
+        transparent 3px);
   }
 }
 
-#appmenuSecondaryPane-spacer {
-  min-height: 1em;
-}
-
-#appmenu-editmenu {
-  -moz-box-pack: end;
-}
-
-#appmenu_print,
-#appmenu_print_popup,
-.appmenu-edit-button,
-#appmenu-editmenu-cut,
-#appmenu-editmenu-copy,
-#appmenu-editmenu-paste,
-#appmenu-quit {
-  list-style-image: url("appmenu-icons.png");
-}
-
-#appmenu-cut,
-#appmenu-editmenu-cut {
-  -moz-image-region: rect(0 16px 16px 0);
-}
-
-#appmenu-copy,
-#appmenu-editmenu-copy {
-  -moz-image-region: rect(0 32px 16px 16px);
-}
-
-#appmenu-paste,
-#appmenu-editmenu-paste {
-  -moz-image-region: rect(0 48px 16px 32px);
-}
-
-#appmenu_print,
-#appmenu_print_popup {
-  -moz-image-region: rect(0 64px 16px 48px);
-}
-
-#appmenu-quit {
-  -moz-image-region: rect(0 80px 16px 64px);
-}
-
-#appmenu-edit-label {
-  -moz-appearance: none;
-  background: transparent;
-  font-style: italic;
-}
-
-#appmenu_bookmarks {
-  list-style-image: url("chrome://browser/skin/places/bookmark.png");
-  -moz-image-region: rect(0px 48px 16px 32px);
+#nav-bar {
+  background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
+  box-shadow: 0 1px 0 @toolbarHighlight@ inset;
+  margin-top: -1px; /* Move up 1px into the TabsToolbar */
+  /* Position the toolbar above the bottom of background tabs */
+  position: relative;
+  z-index: 1;
 }
 
-#appmenu_privateBrowsing,
-#appmenu_newPrivateWindow {
-  list-style-image: url("chrome://browser/skin/Privacy-16.png");
+#personal-bookmarks {
+  min-height: 24px;
 }
 
-@media (min-resolution: 1.25dppx) {
-  #appmenu_privateBrowsing,
-  #appmenu_newPrivateWindow {
-    list-style-image: url("chrome://browser/skin/Privacy-32.png");
-  }
+#print-preview-toolbar:not(:-moz-lwtheme) {
+  -moz-appearance: toolbox;
 }
 
-#appmenu_addons {
-  list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png");
+#browser-bottombox:not(:-moz-lwtheme) {
+  background-color: -moz-dialog;
 }
 
-@media (min-resolution: 1.25dppx) {
-  #appmenu_addons {
-    list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric.png");
+%ifndef WINDOWS_AERO
+@media (-moz-windows-default-theme) {
+  #main-window[tabsintitlebar][sizemode="normal"] #toolbar-menubar {
+    margin-top: 4px;
   }
 }
-
-#BMB_bookmarkThisPage,
-#appmenu_bookmarkThisPage {
-  list-style-image: url("chrome://browser/skin/places/bookmark.png");
-  -moz-image-region: rect(0 16px 16px 0);
-}
+%endif
 
 /* ::::: titlebar ::::: */
 
@@ -543,21 +224,19 @@
 }
 
 @media (-moz-windows-classic) {
-  #main-window[sizemode="normal"] > #titlebar > #titlebar-content > #appmenu-button-container {
+  #main-window[tabsintitlebar][sizemode="normal"] > #tab-view-deck > #browser-panel > #navigator-toolbox > #toolbar-menubar {
     margin-top: 4px;
   }
 }
 
+/* The button box must appear on top of the navigator-toolbox in order for
+ * click and hover mouse events to work properly for the button in the restored
+ * window state. Otherwise, elements in the navigator-toolbox, like the menubar,
+ * can swallow those events. It will also place the buttons above the fog on
+ * themes with Aero Glass.
+ */
 #titlebar-buttonbox {
-  -moz-appearance: -moz-window-button-box;
-}
-
-#main-window[sizemode="maximized"] #titlebar-buttonbox {
-  -moz-appearance: -moz-window-button-box-maximized;
-}
-
-.titlebar-placeholder[type="appmenu-button"] {
-  margin-left: 4px;
+  z-index: 1;
 }
 
 .titlebar-placeholder[type="caption-buttons"] {
@@ -594,7 +273,8 @@
 
 /* ::::: bookmark buttons ::::: */
 
-toolbarbutton.bookmark-item {
+toolbarbutton.bookmark-item,
+#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder {
   margin: 0;
   padding: 2px 3px;
 }
@@ -607,13 +287,15 @@ toolbarbutton.bookmark-item[open="true"] {
   -moz-padding-end: 2px;
 }
 
-.bookmark-item:not(#bookmarks-menu-button) > .toolbarbutton-icon {
+.bookmark-item > .toolbarbutton-icon,
+#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
   width: 16px;
   height: 16px;
 }
 
-/* Prevent [mode="icons"] from hiding the label */
-.bookmark-item > .toolbarbutton-text {
+/* Force the display of the label for bookmarks */
+.bookmark-item > .toolbarbutton-text,
+#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-text {
   display: -moz-box !important;
 }
 
@@ -621,12 +303,7 @@ toolbarbutton.bookmark-item[open="true"] {
   display: none;
 }
 
-#wrapper-personal-bookmarks[place="palette"] > .toolbarpaletteitem-box {
-  background: url("chrome://browser/skin/places/bookmarksToolbar.png") no-repeat center;
-}
-
-.bookmarks-toolbar-customize {
-  max-width: 15em !important;
+#bookmarks-toolbar-placeholder {
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important;
 }
 
@@ -713,19 +390,23 @@ menuitem.bookmark-item {
 
 /* ::::: primary toolbar buttons ::::: */
 
-.toolbarbutton-1 {
-  list-style-image: url("chrome://browser/skin/Toolbar.png");
-}
+%include ../shared/toolbarbuttons.inc.css
+%include ../shared/menupanel.inc.css
 
-.toolbarbutton-1:-moz-lwtheme-brighttext {
-  list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
+%ifndef WINDOWS_AERO
+@media (-moz-windows-theme: luna-silver) {
+  :-moz-any(@primaryToolbarButtons@),
+  #bookmarks-menu-button.toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+    list-style-image: url("chrome://browser/skin/Toolbar-lunaSilver.png");
+  }
 }
+%endif
 
-.toolbarbutton-1[disabled=true] > .toolbarbutton-icon,
-.toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker,
-.toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-dropmarker,
-.toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-.toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon {
+#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-icon,
+#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menu-dropmarker,
+#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-dropmarker,
+#main-window:not([customizing]) .toolbarbutton-1[disabled=true] > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
+#main-window:not([customizing]) .toolbarbutton-1 > .toolbarbutton-menubutton-button[disabled] > .toolbarbutton-icon {
   opacity: .4;
 }
 
@@ -744,57 +425,44 @@ menuitem.bookmark-item {
   -moz-margin-end: 0;
 }
 
-toolbar[mode=full] .toolbarbutton-1:not([type=menu-button]) {
-  -moz-box-orient: vertical;
-}
-
-toolbar[mode=full] .toolbarbutton-1,
-toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
-  min-width: 57px;
-}
-
-#nav-bar {
-  /* force iconsize="small" on this toolbar */
-  counter-reset: smallicons;
-}
-
-@navbarLargeIcons@ .toolbarbutton-1,
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button {
+#nav-bar .toolbarbutton-1,
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   -moz-appearance: none;
   border: none;
   padding: 0;
   background: none;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1:not([type=menu-button]),
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button,
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
-  padding: 5px 2px;
+#nav-bar .toolbarbutton-1:not([type=menu-button]),
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button,
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
+  padding: 8px 2px;
   -moz-box-pack: center;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button) {
+#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button):not(#PanelUI-menu-button) {
   padding-left: 5px;
   padding-right: 5px;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > menupopup {
+#nav-bar .toolbarbutton-1 > menupopup {
   margin-top: -3px;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button {
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   -moz-padding-end: 0;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   -moz-padding-start: 0;
   -moz-box-align: center;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-icon,
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-container,
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+#nav-bar .toolbarbutton-1 > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1 > .toolbarbutton-text,
+#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container,
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
   padding: 2px 6px;
   background: hsla(210,32%,93%,0) padding-box;
   border-radius: 2px;
@@ -807,41 +475,41 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   transition-duration: 150ms;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
-@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container,
-@navbarLargeIcons@ .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container,
+#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
   padding: 3px 7px;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button) > .toolbarbutton-icon,
-@navbarLargeIcons@ .toolbarbutton-1[type=menu] > .toolbarbutton-text /* hack for add-ons that forcefully display the label */ {
+#nav-bar .toolbarbutton-1[type=menu]:not(#back-button):not(#forward-button):not(#feed-button):not(#social-provider-button):not(#PanelUI-menu-button) > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1[type=menu] > .toolbarbutton-text /* hack for add-ons that forcefully display the label */ {
   -moz-padding-end: 17px;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menu-dropmarker {
   -moz-margin-start: -15px;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
   -moz-border-end: none;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
   padding: 8px 5px 7px;
 }
 
-@navbarLargeIcons@ #social-toolbar-item {
+#nav-bar .toolbaritem-combined-buttons {
   margin-left: 2px;
   margin-right: 2px;
 }
 
-@navbarLargeIcons@ #social-toolbar-item > .toolbarbutton-1 {
+#nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1 {
   padding-left: 0;
   padding-right: 0;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before,
-@navbarLargeIcons@ #social-toolbar-item > .toolbarbutton-1:not(:hover):not(:active):not([open]) + .toolbarbutton-1:not(:hover):not(:active):not([open])::before {
+#nav-bar .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before,
+#nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled]) + .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled])::before {
   content: "";
   display: -moz-box;
   width: 1px;
@@ -855,22 +523,23 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   box-shadow: 0 0 0 1px hsla(0,0%,100%,.2);
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(ltr),
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(rtl) {
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(ltr),
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(rtl) {
   border-top-right-radius: 0;
   border-bottom-right-radius: 0;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(rtl),
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(ltr) {
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(rtl),
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(ltr) {
   border-top-left-radius: 0;
   border-bottom-left-radius: 0;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
-@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
-@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
-@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container,
+#nav-bar .toolbarbutton-1:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1:not([disabled]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
+#nav-bar .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text,
+#nav-bar .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container,
 @conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
   background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
   border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.2) hsla(210,54%,20%,.25);
@@ -879,8 +548,8 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
               0 0 2px hsla(210,54%,20%,.1);
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):not([open]):not(:active):hover > .toolbarbutton-icon,
-@navbarLargeIcons@ .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon,
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):not([open]):not(:active):hover > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon,
 @conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled]):hover > .toolbarbutton-icon {
   border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
   background-color: hsla(210,48%,96%,.75);
@@ -888,10 +557,11 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
               0 0 2px hsla(210,54%,20%,.1);
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active > .toolbarbutton-icon,
-@navbarLargeIcons@ .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon,
-@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
-@navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon,
+#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
+#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
   background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
   background-color: hsla(210,54%,20%,.15);
   border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
@@ -904,17 +574,17 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   transition: none;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1:-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
+#nav-bar .toolbarbutton-1:-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
   -moz-border-start-color: hsla(210,54%,20%,.35);
 }
 
-@navbarLargeIcons@ .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
+#nav-bar .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
   background-color: rgba(90%,90%,90%,.4);
   transition: background-color .4s;
 }
 
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1,
-:-moz-any(#TabsToolbar, #addon-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button,
+#TabsToolbar .toolbarbutton-1,
+#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button,
 .tabbrowser-arrowscrollbox > .scrollbutton-up,
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
   -moz-appearance: none;
@@ -935,53 +605,24 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   background-repeat: no-repeat;
 }
 
-#addon-bar .toolbarbutton-1:not([disabled]):hover,
-#addon-bar .toolbarbutton-1[open],
-#addon-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover {
-  background-image: linear-gradient(to top, transparent, rgba(0,0,0,.15)),
-                    linear-gradient(to top, transparent, rgba(0,0,0,.15) 30%),
-                    linear-gradient(to top, transparent, rgba(0,0,0,.15) 30%);
-  background-position: left, left, right;
-  background-size: auto, 1px 100%, 1px 100%;
-  background-repeat: no-repeat;
-}
-
 /* unified back/forward button */
 
-#back-button {
-  -moz-image-region: rect(0, 18px, 18px, 0);
-}
-
 #forward-button {
-  -moz-image-region: rect(0, 36px, 18px, 18px);
-}
-
-#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
-#forward-button:-moz-locale-dir(rtl),
-#forward-button:-moz-locale-dir(rtl) > .toolbarbutton-text {
-  transform: scaleX(-1);
-}
-
-@conditionalForwardWithUrlbar@ {
-  -moz-box-align: center;
+  padding: 0 !important;
 }
 
-@conditionalForwardWithUrlbar@ > #forward-button {
-  padding: 0;
+#forward-button > menupopup {
+  margin-top: 1px !important;
 }
 
-@conditionalForwardWithUrlbar@ > #forward-button > menupopup {
-  margin-top: 1px;
-}
-
-@conditionalForwardWithUrlbar@ > #forward-button > .toolbarbutton-icon {
+#forward-button > .toolbarbutton-icon {
   /*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
-  clip-path: url(chrome://browser/content/browser.xul#windows-keyhole-forward-clip-path);
-  -moz-margin-start: -6px !important;
-  border-left-style: none;
-  border-radius: 0;
-  padding-left: 7px;
-  padding-right: 3px;
+  clip-path: url(chrome://browser/content/browser.xul#windows-keyhole-forward-clip-path) !important;
+  margin-left: -6px !important;
+  border-left-style: none !important;
+  border-radius: 0 !important;
+  padding-left: 7px !important;
+  padding-right: 3px !important;
 }
 
 @conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
@@ -992,60 +633,58 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   opacity: 0;
 }
 
-@conditionalForwardWithUrlbar@ > #back-button {
-  -moz-image-region: rect(18px, 20px, 38px, 0);
-  padding-top: 3px;
-  padding-bottom: 3px;
-  -moz-padding-start: 5px;
-  -moz-padding-end: 0;
-  position: relative;
-  z-index: 1;
-  border-radius: 0 10000px 10000px 0;
+#back-button {
+  padding-top: 3px !important;
+  padding-bottom: 3px !important;
+  -moz-padding-start: 5px !important;
+  -moz-padding-end: 0 !important;
+  position: relative !important;
+  z-index: 1 !important;
+  border-radius: 0 10000px 10000px 0 !important;
 }
 
-@conditionalForwardWithUrlbar@ > #back-button:-moz-locale-dir(rtl) {
-  border-radius: 10000px 0 0 10000px;
+#back-button:-moz-locale-dir(rtl) {
+  border-radius: 10000px 0 0 10000px !important;
 }
 
-@conditionalForwardWithUrlbar@ > #back-button > menupopup {
-  margin-top: -1px;
+#back-button > menupopup {
+  margin-top: -1px !important;
 }
 
-@conditionalForwardWithUrlbar@ > #back-button > .toolbarbutton-icon {
-  border-radius: 10000px;
-  padding: 5px;
-  border: none;
-  background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
+#back-button > .toolbarbutton-icon {
+  border-radius: 10000px !important;
+  padding: 5px !important;
+  border: none !important;
+  background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)) !important;
   box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
               0 0 0 1px hsla(0,0%,100%,.3) inset,
               0 0 0 1px hsla(210,54%,20%,.25),
-              0 1px 0 hsla(210,54%,20%,.35);
-  transition-property: background-color, box-shadow;
-  transition-duration: 250ms;
+              0 1px 0 hsla(210,54%,20%,.35) !important;
+  transition-property: background-color, box-shadow !important;
 }
 
-@conditionalForwardWithUrlbar@ > #back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
-  background-color: hsla(210,48%,96%,.75);
+#back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
+  background-color: hsla(210,48%,96%,.75) !important;
   box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
               0 0 0 1px hsla(0,0%,100%,.3) inset,
               0 0 0 1px hsla(210,54%,20%,.3),
               0 1px 0 hsla(210,54%,20%,.4),
-              0 0 4px hsla(210,54%,20%,.2);
+              0 0 4px hsla(210,54%,20%,.2) !important;
 }
 
-@conditionalForwardWithUrlbar@ > #back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
-@conditionalForwardWithUrlbar@ > #back-button[open="true"] > .toolbarbutton-icon {
-  background-color: hsla(210,54%,20%,.15);
+#back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
+#back-button[open="true"] > .toolbarbutton-icon {
+  background-color: hsla(210,54%,20%,.15) !important;
   box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
               0 0 1px hsla(210,54%,20%,.2) inset,
               0 0 0 1px hsla(210,54%,20%,.4),
-              0 1px 0 hsla(210,54%,20%,.2);
+              0 1px 0 hsla(210,54%,20%,.2) !important;
   transition: none;
 }
 
-@conditionalForwardWithUrlbar@ > #back-button[disabled] > .toolbarbutton-icon {
+#main-window:not([customizing]) #back-button[disabled] > .toolbarbutton-icon {
   box-shadow: 0 0 0 1px hsla(210,54%,20%,.55),
-              0 1px 0 hsla(210,54%,20%,.65);
+              0 1px 0 hsla(210,54%,20%,.65) !important;
   transition: none;
 }
 
@@ -1059,97 +698,18 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   list-style-image: url("chrome://browser/skin/menu-forward.png") !important;
 }
 
-#stop-button {
-  -moz-image-region: rect(0, 54px, 18px, 36px);
-}
-
-#reload-button {
-  -moz-image-region: rect(0, 72px, 18px, 54px);
-}
-
 #home-button.bookmark-item {
   list-style-image: url("chrome://browser/skin/Toolbar.png");
 }
 #home-button.bookmark-item:-moz-lwtheme-brighttext {
   list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
 }
-#home-button {
-  -moz-image-region: rect(0, 90px, 18px, 72px);
-}
-
-#downloads-button {
-  -moz-image-region: rect(0, 108px, 18px, 90px);
-}
-
-#history-button {
-  -moz-image-region: rect(0, 126px, 18px, 108px);
-}
-
-#bookmarks-button,
-#bookmarks-menu-button {
-  -moz-image-region: rect(0, 144px, 18px, 126px);
-}
-
-#bookmarks-menu-button.bookmark-item {
-  list-style-image: url("chrome://browser/skin/Toolbar.png");
-}
-
-#bookmarks-menu-button.bookmark-item:-moz-lwtheme-brighttext {
-  list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
-}
-
-#print-button {
-  -moz-image-region: rect(0, 162px, 18px, 144px);
-}
-
-#new-tab-button {
-  -moz-image-region: rect(0, 180px, 18px, 162px);
-}
-
-#new-window-button {
-  -moz-image-region: rect(0, 198px, 18px, 180px);
-}
-
-#cut-button {
-  -moz-image-region: rect(0, 216px, 18px, 198px);
-}
-
-#copy-button {
-  -moz-image-region: rect(0, 234px, 18px, 216px);
-}
-
-#paste-button {
-  -moz-image-region: rect(0, 252px, 18px, 234px);
-}
-
-#fullscreen-button {
-  -moz-image-region: rect(0, 270px, 18px, 252px);
-}
-
-#zoom-out-button {
-  -moz-image-region: rect(0, 288px, 18px, 270px);
-}
 
-#zoom-in-button {
-  -moz-image-region: rect(0, 306px, 18px, 288px);
-}
-
-#sync-button {
-  -moz-image-region: rect(0, 324px, 18px, 306px);
-}
 #sync-button[status="active"] {
   list-style-image: url("chrome://browser/skin/sync-throbber.png");
   -moz-image-region: rect(0, 18px, 18px, 0);
 }
 
-#feed-button {
-  -moz-image-region: rect(0, 342px, 18px, 324px);
-}
-
-#webrtc-status-button {
-  -moz-image-region: rect(0, 360px, 18px, 342px);
-}
-
 /* tabview button & menu item */
 
 #tabview-button,
@@ -1157,10 +717,6 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   list-style-image: url(chrome://browser/skin/tabview/tabview.png);
 }
 
-%ifdef WINDOWS_AERO
-:-moz-any(#TabsToolbar, #nav-bar[tabsontop=false], #toolbar-menubar) > #tabview-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme),
-:-moz-any(#TabsToolbar, #nav-bar[tabsontop=false], #toolbar-menubar) > toolbarpaletteitem > #tabview-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme),
-%endif
 #tabview-button:-moz-lwtheme-brighttext {
   list-style-image: url(chrome://browser/skin/tabview/tabview-inverted.png);
 }
@@ -1280,53 +836,53 @@ toolbar[mode=full] .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   color: black;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper {
   padding-left: @conditionalForwardWithUrlbarWidth@px;
   -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
   position: relative;
   pointer-events: none;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar {
   -moz-border-start: none;
   margin-left: 0;
   pointer-events: all;
 }
 
-@conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
   transition: margin-left @forwardTransitionLength@ ease-out;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
   border-top-left-radius: 0;
   border-bottom-left-radius: 0;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
   border-top-right-radius: 0;
   border-bottom-right-radius: 0;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
   clip-path: url("chrome://browser/content/browser.xul#windows-urlbar-back-button-clip-path");
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
   margin-left: -@conditionalForwardWithUrlbarWidth@px;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
   /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
   transition-delay: 100s;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar {
+@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar {
   /* when not hovered anymore, trigger a new transition to hide the forward button immediately */
   margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper:-moz-locale-dir(rtl),
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
   /* let windows-urlbar-back-button-mask clip the urlbar's right side for RTL */
   transform: scaleX(-1);
 }
@@ -1343,8 +899,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
 }
 
 #urlbar-container {
-  -moz-box-orient: horizontal;
-  -moz-box-align: stretch;
+  -moz-box-align: center;
 }
 
 .urlbar-textbox-container {
@@ -1385,7 +940,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
   background: transparent;
 }
 
-#urlbar-search-splitter + #urlbar-container > #urlbar ,
+#urlbar-search-splitter + #urlbar-container > #urlbar-wrapper > #urlbar,
 #urlbar-search-splitter + #search-container > #searchbar > .searchbar-textbox {
   -moz-margin-start: 0;
 }
@@ -1424,31 +979,31 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
   border-radius: 0;
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar > #identity-box {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box {
   border-radius: 0;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
   padding-left: 5px;
   transition: padding-left;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
   padding-right: 5px;
   transition: padding-right;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box {
+@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box {
   /* forward button hiding is delayed when hovered */
   transition-delay: 100s;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
   /* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
   padding-left: 5.01px;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
   /* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
   padding-right: 5.01px;
 }
@@ -1507,7 +1062,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar > #identity-box > #page-proxy-favicon {
+@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box > #page-proxy-favicon {
   -moz-margin-end: 1px;
 }
 
@@ -1611,7 +1166,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
 
 /* combined go/reload/stop button in location bar */
 
-#go-button,
 #urlbar > toolbarbutton {
   -moz-appearance: none;
   padding: 0 2px;
@@ -1620,10 +1174,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   list-style-image: url("chrome://browser/skin/reload-stop-go.png");
 }
 
-#go-button {
-  padding: 0 3px;
-}
-
 #urlbar-reload-button {
   -moz-image-region: rect(0, 14px, 14px, 0);
 }
@@ -1642,24 +1192,20 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   transform: scaleX(-1);
 }
 
-#go-button,
 #urlbar-go-button {
   -moz-image-region: rect(0, 42px, 14px, 28px);
 }
 
-#go-button:hover,
 #urlbar-go-button:hover {
   background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.2), hsla(110,70%,50%,0));
   -moz-image-region: rect(14px, 42px, 28px, 28px);
 }
 
-#go-button:hover:active,
 #urlbar-go-button:hover:active {
   background-image: radial-gradient(circle closest-side, hsla(110,70%,50%,.1), hsla(110,70%,50%,0));
   -moz-image-region: rect(28px, 42px, 42px, 28px);
 }
 
-#go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
 #urlbar-go-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
   transform: scaleX(-1);
 }
@@ -1703,11 +1249,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   height: 150px;
 }
 
-#social-share-button {
-  list-style-image: url(chrome://browser/skin/social/share-button.png);
-  -moz-image-region: rect(0, 16px, 16px, 0);
-}
-
 .social-share-toolbar {
   border-right: 1px solid #e2e5e8;
   background: linear-gradient(to bottom, #ffffff, #f5f7fa);
@@ -1807,25 +1348,36 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-/* star button */
+/* bookmarks menu-button */
 
-#star-button {
+#bookmarks-menu-button.bookmark-item {
   list-style-image: url("chrome://browser/skin/places/bookmark.png");
   -moz-image-region: rect(0px 16px 16px 0px);
 }
 
-#star-button:hover {
-  background-image: radial-gradient(circle closest-side, hsla(45,100%,73%,.3), hsla(45,100%,73%,0));
-  -moz-image-region: rect(0px 32px 16px 16px);
+#bookmarks-menu-button.bookmark-item[starred] {
+  -moz-image-region: rect(0px 48px 16px 32px);
 }
 
-#star-button:hover:active {
-  background-image: radial-gradient(circle closest-side, hsla(45,100%,73%,.1), hsla(45,100%,73%,0));
-  -moz-image-region: rect(0px 48px 16px 32px);
+#bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
+  -moz-margin-start: 5px;
+}
+
+#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
+  padding-top: 2px;
+  padding-bottom: 2px;
+}
+
+#BMB_bookmarksPopup[side="top"],
+#BMB_bookmarksPopup[side="bottom"] {
+  margin-left: -20px;
+  margin-right: -20px;
 }
 
-#star-button[starred] {
-  list-style-image: url("chrome://browser/skin/places/editBookmark.png");
+#BMB_bookmarksPopup[side="left"],
+#BMB_bookmarksPopup[side="right"] {
+  margin-top: -20px;
+  margin-bottom: -20px;
 }
 
 /* bookmarking panel */
@@ -1880,21 +1432,11 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
 
 .panel-promo-closebutton {
   -moz-appearance: none;
-  list-style-image: url("chrome://global/skin/icons/close.png");
-  -moz-image-region: rect(0, 16px, 16px, 0);
   border: none;
   -moz-margin-end: -10px;
   margin-top: -5px;
 }
 
-.panel-promo-closebutton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.panel-promo-closebutton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
 .panel-promo-closebutton > .toolbarbutton-text {
   padding: 0;
   margin: 0;
@@ -1916,23 +1458,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   text-shadow: none;
 }
 
-/* ::::: throbber ::::: */
-
-#navigator-throbber {
-  width: 16px;
-  min-height: 16px;
-  margin: 0 3px;
-}
-
-#navigator-throbber[busy="true"] {
-  list-style-image: url("chrome://global/skin/icons/loading_16.png");
-}
-
-#navigator-throbber,
-#wrapper-navigator-throbber > #navigator-throbber {
-  list-style-image: url("chrome://global/skin/icons/notloading_16.png");
-}
-
 /* Tabstrip */
 
 #TabsToolbar {
@@ -1940,9 +1465,12 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   padding: 0;
 }
 
-#TabsToolbar:not(:-moz-lwtheme),
-#TabsToolbar[tabsontop=false] {
-  background-image: linear-gradient(to top, @toolbarShadowColor@ 1px, rgba(0,0,0,.05) 1px, transparent 50%);
+#TabsToolbar:not(:-moz-lwtheme) {
+  background-image: linear-gradient(to top, @toolbarShadowColor@ 2px, rgba(0,0,0,.05) 2px, transparent 50%);
+}
+
+#main-window[tabsintitlebar] #TabsToolbar {
+  background-color: transparent;
 }
 
 %ifndef WINDOWS_AERO
@@ -1954,151 +1482,66 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
 }
 %endif
 
-.tabbrowser-tab,
-.tabs-newtab-button {
-  -moz-appearance: none;
-  background: @toolbarShadowOnTab@, @bgTabTexture@,
-              linear-gradient(-moz-dialog, -moz-dialog);
-  background-origin: border-box;
-  background-position: 1px 2px;
-  background-size: calc(100% - 2px) calc(100% - 2px);
-  background-repeat: no-repeat;
-  margin: 0;
-  padding: 2px 0 4px;
-  border-width: 4px 3px 0;
-  border-style: solid;
-  border-image: url(tabbrowser/tab.png) 4 3 0 fill repeat stretch;
-  border-radius: 0;
-}
-
-.tabbrowser-tab[remote] {
-  text-decoration: underline;
-}
-
-.tabbrowser-tab:hover,
-.tabs-newtab-button:hover {
-  background-image: @toolbarShadowOnTab@, @bgTabTextureHover@,
-                    linear-gradient(-moz-dialog, -moz-dialog);
-}
+%include ../shared/tabs.inc.css
 
 %ifndef WINDOWS_AERO
+/* Use lighter colors of buttons and text in the titlebar on luna-blue */
 @media (-moz-windows-theme: luna-blue) {
-  .tabbrowser-tab,
-  .tabs-newtab-button {
-    background-image: @toolbarShadowOnTab@,
-                      linear-gradient(hsla(51,34%,89%,.9), hsla(51,15%,79%,.9) 1px, hsla(51,9%,68%,.9));
+  #main-window[tabsintitlebar]:not([inFullscreen]) .tabbrowser-arrowscrollbox > .scrollbutton-up,
+  #main-window[tabsintitlebar]:not([inFullscreen]) .tabbrowser-arrowscrollbox > .scrollbutton-down {
+    list-style-image: url(chrome://browser/skin/tabbrowser/tab-arrow-left-inverted.png);
   }
 
-  .tabbrowser-tab:hover,
-  .tabs-newtab-button:hover {
-    background-image: @toolbarShadowOnTab@,
-                      linear-gradient(hsla(51,34%,100%,.9), hsla(51,15%,94%,.9) 1px, hsla(51,9%,83%,.9));
+  #main-window[tabsintitlebar]:not([inFullscreen]) .tabs-newtab-button,
+  #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar > #new-tab-button,
+  #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar > toolbarpaletteitem > #new-tab-button {
+    list-style-image: url(chrome://browser/skin/tabbrowser/newtab-inverted.png);
   }
-}
-%endif
-
-.tabbrowser-tab[selected="true"] {
-  background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 50%),
-                    linear-gradient(-moz-dialog, -moz-dialog);
-}
-
-#main-window[tabsontop=false]:not([disablechrome]) .tabbrowser-tab[selected=true]:not(:-moz-lwtheme) {
-  background-image: @toolbarShadowOnTab@,
-                    linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 50%),
-                    linear-gradient(-moz-dialog, -moz-dialog);
-}
 
-.tabbrowser-tab:-moz-lwtheme {
-  color: inherit;
-}
-
-.tabbrowser-tab[selected="true"]:-moz-lwtheme {
-  background-image: linear-gradient(@selectedTabHighlight@, @toolbarHighlight@ 50%);
-}
-
-.tabbrowser-tab:-moz-lwtheme-brighttext:not([selected="true"]),
-.tabs-newtab-button:-moz-lwtheme-brighttext {
-  background-image: linear-gradient(hsla(0,0%,40%,.6), hsla(0,0%,30%,.6) 80%);
-}
-
-.tabbrowser-tab:-moz-lwtheme-brighttext:not([selected="true"]):hover,
-.tabs-newtab-button:-moz-lwtheme-brighttext:hover {
-  background-image: linear-gradient(hsla(0,0%,60%,.6), hsla(0,0%,45%,.6) 80%);
-}
-
-.tabbrowser-tab:-moz-lwtheme-darktext:not([selected="true"]),
-.tabs-newtab-button:-moz-lwtheme-darktext {
-  background-image: linear-gradient(hsla(0,0%,60%,.5), hsla(0,0%,45%,.5) 80%);
-}
-
-.tabbrowser-tab:-moz-lwtheme-darktext:not([selected="true"]):hover,
-.tabs-newtab-button:-moz-lwtheme-darktext:hover {
-  background-image: linear-gradient(hsla(0,0%,80%,.5), hsla(0,0%,60%,.5) 80%);
-}
+  #main-window[tabsintitlebar]:not([inFullscreen]) #alltabs-button {
+    list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow-inverted.png");
+  }
 
-.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]) {
-  background-image: radial-gradient(circle farthest-corner at 50% 3px, rgba(255,255,255,1) 3%, rgba(186,221,251,.75) 40%, rgba(127,179,255,.5) 80%, rgba(127,179,255,.25));
-}
-.tabbrowser-tab[pinned][titlechanged]:not([selected="true"]):hover {
-  background-image: linear-gradient(hsla(0,0%,100%,.4), hsla(0,0%,75%,.4) 80%),
-                    radial-gradient(circle farthest-corner at 50% 3px, rgba(255,255,255,1) 3%, rgba(186,221,251,.75) 40%, rgba(127,179,255,.5) 80%, rgba(127,179,255,.25));
-}
+  #main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar > #tabview-button {
+    list-style-image: url(chrome://browser/skin/tabview/tabview-inverted.png);
+  }
 
-.tab-throbber,
-.tab-icon-image {
-  width: 16px;
-  height: 16px;
-  list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
-  -moz-margin-start: 2px;
-  -moz-margin-end: 3px;
-}
+  #main-window[tabsintitlebar]:not([inFullscreen]) .tab-close-button:not(:-moz-any(:hover,:-moz-lwtheme,[selected="true"])) {
+    -moz-image-region: rect(0, 64px, 16px, 48px);
+  }
 
-.tab-throbber {
-  list-style-image: url("chrome://browser/skin/tabbrowser/connecting.png");
+  #tabbrowser-tabs[movingtab] > .tabbrowser-tab[beforeselected]:not([last-visible-tab])::after,
+  .tabbrowser-tab:not([selected]):not([afterselected-visible]):not([afterhovered]):not([first-visible-tab]):not(:hover)::before,
+  #tabbrowser-tabs:not([overflow]) > .tabbrowser-tab[last-visible-tab]:not([selected]):not([beforehovered]):not(:hover)::after {
+    background-image: url("chrome://browser/skin/tabbrowser/tab-separator-luna-blue.png");
+  }
 }
+%endif
 
-.tab-throbber[progress] {
-  list-style-image: url("chrome://browser/skin/tabbrowser/loading.png");
+.tab-close-button:not(:hover):not([selected="true"]):-moz-lwtheme-brighttext {
+  -moz-image-region: rect(0, 64px, 16px, 48px) !important;
 }
 
-.tab-throbber[pinned],
-.tab-icon-image[pinned] {
-  -moz-margin-start: 5px;
-  -moz-margin-end: 5px;
+#main-window[tabsintitlebar]:not([inFullscreen]) .tabbrowser-tab:not([selected]):not(:-moz-lwtheme) {
+  color: CaptionText;
 }
 
 /* tabbrowser-tab focus ring */
-.tabbrowser-tab:focus > .tab-stack {
+.tabbrowser-tab:focus > .tab-stack > .tab-content > .tab-label {
   outline: 1px dotted;
 }
 
 /* Tab DnD indicator */
 .tab-drop-indicator {
   list-style-image: url(chrome://browser/skin/tabbrowser/tabDragIndicator.png);
-  margin-bottom: -11px;
+  margin-bottom: -9px;
+  z-index: 3;
 }
 
 /* Tab close button */
 .tab-close-button {
   -moz-appearance: none;
-  -moz-image-region: rect(0, 64px, 16px, 48px);
   border: none;
-  padding: 0px;
-  list-style-image: url("chrome://global/skin/icons/close.png");
-}
-
-.tab-close-button:hover,
-.tab-close-button:hover[selected="true"] {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.tab-close-button:hover:active,
-.tab-close-button:hover:active[selected="true"] {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
-.tab-close-button[selected="true"] {
-  -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 /* Tab scrollbox arrow, tabstrip new tab and all-tabs buttons */
@@ -2112,10 +1555,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   background-origin: border-box;
 }
 
-%ifdef WINDOWS_AERO
-.tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-system-metric(windows-compositor):not(:-moz-lwtheme),
-.tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-system-metric(windows-compositor):not(:-moz-lwtheme),
-%endif
 .tabbrowser-arrowscrollbox > .scrollbutton-up:-moz-lwtheme-brighttext,
 .tabbrowser-arrowscrollbox > .scrollbutton-down:-moz-lwtheme-brighttext {
   list-style-image: url(chrome://browser/skin/tabbrowser/tab-arrow-left-inverted.png);
@@ -2159,20 +1598,12 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   -moz-image-region: auto;
 }
 
-%ifdef WINDOWS_AERO
-#TabsToolbar > #new-tab-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme),
-#TabsToolbar > toolbarpaletteitem > #new-tab-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme),
-%endif
 .tabs-newtab-button:-moz-lwtheme-brighttext,
 #TabsToolbar > #new-tab-button:-moz-lwtheme-brighttext,
 #TabsToolbar > toolbarpaletteitem > #new-tab-button:-moz-lwtheme-brighttext {
   list-style-image: url(chrome://browser/skin/tabbrowser/newtab-inverted.png);
 }
 
-.tabs-newtab-button {
-  width: 28px;
-}
-
 #TabsToolbar > #new-tab-button {
   width: 26px;
 }
@@ -2181,10 +1612,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow.png");
 }
 
-%ifdef WINDOWS_AERO
-:-moz-any(#TabsToolbar, #nav-bar[tabsontop=false], #toolbar-menubar) > #alltabs-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme),
-:-moz-any(#TabsToolbar, #nav-bar[tabsontop=false], #toolbar-menubar) > toolbarpaletteitem > #alltabs-button:-moz-system-metric(windows-compositor):not(:-moz-lwtheme),
-%endif
 #alltabs-button:-moz-lwtheme-brighttext {
   list-style-image: url("chrome://browser/skin/toolbarbutton-dropdown-arrow-inverted.png");
 }
@@ -2218,8 +1645,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
 /* Tabstrip close button */
 .tabs-closebutton {
   -moz-appearance: none;
-  list-style-image: url("chrome://global/skin/icons/close.png");
-  -moz-image-region: rect(0, 16px, 16px, 0);
   padding: 4px 2px;
   margin: 0px;
   border: none;
@@ -2231,14 +1656,6 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
   -moz-padding-start: 2px !important;
 }
 
-.tabs-closebutton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.tabs-closebutton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
 toolbarbutton.chevron {
   list-style-image: url("chrome://global/skin/toolbar/chevron.gif") !important;
 }
@@ -2256,10 +1673,6 @@ toolbarbutton.chevron > .toolbarbutton-icon {
   margin: 0;
 }
 
-toolbar[mode="text"] toolbarbutton.chevron > .toolbarbutton-icon {
-  display: -moz-box; /* display chevron icon in text mode */
-}
-
 #sidebar-throbber[loading="true"] {
   list-style-image: url("chrome://global/skin/icons/loading_16.png");
   -moz-margin-end: 4px;
@@ -2508,7 +1921,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
   -moz-margin-end: -8px;
 }
 
-@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box {
   padding-left: 5px;
 }
 
@@ -2635,8 +2048,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
 }
 
 /* Bookmarks roots menu-items */
-#appmenu_subscribeToPage:not([disabled]),
-#appmenu_subscribeToPageMenu,
 #subscribeToPageMenuitem:not([disabled]),
 #subscribeToPageMenupopup,
 #BMB_subscribeToPageMenuitem:not([disabled]),
@@ -2645,14 +2056,14 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
 }
 
 #bookmarksToolbarFolderMenu,
-#appmenu_bookmarksToolbar,
-#BMB_bookmarksToolbar {
+#BMB_bookmarksToolbar,
+#panelMenu_bookmarksToolbar {
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
   -moz-image-region: auto;
 }
 
-#appmenu_unsortedBookmarks,
-#BMB_unsortedBookmarks {
+#BMB_unsortedBookmarks,
+#panelMenu_unsortedBookmarks {
   list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png");
   -moz-image-region: auto;
 }
@@ -2721,54 +2132,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
   margin-top: .5em;
 }
 
-/* Add-on bar */
-
-#addon-bar {
-  -moz-appearance: none;
-  min-height: 20px;
-  border-top-style: none;
-  border-bottom-style: none;
-  padding-top: 1px;
-  background-image: linear-gradient(rgba(0,0,0,.15) 1px, rgba(255,255,255,.15) 1px);
-  background-size: 100% 2px;
-  background-repeat: no-repeat;
-}
-
-#status-bar {
-  -moz-appearance: none;
-  background-color: transparent;
-  border: none;
-  min-height: 0;
-}
-
-#addon-bar[customizing] > #status-bar {
-  opacity: .5;
-  background-image: repeating-linear-gradient(135deg,
-                                              rgba(255,255,255,.3), rgba(255,255,255,.3) 5px,
-                                              rgba(0,0,0,.3) 5px, rgba(0,0,0,.3) 10px);
-}
-
-#status-bar > statusbarpanel {
-  border-width: 0;
-  -moz-appearance: none;
-}
-
-#addonbar-closebutton {
-  border: none;
-  padding: 0 5px;
-  list-style-image: url("chrome://global/skin/icons/close.png");
-  -moz-appearance: none;
-  -moz-image-region: rect(0, 16px, 16px, 0);
-}
-
-#addonbar-closebutton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-#addonbar-closebutton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
 /* Status panel */
 
 .statuspanel-label {
@@ -2860,7 +2223,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
   position: relative;
 }
 
-@navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-badge-container {
+#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container {
   padding: 2px 5px;
 }
 
@@ -2892,7 +2255,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
   right: 0;
 }
 
-@navbarLargeIcons@ *|* > .toolbarbutton-badge[badge]:not([badge=""])::after {
+#nav-bar .toolbarbutton-badge[badge]:not([badge=""])::after {
   top: 1px;
   right: 1px;
 }
@@ -2902,7 +2265,7 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
   right: auto;
 }
 
-@navbarLargeIcons@ *|* > .toolbarbutton-badge[badge]:not([badge=""]):-moz-locale-dir(rtl)::after {
+#nav-bar .toolbarbutton-badge[badge]:not([badge=""]):-moz-locale-dir(rtl)::after {
   left: 1px;
   right: auto;
 }
@@ -3017,20 +2380,32 @@ chatbox {
   border-top-right-radius: 2.5px;
 }
 
-#main-window[privatebrowsingmode=temporary] #toolbar-menubar {
-  background-image: url("chrome://browser/skin/privatebrowsing-dark.png");
-  background-position: top right;
-  background-repeat: no-repeat;
+/* Customization mode */
+
+%include ../shared/customizableui/customizeMode.inc.css
+
+#main-window[customizing] {
+  background-image: url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png");
+  background-attachment: fixed;
 }
 
-#main-window[privatebrowsingmode=temporary] #toolbar-menubar:-moz-locale-dir(rtl) {
-  background-position: top left;
+#main-window:-moz-any([customize-entering],[customize-entered]) #tab-view-deck {
+  padding: 0 2em 2em;
 }
 
-#main-window[privatebrowsingmode=temporary] #appmenu-button > .button-box > .box-inherit > .button-icon {
-  list-style-image: url("chrome://browser/skin/privatebrowsing-light.png");
-  width: 20px;
-  height: 16px;
+#customization-container {
+  border-left: 1px solid @toolbarShadowColor@;
+  border-right: 1px solid @toolbarShadowColor@;
+  background-clip: padding-box;
+}
+
+/* End customization mode */
+
+#main-window[privatebrowsingmode=temporary] #TabsToolbar::after {
+  content: "";
+  display: -moz-box;
+  width: 40px;
+  background: url("chrome://browser/skin/privatebrowsing-indicator.png") no-repeat center center;
 }
 
 %include ../shared/UITour.inc.css
diff --git a/browser/themes/windows/customizableui/background-noise-toolbar.png b/browser/themes/windows/customizableui/background-noise-toolbar.png
new file mode 100644
index 0000000000000000000000000000000000000000..d09ba9dafb5ede66e92ce577ecaa6f9575dba104
Binary files /dev/null and b/browser/themes/windows/customizableui/background-noise-toolbar.png differ
diff --git a/browser/themes/windows/customizableui/customizeMode-gridTexture.png b/browser/themes/windows/customizableui/customizeMode-gridTexture.png
new file mode 100644
index 0000000000000000000000000000000000000000..a7c2775cfc799da31a505b249f5a59b89c148a58
Binary files /dev/null and b/browser/themes/windows/customizableui/customizeMode-gridTexture.png differ
diff --git a/browser/themes/windows/customizableui/customizeMode-separatorHorizontal.png b/browser/themes/windows/customizableui/customizeMode-separatorHorizontal.png
new file mode 100644
index 0000000000000000000000000000000000000000..5e17cb4db08e310e6c3a9e14c5bd722772dfb639
Binary files /dev/null and b/browser/themes/windows/customizableui/customizeMode-separatorHorizontal.png differ
diff --git a/browser/themes/windows/customizableui/customizeMode-separatorVertical.png b/browser/themes/windows/customizableui/customizeMode-separatorVertical.png
new file mode 100644
index 0000000000000000000000000000000000000000..dc4caee812878f246c87d71093768eb36c5656fc
Binary files /dev/null and b/browser/themes/windows/customizableui/customizeMode-separatorVertical.png differ
diff --git a/browser/themes/windows/customizableui/panelUIOverlay.css b/browser/themes/windows/customizableui/panelUIOverlay.css
new file mode 100644
index 0000000000000000000000000000000000000000..d66a8e0aa1360f4cbe6237c52ca197165b571559
--- /dev/null
+++ b/browser/themes/windows/customizableui/panelUIOverlay.css
@@ -0,0 +1,30 @@
+/* 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/customizableui/panelUIOverlay.inc.css
+
+#PanelUI-contents #zoom-out-btn {
+  padding-left: 12px;
+  padding-right: 12px;
+}
+
+#PanelUI-contents #zoom-in-btn {
+  padding-left: 12px;
+  padding-right: 12px;
+}
+
+#BMB_bookmarksPopup > menu,
+#BMB_bookmarksPopup > menuitem {
+  padding-top: 1px;
+  padding-bottom: 1px;
+}
+
+#BMB_bookmarksPopup > menu > .menu-text,
+#BMB_bookmarksPopup > menuitem > .menu-text,
+#BMB_bookmarksPopup > menu > .menu-iconic-text,
+#BMB_bookmarksPopup > menuitem > .menu-iconic-text,
+#BMB_bookmarksPopup > menuseparator {
+  padding-top: 0;
+  padding-bottom: 0;
+}
diff --git a/browser/themes/windows/downloads/indicator-aero.css b/browser/themes/windows/downloads/indicator-aero.css
index bcb72c8ae4a32182b519e21d5890b86905ecbd54..1c466e1dbf0be954fdacdbae9df4290711b3a7a0 100644
--- a/browser/themes/windows/downloads/indicator-aero.css
+++ b/browser/themes/windows/downloads/indicator-aero.css
@@ -6,30 +6,20 @@
   /* The following rules are for the downloads indicator when in its normal,
      non-downloading, non-paused state (ie, it's just showing the downloads
      button icon). */
-  #toolbar-menubar #downloads-button:not([attention]) > #downloads-indicator-anchor > #downloads-indicator-icon:not(:-moz-lwtheme),
-  #TabsToolbar[tabsontop=true] #downloads-button:not([attention]) > #downloads-indicator-anchor > #downloads-indicator-icon:not(:-moz-lwtheme),
-  #navigator-toolbox[tabsontop=false] > #nav-bar #downloads-button:not([attention]) > #downloads-indicator-anchor > #downloads-indicator-icon:not(:-moz-lwtheme),
-  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child #downloads-button:not([attention]) > #downloads-indicator-anchor > #downloads-indicator-icon:not(:-moz-lwtheme),
+  :-moz-any(#toolbar-menubar, #TabsToolbar) #downloads-button:not([attention]) > #downloads-indicator-anchor > #downloads-indicator-icon:not(:-moz-lwtheme),
 
   /* The following rules are for the downloads indicator when in its paused
      or undetermined progress state. We use :not([counter]) as a shortcut for
      :-moz-any([progress], [paused]). */
 
-  /* This is the case where the downloads indicator has been moved next to the menubar */
+  /* This is the case where the downloads indicator has been moved next to the menubar as well as
+     the case where the downloads indicator is in the tabstrip toolbar. */
   #toolbar-menubar #downloads-button:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter,
-  /* This is the case where the downloads indicator is in the tabstrip toolbar with tabs on top. */
-  #TabsToolbar[tabsontop=true] #downloads-button:not(:-moz-lwtheme):not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter,
-  /* This is the case where the downloads indicator is anywhere in the nav-bar with tabs on bottom. */
-  #navigator-toolbox[tabsontop=false] > #nav-bar #downloads-button:not(:-moz-lwtheme):not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter,
-  /* This is the case where the downloads indicator is in the tabstrip when the tabstrip is the last item in the toolbox (and is therefore over glass) */
-  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child #downloads-button:not(:-moz-lwtheme):not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
-    background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 108, 18, 90);
+  #TabsToolbar #downloads-button:not(:-moz-lwtheme):not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
+    background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 198, 18, 180);
   }
 
-  #toolbar-menubar #downloads-indicator-counter:not(:-moz-lwtheme),
-  #TabsToolbar[tabsontop=true] #downloads-indicator-counter:not(:-moz-lwtheme),
-  #navigator-toolbox[tabsontop=false] > #nav-bar #downloads-indicator-counter:not(:-moz-lwtheme),
-  #nav-bar + #customToolbars + #PersonalToolbar[collapsed=true] + #TabsToolbar[tabsontop=false]:last-child #downloads-indicator-counter:not(:-moz-lwtheme) {
+  :-moz-any(#toolbar-menubar, #TabsToolbar) #downloads-indicator-counter:not(:-moz-lwtheme) {
     color: white;
     text-shadow: 0 0 1px rgba(0,0,0,.7),
                  0 1px 1.5px rgba(0,0,0,.5);
diff --git a/browser/themes/windows/downloads/indicator.css b/browser/themes/windows/downloads/indicator.css
index b989a0e90cdb25085d773a9bf84d48b3a172b074..90b22d45ae5b019ce9e745df23d0eb39f7c73f86 100644
--- a/browser/themes/windows/downloads/indicator.css
+++ b/browser/themes/windows/downloads/indicator.css
@@ -21,14 +21,14 @@
 
 #downloads-indicator-icon {
   background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
-                              0, 108, 18, 90) center no-repeat;
+                              0, 198, 18, 180) center no-repeat;
   min-width: 18px;
   min-height: 18px;
 }
 
 #downloads-indicator-icon:-moz-lwtheme-brighttext {
   background: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"),
-                              0, 108, 18, 90) center no-repeat;
+                              0, 198, 18, 180) center no-repeat;
 }
 
 #downloads-button[attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
@@ -40,10 +40,15 @@
 
 #downloads-button:not([counter]) > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
   background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
-                              0, 108, 18, 90) center no-repeat;
+                              0, 198, 18, 180) center no-repeat;
   background-size: 12px;
 }
 
+#downloads-button:not([counter]) > #downloads-indicator-anchor >
+#downloads-button-progress-area > #downloads-indicator-counter:-moz-lwtheme-brighttext {
+  background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 198, 18, 180);
+}
+
 #downloads-button:not([counter])[attention] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
   background-image: url("chrome://browser/skin/downloads/download-glow.png");
 }
@@ -153,8 +158,3 @@
 #downloads-button[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
   background-image: linear-gradient(#4b5000, #515700);
 }
-
-toolbar[mode="full"] > #downloads-button[indicator] > .toolbarbutton-text {
-  margin: 0;
-  text-align: center;
-}
diff --git a/browser/themes/windows/jar.mn b/browser/themes/windows/jar.mn
index c3db1b6a4473be9661a5de1a2098550a3ab0e280..1df89b3b33310524e7f80884a9ad131e73120b17 100644
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -22,10 +22,13 @@ browser.jar:
 #endif
         skin/classic/browser/aboutTabCrashed.css
         skin/classic/browser/actionicon-tab.png
-        skin/classic/browser/appmenu-icons.png
-        skin/classic/browser/appmenu-dropmarker.png
 *       skin/classic/browser/browser.css
+*       skin/classic/browser/browser-lightweightTheme.css
         skin/classic/browser/click-to-play-warning-stripes.png
+        skin/classic/browser/customizableui/background-noise-toolbar.png  (customizableui/background-noise-toolbar.png)
+        skin/classic/browser/customizableui/customizeMode-gridTexture.png  (customizableui/customizeMode-gridTexture.png)
+        skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png  (customizableui/customizeMode-separatorHorizontal.png)
+        skin/classic/browser/customizableui/customizeMode-separatorVertical.png  (customizableui/customizeMode-separatorVertical.png)
 *       skin/classic/browser/engineManager.css
         skin/classic/browser/fullscreen-darknoise.png
         skin/classic/browser/Geolocation-16.png
@@ -42,6 +45,11 @@ browser.jar:
         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
+        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
@@ -58,8 +66,7 @@ browser.jar:
         skin/classic/browser/Privacy-16.png
         skin/classic/browser/Privacy-32.png
         skin/classic/browser/Privacy-48.png
-        skin/classic/browser/privatebrowsing-light.png
-        skin/classic/browser/privatebrowsing-dark.png
+        skin/classic/browser/privatebrowsing-indicator.png
         skin/classic/browser/reload-stop-go.png
         skin/classic/browser/searchbar.css
         skin/classic/browser/searchbar-dropdown-arrow.png
@@ -68,6 +75,7 @@ browser.jar:
         skin/classic/browser/slowStartup-16.png
         skin/classic/browser/Toolbar.png
         skin/classic/browser/Toolbar-inverted.png
+        skin/classic/browser/Toolbar-lunaSilver.png
         skin/classic/browser/toolbarbutton-dropdown-arrow.png
         skin/classic/browser/toolbarbutton-dropdown-arrow-inverted.png
         skin/classic/browser/urlbar-arrow.png
@@ -79,6 +87,7 @@ browser.jar:
         skin/classic/browser/webRTC-shareDevice-16.png
         skin/classic/browser/webRTC-shareDevice-64.png
         skin/classic/browser/webRTC-sharingDevice-16.png
+*       skin/classic/browser/customizableui/panelUIOverlay.css       (customizableui/panelUIOverlay.css)
 *       skin/classic/browser/downloads/allDownloadsViewOverlay.css   (downloads/allDownloadsViewOverlay.css)
         skin/classic/browser/downloads/buttons.png                   (downloads/buttons.png)
         skin/classic/browser/downloads/contentAreaDownloadsView.css  (downloads/contentAreaDownloadsView.css)
@@ -99,7 +108,6 @@ browser.jar:
         skin/classic/browser/newtab/controls.png                     (newtab/controls.png)
         skin/classic/browser/places/places.css                       (places/places.css)
 *       skin/classic/browser/places/organizer.css                    (places/organizer.css)
-        skin/classic/browser/places/editBookmark.png                 (places/editBookmark.png)
         skin/classic/browser/places/bookmark.png                     (places/bookmark.png)
         skin/classic/browser/places/query.png                        (places/query.png)
         skin/classic/browser/places/bookmarksMenu.png                (places/bookmarksMenu.png)
@@ -130,18 +138,30 @@ browser.jar:
         skin/classic/browser/preferences/aboutPermissions.css        (preferences/aboutPermissions.css)
         skin/classic/browser/social/services-16.png                  (social/services-16.png)
         skin/classic/browser/social/services-64.png                  (social/services-64.png)
-        skin/classic/browser/social/share-button.png                 (social/share-button.png)
-        skin/classic/browser/social/share-button-active.png          (social/share-button-active.png)
         skin/classic/browser/social/chat-icons.png                   (social/chat-icons.png)
         skin/classic/browser/tabbrowser/newtab.png                   (tabbrowser/newtab.png)
         skin/classic/browser/tabbrowser/newtab-inverted.png          (tabbrowser/newtab-inverted.png)
         skin/classic/browser/tabbrowser/connecting.png               (tabbrowser/connecting.png)
         skin/classic/browser/tabbrowser/loading.png                  (tabbrowser/loading.png)
         skin/classic/browser/tabbrowser/tab.png                      (tabbrowser/tab.png)
+        skin/classic/browser/tabbrowser/tab-active-middle.png        (tabbrowser/tab-active-middle.png)
         skin/classic/browser/tabbrowser/tab-arrow-left.png           (tabbrowser/tab-arrow-left.png)
         skin/classic/browser/tabbrowser/tab-arrow-left-inverted.png  (tabbrowser/tab-arrow-left-inverted.png)
+        skin/classic/browser/tabbrowser/tab-background-start.png     (tabbrowser/tab-background-start.png)
+        skin/classic/browser/tabbrowser/tab-background-middle.png    (tabbrowser/tab-background-middle.png)
+        skin/classic/browser/tabbrowser/tab-background-end.png       (tabbrowser/tab-background-end.png)
         skin/classic/browser/tabbrowser/tab-overflow-border.png      (tabbrowser/tab-overflow-border.png)
+
+# NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in
+#       Makefile.in with a non-default marker of "%" and the result of that gets packaged.
+        skin/classic/browser/tabbrowser/tab-selected-end.svg         (tab-selected-end.svg)
+        skin/classic/browser/tabbrowser/tab-selected-start.svg       (tab-selected-start.svg)
+
+        skin/classic/browser/tabbrowser/tab-stroke-end.png           (tabbrowser/tab-stroke-end.png)
+        skin/classic/browser/tabbrowser/tab-stroke-start.png         (tabbrowser/tab-stroke-start.png)
         skin/classic/browser/tabbrowser/tabDragIndicator.png         (tabbrowser/tabDragIndicator.png)
+        skin/classic/browser/tabbrowser/tab-separator-luna-blue.png  (tabbrowser/tab-separator-luna-blue.png)
+        skin/classic/browser/tabbrowser/tab-separator.png            (tabbrowser/tab-separator.png)
         skin/classic/browser/tabview/close.png                      (tabview/close.png)
         skin/classic/browser/tabview/edit-light.png                 (tabview/edit-light.png)
         skin/classic/browser/tabview/grain.png                      (tabview/grain.png)
@@ -300,10 +320,13 @@ browser.jar:
 #endif
         skin/classic/aero/browser/aboutTabCrashed.css
         skin/classic/aero/browser/actionicon-tab.png
-        skin/classic/aero/browser/appmenu-dropmarker.png
-        skin/classic/aero/browser/appmenu-icons.png
 *       skin/classic/aero/browser/browser.css                        (browser-aero.css)
+*       skin/classic/aero/browser/browser-lightweightTheme.css
         skin/classic/aero/browser/click-to-play-warning-stripes.png
+        skin/classic/aero/browser/customizableui/background-noise-toolbar.png  (customizableui/background-noise-toolbar.png)
+        skin/classic/aero/browser/customizableui/customizeMode-gridTexture.png  (customizableui/customizeMode-gridTexture.png)
+        skin/classic/aero/browser/customizableui/customizeMode-separatorHorizontal.png  (customizableui/customizeMode-separatorHorizontal.png)
+        skin/classic/aero/browser/customizableui/customizeMode-separatorVertical.png  (customizableui/customizeMode-separatorVertical.png)
 *       skin/classic/aero/browser/engineManager.css
         skin/classic/aero/browser/fullscreen-darknoise.png
         skin/classic/aero/browser/Geolocation-16.png
@@ -320,6 +343,11 @@ browser.jar:
         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                      (menuPanel-aero.png)
+        skin/classic/aero/browser/menuPanel-customize.png
+        skin/classic/aero/browser/menuPanel-exit.png
+        skin/classic/aero/browser/menuPanel-help.png
+        skin/classic/aero/browser/menuPanel-small.png                (menuPanel-small-aero.png)
         skin/classic/aero/browser/mixed-content-blocked-16.png
         skin/classic/aero/browser/mixed-content-blocked-64.png
         skin/classic/aero/browser/monitor.png
@@ -336,16 +364,15 @@ browser.jar:
         skin/classic/aero/browser/Privacy-16.png                     (Privacy-16-aero.png)
         skin/classic/aero/browser/Privacy-32.png                     (Privacy-32-aero.png)
         skin/classic/aero/browser/Privacy-48.png                     (Privacy-48-aero.png)
-        skin/classic/aero/browser/privatebrowsing-light.png
-        skin/classic/aero/browser/privatebrowsing-dark.png
+        skin/classic/aero/browser/privatebrowsing-indicator.png
         skin/classic/aero/browser/reload-stop-go.png
         skin/classic/aero/browser/searchbar.css
         skin/classic/aero/browser/searchbar-dropdown-arrow.png       (searchbar-dropdown-arrow-aero.png)
         skin/classic/aero/browser/Secure24.png                       (Secure24-aero.png)
         skin/classic/aero/browser/setDesktopBackground.css
         skin/classic/aero/browser/slowStartup-16.png
-        skin/classic/aero/browser/Toolbar.png
-        skin/classic/aero/browser/Toolbar-inverted.png
+        skin/classic/aero/browser/Toolbar.png                        (Toolbar-aero.png)
+        skin/classic/aero/browser/Toolbar-inverted.png               (Toolbar-inverted-aero.png)
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow-inverted.png
         skin/classic/aero/browser/urlbar-arrow.png
@@ -357,6 +384,7 @@ browser.jar:
         skin/classic/aero/browser/webRTC-shareDevice-16.png
         skin/classic/aero/browser/webRTC-shareDevice-64.png
         skin/classic/aero/browser/webRTC-sharingDevice-16.png
+*       skin/classic/aero/browser/customizableui/panelUIOverlay.css  (customizableui/panelUIOverlay.css)
 *       skin/classic/aero/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay-aero.css)
         skin/classic/aero/browser/downloads/buttons.png              (downloads/buttons-aero.png)
         skin/classic/aero/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
@@ -378,7 +406,6 @@ browser.jar:
 *       skin/classic/aero/browser/places/places.css                  (places/places-aero.css)
 *       skin/classic/aero/browser/places/organizer.css               (places/organizer-aero.css)
         skin/classic/aero/browser/places/bookmark.png                (places/bookmark.png)
-        skin/classic/aero/browser/places/editBookmark.png            (places/editBookmark.png)
         skin/classic/aero/browser/places/query.png                   (places/query-aero.png)
         skin/classic/aero/browser/places/bookmarksMenu.png           (places/bookmarksMenu-aero.png)
         skin/classic/aero/browser/places/bookmarksToolbar.png        (places/bookmarksToolbar-aero.png)
@@ -408,18 +435,29 @@ browser.jar:
         skin/classic/aero/browser/preferences/aboutPermissions.css   (preferences/aboutPermissions.css)
         skin/classic/aero/browser/social/services-16.png             (social/services-16.png)
         skin/classic/aero/browser/social/services-64.png             (social/services-64.png)
-        skin/classic/aero/browser/social/share-button.png            (social/share-button.png)
-        skin/classic/aero/browser/social/share-button-active.png     (social/share-button-active.png)
         skin/classic/aero/browser/social/chat-icons.png              (social/chat-icons.png)
         skin/classic/aero/browser/tabbrowser/newtab.png              (tabbrowser/newtab.png)
         skin/classic/aero/browser/tabbrowser/newtab-inverted.png     (tabbrowser/newtab-inverted.png)
         skin/classic/aero/browser/tabbrowser/connecting.png          (tabbrowser/connecting.png)
         skin/classic/aero/browser/tabbrowser/loading.png             (tabbrowser/loading.png)
         skin/classic/aero/browser/tabbrowser/tab.png                 (tabbrowser/tab.png)
+        skin/classic/aero/browser/tabbrowser/tab-active-middle.png   (tabbrowser/tab-active-middle.png)
         skin/classic/aero/browser/tabbrowser/tab-arrow-left.png      (tabbrowser/tab-arrow-left.png)
         skin/classic/aero/browser/tabbrowser/tab-arrow-left-inverted.png (tabbrowser/tab-arrow-left-inverted.png)
+        skin/classic/aero/browser/tabbrowser/tab-background-start.png    (tabbrowser/tab-background-start.png)
+        skin/classic/aero/browser/tabbrowser/tab-background-middle.png   (tabbrowser/tab-background-middle.png)
+        skin/classic/aero/browser/tabbrowser/tab-background-end.png      (tabbrowser/tab-background-end.png)
         skin/classic/aero/browser/tabbrowser/tab-overflow-border.png (tabbrowser/tab-overflow-border.png)
+
+# NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in
+#       Makefile.in with a non-default marker of "%" and the result of that gets packaged.
+        skin/classic/aero/browser/tabbrowser/tab-selected-end.svg    (tab-selected-end-aero.svg)
+        skin/classic/aero/browser/tabbrowser/tab-selected-start.svg  (tab-selected-start-aero.svg)
+
+        skin/classic/aero/browser/tabbrowser/tab-stroke-end.png      (tabbrowser/tab-stroke-end.png)
+        skin/classic/aero/browser/tabbrowser/tab-stroke-start.png    (tabbrowser/tab-stroke-start.png)
         skin/classic/aero/browser/tabbrowser/tabDragIndicator.png    (tabbrowser/tabDragIndicator.png)
+        skin/classic/aero/browser/tabbrowser/tab-separator.png       (tabbrowser/tab-separator-aero.png)
         skin/classic/aero/browser/tabview/close.png                  (tabview/close.png)
         skin/classic/aero/browser/tabview/edit-light.png             (tabview/edit-light.png)
         skin/classic/aero/browser/tabview/grain.png                  (tabview/grain.png)
diff --git a/browser/themes/windows/menuPanel-aero.png b/browser/themes/windows/menuPanel-aero.png
new file mode 100644
index 0000000000000000000000000000000000000000..59061ec0aaa38b85dddacb4c31f257c4ad43ecf5
Binary files /dev/null and b/browser/themes/windows/menuPanel-aero.png differ
diff --git a/browser/themes/windows/menuPanel-customize.png b/browser/themes/windows/menuPanel-customize.png
new file mode 100644
index 0000000000000000000000000000000000000000..e0b0a70a3b82a18c974bd1bc5f1dff863405dd61
Binary files /dev/null and b/browser/themes/windows/menuPanel-customize.png differ
diff --git a/browser/themes/windows/menuPanel-exit.png b/browser/themes/windows/menuPanel-exit.png
new file mode 100644
index 0000000000000000000000000000000000000000..6359d7262a286a34074f6f245636ad15a95993b5
Binary files /dev/null and b/browser/themes/windows/menuPanel-exit.png differ
diff --git a/browser/themes/windows/menuPanel-help.png b/browser/themes/windows/menuPanel-help.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d23717748de84d681bfabd3c326420931a90e84
Binary files /dev/null and b/browser/themes/windows/menuPanel-help.png differ
diff --git a/browser/themes/windows/menuPanel-small-aero.png b/browser/themes/windows/menuPanel-small-aero.png
new file mode 100644
index 0000000000000000000000000000000000000000..4cd3e52b13d26ae5c4d85cb3ed3c00cd6c70f2ab
Binary files /dev/null and b/browser/themes/windows/menuPanel-small-aero.png differ
diff --git a/browser/themes/windows/menuPanel-small.png b/browser/themes/windows/menuPanel-small.png
new file mode 100644
index 0000000000000000000000000000000000000000..a9fe97171b8328cf9646aabb320c6c9097a5b448
Binary files /dev/null and b/browser/themes/windows/menuPanel-small.png differ
diff --git a/browser/themes/windows/menuPanel.png b/browser/themes/windows/menuPanel.png
new file mode 100644
index 0000000000000000000000000000000000000000..31d8d282579eea1379dcb5d918159b5fe43587d6
Binary files /dev/null and b/browser/themes/windows/menuPanel.png differ
diff --git a/browser/themes/windows/newtab/newTab.css b/browser/themes/windows/newtab/newTab.css
index 024bccfd9d2d2498d544c5387dd59065fdc22af8..69258a39642749b60fe117d6ca6abfdf5e0ecddf 100644
--- a/browser/themes/windows/newtab/newTab.css
+++ b/browser/themes/windows/newtab/newTab.css
@@ -57,19 +57,9 @@
   -moz-appearance: none;
   padding: 0;
   border: none;
-  list-style-image: url("chrome://global/skin/icons/close.png");
-  -moz-image-region: rect(0, 16px, 16px, 0);
   -moz-user-focus: normal;
 }
 
-#newtab-undo-close-button:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-#newtab-undo-close-button:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
 #newtab-undo-close-button > .toolbarbutton-text {
   display: none;
 }
diff --git a/browser/themes/windows/places/editBookmark.png b/browser/themes/windows/places/editBookmark.png
deleted file mode 100644
index fbca0523df169b6892d2b5050035152fb6b92606..0000000000000000000000000000000000000000
Binary files a/browser/themes/windows/places/editBookmark.png and /dev/null differ
diff --git a/browser/themes/windows/places/organizer-aero.css b/browser/themes/windows/places/organizer-aero.css
index 645aff64b4b3827563e3901bb4f6e2f31a502ce5..502573a463a1bd42006b01f3419059f7c4e38d0a 100644
--- a/browser/themes/windows/places/organizer-aero.css
+++ b/browser/themes/windows/places/organizer-aero.css
@@ -2,11 +2,12 @@
  * 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/. */
 
+%define WINDOWS_AERO
+%include ../windowsShared.inc
 %include organizer.css
+%undef WINDOWS_AERO
 
 %filter substitution
-%define toolbarHighlight rgba(255,255,255,.5)
-%define customToolbarColor hsl(210,75%,92%)
 
 #placesView {
   border-top: none;
diff --git a/browser/themes/windows/places/organizer.css b/browser/themes/windows/places/organizer.css
index 4ccdc1b5c00d0cacf368102c2b8364703c1201c1..ae20999296c3fac29f7cd334999df980ae6c1cf7 100644
--- a/browser/themes/windows/places/organizer.css
+++ b/browser/themes/windows/places/organizer.css
@@ -18,11 +18,11 @@
 }
 
 #back-button {
-  -moz-image-region: rect(0, 18px, 18px, 0);
+  -moz-image-region: rect(0, 54px, 18px, 36px);
 }
 
 #forward-button {
-  -moz-image-region: rect(0, 36px, 18px, 18px);
+  -moz-image-region: rect(0, 72px, 18px, 54px);
 }
 
 #back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
diff --git a/browser/themes/windows/privatebrowsing-dark.png b/browser/themes/windows/privatebrowsing-indicator.png
similarity index 100%
rename from browser/themes/windows/privatebrowsing-dark.png
rename to browser/themes/windows/privatebrowsing-indicator.png
diff --git a/browser/themes/windows/privatebrowsing-light.png b/browser/themes/windows/privatebrowsing-light.png
deleted file mode 100644
index c12f50779858230c939f5f96582437fd60e82610..0000000000000000000000000000000000000000
Binary files a/browser/themes/windows/privatebrowsing-light.png and /dev/null differ
diff --git a/browser/themes/windows/social/share-button-active.png b/browser/themes/windows/social/share-button-active.png
deleted file mode 100644
index e819a740bf2e8a837d5f09e2e3c84b159acd508f..0000000000000000000000000000000000000000
Binary files a/browser/themes/windows/social/share-button-active.png and /dev/null differ
diff --git a/browser/themes/windows/social/share-button.png b/browser/themes/windows/social/share-button.png
deleted file mode 100644
index 931874dc36ca2057d91682fd6d69af3e42356ed1..0000000000000000000000000000000000000000
Binary files a/browser/themes/windows/social/share-button.png and /dev/null differ
diff --git a/browser/themes/windows/tabbrowser/tab-active-middle.png b/browser/themes/windows/tabbrowser/tab-active-middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..be90ec0a12bf4efc43674e34c6d6c928f6bca98d
Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-active-middle.png differ
diff --git a/browser/themes/windows/tabbrowser/tab-background-end.png b/browser/themes/windows/tabbrowser/tab-background-end.png
new file mode 100644
index 0000000000000000000000000000000000000000..d78b44c0ef10d9509ce234203b6a96c69ad25bda
Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-background-end.png differ
diff --git a/browser/themes/windows/tabbrowser/tab-background-middle.png b/browser/themes/windows/tabbrowser/tab-background-middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..86a4ab4d0acac486d3ea84b15467bce39b44df86
Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-background-middle.png differ
diff --git a/browser/themes/windows/tabbrowser/tab-background-start.png b/browser/themes/windows/tabbrowser/tab-background-start.png
new file mode 100644
index 0000000000000000000000000000000000000000..7898b2b225a0ae9f9a6df197e2d0cceb13dd3f7d
Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-background-start.png differ
diff --git a/browser/themes/windows/tabbrowser/tab-separator-aero.png b/browser/themes/windows/tabbrowser/tab-separator-aero.png
new file mode 100644
index 0000000000000000000000000000000000000000..af4403a500a0e320d1fac2c4d7b9196c9f8973eb
Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-separator-aero.png differ
diff --git a/browser/themes/windows/tabbrowser/tab-separator-luna-blue.png b/browser/themes/windows/tabbrowser/tab-separator-luna-blue.png
new file mode 100644
index 0000000000000000000000000000000000000000..2f8cae3b3251af8c85416c09ec2b7d3b094594e2
Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-separator-luna-blue.png differ
diff --git a/browser/themes/windows/tabbrowser/tab-separator.png b/browser/themes/windows/tabbrowser/tab-separator.png
new file mode 100644
index 0000000000000000000000000000000000000000..c76c615fc18c37261e76ab39db98b18e19c67013
Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-separator.png differ
diff --git a/browser/themes/windows/tabbrowser/tab-stroke-end.png b/browser/themes/windows/tabbrowser/tab-stroke-end.png
new file mode 100644
index 0000000000000000000000000000000000000000..763f43195a6424856df5d181c8954ab1d47dc08b
Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-stroke-end.png differ
diff --git a/browser/themes/windows/tabbrowser/tab-stroke-start.png b/browser/themes/windows/tabbrowser/tab-stroke-start.png
new file mode 100644
index 0000000000000000000000000000000000000000..91f533dfcce43df0f3baa7526f8a6be240564f6b
Binary files /dev/null and b/browser/themes/windows/tabbrowser/tab-stroke-start.png differ
diff --git a/browser/themes/windows/windowsShared.inc b/browser/themes/windows/windowsShared.inc
new file mode 100644
index 0000000000000000000000000000000000000000..d614535a0ee985285b774f9eaea3c37f7840056f
--- /dev/null
+++ b/browser/themes/windows/windowsShared.inc
@@ -0,0 +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/. */
+
+%filter substitution
+
+%define toolbarHighlight rgba(253,253,253,0.45)
+%define fgTabTexture linear-gradient(transparent, transparent 2px, rgba(254,254,254,0.72) 2px, rgba(254,254,254,0.72) 2px, rgba(250,250,250,0.88) 3px, rgba(250,250,250,0.88) 3px, rgba(254,254,254,0.72) 4px, rgba(254,254,254,0.72) 4px, @toolbarHighlight@)
+%define fgTabBackgroundColor -moz-dialog
+%define fgTabTextureLWT @fgTabTexture@
+
+% Aero-only defines
+%define customToolbarColor hsl(210,75%,92%)
diff --git a/gfx/src/nsThemeConstants.h b/gfx/src/nsThemeConstants.h
index 8e11e8af20631e6bfc9e96cbd6dc2bc99f9d4218..d1003c5ad2d46829d91c58eaffda249dcca1d556 100644
--- a/gfx/src/nsThemeConstants.h
+++ b/gfx/src/nsThemeConstants.h
@@ -249,8 +249,9 @@
 #define NS_THEME_WIN_MEDIA_TOOLBOX                         222
 #define NS_THEME_WIN_BROWSER_TAB_BAR_TOOLBOX               223
 
-// Unified toolbar on the Mac
+// Unified toolbar and titlebar elements on the Mac
 #define NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR                   224
+#define NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON                 226
 
 // Vista glass
 #define NS_THEME_WIN_BORDERLESS_GLASS                      229
diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp
index d8c934cabebfead1460434bec0ed4d9d713bfd56..636a371517739273bd9e8d0ed356a43f05d1fb8d 100644
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2196,14 +2196,20 @@ nsDisplayThemedBackground::nsDisplayThemedBackground(nsDisplayListBuilder* aBuil
   const nsStyleDisplay* disp = mFrame->StyleDisplay();
   mAppearance = disp->mAppearance;
   mFrame->IsThemed(disp, &mThemeTransparency);
+
   // Perform necessary RegisterThemeGeometry
-  if (mAppearance == NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR ||
-      mAppearance == NS_THEME_TOOLBAR ||
-      mAppearance == NS_THEME_WINDOW_TITLEBAR) {
-    RegisterThemeGeometry(aBuilder, aFrame);
-  } else if (mAppearance == NS_THEME_WIN_BORDERLESS_GLASS ||
-             mAppearance == NS_THEME_WIN_GLASS) {
-    aBuilder->SetGlassDisplayItem(this);
+  switch (disp->mAppearance) {
+    case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR:
+    case NS_THEME_TOOLBAR:
+    case NS_THEME_WINDOW_TITLEBAR:
+    case NS_THEME_WINDOW_BUTTON_BOX:
+    case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON:
+      RegisterThemeGeometry(aBuilder, aFrame);
+      break;
+    case NS_THEME_WIN_BORDERLESS_GLASS:
+    case NS_THEME_WIN_GLASS:
+      aBuilder->SetGlassDisplayItem(this);
+      break;
   }
 
   mBounds = GetBoundsInternal();
diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h
index 03ec0e796a6533adee483440a86a1f02d9d2933c..62b8bdb502c76adb914483ac2c6dbede37732c11 100644
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -105,6 +105,7 @@ CSS_KEY(-moz-list, _moz_list)
 CSS_KEY(-moz-mac-chrome-active, _moz_mac_chrome_active)
 CSS_KEY(-moz-mac-chrome-inactive, _moz_mac_chrome_inactive)
 CSS_KEY(-moz-mac-focusring, _moz_mac_focusring)
+CSS_KEY(-moz-mac-fullscreen-button, _moz_mac_fullscreen_button)
 CSS_KEY(-moz-mac-menuselect, _moz_mac_menuselect)
 CSS_KEY(-moz-mac-menushadow, _moz_mac_menushadow)
 CSS_KEY(-moz-mac-menutextdisable, _moz_mac_menutextdisable)
diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp
index 40e5ed6e69d7af1f1e5753f86f5ae4a07735624e..0d2bd43d609e217cce2a9e5e030204f126b38efb 100644
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -611,6 +611,7 @@ const int32_t nsCSSProps::kAppearanceKTable[] = {
   eCSSKeyword__moz_win_glass,         NS_THEME_WIN_GLASS,
   eCSSKeyword__moz_win_borderless_glass,      NS_THEME_WIN_BORDERLESS_GLASS,
   eCSSKeyword__moz_mac_unified_toolbar,       NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR,
+  eCSSKeyword__moz_mac_fullscreen_button,     NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON,
   eCSSKeyword__moz_window_titlebar,           NS_THEME_WINDOW_TITLEBAR,
   eCSSKeyword__moz_window_titlebar_maximized, NS_THEME_WINDOW_TITLEBAR_MAXIMIZED,
   eCSSKeyword__moz_window_frame_left,         NS_THEME_WINDOW_FRAME_LEFT,
diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js
index 6d8516161fd0a2e9165027c51445c017d57c3cb4..a410fdde3a6574feefdfbc7a5a9c30024317c072 100644
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3981,6 +3981,8 @@ pref("ui.panel.default_level_parent", true);
 
 pref("mousewheel.system_scroll_override_on_root_content.enabled", false);
 
+pref("ui.key.menuAccessKeyFocuses", true);
+
 # XP_UNIX
 #endif
 #endif
diff --git a/toolkit/components/alerts/resources/content/alert.xul b/toolkit/components/alerts/resources/content/alert.xul
index 7538be0afbdeb4153d3f3fa63d78fab280947453..6850aa50a2715125eac560e11bf786431491c9d8 100644
--- a/toolkit/components/alerts/resources/content/alert.xul
+++ b/toolkit/components/alerts/resources/content/alert.xul
@@ -36,7 +36,7 @@
     </box>
 
     <vbox class="alertCloseBox">
-      <toolbarbutton class="alertCloseButton"
+      <toolbarbutton class="alertCloseButton close-icon"
                      tooltiptext="&closeAlert.tooltip;"
                      onclick="event.stopPropagation();"
                      oncommand="close();"/>
diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json
index b5f3a84db0f02a3ebecc4ec9474bd70159565cc3..0d89d6761170ad709b1caf1f39a753a211cb8e66 100644
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -2714,12 +2714,12 @@
     "n_buckets": 20,
     "description": "Firefox: Time in ms spent on switching tabs in response to a tab click"
   },
-  "FX_APP_MENU_OPEN_MS": {
+  "FX_IDENTITY_POPUP_OPEN_MS": {
     "kind": "exponential",
     "high": "1000",
     "n_buckets": 10,
     "extended_statistics_ok": true,
-    "description": "Firefox: Time taken by the app-menu opening in milliseconds"
+    "description": "Firefox: Time taken by the identity popup to open in milliseconds"
   },
   "FX_BOOKMARKS_TOOLBAR_INIT_MS": {
     "kind": "exponential",
diff --git a/toolkit/content/widgets/findbar.xml b/toolkit/content/widgets/findbar.xml
index 750caff8eca7c536a1aea833d8ea7d8e037724f4..649716d1550f2216a111c5c571353d60ce8e210d 100644
--- a/toolkit/content/widgets/findbar.xml
+++ b/toolkit/content/widgets/findbar.xml
@@ -194,7 +194,7 @@
       <xul:label anonid="match-case-status" class="findbar-find-fast"/>
     </xul:hbox>
     <xul:toolbarbutton anonid="find-closebutton"
-                       class="findbar-closebutton"
+                       class="findbar-closebutton close-icon"
                        tooltiptext="&findCloseButton.tooltip;"
                        oncommand="close();"/>
     </content>
diff --git a/toolkit/content/widgets/notification.xml b/toolkit/content/widgets/notification.xml
index 55511cc64b05b6970d9e638b1de50fffa50b1cd9..1256e55d732fc7885155dd3d37f910a534bb3928 100644
--- a/toolkit/content/widgets/notification.xml
+++ b/toolkit/content/widgets/notification.xml
@@ -370,7 +370,7 @@
           <children/>
         </xul:hbox>
         <xul:toolbarbutton ondblclick="event.stopPropagation();"
-                           class="messageCloseButton tabbable"
+                           class="messageCloseButton close-icon tabbable"
                            xbl:inherits="hidden=hideclose"
                            tooltiptext="&closeNotification.tooltip;"
                            oncommand="document.getBindingParent(this).close();"/>
@@ -466,7 +466,7 @@
             <xul:menupopup anonid="menupopup"
                            xbl:inherits="oncommand=menucommand">
               <children/>
-              <xul:menuitem class="menuitem-iconic popup-notification-closeitem"
+              <xul:menuitem class="menuitem-iconic popup-notification-closeitem close-icon"
                             label="&closeNotificationItem.label;"
                             xbl:inherits="oncommand=closeitemcommand"/>
             </xul:menupopup>
@@ -475,7 +475,7 @@
       </xul:vbox>
       <xul:vbox pack="start">
         <xul:toolbarbutton anonid="closebutton"
-                           class="messageCloseButton popup-notification-closebutton tabbable"
+                           class="messageCloseButton close-icon popup-notification-closebutton tabbable"
                            xbl:inherits="oncommand=closebuttoncommand"
                            tooltiptext="&closeNotification.tooltip;"/>
       </xul:vbox>
diff --git a/toolkit/content/widgets/scrollbox.xml b/toolkit/content/widgets/scrollbox.xml
index ea5f90cc0bba0e5039356b5ba166e769f2f14960..8f2acb41600359991ef1148b31d5501277685a65 100644
--- a/toolkit/content/widgets/scrollbox.xml
+++ b/toolkit/content/widgets/scrollbox.xml
@@ -222,6 +222,12 @@
             bottom: scrollPaddingRect.bottom - parseFloat(style.paddingBottom)
           };
 
+          // Provide an entry point for derived bindings to adjust these values.
+          if (this._adjustElementStartAndEnd) {
+            [elementStart, elementEnd] =
+              this._adjustElementStartAndEnd(element, elementStart, elementEnd);
+          }
+
           if (elementStart <= (vertical ? scrollContentRect.top : scrollContentRect.left)) {
             elementStart = vertical ? scrollPaddingRect.top : scrollPaddingRect.left;
           }
diff --git a/toolkit/content/widgets/toolbar.xml b/toolkit/content/widgets/toolbar.xml
index 935cb0e7bf90daa8756c5545fb81d9c0c402afcc..17158c2c9f553742cf97d0c6fbde8415faaeb68b 100644
--- a/toolkit/content/widgets/toolbar.xml
+++ b/toolkit/content/widgets/toolbar.xml
@@ -404,6 +404,9 @@
       <constructor>
         this._setInactive();
       </constructor>
+      <destructor>
+        this._setActive();
+      </destructor>
 
       <field name="_inactiveTimeout">null</field>
 
diff --git a/toolkit/content/widgets/toolbarbutton.xml b/toolkit/content/widgets/toolbarbutton.xml
index 857461c43675e8915933ff620b74fd22342862a9..e11c29d1b6dff747aa0a34ef0baf3aba54cbc407 100644
--- a/toolkit/content/widgets/toolbarbutton.xml
+++ b/toolkit/content/widgets/toolbarbutton.xml
@@ -60,7 +60,7 @@
       <xul:toolbarbutton class="box-inherit toolbarbutton-menubutton-button"
                          anonid="button" flex="1" allowevents="true"
                          xbl:inherits="disabled,crop,image,label,accesskey,command,
-                                       align,dir,pack,orient"/>
+                                       align,dir,pack,orient,tooltiptext=buttontooltiptext"/>
       <xul:dropmarker type="menu-button" class="toolbarbutton-menubutton-dropmarker"
                       xbl:inherits="align,dir,pack,orient,disabled,label,open"/>
     </content>
@@ -72,5 +72,15 @@
       <xul:image class="toolbarbutton-icon" xbl:inherits="src=image"/>
     </content>
   </binding>
+
+  <binding id="toolbarbutton-wrapping-label"
+           extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
+    <content>
+      <children includes="observes|template|menupopup|panel|tooltip"/>
+      <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
+      <xul:label class="toolbarbutton-text toolbarbutton-label" flex="1"
+                 xbl:inherits="xbl:text=label,accesskey"/>
+    </content>
+  </binding>
     
 </bindings>
diff --git a/toolkit/content/xul.css b/toolkit/content/xul.css
index 6201a7c06060e29e648a963558a0a29f27174992..53674ab828151e6cd813949affddc32c7ae1d03d 100644
--- a/toolkit/content/xul.css
+++ b/toolkit/content/xul.css
@@ -157,6 +157,10 @@ toolbarbutton[type="menu-button"] {
   -moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#menu-button");
 }
 
+toolbarbutton[type="wrap"] {
+  -moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton-wrapping-label");
+}
+
 toolbar[mode="icons"] .toolbarbutton-text,
 toolbar[mode="text"] .toolbarbutton-icon {
   display: none;
@@ -690,7 +694,7 @@ label.text-link, label[onclick] {
   -moz-user-focus: normal;
 }
 
-label[control], label.radio-label, label.checkbox-label {
+label[control], label.radio-label, label.checkbox-label, label.toolbarbutton-label {
   -moz-binding: url("chrome://global/content/bindings/text.xml#label-control");
 }
 
diff --git a/toolkit/modules/LightweightThemeConsumer.jsm b/toolkit/modules/LightweightThemeConsumer.jsm
index c10313efa65dc4136f3a9502b0e7a016e8fcbd88..0e3f8fbd59406c15940fe399ba8dc3955aa7f960 100644
--- a/toolkit/modules/LightweightThemeConsumer.jsm
+++ b/toolkit/modules/LightweightThemeConsumer.jsm
@@ -41,6 +41,23 @@ LightweightThemeConsumer.prototype = {
   _lastData: null,
   _lastScreenWidth: null,
   _lastScreenHeight: null,
+  _enabled: true,
+#ifdef XP_MACOSX
+  _chromemarginDefault: undefined,
+#endif
+
+  enable: function() {
+    this._enabled = true;
+    this._update(this._lastData);
+  },
+
+  disable: function() {
+    // Dance to keep the data, but reset the applied styles:
+    let lastData = this._lastData
+    this._update(null);
+    this._enabled = false;
+    this._lastData = lastData;
+  },
 
   observe: function (aSubject, aTopic, aData) {
     if (aTopic != "lightweight-theme-styling-update")
@@ -80,6 +97,8 @@ LightweightThemeConsumer.prototype = {
       this._lastData = aData;
       aData = LightweightThemeImageOptimizer.optimize(aData, this._win.screen);
     }
+    if (!this._enabled)
+      return;
 
     var root = this._doc.documentElement;
     var active = !!aData.headerURL;
@@ -110,10 +129,21 @@ LightweightThemeConsumer.prototype = {
     }
 
 #ifdef XP_MACOSX
-    if (active)
-      root.setAttribute("drawintitlebar", "true");
-    else
-      root.removeAttribute("drawintitlebar");
+    // Sample whether or not we draw in the titlebar by default the first time we update.
+    // If the root has no chromemargin attribute, getAttribute will return null, and
+    // we'll remove the attribute when the lw-theme is deactivated.
+    if (this._chromemarginDefault === undefined)
+      this._chromemarginDefault = root.getAttribute("chromemargin");
+
+    if (active) {
+      root.setAttribute("chromemargin", "0,-1,-1,-1");
+    }
+    else {
+      if (this._chromemarginDefault)
+        root.setAttribute("chromemargin", this._chromemarginDefault);
+      else
+        root.removeAttribute("chromemargin");
+    }
 #endif
   }
 }
diff --git a/toolkit/themes/linux/global/icons/notloading_16.png b/toolkit/themes/linux/global/icons/notloading_16.png
deleted file mode 100644
index 04dab30ed37c3adc05e20068ccf5bf0f46dbf803..0000000000000000000000000000000000000000
Binary files a/toolkit/themes/linux/global/icons/notloading_16.png and /dev/null differ
diff --git a/toolkit/themes/linux/global/inContentUI.css b/toolkit/themes/linux/global/inContentUI.css
index 98a430ee7adcb40ceadc22460f177465d15bcc3c..784ed4dd6bdd687bafa0a8e8cf9fbb3a90a9504c 100644
--- a/toolkit/themes/linux/global/inContentUI.css
+++ b/toolkit/themes/linux/global/inContentUI.css
@@ -9,14 +9,13 @@
 @namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
 @namespace html url("http://www.w3.org/1999/xhtml");
 
-
 /* Page background */
 *|*:root {
   -moz-appearance: none;
   padding: 18px;
   background-color: Window;
-  background-image: linear-gradient(rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0) 160px),
-                    linear-gradient(-moz-dialog, Window 160px);
+  background-image: /* Texture */
+                    url("chrome://global/skin/inContentUI/background-texture.png");
   color: WindowText;
 }
 
diff --git a/toolkit/themes/linux/global/jar.mn b/toolkit/themes/linux/global/jar.mn
index 5bd2732e6691eed8f73186ad3b43c0b9e79ded13..3332135d9bf5f74ec6deb9b2ec81ecb2e514a98f 100644
--- a/toolkit/themes/linux/global/jar.mn
+++ b/toolkit/themes/linux/global/jar.mn
@@ -45,7 +45,6 @@ toolkit.jar:
 +  skin/classic/global/icons/blacklist_large.png               (icons/blacklist_large.png)
 +  skin/classic/global/icons/find.png                          (icons/find.png)
 +  skin/classic/global/icons/loading_16.png                    (icons/loading_16.png)
-+  skin/classic/global/icons/notloading_16.png                 (icons/notloading_16.png)
 +  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)
diff --git a/toolkit/themes/osx/global/alerts/alert.css b/toolkit/themes/osx/global/alerts/alert.css
index e19d881e77fde264e92c77bbad4137bc2eb15d37..8e30e1885306b52c9b3fdedf3360d809d0d920d2 100644
--- a/toolkit/themes/osx/global/alerts/alert.css
+++ b/toolkit/themes/osx/global/alerts/alert.css
@@ -92,20 +92,9 @@ label {
   -moz-appearance: none;
   padding: 0;
   margin: 2px;
-  list-style-image: url("chrome://global/skin/icons/close.png");
   border: none;
-  -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 .alertCloseButton > .toolbarbutton-text {
   display: none;
 }
-
-.alertCloseButton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.alertCloseButton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
diff --git a/toolkit/themes/osx/global/findBar.css b/toolkit/themes/osx/global/findBar.css
index 7acc18786665c11916908604a84921382a6addcd..89041af18a4d9e0073ef15263994fde752327f60 100644
--- a/toolkit/themes/osx/global/findBar.css
+++ b/toolkit/themes/osx/global/findBar.css
@@ -52,35 +52,12 @@ label.findbar-find-fast:-moz-lwtheme,
   -moz-margin-start: 4px;
   -moz-padding-start: 0;
   -moz-padding-end: 8px;
-  list-style-image: url("chrome://global/skin/icons/close.png");
   border: none;
-  -moz-image-region: rect(0, 16px, 16px, 0);
   /* make sure the closebutton is displayed as the first element in the bar: */
   -moz-box-ordinal-group: 0;
 }
 
-.findbar-closebutton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.findbar-closebutton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
 @media (min-resolution: 2dppx) {
-  .findbar-closebutton {
-    list-style-image: url("chrome://global/skin/icons/close@2x.png");
-    -moz-image-region: rect(0, 32px, 32px, 0);
-  }
-
-  .findbar-closebutton:hover {
-    -moz-image-region: rect(0, 64px, 32px, 32px);
-  }
-
-  .findbar-closebutton:hover:active {
-    -moz-image-region: rect(0, 96px, 32px, 64px);
-  }
-
   .findbar-closebutton > .toolbarbutton-icon {
     width: 16px;
   }
diff --git a/toolkit/themes/osx/global/global.css b/toolkit/themes/osx/global/global.css
index 30f89de3821ed815339fe17da198bdb188c15459..3812de95c7790242be322043f115feccbd25fd62 100644
--- a/toolkit/themes/osx/global/global.css
+++ b/toolkit/themes/osx/global/global.css
@@ -335,3 +335,33 @@ notification > button > .button-box > .button-text {
 .popup-internal-box > autorepeatbutton[disabled="true"] {
   visibility: collapse;
 }
+
+/* :::::: Close button icons ::::: */
+
+.close-icon {
+  list-style-image: url("chrome://global/skin/icons/close.png");
+  -moz-image-region: rect(0, 16px, 16px, 0);
+}
+
+.close-icon:hover {
+  -moz-image-region: rect(0, 32px, 16px, 16px);
+}
+
+.close-icon:hover:active {
+  -moz-image-region: rect(0, 48px, 16px, 32px);
+}
+
+@media (min-resolution: 2dppx) {
+  .close-icon {
+    list-style-image: url("chrome://global/skin/icons/close@2x.png");
+    -moz-image-region: rect(0, 32px, 32px, 0);
+  }
+
+  .close-icon:hover {
+    -moz-image-region: rect(0, 64px, 32px, 32px);
+  }
+
+  .close-icon:hover:active {
+    -moz-image-region: rect(0, 96px, 32px, 64px);
+  }
+}
diff --git a/toolkit/themes/osx/global/icons/close.png b/toolkit/themes/osx/global/icons/close.png
index 9d5b280f258346cfcc848d37380478c57307f965..d58f23bac1f29a8efc2047633e9edeacc59ed25b 100644
Binary files a/toolkit/themes/osx/global/icons/close.png and b/toolkit/themes/osx/global/icons/close.png differ
diff --git a/toolkit/themes/osx/global/icons/notloading_16.png b/toolkit/themes/osx/global/icons/notloading_16.png
deleted file mode 100644
index ece0ee18a1cffa9bccdd9eae5146b48df48819c4..0000000000000000000000000000000000000000
Binary files a/toolkit/themes/osx/global/icons/notloading_16.png and /dev/null differ
diff --git a/toolkit/themes/osx/global/jar.mn b/toolkit/themes/osx/global/jar.mn
index a83da864a69ed6e97a4ae09e4469607042b5b3d4..190224dddfbe5d64849637972f809ae1afb08826 100644
--- a/toolkit/themes/osx/global/jar.mn
+++ b/toolkit/themes/osx/global/jar.mn
@@ -112,7 +112,6 @@ toolkit.jar:
   skin/classic/global/icons/information-large.png                    (icons/information-large.png)
   skin/classic/global/icons/loading_16.png                           (icons/loading_16.png)
   skin/classic/global/icons/menulist-dropmarker.png                  (icons/menulist-dropmarker.png)
-  skin/classic/global/icons/notloading_16.png                        (icons/notloading_16.png)
   skin/classic/global/icons/notfound.png                             (icons/notfound.png)
   skin/classic/global/icons/panebutton-active.png                    (icons/panebutton-active.png)
   skin/classic/global/icons/panebutton-inactive.png                  (icons/panebutton-inactive.png)
diff --git a/toolkit/themes/osx/global/notification.css b/toolkit/themes/osx/global/notification.css
index 3557ed97adcdb1d808e9a0718da8d61880611a08..ee507becbbf17eb96df1d5f218c698182f6453ae 100644
--- a/toolkit/themes/osx/global/notification.css
+++ b/toolkit/themes/osx/global/notification.css
@@ -65,23 +65,13 @@ notification[type="critical"] {
   -moz-appearance: none;
   padding: 0;
   margin: 0 2px;
-  list-style-image: url("chrome://global/skin/icons/close.png");
   border: none;
-  -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
 .messageCloseButton > .toolbarbutton-text {
   display: none;
 }
 
-.messageCloseButton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.messageCloseButton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
 .messageCloseButton:-moz-focusring > .toolbarbutton-icon {
   border-radius: 10000px;
   box-shadow: 0 0 2px 1px -moz-mac-focusring,
@@ -89,19 +79,6 @@ notification[type="critical"] {
 }
 
 @media (min-resolution: 2dppx) {
-  .messageCloseButton {
-    list-style-image: url("chrome://global/skin/icons/close@2x.png");
-    -moz-image-region: rect(0, 32px, 32px, 0);
-  }
-
-  .messageCloseButton:hover {
-    -moz-image-region: rect(0, 64px, 32px, 32px);
-  }
-
-  .messageCloseButton:hover:active {
-    -moz-image-region: rect(0, 96px, 32px, 64px);
-  }
-
   .messageCloseButton > .toolbarbutton-icon {
     width: 16px;
   }
diff --git a/toolkit/themes/osx/global/toolbarbutton.css b/toolkit/themes/osx/global/toolbarbutton.css
index a369527145ad79e16cc2cade75863176e0286771..ae73d8efa98361b0afe04cde24d86e2d3f3e7702 100644
--- a/toolkit/themes/osx/global/toolbarbutton.css
+++ b/toolkit/themes/osx/global/toolbarbutton.css
@@ -34,16 +34,6 @@ toolbarbutton[disabled="true"][open="true"] {
   color: -moz-mac-disabledtoolbartext !important;
 }
 
-/* ..... checked state ..... */
-
-toolbarbutton[checked="true"] {
-    background-color: #DDDDDD;
-    background-image: none;
-    border-right: 1px solid #b9b9b9;
-    border-left: 1px solid #b9b9b9;
-    color: ButtonText !important;
-}
-
 /* ::::: toolbarbutton menu ::::: */
 
 .toolbarbutton-menu-dropmarker {
diff --git a/toolkit/themes/windows/global/alerts/alert.css b/toolkit/themes/windows/global/alerts/alert.css
index 8271681240323f0a985254782e748319f9795b60..06f36038f7aa9526e67059f96f1df03eba0ec2b6 100644
--- a/toolkit/themes/windows/global/alerts/alert.css
+++ b/toolkit/themes/windows/global/alerts/alert.css
@@ -78,9 +78,7 @@ label {
 }
 
 .alertCloseButton {
-  list-style-image: url("chrome://global/skin/icons/close.png");
   -moz-appearance: none;
-  -moz-image-region: rect(0, 16px, 16px, 0);
   padding: 4px 2px;
   border: none !important;
 }
@@ -88,12 +86,3 @@ label {
 .alertCloseButton > .toolbarbutton-text {
   display: none;
 }
-
-.alertCloseButton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.alertCloseButton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
diff --git a/toolkit/themes/windows/global/findBar.css b/toolkit/themes/windows/global/findBar.css
index 86de66ed0d612162b41455d90765dd714acb3e8c..d59dca39522754beebfee6e63c9779229f3f1dc4 100644
--- a/toolkit/themes/windows/global/findBar.css
+++ b/toolkit/themes/windows/global/findBar.css
@@ -35,18 +35,9 @@ findbar[hidden] {
   -moz-padding-start: 0;
   -moz-padding-end: 8px;
   border: none;
-  list-style-image: url("chrome://global/skin/icons/close.png");
   -moz-appearance: none;
-  -moz-image-region: rect(0, 16px, 16px, 0);
 }
 
-.findbar-closebutton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.findbar-closebutton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
 
 /* Search field */
 
diff --git a/toolkit/themes/windows/global/global.css b/toolkit/themes/windows/global/global.css
index b23f7a5c65dfe09fa1cd4006448f78d2d35fef00..8c551d0fe77ebd74d72fb26743bd298ae44b5d7d 100644
--- a/toolkit/themes/windows/global/global.css
+++ b/toolkit/themes/windows/global/global.css
@@ -321,3 +321,38 @@ label[disabled="true"]:-moz-system-metric(windows-classic) {
   background-position: left bottom;
 %endif
 }
+
+/* :::::: Close button icons ::::: */
+
+.close-icon {
+  list-style-image: url("chrome://global/skin/icons/close.png");
+  -moz-image-region: rect(0, 16px, 16px, 0);
+}
+
+.close-icon:hover {
+  -moz-image-region: rect(0, 32px, 16px, 16px);
+}
+
+.close-icon:hover:active {
+  -moz-image-region: rect(0, 48px, 16px, 32px);
+}
+
+%ifdef XP_WIN
+@media (-moz-windows-theme: luna-blue) {
+  .close-icon {
+    list-style-image: url("chrome://global/skin/icons/close-lunaBlue.png");
+  }
+}
+
+@media (-moz-windows-theme: luna-olive) {
+  .close-icon {
+    list-style-image: url("chrome://global/skin/icons/close-lunaOlive.png");
+  }
+}
+
+@media (-moz-windows-theme: luna-silver) {
+  .close-icon {
+    list-style-image: url("chrome://global/skin/icons/close-lunaSilver.png");
+  }
+}
+%endif
diff --git a/toolkit/themes/windows/global/icons/close-lunaBlue.png b/toolkit/themes/windows/global/icons/close-lunaBlue.png
new file mode 100644
index 0000000000000000000000000000000000000000..b657c47e44f9e2b6c75dfc7c7f59a181977e760f
Binary files /dev/null and b/toolkit/themes/windows/global/icons/close-lunaBlue.png differ
diff --git a/toolkit/themes/windows/global/icons/close-lunaOlive.png b/toolkit/themes/windows/global/icons/close-lunaOlive.png
new file mode 100644
index 0000000000000000000000000000000000000000..b071b141b5db14b87eafcbd7d5f5cac19ae82a68
Binary files /dev/null and b/toolkit/themes/windows/global/icons/close-lunaOlive.png differ
diff --git a/toolkit/themes/windows/global/icons/close-lunaSilver.png b/toolkit/themes/windows/global/icons/close-lunaSilver.png
new file mode 100644
index 0000000000000000000000000000000000000000..36cbda9ab129b3905b2d0f7ac9bca924107b54a9
Binary files /dev/null and b/toolkit/themes/windows/global/icons/close-lunaSilver.png differ
diff --git a/toolkit/themes/windows/global/icons/close-win8.png b/toolkit/themes/windows/global/icons/close-win8.png
new file mode 100644
index 0000000000000000000000000000000000000000..803e148b73b19b591bc8cb46289592f453fb1e50
Binary files /dev/null and b/toolkit/themes/windows/global/icons/close-win8.png differ
diff --git a/toolkit/themes/windows/global/icons/close.png b/toolkit/themes/windows/global/icons/close.png
index e559a7003923cba3b85c4e659de29abbac4408da..ae989fd8b86625273be592b626efa84164b764ed 100644
Binary files a/toolkit/themes/windows/global/icons/close.png and b/toolkit/themes/windows/global/icons/close.png differ
diff --git a/toolkit/themes/windows/global/icons/notloading_16.png b/toolkit/themes/windows/global/icons/notloading_16.png
deleted file mode 100644
index f8366ded5146007efaf63a49d9097e706e0af42e..0000000000000000000000000000000000000000
Binary files a/toolkit/themes/windows/global/icons/notloading_16.png and /dev/null differ
diff --git a/toolkit/themes/windows/global/inContentUI.css b/toolkit/themes/windows/global/inContentUI.css
index 94b959815bf7d420341e75cb80b1088931692bdd..61a663df18c7138f23dd1bccf9920ee4fd79684a 100644
--- a/toolkit/themes/windows/global/inContentUI.css
+++ b/toolkit/themes/windows/global/inContentUI.css
@@ -16,9 +16,7 @@
   background-repeat: repeat;
   color: -moz-dialogText;
   background-color: -moz-dialog;
-  background-image: /* Fade-out texture at the top, and blend with browser tab */
-                    linear-gradient(rgba(255,255,255,0.5), rgba(255,255,255,0) 30%),
-                    /* Texture */
+  background-image: /* Texture */
                     url("chrome://global/skin/inContentUI/background-texture.png");
 }
 
@@ -31,9 +29,7 @@ html|html {
   *|*:root {
     color: #000;
     background-color: #CCD9EA;
-    background-image: /* Fade-out texture at the top */
-                      linear-gradient(rgb(237,245,252), rgba(237,245,252,0) 156px),
-                      /* Texture */
+    background-image: /* Texture */
                       url("chrome://global/skin/inContentUI/background-texture.png");
   }
 }
@@ -42,9 +38,7 @@ html|html {
   *|*:root {
     color: #000;
     /* Blame shorlander for this monstrosity. */
-    background-image: /* Fade-out texture and light beams at the top */
-                      linear-gradient(rgb(237,245,252) 3px, rgba(237,245,252,0) 156px),
-                      /* Side gradients */
+    background-image: /* Side gradients */
                       linear-gradient(to right,
                                       rgba(255,255,255,0.2), rgba(255,255,255,0) 40%,
                                       rgba(255,255,255,0) 60%, rgba(255,255,255,0.2)),
diff --git a/toolkit/themes/windows/global/jar.mn b/toolkit/themes/windows/global/jar.mn
index be2369e3cc9963ebb9f6ecbab80b7073d5e4e34c..6cddc68efd405fe26a4101e4b6ee8394ae5262c5 100644
--- a/toolkit/themes/windows/global/jar.mn
+++ b/toolkit/themes/windows/global/jar.mn
@@ -103,6 +103,9 @@ toolkit.jar:
         skin/classic/global/icons/blacklist_large.png            (icons/blacklist_large.png)
         skin/classic/global/icons/Close.gif                      (icons/Close.gif)
         skin/classic/global/icons/close.png                      (icons/close.png)
+        skin/classic/global/icons/close-lunaBlue.png             (icons/close-lunaBlue.png)
+        skin/classic/global/icons/close-lunaOlive.png            (icons/close-lunaOlive.png)
+        skin/classic/global/icons/close-lunaSilver.png           (icons/close-lunaSilver.png)
         skin/classic/global/icons/collapse.png                   (icons/collapse.png)
         skin/classic/global/icons/Error.png                      (icons/Error.png)
         skin/classic/global/icons/error-16.png                   (icons/error-16.png)
@@ -119,7 +122,6 @@ toolkit.jar:
         skin/classic/global/icons/information-48.png             (icons/information-48.png)
         skin/classic/global/icons/information-64.png             (icons/information-64.png)
         skin/classic/global/icons/loading_16.png                 (icons/loading_16.png)
-        skin/classic/global/icons/notloading_16.png              (icons/notloading_16.png)
         skin/classic/global/icons/Minimize.gif                   (icons/Minimize.gif)
         skin/classic/global/icons/Print-preview.png              (icons/Print-preview.png)
         skin/classic/global/icons/Portrait.png                   (icons/Portrait.png)
@@ -301,7 +303,6 @@ toolkit.jar:
         skin/classic/aero/global/icons/information-48.png                (icons/information-48-aero.png)
         skin/classic/aero/global/icons/information-64.png                (icons/information-64-aero.png)
         skin/classic/aero/global/icons/loading_16.png                    (icons/loading_16.png)
-        skin/classic/aero/global/icons/notloading_16.png                 (icons/notloading_16.png)
         skin/classic/aero/global/icons/Minimize.gif                      (icons/Minimize.gif)
         skin/classic/aero/global/icons/Print-preview.png                 (icons/Print-preview-aero.png)
         skin/classic/aero/global/icons/Portrait.png                      (icons/Portrait-aero.png)
diff --git a/toolkit/themes/windows/global/notification.css b/toolkit/themes/windows/global/notification.css
index 0481d09196056112b12c7ad1df1b137da032b7d8..70534dfaaf8b28f38926c3f7d63d68215ffa95d0 100644
--- a/toolkit/themes/windows/global/notification.css
+++ b/toolkit/themes/windows/global/notification.css
@@ -42,21 +42,11 @@ notification[type="critical"] {
 }
 
 .messageCloseButton {
-  list-style-image: url("chrome://global/skin/icons/close.png");
   -moz-appearance: none;
-  -moz-image-region: rect(0, 16px, 16px, 0);
   padding: 4px 2px;
   border: none !important;
 }
 
-.messageCloseButton:hover {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-.messageCloseButton:hover:active {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
 .messageCloseButton > .toolbarbutton-icon {
   -moz-margin-end: 5px;
 }
@@ -172,8 +162,3 @@ XXX: apply styles to all themes until bug 509642 is fixed
   -moz-margin-end: -14px;
   margin-top: -10px;
 }
-
-.popup-notification-closeitem {
-  list-style-image: url("chrome://global/skin/icons/close.png");
-  -moz-image-region: rect(0, 16px, 16px, 0);
-}
diff --git a/widget/cocoa/nsChildView.h b/widget/cocoa/nsChildView.h
index 8ca8855a5205adc06cc0fb8b57c88d7fd4ff603d..ced4bc1b0b526adfb1317d1c3438e17526949e0a 100644
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -109,18 +109,6 @@ class GLManager;
 
 @interface NSView (Undocumented)
 
-// Draws the title string of a window.
-// Present on NSThemeFrame since at least 10.6.
-// _drawTitleBar is somewhat complex, and has changed over the years
-// since OS X 10.6.  But in that time it's never done anything that
-// would break when called outside of -[NSView drawRect:] (which we
-// sometimes do), or whose output can't be redirected to a
-// CGContextRef object (which we also sometimes do).  This is likely
-// to remain true for the indefinite future.  However we should
-// check _drawTitleBar in each new major version of OS X.  For more
-// information see bug 877767.
-- (void)_drawTitleBar:(NSRect)aRect;
-
 // Returns an NSRect that is the bounding box for all an NSView's dirty
 // rectangles (ones that need to be redrawn).  The full list of dirty
 // rectangles can be obtained by calling -[NSView _dirtyRegion] and then
@@ -130,6 +118,14 @@ class GLManager;
 // outside a call to -[NSView drawRect:].
 - (NSRect)_dirtyRect;
 
+// Undocumented method of one or more of NSFrameView's subclasses.  Called
+// when one or more of the titlebar buttons needs to be repositioned, to
+// disappear, or to reappear (say if the window's style changes).  If
+// 'redisplay' is true, the entire titlebar (the window's top 22 pixels) is
+// marked as needing redisplay.  This method has been present in the same
+// format since at least OS X 10.5.
+- (void)_tileTitlebarAndRedisplay:(BOOL)redisplay;
+
 @end
 
 // Support for pixel scroll deltas, not part of NSEvent.h
diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm
index 0616332a90b606db46eb23414a4ad4dc3a272fad..f81bfbb17437124afad5f739db21fd475223543d 100644
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -168,7 +168,6 @@ uint32_t nsChildView::sLastInputEventCount = 0;
 - (void)clearCorners;
 
 // Overlay drawing functions for traditional CGContext drawing
-- (void)drawTitleString;
 - (void)drawTitlebarHighlight;
 - (void)maskTopCornersInContext:(CGContextRef)aContext;
 
@@ -2219,11 +2218,6 @@ nsChildView::UpdateTitlebarImageBuffer()
   NSGraphicsContext* context = [NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[frameView isFlipped]];
   [NSGraphicsContext setCurrentContext:context];
 
-  // Draw the title string.
-  if ([frameView respondsToSelector:@selector(_drawTitleBar:)]) {
-    [frameView _drawTitleBar:[frameView bounds]];
-  }
-
   // Draw the titlebar controls into the titlebar image.
   for (id view in [window titlebarControls]) {
     NSRect viewFrame = [view frame];
@@ -2388,6 +2382,19 @@ FindUnifiedToolbarBottom(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometr
   }
   return unifiedToolbarBottom;
 }
+ 
+static nsIntRect
+FindFirstRectOfType(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries,
+                    uint8_t aWidgetType)
+{
+  for (uint32_t i = 0; i < aThemeGeometries.Length(); ++i) {
+    const nsIWidget::ThemeGeometry& g = aThemeGeometries[i];
+    if (g.mWidgetType == aWidgetType) {
+      return g.mRect;
+    }
+  }
+  return nsIntRect();
+}
 
 void
 nsChildView::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries)
@@ -2395,6 +2402,7 @@ nsChildView::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometri
   if (![mView window] || ![[mView window] isKindOfClass:[ToolbarWindow class]])
     return;
 
+  // Update unified toolbar height.
   int32_t windowWidth = mBounds.width;
   int32_t titlebarBottom = FindTitlebarBottom(aThemeGeometries, windowWidth);
   int32_t unifiedToolbarBottom =
@@ -2406,6 +2414,12 @@ nsChildView::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometri
   int32_t contentOffset = drawsContentsIntoWindowFrame ? titlebarHeight : 0;
   int32_t devUnifiedHeight = titlebarHeight + unifiedToolbarBottom - contentOffset;
   [win setUnifiedToolbarHeight:DevPixelsToCocoaPoints(devUnifiedHeight)];
+
+  // Update titlebar control offsets.
+  nsIntRect windowButtonRect = FindFirstRectOfType(aThemeGeometries, NS_THEME_WINDOW_BUTTON_BOX);
+  [win placeWindowButtons:[mView convertRect:DevPixelsToCocoaPoints(windowButtonRect) toView:nil]];
+  nsIntRect fullScreenButtonRect = FindFirstRectOfType(aThemeGeometries, NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON);
+  [win placeFullScreenButton:[mView convertRect:DevPixelsToCocoaPoints(fullScreenButtonRect) toView:nil]];
 }
 
 TemporaryRef<gfx::DrawTarget>
@@ -3458,7 +3472,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
   }
 
   if ([self isCoveringTitlebar]) {
-    [self drawTitleString];
     [self drawTitlebarHighlight];
     [self maskTopCornersInContext:aContext];
   }
@@ -3626,26 +3639,6 @@ NSEvent* gLastDragMouseDownEvent = nil;
   CGContextRestoreGState(aContext);
 }
 
-- (void)drawTitleString
-{
-  NSView* frameView = [[[self window] contentView] superview];
-  if (![frameView respondsToSelector:@selector(_drawTitleBar:)]) {
-    return;
-  }
-
-  NSGraphicsContext* oldContext = [NSGraphicsContext currentContext];
-  CGContextRef ctx = (CGContextRef)[oldContext graphicsPort];
-  CGContextSaveGState(ctx);
-  if ([oldContext isFlipped] != [frameView isFlipped]) {
-    CGContextTranslateCTM(ctx, 0, [self bounds].size.height);
-    CGContextScaleCTM(ctx, 1, -1);
-  }
-  [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[frameView isFlipped]]];
-  [frameView _drawTitleBar:[frameView bounds]];
-  CGContextRestoreGState(ctx);
-  [NSGraphicsContext setCurrentContext:oldContext];
-}
-
 - (void)drawTitlebarHighlight
 {
   DrawTitlebarHighlight([self bounds].size, [self cornerRadius],
diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h
index 7cc310b40e79dc2410a2ed645d3dc01132c48a56..63f0ff27d2397794c44af8152d403d4426058c81 100644
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -125,6 +125,11 @@ typedef struct _nsCocoaWindowList {
 - (NSRect)contentRectForFrameRect:(NSRect)windowFrame styleMask:(NSUInteger)windowStyle;
 - (NSRect)frameRectForContentRect:(NSRect)windowContentRect styleMask:(NSUInteger)windowStyle;
 
+// Present since at least OS X 10.5.  The OS calls this method on NSWindow
+// (and its subclasses) to find out which NSFrameView subclass to instantiate
+// to create its "frame view".
++ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
+
 @end
 
 @interface PopupWindow : BaseWindow
@@ -192,6 +197,8 @@ typedef struct _nsCocoaWindowList {
   CGFloat mUnifiedToolbarHeight;
   NSColor *mBackgroundColor;
   NSView *mTitlebarView; // strong
+  NSRect mWindowButtonsRect;
+  NSRect mFullScreenButtonRect;
 }
 // Pass nil here to get the default appearance.
 - (void)setTitlebarColor:(NSColor*)aColor forActiveWindow:(BOOL)aActive;
@@ -202,6 +209,10 @@ typedef struct _nsCocoaWindowList {
 - (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect sync:(BOOL)aSync;
 - (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect;
 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState;
+- (void)placeWindowButtons:(NSRect)aRect;
+- (void)placeFullScreenButton:(NSRect)aRect;
+- (NSPoint)windowButtonsPositionWithDefaultPosition:(NSPoint)aDefaultPosition;
+- (NSPoint)fullScreenButtonPositionWithDefaultPosition:(NSPoint)aDefaultPosition;
 @end
 
 class nsCocoaWindow : public nsBaseWidget, public nsPIWidgetCocoa
@@ -282,6 +293,7 @@ public:
     virtual void SetShowsToolbarButton(bool aShow);
     virtual void SetShowsFullScreenButton(bool aShow);
     virtual void SetWindowAnimationType(WindowAnimationType aType);
+    NS_IMETHOD SetNonClientMargins(nsIntMargin &margins);
     NS_IMETHOD SetWindowTitlebarColor(nscolor aColor, bool aActive);
     virtual void SetDrawsInTitlebar(bool aState);
     virtual nsresult SynthesizeNativeMouseEvent(nsIntPoint aPoint,
diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
index c19affe6af4809b468861dfb5f771686ebc974da..5175e669e0f507b362433b441c83b60c11c3ab75 100644
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -1992,6 +1992,15 @@ void nsCocoaWindow::SetWindowAnimationType(nsIWidget::WindowAnimationType aType)
   mAnimationType = aType;
 }
 
+NS_IMETHODIMP nsCocoaWindow::SetNonClientMargins(nsIntMargin &margins)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
+  SetDrawsInTitlebar(margins.top == 0);
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
 NS_IMETHODIMP nsCocoaWindow::SetWindowTitlebarColor(nscolor aColor, bool aActive)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
@@ -2518,14 +2527,95 @@ GetDPI(NSWindow* aWindow)
   return dpi * backingScale;
 }
 
+@interface NSView(FrameViewMethodSwizzling)
+- (NSPoint)FrameView__closeButtonOrigin;
+- (NSPoint)FrameView__fullScreenButtonOrigin;
+@end
+
+@implementation NSView(FrameViewMethodSwizzling)
+
+- (NSPoint)FrameView__closeButtonOrigin
+{
+  NSPoint defaultPosition = [self FrameView__closeButtonOrigin];
+  if ([[self window] isKindOfClass:[ToolbarWindow class]]) {
+    return [(ToolbarWindow*)[self window] windowButtonsPositionWithDefaultPosition:defaultPosition];
+  }
+  return defaultPosition;
+}
+
+- (NSPoint)FrameView__fullScreenButtonOrigin
+{
+  NSPoint defaultPosition = [self FrameView__fullScreenButtonOrigin];
+  if ([[self window] isKindOfClass:[ToolbarWindow class]]) {
+    return [(ToolbarWindow*)[self window] fullScreenButtonPositionWithDefaultPosition:defaultPosition];
+  }
+  return defaultPosition;
+}
+
+@end
+
+static NSMutableSet *gSwizzledFrameViewClasses = nil;
+
 @interface BaseWindow(Private)
 - (void)removeTrackingArea;
 - (void)cursorUpdated:(NSEvent*)aEvent;
 - (void)updateContentViewSize;
+- (void)reflowTitlebarElements;
 @end
 
 @implementation BaseWindow
 
+// The frame of a window is implemented using undocumented NSView subclasses.
+// We offset the window buttons by overriding the methods _closeButtonOrigin
+// and _fullScreenButtonOrigin on these frame view classes. The class which is
+// used for a window is determined in the window's frameViewClassForStyleMask:
+// method, so this is where we make sure that we have swizzled the method on
+// all encountered classes.
++ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask
+{
+  Class frameViewClass = [super frameViewClassForStyleMask:styleMask];
+
+  if (!gSwizzledFrameViewClasses) {
+    gSwizzledFrameViewClasses = [[NSMutableSet setWithCapacity:3] retain];
+    if (!gSwizzledFrameViewClasses) {
+      return frameViewClass;
+    }
+  }
+
+  static IMP our_closeButtonOrigin =
+    class_getMethodImplementation([NSView class],
+                                  @selector(FrameView__closeButtonOrigin));
+  static IMP our_fullScreenButtonOrigin =
+    class_getMethodImplementation([NSView class],
+                                  @selector(FrameView__fullScreenButtonOrigin));
+
+  if (![gSwizzledFrameViewClasses containsObject:frameViewClass]) {
+    // Either of these methods might be implemented in both a subclass of
+    // NSFrameView and one of its own subclasses.  Which means that if we
+    // aren't careful we might end up swizzling the same method twice.
+    // Since method swizzling involves swapping pointers, this would break
+    // things.
+    IMP _closeButtonOrigin =
+      class_getMethodImplementation(frameViewClass,
+                                    @selector(_closeButtonOrigin));
+    if (_closeButtonOrigin && _closeButtonOrigin != our_closeButtonOrigin) {
+      nsToolkit::SwizzleMethods(frameViewClass, @selector(_closeButtonOrigin),
+                                @selector(FrameView__closeButtonOrigin));
+    }
+    IMP _fullScreenButtonOrigin =
+      class_getMethodImplementation(frameViewClass,
+                                    @selector(_fullScreenButtonOrigin));
+    if (_fullScreenButtonOrigin &&
+        _fullScreenButtonOrigin != our_fullScreenButtonOrigin) {
+      nsToolkit::SwizzleMethods(frameViewClass, @selector(_fullScreenButtonOrigin),
+                                @selector(FrameView__fullScreenButtonOrigin));
+    }
+    [gSwizzledFrameViewClasses addObject:frameViewClass];
+  }
+
+  return frameViewClass;
+}
+
 - (id)initWithContentRect:(NSRect)aContentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)aBufferingType defer:(BOOL)aFlag
 {
   mDrawsIntoWindowFrame = NO;
@@ -2606,8 +2696,12 @@ static const NSString* kStateShowsToolbarButton = @"showsToolbarButton";
 
 - (void)setDrawsContentsIntoWindowFrame:(BOOL)aState
 {
+  bool changed = (aState != mDrawsIntoWindowFrame);
   mDrawsIntoWindowFrame = aState;
-  [self updateContentViewSize];
+  if (changed) {
+    [self updateContentViewSize];
+    [self reflowTitlebarElements];
+  }
 }
 
 - (BOOL)drawsContentsIntoWindowFrame
@@ -2722,6 +2816,15 @@ static const NSString* kStateShowsToolbarButton = @"showsToolbarButton";
   [[self contentView] setFrameSize:rect.size];
 }
 
+// Possibly move the titlebar buttons.
+- (void)reflowTitlebarElements
+{
+  NSView *frameView = [[self contentView] superview];
+  if ([frameView respondsToSelector:@selector(_tileTitlebarAndRedisplay:)]) {
+    [frameView _tileTitlebarAndRedisplay:NO];
+  }
+}
+
 // Override methods that translate between content rect and frame rect.
 - (NSRect)contentRectForFrameRect:(NSRect)aRect
 {
@@ -2922,6 +3025,8 @@ static const NSString* kStateShowsToolbarButton = @"showsToolbarButton";
     mBackgroundColor = [[NSColor whiteColor] retain];
 
     mUnifiedToolbarHeight = 22.0f;
+    mWindowButtonsRect = NSZeroRect;
+    mFullScreenButtonRect = NSZeroRect;
 
     // setBottomCornerRounded: is a private API call, so we check to make sure
     // we respond to it just in case.
@@ -3056,6 +3161,40 @@ static const NSString* kStateShowsToolbarButton = @"showsToolbarButton";
   }
 }
 
+- (void)placeWindowButtons:(NSRect)aRect
+{
+  if (!NSEqualRects(mWindowButtonsRect, aRect)) {
+    mWindowButtonsRect = aRect;
+    [self reflowTitlebarElements];
+  }
+}
+
+- (NSPoint)windowButtonsPositionWithDefaultPosition:(NSPoint)aDefaultPosition
+{
+  if ([self drawsContentsIntoWindowFrame] && !NSIsEmptyRect(mWindowButtonsRect)) {
+    return NSMakePoint(std::max(mWindowButtonsRect.origin.x, aDefaultPosition.x),
+                       std::min(mWindowButtonsRect.origin.y, aDefaultPosition.y));
+  }
+  return aDefaultPosition;
+}
+
+- (void)placeFullScreenButton:(NSRect)aRect
+{
+  if (!NSEqualRects(mFullScreenButtonRect, aRect)) {
+    mFullScreenButtonRect = aRect;
+    [self reflowTitlebarElements];
+  }
+}
+
+- (NSPoint)fullScreenButtonPositionWithDefaultPosition:(NSPoint)aDefaultPosition;
+{
+  if ([self drawsContentsIntoWindowFrame] && !NSIsEmptyRect(mFullScreenButtonRect)) {
+    return NSMakePoint(std::min(mFullScreenButtonRect.origin.x, aDefaultPosition.x),
+                       std::min(mFullScreenButtonRect.origin.y, aDefaultPosition.y));
+  }
+  return aDefaultPosition;
+}
+
 // Returning YES here makes the setShowsToolbarButton method work even though
 // the window doesn't contain an NSToolbar.
 - (BOOL)_hasToolbar
diff --git a/widget/cocoa/nsNativeThemeCocoa.mm b/widget/cocoa/nsNativeThemeCocoa.mm
index 76deab83a6e10ad3392f38f3c863982718b864f2..d250bbd4382c5f9ac5a55c2f6a304892c29da67f 100644
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -361,6 +361,33 @@ static NSWindow* NativeWindowForFrame(nsIFrame* aFrame,
   return (NSWindow*)topLevelWidget->GetNativeData(NS_NATIVE_WINDOW);
 }
 
+static NSSize
+WindowButtonsSize(nsIFrame* aFrame)
+{
+  NSWindow* window = NativeWindowForFrame(aFrame);
+  if (!window) {
+    // Return fallback values.
+    if (!nsCocoaFeatures::OnLionOrLater())
+      return NSMakeSize(57, 16);
+    return NSMakeSize(54, 16);
+  }
+
+  NSRect buttonBox = NSZeroRect;
+  NSButton* closeButton = [window standardWindowButton:NSWindowCloseButton];
+  if (closeButton) {
+    buttonBox = NSUnionRect(buttonBox, [closeButton frame]);
+  }
+  NSButton* minimizeButton = [window standardWindowButton:NSWindowMiniaturizeButton];
+  if (minimizeButton) {
+    buttonBox = NSUnionRect(buttonBox, [minimizeButton frame]);
+  }
+  NSButton* zoomButton = [window standardWindowButton:NSWindowZoomButton];
+  if (zoomButton) {
+    buttonBox = NSUnionRect(buttonBox, [zoomButton frame]);
+  }
+  return buttonBox.size;
+}
+
 static BOOL FrameIsInActiveWindow(nsIFrame* aFrame)
 {
   nsIWidget* topLevelWidget = NULL;
@@ -2748,7 +2775,24 @@ nsNativeThemeCocoa::GetMinimumWidgetSize(nsRenderingContext* aContext,
       aResult->SizeTo(0, (2 + 2) /* top */ + 9 + (1 + 1) /* bottom */);
       break;
     }
-      
+
+    case NS_THEME_WINDOW_BUTTON_BOX: {
+      NSSize size = WindowButtonsSize(aFrame);
+      aResult->SizeTo(size.width, size.height);
+      *aIsOverridable = false;
+      break;
+    }
+
+    case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON: {
+      if ([NativeWindowForFrame(aFrame) respondsToSelector:@selector(toggleFullScreen:)]) {
+        // This value is hardcoded because it's needed before we can measure the
+        // position and size of the fullscreen button.
+        aResult->SizeTo(16, 17);
+      }
+      *aIsOverridable = false;
+      break;
+    }
+
     case NS_THEME_PROGRESSBAR:
     {
       SInt32 barHeight = 0;
@@ -3039,10 +3083,12 @@ nsNativeThemeCocoa::ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* a
 
     case NS_THEME_DIALOG:
     case NS_THEME_WINDOW:
+    case NS_THEME_WINDOW_BUTTON_BOX:
     case NS_THEME_WINDOW_TITLEBAR:
     case NS_THEME_MENUPOPUP:
     case NS_THEME_MENUITEM:
     case NS_THEME_MENUSEPARATOR:
+    case NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON:
     case NS_THEME_TOOLTIP:
     
     case NS_THEME_CHECKBOX: