Automated merge with https://hg.mozilla.org/mozilla-central
authorJared Wein <jwein@mozilla.com>
Wed, 03 Jul 2013 12:40:14 -0400
changeset 155519 b6f8dc3e635b9fe86616f53436d24bb4cf30b993
parent 137216 2cae857c17cb648d766c43c93bcb0bd68901b3f1 (current diff)
parent 155518 0b667de52fa49c68b8e38cb741adfc223009b451 (diff)
child 155520 070ae719d24245b2ed306734e7d242c3f16954f8
push id3502
push usergijskruitbosch@gmail.com
push dateMon, 18 Nov 2013 16:04:49 +0000
treeherderfx-team@838fe39e3dc5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone25.0a1
Automated merge with https://hg.mozilla.org/mozilla-central
browser/base/content/browser-appmenu.inc
browser/base/content/browser.css
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/tabbrowser.xml
browser/base/content/test/Makefile.in
browser/base/content/test/browser_addon_bar.js
browser/base/content/test/browser_addon_bar_aomlistener.js
browser/base/content/test/browser_addon_bar_close_button.js
browser/base/content/test/browser_addon_bar_shortcut.js
browser/base/content/test/browser_bug598923.js
browser/base/content/test/browser_bug599325.js
browser/base/content/test/browser_bug616836.js
browser/base/content/test/browser_customize.js
browser/base/content/test/browser_disablechrome.js
browser/base/content/test/disablechrome.html
browser/base/content/urlbarBindings.xml
browser/components/nsBrowserGlue.js
browser/locales/en-US/chrome/browser/browser.dtd
browser/locales/jar.mn
browser/modules/Makefile.in
browser/themes/linux/browser.css
browser/themes/linux/places/pageStarred.png
browser/themes/linux/places/starPage.png
browser/themes/osx/Toolbar-lion.png
browser/themes/osx/Toolbar-lion@2x.png
browser/themes/osx/browser.css
browser/themes/osx/tabbrowser/tab-bottom-hover-active.png
browser/themes/osx/tabbrowser/tab-bottom-normal-active.png
browser/themes/osx/tabbrowser/tab-bottom-selected-active.png
browser/themes/osx/tabbrowser/tab-top-hover-active.png
browser/themes/osx/tabbrowser/tab-top-hover-active@2x.png
browser/themes/osx/tabbrowser/tab-top-normal-active.png
browser/themes/osx/tabbrowser/tab-top-normal-active@2x.png
browser/themes/osx/tabbrowser/tab-top-selected-active.png
browser/themes/osx/tabbrowser/tab-top-selected-active@2x.png
browser/themes/windows/appmenu-dropmarker.png
browser/themes/windows/appmenu-icons.png
browser/themes/windows/browser-aero.css
browser/themes/windows/browser.css
browser/themes/windows/places/editBookmark.png
toolkit/modules/LightweightThemeConsumer.jsm
toolkit/themes/linux/global/icons/notloading_16.png
toolkit/themes/osx/global/icons/notloading_16.png
toolkit/themes/windows/global/icons/notloading_16.png
toolkit/themes/windows/global/jar.mn
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -421,21 +421,20 @@ pref("browser.tabs.warnOnCloseOtherTabs"
 pref("browser.tabs.warnOnOpen", true);
 pref("browser.tabs.maxOpenBeforeWarn", 15);
 pref("browser.tabs.loadInBackground", true);
 pref("browser.tabs.opentabfor.middleclick", true);
 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
+#ifdef UNIX_BUT_NOT_MAC
+pref("browser.tabs.drawInTitlebar", false);
+#else
 pref("browser.tabs.drawInTitlebar", true);
-#else
-pref("browser.tabs.drawInTitlebar", false);
 #endif
 
 // Where to show tab close buttons:
 // 0  on active tab only
 // 1  on all tabs until tabClipWidth is reached, then active tab only
 // 2  no close buttons at all
 // 3  at the end of the tabstrip
 pref("browser.tabs.closeButtons", 1);
@@ -1272,8 +1271,11 @@ pref("media.webaudio.enabled", true);
 #endif
 
 // If this turns true, Moz*Gesture events are not called stopPropagation()
 // before content.
 pref("dom.debug.propagate_gesture_events_through_content", false);
 
 // The request URL of the GeoLocation backend.
 pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%");
+
+// CustomizableUI debug logging.
+pref("browser.uiCustomization.debug", false);
--- a/browser/base/content/browser-addons.js
+++ b/browser/base/content/browser-addons.js
@@ -173,60 +173,16 @@ const gXPInstallObserver = {
 
       PopupNotifications.show(browser, notificationID, messageString, anchorID,
                               action, null, options);
       break;
     }
   }
 };
 
-/*
- * 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) {
       case "InstallBrowserTheme":
       case "PreviewBrowserTheme":
       case "ResetBrowserThemePreview":
         // ignore requests from background tabs
         if (event.target.ownerDocument.defaultView.top != content)
@@ -410,8 +366,63 @@ var LightWeightThemeWebInstaller = {
     return pm.testPermission(uri, "install") == pm.ALLOW_ACTION;
   },
 
   _getThemeFromNode: function (node) {
     return this._manager.parseTheme(node.getAttribute("data-browsertheme"),
                                     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);
+    this.updateStyleSheet("url(" + themeData.headerURL + ")");
+  },
+};
deleted file mode 100644
--- a/browser/base/content/browser-appmenu.inc
+++ /dev/null
@@ -1,400 +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_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);"/>
-#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>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/browser-customization.js
@@ -0,0 +1,104 @@
+# -*- 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();
+    setUrlAndSearchBarWidthForConditionalForwardButton();
+
+    // Update the urlbar
+    if (gURLBar) {
+      URLBarSetURI();
+      XULBrowserWindow.asyncUpdateUI();
+      BookmarkingUI.updateStarState();
+      SocialMark.updateMarkState();
+    }
+
+    // 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");
+
+    // make sure to re-enable click-and-hold
+    if (!getBoolPref("ui.click_hold_context_menus", false)) {
+      SetClickAndHoldHandlers();
+    }
+
+    gBrowser.selectedBrowser.focus();
+  }
+}
--- a/browser/base/content/browser-feeds.js
+++ b/browser/base/content/browser-feeds.js
@@ -3,85 +3,69 @@
 # 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/.
 
 /**
  * The Feed Handler object manages discovery of RSS/ATOM feeds in web pages
  * 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");
+      container.appendChild(item);
     }
     return true;
   },
 
   /**
    * 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
    *          event target's feed attribute is examined.
    * @param   event
    *          The event this method is handling. Used to decide where
    *          to open the preview UI. (Optional, unless href is null)
    */
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -12,17 +12,17 @@ var FullScreen = {
   toggle: function (event) {
     var enterFS = window.fullScreen;
 
     // We get the fullscreen event _before_ the window transitions into or out of FS mode.
     if (event && event.type == "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);
     } else {
       fullscreenCommand.removeAttribute("checked");
     }
 
 #ifdef XP_MACOSX
@@ -512,50 +512,31 @@ var FullScreen = {
   showXULChrome: function(aTag, aShow)
   {
     var els = document.getElementsByTagNameNS(this._XULNS, aTag);
 
     for (let el of els) {
       // 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"));
           if (el.id == "nav-bar" || el.id == "TabsToolbar")
             el.setAttribute("context", "autohide-context");
           else
             el.removeAttribute("context");
 
           // Set the inFullscreen attribute to allow specific styling
           // in fullscreen mode
           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);
-            }
-          }
-
-          restoreAttr("mode");
-          restoreAttr("iconsize");
-          restoreAttr("context");
-
+          el.setAttribute("context", el.getAttribute("saved-context"));
+          el.removeAttribute("saved-context");
           el.removeAttribute("inFullscreen");
         }
       } else {
         // use moz-collapsed so it doesn't persist hidden/collapsed,
         // so that new windows don't have missing toolbars
         if (aShow)
           el.removeAttribute("moz-collapsed");
         else
@@ -566,21 +547,19 @@ var FullScreen = {
     if (aShow) {
       gNavToolbox.removeAttribute("inFullscreen");
       document.documentElement.removeAttribute("inFullscreen");
     } else {
       gNavToolbox.setAttribute("inFullscreen", true);
       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);
     }
     else if (fullscreenctls.parentNode.id == "TabsToolbar" && !ctlsOnTabbar) {
       fullscreenctls.setAttribute("flex", "1");
       navbar.appendChild(fullscreenctls);
     }
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -385,16 +385,17 @@ var FullZoom = {
     });
   },
 
   /**
    * Saves the zoom level of the page in the current browser to the content
    * prefs store.
    */
   _applyZoomToPref: function FullZoom__applyZoomToPref() {
+    Services.obs.notifyObservers(null, "browser-fullZoom:zoomChange", "");
     if (!this.siteSpecific ||
         gInPrintPreviewMode ||
         content.document.mozSyntheticDocument)
       return;
 
     this._cps2.set(gBrowser.currentURI.spec, this.name, ZoomManager.zoom,
                    this._loadContextFromWindow(gBrowser.contentWindow), {
       handleCompletion: function () {
@@ -402,26 +403,28 @@ var FullZoom = {
       }.bind(this),
     });
   },
 
   /**
    * Removes from the content prefs store the zoom level of the current browser.
    */
   _removePref: function FullZoom__removePref() {
+        Services.obs.notifyObservers(null, "browser-fullZoom:zoomReset", "");
     if (content.document.mozSyntheticDocument)
       return;
     let ctxt = this._loadContextFromWindow(gBrowser.contentWindow);
     this._cps2.removeByDomainAndName(gBrowser.currentURI.spec, this.name, ctxt, {
       handleCompletion: function () {
         this._isNextContentPrefChangeInternal = true;
       }.bind(this),
     });
   },
 
+
   //**************************************************************************//
   // Utilities
 
   /**
    * Returns the current FullZoom "state".  Asynchronous operations that change
    * the zoom should use this method to capture the state before starting and
    * use _isStateCurrent to determine if it's still current when done.  If the
    * captured state is no longer current, then the zoom should not be changed.
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -180,21 +180,16 @@
                   accesskey="&viewMenu.accesskey;">
               <menupopup id="menu_viewPopup"
                          onpopupshowing="updateCharacterEncodingMenuState();">
                 <menu id="viewToolbarsMenu"
                       label="&viewToolbarsMenu.label;"
                       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;"
                               command="cmd_CustomizeToolbars"/>
                   </menupopup>
                 </menu>
                 <menu id="viewSidebarMenuMenu"
                       label="&viewSidebarMenu.label;"
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -129,19 +129,16 @@ var StarUI = {
       this._doShowEditBookmarkPanel(aItemId, aAnchorElement, aPosition);
       return;
     }
 
     this._overlayLoading = true;
     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");
         let rows = this._element("editBookmarkPanelGrid").lastChild;
         rows.insertBefore(header, rows.firstChild);
         header.hidden = false;
 
         this._overlayLoading = false;
@@ -989,52 +986,55 @@ let PlacesToolbarHelper = {
     this.init();
   }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 //// 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");
     }
     return this._button;
   },
 
   get star() {
-    if (!this._star) {
-      this._star = document.getElementById("star-button");
+    if (!this._star && this.button) {
+      this._star = document.getAnonymousElementByAttribute(this.button,
+                                                           "anonid",
+                                                           "button");
     }
     return this._star;
   },
 
   get anchor() {
-    if (this.star && isElementVisible(this.star)) {
+    if (!this._anchor && this.star && isElementVisible(this.star)) {
       // Anchor to the icon, so the panel looks more natural.
-      return this.star;
+      this._anchor = document.getAnonymousElementByAttribute(this.star,
+                                                             "class",
+                                                             "toolbarbutton-icon");
     }
-    return null;
+    return this._anchor;
   },
 
   STATUS_UPDATING: -1,
   STATUS_UNSTARRED: 0,
   STATUS_STARRED: 1,
   get status() {
     if (this._pendingStmt)
       return this.STATUS_UPDATING;
-    return this.star &&
-           this.star.hasAttribute("starred") ? this.STATUS_STARRED
-                                             : this.STATUS_UNSTARRED;
+    return this.button &&
+           this.button.hasAttribute("starred") ? this.STATUS_STARRED
+                                               : this.STATUS_UNSTARRED;
   },
 
   get _starredTooltip()
   {
     delete this._starredTooltip;
     return this._starredTooltip =
       gNavigatorBundle.getString("starButtonOn.tooltip");
   },
@@ -1093,21 +1093,22 @@ let BookmarkingUI = {
    */
   onPageProxyStateChanged: function BUI_onPageProxyStateChanged(aState) {
     if (!this.star) {
       return;
     }
 
     if (aState == "invalid") {
       this.star.setAttribute("disabled", "true");
-      this.star.removeAttribute("starred");
+      this.button.removeAttribute("starred");
     }
     else {
       this.star.removeAttribute("disabled");
     }
+    this._updateToolbarStyle();
   },
 
   _updateToolbarStyle: function BUI__updateToolbarStyle() {
     if (!this.button) {
       return;
     }
 
     let personalToolbar = document.getElementById("PersonalToolbar");
@@ -1138,16 +1139,18 @@ let BookmarkingUI = {
   },
 
   customizeChange: function BUI_customizeChange() {
     this._updateToolbarStyle();
   },
 
   customizeDone: function BUI_customizeDone() {
     delete this._button;
+    delete this._star;
+    delete this._anchor;
     this.onToolbarVisibilityChange();
     this._updateToolbarStyle();
   },
 
   _hasBookmarksObserver: false,
   uninit: function BUI_uninit() {
     this._uninitView();
 
@@ -1157,17 +1160,17 @@ let BookmarkingUI = {
 
     if (this._pendingStmt) {
       this._pendingStmt.cancel();
       delete this._pendingStmt;
     }
   },
 
   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;
     }
 
     // Reset tracked values.
     this._uri = gBrowser.currentURI;
     this._itemIds = [];
 
     if (this._pendingStmt) {
@@ -1206,63 +1209,75 @@ let BookmarkingUI = {
         }
       }
 
       delete this._pendingStmt;
     }, this);
   },
 
   _updateStar: function BUI__updateStar() {
-    if (!this.star) {
+    if (!this.button) {
       return;
     }
 
     if (this._itemIds.length > 0) {
-      this.star.setAttribute("starred", "true");
-      this.star.setAttribute("tooltiptext", this._starredTooltip);
+      this.button.setAttribute("starred", "true");
+      this.button.setAttribute("tooltiptext", this._starredTooltip);
     }
     else {
-      this.star.removeAttribute("starred");
-      this.star.setAttribute("tooltiptext", this._unstarredTooltip);
+      this.button.removeAttribute("starred");
+      this.button.setAttribute("tooltiptext", this._unstarredTooltip);
     }
   },
 
   onCommand: function BUI_onCommand(aEvent) {
     if (aEvent.target != aEvent.currentTarget) {
       return;
     }
     // Ignore clicks on the star if we are updating its state.
     if (!this._pendingStmt) {
       PlacesCommandHook.bookmarkCurrentPage(this._itemIds.length > 0);
     }
   },
 
   // 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) {
         this._itemIds.push(aItemId);
         this._updateStar();
       }
     }
   },
 
   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) {
       this._itemIds.splice(index, 1);
       this._updateStar();
     }
   },
 
   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
       // a different uri and unregister it.
       if (index != -1 && aNewValue != this._uri.spec) {
         this._itemIds.splice(index, 1);
         this._updateStar();
       }
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -27,17 +27,16 @@
     <command id="Browser:SendLink"
              oncommand="MailIntegration.sendLinkForWindow(window.content);"/>
 
     <command id="cmd_pageSetup" oncommand="PrintUtils.showPageSetup();"/>
     <command id="cmd_print" oncommand="PrintUtils.print();"/>
     <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()"/>
 
 
     <commandset id="editMenuCommands"/>
 
     <command id="View:PageSource" oncommand="BrowserViewSourceOfDocument(content.document);" observes="isImage"/>
     <command id="View:PageInfo" oncommand="BrowserPageInfo();"/>
@@ -103,17 +102,16 @@
     <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
     <command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/>
     <command id="Tools:Sanitize"
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing"
       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:TogglePageMark" oncommand="SocialMark.togglePageMark();" disabled="true"/>
     <command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/>
     <command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();"/>
     <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');"/>
   </commandset>
@@ -408,17 +406,15 @@
 #expand    <key id="key_selectTab3" oncommand="gBrowser.selectTabAtIndex(2, event);" key="3" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
 #expand    <key id="key_selectTab4" oncommand="gBrowser.selectTabAtIndex(3, event);" key="4" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
 #expand    <key id="key_selectTab5" oncommand="gBrowser.selectTabAtIndex(4, event);" key="5" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
 #expand    <key id="key_selectTab6" oncommand="gBrowser.selectTabAtIndex(5, event);" key="6" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
 #expand    <key id="key_selectTab7" oncommand="gBrowser.selectTabAtIndex(6, event);" key="7" modifiers="__NUM_SELECT_TAB_MODIFIER__"/>
 #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
 #ifdef XP_MACOSX
   <commandset id="baseMenuCommandSet" />
 #endif
   <keyset id="baseMenuKeyset" />
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -792,19 +792,17 @@ SocialShare = {
       }, true);
     }
     // always ensure that origin belongs to the endpoint
     let uri = Services.io.newURI(shareEndpoint, null, null);
     iframe.setAttribute("origin", provider.origin);
     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));
   },
 
   _generateShareEndpointURL: function(shareURL, pageData) {
     // support for existing share endpoints by supporting their querystring
     // arguments. parse the query string template and do replacements where
     // necessary the query names may be different than ours, so we could see
@@ -1233,19 +1231,17 @@ SocialToolbar = {
           setTimeout(function() {
             dispatchPanelEvent("socialFrameShow");
           }, 0);
         }, true);
       }
     });
 
     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() {
       panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
     }, 0);
   },
 
   setPanelErrorMessage: function SocialToolbar_setPanelErrorMessage(aNotificationFrame) {
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -415,26 +415,23 @@ let TabView = {
   _addToolbarButton: function TabView__addToolbarButton() {
     let buttonId = "tabview-button";
 
     if (document.getElementById(buttonId))
       return;
 
     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);
   },
 
   // ----------
   // Function: updateGroupNumberBroadcaster
   // Updates the group number broadcaster.
   updateGroupNumberBroadcaster: function TabView_updateGroupNumberBroadcaster(number) {
     let groupsNumber = document.getElementById("tabviewGroupsNumber");
     groupsNumber.setAttribute("groups", number);
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -8,16 +8,69 @@
 searchbar {
   -moz-binding: url("chrome://browser/content/search/search.xml#searchbar");
 }
 
 browser[remote="true"] {
   -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[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");
 }
 
 .tabbrowser-tabs {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tabs");
 }
 
@@ -34,31 +87,31 @@ tabbrowser {
 }
 
 .tabbrowser-tab {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tab");
 }
 
 .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,
+              max-width 230ms ease-out,
               opacity 50ms ease-out 20ms /* hide the tab for the first 20ms of the max-width transition */;
 }
 
 .tabbrowser-tab:not([pinned]):not([fadein]) {
   max-width: 0.1px;
   min-width: 0.1px;
   opacity: 0 !important;
   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,
+              opacity 50ms ease-out 160ms /* hide the tab for the last 20ms of the max-width transition */;
 }
 
 .tab-throbber:not([fadein]):not([pinned]),
 .tab-label:not([fadein]):not([pinned]),
 .tab-icon-image:not([fadein]):not([pinned]),
 .tab-close-button:not([fadein]):not([pinned]) {
   display: none;
 }
@@ -81,30 +134,23 @@ tabbrowser {
 #alltabs-popup {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-alltabs-popup");
 }
 
 toolbar[printpreview="true"] {
   -moz-binding: url("chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar");
 }
 
-#toolbar-menubar {
-  -moz-box-ordinal-group: 5;
+toolbar[overflowable] > .customization-target {
+  overflow: hidden;
 }
 
-#navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
-  -moz-box-ordinal-group: 50;
-}
-
-#TabsToolbar {
-  -moz-box-ordinal-group: 100;
-}
-
-#TabsToolbar[tabsontop="true"] {
-  -moz-box-ordinal-group: 10;
+toolbar[customizing][overflowable] > .overflow-button,
+toolbar[overflowable]:not([overflowing]) > .overflow-button {
+  display: none;
 }
 
 %ifdef CAN_DRAW_IN_TITLEBAR
 #main-window[inFullscreen] > #titlebar,
 #main-window[inFullscreen] .titlebar-placeholder,
 #main-window:not([tabsintitlebar]) .titlebar-placeholder {
   display: none;
 }
@@ -112,53 +158,68 @@ toolbar[printpreview="true"] {
 #titlebar {
   -moz-binding: url("chrome://global/content/bindings/general.xml#windowdragbox");
 }
 
 #titlebar-spacer {
   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
+
+%ifdef XP_WIN
+#main-window[sizemode="maximized"] #titlebar-buttonbox {
+  -moz-appearance: -moz-window-button-box-maximized;
+}
+%endif
+
 %endif
 
 .bookmarks-toolbar-customize,
 #wrapper-personal-bookmarks > #personal-bookmarks > #PlacesToolbar > hbox > #PlacesToolbarItems {
   display: none;
 }
 
 #wrapper-personal-bookmarks[place="toolbar"] > #personal-bookmarks > #PlacesToolbar > .bookmarks-toolbar-customize {
   display: -moz-box;
 }
 
-#main-window[disablechrome] #navigator-toolbox[tabsontop="true"] > toolbar:not(#toolbar-menubar):not(#TabsToolbar) {
-  visibility: collapse;
-}
-
 #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] {
+#urlbar-reload-button:not([displaystop]) + #urlbar-stop-button,
+#urlbar-reload-button[displaystop],
+#reload-button:not([displaystop]) + #stop-button,
+#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;
+#urlbar-container {
+  min-width: 50ch;
+}
+
+#search-container {
+  min-width: 25ch;
 }
 
 #main-window:-moz-lwtheme {
   background-repeat: no-repeat;
   background-position: top right;
 }
 
 %ifdef XP_MACOSX
@@ -167,59 +228,26 @@ toolbar[mode="icons"] > #reload-button[d
 }
 %endif
 
 #browser-bottombox[lwthemefooter="true"] {
   background-repeat: no-repeat;
   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");
 }
 
 .menuitem-iconic-tooltip,
 .menuitem-tooltip[type="checkbox"],
 .menuitem-tooltip[type="radio"] {
   -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;
 }
 
 /* ::::: location bar ::::: */
 #urlbar {
   -moz-binding: url(chrome://browser/content/urlbarBindings.xml#urlbar);
@@ -303,28 +331,30 @@ panel[noactions] > richlistbox > richlis
 .unified-nav-current {
   font-weight: bold;
 }
 
 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;
 }
 
 menuitem.spell-suggestion {
   font-weight: bold;
 }
 
@@ -339,17 +369,16 @@ window[sizemode="maximized"] #content .n
 
 /* Hide extension toolbars that neglected to set the proper class */
 window[chromehidden~="location"][chromehidden~="toolbar"] toolbar:not(.chromeclass-menubar),
 window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-menubar) {
   display: none;
 }
 
 #navigator-toolbox ,
-#status-bar ,
 #mainPopupSet {
   min-width: 1px;
 }
 
 %ifdef MOZ_SERVICES_SYNC
 /* Sync notification UI */
 #sync-notifications {
   -moz-binding: url("chrome://browser/content/sync/notification.xml#notificationbox");
@@ -438,24 +467,16 @@ window[chromehidden~="toolbar"] toolbar:
 
 #full-screen-domain-text,
 #full-screen-remember-decision > .checkbox-label-box > .checkbox-label {
   word-wrap: break-word;
   /* We must specify a min-width, otherwise word-wrap:break-word doesn't work. Bug 630864. */
   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,
 .ctrlTab-preview > html|canvas {
   min-width: inherit;
   max-width: inherit;
   min-height: inherit;
   max-height: inherit;
@@ -510,27 +531,16 @@ window[chromehidden~="toolbar"] toolbar:
 #click-to-play-plugins-notification {
   -moz-binding: url("chrome://browser/content/urlbarBindings.xml#click-to-play-plugins-notification");
 }
 
 .plugin-popupnotification-centeritem {
   -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;
 }
 
 /* Status panel */
 
 statuspanel {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#statuspanel");
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -89,16 +89,22 @@ this.__defineSetter__("PluralForm", func
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
   "resource://gre/modules/TelemetryStopwatch.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AboutHomeUtils",
   "resource:///modules/AboutHomeUtils.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");
 #endif
 
 XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () {
   let tmp = {};
   Cu.import("resource://gre/modules/PopupNotifications.jsm", tmp);
@@ -149,16 +155,17 @@ let gInitialPages = [
   "about:newtab",
   "about:home",
   "about:privatebrowsing",
   "about:welcomeback",
   "about:sessionrestore"
 ];
 
 #include browser-addons.js
+#include browser-customization.js
 #include browser-feeds.js
 #include browser-fullScreen.js
 #include browser-fullZoom.js
 #include browser-places.js
 #include browser-plugins.js
 #include browser-safebrowsing.js
 #include browser-social.js
 #include browser-tabPreviews.js
@@ -922,38 +929,33 @@ var gBrowserInit = {
         // border.  Use 28px as a guess (titlebar + bottom window border)
         defaultHeight -= 28;
 #endif
       }
       document.documentElement.setAttribute("width", defaultWidth);
       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) {
         gURLBar.setAttribute("readonly", "true");
         gURLBar.setAttribute("enablehistory", "false");
       }
       goSetCommandEnabled("cmd_newNavigatorTab", false);
     }
 
-#ifdef MENUBAR_CAN_AUTOHIDE
-    updateAppButtonDisplay();
+#ifdef CAN_DRAW_IN_TITLEBAR
+    updateTitlebarDisplay();
 #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, uriToLoad, mustLoadSidebar);
     window.addEventListener("MozAfterPaint", this._boundDelayedStartup);
 
     this._loadHandled = true;
   },
 
@@ -1040,18 +1042,23 @@ var gBrowserInit = {
     Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
     Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
     Services.obs.addObserver(gFormSubmitObserver, "invalidformsubmit", false);
 
     BrowserOffline.init();
     OfflineApps.init();
     IndexedDBPromptHelper.init();
     gFormSubmitObserver.init();
+    // 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();
     SocialUI.init();
-    AddonManager.addAddonListener(AddonsMgrListener);
+    LightweightThemeListener.init();
     WebrtcIndicator.init();
 
     // Ensure login manager is up and running.
     Services.logins;
 
     if (mustLoadSidebar) {
       let sidebar = document.getElementById("sidebar");
       let sidebarBox = document.getElementById("sidebar-box");
@@ -1087,21 +1094,16 @@ var gBrowserInit = {
       document.getElementById("textfieldDirection-swap").hidden = false;
     }
 
     // Setup click-and-hold gestures access to the session history
     // menus if global click-and-hold isn't turned on
     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 = {};
       Cu.import("resource:///modules/NetworkPrioritizer.jsm", NP);
       NP.trackBrowserWindow(window);
     }
 
     // initialize the session-restore service (in case it's not already running)
@@ -1226,56 +1228,33 @@ var gBrowserInit = {
     // Enable DevTools connection screen, if the preference allows this.
     let devtoolsRemoteEnabled = gPrefService.getBoolPref("devtools.debugger.remote-enabled");
     if (devtoolsRemoteEnabled) {
       let cmd = document.getElementById("Tools:DevToolsConnect");
       cmd.removeAttribute("disabled");
       cmd.removeAttribute("hidden");
     }
 
-#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
-
     // Enable Responsive UI?
     let responsiveUIEnabled = gPrefService.getBoolPref("devtools.responsiveUI.enabled");
     if (responsiveUIEnabled) {
       let cmd = document.getElementById("Tools:ResponsiveUI");
       cmd.removeAttribute("disabled");
       cmd.removeAttribute("hidden");
     }
 
     // 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 {
       const startupCrashEndDelay = 30 * 1000;
       setTimeout(Services.startup.trackStartupCrashEnd, startupCrashEndDelay);
     } catch (ex) {
       Cu.reportError("Could not end startup crash tracking: " + ex);
     }
@@ -1324,18 +1303,16 @@ var gBrowserInit = {
     try {
       gBrowser.removeProgressListener(window.XULBrowserWindow);
       gBrowser.removeTabsProgressListener(window.TabsProgressListener);
     } catch (ex) {
     }
 
     BookmarkingUI.uninit();
 
-    TabsOnTop.uninit();
-
     TabsInTitlebar.uninit();
 
     var enumerator = Services.wm.getEnumerator(null);
     enumerator.getNext();
     if (!enumerator.hasMoreElements()) {
       document.persist("sidebar-box", "sidebarcommand");
       document.persist("sidebar-box", "width");
       document.persist("sidebar-box", "src");
@@ -1376,18 +1353,19 @@ var gBrowserInit = {
         Services.prefs.removeObserver(prefName, gMetroPrefs);
       });
 #endif
 #endif
 
       BrowserOffline.uninit();
       OfflineApps.uninit();
       IndexedDBPromptHelper.uninit();
-      AddonManager.removeAddonListener(AddonsMgrListener);
       SocialUI.uninit();
+      LightweightThemeListener.uninit();
+      PanelUI.uninit();
     }
 
     // Final window teardown, do this last.
     window.XULBrowserWindow.destroy();
     window.XULBrowserWindow = null;
     window.QueryInterface(Ci.nsIInterfaceRequestor)
           .getInterface(Ci.nsIWebNavigation)
           .QueryInterface(Ci.nsIDocShellTreeItem).treeOwner
@@ -1403,17 +1381,17 @@ var gBrowserInit = {
   // macBrowserOverlay
   nonBrowserWindowStartup: function() {
     // Disable inappropriate commands / submenus
     var disabledItems = ['Browser:SavePage',
                          'Browser:SendLink', 'cmd_pageSetup', 'cmd_print', 'cmd_find', 'cmd_findAgain',
                          '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) {
       element = document.getElementById(disabledItem);
       if (element)
         element.setAttribute("disabled", "true");
     }
 
@@ -2685,35 +2663,32 @@ var PrintPreviewListener = {
     if (gInPrintPreviewMode)
       this._hideChrome();
     else
       this._showChrome();
 
     if (this._chromeState.sidebarOpen)
       toggleSidebar(this._sidebarCommand);
 
-#ifdef MENUBAR_CAN_AUTOHIDE
-    updateAppButtonDisplay();
+#ifdef CAN_DRAW_IN_TITLEBAR
+    updateTitlebarDisplay();
 #endif
   },
   _hideChrome: function () {
     this._chromeState = {};
 
     var sidebar = document.getElementById("sidebar-box");
     this._chromeState.sidebarOpen = !sidebar.hidden;
     this._sidebarCommand = sidebar.getAttribute("sidebarcommand");
 
     var notificationBox = gBrowser.getNotificationBox();
     this._chromeState.notificationsOpen = !notificationBox.notificationsHidden;
     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;
     if (gFindBarInitialized)
       gFindBar.close();
 
     var globalNotificationBox = document.getElementById("global-notificationbox");
     this._chromeState.globalNotificationsOpen = !globalNotificationBox.notificationsHidden;
@@ -2725,21 +2700,16 @@ var PrintPreviewListener = {
       this._chromeState.syncNotificationsOpen = !syncNotifications.notificationsHidden;
       syncNotifications.notificationsHidden = true;
     }
   },
   _showChrome: function () {
     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();
 
     if (this._chromeState.globalNotificationsOpen)
       document.getElementById("global-notificationbox").notificationsHidden = false;
 
     if (this._chromeState.syncNotificationsOpen)
       document.getElementById("sync-notifications").notificationsHidden = false;
@@ -2806,45 +2776,16 @@ function openHomeDialog(aURL)
       gPrefService.setComplexValue("browser.startup.homepage",
                                    Components.interfaces.nsISupportsString, str);
     } catch (ex) {
       dump("Failed to set the home page.\n"+ex+"\n");
     }
   }
 }
 
-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)
   {
     browserDragAndDrop.dragOver(aEvent);
   },
 
   onDragExit: function (aEvent)
   {
@@ -3353,164 +3294,28 @@ function OpenBrowserWindow(options)
   else // forget about the charset information.
   {
     win = window.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no" + extraFeatures, defaultArgs);
   }
 
   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();
-    SocialMark.updateMarkState();
-    SocialShare.update();
-  }
-
-  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();
 }
 
 /**
  * Update the global flag that tracks whether or not any edit UI (the Edit menu,
  * edit-related items in the context menu, and edit-related toolbar buttons
  * is visible, then update the edit commands' enabled state accordingly.  We use
  * this flag to skip updating the edit commands on focus or selection changes
  * when no UI is visible to improve performance (including pageload performance,
@@ -3529,36 +3334,27 @@ function retrieveToolbarIconsizesFromThe
  * is a no op.
  */
 function updateEditUIVisibility()
 {
 #ifndef XP_MACOSX
   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,
   // or Paste toolbar buttons.
   gEditUIVisible = editMenuPopupState == "showing" ||
                    editMenuPopupState == "open" ||
                    contextMenuPopupState == "showing" ||
                    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.
   if (gEditUIVisible)
     goUpdateGlobalEditMenuItems();
 
   // Otherwise, enable all commands, so that keyboard shortcuts still work,
   // then lazily determine their actual enabled state when the user presses
@@ -3578,44 +3374,29 @@ function updateEditUIVisibility()
 
 /**
  * Makes the Character Encoding menu enabled or disabled as appropriate.
  * To be called when the View menu or the app menu is opened.
  */
 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.
   if (gBrowser &&
       gBrowser.docShell &&
       gBrowser.docShell.mayEnableCharacterEncodingMenu) {
     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");
-    }
   }
 }
 
 /**
  * Returns true if |aMimeType| is text-based, false otherwise.
  *
  * @param aMimeType
  *        The MIME type to check.
@@ -3637,18 +3418,18 @@ function mimeTypeIsTextBased(aMimeType)
 var XULBrowserWindow = {
   // Stored Status, Link and Loading values
   status: "",
   defaultStatus: "",
   overLink: "",
   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) ||
         aIID.equals(Ci.nsIWebProgressListener2) ||
         aIID.equals(Ci.nsISupportsWeakReference) ||
         aIID.equals(Ci.nsIXULBrowserWindow) ||
         aIID.equals(Ci.nsISupports))
       return this;
@@ -3668,32 +3449,29 @@ var XULBrowserWindow = {
     return this.statusTextField = document.getElementById("statusbar-display");
   },
   get isImage () {
     delete this.isImage;
     return this.isImage = document.getElementById("isImage");
   },
 
   init: function () {
-    this.throbberElement = document.getElementById("navigator-throbber");
-
     // Bug 666809 - SecurityUI support for e10s
     if (gMultiProcessBrowser)
       return;
 
     // Initialize the security button's state and tooltip text.  Remember to reset
     // _hostChanged, otherwise onSecurityChange will short circuit.
     var securityUI = gBrowser.securityUI;
     this._hostChanged = true;
     this.onSecurityChange(null, null, securityUI.state);
   },
 
   destroy: function () {
     // XXXjag to avoid leaks :-/, see bug 60729
-    delete this.throbberElement;
     delete this.stopCommand;
     delete this.reloadCommand;
     delete this.statusTextField;
     delete this.statusText;
   },
 
   setJSStatus: function () {
     // unsupported
@@ -3808,20 +3586,16 @@ var XULBrowserWindow = {
         gBrowser.selectedBrowser.engines = null;
       }
 
       this.isBusy = true;
 
       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();
       }
     }
     else if (aStateFlags & nsIWebProgressListener.STATE_STOP) {
       // This (thanks to the filter) is a network stop or the last
       // request stop outside of loading the document, stop throbbers
@@ -3856,20 +3630,16 @@ var XULBrowserWindow = {
           this.isImage.setAttribute('disabled', 'true');
       }
 
       this.isBusy = false;
 
       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);
       }
     }
   },
 
   onLocationChange: function (aWebProgress, aRequest, aLocationURI, aFlags) {
     var location = aLocationURI ? aLocationURI.spec : "";
@@ -3928,27 +3698,16 @@ var XULBrowserWindow = {
         URLBarSetURI(aLocationURI);
 
         // Update starring UI
         BookmarkingUI.updateStarState();
         SocialMark.updateMarkState();
         SocialShare.update();
       }
 
-      // Show or hide browser chrome based on the whitelist
-      if (this.hideChromeForLocation(location)) {
-        document.documentElement.setAttribute("disablechrome", "true");
-      } else {
-        let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
-        if (ss.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;
         return docElt && docElt.getAttribute("disablefastfind") == "true";
       }
 
       var disableFindCommands = function disableFindCommands(aDisable) {
         let findCommands = [document.getElementById("cmd_find"),
@@ -3998,16 +3757,27 @@ var XULBrowserWindow = {
         if (gFindBar.findMode != gFindBar.FIND_NORMAL) {
           // Close the Find toolbar if we're in old-style TAF mode
           gFindBar.close();
         }
 
         // fix bug 253793 - turn off highlight when page changes
         gFindBar.getElement("highlight").checked = 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);
 
     gGestureSupport.restoreRotationState();
 
     // See bug 358202, when tabs are switched during a drag operation,
     // timers don't fire on windows (bug 203573)
     if (aRequest)
@@ -4015,22 +3785,18 @@ var XULBrowserWindow = {
     else
       this.asyncUpdateUI();
   },
 
   asyncUpdateUI: function () {
     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;
     this.updateStatusField();
   },
 
   // Properties used to cache security state used to update the UI
   _state: null,
@@ -4198,18 +3964,17 @@ 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 ||
+      if (!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");
       }
     }
@@ -4513,31 +4278,28 @@ function onViewToolbarsPopupShowing(aEve
     var deadItem = popup.childNodes[i];
     if (deadItem.hasAttribute("toolbarId"))
       popup.removeChild(deadItem);
   }
 
   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");
     if (toolbarName) {
       let menuItem = document.createElement("menuitem");
       let hidingAttribute = toolbar.getAttribute("type") == "menubar" ?
                             "autohide" : "collapsed";
       menuItem.setAttribute("id", "toggle_" + toolbar.id);
       menuItem.setAttribute("toolbarId", toolbar.id);
       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"));
       if (popup.id != "toolbar-context-menu")
         menuItem.setAttribute("key", toolbar.getAttribute("key"));
 
       popup.insertBefore(menuItem, firstMenuItem);
 
       menuItem.addEventListener("command", onViewToolbarCommand, false);
     }
   }
@@ -4556,205 +4318,249 @@ function setToolbarVisibility(toolbar, i
 
   toolbar.setAttribute(hidingAttribute, !isVisible);
   document.persist(toolbar.id, hidingAttribute);
 
   PlacesToolbarHelper.init();
   BookmarkingUI.onToolbarVisibilityChange();
   gBrowser.updateWindowResizers();
 
-#ifdef MENUBAR_CAN_AUTOHIDE
-  updateAppButtonDisplay();
+#ifdef CAN_DRAW_IN_TITLEBAR
+  updateTitlebarDisplay();
 #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 = {
   init: function () {
 #ifdef CAN_DRAW_IN_TITLEBAR
     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});
     this._initialized = true;
 #endif
   },
 
   allowedBy: function (condition, allow) {
 #ifdef CAN_DRAW_IN_TITLEBAR
     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";
   },
 
 #ifdef CAN_DRAW_IN_TITLEBAR
   observe: function (subject, topic, data) {
     if (topic == "nsPref:changed")
       this._readPref();
   },
 
+  _onMenuMutate: function (aMutations) {
+    // We don't care about restored windows, since the menu shouldn't be
+    // pushing the tab-strip down.
+    if (document.documentElement.getAttribute("sizemode") == "normal") {
+      return;
+    }
+
+    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();
 
     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;
+    function $(id) document.getElementById(id);
 
     let titlebar = $("titlebar");
+    let titlebarContent = $("titlebar-content");
+    let menubar = $("toolbar-menubar");
+
+    // Reset the margins and padding that _update modifies so that we can take
+    // accurate measurements.
+    titlebarContent.style.marginBottom = "";
+    titlebar.style.marginBottom = "";
+    menubar.style.paddingBottom = "";
 
     if (allowed) {
-      let tabsToolbar       = $("TabsToolbar");
-
-#ifdef MENUBAR_CAN_AUTOHIDE
-      let appmenuButtonBox  = $("appmenu-button-container");
-      this._sizePlaceholder("appmenu-button", rect(appmenuButtonBox).width);
-#endif
+      // We set the tabsintitlebar attribute first so that our CSS for
+      // tabsintitlebar manifests before we do our measurements.
+      document.documentElement.setAttribute("tabsintitlebar", "true");
+
       let captionButtonsBox = $("titlebar-buttonbox");
       this._sizePlaceholder("caption-buttons", rect(captionButtonsBox).width);
-
-      let tabsToolbarRect = rect(tabsToolbar);
-      let titlebarTop = rect($("titlebar-content")).top;
-      titlebar.style.marginBottom = - Math.min(tabsToolbarRect.top - titlebarTop,
-                                               tabsToolbarRect.height) + "px";
-
-      document.documentElement.setAttribute("tabsintitlebar", "true");
-
-      if (!this._draghandle) {
+#ifdef XP_MACOSX
+      let fullscreenButton  = $("titlebar-fullscreen-button");
+      this._sizePlaceholder("fullscreen-button", rect(fullscreenButton).width);
+#endif
+      let titlebarContentHeight = rect(titlebarContent).height;
+      let menuHeight = this._outerHeight(menubar);
+
+      // If the titlebar is taller than the menubar, add more padding to the
+      // bottom of the menubar so that it matches.
+      if (menuHeight && titlebarContentHeight > menuHeight) {
+        let menuTitlebarDelta = titlebarContentHeight - menuHeight;
+        menubar.style.paddingBottom = menuTitlebarDelta + "px";
+        menuHeight += menuTitlebarDelta;
+      }
+
+      // Next, we calculate how much we need to stretch the titlebar down to
+      // go all the way to the bottom of the tab strip.
+      let tabsToolbar = $("TabsToolbar");
+      let tabAndMenuHeight = this._outerHeight(tabsToolbar) + menuHeight;
+      titlebarContent.style.marginBottom = tabAndMenuHeight + "px";
+
+      // Finally, we have to determine how much to bring up the elements below
+      // the titlebar. We start with a baseHeight of tabAndMenuHeight, to offset
+      // the amount we added to the titlebar content. Then, we have two cases:
+      //
+      // 1) The titlebar is larger than the tabAndMenuHeight. This can happen in
+      //    large font mode with the menu autohidden. In this case, we want to
+      //    add tabAndMenuHeight, since this should line up the bottom of the
+      //    tabstrip with the bottom of the titlebar.
+      //
+      // 2) The titlebar is equal to or smaller than the tabAndMenuHeight. This
+      //    is the more common case, and occurs with normal font sizes. In this
+      //    case, we want to bring the menu and tabstrip right up to the top of
+      //    the titlebar, so we add the titlebarContentHeight to the baseHeight.
+      let baseHeight = tabAndMenuHeight;
+      baseHeight += (titlebarContentHeight > tabAndMenuHeight) ? tabAndMenuHeight
+                                                               : titlebarContentHeight;
+      titlebar.style.marginBottom = "-" + baseHeight + "px";
+
+      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");
-
-      titlebar.style.marginBottom = "";
     }
   },
 
   _sizePlaceholder: function (type, width) {
     Array.forEach(document.querySelectorAll(".titlebar-placeholder[type='"+ type +"']"),
                   function (node) { node.width = width; });
   },
+
+  /**
+   * Retrieve the height of an element, including its top and bottom
+   * margins.
+   *
+   * @param ele
+   *        The element to measure.
+   * @return
+   *        The height and margins as an integer. If the height of the element
+   *        is 0, then this returns 0, regardless of what the margins are.
+   */
+  _outerHeight: function (ele) {
+    let cstyle = document.defaultView.getComputedStyle(ele);
+    let margins = parseInt(cstyle.marginTop) + parseInt(cstyle.marginBottom);
+    let height = ele.getBoundingClientRect().height;
+    return height > 0 ? Math.abs(height + margins) : 0;
+  },
 #endif
 
   uninit: function () {
 #ifdef CAN_DRAW_IN_TITLEBAR
     this._initialized = false;
     Services.prefs.removeObserver(this._prefName, this);
+    this._menuObserver.disconnect();
 #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;
-
-  if (displayAppButton)
+function updateTitlebarDisplay() {
+  let drawInTitlebar = !gInPrintPreviewMode && window.toolbar.visible;
+  document.getElementById("titlebar").hidden = !drawInTitlebar;
+
+  if (drawInTitlebar)
     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;
-#endif
+  TabsInTitlebar.allowedBy("drawing-in-titlebar", drawInTitlebar);
 }
 #endif
 
 #ifdef CAN_DRAW_IN_TITLEBAR
 function onTitlebarMaxClick() {
   if (window.windowState == window.STATE_MAXIMIZED)
     window.restore();
   else
@@ -6967,39 +6773,32 @@ let gPrivateBrowsingUI = {
       return;
     }
 
     // Disable the Clear Recent History... menu item when in PB mode
     // temporary fix until bug 463607 is fixed
     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) {
         docElement.setAttribute("title",
           docElement.getAttribute("title_privatebrowsing"));
         docElement.setAttribute("titlemodifier",
           docElement.getAttribute("titlemodifier_privatebrowsing"));
       }
       docElement.setAttribute("privatebrowsingmode",
         PrivateBrowsingUtils.permanentPrivateBrowsing ? "permanent" : "temporary");
       gBrowser.updateTitlebar();
 
       if (PrivateBrowsingUtils.permanentPrivateBrowsing) {
         // 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);
           if (newWindow && newPrivateWindow) {
             newPrivateWindow.hidden = true;
             newWindow.label = newPrivateWindow.label;
             newWindow.accessKey = newPrivateWindow.accessKey;
             newWindow.command = newPrivateWindow.command;
@@ -7203,21 +7002,16 @@ function duplicateTabIn(aTab, where, del
       // A background tab has been opened, nothing else to do here.
       break;
     case "tab":
       gBrowser.selectedTab = newTab;
       break;
   }
 }
 
-function toggleAddonBar() {
-  let addonBar = document.getElementById("addon-bar");
-  setToolbarVisibility(addonBar, addonBar.collapsed);
-}
-
 var Scratchpad = {
   prefEnabledName: "devtools.scratchpad.enabled",
 
   openScratchpad: function SP_openScratchpad() {
     return this.ScratchpadManager.openScratchpad();
   }
 };
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -4,52 +4,57 @@
 #
 # 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/.
 
 <?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"?>
 <?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
 
 # All DTD information is stored in a separate file so that it can be shared by
 # hiddenWindow.xul.
 #include browser-doctype.inc
 
 <window id="main-window"
         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:svg="http://www.w3.org/2000/svg"
+        xmlns:html="http://www.w3.org/1999/xhtml"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         onload="gBrowserInit.onLoad()" onunload="gBrowserInit.onUnload()" onclose="return WindowIsClosing();"
         title="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
         title_normal="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
 #ifdef XP_MACOSX
         title_privatebrowsing="&mainWindow.title;@PRE_RELEASE_SUFFIX@&mainWindow.titlemodifiermenuseparator;&mainWindow.titlePrivateBrowsingSuffix;"
         titledefault="&mainWindow.title;@PRE_RELEASE_SUFFIX@"
         titlemodifier=""
         titlemodifier_normal=""
         titlemodifier_privatebrowsing="&mainWindow.titlePrivateBrowsingSuffix;"
+        chromemargin="0,-1,-1,-1"
 #else
         title_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;"
         titlemodifier="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
         titlemodifier_normal="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@"
         titlemodifier_privatebrowsing="&mainWindow.titlemodifier;@PRE_RELEASE_SUFFIX@ &mainWindow.titlePrivateBrowsingSuffix;"
 #endif
         titlemenuseparator="&mainWindow.titlemodifiermenuseparator;"
         lightweightthemes="true"
         lightweightthemesfooter="browser-bottombox"
         windowtype="navigator:browser"
         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
 # wishes to include *must* go into the global-scripts.inc file
 # so that they can be shared by macBrowserOverlay.xul.
 #include global-scripts.inc
 <script type="application/javascript" src="chrome://browser/content/nsContextMenu.js"/>
 
@@ -236,20 +241,16 @@
            rolluponmousewheel="true"
            consumeoutsideclicks="false"
            noautofocus="true"
            position="topcenter topright"/>
 
     <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;"/>
     </menupopup>
 
     <menupopup id="blockedPopupOptions"
                onpopupshowing="gPopupBlockerObserver.fillPopupList(event);"
                onpopuphiding="gPopupBlockerObserver.onPopupHiding(event);">
@@ -357,20 +358,16 @@
       <hbox pack="center">
         <button id="ctrlTab-showAll" class="ctrlTab-preview" noicon="true"/>
       </hbox>
     </panel>
 
     <!-- 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">
       <label class="tooltip-label" value="&backButton.tooltip;"/>
 #ifdef XP_MACOSX
       <label class="tooltip-label" value="&backForwardButtonMenuMac.tooltip;"/>
 #else
       <label class="tooltip-label" value="&backForwardButtonMenu.tooltip;"/>
@@ -383,39 +380,37 @@
       <label class="tooltip-label" value="&backForwardButtonMenuMac.tooltip;"/>
 #else
       <label class="tooltip-label" value="&backForwardButtonMenu.tooltip;"/>
 #endif
     </tooltip>
 
 #include popup-notifications.inc
 
+#include ../../components/customizableui/content/panelUI.inc.xul
   </popupset>
 
 #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>
+    <spacer id="titlebar-spacer" flex="1"/>
+    <hbox id="titlebar-buttonbox-container" align="start"
+#ifdef XP_MACOSX
+          ordinal="0"
 #endif
-    <spacer id="titlebar-spacer" flex="1"/>
-    <hbox id="titlebar-buttonbox-container" align="start">
+    >
       <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
 
 <deck flex="1" id="tab-view-deck">
 <vbox flex="1" id="browser-panel">
 
   <toolbox id="navigator-toolbox"
@@ -433,325 +428,438 @@
              context="toolbar-context-menu">
       <toolbaritem id="menubar-items" align="center">
 # 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"/>
+      <hbox class="titlebar-placeholder" type="caption-buttons"
+#ifndef XP_MACOSX
+            ordinal="1000"
+#endif
+      />
+
+#ifdef XP_MACOSX
+      <hbox class="titlebar-placeholder" type="fullscreen-button"/>
+#endif
+#endif
+    </toolbar>
+
+    <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"
+             defaultset="tabbrowser-tabs,new-tab-button,alltabs-button,tabs-closebutton"
+             collapsed="true">
+
+      <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 close-icon"
+                     command="cmd_close"
+                     label="&closeTab.label;"
+                     tooltiptext="&closeTab.label;"/>
+
+#ifdef CAN_DRAW_IN_TITLEBAR
+      <hbox class="titlebar-placeholder" type="caption-buttons"
+#ifndef XP_MACOSX
+            ordinal="1000"
+#endif
+      />
+
+#ifdef XP_MACOSX
+      <hbox class="titlebar-placeholder" type="fullscreen-button"/>
+#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"
-             toolbarname="&navbarCmd.label;" accesskey="&navbarCmd.accesskey;"
+             aria-label="&navbarCmd.label;"
              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"
+             defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,webrtc-status-button,bookmarks-menu-button,downloads-button,home-button,social-share-button"
+             customizationtarget="nav-bar-customizationtarget"
+             overflowbutton="nav-bar-overflow-button"
              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>
+      <hbox id="nav-bar-customizationtarget" class="customization-target" flex="1">
+        <toolbaritem id="unified-back-forward-button" class="chromeclass-toolbar-additional"
+                     context="backForwardMenu" removable="false"
+                     forwarddisabled="true"
+                     title="&backForwardItem.title;"
+                     nooverflow="true">
+          <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>
 
-      <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="blocked-plugins-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"/>
+        <toolbaritem id="urlbar-container" align="center" flex="400" persist="width" combined="true"
+                     title="&locationItem.title;" class="chromeclass-location" removable="false" nooverflow="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="blocked-plugins-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="go-button"
+                     class="urlbar-icon"
+                     tooltiptext="&goEndCap.tooltip;"
+                     onclick="gURLBar.handleCommand(event);"/>
             </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="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>
+            <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>
 
-      <toolbarbutton id="reload-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&reloadCmd.label;" removable="true"
-                     command="Browser:ReloadOrDuplicate"
-                     onclick="checkForMiddleClick(this, event);"
-                     tooltiptext="&reloadButton.tooltip;"/>
+        <toolbarbutton id="reload-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       label="&reloadCmd.label;" removable="true"
+                       command="Browser:ReloadOrDuplicate"
+                       onclick="checkForMiddleClick(this, event);"
+                       tooltiptext="&reloadButton.tooltip;"
+                       nooverflow="true"/>
 
-      <toolbarbutton id="stop-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     label="&stopCmd.label;" removable="true"
-                     command="Browser:Stop"
-                     tooltiptext="&stopButton.tooltip;"/>
+        <toolbarbutton id="stop-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       label="&stopCmd.label;" removable="true"
+                       command="Browser:Stop"
+                       tooltiptext="&stopButton.tooltip;"
+                       nooverflow="true"/>
 
-      <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>
+        <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>
 
-      <toolbarbutton id="webrtc-status-button"
-                     class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     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);"/>
-      </toolbarbutton>
+        <toolbarbutton id="webrtc-status-button"
+                       class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       type="menu"
+                       hidden="true"
+                       orient="horizontal"
+                       label="&webrtcIndicatorButton.label;"
+                       tooltiptext="&webrtcIndicatorButton.tooltip;"
+                       nooverflow="true">
+          <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"
-                     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="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);"
+                       oncommand="BookmarkingUI.onCommand(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_subscribeToPageMenuitem"
 #ifndef XP_MACOSX
-                    class="menuitem-iconic"
+                      class="menuitem-iconic"
 #endif
-                    label="&bookmarkThisPageCmd.label;"
-                    command="Browser:AddBookmarkAs"
-                    key="addBookmarkAsKb"/>
-          <menuitem id="BMB_subscribeToPageMenuitem"
+                      label="&subscribeToPageMenuitem.label;"
+                      oncommand="return FeedHandler.subscribeToFeed(null, event);"
+                      onclick="checkForMiddleClick(this, event);"
+                      observes="singleFeedMenuitemState"/>
+            <menu id="BMB_subscribeToPageMenupopup"
 #ifndef XP_MACOSX
-                    class="menuitem-iconic"
+                  class="menu-iconic"
 #endif
-                    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"
-#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"
+                  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>
 
-      <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;"/>
+        <!-- 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"
+                       tooltiptext="&downloads.tooltip;"/>
 
-      <toolbarbutton id="social-share-button"
-                     class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     hidden="true"
-                     label="&sharePageCmd.label;"
-                     tooltiptext="&sharePageCmd.label;"
-                     command="Social:SharePage"/>
+        <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;"/>
+
 
-      <toolbaritem id="social-toolbar-item"
-                   class="chromeclass-toolbar-additional"
-                   removable="false"
-                   title="&socialToolbar.title;"
-                   hidden="true"
-                   skipintoolbarset="true"
-                   observes="socialActiveBroadcaster">
+        <toolbarbutton id="social-share-button"
+                       class="toolbarbutton-1 chromeclass-toolbar-additional"
+                       hidden="true"
+                       nooverflow="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"
+                     nooverflow="true"
+                     skipintoolbarset="true"
+                     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>
-        <toolbarbutton id="social-mark-button"
+              <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>
+          <toolbarbutton id="social-mark-button"
+                         class="toolbarbutton-1"
+                         hidden="true"
+                         disabled="true"
+                         command="Social:TogglePageMark"/>
+        </toolbaritem>
+      </hbox>
+
+      <toolbarbutton id="nav-bar-overflow-button"
+                     class="toolbarbutton-1 chromeclass-toolbar-additional chevron 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"
-                       hidden="true"
-                       disabled="true"
-                       command="Social:TogglePageMark"/>
+                       label="&brandShortName;"
+                       tooltiptext="&appmenu.title;"
+                       oncommand="PanelUI.toggle(event);"/>
       </toolbaritem>
 
-      <hbox id="window-controls" hidden="true" pack="end">
+      <hbox id="window-controls" hidden="true" pack="end" skipintoolbarset="true">
         <toolbarbutton id="minimize-button"
                        tooltiptext="&fullScreenMinimize.tooltip;"
                        oncommand="window.minimize();"/>
 
         <toolbarbutton id="restore-button"
                        tooltiptext="&fullScreenRestore.tooltip;"
                        oncommand="BrowserFullScreen();"/>
 
@@ -806,250 +914,111 @@
                          tooltip="bhTooltip" popupsinherittooltip="true"
                          context="placesContext"/>
             </toolbarbutton>
           </hbox>
         </hbox>
       </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">
 
 # Update primaryToolbarButtons in browser/themes/shared/browser.inc when adding
 # 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;"/>
+#ifdef XP_MACOSX
+                     command="cmd_print"
+#else
+                     command="cmd_printPreview"
+#endif
+                     label="&printButton.label;" 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)"/>
 
       <toolbarbutton id="new-window-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&newNavigatorCmd.label;"
                      command="key_newNavigator"
                      tooltiptext="&newWindowButton.tooltip;"
                      ondrop="newWindowButtonObserver.onDrop(event)"
                      ondragover="newWindowButtonObserver.onDragOver(event)"
                      ondragenter="newWindowButtonObserver.onDragOver(event)"
                      ondragexit="newWindowButtonObserver.onDragExit(event)"/>
 
       <toolbarbutton id="fullscreen-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      observes="View:FullScreen"
                      type="checkbox"
                      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"
                      label="&syncToolbarButton.label;"
                      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"
                      tooltiptext="&tabGroupsButton.tooltip;"
                      observes="tabviewGroupsNumber"/>
     </toolbarpalette>
   </toolbox>
 
   <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>
+  <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" disablehistory="true"
-                  flex="1" contenttooltip="aHTMLTooltip"
-                  tabcontainer="tabbrowser-tabs"
-                  contentcontextmenu="contentAreaContextMenu"
-                  autocompletepopup="PopupAutoComplete"/>
-      <chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/>
-      <statuspanel id="statusbar-display" inactive="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"
+      <splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
+      <vbox id="appcontent" flex="1">
+        <tabbrowser id="content" disablehistory="true"
+                    flex="1" contenttooltip="aHTMLTooltip"
+                    tabcontainer="tabbrowser-tabs"
+                    contentcontextmenu="contentAreaContextMenu"
+                    autocompletepopup="PopupAutoComplete"
+                    onclick="contentAreaClick(event, false);"/>
+        <chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/>
+        <statuspanel id="statusbar-display" inactive="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. -->
       <vbox id="full-screen-warning-message" align="center">
         <description id="full-screen-domain-text"/>
         <description class="full-screen-description" value="&fullscreenExitHint.value;"/>
         <vbox id="full-screen-approval-pane" align="center">
           <description class="full-screen-description" value="&fullscreenApproval.value;"/>
@@ -1088,66 +1057,46 @@
                          tooltiptext="&devToolbarToolsButton.tooltip;"/>
 #ifndef XP_MACOSX
           <toolbarbutton id="developer-toolbar-closebutton"
                          class="devtools-closebutton"
                          oncommand="DeveloperToolbar.hide();"
                          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>
 
+  <svg:svg height="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>
+    <svg:clipPath id="tab-clip-path-outer" clipPathUnits="objectBoundingBox">
+      <svg:path d="m 0.1894,0 0,0.4194 C 0.1742,0.5484 0.1667,0.6774 0.1364,0.7903 0.1123,0.8935 0,0.9032 0,0.9032 l 0,0.0968 1,0 0,-0.0968 c 0,0 -0.1121,0 -0.1364,-0.1129 C 0.8333,0.6774 0.8258,0.5452 0.8106,0.4194 l 0,-0.4194 z"/>
+    </svg:clipPath>
+
 #ifndef XP_UNIX
-  <svg:svg height="0">
     <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: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:path d="m 0,-5 0,9.03 C 3.6,6.8 6,11.1 6,16 6,21 3.6,25 0,28 l 0,27 10000,0 0,-55 L 0,-5 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: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>
+#endif
   </svg:svg>
-#endif
 
 </vbox>
 # <iframe id="tab-view"> is dynamically appended as the 2nd child of #tab-view-deck.
 #     Introducing the iframe dynamically, as needed, was found to be better than
 #     starting with an empty iframe here in browser.xul from a Ts standpoint.
 </deck>
 
 </window>
--- a/browser/base/content/global-scripts.inc
+++ b/browser/base/content/global-scripts.inc
@@ -4,10 +4,11 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 <script type="application/javascript" src="chrome://global/content/printUtils.js"/>
 <script type="application/javascript" src="chrome://global/content/viewZoomOverlay.js"/>
 <script type="application/javascript" src="chrome://browser/content/places/browserPlacesViews.js"/>
 <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"/>
--- a/browser/base/content/newtab/newTab.xul
+++ b/browser/base/content/newtab/newTab.xul
@@ -26,16 +26,17 @@
                      value="&newtab.undo.removedLabel;" />
           <xul:button id="newtab-undo-button" tabindex="-1"
                       label="&newtab.undo.undoButton;"
                       class="newtab-undo-button" />
           <xul:button id="newtab-undo-restore-button" tabindex="-1"
                       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>
 
       <div id="newtab-horizontal-margin">
         <div class="newtab-side-margin"/>
 
         <div id="newtab-grid">
--- a/browser/base/content/sync/notification.xml
+++ b/browser/base/content/sync/notification.xml
@@ -78,17 +78,17 @@
 
     </implementation>
   </binding>
 
   <binding id="notification" extends="chrome://global/content/bindings/notification.xml#notification">
     <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()"/>
         <xul:hbox anonid="details" align="center" flex="1">
           <xul:image anonid="messageImage" class="messageImage" xbl:inherits="src=image"/>
           <xul:description anonid="messageText" class="messageText" xbl:inherits="xbl:text=label"/>
 
           <!-- The children are the buttons defined by the notification. -->
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -36,16 +36,17 @@ tabpanels {
   background-color: transparent;
 }
 
 .tab-drop-indicator {
   position: relative;
   z-index: 2;
 }
 
+.tab-icon-image:not([src]):not([pinned]),
 .tab-throbber:not([busy]),
 .tab-throbber[busy] + .tab-icon-image {
   display: none;
 }
 
 .closing-tabs-spacer {
   pointer-events: none;
 }
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -135,18 +135,17 @@
         ]]></getter>
       </property>
 
       <method name="updateWindowResizers">
         <body><![CDATA[
           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;
           }
         ]]></body>
       </method>
 
       <method name="_setCloseKeyState">
         <parameter name="aEnabled"/>
@@ -1338,18 +1337,17 @@
             b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
             b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
 
             if (Services.prefs.getPrefType("browser.tabs.remote") == Services.prefs.PREF_BOOL &&
                 Services.prefs.getBoolPref("browser.tabs.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");
             }
 
             if (this.hasAttribute("autocompletepopup"))
               b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
             b.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
 
             // Create the browserStack container
@@ -3194,20 +3192,16 @@
       <method name="_propagateVisibility">
         <body><![CDATA[
           let visible = this.visible;
 
           document.getElementById("menu_closeWindow").hidden = !visible;
           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>
 
       <method name="updateVisibility">
         <body><![CDATA[
           if (this.childNodes.length - this.tabbrowser._removingTabs.length == 1)
             this.visible = window.toolbar.visible;
@@ -3549,19 +3543,17 @@
           switch (aEvent.type) {
             case "load":
               this.updateVisibility();
               break;
             case "resize":
               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;
               }
@@ -3852,18 +3844,17 @@
         }
       ]]></handler>
 
       <handler event="dblclick"><![CDATA[
 #ifndef XP_MACOSX
         // 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
 
         if (event.button != 0 ||
             event.originalTarget.localName != "box")
           return;
 
         // See hack note in the tabbrowser-close-tab-button binding
@@ -4284,17 +4275,17 @@
          * with the tabbar as its event target (and explicit/originalTarget),
          * which treats that as a mouse gesture for opening a new tab.
          * In this context, we're manually blocking the dblclick event
          * (see dblclick handler).
          */
         var clickedOnce = false;
         function enableDblClick(event) {
           var target = event.originalTarget;
-          if (target.className == 'tab-close-button')
+          if (target.classList.contains("tab-close-button"))
             target._ignoredClick = true;
           if (!clickedOnce) {
             clickedOnce = true;
             return;
           }
           tabContainer._blockDblClick = false;
           tabContainer.removeEventListener("click", enableDblClick, true);
         }
@@ -4340,17 +4331,17 @@
                      validate="never"
                      role="presentation"/>
           <xul:label flex="1"
                      xbl:inherits="value=label,crop,accesskey,fadein,pinned,selected"
                      class="tab-text tab-label"
                      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>
 
     <implementation>
       <property name="pinned" readonly="true">
         <getter>
           return this.getAttribute("pinned") == "true";
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -132,20 +132,17 @@ MOCHITEST_BROWSER_FILES = \
                  browser_bug585785.js \
                  browser_bug585830.js \
                  browser_bug590206.js \
                  browser_bug592338.js \
                  browser_bug594131.js \
                  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 \
                  browser_bug647886.js \
                  browser_bug655584.js \
                  browser_bug664672.js \
                  browser_bug678392.js \
                  browser_bug678392-1.html \
@@ -163,24 +160,22 @@ MOCHITEST_BROWSER_FILES = \
                  browser_bug783614.js \
                  browser_bug797677.js \
                  browser_bug816527.js \
                  browser_bug817947.js \
                  browser_bug822367.js \
                  browser_bug832435.js \
                  browser_bug839103.js \
                  browser_canonizeURL.js \
-                 browser_customize.js \
                  browser_findbarClose.js \
                  browser_homeDrop.js \
                  browser_keywordBookmarklets.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_customize_popupNotification.js \
-                 browser_disablechrome.js \
                  browser_discovery.js \
                  browser_duplicateIDs.js \
                  browser_fullscreen-window-open.js \
                  file_fullscreen-window-open.html \
                  browser_gestureSupport.js \
                  browser_getshortcutoruri.js \
                  browser_hide_removing.js \
                  browser_overflowScroll.js \
@@ -238,17 +233,16 @@ MOCHITEST_BROWSER_FILES = \
                  browser_urlHighlight.js \
                  browser_visibleFindSelection.js \
                  browser_visibleTabs.js \
                  browser_visibleTabs_contextMenu.js \
                  browser_visibleTabs_bookmarkAllPages.js \
                  browser_visibleTabs_bookmarkAllTabs.js \
                  browser_visibleTabs_tabPreview.js \
                  bug592338.html \
-                 disablechrome.html \
                  discovery.html \
                  domplate_test.js \
                  file_bug822367_1.html \
                  file_bug822367_1.js \
                  file_bug822367_2.html \
                  file_bug822367_3.html \
                  file_bug822367_4.html \
                  file_bug822367_4.js \
@@ -282,19 +276,16 @@ MOCHITEST_BROWSER_FILES = \
                  zoom_test.html \
                  dummy_page.html \
                  file_bug550565_popup.html \
                  file_bug550565_favicon.ico \
                  browser_aboutHome.js \
                  app_bug575561.html \
                  app_subframe_bug575561.html \
                  browser_contentAreaClick.js \
-                 browser_addon_bar_close_button.js \
-                 browser_addon_bar_shortcut.js \
-                 browser_addon_bar_aomlistener.js \
                  test_bug628179.html \
                  browser_wyciwyg_urlbarCopying.js \
                  test_wyciwyg_copying.html \
                  authenticate.sjs \
                  browser_minimize.js \
                  browser_aboutSyncProgress.js \
                  browser_middleMouse_inherit.js \
                  redirect_bug623155.sjs \
deleted file mode 100644
--- a/browser/base/content/test/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();
-}
deleted file mode 100644
--- a/browser/base/content/test/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");
-}
deleted file mode 100644
--- a/browser/base/content/test/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");
-}
deleted file mode 100644
--- a/browser/base/content/test/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");
-}
--- a/browser/base/content/test/browser_bug462289.js
+++ b/browser/base/content/test/browser_bug462289.js
@@ -29,26 +29,19 @@ function step2()
   setTimeout(step3, 0);
 }
 
 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");
 
   EventUtils.synthesizeMouseAtCenter(tab1, {});
   setTimeout(step4, 0);
 }
 
 function step4()
deleted file mode 100644
--- a/browser/base/content/test/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");
-}
deleted file mode 100644
--- a/browser/base/content/test/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();
-  }
-}
deleted file mode 100644
--- a/browser/base/content/test/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");
-}
--- a/browser/base/content/test/browser_bug624734.js
+++ b/browser/base/content/test/browser_bug624734.js
@@ -6,18 +6,18 @@
 
 function test() {
   waitForExplicitFinish();
 
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   tab.linkedBrowser.addEventListener("load", (function(event) {
     tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
 
-    is(BookmarkingUI.star.getAttribute("tooltiptext"),
+    is(BookmarkingUI.button.getAttribute("tooltiptext"),
        BookmarkingUI._unstarredTooltip,
        "Star icon should have the unstarred tooltip text");
-  
+
     gBrowser.removeCurrentTab();
     finish();
   }), true);
 
   tab.linkedBrowser.loadURI("http://example.com/browser/browser/base/content/test/dummy_page.html");
 }
deleted file mode 100644
--- a/browser/base/content/test/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;
-}
deleted file mode 100644
--- a/browser/base/content/test/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/";
-
-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
deleted file mode 100644
--- a/browser/base/content/test/disablechrome.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<html>
-<body>
-</body>
-</html>
--- a/browser/base/content/test/head.js
+++ b/browser/base/content/test/head.js
@@ -32,59 +32,37 @@ function updateTabContextMenu(tab) {
     tab = gBrowser.selectedTab;
   var evt = new Event("");
   tab.dispatchEvent(evt);
   menu.openPopup(tab, "end_after", 0, 0, true, false, evt);
   is(TabContextMenu.contextTab, tab, "TabContextMenu context is the expected 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) {
   var tries = 0;
   var interval = setInterval(function() {
     if (tries >= 30) {
       ok(false, errorMsg);
       moveOn();
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -932,26 +932,26 @@
                   pack="end" align="center">
           <xul:button anonid="button"
                       class="popup-notification-menubutton"
                       type="menu-button"
                       xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey">
             <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>
           </xul:button>
         </xul:hbox>
       </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>
     </content>
     <implementation>
       <constructor><![CDATA[
         this.cancelbtn.setAttribute("tooltiptext", gNavigatorBundle.getString("addonDownloadCancelTooltip"));
 
@@ -1164,26 +1164,26 @@
                      style="visibility:hidden" width="16" height="16"/>
           <xul:button anonid="button"
                       type="menu-button"
                       class="popup-notification-menubutton"
                       xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey">
             <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>
           </xul:button>
         </xul:hbox>
       </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>
     </content>
     <implementation>
       <constructor><![CDATA[
         // this.notification.options.identity is used to pass identity-specific info to the binding
         let origin = this.identity.origin
@@ -1503,17 +1503,17 @@
       <xul:vbox flex="1" align="stretch" class="popup-notification-main-box"
                 xbl:inherits="popupid">
         <xul:hbox class="click-to-play-plugins-notification-description-box" flex="1" align="start">
           <xul:description class="click-to-play-plugins-outer-description" flex="1">
             <html:span anonid="click-to-play-plugins-notification-description" />
             <xul:label class="text-link click-to-play-plugins-notification-link" anonid="click-to-play-plugins-notification-link" />
           </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>
         <xul:grid anonid="click-to-play-plugins-notification-center-box"
                   class="click-to-play-plugins-notification-center-box">
           <xul:columns>
             <xul:column flex="1"/>
             <xul:column/>
@@ -2003,17 +2003,17 @@
         <xul:hbox align="center" flex="1">
           <xul:image class="panel-promo-icon"/>
           <xul:description anonid="promo-message" class="panel-promo-message" flex="1">
             <xul:description anonid="promo-link"
                              class="plain text-link inline-link"
                              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>
     </content>
 
     <implementation implements="nsIDOMEventListener">
       <constructor><![CDATA[
         this._panel.addEventListener("popupshowing", this, false);
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -8,18 +8,17 @@ browser.jar:
 %  overlay chrome://global/content/console.xul chrome://browser/content/jsConsoleOverlay.xul
 %  overlay chrome://mozapps/content/update/updates.xul chrome://browser/content/softwareUpdateOverlay.xul
 #endif
 #ifdef XP_WIN
 %  overlay chrome://browser/content/browser.xul chrome://browser/content/win6BrowserOverlay.xul os=WINNT osversion>=6
 #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)
         content/browser/aboutRobots.xhtml             (content/aboutRobots.xhtml)
         content/browser/abouthome/aboutHome.xhtml     (content/abouthome/aboutHome.xhtml)
         content/browser/abouthome/aboutHome.js        (content/abouthome/aboutHome.js)
 *       content/browser/abouthome/aboutHome.css       (content/abouthome/aboutHome.css)
         content/browser/abouthome/noise.png           (content/abouthome/noise.png)
--- a/browser/branding/nightly/branding.nsi
+++ b/browser/branding/nightly/branding.nsi
@@ -3,17 +3,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # NSIS branding defines for nightly builds.
 # The official release build branding.nsi is located in other-license/branding/firefox/
 # The unofficial build branding.nsi is located in browser/branding/unofficial/
 
 # BrandFullNameInternal is used for some registry and file system values
 # instead of BrandFullName and typically should not be modified.
-!define BrandFullNameInternal "Nightly"
+!define BrandFullNameInternal "UX"
 !define CompanyName           "mozilla.org"
 !define URLInfoAbout          "http://www.mozilla.org"
 !define URLUpdateInfo         "http://www.mozilla.org/projects/firefox"
 
 !define URLStubDownload "http://download.mozilla.org/?product=firefox-nightly-latest&os=win&lang=${AB_CD}"
 !define URLManualDownload "https://www.mozilla.org/${AB_CD}/firefox/installer-help/?channel=nightly&installer_lang=${AB_CD}"
 !define Channel "nightly"
 
--- a/browser/branding/nightly/configure.sh
+++ b/browser/branding/nightly/configure.sh
@@ -1,5 +1,5 @@
 # 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/.
 
-MOZ_APP_DISPLAYNAME=Nightly
+MOZ_APP_DISPLAYNAME=UX
--- a/browser/branding/nightly/locales/en-US/brand.dtd
+++ b/browser/branding/nightly/locales/en-US/brand.dtd
@@ -1,8 +1,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/. -->
 
-<!ENTITY  brandShortName        "Nightly">
-<!ENTITY  brandFullName         "Nightly">
+<!ENTITY  brandShortName        "UX">
+<!ENTITY  brandFullName         "UX">
 <!ENTITY  vendorShortName       "Mozilla">
 <!ENTITY  trademarkInfo.part1   " ">
--- a/browser/branding/nightly/locales/en-US/brand.properties
+++ b/browser/branding/nightly/locales/en-US/brand.properties
@@ -1,9 +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/.
 
-brandShortName=Nightly
-brandFullName=Nightly
+brandShortName=UX
+brandFullName=UX
 vendorShortName=Mozilla
 
 syncBrandShortName=Sync
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -81,16 +81,18 @@ static RedirEntry kRedirMap[] = {
   { "preferences", "chrome://browser/content/preferences/in-content/preferences.xul",
     nsIAboutModule::ALLOW_SCRIPT },
   { "downloads", "chrome://browser/content/downloads/contentAreaDownloadsView.xul",
     nsIAboutModule::ALLOW_SCRIPT },
 #ifdef MOZ_SERVICES_HEALTHREPORT
   { "healthreport", "chrome://browser/content/abouthealthreport/abouthealth.xhtml",
     nsIAboutModule::ALLOW_SCRIPT },
 #endif
+  { "customizing", "chrome://browser/content/customizableui/aboutCustomizing.xhtml",
+    nsIAboutModule::ALLOW_SCRIPT },
 };
 static const int kRedirTotal = NS_ARRAY_LENGTH(kRedirMap);
 
 static nsAutoCString
 GetAboutModuleName(nsIURI *aURI)
 {
   nsAutoCString path;
   aURI->GetPath(path);
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -103,16 +103,17 @@ static const mozilla::Module::ContractID
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "home", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "permissions", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "downloads", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #ifdef MOZ_SERVICES_HEALTHREPORT
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #endif
+    { 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)
     { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
 #endif
     { NULL }
 };
 
new file mode 100644
--- /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>
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/content/customizeMode.inc.xul
@@ -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/. -->
+
+<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" flex="1">
+        <hbox id="customization-panelHolder"/>
+        <box class="panel-inner-arrowcontentfooter" hidden="true"/>
+      </box>
+    </vbox>
+    <spacer flex="1"/>
+  </vbox>
+</hbox>
new file mode 100644
--- /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
+
new file mode 100644
--- /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/.
+
new file mode 100644
--- /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: hidden;
+}
+
+.panel-subviews[panelopen] {
+  transition: transform 150ms;
+}
+
+.panel-viewcontainer[panelopen]:-moz-any(:not([viewtype="main"]),[transitioning="true"]) {
+  transition: height 150ms;
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -0,0 +1,81 @@
+<!-- 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"
+       consumeoutsideclicks="true"
+       noautofocus="true">
+  <panelmultiview id="PanelUI-multiView" mainViewId="PanelUI-mainView">
+    <panelview id="PanelUI-mainView" contextmenu="customizationPanelContextMenu">
+      <vbox id="PanelUI-contents" type="grid"/>
+
+      <vbox id="PanelUI-mainView-spring" flex="1"/>
+
+      <footer class="PanelUI-footer" align="center">
+        <!-- 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-btn" label="&helpMenu.label;"
+                       onclick="PanelUI.showHelpView(this.parentNode);"/>
+        <spacer flex="1"/>
+        <toolbarbutton id="PanelUI-customize-btn" label="&appMenuCustomize.label;"
+                       command="cmd_CustomizeToolbars"/>
+      </footer>
+    </panelview>
+
+    <panelview id="PanelUI-history" flex="1">
+      <label value="&appMenuHistory.label;"/>
+      <toolbarbutton id="appMenuClearRecentHistory"
+                     label="&appMenuHistory.clearRecent.label;"
+                     command="Tools:Sanitize"/>
+      <toolbarbutton id="appMenuRestoreLastSession"
+                     label="&appMenuHistory.restoreSession.label;"
+                     command="Browser:RestoreLastSession"/>
+      <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-feeds" flex="1" oncommand="FeedHandler.subscribeToFeed(null, event);"></panelview>
+
+    <panelview id="PanelUI-help" flex="1">
+      <label value="&helpMenu.label;"/>
+      <vbox id="PanelUI-helpItems"/>
+    </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-list">
+  </vbox>
+</panel>
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/content/panelUI.js
@@ -0,0 +1,280 @@
+/* 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");
+/**
+ * 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-help",
+      menuButton: "PanelUI-menu-button",
+      panel: "PanelUI-popup"
+    };
+  },
+
+  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);
+      });
+    }
+
+    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);
+  },
+
+  uninit: function() {
+    for (let event of this.kEvents) {
+      this.panel.removeEventListener(event, this);
+    }
+    this.helpView.removeEventListener("ViewShowing", this._onHelpViewShow);
+    this.helpView.removeEventListener("ViewHiding", this._onHelpViewHide);
+  },
+
+  /**
+   * 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.multiView.setMainView(aMainView);
+  },
+
+  /**
+   * Opens the menu panel if it's closed, or closes it if it's
+   * open. 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 that triggers the toggle.
+   */
+  toggle: function(aEvent) {
+    if (this.panel.state == "open") {
+      this.hide();
+    } else if (this.panel.state == "closed") {
+      this.ensureRegistered();
+      this.panel.hidden = false;
+
+      let anchor = aEvent.target;
+      let iconAnchor =
+        document.getAnonymousElementByAttribute(anchor, "class",
+                                                "toolbarbutton-icon");
+      this.panel.openPopup(iconAnchor || anchor, "bottomcenter topright");
+    }
+  },
+
+  /**
+   * If the menu panel is being shown, hide it.
+   */
+  hide: function() {
+    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;
+      }
+    }
+  },
+
+  /**
+   * Registering the menu panel is done lazily for performance reasons. This
+   * method is exposed so that CustomizationMode can force registration in the
+   * event that customization mode is started before the panel has had a chance
+   * to register itself.
+   *
+   * @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.
+   */
+  ensureRegistered: function(aCustomizing=false) {
+    if (aCustomizing) {
+      CustomizableUI.registerMenuPanel(this.contents);
+    } else {
+      this.beginBatchUpdate();
+      CustomizableUI.registerMenuPanel(this.contents);
+      this.endBatchUpdate();
+    }
+  },
+
+  /**
+   * Switch the panel to the main view if it's not already
+   * in that view.
+   */
+  showMainView: function() {
+    this.multiView.showMainView();
+  },
+
+  /**
+   * Switch the panel to the help view if it's not already
+   * in that view.
+   */
+  showHelpView: function(aAnchor) {
+    this.multiView.showSubView("PanelUI-help", 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) {
+    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 {
+      // 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");
+      document.getElementById(CustomizableUI.AREA_NAVBAR).appendChild(tempPanel);
+
+      let multiView = document.createElement("panelmultiview");
+      tempPanel.appendChild(multiView);
+      multiView.setMainView(viewNode);
+      tempPanel.addEventListener("command", PanelUI._onWidgetPanelCommand);
+
+      tempPanel.addEventListener("popuphidden", function panelRemover() {
+        tempPanel.removeEventListener("popuphidden", panelRemover);
+        tempPanel.removeEventListener("command", PanelUI._onWidgetPanelCommand);
+        this.multiView.appendChild(viewNode);
+        tempPanel.parentElement.removeChild(tempPanel);
+      }.bind(this));
+
+      let iconAnchor =
+        document.getAnonymousElementByAttribute(aAnchor, "class",
+                                                "toolbarbutton-icon");
+
+      tempPanel.openPopup(iconAnchor || aAnchor, "bottomcenter topright");
+    }
+  },
+
+  /** 
+   * 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.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.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";
+  },
+
+  _onWidgetPanelCommand: function(aEvent) {
+    if (!aEvent.originalTarget.hasAttribute("noautoclose")) {
+      aEvent.currentTarget.hidePopup();
+    }
+  },
+
+  _onHelpViewCommand: function(aEvent) {
+    if (!aEvent.originalTarget.hasAttribute("noautoclose")) {
+      PanelUI.hide();
+    }
+  },
+
+  _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._onHelpViewCommand);
+  },
+
+  _onHelpViewHide: function(aEvent) {
+    this.removeEventListener("command", PanelUI._onHelpViewCommand);
+  }
+};
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/content/panelUI.xml
@@ -0,0 +1,349 @@
+<?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="toolbarbutton" display="xul:button"
+           extends="chrome://global/content/bindings/button.xml#button-base">
+    <resources>
+      <stylesheet src="chrome://global/skin/toolbarbutton.css"/>
+    </resources>
+    
+    <content>
+      <children includes="observes|template|menupopup|panel|tooltip"/>
+      <xul:hbox align="center" flex="1">
+	      <xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
+	      <xul:vbox flex="1">
+	  	    <xul:label class="toolbarbutton-text" crop="right" flex="1"
+  	  	             xbl:inherits="value=label,accesskey,crop"/>
+  	  	  <xul:hbox pack="end">
+	  	  	  <xul:label class="toolbarbutton-acceltext" crop="middle"
+  		  	  	         xbl:inherits="value=acceltext"/>
+  		  	</xul:hbox>
+  		  </xul:vbox>
+  		</xul:hbox>
+    </content>
+    
+    <implementation implements="nsIAccessibleProvider">
+      <property name="accessibleType" readonly="true">
+        <getter>
+          return Components.interfaces.nsIAccessibleProvider.XULToolbarButton;
+        </getter>
+      </property>
+    </implementation>
+  </binding>
+
+  <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 document.getElementById(this._mainViewId);"/>
+
+      <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("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("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 left 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 leftEdge = anchorRect.left - mainViewRect.left;
+            let center = aAnchor.clientWidth / 2;
+            let target = leftEdge + 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 "popuphidden":
+              this.removeAttribute("panelopen");
+              this.showMainView();
+              break;
+          }
+        ]]></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>
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/content/toolbar.xml
@@ -0,0 +1,447 @@
+<?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">
+      <property name="accessibleType" readonly="true">
+        <getter>
+          return Components.interfaces.nsIAccessibleProvider.XULToolbar;
+        </getter>
+      </property>
+
+      <constructor><![CDATA[
+          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);
+              }
+            }
+          }
+
+          CustomizableUI.registerToolbar(this);
+        ]]></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" readonly="true">
+        <getter><![CDATA[
+          if (!this._customizationTarget)
+            return "";
+
+          return [node.id for (node of this._customizationTarget.children)].join(',');
+        ]]></getter>
+      </property>
+
+
+    </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) {
+              // Don't move while customizing.
+              return this._dragBindingAlive &&
+                     this.getAttribute("customizing") != "true";
+            };
+          } 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);
+              }
+            }
+          }
+          CustomizableUI.registerToolbar(this);
+          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;
+            if (!toolbar._isModifying) {
+              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>
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/moz.build
@@ -0,0 +1,11 @@
+# -*- 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',
+		'test',
+]
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -0,0 +1,2184 @@
+/* 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/NetUtil.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "CustomizableWidgets",
+  "resource:///modules/CustomizableWidgets.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
+  "resource://gre/modules/DeferredTask.jsm");
+XPCOMUtils.defineLazyGetter(this, "gWidgetsBundle", function() {
+  const kUrl = "chrome://browser/locale/customizableui/customizableWidgets.properties";
+  return Services.strings.createBundle(kUrl);
+});
+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 kContextMenuBackup        = "customization-old-context";
+
+
+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"]);
+
+/**
+ * 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();
+
+let gSavedState = null;
+let gRestoring = false;
+let gDirty = false;
+let gInBatch = false;
+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 gWrapperCache = 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();
+
+    this.registerArea(CustomizableUI.AREA_PANEL, {
+      anchor: "PanelUI-menu-button",
+      type: CustomizableUI.TYPE_MENU_PANEL,
+      defaultPlacements: [
+        "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",
+      ]
+    });
+    this.registerArea(CustomizableUI.AREA_NAVBAR, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR,
+      overflowable: true,
+      defaultPlacements: [
+        "unified-back-forward-button",
+        "urlbar-container",
+        "reload-button",
+        "stop-button",
+        "search-container",
+        "webrtc-status-button",
+        "bookmarks-menu-button",
+        "downloads-button",
+        "home-button",
+        "social-share-button",
+      ]
+    });
+    this.registerArea(CustomizableUI.AREA_MENUBAR, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR,
+      defaultPlacements: [
+        "menubar-items",
+      ]
+    });
+    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) {
+    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);
+      }
+      return widget.wrapper;
+    }
+
+    // PROVIDER_SPECIAL gets treated the same as PROVIDER_XUL.
+    return new XULWidgetGroupWrapper(aWidgetId);
+  },
+
+  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);
+    this.endBatchUpdate(true);
+  },
+
+  registerToolbar: function(aToolbar) {
+    let document = aToolbar.ownerDocument;
+    let area = aToolbar.id;
+
+    if (!gAreas.has(area)) {
+      throw new Error("Unknown customization area: " + area);
+    }
+
+    if (this.isBuildAreaRegistered(area, aToolbar)) {
+      return;
+    }
+
+    let areaProperties = gAreas.get(area);
+
+    if (!gPlacements.has(area) && 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);
+    }
+
+    if (areaProperties.has("overflowable")) {
+      aToolbar.overflowable = new OverflowableToolbar(aToolbar);
+    }
+
+    this.registerBuildArea(area, aToolbar);
+
+    let placements = gPlacements.get(area);
+    this.buildArea(area, placements, aToolbar);
+    aToolbar.setAttribute("currentset", placements.join(","));
+  },
+
+  buildArea: function(aArea, aPlacements, aAreaNode) {
+    let document = aAreaNode.ownerDocument;
+    let window = document.defaultView;
+    let container = aAreaNode.customizationTarget;
+
+    if (!container) {
+      throw new Error("Expected area " + aArea
+                      + " to have a customizationTarget attribute.");
+    }
+
+    this.beginBatchUpdate();
+
+    let currentNode = container.firstChild;
+    for (let id of aPlacements) {
+      if (currentNode && currentNode.id == id) {
+        this._addParentFlex(currentNode);
+        this.setLocationAttributes(currentNode, container, aArea);
+
+        // Normalize removable attribute. It defaults to false if the widget is
+        // originally defined as a child of a build area.
+        if (!currentNode.hasAttribute("removable")) {
+          currentNode.setAttribute("removable", this.isWidgetRemovable(id));
+        }
+
+        currentNode = currentNode.nextSibling;
+        continue;
+      }
+
+      let [provider, node] = this.getWidgetNode(id, window);
+      if (!node) {
+        LOG("Unknown widget: " + id);
+        continue;
+      }
+
+      this.ensureButtonContextMenu(node, aArea == CustomizableUI.AREA_PANEL);
+
+      this.insertWidgetBefore(node, currentNode, container, aArea);
+      this._addParentFlex(node);
+      if (gResetting)
+        this.notifyListeners("onWidgetReset", id);
+    }
+
+    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) {
+          if (this.isWidgetRemovable(node.id)) {
+            if (palette) {
+              palette.appendChild(node);
+            } else {
+              container.removeChild(node);
+            }
+          } else if (node.getAttribute("skipintoolbarset") != "true") {
+            this.setLocationAttributes(currentNode, container, 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;
+      }
+    }
+
+    this.endBatchUpdate();
+  },
+
+  ensureButtonsClosePanel: function(aPanel) {
+    gELS.addSystemEventListener(aPanel, "click", this, false);
+    gELS.addSystemEventListener(aPanel, "keypress", this, false);
+  },
+
+  removePanelCloseListeners: function(aPanel) {
+    gELS.removeSystemEventListener(aPanel, "click", this, false);
+    gELS.removeSystemEventListener(aPanel, "keypress", this, false);
+  },
+
+  ensureButtonContextMenu: function(aNode, ourContextMenu) {
+    if (ourContextMenu) {
+      let currentCtxt = aNode.getAttribute("context");
+      // Need to save widget's own context menu if we're replacing it:
+      if (currentCtxt && currentCtxt != kCustomizationContextMenu) {
+        aNode.setAttribute(kContextMenuBackup, currentCtxt);
+      }
+      aNode.setAttribute("context", kCustomizationContextMenu);
+    } else if (aNode.getAttribute("context") == kCustomizationContextMenu) {
+      let oldCtxt = aNode.getAttribute(kContextMenuBackup);
+      if (oldCtxt) {
+        aNode.setAttribute("context", oldCtxt);
+        aNode.removeAttribute(kContextMenuBackup);
+      } else {
+        aNode.removeAttribute("context");
+      }
+    }
+  },
+
+  getWidgetProvider: function(aWidgetId) {
+    if (this.isSpecialWidget(aWidgetId)) {
+      return CustomizableUI.PROVIDER_SPECIAL;
+    }
+    if (gPalette.has(aWidgetId)) {
+      return CustomizableUI.PROVIDER_API;
+    }
+
+    // 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 (this.isBuildAreaRegistered(CustomizableUI.AREA_PANEL, aPanel)) {
+      return;
+    }
+
+    let document = aPanel.ownerDocument;
+
+    for (let btn of aPanel.querySelectorAll("toolbarbutton")) {
+      this.ensureButtonContextMenu(btn, true);
+    }
+
+    aPanel.toolbox = document.getElementById("navigator-toolbox");
+    aPanel.customizationTarget = aPanel;
+
+    this.ensureButtonsClosePanel(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) {
+    let areaNodes = gBuildAreas.get(aArea);
+    if (!areaNodes) {
+      return;
+    }
+
+    let placements = gPlacements.get(aArea);
+    if (!placements) {
+      ERROR("Could not find any placements for " + aArea +
+            " when adding 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) {
+      let window = areaNode.ownerDocument.defaultView;
+      let container = areaNode.customizationTarget;
+      let [provider, widgetNode] = this.getWidgetNode(aWidgetId, window);
+
+      this.ensureButtonContextMenu(widgetNode, aArea == CustomizableUI.AREA_PANEL);
+
+      let nextNode = nextNodeId ? container.querySelector(idToSelector(nextNodeId))
+                                : null;
+      this.insertWidgetBefore(widgetNode, nextNode, container, aArea);
+      this._addParentFlex(widgetNode);
+    }
+  },
+
+  onWidgetRemoved: function(aWidgetId, aArea) {
+    let areaNodes = gBuildAreas.get(aArea);
+    if (!areaNodes) {
+      return;
+    }
+
+    for (let areaNode of areaNodes) {
+      let container = areaNode.customizationTarget;
+      let widgetNode = container.ownerDocument.getElementById(aWidgetId);
+      if (!widgetNode) {
+        ERROR("Widget not found, unable to remove");
+        continue;
+      }
+
+      this._removeParentFlex(widgetNode);
+
+      if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) {
+        container.removeChild(widgetNode);
+      } else {
+        this.removeLocationAttributes(widgetNode);
+        areaNode.toolbox.palette.appendChild(widgetNode);
+      }
+    }
+  },
+
+  onWidgetMoved: function(aWidgetId, aArea, aOldPosition, aNewPosition) {
+    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[aNewPosition + 1];
+
+    for (let areaNode of areaNodes) {
+      let window = areaNode.ownerDocument.defaultView;
+      let container = areaNode.customizationTarget;
+      let [provider, widgetNode] = this.getWidgetNode(aWidgetId, window);
+      if (!widgetNode) {
+        ERROR("Widget not found, unable to move");
+        continue;
+      }
+
+      let nextNode = nextNodeId ? container.querySelector(idToSelector(nextNodeId))
+                                : null;
+      this.insertWidgetBefore(widgetNode, nextNode, container, aArea);
+    }
+  },
+
+  isBuildAreaRegistered: function(aArea, aInstance) {
+    if (!gBuildAreas.has(aArea)) {
+      return false;
+    }
+    return gBuildAreas.get(aArea).has(aInstance);
+  },
+
+  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;
+    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, false);
+  },
+
+  unregisterBuildWindow: function(aWindow) {
+    gBuildWindows.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, aContainer, aArea) {
+    let props = gAreas.get(aArea);
+    if (!props) {
+      throw new Error("Expected area " + aArea + " to have a properties Map " +
+                      "associated with it.");
+    }
+
+    aNode.setAttribute("customizableui-areatype", props.get("type") || "");
+    aNode.setAttribute("customizableui-anchorid", props.get("anchor") || "");
+  },
+
+  removeLocationAttributes: function(aNode) {
+    aNode.removeAttribute("customizableui-areatype");
+    aNode.removeAttribute("customizableui-anchorid");
+  },
+
+  insertWidgetBefore: function(aNode, aNextNode, aContainer, aArea) {
+    this.setLocationAttributes(aNode, aContainer, aArea);
+    aContainer.insertBefore(aNode, aNextNode);
+  },
+
+  handleEvent: function(aEvent) {
+    switch (aEvent.type) {
+      case "click":
+      case "keypress":
+        this.maybeAutoHidePanel(aEvent);
+        break;
+      case "unload": {
+        let window = aEvent.currentTarget;
+        window.removeEventListener("unload", this);
+        this.unregisterBuildWindow(window);
+        break;
+      }
+    }
+  },
+
+  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) {
+      // Due to timers resolution Date.now() can be the same for
+      // elements created in small timeframes.  So ids are
+      // differentiated through a unique count suffix.
+      return kSpecialWidgetPfx + aId + Date.now() + (++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");
+    }
+
+    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 && 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")) {
+          // 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("label", this.getLocalizedProperty(aWidget, "label"));
+      node.setAttribute("tooltiptext", this.getLocalizedProperty(aWidget, "tooltiptext"));
+      //XXXunf Need to hook this up to a <key> element or something.
+      let shortcut = this.getLocalizedProperty(aWidget, "shortcut");
+      if (shortcut) {
+        node.setAttribute("acceltext", shortcut);
+      }
+      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) {
+          ERROR("Could not find the view node with id: " + aWidget.viewId);
+          throw new Error("Could not find the view node with id: " + aWidget.viewId);
+        }
+
+        // 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.");
+      }
+
+      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.");
+    }
+    if (typeof aWidget[aProp] == "string") {
+      return aWidget[aProp];
+    }
+    let def = aDef || "";
+    let name = aWidget.id + "." + aProp;
+    try {
+      if (Array.isArray(aFormatArgs) && aFormatArgs.length) {
+        return gWidgetsBundle.formatStringFromName(name, aFormatArgs,
+          aFormatArgs.length) || def;
+      }
+      return gWidgetsBundle.GetStringFromName(name) || def;
+    } catch(ex) {
+      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);
+    }
+  },
+
+  /*
+   * 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 = aNode;
+    while (panel && panel.localName != "panel")
+      panel = panel.parentNode;
+    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 { // 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) {
+    for (let [area, placements] of gPlacements) {
+      let index = placements.indexOf(aWidgetId);
+      if (index != -1) {
+        return { area: area, position: index };
+      }
+    }
+
+    return null;
+  },
+
+  addWidgetToArea: function(aWidgetId, aArea, aPosition) {
+    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;
+    }
+
+    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();
+
+    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;
+    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 || []);
+  },
+
+  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);
+      }
+      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 (gInBatch || !gDirty) {
+      return;
+    }
+    let state = { placements: gPlacements,
+                  seen: gSeenWidgets };
+
+    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() {
+    gInBatch = true;
+  },
+
+  endBatchUpdate: function(aForceSave) {
+    gInBatch = false;
+    if (aForceSave === true) {
+      gDirty = true;
+    }
+    this.saveState();
+  },
+
+  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 (aEvent in listener) {
+          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);
+      }
+    }
+
+    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 = {
+      source: aSource || "addon",
+      instances: new Map(),
+      currentArea: null,
+      removable: false,
+      defaultArea: null,
+      allowedAreas: [],
+      shortcut: null,
+      tooltiptext: null,
+    };
+
+    if (typeof aData.id != "string" || !/^[a-z0-9-_]{1,}$/i.test(aData.id)) {
+      ERROR("Given an illegal id in normalizeWidget: " + aData.id);
+      return null;
+    }
+
+    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", "shortcut"];
+    for (let prop of kOptStringProps) {
+      if (typeof aData[prop] == "string") {
+        widget[prop] = aData[prop];
+      }
+    }
+
+    if ("removable" in aData && typeof aData.removable == "boolean") {
+      widget.removable = aData.removable;
+    }
+
+    if (aData.defaultArea && gAreas.has(aData.defaultArea)) {
+      widget.defaultArea = aData.defaultArea;
+    }
+
+    if (Array.isArray(aData.allowedAreas)) {
+      widget.allowedAreas =
+        [area for (area of aData.allowedAreas) if (gAreas.has(area))];
+    }
+
+    if ("type" in aData && gSupportedWidgetTypes.has(aData.type)) {
+      widget.type = aData.type;
+    } else {
+      widget.type = "button";
+    }
+
+    widget.disabled = aData.disabled === true;
+
+    widget.onClick = typeof aData.onClick == "function" ? aData.onClick : null;
+
+    widget.onCreated = typeof aData.onCreated == "function" ? aData.onCreated : null;
+
+    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;
+
+      widget.onViewShowing = typeof aData.onViewShowing == "function" ?
+                                 aData.onViewShowing :
+                                 null;
+      widget.onViewHiding = typeof aData.onViewHiding == "function" ? 
+                                 aData.onViewHiding :
+                                 null;
+    } else if (widget.type == "custom") {
+      widget.onBuild = typeof aData.onBuild == "function" ?
+                                 aData.onBuild :
+                                 null;
+    }
+
+    if (gPalette.has(widget.id)) {
+      return null;
+    }
+
+    return widget;
+  },
+
+  destroyWidget: function(aWidgetId) {
+    let widget = gPalette.get(aWidgetId);
+    if (!widget) {
+      return;
+    }
+
+    // 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;
+    if (area) {
+      let buildArea = gBuildAreas.get(area);
+      for (let buildNode of buildArea) {
+        let widgetNode = buildNode.ownerDocument.getElementById(aWidgetId);
+        if (widgetNode) {
+          widgetNode.parentNode.removeChild(widgetNode);
+        }
+        for (let eventName of kSubviewEvents) {
+          let handler = "on" + eventName;
+          if (typeof widget[handler] == "function") {
+            viewNode.removeEventListener(eventName, widget[handler], false);
+          }
+        }
+      }
+    }
+
+    gPalette.delete(aWidgetId);
+
+    this.notifyListeners("onWidgetDestroyed", aWidgetId);
+  },
+
+  registerManifest: function(aBaseLocation, aData) {
+    let tokens = aData.split(/\s+/);
+    let directive = tokens.shift();
+    if (directive != "widget") {
+      return;
+    }
+
+    for (let [id, widget] of gPalette) {
+      if (widget.source == aBaseLocation.spec) {
+        return; // Already registered.
+      }
+    }
+
+    let uri = NetUtil.newURI(tokens.shift(), null, aBaseLocation);
+
+    dump("\tNew widget! " + uri.spec + "\n");
+
+    let data = "";
+    try {
+      if (uri.schemeIs("jar")) {
+        data = this.readManifestFromJar(uri);
+      } else {
+        data = this.readManifestFromFile(uri);
+      }
+    }
+    catch (e) {
+      ERROR(e);
+      return;
+    }
+    data = JSON.parse(data);
+    data.source = aBaseLocation.spec;
+
+    this.createWidget(data);
+  },
+
+  // readManifestFromJar and readManifestFromFile from ChromeManifestParser.jsm.
+  readManifestFromJar: function(aURI) {
+    let data = "";
+    let entries = [];
+    let readers = [];
+
+    try {
+      // Deconstrict URI, which can be nested jar: URIs. 
+      let uri = aURI.clone();
+      while (uri instanceof Ci.nsIJARURI) {
+        entries.push(uri.JAREntry);
+        uri = uri.JARFile;
+      }
+
+      // Open the base jar.
+      let reader = Cc["@mozilla.org/libjar/zip-reader;1"]
+                     .createInstance(Ci.nsIZipReader);
+      reader.open(uri.QueryInterface(Ci.nsIFileURL).file);
+      readers.push(reader);
+
+      // Open the nested jars.
+      for (let i = entries.length - 1; i > 0; i--) {
+        let innerReader = Cc["@mozilla.org/libjar/zip-reader;1"].
+                          createInstance(Ci.nsIZipReader);
+        innerReader.openInner(reader, entries[i]);
+        readers.push(innerReader);
+        reader = innerReader;
+      }
+
+      // First entry is the actual file we want to read.
+      let zis = reader.getInputStream(entries[0]);
+      data = NetUtil.readInputStreamToString(zis, zis.available());
+    }
+    finally {
+      // Close readers in reverse order.
+      for (let i = readers.length - 1; i >= 0; i--) {
+        readers[i].close();
+        //XXXunf Don't think this is needed, but need to double check.
+        //flushJarCache(readers[i].file);
+      }
+    }
+
+    return data;
+  },
+
+  readManifestFromFile: function(aURI) {
+    let file = aURI.QueryInterface(Ci.nsIFileURL).file;
+    if (!file.exists() || !file.isFile()) {
+      return "";
+    }
+
+    let data = "";
+    let fis = Cc["@mozilla.org/network/file-input-stream;1"]
+                .createInstance(Ci.nsIFileInputStream);
+    try {
+      fis.init(file, -1, -1, false);
+      data = NetUtil.readInputStreamToString(fis, fis.available());
+    } finally {
+      fis.close();
+    }
+    return data;
+  },
+
+  getCustomizeTargetForArea: function(aArea, aWindow) {
+    let buildAreaNodes = gBuildAreas.get(aArea);
+    if (!buildAreaNodes) {
+      throw new Error("No build area nodes registered for " + aArea);
+    }
+
+    for (let node of buildAreaNodes) {
+      if (node.ownerDocument.defaultView === aWindow) {
+        return node.customizationTarget ? node.customizationTarget : node;
+      }
+    }
+
+    throw new Error("Could not find any window nodes for area " + aArea);
+  },
+
+  reset: function() {
+    gResetting = true;
+    Services.prefs.clearUserPref(kPrefCustomizationState);
+    LOG("State reset");
+
+    // Reset placements to make restoring default placements possible.
+    gPlacements = new Map();
+    // 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;
+  },
+
+  _addParentFlex: function(aElement) {
+    // If necessary, add flex to accomodate new child.
+    if (aElement.hasAttribute("flex")) {
+      let parent = aElement.parentNode;
+      let parentFlex = parent.hasAttribute("flex") ? parseInt(parent.getAttribute("flex"), 10) : 0;
+      let elementFlex = parseInt(aElement.getAttribute("flex"), 10);
+      parent.setAttribute("flex", parentFlex + elementFlex);
+    }
+  },
+
+  _removeParentFlex: function(aElement) {
+    if (aElement.parentNode.hasAttribute("flex") && aElement.hasAttribute("flex")) {
+      let parent = aElement.parentNode;
+      let parentFlex = parseInt(parent.getAttribute("flex"), 10);
+      let elementFlex = parseInt(aElement.getAttribute("flex"), 10);
+      parent.setAttribute("flex", Math.max(0, parentFlex - elementFlex));
+    }
+  },
+
+  isWidgetRemovable: function(aWidgetId) {
+    let provider = this.getWidgetProvider(aWidgetId);
+
+    if (provider == CustomizableUI.PROVIDER_API) {
+      return gPalette.get(aWidgetId).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;
+      }
+
+      // Pick any of the build windows to look at.
+      let [window,] = [...gBuildWindows][0];
+      let [, node] = this.getWidgetNode(aWidgetId, window);
+      return node.getAttribute("removable") == "true";
+    }
+
+    // Otherwise this is a special widget, which are always removable.
+    return true;
+  },
+
+  canWidgetMoveToArea: function(aWidgetId, aArea) {
+    let placement = this.getPlacementOfWidget(aWidgetId);
+    if (placement && placement.area != aArea &&
+        !this.isWidgetRemovable(aWidgetId)) {
+      return false;
+    }
+    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];
+        // 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("\n") +
+          " vs. " + defaultPlacements.join("\n"));
+
+      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);
+  },
+  //XXXunf registerToolbarNode / registerToolbarInstance ?
+  registerToolbar: function(aToolbar) {
+    CustomizableUIInternal.registerToolbar(aToolbar);
+  },
+  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);
+  },
+  beginBatchUpdate: function() {
+    CustomizableUIInternal.beginBatchUpdate();
+  },
+  endBatchUpdate: function(aForceSave) {
+    CustomizableUIInternal.endBatchUpdate(aForceSave);
+  },
+  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");
+    }
+
+    return gPlacements.get(aArea);
+  },
+  getWidgetsInArea: function(aArea) {
+    return this.getWidgetIdsInArea(aArea).map(
+      CustomizableUIInternal.wrapWidget,
+      CustomizableUIInternal
+    );
+  },
+  get areas() {
+    return [area for ([area, props] of gAreas)];
+  },
+  getCustomizeTargetForArea: function(aArea, aWindow) {
+    return CustomizableUIInternal.getCustomizeTargetForArea(aArea, aWindow);
+  },
+  reset: function() {
+    CustomizableUIInternal.reset();
+  },
+  getPlacementOfWidget: function(aWidgetId) {
+    return CustomizableUIInternal.getPlacementOfWidget(aWidgetId);
+  },
+  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);
+  }
+};
+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"];
+  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 instance = aWidget.instances.get(aWindow.document);
+    if (!instance) {
+      instance = CustomizableUIInternal.buildWidget(aWindow.document,
+                                                    aWidget);
+    }
+
+    let wrapper = gWrapperCache.get(instance);
+    if (!wrapper) {
+      wrapper = new WidgetSingleWrapper(aWidget, instance);
+      gWrapperCache.set(instance, wrapper);
+    }
+    return wrapper;
+  };
+
+  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 = aNode.getAttribute("customizableui-anchorid");
+    return anchorId ? aNode.ownerDocument.getElementById(anchorId)
+                    : aNode;
+  });
+
+  this.__defineGetter__("areaType", function() {
+    return aNode.getAttribute("customizableui-areatype") || "";
+  });
+
+
+  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;
+
+  let nodes = [];
+
+  let placement = CustomizableUIInternal.getPlacementOfWidget(aWidgetId);
+  if (placement) {
+    let buildAreas = gBuildAreas.get(placement.area) || [];
+    for (let areaNode of buildAreas)
+      nodes.push(areaNode.ownerDocument.getElementById(aWidgetId));
+  }
+
+  this.id = aWidgetId;
+  this.type = "custom";
+  this.provider = CustomizableUI.PROVIDER_XUL;
+
+  this.forWindow = function XULWidgetGroupWrapper_forWindow(aWindow) {
+    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 = gWrapperCache.get(instance);
+    if (!wrapper) {
+      wrapper = new XULWidgetSingleWrapper(aWidgetId, instance);
+      gWrapperCache.set(instance, wrapper);
+    }
+    return wrapper;
+  };
+
+  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 = aNode.getAttribute("customizableui-anchorid");
+    return anchorId ? aNode.ownerDocument.getElementById(anchorId)
+                    : aNode;
+  });
+
+  this.__defineGetter__("areaType", function() {
+    return aNode.getAttribute("customizableui-areatype") || "";
+  });
+
+  Object.freeze(this);
+}
+
+const LAZY_RESIZE_INTERVAL_MS = 200;
+
+function OverflowableToolbar(aToolbarNode) {
+  this._toolbar = aToolbarNode;
+  this._collapsed = [];
+  this._enabled = true;
+
+  this._toolbar.setAttribute("overflowable", "true");
+  Services.obs.addObserver(this, "browser-delayed-startup-finished", false);
+}
+
+OverflowableToolbar.prototype = {
+  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("widget-overflow-list");
+    this._toolbar.customizationTarget.addEventListener("overflow", this);
+
+    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.ensureButtonsClosePanel(this._panel);
+
+    this.initialized = true;
+
+    // The toolbar could initialize in an overflowed state, in which case
+    // the 'overflow' event may have been fired before the handler was registered.
+    this._onOverflow();
+  },
+
+  uninit: function() {
+    if (!this.initialized) {
+      return;
+    }
+    this._disable();
+
+    this._toolbar.removeAttribute("overflowable");
+    this._toolbar.customizationTarget.removeEventListener("overflow", this);
+    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);
+    CustomizableUIInternal.removePanelCloseListeners(this._panel);
+  },
+
+  handleEvent: function(aEvent) {
+    switch(aEvent.type) {
+      case "overflow":
+        this._onOverflow();
+        break;
+      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() {
+    if (!this._enabled)
+      return;
+
+    let child = this._target.lastChild;
+
+    while(child && this._target.clientWidth < this._target.scrollWidth) {
+      let prevChild = child.previousSibling;
+
+      if (!child.hasAttribute("nooverflow")) {
+        this._collapsed.push({child: child, minSize: this._target.clientWidth});
+        child.classList.add("overflowedItem");
+
+        this._list.insertBefore(child, this._list.firstChild);
+        this._toolbar.setAttribute("overflowing", "true");
+      }
+      child = prevChild;
+    };
+  },
+
+  _onResize: function(aEvent) {
+    if (!this._lazyResizeHandler) {
+      this._lazyResizeHandler = new DeferredTask(this._onLazyResize.bind(this),
+                                                 LAZY_RESIZE_INTERVAL_MS);
+    }
+    this._lazyResizeHandler.start();
+  },
+
+  _moveItemsBackToTheirOrigin: function(shouldMoveAllItems) {
+    for (let i = this._collapsed.length - 1; i >= 0; i--) {
+      let {child, minSize} = this._collapsed[i];
+
+      if (!shouldMoveAllItems &&
+          this._target.clientWidth <= minSize) {
+        return;
+      }
+
+      this._collapsed.pop();
+      this._target.appendChild(child);
+      child.classList.remove("overflowedItem");
+    }
+
+    if (!this._collapsed.length) {
+      this._toolbar.removeAttribute("overflowing");
+    }
+  },
+
+  _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();
+  }
+};
+
+// When IDs contain special characters, we need to escape them for use with querySelector:
+function idToSelector(aId) {
+  return "#" + aId.replace(/[ !"'#$%&\(\)*+\-,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&');
+}
+
+CustomizableUIInternal.initialize();
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/src/CustomizableWidgets.jsm
@@ -0,0 +1,520 @@
+/* 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");
+
+const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+const kPrefCustomizationDebug = "browser.uiCustomization.debug";
+const kWidePanelItemClass = "panel-combined-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(aAttrs, name);
+      aNode.setAttribute(name, value);
+    }
+  }
+}
+
+// This function is called whenever an item gets moved in the menu panel. It
+// adjusts the position of widgets within the panel to reduce single-column
+// buttons from being placed in a row by themselves.
+function adjustPosition(aNode) {
+  // TODO(bug 885574): Merge this constant with the one in CustomizeMode.jsm,
+  //                   maybe just use a pref for this.
+  const kColumnsInMenuPanel = 3;
+
+  // Make sure that there are n % columns = 0 narrow buttons before the widget.
+  let prevSibling = aNode.previousElementSibling;
+  let previousSiblingCount = 0;
+  while (prevSibling) {
+    if (!prevSibling.classList.contains(kWidePanelItemClass)) {
+      previousSiblingCount++;
+    }
+    prevSibling = prevSibling.previousElementSibling;
+  }
+  if (previousSiblingCount % kColumnsInMenuPanel) {
+    let previousElement = aNode.previousElementSibling;
+    if (!previousElement ||
+        previousElement.classList.contains(kWidePanelItemClass)) {
+      return;
+    }
+
+    let position = Array.prototype.indexOf.call(aNode.parentNode.children, aNode);
+    // We don't need to move all of the items in this pass, because
+    // this move will trigger adjustPosition to get called again. The
+    // function will stop recursing when it finds that there is no
+    // more work that is needed.
+    CustomizableUI.moveWidgetWithinArea(aNode.id, position - 1);
+  }
+}
+
+const CustomizableWidgets = [{
+    id: "history-panelmenu",
+    type: "view",
+    viewId: "PanelUI-history",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL, CustomizableUI.AREA_NAVBAR],
+    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 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.addEventListener("click", function(aEvent) {
+                if (aEvent.button == 0) {
+                  doc.defaultView.openUILink(uri, aEvent);
+                  CustomizableUI.hidePanelForNode(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!");
+        },
+      });
+    },
+    onViewHiding: function(aEvent) {
+      LOG("History view is being hidden!");
+    }
+  }, {
+    id: "privatebrowsing-button",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [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,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [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,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [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,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [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",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL],
+    onCommand: function(aEvent) {
+      let win = aEvent.target &&
+                aEvent.target.ownerDocument &&
+                aEvent.target.ownerDocument.defaultView;
+      if (win && win.gDevToolsBrowser) {
+        win.gDevToolsBrowser.toggleToolboxCommand(win.gBrowser);
+      }
+    }
+  }, {
+    id: "add-ons-button",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [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,
+    allowedAreas: [CustomizableUI.AREA_PANEL],
+    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,
+    allowedAreas: [CustomizableUI.AREA_PANEL, CustomizableUI.AREA_NAVBAR],
+    onBuild: function(aDocument) {
+      let inPanel = (this.currentArea == CustomizableUI.AREA_PANEL);
+      let noautoclose = inPanel ? "true" : null;
+      let flex = inPanel ? "1" : null;
+      let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1";
+      let buttons = [{
+        id: "zoom-out-button",
+        noautoclose: noautoclose,
+        command: "cmd_fullZoomReduce",
+        flex: flex,
+        class: cls,
+        label: true,
+        tooltiptext: true
+      }, {
+        id: "zoom-reset-button",
+        noautoclose: noautoclose,
+        command: "cmd_fullZoomReset",
+        flex: flex,
+        class: cls,
+        tooltiptext: true
+      }, {
+        id: "zoom-in-button",
+        noautoclose: noautoclose,
+        command: "cmd_fullZoomEnlarge",
+        flex: flex,
+        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");
+      if (inPanel)
+        node.setAttribute("flex", "1");
+      node.classList.add("chromeclass-toolbar-additional");
+      node.classList.add(kWidePanelItemClass);
+
+      buttons.forEach(function(aButton) {
+        let btnNode = aDocument.createElementNS(kNSXUL, "toolbarbutton");
+        setAttributes(btnNode, aButton);
+        node.appendChild(btnNode);
+      });
+
+      // The middle node is the 'Reset Zoom' button.
+      let zoomResetButton = node.childNodes[1];
+      let window = aDocument.defaultView;
+      function updateZoomResetButton() {
+        zoomResetButton.setAttribute("label", CustomizableUI.getLocalizedProperty(
+          buttons[1], "label", [Math.floor(window.ZoomManager.zoom * 100)]
+        ));
+      };
+
+      // 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);
+      Services.obs.addObserver(updateZoomResetButton, "browser-fullZoom:locationChange", false);
+
+      updateZoomResetButton();
+      if (!inPanel)
+        zoomResetButton.setAttribute("hidden", "true");
+
+      function updateWidgetStyle(aInPanel) {
+        let attrs = {
+          noautoclose: aInPanel ? "true" : null,
+          flex: aInPanel ? "1" : null,
+          class: aInPanel ? "panel-combined-button" : "toolbarbutton-1"
+        };
+        for (let i = 0, l = node.childNodes.length; i < l; ++i) {
+          setAttributes(node.childNodes[i], attrs);
+        }
+        zoomResetButton.setAttribute("hidden", aInPanel ? "false" : "true");
+        if (aInPanel)
+          node.setAttribute("flex", "1");
+        else if (node.hasAttribute("flex"))
+          node.removeAttribute("flex");
+      }
+
+      let listener = {
+        onWidgetAdded: function(aWidgetId, aArea, aPosition) {
+          if (this.currentArea == CustomizableUI.AREA_PANEL) {
+            adjustPosition(node);
+          }
+
+          if (aWidgetId != this.id)
+            return;
+
+          updateWidgetStyle(aArea == CustomizableUI.AREA_PANEL);
+        }.bind(this),
+
+        onWidgetRemoved: function(aWidgetId, aPrevArea) {
+          if (this.currentArea == CustomizableUI.AREA_PANEL) {
+            adjustPosition(node);
+          }
+
+          if (aWidgetId != this.id)
+            return;
+
+          // When a widget is demoted to the palette ('removed'), it's visual
+          // style should change.
+          updateWidgetStyle(false);
+          zoomResetButton.setAttribute("hidden", "true");
+        }.bind(this),
+
+        onWidgetReset: function(aWidgetId) {
+          if (aWidgetId != this.id)
+            return;
+          updateWidgetStyle(this.currentArea == CustomizableUI.AREA_PANEL);
+        }.bind(this),
+
+        onWidgetMoved: function(aWidgetId, aArea) {
+          if (this.currentArea == CustomizableUI.AREA_PANEL) {
+            adjustPosition(node);
+          }
+
+          if (aWidgetId != this.id)
+            return;
+          updateWidgetStyle(aArea == CustomizableUI.AREA_PANEL);
+        }.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");
+        }.bind(this)
+      };
+      CustomizableUI.addListener(listener);
+
+      return node;
+    }
+  }, {
+    id: "edit-controls",
+    type: "custom",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL, CustomizableUI.AREA_NAVBAR],
+    onBuild: function(aDocument) {
+      let inPanel = (this.currentArea == CustomizableUI.AREA_PANEL);
+      let flex = inPanel ? "1" : null;
+      let cls = inPanel ? "panel-combined-button" : "toolbarbutton-1";
+      let buttons = [{
+        id: "cut-button",
+        command: "cmd_cut",
+        flex: flex,
+        class: cls,
+        label: true,
+        tooltiptext: true
+      }, {
+        id: "copy-button",
+        command: "cmd_copy",
+        flex: flex,
+        class: cls,
+        label: true,
+        tooltiptext: true
+      }, {
+        id: "paste-button",
+        command: "cmd_paste",
+        flex: flex,
+        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");
+      if (inPanel)
+        node.setAttribute("flex", "1");
+      node.classList.add("chromeclass-toolbar-additional");
+      node.classList.add(kWidePanelItemClass);
+
+      buttons.forEach(function(aButton) {
+        let btnNode = aDocument.createElementNS(kNSXUL, "toolbarbutton");
+        setAttributes(btnNode, aButton);
+        node.appendChild(btnNode);
+      });
+
+      function updateWidgetStyle(aInPanel) {
+        let attrs = {
+          flex: aInPanel ? "1" : null,
+          class: aInPanel ? "panel-combined-button" : "toolbarbutton-1"
+        };
+        for (let i = 0, l = node.childNodes.length; i < l; ++i) {
+          setAttributes(node.childNodes[i], attrs);
+        }
+        if (aInPanel)
+          node.setAttri