Merge mozilla-central and ux
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Wed, 10 Jul 2013 23:53:05 +0200
changeset 170098 633f38c4b84175857d19035f49b40b8089e35650
parent 150267 3fc610532baf20310494c840e3650c8168798eb9 (current diff)
parent 170097 a39e19167f5e7ec496cb3720229a65a54f863af9 (diff)
child 170099 5c6b1a1ed828bfc9c43a4b060bb1674ade035c0f
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central and ux
browser/app/profile/firefox.js
browser/base/content/browser-appmenu.inc
browser/base/content/browser-fullZoom.js
browser/base/content/browser.js
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/test/head.js
browser/themes/linux/jar.mn
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/jar.mn
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/jar.mn
browser/themes/windows/places/editBookmark.png
toolkit/content/widgets/findbar.xml
toolkit/themes/linux/global/icons/notloading_16.png
toolkit/themes/osx/global/icons/notloading_16.png
toolkit/themes/windows/global/icons/notloading_16.png
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -413,21 +413,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);
@@ -1269,8 +1268,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,33 @@ 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);
-            }
+          if (el.hasAttribute("saved-context")) {
+            el.setAttribute("context", el.getAttribute("saved-context"));
+            el.removeAttribute("saved-context");
           }
-
-          restoreAttr("mode");
-          restoreAttr("iconsize");
-          restoreAttr("context");
-
           el.removeAttribute("inFullscreen");
         }
       } else {
         // 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 +549,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
@@ -392,16 +392,17 @@ var FullZoom = {
 
   /**
    * Saves the zoom level of the page in the given browser to the content
    * prefs store.
    *
    * @param browser  The zoom of this browser will be saved.  Required.
    */
   _applyZoomToPref: function FullZoom__applyZoomToPref(browser) {
+    Services.obs.notifyObservers(null, "browser-fullZoom:zoomChange", "");
     if (!this.siteSpecific ||
         gInPrintPreviewMode ||
         browser.contentDocument.mozSyntheticDocument)
       return;
 
     this._cps2.set(browser.currentURI.spec, this.name,
                    ZoomManager.getZoomForBrowser(browser),
                    this._loadContextFromWindow(browser.contentWindow), {
@@ -412,16 +413,17 @@ var FullZoom = {
   },
 
   /**
    * Removes from the content prefs store the zoom level of the given browser.
    *
    * @param browser  The zoom of this browser will be removed.  Required.
    */
   _removePref: function FullZoom__removePref(browser) {
+    Services.obs.notifyObservers(null, "browser-fullZoom:zoomReset", "");
     if (browser.contentDocument.mozSyntheticDocument)
       return;
     let ctxt = this._loadContextFromWindow(browser.contentWindow);
     this._cps2.removeByDomainAndName(browser.currentURI.spec, this.name, ctxt, {
       handleCompletion: function () {
         this._isNextContentPrefChangeInternal = true;
       }.bind(this),
     });
--- 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,73 @@
 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-menubar {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-stub");
+}
+
+toolbar[customizable="true"]:not([nowindowdrag="true"]) {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
+}
+%endif
+
+#toolbar-menubar[autohide="true"] {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-autohide");
+}
+
+#addon-bar {
+  -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#addonbar-delegating");
+  visibility: visible;
+  margin: 0;
+  height: 0 !important;
+  overflow: hidden;
+  padding: 0;
+  border: 0 none;
+}
+
+#addonbar-closebutton {
+  visibility: visible;
+  height: 0 !important;
+}
+
+#status-bar {
+  height: 0 !important;
+  -moz-binding: none;
+  padding: 0;
+  margin: 0;
+}
+
+panelmultiview {
+  -moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelmultiview");
+}
+
+panelview {
+  -moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelview");
+  -moz-box-orient: vertical;
+}
+
+.panel-mainview {
+  transition: transform 150ms;
+}
+
+panelview:not([mainview]):not([current]) {
+  display: none;
+}
+
 tabbrowser {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser");
 }
 
 .tabbrowser-tabs {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-tabs");
 }
 
@@ -34,31 +91,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 +138,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 +162,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 +232,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 +335,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 +373,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 +471,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 +535,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
@@ -82,16 +82,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);
@@ -142,16 +148,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
@@ -915,38 +922,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;
   },
 
@@ -1033,16 +1035,21 @@ 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);
     WebrtcIndicator.init();
 
     // Ensure login manager is up and running.
     Services.logins;
 
     if (mustLoadSidebar) {
@@ -1080,21 +1087,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)
@@ -1219,56 +1221,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);
     }
@@ -1317,18 +1296,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");
@@ -1369,18 +1346,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
@@ -1396,17 +1374,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");
     }
 
@@ -2678,35 +2656,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;
@@ -2718,21 +2693,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;
@@ -2799,45 +2769,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)
   {
@@ -3346,164 +3287,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,
@@ -3522,36 +3327,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
@@ -3571,44 +3367,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.
@@ -3630,18 +3411,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;
@@ -3661,28 +3442,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
@@ -3797,20 +3579,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
@@ -3845,20 +3623,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 : "";
@@ -3917,27 +3691,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"),
@@ -3978,16 +3741,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)
@@ -3995,22 +3769,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,
@@ -4163,18 +3933,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");
       }
     }
@@ -4478,31 +4247,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);
     }
   }
@@ -4516,210 +4282,262 @@ function onViewToolbarCommand(aEvent) {
 }
 
 function setToolbarVisibility(toolbar, isVisible) {
   var hidingAttribute = toolbar.getAttribute("type") == "menubar" ?
                         "autohide" : "collapsed";
 
   toolbar.setAttribute(hidingAttribute, !isVisible);
   document.persist(toolbar.id, hidingAttribute);
+  let eventParams = {
+    detail: {
+      visible: isVisible
+    },
+    bubbles: true
+  };
+  let event = new CustomEvent("toolbarvisibilitychange", eventParams);
+  toolbar.dispatchEvent(event);
 
   PlacesToolbarHelper.init();
   BookmarkingUI.onToolbarVisibilityChange();
   gBrowser.updateWindowResizers();
 
-#ifdef MENUBAR_CAN_AUTOHIDE
-  updateAppButtonDisplay();
+#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
@@ -6948,39 +6766,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;
@@ -7184,21 +6995,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,439 @@
              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"
+             overflowtarget="widget-overflow-list"
              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 +915,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 +1058,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
@@ -172,18 +172,17 @@
         ]]></body>
       </method>
 
       <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"/>
@@ -1377,18 +1376,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
@@ -3226,20 +3224,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;
@@ -3581,19 +3575,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;
               }
@@ -3884,18 +3876,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
@@ -4316,17 +4307,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);
         }
@@ -4372,17 +4363,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
@@ -133,20 +133,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 \
@@ -164,24 +161,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 \
@@ -239,17 +234,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 \
@@ -283,19 +277,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,86 @@
+<!-- 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">
+        <toolbarbutton id="PanelUI-customize-btn" label="&appMenuCustomize.label;"
+                       oncommand="gCustomizeMode.toggle()" flex="1"/>
+        <!-- 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" aria-label="&helpMenu.label;"
+                       oncommand="PanelUI.showHelpView(this.parentNode);"/>
+      </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>
+
+    <panelview id="PanelUI-developer" flex="1">
+      <label value="&webDeveloperMenu.label;"/>
+      <vbox id="PanelUI-developerItems"/>
+    </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,287 @@
+/* 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);
+        let evt = new CustomEvent("ViewHiding", {detail: viewNode});
+        viewNode.dispatchEvent(evt);
+
+        this.multiView.appendChild(viewNode);
+        tempPanel.parentElement.removeChild(tempPanel);
+      }.bind(this));
+
+      let iconAnchor =
+        document.getAnonymousElementByAttribute(aAnchor, "class",
+                                                "toolbarbutton-icon");
+
+      tempPanel.openPopup(iconAnchor || aAnchor, "bottomcenter topright");
+    }
+  },
+
+  /**
+   * This function can be used as a command event listener for subviews
+   * so that the panel knows if and when to close itself.
+   */
+  onCommandHandler: function(aEvent) {
+    if (!aEvent.originalTarget.hasAttribute("noautoclose")) {
+      PanelUI.hide();
+    }
+  },
+
+  /** 
+   * 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();
+    }
+  },
+
+  _onHelpViewShow: function(aEvent) {
+    // Call global menu setup function
+    buildHelpMenu();
+
+    let helpMenu = document.getElementById("menu_HelpPopup");
+    let items = this.getElementsByTagName("vbox")[0];
+    let attrs = ["oncommand", "onclick", "label", "key", "disabled"];
+    let NSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+    // Remove all buttons from the view
+    while (items.firstChild) {
+      items.removeChild(items.firstChild);
+    }
+
+    // Add the current set of menuitems of the Help menu to this view
+    let menuItems = Array.prototype.slice.call(helpMenu.getElementsByTagName("menuitem"));
+    let fragment = document.createDocumentFragment();
+    for (let node of menuItems) {
+      if (node.hidden)
+        continue;
+      let button = document.createElementNS(NSXUL, "toolbarbutton");
+      // Copy specific attributes from a menuitem of the Help menu
+      for (let attrName of attrs) {
+        if (!node.hasAttribute(attrName))
+          continue;
+        button.setAttribute(attrName, node.getAttribute(attrName));
+      }
+      fragment.appendChild(button);
+    }
+    items.appendChild(fragment);
+
+    this.addEventListener("command", PanelUI.onCommandHandler);
+  },
+
+  _onHelpViewHide: function(aEvent) {
+    this.removeEventListener("command", PanelUI.onCommandHandler);
+  }
+};
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,520 @@
+<?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">
+        <getter><![CDATA[
+          if (!this._customizationTarget)
+            return "";
+
+          let rv = [];
+          for (let node of this._customizationTarget.children) {
+            if (node.getAttribute("skipintoolbarset") != "true") {
+              rv.push(node.id);
+            }
+          }
+          if (this.getAttribute("overflowing") == "true") {
+            let overflowTarget = this.getAttribute("overflowtarget");
+            let overflowList = this.ownerDocument.getElementById(overflowTarget);
+            for (let node of overflowList.children) {
+              if (node.getAttribute("skipintoolbarset") != "true") {
+                rv.push(node.id);
+              }
+            }
+          }
+          return rv.join(',');
+        ]]></getter>
+        <setter><![CDATA[
+          // Get list of new and old ids:
+          let newVal = (val || '').split(',').filter(x => x);
+          let oldIds = CustomizableUI.getWidgetIdsInArea(this.id);
+
+          // Get a list of items only in the new list
+          let newIds = [id for (id of newVal) if (oldIds.indexOf(id) == -1)];
+          CustomizableUI.beginBatchUpdate();
+          for (let newId of newIds) {
+            let nextId = newId;
+            let pos;
+            do {
+              // Get the next item
+              nextId = newVal[newVal.indexOf(nextId) + 1];
+              // Figure out where it is in the old list
+              pos = oldIds.indexOf(nextId);
+              // If it's not in the old list, repeat:
+            } while (pos == -1 && nextId);
+            if (pos == -1) {
+              pos = null; // We didn't find anything, insert at the end
+            }
+            CustomizableUI.addWidgetToArea(newId, this.id, pos);
+          }
+
+          let currentIds = this.currentSet.split(',');
+          let removedIds = [id for (id of currentIds) if (newIds.indexOf(id) == -1 && newVal.indexOf(id) == -1)];
+          for (let removedId of removedIds) {
+            CustomizableUI.removeWidgetFromArea(removedId);
+          }
+          CustomizableUI.endBatchUpdate();
+        ]]></setter>
+      </property>
+
+
+    </implementation>
+  </binding>
+
+  <binding id="toolbar-menubar-stub">
+    <implementation>
+      <property name="toolbox" readonly="true">
+        <getter><![CDATA[
+          if (this._toolbox)
+            return this._toolbox;
+
+          if (this.parentNode && this.parentNode.localName == "toolbox") {
+            this._toolbox = this.parentNode;
+          }
+
+          return this._toolbox;
+        ]]></getter>
+      </property>
+      <property name="currentSet" readonly="true">
+        <getter><![CDATA[
+          return this.getAttribute("defaultset");
+        ]]></getter>
+      </property>
+      <method name="insertItem">
+        <body><![CDATA[
+          return null;
+        ]]></body>
+      </method>
+    </implementation>
+  </binding>
+
+  <!-- The toolbar-menubar-autohide and toolbar-drag bindings are almost
+       verbatim copies of their toolkit counterparts - they just inherit from
+       the customizableui's toolbar binding instead of toolkit's. We're currently
+       OK with the maintainance burden of having two copies of a binding, since
+       the long term goal is to move the customization framework into toolkit. -->
+
+  <binding id="toolbar-menubar-autohide"
+           extends="chrome://browser/content/customizableui/toolbar.xml#toolbar">
+    <implementation>
+      <constructor>
+        this._setInactive();
+      </constructor>
+      <destructor>
+        this._setActive();
+      </destructor>
+
+      <field name="_inactiveTimeout">null</field>
+
+      <field name="_contextMenuListener"><![CDATA[({
+        toolbar: this,
+        contextMenu: null,
+
+        get active () !!this.contextMenu,
+
+        init: function (event) {
+          let node = event.target;
+          while (node != this.toolbar) {
+            if (node.localName == "menupopup")
+              return;
+            node = node.parentNode;
+          }
+
+          let contextMenuId = this.toolbar.getAttribute("context");
+          if (!contextMenuId)
+            return;
+
+          this.contextMenu = document.getElementById(contextMenuId);
+          if (!this.contextMenu)
+            return;
+
+          this.contextMenu.addEventListener("popupshown", this, false);
+          this.contextMenu.addEventListener("popuphiding", this, false);
+          this.toolbar.addEventListener("mousemove", this, false);
+        },
+        handleEvent: function (event) {
+          switch (event.type) {
+            case "popupshown":
+              this.toolbar.removeEventListener("mousemove", this, false);
+              break;
+            case "popuphiding":
+            case "mousemove":
+              this.toolbar._setInactiveAsync();
+              this.toolbar.removeEventListener("mousemove", this, false);
+              this.contextMenu.removeEventListener("popuphiding", this, false);
+              this.contextMenu.removeEventListener("popupshown", this, false);
+              this.contextMenu = null;
+              break;
+          }
+        }
+      })]]></field>
+
+      <method name="_setInactive">
+        <body><![CDATA[
+          this.setAttribute("inactive", "true");
+        ]]></body>
+      </method>
+
+      <method name="_setInactiveAsync">
+        <body><![CDATA[
+          this._inactiveTimeout = setTimeout(function (self) {
+            if (self.getAttribute("autohide") == "true") {
+              self._inactiveTimeout = null;
+              self._setInactive();
+            }
+          }, 0, this);
+        ]]></body>
+      </method>
+
+      <method name="_setActive">
+        <body><![CDATA[
+          if (this._inactiveTimeout) {
+            clearTimeout(this._inactiveTimeout);
+            this._inactiveTimeout = null;
+          }
+          this.removeAttribute("inactive");
+        ]]></body>
+      </method>
+    </implementation>
+
+    <handlers>
+      <handler event="DOMMenuBarActive"     action="this._setActive();"/>
+      <handler event="popupshowing"         action="this._setActive();"/>
+      <handler event="mousedown" button="2" action="this._contextMenuListener.init(event);"/>
+      <handler event="DOMMenuBarInactive"><![CDATA[
+        if (!this._contextMenuListener.active)
+          this._setInactiveAsync();
+      ]]></handler>
+    </handlers>
+  </binding>
+
+  <binding id="toolbar-drag"
+           extends="chrome://browser/content/customizableui/toolbar.xml#toolbar">
+    <implementation>
+      <field name="_dragBindingAlive">true</field>
+      <constructor><![CDATA[
+        if (!this._draggableStarted) {
+          this._draggableStarted = true;
+          try {
+            let tmp = {};
+            Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
+            let draggableThis = new tmp.WindowDraggingElement(this);
+            draggableThis.mouseDownCheck = function(e) {
+              // 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,2227 @@
+/* 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.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
+  "resource://gre/modules/PrivateBrowsingUtils.jsm");
+XPCOMUtils.defineLazyGetter(this, "gWidgetsBundle", function() {
+  const kUrl = "chrome://browser/locale/customizableui/customizableWidgets.properties";
+  return Services.strings.createBundle(kUrl);
+});
+XPCOMUtils.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",
+      ]
+    });
+#ifndef XP_MACOSX
+    this.registerArea(CustomizableUI.AREA_MENUBAR, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR,
+      defaultPlacements: [
+        "menubar-items",
+      ]
+    });
+#endif
+    this.registerArea(CustomizableUI.AREA_TABSTRIP, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR,
+      defaultPlacements: [
+        "tabbrowser-tabs",
+        "new-tab-button",
+        "alltabs-button",
+        "tabs-closebutton",
+      ]
+    });
+    this.registerArea(CustomizableUI.AREA_BOOKMARKS, {
+      legacy: true,
+      type: CustomizableUI.TYPE_TOOLBAR,
+      defaultPlacements: [
+        "personal-bookmarks",
+      ]
+    });
+
+    this.registerArea(CustomizableUI.AREA_ADDONBAR, {
+      type: CustomizableUI.TYPE_TOOLBAR,
+      legacy: true,
+      defaultPlacements: ["addonbar-closebutton", "status-bar"]
+    });
+  },
+
+  _defineBuiltInWidgets: function() {
+    //XXXunf Need to figure out how to auto-add new builtin widgets in new
+    //       app versions to already customized areas.
+    for (let widgetDefinition of CustomizableWidgets) {
+      this.createBuiltinWidget(widgetDefinition);
+    }
+  },
+
+  wrapWidget: function(aWidgetId) {
+    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 inPrivateWindow = PrivateBrowsingUtils.isWindowPrivate(window);
+    let container = aAreaNode.customizationTarget;
+
+    if (!container) {
+      throw new Error("Expected area " + aArea
+                      + " to have a customizationTarget attribute.");
+    }
+
+    this.beginBatchUpdate();
+
+    let currentNode = container.firstChild;
+    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;
+      }
+
+      if (inPrivateWindow && provider == CustomizableUI.PROVIDER_API) {
+        let widget = gPalette.get(id);
+        if (!widget.showInPrivateBrowsing && inPrivateWindow) {
+          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 showInPrivateBrowsing = gPalette.has(aWidgetId)
+                              ? gPalette.get(aWidgetId).showInPrivateBrowsing
+                              : true;
+    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;
+      if (!showInPrivateBrowsing && PrivateBrowsingUtils.isWindowPrivate(window)) {
+        continue;
+      }
+
+      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;
+    }
+
+    let showInPrivateBrowsing = gPalette.has(aWidgetId)
+                              ? gPalette.get(aWidgetId).showInPrivateBrowsing
+                              : true;
+
+    for (let areaNode of areaNodes) {
+      let window = areaNode.ownerDocument.defaultView;
+      if (!showInPrivateBrowsing &&
+          PrivateBrowsingUtils.isWindowPrivate(window)) {
+        continue;
+      }
+
+      let container = areaNode.customizationTarget;
+      let widgetNode = container.ownerDocument.getElementById(aWidgetId);
+      if (!widgetNode) {
+        ERROR("Widget not found, unable to remove");
+        continue;
+      }
+
+      this._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 showInPrivateBrowsing = gPalette.has(aWidgetId)
+                              ? gPalette.get(aWidgetId).showInPrivateBrowsing
+                              : true;
+
+    let nextNodeId = placements[aNewPosition + 1];
+
+    for (let areaNode of areaNodes) {
+      let window = areaNode.ownerDocument.defaultView;
+      if (!showInPrivateBrowsing &&
+          PrivateBrowsingUtils.isWindowPrivate(window)) {
+        continue;
+      }
+
+      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,
+      showInPrivateBrowsing: true,
+    };
+
+    if (typeof aData.id != "string" || !/^[a-z0-9-_]{1,}$/i.test(aData.id)) {
+      ERROR("Given an illegal id in normalizeWidget: " + aData.id);
+      return null;
+    }
+
+    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];
+      }
+    }
+
+    const kOptBoolProps = ["removable", "showInPrivateBrowsing"]
+    for (let prop of kOptBoolProps) {
+      if (typeof aData[prop] == "boolean") {
+        widget[prop] = aData[prop];
+      }
+    }
+
+    if (aData.defaultArea && gAreas.has(aData.defaultArea)) {
+      widget.defaultArea = aData.defaultArea;
+    }
+
+    if (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;
+    let buildAreaNodes = area && gBuildAreas.get(area);
+    if (buildAreaNodes) {
+      for (let buildNode of buildAreaNodes) {
+        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",
+                      "showInPrivateBrowsing"];
+  for (let prop of kBareProps) {
+    let propertyName = prop;
+    this.__defineGetter__(propertyName, function() aWidget[propertyName]);
+  }
+
+  this.__defineGetter__("provider", function() CustomizableUI.PROVIDER_API);
+
+  this.__defineSetter__("disabled", function(aValue) {
+    aValue = !!aValue;
+    aWidget.disabled = aValue;
+    for (let [,instance] of aWidget.instances) {
+      instance.disabled = aValue;
+    }
+  });
+
+  this.forWindow = function WidgetGroupWrapper_forWindow(aWindow) {
+    let 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(this._toolbar.getAttribute("overflowtarget"));
+    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,567 @@
+/* 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",
+    type: "view",
+    viewId: "PanelUI-developer",
+    removable: true,
+    defaultArea: CustomizableUI.AREA_PANEL,
+    allowedAreas: [CustomizableUI.AREA_PANEL],
+    onViewShowing: function(aEvent) {
+      // Populate the subview with whatever menuitems are in the developer
+      // menu. We skip menu elements, because the menu panel has no way
+      // of dealing with those right now.
+      let doc = aEvent.target.ownerDocument;
+      let win = doc.defaultView;
+
+      let items = doc.getElementById("PanelUI-developerItems");
+      let menu = doc.getElementById("menuWebDeveloperPopup");
+      let attrs = ["oncommand", "onclick", "label", "key", "disabled",
+                   "command"];
+
+      let fragment = doc.createDocumentFragment();
+      for (let node of menu.children) {
+        if (node.hidden)
+          continue;
+
+        let item;
+        if (node.localName == "menuseparator") {
+          item = doc.createElementNS(kNSXUL, "menuseparator");
+        } else if (node.localName == "menuitem") {
+          item = doc.createElementNS(kNSXUL, "toolbarbutton");
+        } else {
+          continue;
+        }
+        for (let attr of attrs) {
+          let attrVal = node.getAttribute(attr);
+          if (attrVal)
+            item.setAttribute(attr, attrVal);
+        }
+        fragment.appendChild(item);
+      }
+      items.appendChild(fragment);
+
+      aEvent.target.addEventListener("command", win.PanelUI.onCommandHandler);
+    },
+    onViewHiding: function(aEvent) {
+      let doc = aEvent.target.ownerDocument;
+      let win = doc.defaultView;
+      let items = doc.getElementById("PanelUI-developerItems");
+      let parent = items.parentNode;
+      // We'll take the container out of the document before cleaning it out
+      // to avoid reflowing each time we remove something.
+      parent.removeChild(items);
+
+      while (items.firstChild) {
+        items.firstChild.remove();
+      }
+
+      parent.appendChild(items);
+      aEvent.target.removeEventListener("command",
+                                        win.PanelUI.onCommandHandler);
+    }
+  }, {
+    id: "add-ons-button",
+    removable: true,
+    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") {
+